#6321 - Negative ticket #158

Open
jsegarra wants to merge 197 commits from 6321_negative_tickets into dev
8 changed files with 131 additions and 114 deletions
Showing only changes of commit 85a0e328e3 - Show all commits

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n'; import { ref } from 'vue';
const { t } = useI18n();
const $props = defineProps({ defineProps({
icon: { icon: {
type: String, type: String,
default: 'refresh', default: 'refresh',
@ -19,16 +19,17 @@ const $props = defineProps({
default: 'primary', default: 'primary',
}, },
}); });
const popupProxyRef = ref(null);
</script> </script>
<template> <template>
<QBtn :color="$props.color" :icon="$props.icon" :label="t($props.label)"> <QBtn :color="$props.color" :icon="$props.icon" :label="$t($props.label)">
<QPopupProxy ref="popupProxyRef" style="max-width: none"> <QPopupProxy ref="popupProxyRef" style="max-width: none">
Review

Contenedor para QPopupProxy con mas personalziación

Contenedor para QPopupProxy con mas personalziación
<QCard> <QCard>
<slot></slot> <slot :popup="popupProxyRef"></slot>
</QCard> </QCard>
</QPopupProxy> </QPopupProxy>
<QTooltip>{{ t($props.tooltip) }}</QTooltip> <QTooltip>{{ $t($props.tooltip) }}</QTooltip>
</QBtn> </QBtn>
</template> </template>

View File

@ -1,23 +1,21 @@
<script setup> <script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue'; import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import ChangeQuantityDialog from 'pages/Ticket/Negative/components/ChangeQuantityDialog.vue'; import ChangeQuantityDialog from './components/ChangeQuantityDialog.vue';
import ChangeStateDialog from 'pages/Ticket/Negative/components/ChangeStateDialog.vue'; import ChangeStateDialog from './components/ChangeStateDialog.vue';
import ChangeItemDialog from 'pages/Ticket/Negative/components/ChangeItemDialog.vue'; import ChangeItemDialog from './components/ChangeItemDialog.vue';
import FetchedTags from 'components/ui/FetchedTags.vue'; import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import TicketTransfer from '../Card/TicketTransfer.vue'; import TicketTransfer from '../Card/TicketTransfer.vue';
import TicketMassiveUpdate from '../Card/TicketMassiveUpdate.vue';
import VnPaginate from 'src/components/ui/VnPaginate.vue'; import VnPaginate from 'src/components/ui/VnPaginate.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
// import { useArrayData } from 'src/composables/useArrayData';
import VnImg from 'src/components/ui/VnImg.vue'; import VnImg from 'src/components/ui/VnImg.vue';
import TicketLackTable from './TicketLackTable.vue'; import TicketLackTable from './TicketLackTable.vue';
import ItemProposalProxy from 'src/pages/Item/components/ItemProposalProxy.vue'; import ItemProposalProxy from 'src/pages/Item/components/ItemProposalProxy.vue';
import { toCurrency } from 'filters/index'; import VnPopupProxy from 'src/components/common/VnPopupProxy.vue';
const { t } = useI18n(); const { t } = useI18n();
const URL_KEY = 'Tickets/ItemLack'; const URL_KEY = 'Tickets/ItemLack';
@ -25,9 +23,9 @@ const editableStates = ref([]);
const stateStore = useStateStore(); const stateStore = useStateStore();
const proposalDialogRef = ref(); const proposalDialogRef = ref();
const tableRef = ref(); const tableRef = ref();
const changeItemDialogRef = ref(); const changeItemDialogRef = ref(null);
const changeStateDialogRef = ref(); const changeStateDialogRef = ref(null);
const changeQuantityDialogRef = ref(); const changeQuantityDialogRef = ref(null);
const showProposalDialog = ref(false); const showProposalDialog = ref(false);
const showChangeQuantityDialog = ref(false); const showChangeQuantityDialog = ref(false);
const showFree = ref(true); const showFree = ref(true);
@ -109,6 +107,11 @@ function onBuysFetched(data) {
function onTicketLackFetched(data) { function onTicketLackFetched(data) {
itemLack.value = data[0]; itemLack.value = data[0];
} }
const closeDialogs = (refs, evt) => {
changeItemDialogRef.value.hide();
changeQuantityDialogRef.value.hide();
changeStateDialogRef.value.hide();
};
</script> </script>
<template> <template>
@ -139,42 +142,43 @@ function onTicketLackFetched(data) {
<VnSubToolbar> <VnSubToolbar>
<template #st-data> <template #st-data>
<QBtnGroup push style="column-gap: 1px"> <QBtnGroup push style="column-gap: 1px">
{{ selectedRows.length }} <VnPopupProxy
<TicketMassiveUpdate
:disable="selectedRows.length < 1" :disable="selectedRows.length < 1"
:label="t('negative.buttonsUpdate.item')" :label="t('negative.buttonsUpdate.item')"
:tooltip="t('negative.detail.modal.changeItem.title')" :tooltip="t('negative.detail.modal.changeItem.title')"
> >
<ChangeItemDialog <template v-slot="{ popup }">
ref="changeItemDialogRef" <ChangeItemDialog
@update-item="changeItemDialogRef.hide()" ref="changeItemDialogRef"
:selected-rows="selectedRows" @update-item="popup.hide()"
></ChangeItemDialog> :selected-rows="selectedRows"
</TicketMassiveUpdate> /></template>
<TicketMassiveUpdate </VnPopupProxy>
<VnPopupProxy
:disable="selectedRows.length < 1" :disable="selectedRows.length < 1"
:label="t('negative.buttonsUpdate.state')" :label="t('negative.buttonsUpdate.state')"
:tooltip="t('negative.detail.modal.changeState.title')" :tooltip="t('negative.detail.modal.changeState.title')"
> >
<ChangeStateDialog <template v-slot="{ popup }">
ref="changeStateDialogRef" <ChangeStateDialog
@update-state="changeStateDialogRef.hide()" ref="changeStateDialogRef"
:selected-rows="selectedRows" @update-state="popup.hide()"
></ChangeStateDialog> :selected-rows="selectedRows"
</TicketMassiveUpdate> /></template>
<TicketMassiveUpdate </VnPopupProxy>
<VnPopupProxy
:disable="selectedRows.length < 1" :disable="selectedRows.length < 1"
:label="t('negative.buttonsUpdate.quantity')" :label="t('negative.buttonsUpdate.quantity')"
:tooltip="t('negative.detail.modal.changeQuantity.title')" :tooltip="t('negative.detail.modal.changeQuantity.title')"
@click="showChangeQuantityDialog = true" @click="showChangeQuantityDialog = true"
> >
<ChangeQuantityDialog <template v-slot="{ popup }">
ref="changeQuantityDialogRef" <ChangeQuantityDialog
@update-quantity="changeQuantityDialogRef.hide()" ref="changeQuantityDialogRef"
:selected-rows="selectedRows" @update-quantity="popup.hide()"
> :selected-rows="selectedRows"
</ChangeQuantityDialog> /></template>
</TicketMassiveUpdate> </VnPopupProxy>
<QBtn <QBtn
color="primary" color="primary"
icon="vn:splitline" icon="vn:splitline"
@ -223,13 +227,7 @@ function onTicketLackFetched(data) {
<template #body> <template #body>
<div style="display: flex; align-items: center"> <div style="display: flex; align-items: center">
<VnImg :id="item.id" class="rounded image-wrapper"></VnImg> <VnImg :id="item.id" class="rounded image-wrapper"></VnImg>
<div <div class="flex column" style="align-items: center">
style="
display: flex;
align-items: center;
flex-direction: column;
"
>
<QBadge <QBadge
ref="badgeLackRef" ref="badgeLackRef"
class="q-ml-xs" class="q-ml-xs"
@ -238,19 +236,14 @@ function onTicketLackFetched(data) {
:color="itemLack.lack === 0 ? 'green' : 'red'" :color="itemLack.lack === 0 ? 'green' : 'red'"
:label="itemLack.lack" :label="itemLack.lack"
/> />
<!-- <QBadge
color="secondary"
class="q-ml-xs q-mt-xs"
v-if="itemLack"
:label="toCurrency(itemLack.quantity * itemLack.price)"
outline
/> -->
</div> </div>
<QBtn flat class="link text-blue"> <div class="flex column left" style="align-items: flex-start">
{{ item.longName }} <QBtn flat class="link text-blue">
<ItemDescriptorProxy :id="entityId" /> {{ item?.longName ?? item.name }}
</QBtn> <ItemDescriptorProxy :id="entityId" />
<FetchedTags class="q-ml-md" :item="item" :columns="3" /> </QBtn>
<FetchedTags class="q-ml-md" :item="item" :columns="7" />
</div>
</div> </div>
</template> </template>
</VnPaginate> </VnPaginate>

View File

@ -23,7 +23,7 @@ watch(
(v) => { (v) => {
filterLack.value.where = v; filterLack.value.where = v;
tableRef.value.reload(filterLack); tableRef.value.reload(filterLack);
} },
); );
const filterLack = ref({ const filterLack = ref({
@ -78,8 +78,38 @@ const saveChange = async (field, { rowIndex, row }) => {
}; };
const entityId = computed(() => route.params.id); const entityId = computed(() => route.params.id);
const item = ref({}); const item = ref({});
const rowColor = (row) => {
if (!row.hasToIgnore) return 'negative';
return 'transparent';
};
// const textRowColor = (row) => {
// if (row.hasToIgnore) return 'black';
// return 'white';
// };
const columns = computed(() => [ const columns = computed(() => [
{
align: 'left',
label: t('negative.detail.isBasket'),
name: 'isBasket',
cardVisible: true,
create: true,
component: 'checkbox',
attrs: ({ row }) => {
return {
'toggle-indeterminate': true,
};
},
columnClass: 'shrink',
},
{
align: 'left',
label: t('negative.detail.hasSubstitution'),
name: 'hasSubstitution',
cardVisible: true,
create: true,
component: 'checkbox',
columnClass: 'shrink',
},
{ {
name: 'status', name: 'status',
align: 'left', align: 'left',
@ -139,19 +169,6 @@ const columns = computed(() => [
align: 'left', align: 'left',
sortable: true, sortable: true,
// columnFilter: {
// columnField: {
// component: 'select',
// event: getInputEvents,
// attrs: {
// event: (v) => console.error(v),
// options: editableStates.value,
// 'option-value': 'id',
// 'option-label': 'name',
// // },
// },
// },
}, },
{ {
name: 'zoneName', name: 'zoneName',
@ -177,13 +194,7 @@ const columns = computed(() => [
type: 'number', type: 'number',
}, },
]); ]);
const itemLackForm = ref();
const reload = async (data) => {
// window.location.reload();
console.error(data);
};
defineExpose({ reload });
const emit = defineEmits(['update:selection']); const emit = defineEmits(['update:selection']);
const tableRef = ref(null); const tableRef = ref(null);
@ -291,8 +302,10 @@ function onTicketLackFetched(data) {
</QIcon></QTd </QIcon></QTd
> >
</template> </template>
<template #column-ticketFk="{ row }" <template #column-ticketFk="{ row }">
><span class="link">{{ row.ticketFk }}</span> <QBadge class="q-pa-sm" :color="rowColor(row)">
{{ row.ticketFk }}
</QBadge>
<TicketDescriptorProxy :id="row.ticketFk" <TicketDescriptorProxy :id="row.ticketFk"
/></template> /></template>
<template #column-zoneName="{ row }"> <template #column-zoneName="{ row }">

View File

@ -3,10 +3,8 @@ import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
const emit = defineEmits(['update-item']); const emit = defineEmits(['update-item']);
const editableItems = ref([]);
const { t } = useI18n(); const { t } = useI18n();
const showChangeItemDialog = ref(false); const showChangeItemDialog = ref(false);
const newItem = ref(null); const newItem = ref(null);
@ -16,31 +14,29 @@ const $props = defineProps({
default: () => [], default: () => [],
}, },
}); });
const updateItem = async () => { const updateItem = async () => {
try { try {
showChangeItemDialog.value = true; showChangeItemDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ ticketFk }) => const rowsToUpdate = $props.selectedRows.map(({ saleFk }) =>
axios.post(`Tickets/state`, { axios.post(`Sales/${saleFk}/updateConcept`, {
ticketFk, newConcept: newItem.value,
code: newItem.value, }),
})
); );
await Promise.all(rowsToUpdate); await Promise.allSettled(rowsToUpdate);
emit('update-item');
emit('update-item', newItem.value);
} catch (err) { } catch (err) {
console.error('Error updating item:', err);
return err; return err;
} }
}; };
</script> </script>
<template> <template>
<FetchData
url="State/editableStates"
@on-fetch="(data) => (editableItems = data)"
auto-load
/>
<QCard class="q-pa-sm"> <QCard class="q-pa-sm">
<QCardSection class="row items-center justify-center column items-stretch"> <QCardSection class="row items-center justify-center column items-stretch">
{{ showChangeItemDialog }}
<span>{{ t('negative.detail.modal.changeItem.title') }}</span> <span>{{ t('negative.detail.modal.changeItem.title') }}</span>
<VnSelect <VnSelect
url="Items/WithName" url="Items/WithName"
@ -50,7 +46,6 @@ const updateItem = async () => {
option-label="name" option-label="name"
option-value="id" option-value="id"
v-model="newItem" v-model="newItem"
@update:model-value="updateItem(row)"
> >
</VnSelect> </VnSelect>
</QCardSection> </QCardSection>
@ -75,7 +70,9 @@ const updateItem = async () => {
} }
.grid-style-transition { .grid-style-transition {
transition: transform 0.28s, background-color 0.28s; transition:
transform 0.28s,
background-color 0.28s;
} }
#true { #true {

View File

@ -15,16 +15,17 @@ const $props = defineProps({
}); });
const emit = defineEmits(['update-quantity']); const emit = defineEmits(['update-quantity']);
const updateQuantity = async () => { const updateQuantity = async () => {
showChangeQuantityDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ saleFk }) =>
axios.post(`Sales/${saleFk}/updateQuantity`, {
quantity: +newQuantity.value,
})
);
try { try {
await Promise.all(rowsToUpdate); showChangeQuantityDialog.value = true;
emit('update-quantity'); const rowsToUpdate = $props.selectedRows.map(({ saleFk }) =>
axios.post(`Sales/${saleFk}/updateQuantity`, {
quantity: +newQuantity.value,
}),
);
const results = await Promise.allSettled(rowsToUpdate);
console.log(results);
emit('update-quantity', newQuantity.value);
} catch (err) { } catch (err) {
return err; return err;
} }
@ -63,7 +64,9 @@ const updateQuantity = async () => {
} }
.grid-style-transition { .grid-style-transition {
transition: transform 0.28s, background-color 0.28s; transition:
transform 0.28s,
background-color 0.28s;
} }
#true { #true {

View File

@ -23,10 +23,11 @@ const updateState = async () => {
axios.post(`Tickets/state`, { axios.post(`Tickets/state`, {
ticketFk, ticketFk,
code: newState.value, code: newState.value,
}) }),
); );
await Promise.all(rowsToUpdate); const results = await Promise.allSettled(rowsToUpdate);
emit('update-state'); console.log(results);
emit('update-state', newState.value);
} catch (err) { } catch (err) {
return err; return err;
} }
@ -71,7 +72,9 @@ const updateState = async () => {
} }
.grid-style-transition { .grid-style-transition {
transition: transform 0.28s, background-color 0.28s; transition:
transform 0.28s,
background-color 0.28s;
} }
#true { #true {

