Merge branch 'test' of https://gitea.verdnatura.es/verdnatura/salix-front into dev
gitea/salix-front/pipeline/head Build queued... Details

This commit is contained in:
Alex Moreno 2025-04-02 14:18:19 +02:00
commit a4b710352d
15 changed files with 149 additions and 106 deletions

View File

@ -26,11 +26,7 @@ const route = useRoute();
const stateStore = useStateStore(); const stateStore = useStateStore();
const router = useRouter(); const router = useRouter();
const entityId = computed(() => props.id || route?.params?.id); const entityId = computed(() => props.id || route?.params?.id);
const arrayData = useArrayData(props.dataKey, { let arrayData = getArrayData(entityId.value, props.url);
url: props.url,
userFilter: props.filter,
oneRecord: true,
});
onBeforeRouteLeave(() => { onBeforeRouteLeave(() => {
stateStore.cardDescriptorChangeValue(null); stateStore.cardDescriptorChangeValue(null);
@ -61,16 +57,31 @@ onBeforeRouteUpdate(async (to, from) => {
}); });
async function fetch(id, append = false) { async function fetch(id, append = false) {
const regex = /\/(\d+)/;
if (props.idInWhere) arrayData.store.filter.where = { id }; if (props.idInWhere) arrayData.store.filter.where = { id };
else if (!regex.test(props.url)) arrayData.store.url = `${props.url}/${id}`; else {
else arrayData.store.url = props.url.replace(regex, `/${id}`); arrayData = getArrayData(id);
}
await arrayData.fetch({ append, updateRouter: false }); await arrayData.fetch({ append, updateRouter: false });
emit('onFetch', arrayData.store.data); emit('onFetch', arrayData.store.data);
} }
function hasRouteParam(params, valueToCheck = ':addressId') { function hasRouteParam(params, valueToCheck = ':addressId') {
return Object.values(params).includes(valueToCheck); return Object.values(params).includes(valueToCheck);
} }
function formatUrl(id) {
const newId = id || entityId.value;
const regex = /\/(\d+)/;
if (!regex.test(props.url)) return `${props.url}/${newId}`;
return props.url.replace(regex, `/${newId}`);
}
function getArrayData(id, url) {
return useArrayData(props.dataKey, {
url: url ?? formatUrl(id),
userFilter: props.filter,
oneRecord: true,
});
}
</script> </script>
<template> <template>
<template v-if="visual"> <template v-if="visual">

View File

@ -40,10 +40,6 @@ const $props = defineProps({
type: Boolean, type: Boolean,
default: true, default: true,
}, },
keepData: {
type: Boolean,
default: true,
},
}); });
const route = useRoute(); const route = useRoute();
@ -61,7 +57,6 @@ onBeforeMount(() => {
if ($props.dataKey) if ($props.dataKey)
arrayData = useArrayData($props.dataKey, { arrayData = useArrayData($props.dataKey, {
searchUrl: 'table', searchUrl: 'table',
keepData: $props.keepData,
...$props.arrayDataProps, ...$props.arrayDataProps,
navigate: $props.redirect, navigate: $props.redirect,
}); });

View File

@ -115,7 +115,7 @@ onMounted(async () => {
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
if (!store.keepData) arrayData.reset(['data']); arrayData.reset(['data']);
arrayData.resetPagination(); arrayData.resetPagination();
}); });

View File

