Merge branch 'dev' into 6321_negative_tickets
gitea/salix-front/pipeline/head This commit looks good Details

This commit is contained in:
Javier Segarra 2025-02-11 08:43:22 +00:00
commit 4bd9e69bf1
22 changed files with 203 additions and 72 deletions

View File

@ -328,7 +328,6 @@ en:
active: Is active
visible: Is visible
floramondo: Is floramondo
salesPersonFk: Buyer
categoryFk: Category
es:
@ -339,7 +338,6 @@ es:
active: Activo
visible: Visible
floramondo: Floramondo
salesPersonFk: Comprador
categoryFk: Categoría
Plant: Planta natural
Flower: Flor fresca

View File

@ -15,6 +15,7 @@ const model = defineModel({ type: [String, Number, Object] });
:fields="['id', 'name', 'nickname', 'nif']"
:filter-options="['id', 'name', 'nickname', 'nif']"
sort-by="name ASC"
data-cy="vnSupplierSelect"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -57,7 +57,7 @@ defineExpose({ getData });
onBeforeMount(async () => {
arrayData = useArrayData($props.dataKey, {
url: $props.url,
filter: $props.filter,
userFilter: $props.filter,
skip: 0,
oneRecord: true,
});

View File

@ -18,7 +18,12 @@ import VnInput from 'components/common/VnInput.vue';
const emit = defineEmits(['onFetch']);
const $attrs = useAttrs();
const originalAttrs = useAttrs();
const $attrs = computed(() => {
const { style, ...rest } = originalAttrs;
return rest;
});
const isRequired = computed(() => {
return Object.keys($attrs).includes('required')

View File

@ -690,7 +690,6 @@ supplier:
tableVisibleColumns:
nif: NIF/CIF
account: Cuenta
summary:
responsible: Responsable
verified: Verificado

View File

@ -23,7 +23,7 @@ onMounted(async () => {
<CardDescriptor
ref="descriptor"
:url="`VnUsers/preview`"
:filter="filter"
:filter="{ ...filter, where: { id: entityId } }"
module="Account"
data-key="Account"
title="nickname"

View File

@ -86,7 +86,7 @@ onMounted(async () => {
/>
</template>
</VnLv>
<VnLv :label="t('claim.zone')">
<VnLv v-if="entity.ticket?.zone?.id" :label="t('claim.zone')">
<template #value>
<span class="link">
{{ entity.ticket?.zone?.name }}
@ -98,11 +98,10 @@ onMounted(async () => {
:label="t('claim.province')"
:value="entity.ticket?.address?.province?.name"
/>
<VnLv :label="t('claim.ticketId')">
<VnLv v-if="entity.ticketFk" :label="t('claim.ticketId')">
<template #value>
<span class="link">
{{ entity.ticketFk }}
<TicketDescriptorProxy :id="entity.ticketFk" />
</span>
</template>

View File

@ -1,5 +1,5 @@
<script setup>
import { computed } from 'vue';
import { computed, useAttrs } from 'vue';
import { useRoute } from 'vue-router';
import { useState } from 'src/composables/useState';
import VnNotes from 'src/components/ui/VnNotes.vue';
@ -7,6 +7,7 @@ import VnNotes from 'src/components/ui/VnNotes.vue';
const route = useRoute();
const state = useState();
const user = state.getUser();
const $attrs = useAttrs();
const $props = defineProps({
id: { type: [Number, String], default: null },

View File

@ -131,7 +131,7 @@ const STATE_COLOR = {
prefix="claim"
:array-data-props="{
url: 'Claims/filter',
order: ['cs.priority ASC', 'created ASC'],
order: 'cs.priority ASC, created ASC',
}"
>
<template #advanced-menu>

View File

@ -117,7 +117,7 @@ const toCustomerAddressEdit = (addressId) => {
data-key="CustomerAddresses"
order="id DESC"
ref="vnPaginateRef"
:user-filter="addressFilter"
:filter="addressFilter"
:url="`Clients/${route.params.id}/addresses`"
/>
<div class="full-width flex justify-center">
@ -189,11 +189,11 @@ const toCustomerAddressEdit = (addressId) => {
<QSeparator
class="q-mx-lg"
v-if="item.observations.length"
v-if="item?.observations?.length"
vertical
/>
<div v-if="item.observations.length">
<div v-if="item?.observations?.length">
<div
:key="obIndex"
class="flex q-mb-sm"

View File

@ -61,6 +61,23 @@ const columns = computed(() => [
columnFilter: false,
cardVisible: true,
},
{
align: 'left',
name: 'buyerId',
label: t('customer.params.buyerId'),
component: 'select',
attrs: {
url: 'TicketRequests/getItemTypeWorker',
optionLabel: 'nickname',
optionValue: 'id',
fields: ['id', 'nickname'],
sortBy: ['nickname ASC'],
optionFilter: 'firstName',
},
cardVisible: false,
visible: false,
},
{
name: 'description',
align: 'left',
@ -74,6 +91,7 @@ const columns = computed(() => [
name: 'quantity',
label: t('globals.quantity'),
cardVisible: true,
visible: true,
columnFilter: {
inWhere: true,
},
@ -138,11 +156,11 @@ const updateDateParams = (value, params) => {
const campaign = campaignList.value.find((c) => c.id === value);
if (!campaign) return;
const { dated, previousDays, scopeDays } = campaign;
const _date = new Date(dated);
const [from, to] = dateRange(_date);
params.from = new Date(from.setDate(from.getDate() - previousDays)).toISOString();
params.to = new Date(to.setDate(to.getDate() + scopeDays)).toISOString();
const { dated, scopeDays } = campaign;
const from = new Date(dated);
from.setDate(from.getDate() - scopeDays);
params.from = from;
params.to = dated;
return params;
};
</script>
@ -205,24 +223,57 @@ const updateDateParams = (value, params) => {
<template #moreFilterPanel="{ params }">
<div class="column no-wrap flex-center q-gutter-y-md q-mt-xs q-pr-xl">
<VnSelect
v-model="params.campaign"
:options="campaignList"
:label="t('globals.campaign')"
:filled="true"
class="q-px-sm q-pt-none fit"
url="ItemTypes"
v-model="params.typeId"
:label="t('item.list.typeName')"
:fields="['id', 'name', 'categoryFk']"
:include="'category'"
:sortBy="'name ASC'"
dense
option-label="code"
@update:model-value="(data) => updateDateParams(data, params)"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.code }}
{{
new Date(scope.opt?.dated).getFullYear()
}}</QItemLabel
>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>{{
scope.opt?.category?.name
}}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
<VnSelect
:filled="true"
class="q-px-sm q-pt-none fit"
url="ItemCategories"
v-model="params.categoryId"
:label="t('item.list.category')"
:fields="['id', 'name']"
:sortBy="'name ASC'"
dense
@update:model-value="(data) => updateDateParams(data, params)"
/>
<VnSelect
v-model="params.campaign"
:options="campaignList"
:label="t('globals.campaign')"
:filled="true"
class="q-px-sm q-pt-none fit"
:option-label="(opt) => t(opt.code)"
:fields="['id', 'code', 'dated', 'scopeDays']"
@update:model-value="(data) => updateDateParams(data, params)"
dense
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel> {{ t(scope.opt?.code) }} </QItemLabel>
<QItemLabel caption>
{{ new Date(scope.opt?.dated).getFullYear() }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
@ -247,7 +298,19 @@ const updateDateParams = (value, params) => {
</template>
<i18n>
en:
valentinesDay: Valentine's Day
mothersDay: Mother's Day
allSaints: All Saints' Day
es:
Enter a new search: Introduce una nueva búsqueda
Group by items: Agrupar por artículos
valentinesDay: Día de San Valentín
mothersDay: Día de la Madre
allSaints: Día de Todos los Santos
Campaign consumption: Consumo campaña
Campaign: Campaña
From: Desde
To: Hasta
</i18n>

View File

@ -107,6 +107,9 @@ customer:
defaulterSinced: Defaulted Since
hasRecovery: Has Recovery
socialName: Social name
typeId: Type
buyerId: Buyer
categoryId: Category
city: City
phone: Phone
postcode: Postcode

View File

@ -108,6 +108,9 @@ customer:
hasRecovery: Tiene recobro
socialName: Razón social
campaign: Campaña
typeId: Familia
buyerId: Comprador
categoryId: Reino
city: Ciudad
phone: Teléfono
postcode: Código postal

View File

@ -54,8 +54,8 @@ const transferEntry = async () => {
<i18n>
en:
transferEntryDialog: The entries will be transferred to the next day
transferEntry: Transfer Entry
transferEntry: Partial delay
es:
transferEntryDialog: Se van a transferir las compras al dia siguiente
transferEntry: Transferir Entrada
transferEntry: Retraso parcial
</i18n>

View File

@ -149,6 +149,7 @@ function deleteFile(dmsFk) {
option-value="id"
option-label="id"
:filter-options="['id', 'name']"
data-cy="UnDeductibleVatSelect"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -97,12 +97,19 @@ const columns = computed(() => [
},
{
align: 'left',
name: 'companyCode',
name: 'companyFk',
label: t('globals.company'),
cardVisible: true,
component: 'select',
attrs: { url: 'Companies', optionLabel: 'code', optionValue: 'id' },
columnField: { component: null },
attrs: {
url: 'Companies',
optionLabel: 'code',
optionValue: 'id',
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.companyCode),
},
{
align: 'left',

View File

@ -43,10 +43,9 @@ const addToOrder = async () => {
);
state.set('orderTotal', orderTotal);
const rows = orderData.value.rows.push(...items) || [];
state.set('Order', {
...orderData.value,
rows,
items,
});
notify(t('globals.dataSaved'), 'positive');
emit('added', -totalQuantity(items));

View File

@ -53,6 +53,7 @@ const handlePhotoUpdated = (evt = false) => {
module="Worker"
:data-key="dataKey"
url="Workers/summary"
:filter="{ where: { id: entityId } }"
title="user.nickname"
@on-fetch="getIsExcluded"
>

View File

@ -1,5 +1,7 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue';
import FetchData from 'components/FetchData.vue';
import FormModel from 'src/components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
@ -7,10 +9,33 @@ import VnInputTime from 'src/components/common/VnInputTime.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
const { t } = useI18n();
const agencyFilter = {
fields: ['id', 'name'],
order: 'name ASC',
limit: 30,
};
const agencyOptions = ref([]);
const validAddresses = ref([]);
const filterWhere = computed(() => ({
id: { inq: validAddresses.value.map((item) => item.addressFk) },
}));
</script>
<template>
<FormModel :url="`Zones/${$route.params.id}`" auto-load model="zone">
<FetchData
:filter="agencyFilter"
@on-fetch="(data) => (agencyOptions = data)"
auto-load
url="AgencyModes/isActive"
/>
<FetchData
url="RoadmapAddresses"
auto-load
@on-fetch="(data) => (validAddresses = data)"
/>
<FormModel :url="`Zones/${route.params.id}`" auto-load model="zone">
<template #form="{ data, validate }">
<VnRow>
<VnInput
@ -109,6 +134,8 @@ const { t } = useI18n();
hide-selected
map-options
:rules="validate('data.addressFk')"
:filter-options="['id']"
:where="filterWhere"
/>
</VnRow>
<VnRow>

View File

@ -22,15 +22,50 @@ const exprBuilder = (param, value) => {
return /^\d+$/.test(value) ? { id: value } : { name: { like: `%${value}%` } };
}
};
const tableFilter = {
include: [
{
relation: 'agencyMode',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'address',
scope: {
fields: ['id', 'nickname', 'provinceFk', 'postalCode'],
include: [
{
relation: 'province',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'postcode',
scope: {
fields: ['code', 'townFk'],
include: {
relation: 'town',
scope: {
fields: ['id', 'name'],
},
},
},
},
],
},
},
],
};
</script>
<template>
<VnSearchbar
data-key="ZonesList"
url="Zones"
:filter="{
include: { relation: 'agencyMode', scope: { fields: ['name'] } },
}"
:filter="tableFilter"
:expr-builder="exprBuilder"
:label="t('list.searchZone')"
:info="t('list.searchInfo')"

View File

@ -4,7 +4,7 @@ import { useRouter } from 'vue-router';
import { computed, ref } from 'vue';
import axios from 'axios';
import { toCurrency } from 'src/filters';
import { dashIfEmpty, toCurrency } from 'src/filters';
import { toTimeFormat } from 'src/filters/date';
import { useVnConfirm } from 'composables/useVnConfirm';
import useNotify from 'src/composables/useNotify.js';
@ -17,7 +17,6 @@ import VnInputTime from 'src/components/common/VnInputTime.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import ZoneFilterPanel from './ZoneFilterPanel.vue';
import ZoneSearchbar from './Card/ZoneSearchbar.vue';
import FetchData from 'src/components/FetchData.vue';
const { t } = useI18n();
const router = useRouter();
@ -26,7 +25,6 @@ const { viewSummary } = useSummaryDialog();
const { openConfirmationModal } = useVnConfirm();
const tableRef = ref();
const warehouseOptions = ref([]);
const validAddresses = ref([]);
const tableFilter = {
include: [
@ -161,30 +159,18 @@ const handleClone = (id) => {
openConfirmationModal(
t('list.confirmCloneTitle'),
t('list.confirmCloneSubtitle'),
() => clone(id)
() => clone(id),
);
};
function showValidAddresses(row) {
if (row.addressFk) {
const isValid = validAddresses.value.some(
(address) => address.addressFk === row.addressFk
);
if (isValid)
return `${row.address?.nickname},
${row.address?.postcode?.town?.name} (${row.address?.province?.name})`;
else return '-';
}
return '-';
function formatRow(row) {
if (!row?.address) return '-';
return dashIfEmpty(`${row?.address?.nickname},
${row?.address?.postcode?.town?.name} (${row?.address?.province?.name})`);
}
</script>
<template>
<FetchData
url="RoadmapAddresses"
auto-load
@on-fetch="(data) => (validAddresses = data)"
/>
<ZoneSearchbar />
<RightMenu>
<template #right-panel>
@ -207,7 +193,7 @@ function showValidAddresses(row) {
:right-search="false"
>
<template #column-addressFk="{ row }">
{{ showValidAddresses(row) }}
{{ dashIfEmpty(formatRow(row)) }}
</template>
<template #more-create-dialog="{ data }">
<VnSelect

View File

@ -1,9 +1,9 @@
/// <reference types="cypress" />
describe('InvoiceInBasicData', () => {
const formInputs = '.q-form > .q-card input';
const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
const documentBtns = '[data-cy="dms-buttons"] button';
const dialogInputs = '.q-dialog input';
const resetBtn = '.q-btn-group--push > .q-btn--flat';
const getDocumentBtns = (opt) => `[data-cy="dms-buttons"] > :nth-child(${opt})`;
beforeEach(() => {
cy.login('developer');
@ -11,13 +11,16 @@ describe('InvoiceInBasicData', () => {
});
it('should edit the provideer and supplier ref', () => {
cy.selectOption(firstFormSelect, 'Bros');
cy.get('[title="Reset"]').click();
cy.get(formInputs).eq(1).type('{selectall}4739');
cy.saveCard();
cy.dataCy('UnDeductibleVatSelect').type('4751000000');
cy.get('.q-menu .q-item').contains('4751000000').click();
cy.get(resetBtn).click();
cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Plants nick');
cy.get(formInputs).eq(1).invoke('val').should('eq', '4739');
cy.waitForElement('#formModel').within(() => {
cy.dataCy('vnSupplierSelect').type('Bros nick');
})
cy.get('.q-menu .q-item').contains('Bros nick').click();
cy.saveCard();
cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Bros nick');
});
it('should edit, remove and create the dms data', () => {
@ -25,18 +28,18 @@ describe('InvoiceInBasicData', () => {
const secondInput = "I don't know what posting here!";
//edit
cy.get(documentBtns).eq(1).click();
cy.get(getDocumentBtns(2)).click();
cy.get(dialogInputs).eq(0).type(`{selectall}${firtsInput}`);
cy.get('textarea').type(`{selectall}${secondInput}`);
cy.get('[data-cy="FormModelPopup_save"]').click();
cy.get(documentBtns).eq(1).click();
cy.get(getDocumentBtns(2)).click();
cy.get(dialogInputs).eq(0).invoke('val').should('eq', firtsInput);
cy.get('textarea').invoke('val').should('eq', secondInput);
cy.get('[data-cy="FormModelPopup_save"]').click();
cy.checkNotification('Data saved');
//remove
cy.get(documentBtns).eq(2).click();
cy.get(getDocumentBtns(3)).click();
cy.get('[data-cy="VnConfirm_confirm"]').click();
cy.checkNotification('Data saved');