View File

@ -238,16 +238,18 @@ negative:
isRookie: 'Is rookie' isRookie: 'Is rookie'
turno: 'Turn line' turno: 'Turn line'
showFree: Show Free lines showFree: Show Free lines
isBasket: 'Basket'
hasSubstitution: 'Has substitution'
modal: modal:
changeItem:
title: Update item reference
placeholder: New item
changeState: changeState:
title: Update tickets state title: Update tickets state
placeholder: New state placeholder: New state
changeQuantity: changeQuantity:
title: Update tickets quantity title: Update tickets quantity
placeholder: New quantity placeholder: New quantity
changeItem:
title: Update tickets item
placeholder: New item
split: split:
title: Are you sure you want to split selected tickets? title: Are you sure you want to split selected tickets?
subTitle: Confirm split action subTitle: Confirm split action

View File

@ -239,7 +239,7 @@ negative:
totalNegative: 'Total negativos' totalNegative: 'Total negativos'
days: Rango de dias days: Rango de dias
buttonsUpdate: buttonsUpdate:
itemProposal: artículo item: artículo
state: Estado state: Estado
quantity: Cantidad quantity: Cantidad
modalOrigin: modalOrigin:
@ -266,7 +266,12 @@ negative:
isRookie: 'Cliente nuevo' isRookie: 'Cliente nuevo'
turno: 'Linea turno' turno: 'Linea turno'
showFree: Solo estado libre showFree: Solo estado libre
isBasket: 'Cesta'
hasSubstitution: 'Tiene sustitución'
modal: modal:
changeItem:
title: Actualizar referencia artículo
placeholder: Nuevo articulo
changeState: changeState:
title: Actualizar estado title: Actualizar estado
placeholder: Nuevo estado placeholder: Nuevo estado