@ -56,7 +56,6 @@ export function useArrayData(key, userOptions) {
'searchUrl', 'searchUrl',
'navigate', 'navigate',
'mapKey', 'mapKey',
'keepData',
'oneRecord', 'oneRecord',
]; ];
if (typeof userOptions === 'object') { if (typeof userOptions === 'object') {
@ -108,7 +107,7 @@ export function useArrayData(key, userOptions) {
store.hasMoreData = limit && response.data.length >= limit; store.hasMoreData = limit && response.data.length >= limit;
if (!append && !isDialogOpened() && updateRouter) { if (!append && !isDialogOpened() && updateRouter) {
if (updateStateParams(response.data)?.redirect && !store.keepData) return; if (updateStateParams(response.data)?.redirect) return;
} }
store.isLoading = false; store.isLoading = false;
canceller = null; canceller = null;

View File

@ -72,6 +72,7 @@ const exprBuilder = (param, value) => {
option-value="id" option-value="id"
option-label="name" option-label="name"
url="Departments" url="Departments"
no-one="true"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -154,6 +155,7 @@ en:
city: City city: City
phone: Phone phone: Phone
email: Email email: Email
departmentFk: Department
isToBeMailed: Mailed isToBeMailed: Mailed
isEqualizated: Equailized isEqualizated: Equailized
departmentFk: Department departmentFk: Department
@ -171,6 +173,7 @@ es:
search: Contiene search: Contiene
fi: NIF fi: NIF
isActive: Activo isActive: Activo
departmentFk: Departamento
isToBeMailed: A enviar isToBeMailed: A enviar
isEqualizated: Recargo de equivalencia isEqualizated: Recargo de equivalencia
businessTypeFk: Tipo de negocio businessTypeFk: Tipo de negocio

View File

@ -127,6 +127,7 @@ es:
Identifier: Identificador Identifier: Identificador
Social name: Razón social Social name: Razón social
Phone: Teléfono Phone: Teléfono
Postcode: Código postal
City: Población City: Población
Email: Email Email: Email
Campaign consumption: Consumo campaña Campaign consumption: Consumo campaña

View File

@ -93,10 +93,26 @@ const updateAddressTicket = async () => {
}; };
const updateObservations = async (payload) => { const updateObservations = async (payload) => {
await axios.post('AddressObservations/crud', payload); await axios.post('AddressObservations/crud', cleanPayload(payload));
notes.value = []; notes.value = [];
deletes.value = []; deletes.value = [];
}; };
function cleanPayload(payload) {
['creates', 'deletes', 'updates'].forEach((prop) => {
if (prop === 'creates' || prop === 'updates') {
payload[prop] = payload[prop].filter(
(item) => item.description !== '' && item.observationTypeFk !== '',
);
} else {
payload[prop] = payload[prop].filter(
(item) => item !== null && item !== undefined,
);
}
});
return payload;
}
async function updateAll({ data, payload }) { async function updateAll({ data, payload }) {
await updateObservations(payload); await updateObservations(payload);
await updateAddress(data); await updateAddress(data);

View File

@ -191,7 +191,7 @@ const getItemPackagingType = (ticketSales) => {
:without-header="true" :without-header="true"
auto-load auto-load
:row-click="rowClick" :row-click="rowClick"
order="shipped DESC, id" order="shipped DESC, id DESC"
:disable-option="{ card: true, table: true }" :disable-option="{ card: true, table: true }"
class="full-width" class="full-width"
:disable-infinite-scroll="true" :disable-infinite-scroll="true"

View File

@ -106,7 +106,7 @@ const getEntryQueryParams = (supplier) => {
<QBtn <QBtn
:to="{ :to="{
name: 'EntryList', name: 'EntryList',
query: { params: JSON.stringify(getEntryQueryParams(entity)) }, query: { table: JSON.stringify(getEntryQueryParams(entity)) },
}" }"
size="md" size="md"
icon="vn:entry" icon="vn:entry"

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, ref, computed, watch } from 'vue'; import { onMounted, ref, computed, watch, inject } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -25,7 +25,7 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue';
import TicketProblems from 'src/components/TicketProblems.vue'; import TicketProblems from 'src/components/TicketProblems.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
const app = inject('app');
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
@ -196,13 +196,17 @@ const changeQuantity = async (sale) => {
if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity) if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity)
return; return;
else sale.originalQuantity = sale.quantity; else sale.originalQuantity = sale.quantity;
if (!sale.id) return addSale(sale); try {
if (!sale.id) await addSale(sale);
} catch (e) {
app.config.errorHandler(e);
return;
}
if (await isSalePrepared(sale)) { if (await isSalePrepared(sale)) {
await confirmUpdate(() => updateQuantity(sale)); await confirmUpdate(() => updateQuantity(sale));
} else await updateQuantity(sale); } else await updateQuantity(sale);
}; };
const updateQuantity = async (sale) => { const updateQuantity = async (sale) => {
try { try {
let { quantity, id } = sale; let { quantity, id } = sale;
@ -215,7 +219,7 @@ const updateQuantity = async (sale) => {
(s) => s.id === sale.id, (s) => s.id === sale.id,
); );
sale.quantity = quantity; sale.quantity = quantity;
throw e; app.config.errorHandler(e);
} }
}; };
@ -224,24 +228,27 @@ const addSale = async (sale) => {
barcode: sale.itemFk, barcode: sale.itemFk,
quantity: sale.quantity, quantity: sale.quantity,
}; };
try {
const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params);
const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params); if (!data) return;
if (!data) return; const newSale = data;
sale.id = newSale.id;
sale.image = newSale.item.image;
sale.subName = newSale.item.subName;
sale.concept = newSale.concept;
sale.quantity = newSale.quantity;
sale.discount = newSale.discount;
sale.price = newSale.price;
sale.item = newSale.item;
const newSale = data; notify('globals.dataSaved', 'positive');
sale.id = newSale.id; sale.isNew = false;
sale.image = newSale.item.image; resetChanges();
sale.subName = newSale.item.subName; } catch (e) {
sale.concept = newSale.concept; app.config.errorHandler(e);
sale.quantity = newSale.quantity; }
sale.discount = newSale.discount;
sale.price = newSale.price;
sale.item = newSale.item;
notify('globals.dataSaved', 'positive');
sale.isNew = false;
resetChanges();
}; };
const changeConcept = async (sale) => { const changeConcept = async (sale) => {
if (await isSalePrepared(sale)) { if (await isSalePrepared(sale)) {
@ -250,10 +257,14 @@ const changeConcept = async (sale) => {
}; };
const updateConcept = async (sale) => { const updateConcept = async (sale) => {
const data = { newConcept: sale.concept }; try {
await axios.post(`Sales/${sale.id}/updateConcept`, data); const data = { newConcept: sale.concept };
notify('globals.dataSaved', 'positive'); await axios.post(`Sales/${sale.id}/updateConcept`, data);
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const DEFAULT_EDIT = { const DEFAULT_EDIT = {
@ -264,18 +275,6 @@ const DEFAULT_EDIT = {
oldQuantity: null, oldQuantity: null,
}; };
const edit = ref({ ...DEFAULT_EDIT }); const edit = ref({ ...DEFAULT_EDIT });
const usesMana = ref(null);
const getUsesMana = async () => {
const { data } = await axios.get('Sales/usesMana');
usesMana.value = data;
};
const getMana = async () => {
const { data } = await axios.get(`Tickets/${route.params.id}/getDepartmentMana`);
mana.value = data;
await getUsesMana();
};
const selectedValidSales = computed(() => { const selectedValidSales = computed(() => {
if (!sales.value) return; if (!sales.value) return;
@ -312,11 +311,15 @@ const changePrice = async (sale) => {
} }
}; };
const updatePrice = async (sale, newPrice) => { const updatePrice = async (sale, newPrice) => {
await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice }); try {
sale.price = newPrice; await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
edit.value = { ...DEFAULT_EDIT }; sale.price = newPrice;
notify('globals.dataSaved', 'positive'); edit.value = { ...DEFAULT_EDIT };
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const changeDiscount = async (sale) => { const changeDiscount = async (sale) => {
@ -339,15 +342,20 @@ const updateDiscounts = async (sales, newDiscount) => {
}; };
const updateDiscount = async (sales, newDiscount = 0) => { const updateDiscount = async (sales, newDiscount = 0) => {
const salesIds = sales.map(({ id }) => id); try {
const params = { const salesIds = sales.map(({ id }) => id);
salesIds, const params = {
newDiscount, salesIds,
manaCode: manaCode.value, newDiscount,
}; manaCode: manaCode.value,
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params); };
notify('globals.dataSaved', 'positive'); await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
return;
}
}; };
const getNewPrice = computed(() => { const getNewPrice = computed(() => {
@ -369,11 +377,15 @@ const getNewPrice = computed(() => {
}); });
const newOrderFromTicket = async () => { const newOrderFromTicket = async () => {
const { data } = await axios.post(`Orders/newFromTicket`, { try {
ticketFk: Number(route.params.id), const { data } = await axios.post(`Orders/newFromTicket`, {
}); ticketFk: Number(route.params.id),
const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } }); });
window.open(routeData.href, '_blank'); const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } });
window.open(routeData.href, '_blank');
} catch (e) {
app.config.errorHandler(e);
}
}; };
const goToLog = (saleId) => { const goToLog = (saleId) => {
@ -390,11 +402,15 @@ const goToLog = (saleId) => {
}; };
const changeTicketState = async (val) => { const changeTicketState = async (val) => {
stateBtnDropdownRef.value.hide(); try {
const params = { ticketFk: route.params.id, code: val }; stateBtnDropdownRef.value.hide();
await axios.post('Tickets/state', params); const params = { ticketFk: route.params.id, code: val };
notify('globals.dataSaved', 'positive'); await axios.post('Tickets/state', params);
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const removeSelectedSales = () => { const removeSelectedSales = () => {
@ -414,10 +430,14 @@ const removeSales = async () => {
.forEach((sale) => tableRef.value.CrudModelRef.formData.splice(sale.$index, 1)); .forEach((sale) => tableRef.value.CrudModelRef.formData.splice(sale.$index, 1));
if (params.sales.length == 0) return; if (params.sales.length == 0) return;
await axios.post('Sales/deleteSales', params); try {
removeSelectedSales(); await axios.post('Sales/deleteSales', params);
notify('globals.dataSaved', 'positive'); removeSelectedSales();
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const setTransferParams = async () => { const setTransferParams = async () => {

View File

@ -66,7 +66,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.ref, entity.
:to="{ :to="{
name: 'TravelList', name: 'TravelList',
query: { query: {
params: JSON.stringify({ table: JSON.stringify({
agencyModeFk: entity.agencyModeFk, agencyModeFk: entity.agencyModeFk,
}), }),
}, },

View File

@ -505,7 +505,6 @@ watch(route, () => {
:props="props" :props="props"
@click="stopEventPropagation($event, col)" @click="stopEventPropagation($event, col)"
:style="col.style" :style="col.style"
style="padding-left: 5px"
> >
<component <component
:is="tableColumnComponents[col.name].component" :is="tableColumnComponents[col.name].component"
@ -581,19 +580,20 @@ watch(route, () => {
<QBtn dense flat class="link">{{ entry.id }} </QBtn> <QBtn dense flat class="link">{{ entry.id }} </QBtn>
<EntryDescriptorProxy :id="entry.id" /> <EntryDescriptorProxy :id="entry.id" />
</QTd> </QTd>
<QTd> <QTd :colspan="2">
<QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn> <div style="display: flex">
<SupplierDescriptorProxy :id="entry.supplierFk" /> <span class="link">
</QTd> {{ entry.supplierName }}
<QTd class="text-center"> <SupplierDescriptorProxy :id="entry.supplierFk" />
<QIcon </span>
v-if="entry.isCustomInspectionRequired" <QIcon
name="warning" v-if="entry.isCustomInspectionRequired"
color="negative" name="warning"
size="md" color="negative"
:title="t('extraCommunity.requiresInspection')" size="md"
> :title="t('extraCommunity.requiresInspection')"
</QIcon> />
</div>
</QTd> </QTd>
<QTd class="text-right"> <QTd class="text-right">
<span>{{ toCurrency(entry.invoiceAmount) }}</span> <span>{{ toCurrency(entry.invoiceAmount) }}</span>
@ -639,9 +639,7 @@ watch(route, () => {
&:nth-child(1) { &:nth-child(1) {
max-width: 65px; max-width: 65px;
} }
&:nth-child(4) { padding: 0 5px 0;
padding: 0;
}
} }
thead > tr > th { thead > tr > th {
padding: 3px; padding: 3px;

View File

@ -18,7 +18,6 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
navigate: null, navigate: null,
page: 1, page: 1,
mapKey: 'id', mapKey: 'id',
keepData: false,
oneRecord: false, oneRecord: false,
}; };

View File

@ -1,6 +1,6 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
// https://redmine.verdnatura.es/issues/8848
describe('VnShortcuts', () => { describe.skip('VnShortcuts', () => {
const modules = { const modules = {
item: 'a', item: 'a',
customer: 'c', customer: 'c',

View File

@ -1,4 +1,5 @@
describe('WorkerList', () => { // https://redmine.verdnatura.es/issues/8848
describe.skip('WorkerList', () => {
const inputName = '.q-drawer .q-form input[aria-label="First Name"]'; const inputName = '.q-drawer .q-form input[aria-label="First Name"]';
const searchBtn = '.q-drawer button:nth-child(3)'; const searchBtn = '.q-drawer button:nth-child(3)';
const descriptorTitle = '.descriptor .title span'; const descriptorTitle = '.descriptor .title span';
@ -13,7 +14,7 @@ describe('WorkerList', () => {
cy.intercept('GET', /\/api\/Workers\/summary+/).as('worker'); cy.intercept('GET', /\/api\/Workers\/summary+/).as('worker');
cy.get(searchBtn).click(); cy.get(searchBtn).click();
cy.wait('@worker').then(() => cy.wait('@worker').then(() =>
cy.get(descriptorTitle).should('include.text', 'Jessica') cy.get(descriptorTitle).should('include.text', 'Jessica'),
); );
}); });
}); });