feat: 6321_fix_ticketNegative

This commit is contained in:
Javier Segarra 2025-03-02 22:07:28 +01:00
parent 3b88f5e5cf
commit c5f83d43f6
21 changed files with 618 additions and 213 deletions

View File

@ -0,0 +1,31 @@
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
export function showResultsAsTable() {
const quasar = useQuasar();
const { t } = useI18n();
function openTable(dialog, results, tag, action, title) {
quasar.notify({
message: t('bulkEdit.completed'),
color: 'positive',
actions: [
{
label: t('bulkEdit.openTable'),
color: 'white',
handler: () => {
quasar.dialog({
component: dialog,
componentProps: {
title,
results,
tag,
action,
},
});
},
},
],
});
}
return { openTable };
}

View File

@ -11,7 +11,7 @@ const $props = defineProps({
</script>
<template>
<QPopupProxy>
<QPopupProxy data-cy="customerDescriptorProxy">
<CustomerDescriptor v-if="$props.id" :id="$props.id" :summary="CustomerSummary" />
</QPopupProxy>
</template>

View File

@ -22,7 +22,7 @@ const $props = defineProps({
});
</script>
<template>
<QPopupProxy style="max-width: 10px">
<QPopupProxy style="max-width: 10px" data-cy="itemDescriptorProxy">
<ItemDescriptor
v-if="$props.id"
:id="$props.id"

View File

@ -6,9 +6,10 @@ import { toCurrency } from 'filters/index';
import VnStockValueDisplay from 'src/components/ui/VnStockValueDisplay.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
import axios from 'axios';
import notifyResults from 'src/utils/notifyResults';
import { showResultsAsTable } from 'src/composables/showResultsTable';
import FetchData from 'components/FetchData.vue';
const { openTable } = showResultsAsTable();
import HandleSplitDialog from 'src/pages/Ticket/Negative/components/HandleSplitDialog.vue';
const MATCH = 'match';
const { t } = useI18n();
@ -32,7 +33,10 @@ const $props = defineProps({
const proposalSelected = ref([]);
const ticketConfig = ref({});
const proposalTableRef = ref(null);
const isLoading = ref(true);
const filterTicketConfig = {
fields: ['lackAlertPrice'],
};
const sale = computed(() => $props.sales[0]);
const saleFk = computed(() => sale.value.saleFk);
const filter = computed(() => ({
@ -77,7 +81,7 @@ const columns = computed(() => [
},
{
align: 'left',
align: 'center',
sortable: true,
label: t('proposal.longName'),
name: 'longName',
@ -85,7 +89,7 @@ const columns = computed(() => [
columnClass: 'expand',
},
{
align: 'left',
align: 'center',
sortable: true,
label: t('item.list.color'),
name: 'tag5',
@ -93,7 +97,7 @@ const columns = computed(() => [
columnClass: 'expand',
},
{
align: 'left',
align: 'center',
sortable: true,
label: t('item.list.stems'),
name: 'tag6',
@ -101,7 +105,7 @@ const columns = computed(() => [
columnClass: 'expand',
},
{
align: 'left',
align: 'center',
sortable: true,
label: t('item.list.producer'),
name: 'tag7',
@ -197,9 +201,10 @@ const isSelectionAvailable = (itemProposal) => {
async function change({ itemFk: substitutionFk }) {
try {
const promises = $props.sales.map(({ saleFk, quantity }) => {
const promises = $props.sales.map(({ saleFk, quantity, ticketFk }) => {
const params = {
saleFk,
ticketFk,
substitutionFk,
quantity,
};
@ -207,10 +212,9 @@ async function change({ itemFk: substitutionFk }) {
});
const results = await Promise.allSettled(promises);
notifyResults(results, 'saleFk');
openTable(HandleSplitDialog, results, 'ticketFk', 'changeItem');
emit('itemReplaced', {
type: 'refresh',
quantity: quantity.value,
itemProposal: proposalSelected.value[0],
});
proposalSelected.value = [];
@ -221,18 +225,20 @@ async function change({ itemFk: substitutionFk }) {
async function handleTicketConfig(data) {
ticketConfig.value = data[0];
isLoading.value = false;
}
</script>
<template>
<FetchData
url="TicketConfigs"
:filter="{ fields: ['lackAlertPrice'] }"
@on-fetch="handleTicketConfig"
:filter="filterTicketConfig"
auto-load
/>
@on-fetch="handleTicketConfig"
></FetchData>
<QSpinner v-if="isLoading" color="primary" size="md"></QSpinner>
<VnTable
v-if="ticketConfig"
v-else
auto-load
data-cy="proposalTable"
ref="proposalTableRef"
@ -242,7 +248,7 @@ async function handleTicketConfig(data) {
:columns="columns"
class="full-width q-mt-md"
row-key="id"
:row-click="change"
redirect="false"
:is-editable="false"
:right-search="false"
:without-header="true"
@ -260,10 +266,10 @@ async function handleTicketConfig(data) {
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
</div>
<div style="flex: 2 0 100%; align-content: center">
<div>
<span class="link">{{ row.longName }}</span>
<ItemDescriptorProxy :id="row.id" />
</div>
<span class="link" @click.stop>
{{ row.longName }}
<ItemDescriptorProxy :id="row.itemFk" />
</span>
</div>
</QTd>
</template>

View File

@ -19,16 +19,18 @@ const $props = defineProps({
default: () => [],
},
});
const { dialogRef } = useDialogPluginComponent();
const emit = defineEmits([
'onDialogClosed',
'itemReplaced',
...useDialogPluginComponent.emits,
]);
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent();
const emit = defineEmits(['onDialogClosed', ...useDialogPluginComponent.emits]);
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
</script>
<template>
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
<QDialog
ref="dialogRef"
transition-show="scale"
transition-hide="scale"
@hide="onDialogHide"
>
<QCard class="dialog-width">
<QCardSection class="row items-center q-pb-none">
<span class="text-h6 text-grey">{{ $t('Item proposal') }}</span>
@ -39,8 +41,8 @@ defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.h
<ItemProposal
v-bind="$props"
@item-replaced="
(data) => {
emit('itemReplaced', data);
() => {
emit('onDialogClosed', true);
dialogRef.hide();
}
"

View File

@ -44,6 +44,7 @@ function ticketFilter(ticket) {
@on-fetch="(data) => ([problems] = data)"
/>
<CardDescriptor
:id="entityId"
:url="`Tickets/${entityId}`"
:filter="filter"
data-key="Ticket"

View File

@ -10,7 +10,7 @@ const $props = defineProps({
});
</script>
<template>
<QPopupProxy>
<QPopupProxy data-cy="ticketDescriptorProxy">
<TicketDescriptor v-if="$props.id" :id="$props.id" :summary="TicketSummary" />
</QPopupProxy>
</template>

View File

@ -2,7 +2,7 @@
import { ref } from 'vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import split from './components/split';
import { splitTicket } from './components/split';
const emit = defineEmits(['ticketTransfered']);
const $props = defineProps({
@ -12,6 +12,8 @@ const $props = defineProps({
},
});
const { split } = splitTicket();
const splitDate = ref(Date.vnNew());
const splitSelectedRows = async () => {

View File

@ -0,0 +1,112 @@
<script setup>
import TicketProblems from 'src/components/TicketProblems.vue';
import FetchedTags from 'src/components/ui/FetchedTags.vue';
import { dashIfEmpty, toDate, toCurrency } from 'src/filters';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import { ref } from 'vue';
const props = defineProps({
sales: {
type: Array,
required: true,
},
ticket: {
type: Object,
required: true,
},
});
const sales = ref(props?.sales);
</script>
<template>
<QTable v-if="sales" :rows="sales" style="text-align: center">
<template #body-cell="{ value }">
<QTd>{{ value }}</QTd>
</template>
<template #header="props">
<QTr class="tr-header" :props="props">
<QTh auto-width></QTh>
<QTh auto-width>{{ $t('globals.item') }}</QTh>
<QTh auto-width>{{ $t('globals.visible') }}</QTh>
<QTh auto-width>{{ $t('ticket.summary.available') }}</QTh>
<QTh auto-width>{{ $t('globals.quantity') }}</QTh>
<QTh auto-width>{{ $t('globals.description') }}</QTh>
<QTh auto-width>{{ $t('globals.price') }}</QTh>
<QTh auto-width>{{ $t('ticket.summary.discount') }}</QTh>
<QTh auto-width>{{ $t('globals.amount') }}</QTh>
<QTh auto-width>{{ $t('ticket.summary.packing') }}</QTh>
</QTr>
</template>
<template #body="props">
<QTr :props="props">
<QTd class="q-gutter-x-xs">
<TicketProblems :row="props.row" />
</QTd>
<QTd>
<QBtn class="link" flat>
{{ props.row.itemFk }}
<ItemDescriptorProxy
:id="props.row.itemFk"
:sale-fk="props.row.id"
:warehouse-fk="$props.ticket.warehouseFk"
/>
</QBtn>
</QTd>
<QTd>
<QChip
v-if="props.row.visible < 0"
dense
rounded
:color="'negative'"
text-color="white"
>
{{ props.row.visible }}
</QChip>
<span v-else>
{{ props.row.visible }}
</span>
</QTd>
<QTd>
<QChip
v-if="props.row.available < 0"
dense
rounded
:color="'negative'"
text-color="white"
>
{{ props.row.available }}
</QChip>
<span v-else>
{{ props.row.available }}
</span>
</QTd>
<QTd>{{ props.row.quantity }}</QTd>
<QTd class="description-cell">
<div class="row full-width justify-between">
{{ props.row.concept }}
<div v-if="props.row.item.subName" class="subName">
{{ props.row.item.subName.toUpperCase() }}
</div>
</div>
<FetchedTags
class="fetched-tags"
:item="props.row.item"
></FetchedTags>
</QTd>
<QTd>{{ props.row.price }} </QTd>
<QTd>{{ props.row.discount }} %</QTd>
<QTd
>{{
toCurrency(
props.row.quantity *
props.row.price *
((100 - props.row.discount) / 100),
)
}}
</QTd>
<QTd>{{ dashIfEmpty(props.row.item.itemPackingTypeFk) }}</QTd>
</QTr>
</template>
</QTable>
</template>

View File

@ -0,0 +1,42 @@
<script setup>
import FetchData from 'src/components/FetchData.vue';
import { dashIfEmpty, toDate, toCurrency } from 'src/filters';
import { ref } from 'vue';
import TicketSaleTable from './TicketSaleTable.vue';
const props = defineProps({
sales: {
type: Array,
required: true,
},
ticket: {
type: Number,
required: true,
},
});
const sales = ref(props?.sales);
</script>
<template>
<QDialog ref="dialogRef" full-width data-cy="ticketSaleTableDialog">
<FetchData
v-if="!sales"
:url="`Tickets/${$props.ticket}/getSales`"
@on-fetch="(data) => (sales = data)"
auto-load
></FetchData>
<QCard class="q-pa-sm">
<QCardSection class="row items-center q-pb-none">
<span class="text-h6 text-grey">{{
$t('ticket.summary.saleLines')
}}</span>
<QSpace />
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection>
<TicketSaleTable v-if="sales" :ticket="$props.ticket" :sales="sales" />
</QCardSection>
</QCard>
</QDialog>
</template>

View File

@ -1,22 +1,24 @@
import axios from 'axios';
import notifyResults from 'src/utils/notifyResults';
import { showResultsAsTable } from 'src/composables/showResultsTable';
import HandleSplitDialog from 'src/pages/Ticket/Negative/components/HandleSplitDialog.vue';
export function splitTicket() {
const { openTable } = showResultsAsTable();
export default async function (data, date) {
const reducedData = data.reduce((acc, item) => {
const existing = acc.find(({ ticketFk }) => ticketFk === item.id);
if (existing) {
existing.sales.push(item.saleFk);
} else {
acc.push({ ticketFk: item.id, sales: [item.saleFk], date });
}
return acc;
}, []);
async function split(data, date) {
const reducedData = data.reduce((acc, item) => {
const existing = acc.find(({ ticketFk }) => ticketFk === item.ticketFk);
if (existing) {
existing.sales.push(item.saleFk);
} else {
acc.push({ ticketFk: item.ticketFk, sales: [item.saleFk], landed: date });
}
return acc;
}, []);
const promises = reducedData.map((params) => axios.post(`Tickets/split`, params));
const promises = reducedData.map((params) => axios.post(`Tickets/split`, params));
const results = await Promise.allSettled(promises);
notifyResults(results, 'ticketFk');
return results;
const result = await Promise.allSettled(promises);
openTable(HandleSplitDialog, result, 'ticket', 'split');
}
return { split };
}

View File

@ -68,7 +68,8 @@ const showItemProposal = () => {
sales: selectedRows.value,
},
})
.onOk(itemProposalEvt);
.onOk(reload)
.onCancel(reload);
};
</script>
@ -146,7 +147,12 @@ const showItemProposal = () => {
<template v-slot="{ popup }">
<ChangeItemDialog
ref="changeItemDialogRef"
@update-item="popup.hide()"
@update-item="
() => {
popup.hide();
reload();
}
"
:selected-rows="selectedRows"
/></template>
</VnPopupProxy>
@ -160,7 +166,12 @@ const showItemProposal = () => {
<template v-slot="{ popup }">
<ChangeStateDialog
ref="changeStateDialogRef"
@update-state="popup.hide()"
@update-state="
() => {
popup.hide();
reload();
}
"
:selected-rows="selectedRows"
/></template>
</VnPopupProxy>
@ -175,7 +186,12 @@ const showItemProposal = () => {
<template v-slot="{ popup }">
<ChangeQuantityDialog
ref="changeQuantityDialogRef"
@update-quantity="popup.hide()"
@update-quantity="
() => {
popup.hide();
reload();
}
"
:selected-rows="selectedRows"
/></template>
</VnPopupProxy> </QBtnGroup

View File

@ -94,7 +94,7 @@ const setUserParams = (params) => {
<QItem>
<QItemSection>
<VnInput
v-model="params.id"
v-model="params.itemFk"
:label="t('negative.id')"
dense
is-outlined
@ -102,25 +102,6 @@ const setUserParams = (params) => {
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.producer"
:label="t('negative.producer')"
dense
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.origen"
:label="t('negative.origen')"
dense
is-outlined
/>
</QItemSection> </QItem
><QItem>
<QItemSection v-if="categoriesOptions">
<VnSelect
:label="t('negative.categoryFk')"

View File

@ -65,15 +65,19 @@ const columns = computed(() => [
columnFilter: {
component: 'input',
type: 'number',
columnClass: 'shrink',
inWhere: false,
},
},
{
name: 'longName',
align: 'center',
align: 'left',
label: t('negative.longName'),
field: ({ longName }) => longName,
columnFilter: {
component: 'input',
inWhere: false,
useLike: true,
},
sortable: true,
headerStyle: 'width: 350px',
cardVisible: true,
@ -94,6 +98,11 @@ const columns = computed(() => [
field: ({ inkFk }) => inkFk,
sortable: true,
cardVisible: true,
columnFilter: {
component: 'input',
columnClass: 'shrink',
inWhere: false,
},
},
{
name: 'size',
@ -155,7 +164,6 @@ const setUserParams = (params) => {
<TicketLackFilter data-key="NegativeList" @set-user-params="setUserParams" />
</template>
</RightMenu>
{{ filterRef }}
<VnTable
ref="tableRef"
data-key="NegativeList"

View File

@ -5,7 +5,7 @@ import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
import FetchData from 'src/components/FetchData.vue';
import { toDate, toHour } from 'src/filters';
import { toDate } from 'src/filters';
import useNotify from 'src/composables/useNotify.js';
import ZoneDescriptorProxy from 'pages/Zone/Card/ZoneDescriptorProxy.vue';
import { useRoute } from 'vue-router';
@ -22,14 +22,6 @@ const $props = defineProps({
},
});
watch(
() => $props.filter,
(v) => {
filterLack.value.where = v;
tableRef.value.reload(filterLack);
},
);
const filterLack = ref({
include: [
{
@ -90,6 +82,7 @@ const columns = computed(() => [
},
{
name: 'alertLevelCode',
field: 'alertLevelCode',
label: t('negative.detail.state'),
columnFilter: {
name: 'alertLevelCode',
@ -108,14 +101,14 @@ const columns = computed(() => [
name: 'zoneName',
label: t('negative.detail.zoneName'),
field: 'zoneName',
align: 'center',
align: 'left',
sortable: true,
},
{
name: 'nickname',
label: t('negative.detail.nickname'),
field: 'nickname',
align: 'center',
align: 'left',
sortable: true,
},
{
@ -139,27 +132,22 @@ const getInputEvents = ({ col, ...rows }) => ({
'keyup.enter': () => saveChange(col.name, rows),
});
const saveChange = async (field, { row }) => {
try {
switch (field) {
case 'alertLevelCode':
await axios.post(`Tickets/state`, {
ticketFk: row.ticketFk,
code: row[field],
});
break;
switch (field) {
case 'alertLevelCode':
await axios.post(`Tickets/state`, {
ticketFk: row.ticketFk,
code: row[field],
});
break;
case 'quantity':
await axios.post(`Sales/${row.saleFk}/updateQuantity`, {
quantity: +row.quantity,
});
break;
}
notify('globals.dataSaved', 'positive');
fetchItemLack.value.fetch();
} catch (err) {
console.error('Error saving changes', err);
f;
case 'quantity':
await axios.post(`Sales/${row.saleFk}/updateQuantity`, {
quantity: +row.quantity,
});
break;
}
notify('globals.dataSaved', 'positive');
fetchItemLack.value.fetch();
};
function onBuysFetched(data) {
@ -171,7 +159,7 @@ function onBuysFetched(data) {
<FetchData
ref="fetchItemLack"
:url="`Tickets/itemLack`"
:params="{ id: entityId }"
:params="{ itemFk: entityId }"
@on-fetch="(data) => (itemLack = data[0])"
auto-load
/>
@ -238,65 +226,59 @@ function onBuysFetched(data) {
</template>
<template #column-status="{ row }">
<QTd style="min-width: 150px">
<div class="icon-container">
<QIcon
v-if="row.isBasket"
name="vn:basket"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{ t('negative.detail.isBasket') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasToIgnore"
name="star"
color="primary"
class="cursor-pointer fill-icon"
size="xs"
>
<QTooltip>{{ t('negative.detail.hasToIgnore') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasObservation"
name="change_circle"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{
t('negative.detail.hasObservation')
}}</QTooltip> </QIcon
><QIcon
v-if="row.isRookie"
name="vn:Person"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.isRookie') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.peticionCompra"
name="vn:buyrequest"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.peticionCompra') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.turno"
name="vn:calendar"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.turno') }}</QTooltip>
</QIcon>
</div></QTd
<QIcon
v-if="row.isBasket"
name="vn:basket"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{ t('negative.detail.isBasket') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasToIgnore"
name="star"
color="primary"
class="cursor-pointer fill-icon"
size="xs"
>
<QTooltip>{{ t('negative.detail.hasToIgnore') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasObservation"
name="change_circle"
color="primary"
class="cursor-pointer"
size="xs"
>
<QTooltip>{{ t('negative.detail.hasObservation') }}</QTooltip> </QIcon
><QIcon
v-if="row.isRookie"
name="vn:Person"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.isRookie') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.peticionCompra"
name="vn:buyrequest"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.peticionCompra') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.turno"
name="vn:calendar"
size="xs"
color="primary"
class="cursor-pointer"
>
<QTooltip>{{ t('negative.detail.turno') }}</QTooltip>
</QIcon>
</template>
<template #column-nickname="{ row }">
<span class="link" @click.stop>
@ -305,9 +287,9 @@ function onBuysFetched(data) {
</span>
</template>
<template #column-ticketFk="{ row }">
<span class="q-pa-sm link">
{{ row.id }}
<TicketDescriptorProxy :id="row.id" />
<span class="link" @click.stop>
{{ row.ticketFk }}
<TicketDescriptorProxy :id="row.ticketFk" />
</span>
</template>
<template #column-alertLevelCode="props">
@ -335,15 +317,6 @@ function onBuysFetched(data) {
</VnTable>
</template>
<style lang="scss" scoped>
.icon-container {
display: grid;
grid-template-columns: repeat(3, 0.2fr);
row-gap: 5px; /* Ajusta el espacio entre los iconos según sea necesario */
}
.icon-container > * {
width: 100%;
height: auto;
}
.list-enter-active,
.list-leave-active {
transition: all 1s ease;

View File

@ -1,8 +1,11 @@
<script setup>
import { ref } from 'vue';
import axios from 'axios';
import VnSelect from 'src/components/common/VnSelect.vue';
import notifyResults from 'src/utils/notifyResults';
import { showResultsAsTable } from 'src/composables/showResultsTable';
import HandleSplitDialog from './HandleSplitDialog.vue';
const { openTable } = showResultsAsTable();
const emit = defineEmits(['update-item']);
const showChangeItemDialog = ref(false);
@ -17,15 +20,17 @@ const $props = defineProps({
const updateItem = async () => {
try {
showChangeItemDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ saleFk, quantity }) =>
const rowsToUpdate = $props.selectedRows.map(({ ticketFk, saleFk, quantity }) =>
axios.post(`Sales/replaceItem`, {
ticketFk,
saleFk,
substitutionFk: newItem.value,
quantity,
}),
);
const result = await Promise.allSettled(rowsToUpdate);
notifyResults(result, 'saleFk');
openTable(HandleSplitDialog, result, 'ticketFk', 'changeItem');
emit('update-item', newItem.value);
} catch (err) {
console.error('Error updating item:', err);
@ -37,9 +42,9 @@ const updateItem = async () => {
<template>
<QCard class="q-pa-sm">
<QCardSection class="row items-center justify-center column items-stretch">
{{ showChangeItemDialog }}
<span>{{ $t('negative.detail.modal.changeItem.title') }}</span>
<VnSelect
:label="$t('negative.detail.modal.changeItem.placeholder')"
url="Items/WithName"
:fields="['id', 'name']"
:sort-by="['id DESC']"

View File

@ -2,8 +2,9 @@
import { ref } from 'vue';
import axios from 'axios';
import VnInput from 'src/components/common/VnInput.vue';
import notifyResults from 'src/utils/notifyResults';
import { showResultsAsTable } from 'src/composables/showResultsTable';
import HandleSplitDialog from './HandleSplitDialog.vue';
const { openTable } = showResultsAsTable();
const showChangeQuantityDialog = ref(false);
const newQuantity = ref(null);
const $props = defineProps({
@ -14,22 +15,17 @@ const $props = defineProps({
});
const emit = defineEmits(['update-quantity']);
const updateQuantity = async () => {
try {
showChangeQuantityDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ saleFk }) =>
axios.post(`Sales/${saleFk}/updateQuantity`, {
saleFk,
quantity: +newQuantity.value,
}),
);
showChangeQuantityDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ saleFk }) =>
axios.post(`Sales/${saleFk}/updateQuantity`, {
saleFk,
quantity: +newQuantity.value,
}),
);
const result = await Promise.allSettled(rowsToUpdate);
notifyResults(result, 'saleFk');
emit('update-quantity', newQuantity.value);
} catch (err) {
return err;
}
const result = await Promise.allSettled(rowsToUpdate);
openTable(HandleSplitDialog, result, 'ticketFk', 'changeQuantity');
emit('update-quantity', newQuantity.value);
};
</script>

View File

@ -3,7 +3,9 @@ import { ref } from 'vue';
import axios from 'axios';
import VnSelect from 'src/components/common/VnSelect.vue';
import FetchData from 'components/FetchData.vue';
import notifyResults from 'src/utils/notifyResults';
import { showResultsAsTable } from 'src/composables/showResultsTable';
import HandleSplitDialog from './HandleSplitDialog.vue';
const { openTable } = showResultsAsTable();
const emit = defineEmits(['update-state']);
const editableStates = ref([]);
@ -16,21 +18,18 @@ const $props = defineProps({
},
});
const updateState = async () => {
try {
showChangeStateDialog.value = true;
const rowsToUpdate = $props.selectedRows.map(({ id }) =>
const rowsToUpdate = $props.selectedRows.map(({ ticketFk }) =>
axios.post(`Tickets/state`, {
ticketFk: id,
ticketFk,
code: newState.value,
}),
);
const result = await Promise.allSettled(rowsToUpdate);
notifyResults(result, 'ticketFk');
const result = await Promise.allSettled(rowsToUpdate);
openTable(HandleSplitDialog, result, 'ticketFk', 'changeState');
emit('update-state', newState.value);
} catch (err) {
return err;
}
};
</script>
@ -47,8 +46,6 @@ const updateState = async () => {
:label="$t('negative.detail.modal.changeState.placeholder')"
v-model="newState"
:options="editableStates"
option-label="name"
option-value="code"
/>
</QCardSection>
<QCardActions align="right">

View File

@ -0,0 +1,226 @@
<script setup>
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import FetchData from 'components/FetchData.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import TicketSaleTable from 'src/pages/Ticket/Card/components/TicketSaleTable.vue';
import { useQuasar } from 'quasar';
import TicketSaleTableDialog from '../../Card/components/TicketSaleTableDialog.vue';
const quasar = useQuasar();
const { t } = useI18n();
const $props = defineProps({
results: {
type: Array,
default: () => [],
},
tag: {
type: String,
default: 'ticketFk',
},
title: {
type: String,
default: 'bulkEdit.edit',
},
action: {
type: String,
default: '',
},
});
const results = ref($props.results);
const states = ref([]);
const columns = computed(() => [
{
name: 'status',
label: t('negative.split.status'),
field: ({ status }) => status,
sortable: true,
align: 'center',
},
{
name: 'value',
label: t('negative.split.ticket'),
sortable: true,
align: 'center',
},
{
name: 'statusText',
label: t('negative.split.message'),
sortable: true,
align: 'center',
},
{
name: 'actions',
label: '',
sortable: false,
align: 'right',
},
]);
function getState(value) {
return states.value.find((state) => state.id === value)?.name;
}
function getTicketRejected(row) {
return JSON.parse(row.reason.config.data)?.ticketFk;
}
function getTicketFulFilled(row) {
return JSON.parse(row.value.config.data).ticketFk;
}
function getIcon(value) {
const icons = {
fulfilled: {
name: 'check_circle',
color: 'secondary',
},
noSplit: {
name: 'warning',
color: 'primary',
},
rejected: {
name: 'close',
color: 'negative',
},
};
return icons[value];
}
function openLinesDialog(row) {
const ticket =
row.status === 'fulfilled'
? (row.value.data[$props.tag] ?? getTicketFulFilled(row))
: getTicketRejected(row);
quasar.dialog({
component: TicketSaleTableDialog,
componentProps: {
ticket: ticket,
sales: null,
},
});
}
</script>
<template>
<QDialog ref="dialogRef" @hide="onDialogHide" data-cy="handleSplitDialog" persistent>
<FetchData
v-if="$props.action === 'changeState'"
url="States"
@on-fetch="(data) => (states = data)"
auto-load
/>
<QCard class="q-pa-sm" style="width: 60vw; max-width: 80vw">
<QCardSection class="row items-center q-pb-none">
<QAvatar
:icon="icon"
color="primary"
text-color="white"
size="xl"
v-if="icon"
/>
<span class="text-h6 text-grey"
>{{ t($props.title) }} ({{ $props.action }})
</span>
<QSpace />
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection class="row items-center justify-center column items-stretch">
<QTable
:rows="results"
:columns="columns"
row-key="newTicket"
:no-data-label="t('globals.noResults')"
flat
dense
hide-bottom
auto-load
>
<template #header="props">
<QTr :props="props">
<QTh v-for="col in props.cols" :key="col.name" :props="props">
{{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #body-cell-status="{ value }">
<QTd align="center">
<QIcon
:name="`${getIcon(value)?.name}`"
size="xs"
class="cursor-pointer"
:color="getIcon(value)?.color"
>
</QIcon
></QTd>
</template>
<template #body-cell-value="{ row }">
<QTd align="center">
<div class="link" @click.stop>
<div v-if="row.status === 'fulfilled'">
<span v-if="$props.action !== 'changeItem'">
{{ row.value.data[$props.tag] }}
<TicketDescriptorProxy
:id="row.value.data[$props.tag]"
>
</TicketDescriptorProxy>
</span>
<span v-else
>{{ getTicketFulFilled(row)
}}<TicketDescriptorProxy
:id="getTicketFulFilled(row)"
>
</TicketDescriptorProxy>
</span>
</div>
<span v-else>
{{ getTicketRejected(row)
}}<TicketDescriptorProxy :id="getTicketRejected(row)">
</TicketDescriptorProxy
></span>
</div>
</QTd>
</template>
<template #body-cell-statusText="{ row }">
<QTd align="center">
<div v-if="row.status === 'fulfilled'">
<div v-if="$props.action === 'changeState'">
{{ getState(row.value.data.stateFk) }}
</div>
<div v-if="$props.action === 'split'">
<span>
{{ row.value.data.status }}
</span>
</div>
<div v-if="$props.action === 'changeItem'">
<span class="link" @click.stop>
{{ value }}
<ItemDescriptorProxy :id="value">
</ItemDescriptorProxy>
</span>
</div>
<div v-if="$props.action === 'changeQuantity'">
{{ row.value.data.quantity }}
</div>
</div>
<div v-else>{{ row.reason.response.data.error.message }}</div>
</QTd>
</template>
<template #body-cell-actions="props">
<QTd align="center">
<div v-if="['changeItem'].includes($props.action)">
<QIcon
name="list"
size="xs"
color="primary"
class="cursor-pointer"
@click="openLinesDialog(props.row)"
>
<QTooltip>{{ t('ticketList.toLines') }} </QTooltip>
</QIcon>
</div>
</QTd>
</template>
</QTable>
</QCardSection>
</QCard>
</QDialog>
</template>

View File

@ -286,7 +286,7 @@ negative:
title: Gestionar tickets spliteados
subTitle: Confir fecha y agencia
split:
ticket: Ticket viejo
ticket: Ticket origen
newTicket: Ticket nuevo
status: Estado
message: Mensaje

View File

@ -11,7 +11,12 @@ const $props = defineProps({
</script>
<template>
<QPopupProxy>
<ZoneDescriptor v-if="$props.id" :id="$props.id" :summary="ZoneSummary" />
<QPopupProxy data-cy="zoneDescriptorProxy">
<ZoneDescriptor
v-if="$props.id"
:id="$props.id"
:summary="ZoneSummary"
data-cy="zoneDescriptorProxy"
/>
</QPopupProxy>
</template>