#6321 - Negative ticket #158

Open
jsegarra wants to merge 197 commits from 6321_negative_tickets into dev
6 changed files with 70 additions and 168 deletions
Showing only changes of commit 055a0b8751 - Show all commits

View File

@ -5,6 +5,8 @@ import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
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';
const MATCH_VALUES = [5, 6, 7, 8];
const { t } = useI18n();
@ -12,8 +14,6 @@ const extractNumericValue = (percentageString) => {
const match = percentageString.match(/(\d+(\.\d+)?)/);
return match ? parseFloat(match[0]) : null;
};
const primaryColor = '#f5b351';
const colorSpacer = '#ecf0f1';
const compatibilityItem = (value) => `${100 * (value / MATCH_VALUES.length)}%`;
const gradientStyle = (value) => {
let color = 'white';
@ -157,7 +157,8 @@ const columns = computed(() => [
field: 'located',
},
]);
const isSelected = (row) => proposalSelected.value.some((item) => row.id === item.id);
const isSelected = (row) =>
proposalSelected.value.some((item) => row.itemFk === item.itemFk);
function change(row) {
if (isSelected(row)) {
confirm(row);
@ -165,29 +166,24 @@ function change(row) {
}
proposalSelected.value = [row];
}
async function confirm(row) {
async function confirm() {
try {
// const params = {
// saleFk: saleFk.value,
// substitutionFk: proposalSelected.value[0].id,
// quantity: quantity.value,
// };
// const { data } = await axios.post('Sales/replaceItem', params);
const params = [
saleFk.value,
row ?? proposalSelected.value[0].id,
quantity.value,
];
// const { data } = await axios.post('Applications/sale_replaceItem/execute-proc', {
// schema: 'vn',
// params,
// });
// proposalTableRef.value.reload();
const substitutionFk = proposalSelected.value[0].itemFk;
const promises = $props.sales.map(({ saleFk, quantity }) => {
const params = {
saleFk,
substitutionFk,
quantity,
};
return axios.post('Sales/replaceItem', params);
});
const results = await Promise.allSettled(promises);
notifyResults(results, 'saleFk');
emit('itemReplaced', {
type: 'refresh',
quantity: quantity.value,
itemProposal: proposalSelected.value[0],
...params,
});
proposalSelected.value = [];
} catch (error) {
@ -198,13 +194,9 @@ const filter = computed(() => ({
itemFk: $props.itemLack.itemFk,
sales: saleFk.value,
}));
function handleSelection(value, _) {
quantity.value = value.available;
}
const isSelectionAvailable = (itemProposal) => {
const { price2 } = itemProposal;
const salePrice = sale.value.price;
// debugger;
const byPrice = (100 * price2) / salePrice > 30;
if (byPrice) {
return byPrice;
@ -213,8 +205,6 @@ const isSelectionAvailable = (itemProposal) => {
(100 * itemProposal.available) / Math.abs($props.itemLack.lack) < 30;
return byQuantity;
};
const isDisabled = (row) => !isSelectionAvailable(row);
</script>
<template>
<VnTable

View File

@ -1,7 +1,5 @@
<script setup>
import ItemProposal from './ItemProposal.vue';
import { ref } from 'vue';
const popupProxyRef = ref(null);
import { useDialogPluginComponent } from 'quasar';
const emit = defineEmits([
'onDialogClosed',
@ -12,8 +10,7 @@ const emit = defineEmits([
]);
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent();
const { dialogRef } = useDialogPluginComponent();
const $props = defineProps({
itemLack: {
type: Object,
@ -41,21 +38,12 @@ const $props = defineProps({
<QBtn icon="close" flat round dense v-close-popup />
</QCardSection>
<QCardSection>
<!-- <VnImg :id="itemLack.id" class="rounded image-wrapper"></VnImg>
<QBtn flat class="link text-blue">
{{ itemLack.longName }}
<ItemDescriptorProxy :id="itemLack.id" />
</QBtn>
<FetchedTags :item="itemLack" />
</QCardSection>
<QCardSection class="q-pt-none"> -->
<ItemProposal
v-bind="$props"
@item-replaced="
(data) => {
emit('itemReplaced', data);
popupProxyRef.value.hide();
dialogRef.hide();
}
"
></ItemProposal

View File

@ -8,6 +8,7 @@ import TicketTransferForm from './TicketTransferForm.vue';
import { toDateFormat } from 'src/filters/date.js';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import split from './components/split';
const emit = defineEmits(['ticketTransfered']);
const $props = defineProps({
mana: {
@ -94,7 +95,8 @@ const handleRowClick = (row) => {
};
const splitSelectedRows = async () => {
const tickets = Array.isArray($props.ticket) ? $props.ticket : [$props.ticket];
await split(tickets);
await split(tickets, splitDate.value);
emit('ticketTransfered', tickets);
};
</script>

View File

@ -1,13 +1,13 @@
import axios from 'axios';
import notifyResults from 'src/utils/notifyResults';
export default async function (data) {
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] });
acc.push({ ticketFk: item.id, sales: [item.saleFk], date });
}
return acc;
}, []);

View File

@ -13,9 +13,6 @@ import { useRoute } from 'vue-router';
import TicketLackTable from './TicketLackTable.vue';
import VnPopupProxy from 'src/components/common/VnPopupProxy.vue';
import ItemProposalProxy from 'src/pages/Item/components/ItemProposalProxy.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnImg from 'src/components/ui/VnImg.vue';
import { useQuasar } from 'quasar';
const quasar = useQuasar();
@ -41,76 +38,27 @@ onUnmounted(() => {
const entityId = computed(() => route.params.id);
const item = ref({});
const itemLackForm = ref();
const itemProposalSelected = ref(null);
const reload = async () => {
itemLackForm.value.fetch();
tableRef.value.tableRef.reload();
};
defineExpose({ reload });
// Función de comparación
// function freeFirst({ alertLevel: a }, { alertLevel: b }) {
// const DEFAULT = 0;
// // Si el estado de 'a' es 'free' y el de 'b' no lo es, 'a' viene primero
// if (a === DEFAULT && b !== DEFAULT) {
// return -1;
// }
// // Si el estado de 'b' es 'free' y el de 'a' no lo es, 'b' viene primero
// if (b === DEFAULT && a !== DEFAULT) {
// return 1;
// }
// // En cualquier otro caso, no se cambia el orden
// return 0;
// }
// const { store } = useArrayData(URL_KEY);
// const handleRows = (rows) => {
// // rows.forEach((row) => (row.concept = item.value.name));
// rows = rows.sort(freeFirst);
// if (showFree.value) return rows.filter(({ alertLevel }) => alertLevel === 0);
// return rows;
// };
const someBasket = computed(() => selectedRows.value.some((row) => row.isBasket === 1));
const itemProposalEvt = (data) => {
const { itemProposal, quantity } = data;
itemProposalSelected.value = itemProposal;
// badgeLackRef.value.reload();
itemLack.value.lack += +quantity;
tableRef.value.reload();
// replaceItem();
reload();
};
const itemProposalSelected = ref(null);
// const replaceItem = () => {
// const rows = handleRows(originalRowDataCopy.value).sort((row) => row.quantity);
// for (const ticket of rows) {
// if (ticket.quantity > itemProposalSelected.value.available) continue;
// originalRowDataCopy.value.splice(originalRowDataCopy.value.indexOf(ticket));
// ticket.itemFk = itemProposalSelected.value.id;
// selectedRows.value.push({ ticketFk: ticket.ticketFk });
// itemProposalSelected.value.available -= ticket.quantity;
// itemLack.value.lack += ticket.quantity;
// const index = store.data.findIndex((t) => t.ticketFk === ticket.ticketFk);
// store.data.splice(index, 1);
// console.log(ticket);
// useArrayData('ItemsGetSimilar').store.data[1].available =
// itemProposalSelected.value.available;
// }
// };
function onBuysFetched(data) {
Object.assign(item.value, data[0]);
}
const closeDialogs = (refs, evt) => {
changeItemDialogRef.value.hide();
changeQuantityDialogRef.value.hide();
changeStateDialogRef.value.hide();
};
const showItemProposal = () => {
quasar
.dialog({
component: ItemProposalProxy,
componentProps: {
itemLack: itemLack.value,
itemLack: tableRef.value.itemLack,
replaceAction: true,
sales: selectedRows.value,
},
@ -139,16 +87,7 @@ const filterTable = { stateFk: 0, warehouseFk: useState().getUser().value.wareho
@on-fetch="onBuysFetched"
auto-load
/>
<FetchData
:url="`Tickets/itemLack`"
:params="{ itemFk: entityId }"
@on-fetch="(data) => (itemLack = data[0])"
auto-load
/>
<!-- <VnSubToolbar>
<template #st-data> </template>
<template #st-actions> </template>
</VnSubToolbar> -->
<TicketLackTable
ref="tableRef"
:filter="filterTable"
@ -171,6 +110,7 @@ const filterTable = { stateFk: 0, warehouseFk: useState().getUser().value.wareho
sales: selectedRows,
lastActiveTickets: selectedRows.map((row) => row.id),
}"
@ticket-transfered="reload"
></TicketTransfer>
</QBtn>
<QBtn
@ -183,13 +123,6 @@ const filterTable = { stateFk: 0, warehouseFk: useState().getUser().value.wareho
class="rotate-90"
@click="showItemProposal"
></QIcon>
<!-- <ItemProposalProxy
ref="proposalDialogRef"
:item-lack="itemLack"
:replace-action="true"
:sales="selectedRows"
@item-replaced="itemProposalEvt"
></ItemProposalProxy> -->
<QTooltip bottom anchor="bottom right">
{{ t('itemProposal') }}
</QTooltip>
@ -238,27 +171,6 @@ const filterTable = { stateFk: 0, warehouseFk: useState().getUser().value.wareho
/></template>
</VnPopupProxy> </QBtnGroup
></template>
<template #top-left>
<div style="display: flex; align-items: center" v-if="itemLack">
<VnImg :id="itemLack.itemFk" class="rounded image-wrapper"></VnImg>
<div class="flex column" style="align-items: center">
<QBadge
ref="badgeLackRef"
class="q-ml-xs"
text-color="white"
:color="itemLack.lack === 0 ? 'green' : 'red'"
:label="itemLack.lack"
/>
</div>
<div class="flex column left" style="align-items: flex-start">
<QBtn flat class="link text-blue">
{{ item?.longName ?? item.name }}
<ItemDescriptorProxy :id="entityId" />
</QBtn>
<FetchedTags class="q-ml-md" :item="item" :columns="7" />
</div>
</div>
</template>
</TicketLackTable>
</template>
<style lang="scss" scoped>

View File

@ -1,4 +1,7 @@
<script setup>
import FetchedTags from 'components/ui/FetchedTags.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import VnImg from 'src/components/ui/VnImg.vue';
import { computed, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
@ -70,6 +73,7 @@ const saveChange = async (field, { rowIndex, row }) => {
break;
}
notify('globals.dataSaved', 'positive');
fetchItemLack.value.fetch();
} catch (err) {
console.error('Error saving changes', err);
f;
@ -82,34 +86,7 @@ const rowColor = (row) => {
if (hasToIgnore(row)) return 'transparent';
return 'negative';
};
// const textRowColor = (row) => {
// if (row.hasToIgnore) return 'black';
// return 'white';
// };
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',
align: 'left',
@ -206,15 +183,24 @@ const columns = computed(() => [
]);
const emit = defineEmits(['update:selection']);
const itemLack = ref(null);
const fetchItemLack = ref(null);
const tableRef = ref(null);
watch(selectedRows, () => emit('update:selection', selectedRows));
function onBuysFetched(data) {
Object.assign(item.value, data[0]);
}
defineExpose({ tableRef, itemLack });
</script>
<template>
<FetchData
ref="fetchItemLack"
:url="`Tickets/itemLack`"
:params="{ itemFk: entityId }"
@on-fetch="(data) => (itemLack = data[0])"
auto-load
/>
<FetchData
:url="`Items/${entityId}/getCard`"
:fields="['longName']"
@ -253,7 +239,25 @@ function onBuysFetched(data) {
:disable-option="{ card: true }"
>
<template #top-left>
<slot name="top-left" />
<div style="display: flex; align-items: center" v-if="itemLack">
<VnImg :id="itemLack.itemFk" class="rounded image-wrapper"></VnImg>
<div class="flex column" style="align-items: center">
<QBadge
ref="badgeLackRef"
class="q-ml-xs"
text-color="white"
:color="itemLack.lack === 0 ? 'green' : 'red'"
:label="itemLack.lack"
/>
</div>
<div class="flex column left" style="align-items: flex-start">
<QBtn flat class="link text-blue">
{{ item?.longName ?? item.name }}
<ItemDescriptorProxy :id="entityId" />
</QBtn>
<FetchedTags class="q-ml-md" :item="item" :columns="7" />
</div>
</div>
</template>
<template #top-right>
<slot name="top-right" />
@ -263,6 +267,7 @@ function onBuysFetched(data) {
<QTd style="width: 150px">
<div class="icon-container">
<QIcon
v-if="row.isBasket"
name="vn:basket"
color="primary"
class="cursor-pointer"
@ -271,6 +276,7 @@ function onBuysFetched(data) {
<QTooltip>{{ t('negative.detail.isBasket') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasToIgnore"
name="star"
color="primary"
class="cursor-pointer fill-icon"
@ -279,6 +285,7 @@ function onBuysFetched(data) {
<QTooltip>{{ t('negative.detail.hasToIgnore') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.hasSubstitution"
name="change_circle"
color="primary"
class="cursor-pointer"
@ -288,6 +295,7 @@ function onBuysFetched(data) {
t('negative.detail.hasSubstitution')
}}</QTooltip> </QIcon
><QIcon
v-if="row.isRookie"
name="vn:Person"
size="xs"
color="primary"
@ -296,6 +304,7 @@ function onBuysFetched(data) {
<QTooltip>{{ t('negative.detail.isRookie') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.peticionCompra"
name="vn:buyrequest"
size="xs"
color="primary"
@ -304,6 +313,7 @@ function onBuysFetched(data) {
<QTooltip>{{ t('negative.detail.peticionCompra') }}</QTooltip>
</QIcon>
<QIcon
v-if="row.turno"
name="vn:calendar"
size="xs"
color="primary"