This commit is contained in:
Jorge Penadés 2024-10-28 14:19:36 +01:00
commit a73a451cd8
10 changed files with 143 additions and 36 deletions

View File

@ -30,10 +30,10 @@ const props = defineProps({
}, },
}); });
defineEmits(['confirm', ...useDialogPluginComponent.emits]); const emit = defineEmits(['confirm', 'cancel', ...useDialogPluginComponent.emits]);
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
const { dialogRef, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent();
const title = props.title || t('Confirm'); const title = props.title || t('Confirm');
const message = const message =
@ -53,9 +53,14 @@ async function confirm() {
} }
onDialogOK(props.data); onDialogOK(props.data);
} }
function cancel() {
emit('cancel');
onDialogCancel();
}
</script> </script>
<template> <template>
<QDialog ref="dialogRef"> <QDialog ref="dialogRef" @hide="onDialogHide">
<QCard class="q-pa-sm"> <QCard class="q-pa-sm">
<QCardSection class="row items-center q-pb-none"> <QCardSection class="row items-center q-pb-none">
<QAvatar <QAvatar
@ -67,7 +72,14 @@ async function confirm() {
/> />
<span class="text-h6">{{ title }}</span> <span class="text-h6">{{ title }}</span>
<QSpace /> <QSpace />
<QBtn icon="close" :disable="isLoading" flat round dense v-close-popup /> <QBtn
icon="close"
:disable="isLoading"
flat
round
dense
@click="cancel()"
/>
</QCardSection> </QCardSection>
<QCardSection class="q-pb-none"> <QCardSection class="q-pb-none">
<span v-if="message !== false" v-html="message" /> <span v-if="message !== false" v-html="message" />
@ -81,7 +93,7 @@ async function confirm() {
color="primary" color="primary"
:disable="isLoading" :disable="isLoading"
flat flat
v-close-popup @click="cancel()"
/> />
<QBtn <QBtn
:label="t('globals.confirm')" :label="t('globals.confirm')"

View File

@ -278,6 +278,7 @@ globals:
RouteExtendedList: Router RouteExtendedList: Router
wasteRecalc: Waste recaclulate wasteRecalc: Waste recaclulate
operator: Operator operator: Operator
parking: Parking
supplier: Supplier supplier: Supplier
created: Created created: Created
worker: Worker worker: Worker
@ -663,8 +664,6 @@ parking:
sector: Sector sector: Sector
row: Row row: Row
column: Column column: Column
pageTitles:
parking: Parking
searchBar: searchBar:
info: You can search by parking code info: You can search by parking code
label: Search parking... label: Search parking...

View File

@ -282,6 +282,7 @@ globals:
medical: Mutua medical: Mutua
wasteRecalc: Recalcular mermas wasteRecalc: Recalcular mermas
operator: Operario operator: Operario
parking: Parking
supplier: Proveedor supplier: Proveedor
created: Fecha creación created: Fecha creación
worker: Trabajador worker: Trabajador
@ -710,8 +711,6 @@ parking:
pickingOrder: Orden de recogida pickingOrder: Orden de recogida
row: Fila row: Fila
column: Columna column: Columna
pageTitles:
parking: Parking
searchBar: searchBar:
info: Puedes buscar por código de parking info: Puedes buscar por código de parking
label: Buscar parking... label: Buscar parking...

View File

@ -40,6 +40,12 @@ const itemFilter = {
fields: ['id', 'name'], fields: ['id', 'name'],
}, },
}, },
{
relation: 'production',
scope: {
fields: ['id', 'name'],
},
},
], ],
}; };
const columns = computed(() => [ const columns = computed(() => [
@ -161,19 +167,13 @@ const columns = computed(() => [
name: 'intrastat', name: 'intrastat',
align: 'left', align: 'left',
component: 'select', component: 'select',
attrs: {
url: 'Intrastats',
optionValue: 'description',
optionLabel: 'description',
},
columnFilter: { columnFilter: {
name: 'description', name: 'intrastat',
attrs: { attrs: {
url: 'Intrastats', url: 'Intrastats',
optionValue: 'description', optionValue: 'description',
optionLabel: 'description', optionLabel: 'description',
}, },
alias: 'intr',
}, },
columnField: { columnField: {
component: null, component: null,
@ -211,14 +211,19 @@ const columns = computed(() => [
label: t('item.list.userName'), label: t('item.list.userName'),
name: 'userName', name: 'userName',
align: 'left', align: 'left',
component: 'select',
columnFilter: { columnFilter: {
name: 'workerFk', name: 'workerFk',
attrs: { attrs: {
url: 'Users', url: 'VnUsers/preview',
optionValue: 'id', optionValue: 'id',
optionLabel: 'userName', optionLabel: 'nickname',
}, },
}, },
columnField: {
component: null,
},
}, },
{ {
label: t('item.list.weightByPiece'), label: t('item.list.weightByPiece'),
@ -255,9 +260,13 @@ const columns = computed(() => [
name: 'producer', name: 'producer',
align: 'left', align: 'left',
component: 'select', component: 'select',
columnFilter: {
name: 'producerFk',
attrs: { attrs: {
url: 'Producers', url: 'Producers',
fields: ['id', 'name'], optionValue: 'id',
optionLabel: 'name',
},
}, },
columnField: { columnField: {
component: null, component: null,
@ -331,7 +340,7 @@ const columns = computed(() => [
<template #column-userName="{ row }"> <template #column-userName="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.userName }} {{ row.userName }}
<WorkerDescriptorProxy :id="row.buyerFk" /> <WorkerDescriptorProxy :id="row.workerFk" />
</span> </span>
</template> </template>
<template #column-description="{ row }"> <template #column-description="{ row }">

View File

@ -70,6 +70,18 @@ const columns = computed(() => [
{ {
label: t('item.buyRequest.requester'), label: t('item.buyRequest.requester'),
name: 'requesterName', name: 'requesterName',
component: 'select',
columnFilter: {
name: 'requesterFk',
attrs: {
url: 'VnUsers/preview',
optionValue: 'id',
optionLabel: 'nickname',
},
},
columnField: {
component: null,
},
columnClass: 'shrink', columnClass: 'shrink',
}, },
{ {
@ -88,6 +100,18 @@ const columns = computed(() => [
label: t('item.buyRequest.attender'), label: t('item.buyRequest.attender'),
name: 'attenderName', name: 'attenderName',
align: 'left', align: 'left',
component: 'select',
columnFilter: {
name: 'attenderFk',
attrs: {
url: 'VnUsers/preview',
optionValue: 'id',
optionLabel: 'nickname',
},
},
columnField: {
component: null,
},
columnClass: 'shrink', columnClass: 'shrink',
}, },
{ {

View File

@ -2,17 +2,11 @@
import VnCard from 'components/common/VnCard.vue'; import VnCard from 'components/common/VnCard.vue';
import ParkingDescriptor from 'pages/Parking/Card/ParkingDescriptor.vue'; import ParkingDescriptor from 'pages/Parking/Card/ParkingDescriptor.vue';
import ParkingFilter from 'pages/Parking/ParkingFilter.vue'; import ParkingFilter from 'pages/Parking/ParkingFilter.vue';
const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder', 'row', 'column'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
};
</script> </script>
<template> <template>
<VnCard <VnCard
data-key="Parking" data-key="Parking"
base-url="Parkings" base-url="Parkings"
:filter="filter"
:descriptor="ParkingDescriptor" :descriptor="ParkingDescriptor"
:filter-panel="ParkingFilter" :filter-panel="ParkingFilter"
search-data-key="ParkingList" search-data-key="ParkingList"

View File

@ -29,6 +29,7 @@ const filter = {
:url="`Parkings/${entityId}`" :url="`Parkings/${entityId}`"
title="code" title="code"
:filter="filter" :filter="filter"
:to-module="{ name: 'ParkingList' }"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('globals.code')" :value="entity.code" /> <VnLv :label="t('globals.code')" :value="entity.code" />

View File

@ -22,7 +22,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
const filter = { const filter = {
fields: ['id', 'sectorFk', 'code', 'pickingOrder'], fields: ['id', 'sectorFk', 'code', 'pickingOrder'],
include: [{ relation: 'sector', scope: { fields: ['id', 'description'] } }],
}; };
function exprBuilder(param, value) { function exprBuilder(param, value) {
@ -55,10 +54,9 @@ function exprBuilder(param, value) {
<VnPaginate <VnPaginate
data-key="ParkingList" data-key="ParkingList"
url="Parkings" url="Parkings"
:filter="filter" :user-filter="filter"
:expr-builder="exprBuilder" :expr-builder="exprBuilder"
:limit="20" :limit="20"
auto-load
order="code" order="code"
> >
<template #body="{ rows }"> <template #body="{ rows }">

View File

@ -2,6 +2,7 @@
import { onMounted, ref, computed, onUnmounted, watch } from 'vue'; import { onMounted, ref, computed, onUnmounted, watch } 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 FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
@ -23,6 +24,7 @@ import useNotify from 'src/composables/useNotify.js';
import axios from 'axios'; import axios from 'axios';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnUsesMana from 'src/components/ui/VnUsesMana.vue'; import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -32,7 +34,7 @@ const { notify } = useNotify();
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const editPriceProxyRef = ref(null); const editPriceProxyRef = ref(null);
const stateBtnDropdownRef = ref(null); const stateBtnDropdownRef = ref(null);
const quasar = useQuasar();
const arrayData = useArrayData('ticketData'); const arrayData = useArrayData('ticketData');
const { store } = arrayData; const { store } = arrayData;
const selectedRows = ref([]); const selectedRows = ref([]);
@ -51,6 +53,7 @@ const transfer = ref({
sales: [], sales: [],
}); });
const tableRef = ref([]); const tableRef = ref([]);
const canProceed = ref();
watch( watch(
() => route.params.id, () => route.params.id,
@ -214,7 +217,9 @@ const addSale = async (sale) => {
} }
}; };
const changeQuantity = (sale) => { const changeQuantity = async (sale) => {
canProceed.value = await isSalePrepared(sale);
if (!canProceed.value) return;
if ( if (
!sale.itemFk || !sale.itemFk ||
sale.quantity == null || sale.quantity == null ||
@ -226,6 +231,8 @@ const changeQuantity = (sale) => {
}; };
const updateConcept = async (sale) => { const updateConcept = async (sale) => {
canProceed.value = await isSalePrepared(sale);
if (!canProceed.value) return;
try { try {
const data = { newConcept: sale.concept }; const data = { newConcept: sale.concept };
await axios.post(`Sales/${sale.id}/updateConcept`, data); await axios.post(`Sales/${sale.id}/updateConcept`, data);
@ -286,6 +293,8 @@ const onOpenEditDiscountPopover = async (sale) => {
}; };
const updatePrice = async (sale) => { const updatePrice = async (sale) => {
canProceed.value = await isSalePrepared(sale);
if (!canProceed.value) return;
try { try {
const newPrice = edit.value.price; const newPrice = edit.value.price;
if (newPrice != null && newPrice != sale.price) { if (newPrice != null && newPrice != sale.price) {
@ -300,12 +309,18 @@ const updatePrice = async (sale) => {
} }
}; };
const changeDiscount = (sale) => { const changeDiscount = async (sale) => {
canProceed.value = await isSalePrepared(sale);
if (!canProceed.value) return;
const newDiscount = edit.value.discount; const newDiscount = edit.value.discount;
if (newDiscount != null && newDiscount != sale.discount) updateDiscount([sale]); if (newDiscount != null && newDiscount != sale.discount) updateDiscount([sale]);
}; };
const updateDiscount = async (sales, newDiscount = null) => { const updateDiscount = async (sales, newDiscount = null) => {
for (const sale of sales) {
const canProceed = await isSalePrepared(sale);
if (!canProceed) return;
}
const saleIds = sales.map((sale) => sale.id); const saleIds = sales.map((sale) => sale.id);
const _newDiscount = newDiscount || edit.value.discount; const _newDiscount = newDiscount || edit.value.discount;
const params = { const params = {
@ -433,7 +448,9 @@ onUnmounted(() => (stateStore.rightDrawer = false));
const items = ref([]); const items = ref([]);
const newRow = ref({}); const newRow = ref({});
const updateItem = (row) => { const updateItem = async (row) => {
canProceed.value = await isSalePrepared(row);
if (!canProceed.value) return;
const selectedItem = items.value.find((item) => item.id === row.itemFk); const selectedItem = items.value.find((item) => item.id === row.itemFk);
if (selectedItem) { if (selectedItem) {
row.item = selectedItem; row.item = selectedItem;
@ -476,6 +493,55 @@ const endNewRow = (row) => {
} }
}; };
async function isSalePrepared(item) {
const filter = {
params: {
where: { ticketFk: route.params.id },
order: ['concept ASC', 'quantity DESC'],
},
};
const { data } = await axios.get(`SaleTrackings/${route.params.id}/filter`, {
params: {
filter: JSON.stringify(filter),
},
});
const matchingSale = data.find((sale) => sale.itemFk === item.itemFk);
if (!matchingSale) {
return true;
}
if (
matchingSale.hasSaleGroupDetail ||
matchingSale.isControled ||
matchingSale.isPrepared ||
matchingSale.isPrevious ||
matchingSale.isPreviousSelected
) {
try {
await new Promise((resolve, reject) => {
quasar
.dialog({
component: VnConfirm,
componentProps: {
title: t('Item prepared'),
message: t(
'This item is already prepared. Do you want to continue?'
),
data: item,
},
})
.onOk(() => resolve(true))
.onCancel(() => reject(new Error('cancelled')));
});
} catch (error) {
tableRef.value.reload();
return false;
}
}
return true;
}
watch( watch(
() => newRow.value.itemFk, () => newRow.value.itemFk,
(newItemFk) => { (newItemFk) => {
@ -821,4 +887,6 @@ es:
You are going to delete lines of the ticket: Vas a eliminar lineas del ticket You are going to delete lines of the ticket: Vas a eliminar lineas del ticket
Add item: Añadir artículo Add item: Añadir artículo
Transfer lines: Transferir líneas Transfer lines: Transferir líneas
Item prepared: Artículo preparado
This item is already prepared. Do you want to continue?: Este artículo ya esta preparado. Desea continuar?
</i18n> </i18n>

View File

@ -1,5 +1,6 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
describe('ParkingList', () => { describe('ParkingList', () => {
const searchbar = '#searchbar input';
const firstCard = '.q-card:nth-child(1)'; const firstCard = '.q-card:nth-child(1)';
const firstChipId = const firstChipId =
':nth-child(1) > :nth-child(1) > .justify-between > .flex > .q-chip > .q-chip__content'; ':nth-child(1) > :nth-child(1) > .justify-between > .flex > .q-chip > .q-chip__content';
@ -14,6 +15,7 @@ describe('ParkingList', () => {
}); });
it('should redirect on clicking a parking', () => { it('should redirect on clicking a parking', () => {
cy.get(searchbar).type('{enter}');
cy.get(firstChipId) cy.get(firstChipId)
.invoke('text') .invoke('text')
.then((content) => { .then((content) => {
@ -24,6 +26,7 @@ describe('ParkingList', () => {
}); });
it('should open the details', () => { it('should open the details', () => {
cy.get(searchbar).type('{enter}');
cy.get(firstDetailBtn).click(); cy.get(firstDetailBtn).click();
cy.get(summaryHeader).contains('Basic data'); cy.get(summaryHeader).contains('Basic data');
}); });