Compare commits
9 Commits
dev
...
warmfix_85
Author | SHA1 | Date |
---|---|---|
|
e1be86774b | |
|
76df3413b9 | |
|
22f77fc70c | |
|
adf33c14ae | |
|
8e47a4134d | |
|
f15865ee42 | |
|
0ff6cc5dbe | |
|
6c0fcc38b0 | |
|
31f1850704 |
|
@ -6,17 +6,25 @@ import { useRequired } from 'src/composables/useRequired';
|
|||
|
||||
const $attrs = useAttrs();
|
||||
const { isRequired, requiredFieldRule } = useRequired($attrs);
|
||||
const model = defineModel({ type: [String, Date] });
|
||||
|
||||
const $props = defineProps({
|
||||
isOutlined: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
showEvent: {
|
||||
isPopupOpen: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const model = defineModel({
|
||||
type: [String, Date, Array],
|
||||
default: null,
|
||||
});
|
||||
|
||||
const vnInputDateRef = ref(null);
|
||||
|
@ -31,10 +39,17 @@ const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
|
|||
const formattedDate = computed({
|
||||
get() {
|
||||
if (!model.value) return model.value;
|
||||
if ($props.multiple) {
|
||||
return model.value
|
||||
.map((d) => date.formatDate(new Date(d), dateFormat))
|
||||
.join(', ');
|
||||
}
|
||||
return date.formatDate(new Date(model.value), dateFormat);
|
||||
},
|
||||
set(value) {
|
||||
if (value == model.value) return;
|
||||
if ($props.multiple) return; // No permitir edición manual en modo múltiple
|
||||
|
||||
let newDate;
|
||||
if (value) {
|
||||
// parse input
|
||||
|
@ -47,7 +62,7 @@ const formattedDate = computed({
|
|||
}
|
||||
const [year, month, day] = value.split('-').map((e) => parseInt(e));
|
||||
newDate = new Date(year, month - 1, day);
|
||||
if (model.value) {
|
||||
if (model.value && !$props.multiple) {
|
||||
const orgDate =
|
||||
model.value instanceof Date ? model.value : new Date(model.value);
|
||||
|
||||
|
@ -63,12 +78,19 @@ const formattedDate = computed({
|
|||
},
|
||||
});
|
||||
|
||||
const popupDate = computed(() =>
|
||||
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value,
|
||||
);
|
||||
const popupDate = computed(() => {
|
||||
if (!model.value) return model.value;
|
||||
if ($props.multiple) {
|
||||
return model.value.map((d) => date.formatDate(new Date(d), 'YYYY/MM/DD'));
|
||||
}
|
||||
return date.formatDate(new Date(model.value), 'YYYY/MM/DD');
|
||||
});
|
||||
onMounted(() => {
|
||||
// fix quasar bug
|
||||
mask.value = '##/##/####';
|
||||
if ($props.multiple && !model.value) {
|
||||
model.value = [];
|
||||
}
|
||||
});
|
||||
watch(
|
||||
() => model.value,
|
||||
|
@ -86,9 +108,13 @@ const styleAttrs = computed(() => {
|
|||
: {};
|
||||
});
|
||||
|
||||
const manageDate = (date) => {
|
||||
formattedDate.value = date;
|
||||
isPopupOpen.value = false;
|
||||
const manageDate = (dates) => {
|
||||
if ($props.multiple) {
|
||||
model.value = dates.map((d) => new Date(d).toISOString());
|
||||
} else {
|
||||
formattedDate.value = dates;
|
||||
}
|
||||
if ($props.isPopupOpen) isPopupOpen.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -98,7 +124,7 @@ const manageDate = (date) => {
|
|||
ref="vnInputDateRef"
|
||||
v-model="formattedDate"
|
||||
class="vn-input-date"
|
||||
:mask="mask"
|
||||
:mask="$props.multiple ? undefined : mask"
|
||||
placeholder="dd/mm/aaaa"
|
||||
v-bind="{ ...$attrs, ...styleAttrs }"
|
||||
:class="{ required: isRequired }"
|
||||
|
@ -136,10 +162,18 @@ const manageDate = (date) => {
|
|||
:no-focus="true"
|
||||
:no-parent-event="true"
|
||||
>
|
||||
<VnDate v-model="popupDate" @update:model-value="manageDate" />
|
||||
<VnDate
|
||||
v-model="popupDate"
|
||||
@update:model-value="manageDate"
|
||||
:multiple="multiple"
|
||||
/>
|
||||
</QMenu>
|
||||
<QDialog v-else v-model="isPopupOpen">
|
||||
<VnDate v-model="popupDate" @update:model-value="manageDate" />
|
||||
<VnDate
|
||||
v-model="popupDate"
|
||||
@update:model-value="manageDate"
|
||||
:multiple="multiple"
|
||||
/>
|
||||
</QDialog>
|
||||
</QInput>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { toPercentage } from 'filters/index';
|
||||
import { toCurrency, toPercentage } from 'filters/index';
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
|
@ -8,6 +8,10 @@ const props = defineProps({
|
|||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
format: {
|
||||
type: String,
|
||||
default: 'percentage', // 'currency'
|
||||
},
|
||||
});
|
||||
|
||||
const valueClass = computed(() =>
|
||||
|
@ -21,7 +25,10 @@ const formattedValue = computed(() => props.value);
|
|||
<template>
|
||||
<span :class="valueClass">
|
||||
<QIcon :name="iconName" size="sm" class="value-icon" />
|
||||
{{ toPercentage(formattedValue) }}
|
||||
<span v-if="$props.format === 'percentage'">{{
|
||||
toPercentage(formattedValue)
|
||||
}}</span>
|
||||
<span v-if="$props.format === 'currency'">{{ toCurrency(formattedValue) }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ const ticketConfig = ref({});
|
|||
const proposalTableRef = ref(null);
|
||||
|
||||
const sale = computed(() => $props.sales[0]);
|
||||
const saleFk = computed(() => sale.value.saleFk);
|
||||
const saleFk = computed(() => sale.value?.saleFk);
|
||||
const filter = computed(() => ({
|
||||
where: $props.filter,
|
||||
|
||||
|
@ -56,8 +56,24 @@ const defaultColumnAttrs = {
|
|||
};
|
||||
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
|
||||
|
||||
const conditionalValuePrice = (price) =>
|
||||
price > 1 + ticketConfig.value.lackAlertPrice / 100 ? 'match' : 'not-match';
|
||||
const priceStatusClass = (proposalPrice) => {
|
||||
const originalPrice = sale.value?.price;
|
||||
|
||||
if (
|
||||
!originalPrice ||
|
||||
!ticketConfig.value ||
|
||||
typeof ticketConfig.value.lackAlertPrice !== 'number'
|
||||
) {
|
||||
return 'price-ok';
|
||||
}
|
||||
|
||||
const priceIncreasePercentage =
|
||||
((proposalPrice - originalPrice) / originalPrice) * 100;
|
||||
|
||||
return priceIncreasePercentage > ticketConfig.value.lackAlertPrice
|
||||
? 'price-alert'
|
||||
: 'price-ok';
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
|
@ -97,7 +113,15 @@ const columns = computed(() => [
|
|||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('item.list.color'),
|
||||
label: t('item.list.producer'),
|
||||
name: 'subName',
|
||||
field: 'subName',
|
||||
columnClass: 'expand',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('proposal.tag5'),
|
||||
name: 'tag5',
|
||||
field: 'value5',
|
||||
columnClass: 'expand',
|
||||
|
@ -105,7 +129,7 @@ const columns = computed(() => [
|
|||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('item.list.stems'),
|
||||
label: t('proposal.tag6'),
|
||||
name: 'tag6',
|
||||
field: 'value6',
|
||||
columnClass: 'expand',
|
||||
|
@ -113,12 +137,27 @@ const columns = computed(() => [
|
|||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('item.list.producer'),
|
||||
label: t('proposal.tag7'),
|
||||
name: 'tag7',
|
||||
field: 'value7',
|
||||
columnClass: 'expand',
|
||||
},
|
||||
|
||||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('proposal.tag8'),
|
||||
name: 'tag8',
|
||||
field: 'value8',
|
||||
columnClass: 'expand',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
label: t('proposal.advanceable'),
|
||||
name: 'advanceable',
|
||||
field: 'advanceable',
|
||||
columnClass: 'expand',
|
||||
},
|
||||
{
|
||||
...defaultColumnAttrs,
|
||||
label: t('proposal.price2'),
|
||||
|
@ -169,14 +208,14 @@ function extractMatchValues(obj) {
|
|||
.filter((key) => key.startsWith(MATCH))
|
||||
.map((key) => parseInt(key.replace(MATCH, ''), 10));
|
||||
}
|
||||
const gradientStyle = (value) => {
|
||||
const gradientStyleClass = (row) => {
|
||||
let color = 'white';
|
||||
const perc = parseFloat(value);
|
||||
const value = parseFloat(row);
|
||||
switch (true) {
|
||||
case perc >= 0 && perc < 33:
|
||||
case value >= 0 && value < 33:
|
||||
color = 'primary';
|
||||
break;
|
||||
case perc >= 33 && perc < 66:
|
||||
case value >= 33 && value < 66:
|
||||
color = 'warning';
|
||||
break;
|
||||
|
||||
|
@ -193,34 +232,49 @@ const statusConditionalValue = (row) => {
|
|||
};
|
||||
|
||||
const isSelectionAvailable = (itemProposal) => {
|
||||
const { price2 } = itemProposal;
|
||||
const salePrice = sale.value.price;
|
||||
const byPrice = (100 * price2) / salePrice > ticketConfig.value.lackAlertPrice;
|
||||
if (byPrice) {
|
||||
return byPrice;
|
||||
const { price2, available } = itemProposal;
|
||||
const originalPrice = sale.value?.price;
|
||||
const lackQuantity = $props.itemLack?.lack;
|
||||
|
||||
if (
|
||||
!originalPrice ||
|
||||
!lackQuantity ||
|
||||
!ticketConfig.value ||
|
||||
typeof ticketConfig.value.lackAlertPrice !== 'number'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const byQuantity =
|
||||
(100 * itemProposal.available) / Math.abs($props.itemLack.lack) <
|
||||
ticketConfig.value.lackAlertPrice;
|
||||
return byQuantity;
|
||||
|
||||
const priceIncreasePercentage = ((price2 - originalPrice) / originalPrice) * 100;
|
||||
const isPriceTooHigh = priceIncreasePercentage > ticketConfig.value.lackAlertPrice;
|
||||
|
||||
if (isPriceTooHigh) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const availablePercentage = (available / Math.abs(lackQuantity)) * 100;
|
||||
const hasEnoughQuantity = availablePercentage >= ticketConfig.value.lackAlertPrice;
|
||||
|
||||
return hasEnoughQuantity;
|
||||
};
|
||||
|
||||
async function change({ itemFk: substitutionFk }) {
|
||||
try {
|
||||
let body;
|
||||
const promises = $props.sales.map(({ saleFk, quantity }) => {
|
||||
const params = {
|
||||
body = {
|
||||
saleFk,
|
||||
substitutionFk,
|
||||
quantity,
|
||||
};
|
||||
return axios.post('Sales/replaceItem', params);
|
||||
return axios.post('Sales/replaceItem', body);
|
||||
});
|
||||
const results = await Promise.allSettled(promises);
|
||||
|
||||
notifyResults(results, 'saleFk');
|
||||
emit('itemReplaced', {
|
||||
...body,
|
||||
type: 'refresh',
|
||||
quantity: quantity.value,
|
||||
itemProposal: proposalSelected.value[0],
|
||||
});
|
||||
proposalSelected.value = [];
|
||||
|
@ -232,6 +286,13 @@ async function change({ itemFk: substitutionFk }) {
|
|||
async function handleTicketConfig(data) {
|
||||
ticketConfig.value = data[0];
|
||||
}
|
||||
|
||||
function filterRows(data) {
|
||||
const filteredRows = data.sort(
|
||||
(a, b) => isSelectionAvailable(b) - isSelectionAvailable(a),
|
||||
);
|
||||
proposalTableRef.value.CrudModelRef.formData = filteredRows;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
|
@ -251,13 +312,22 @@ async function handleTicketConfig(data) {
|
|||
:user-filter="filter"
|
||||
:columns="columns"
|
||||
class="full-width q-mt-md"
|
||||
@on-fetch="filterRows"
|
||||
row-key="id"
|
||||
:row-click="change"
|
||||
:is-editable="false"
|
||||
:right-search="false"
|
||||
:without-header="true"
|
||||
:disable-option="{ card: true, table: true }"
|
||||
>
|
||||
<template #top-right>
|
||||
<QBtn
|
||||
flat
|
||||
class="q-mr-sm"
|
||||
color="primary"
|
||||
icon="refresh"
|
||||
@click="proposalTableRef.reload()"
|
||||
/>
|
||||
</template>
|
||||
<template #column-longName="{ row }">
|
||||
<QTd
|
||||
class="flex"
|
||||
|
@ -265,15 +335,17 @@ async function handleTicketConfig(data) {
|
|||
>
|
||||
<div
|
||||
class="middle full-width"
|
||||
:class="[`proposal-${gradientStyle(statusConditionalValue(row))}`]"
|
||||
:class="[
|
||||
`proposal-${gradientStyleClass(statusConditionalValue(row))}`,
|
||||
]"
|
||||
>
|
||||
<QTooltip> {{ statusConditionalValue(row) }}% </QTooltip>
|
||||
</div>
|
||||
<div style="flex: 2 0 100%; align-content: center">
|
||||
<div>
|
||||
<span class="link">{{ row.longName }}</span>
|
||||
<span class="link" @click.stop>
|
||||
{{ row.longName }}
|
||||
<ItemDescriptorProxy :id="row.id" />
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</QTd>
|
||||
</template>
|
||||
|
@ -286,6 +358,9 @@ async function handleTicketConfig(data) {
|
|||
<template #column-tag7="{ row }">
|
||||
<span :class="{ match: !row.match7 }">{{ row.value7 }}</span>
|
||||
</template>
|
||||
<template #column-tag8="{ row }">
|
||||
<span :class="{ match: !row.match8 }">{{ row.value8 }}</span>
|
||||
</template>
|
||||
<template #column-counter="{ row }">
|
||||
<span
|
||||
:class="{
|
||||
|
@ -300,8 +375,17 @@ async function handleTicketConfig(data) {
|
|||
</template>
|
||||
<template #column-price2="{ row }">
|
||||
<div class="flex column items-center content-center">
|
||||
<VnStockValueDisplay :value="(sales[0].price - row.price2) / 100" />
|
||||
<span :class="[conditionalValuePrice(row.price2)]">{{
|
||||
<!-- Use class binding for tooltip background -->
|
||||
<QTooltip :offset="[0, 5]" anchor="top middle" self="bottom middle">
|
||||
<div>{{ $t('proposal.price2') }}: {{ toCurrency(row.price2) }}</div>
|
||||
<div>
|
||||
{{ $t('proposal.itemOldPrice') }}:
|
||||
{{ toCurrency(sales[0]?.price) }}
|
||||
</div>
|
||||
</QTooltip>
|
||||
<VnStockValueDisplay :format="'currency'" :value="-row.price2 / 100" />
|
||||
<!-- Use class binding for text color -->
|
||||
<span :class="[priceStatusClass(row.price2)]">{{
|
||||
toCurrency(row.price2)
|
||||
}}</span>
|
||||
</div>
|
||||
|
@ -315,12 +399,37 @@ async function handleTicketConfig(data) {
|
|||
margin-right: 2px;
|
||||
flex: 2 0 5px;
|
||||
}
|
||||
.match {
|
||||
|
||||
/* Removed old .match / .not-match specific to price */
|
||||
/* .match {
|
||||
color: $negative;
|
||||
}
|
||||
.not-match {
|
||||
color: inherit;
|
||||
} */
|
||||
|
||||
/* Added classes for price status */
|
||||
.price-alert {
|
||||
color: $negative; /* Alert text color */
|
||||
&.q-tooltip {
|
||||
background-color: $negative; /* Alert tooltip background */
|
||||
color: white; /* Ensure tooltip text is readable */
|
||||
}
|
||||
}
|
||||
|
||||
.price-ok {
|
||||
color: inherit; /* Default text color */
|
||||
&.q-tooltip {
|
||||
/* Keep default tooltip background or set a specific 'ok' color */
|
||||
background-color: $positive; /* Example: green background for OK price */
|
||||
color: white; /* Ensure tooltip text is readable */
|
||||
}
|
||||
}
|
||||
|
||||
.match {
|
||||
color: $negative;
|
||||
}
|
||||
|
||||
.proposal-warning {
|
||||
background-color: $warning;
|
||||
}
|
||||
|
|
|
@ -23,33 +23,32 @@ const $props = defineProps({
|
|||
default: () => [],
|
||||
},
|
||||
});
|
||||
const { dialogRef } = useDialogPluginComponent();
|
||||
|
||||
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
|
||||
useDialogPluginComponent();
|
||||
const emit = defineEmits([
|
||||
'onDialogClosed',
|
||||
'onDialogOk',
|
||||
'itemReplaced',
|
||||
...useDialogPluginComponent.emits,
|
||||
]);
|
||||
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
|
||||
const itemReplaced = (data) => {
|
||||
onDialogOK(data);
|
||||
dialogRef.value.hide();
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<QDialog ref="dialogRef" transition-show="scale" transition-hide="scale">
|
||||
<QCard class="dialog-width">
|
||||
<QCardSection class="row items-center q-pb-none">
|
||||
<span class="text-h6 text-grey">{{ $t('itemProposal') }}</span>
|
||||
<span class="text-h6 text-grey" v-text="$t('itemProposal')" />
|
||||
<QSpace />
|
||||
<QBtn icon="close" flat round dense v-close-popup />
|
||||
</QCardSection>
|
||||
<QCardSection>
|
||||
<ItemProposal
|
||||
v-bind="$props"
|
||||
@item-replaced="
|
||||
(data) => {
|
||||
emit('itemReplaced', data);
|
||||
dialogRef.hide();
|
||||
}
|
||||
"
|
||||
></ItemProposal
|
||||
></QCardSection>
|
||||
<ItemProposal v-bind="$props" @item-replaced="itemReplaced"
|
||||
/></QCardSection>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
</template>
|
||||
|
|
|
@ -231,6 +231,11 @@ proposal:
|
|||
value6: value6
|
||||
value7: value7
|
||||
value8: value8
|
||||
tag5: Tag5
|
||||
tag6: Tag6
|
||||
tag7: Tag7
|
||||
tag8: Tag8
|
||||
advanceable: Advanceable
|
||||
available: Available
|
||||
minQuantity: minQuantity
|
||||
price2: Price
|
||||
|
|
|
@ -237,11 +237,16 @@ proposal:
|
|||
value6: value6
|
||||
value7: value7
|
||||
value8: value8
|
||||
tag5: Tag5
|
||||
tag6: Tag6
|
||||
tag7: Tag7
|
||||
tag8: Tag8
|
||||
available: Disponible
|
||||
minQuantity: Min. cantidad
|
||||
price2: Precio
|
||||
located: Ubicado
|
||||
counter: Contador
|
||||
advanceable: Adelantable
|
||||
difference: Diferencial
|
||||
groupingPrice: Precio Grouping
|
||||
itemOldPrice: Precio itemOld
|
||||
|
|
|
@ -7,6 +7,8 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
|||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInputDateTime from 'src/components/common/VnInputDateTime.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
dataKey: {
|
||||
|
@ -67,7 +69,6 @@ const setUserParams = (params) => {
|
|||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
@set-user-params="setUserParams"
|
||||
:unremovable-params="['warehouseFk']"
|
||||
>
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
|
@ -85,7 +86,7 @@ const setUserParams = (params) => {
|
|||
dense
|
||||
filled
|
||||
@update:model-value="
|
||||
(value) => {
|
||||
() => {
|
||||
setUserParams(params);
|
||||
}
|
||||
"
|
||||
|
@ -120,8 +121,21 @@ const setUserParams = (params) => {
|
|||
dense
|
||||
filled
|
||||
/>
|
||||
</QItemSection> </QItem
|
||||
><QItem>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
v-model="params.excludedDates"
|
||||
filled
|
||||
:label="t('negative.excludedDates')"
|
||||
:multiple="true"
|
||||
:is-popup-open="false"
|
||||
>
|
||||
</VnInputDate>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection v-if="categoriesOptions">
|
||||
<VnSelect
|
||||
:label="t('negative.categoryFk')"
|
||||
|
|
|
@ -7,6 +7,7 @@ import { onBeforeMount } from 'vue';
|
|||
import { dashIfEmpty, toDate, toHour } from 'src/filters';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import TicketLackFilter from './TicketLackFilter.vue';
|
||||
|
@ -45,10 +46,10 @@ const columns = computed(() => [
|
|||
},
|
||||
{
|
||||
columnClass: 'shrink',
|
||||
name: 'timed',
|
||||
name: 'minTimed',
|
||||
align: 'center',
|
||||
label: t('negative.timed'),
|
||||
format: ({ timed }) => toHour(timed),
|
||||
format: ({ minTimed }) => toHour(minTimed),
|
||||
sortable: true,
|
||||
cardVisible: true,
|
||||
columnFilter: {
|
||||
|
@ -64,9 +65,25 @@ const columns = computed(() => [
|
|||
columnFilter: {
|
||||
component: 'input',
|
||||
type: 'number',
|
||||
inWhere: false,
|
||||
columnClass: 'shrink',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'nextEntryFk',
|
||||
align: 'center',
|
||||
label: t('negative.nextEntryFk'),
|
||||
format: ({ nextEntryFk }) => nextEntryFk,
|
||||
sortable: false,
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
name: 'nextEntryLanded',
|
||||
align: 'center',
|
||||
label: t('negative.nextEntryLanded'),
|
||||
format: ({ nextEntryLanded }) => toDate(nextEntryLanded),
|
||||
sortable: false,
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
name: 'longName',
|
||||
align: 'left',
|
||||
|
@ -194,6 +211,12 @@ const setUserParams = (params) => {
|
|||
<span @click.stop>{{ row.itemFk }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #column-nextEntryFk="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.nextEntryFk }}
|
||||
<EntryDescriptorProxy :id="row.nextEntryFk" />
|
||||
</span>
|
||||
</template>
|
||||
<template #column-longName="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.longName }}
|
||||
|
|
|
@ -206,7 +206,6 @@ ticketList:
|
|||
toLines: Go to lines
|
||||
addressNickname: Address nickname
|
||||
ref: Reference
|
||||
hour: Hour
|
||||
rounding: Rounding
|
||||
noVerifiedData: No verified data
|
||||
purchaseRequest: Purchase request
|
||||
|
@ -214,6 +213,8 @@ ticketList:
|
|||
clientFrozen: Client frozen
|
||||
componentLack: Component lack
|
||||
negative:
|
||||
nextEntryFk: Next entry
|
||||
nextEntryLanded: Next entry landed
|
||||
hour: Hour
|
||||
id: Id Article
|
||||
longName: Article
|
||||
|
@ -224,6 +225,7 @@ negative:
|
|||
value: Negative
|
||||
itemFk: Article
|
||||
producer: Producer
|
||||
excludedDates: Excluded dates
|
||||
warehouse: Warehouse
|
||||
warehouseFk: Warehouse
|
||||
category: Category
|
||||
|
|
|
@ -215,6 +215,8 @@ ticketList:
|
|||
addressNickname: Alias consignatario
|
||||
ref: Referencia
|
||||
negative:
|
||||
nextEntryLanded: F. Entrada
|
||||
nextEntryFk: Entrada
|
||||
hour: Hora
|
||||
id: Id Articulo
|
||||
longName: Artículo
|
||||
|
@ -225,7 +227,8 @@ negative:
|
|||
origen: Origen
|
||||
value: Negativo
|
||||
warehouseFk: Almacen
|
||||
producer: Producer
|
||||
producer: Productor
|
||||
excludedDates: Fechas excluidas
|
||||
category: Categoría
|
||||
categoryFk: Familia
|
||||
typeFk: Familia
|
||||
|
|
|
@ -1,147 +1,173 @@
|
|||
/// <reference types="cypress" />
|
||||
describe.skip('Ticket Lack detail', () => {
|
||||
|
||||
const firstRow = 'tr.cursor-pointer > :nth-child(1)';
|
||||
const ticketId = 1000000;
|
||||
const findTr = (index) => `tbody > tr > :nth-child(${index}) > div`;
|
||||
const clickNotificationAction = () => {
|
||||
const notification = '.q-notification';
|
||||
cy.waitForElement(notification);
|
||||
cy.get(notification).should('be.visible');
|
||||
cy.get(notification).find('.q-btn').click();
|
||||
cy.get(notification).should('not.be.visible');
|
||||
};
|
||||
describe('Ticket Lack detail', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.intercept('GET', /\/api\/Tickets\/itemLack\/5.*$/, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
saleFk: 33,
|
||||
code: 'OK',
|
||||
ticketFk: 142,
|
||||
nickname: 'Malibu Point',
|
||||
shipped: '2000-12-31T23:00:00.000Z',
|
||||
hour: 0,
|
||||
quantity: 50,
|
||||
agName: 'Super-Man delivery',
|
||||
alertLevel: 0,
|
||||
stateName: 'OK',
|
||||
stateId: 3,
|
||||
itemFk: 5,
|
||||
price: 1.79,
|
||||
alertLevelCode: 'FREE',
|
||||
zoneFk: 9,
|
||||
zoneName: 'Zone superMan',
|
||||
theoreticalhour: '2011-11-01T22:59:00.000Z',
|
||||
isRookie: 1,
|
||||
turno: 1,
|
||||
peticionCompra: 1,
|
||||
hasObservation: 1,
|
||||
hasToIgnore: 1,
|
||||
isBasket: 1,
|
||||
minTimed: 0,
|
||||
customerId: 1104,
|
||||
customerName: 'Tony Stark',
|
||||
observationTypeCode: 'administrative',
|
||||
},
|
||||
],
|
||||
}).as('getItemLack');
|
||||
cy.intercept('GET', /\/api\/Tickets\/itemLack\/88.*$/).as('getItemLack');
|
||||
cy.visit('/#/ticket/negative/88');
|
||||
|
||||
cy.visit('/#/ticket/negative/5', false);
|
||||
cy.wait('@getItemLack');
|
||||
cy.wait('@getItemLack').then((interception) => {
|
||||
const { query } = interception.request;
|
||||
const filter = JSON.parse(query.filter);
|
||||
expect(filter).to.have.property('where');
|
||||
expect(filter.where).to.have.property('alertLevelCode', 'FREE');
|
||||
});
|
||||
cy.domContentLoad();
|
||||
cy.waitForElement('.q-table');
|
||||
});
|
||||
describe('Table actions', () => {
|
||||
describe('Table detail', () => {
|
||||
it('should open descriptors', () => {
|
||||
cy.get('.q-table').should('be.visible');
|
||||
cy.colField('zoneName').click();
|
||||
cy.dataCy('zoneDescriptorProxy').should('be.visible');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
|
||||
cy.colField('ticketFk').click();
|
||||
cy.dataCy('ticketDescriptorProxy').should('be.visible');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ` #${ticketId}`);
|
||||
cy.colField('nickname').find('.link').click();
|
||||
cy.waitForElement('[data-cy="customerDescriptorProxy"]');
|
||||
cy.dataCy('customerDescriptorProxy').should('be.visible');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
|
||||
});
|
||||
it('should display only one row in the lack list', () => {
|
||||
cy.location('href').should('contain', '#/ticket/negative/5');
|
||||
|
||||
cy.get('[data-cy="changeItem"]').should('be.disabled');
|
||||
cy.get('[data-cy="changeState"]').should('be.disabled');
|
||||
cy.get('[data-cy="changeQuantity"]').should('be.disabled');
|
||||
cy.get('[data-cy="itemProposal"]').should('be.disabled');
|
||||
cy.get('[data-cy="transferLines"]').should('be.disabled');
|
||||
cy.dataCy('changeItem').should('be.disabled');
|
||||
cy.dataCy('changeState').should('be.disabled');
|
||||
cy.dataCy('changeQuantity').should('be.disabled');
|
||||
cy.dataCy('itemProposal').should('be.disabled');
|
||||
cy.dataCy('transferLines').should('be.disabled');
|
||||
cy.get('tr.cursor-pointer > :nth-child(1)').click();
|
||||
cy.get('[data-cy="changeItem"]').should('be.enabled');
|
||||
cy.get('[data-cy="changeState"]').should('be.enabled');
|
||||
cy.get('[data-cy="changeQuantity"]').should('be.enabled');
|
||||
cy.get('[data-cy="itemProposal"]').should('be.enabled');
|
||||
cy.get('[data-cy="transferLines"]').should('be.enabled');
|
||||
cy.dataCy('changeItem').should('be.enabled');
|
||||
cy.dataCy('changeState').should('be.enabled');
|
||||
cy.dataCy('changeQuantity').should('be.enabled');
|
||||
cy.dataCy('itemProposal').should('be.enabled');
|
||||
cy.dataCy('transferLines').should('be.enabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Split', () => {
|
||||
beforeEach(() => {
|
||||
cy.get(firstRow).click();
|
||||
cy.dataCy('transferLines').click();
|
||||
});
|
||||
it('Split', () => {
|
||||
cy.dataCy('ticketTransferPopup').find('.flex > .q-btn').click();
|
||||
|
||||
clickNotificationAction();
|
||||
|
||||
cy.dataCy('HandleLackDialog').should('be.visible');
|
||||
cy.dataCy('HandleLackDialog').find('tbody > tr > :nth-child(1) > .q-icon');
|
||||
cy.dataCy('HandleLackDialog').find(findTr(2)).should('have.class', 'link');
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.find(`${findTr(2)}.link > div > span`)
|
||||
.should('have.text', `${ticketId} `);
|
||||
cy.dataCy('HandleLackDialog').find(findTr(3)).should('have.text', 'noSplit');
|
||||
});
|
||||
});
|
||||
describe('Change Item', () => {
|
||||
beforeEach(() => {
|
||||
cy.get(firstRow).click();
|
||||
cy.dataCy('changeItem').click();
|
||||
});
|
||||
it('Change failed', () => {
|
||||
cy.dataCy('New item_select').should('be.visible').click();
|
||||
cy.get('.q-item').contains('Palito rojo').click();
|
||||
cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
|
||||
|
||||
clickNotificationAction();
|
||||
|
||||
cy.dataCy('HandleLackDialog').should('be.visible');
|
||||
cy.dataCy('HandleLackDialog').find('tbody > tr > :nth-child(1) > .q-icon');
|
||||
cy.dataCy('HandleLackDialog').find(findTr(2)).should('have.class', 'link');
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.find(`${findTr(2)}.link > span`)
|
||||
.should('have.text', `${ticketId}`);
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.find(findTr(3))
|
||||
.should('have.text', 'price retrieval failed');
|
||||
});
|
||||
});
|
||||
describe('Change state', () => {
|
||||
beforeEach(() => {
|
||||
cy.get(firstRow).click();
|
||||
cy.dataCy('changeState').click();
|
||||
});
|
||||
it('Change success', () => {
|
||||
cy.dataCy('New state_select').should('be.visible').click();
|
||||
cy.get('.q-item').contains('OK').click();
|
||||
cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
|
||||
|
||||
clickNotificationAction();
|
||||
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.should('be.visible')
|
||||
.find('tbody > tr > :nth-child(1) > .q-icon');
|
||||
cy.dataCy('HandleLackDialog').find(findTr(2)).should('have.class', 'link');
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.find(`${findTr(2)}.link > div > span`)
|
||||
.should('have.text', `${ticketId} `);
|
||||
cy.dataCy('HandleLackDialog').find(findTr(3)).should('have.text', 'OK');
|
||||
});
|
||||
});
|
||||
describe('change quantity', () => {
|
||||
beforeEach(() => {
|
||||
cy.get(firstRow).click();
|
||||
|
||||
cy.dataCy('changeQuantity').click();
|
||||
});
|
||||
|
||||
it('Change success', () => {
|
||||
cy.dataCy('New quantity_input').type(10);
|
||||
cy.get('.q-btn--unelevated > .q-btn__content > .block').click();
|
||||
|
||||
clickNotificationAction();
|
||||
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.should('be.visible')
|
||||
.find('tbody > tr > :nth-child(1) > .q-icon');
|
||||
cy.dataCy('HandleLackDialog').find(findTr(2)).should('have.class', 'link');
|
||||
cy.dataCy('HandleLackDialog')
|
||||
.find(`${findTr(2)}.link > div > span`)
|
||||
.should('have.text', `${ticketId} `);
|
||||
cy.dataCy('HandleLackDialog').find(findTr(3)).should('have.text', '10');
|
||||
});
|
||||
});
|
||||
describe('Item proposal', () => {
|
||||
beforeEach(() => {
|
||||
cy.get('tr.cursor-pointer > :nth-child(1)').click();
|
||||
|
||||
cy.intercept('GET', /\/api\/Items\/getSimilar\?.*$/, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
id: 1,
|
||||
longName: 'Ranged weapon longbow 50cm',
|
||||
subName: 'Stark Industries',
|
||||
tag5: 'Color',
|
||||
value5: 'Brown',
|
||||
match5: 0,
|
||||
match6: 0,
|
||||
match7: 0,
|
||||
match8: 1,
|
||||
tag6: 'Categoria',
|
||||
value6: '+1 precission',
|
||||
tag7: 'Tallos',
|
||||
value7: '1',
|
||||
tag8: null,
|
||||
value8: null,
|
||||
available: 20,
|
||||
calc_id: 6,
|
||||
counter: 0,
|
||||
minQuantity: 1,
|
||||
visible: null,
|
||||
price2: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
longName: 'Ranged weapon longbow 100cm',
|
||||
subName: 'Stark Industries',
|
||||
tag5: 'Color',
|
||||
value5: 'Brown',
|
||||
match5: 0,
|
||||
match6: 1,
|
||||
match7: 0,
|
||||
match8: 1,
|
||||
tag6: 'Categoria',
|
||||
value6: '+1 precission',
|
||||
tag7: 'Tallos',
|
||||
value7: '1',
|
||||
tag8: null,
|
||||
value8: null,
|
||||
available: 50,
|
||||
calc_id: 6,
|
||||
counter: 1,
|
||||
minQuantity: 5,
|
||||
visible: null,
|
||||
price2: 10,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
longName: 'Ranged weapon longbow 200cm',
|
||||
subName: 'Stark Industries',
|
||||
tag5: 'Color',
|
||||
value5: 'Brown',
|
||||
match5: 1,
|
||||
match6: 1,
|
||||
match7: 1,
|
||||
match8: 1,
|
||||
tag6: 'Categoria',
|
||||
value6: '+1 precission',
|
||||
tag7: 'Tallos',
|
||||
value7: '1',
|
||||
tag8: null,
|
||||
value8: null,
|
||||
available: 185,
|
||||
calc_id: 6,
|
||||
counter: 10,
|
||||
minQuantity: 10,
|
||||
visible: null,
|
||||
price2: 100,
|
||||
},
|
||||
],
|
||||
}).as('getItemGetSimilar');
|
||||
cy.get('[data-cy="itemProposal"]').click();
|
||||
cy.wait('@getItemGetSimilar');
|
||||
cy.get(firstRow).click();
|
||||
cy.dataCy('itemProposal').click();
|
||||
});
|
||||
describe.skip('Replace item if', () => {
|
||||
it('Quantity is less than available', () => {
|
||||
describe('Replace item if', () => {
|
||||
it.skip('Quantity is less than available', () => {
|
||||
cy.get(':nth-child(1) > .text-right > .q-btn').click();
|
||||
});
|
||||
|
||||
it('item proposal cells', () => {
|
||||
cy.get('[data-col-field="longName"] .link').first().click();
|
||||
|
||||
cy.dataCy('itemDescriptorProxy').should('be.visible');
|
||||
|
||||
cy.colField('longName', 2)
|
||||
.find('.no-padding > .q-td > .middle')
|
||||
.should('have.class', 'proposal-primary');
|
||||
cy.colField('tag5', 2)
|
||||
.find('.no-padding > .match')
|
||||
.should('have.class', 'match');
|
||||
cy.colField('tag6', 2)
|
||||
.find('.no-padding > .match')
|
||||
.should('have.class', 'match');
|
||||
cy.colField('tag7', 2).click();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,34 +1,16 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('Ticket Lack list', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.intercept('GET', /Tickets\/itemLack\?.*$/, {
|
||||
statusCode: 200,
|
||||
body: [
|
||||
{
|
||||
itemFk: 5,
|
||||
longName: 'Ranged weapon pistol 9mm',
|
||||
warehouseFk: 1,
|
||||
producer: null,
|
||||
size: 15,
|
||||
category: null,
|
||||
warehouse: 'Warehouse One',
|
||||
lack: -50,
|
||||
inkFk: 'SLV',
|
||||
timed: '2025-01-25T22:59:00.000Z',
|
||||
minTimed: '23:59',
|
||||
originFk: 'Holand',
|
||||
},
|
||||
],
|
||||
}).as('getLack');
|
||||
cy.viewport(1280, 720);
|
||||
|
||||
cy.login('developer');
|
||||
cy.visit('/#/ticket/negative');
|
||||
});
|
||||
|
||||
describe('Table actions', () => {
|
||||
it('should display only one row in the lack list', () => {
|
||||
cy.wait('@getLack', { timeout: 10000 });
|
||||
|
||||
cy.get('[data-col-field="longName"]').first().click();
|
||||
cy.dataCy('itemDescriptorProxy').should('be.visible');
|
||||
cy.get('.q-virtual-scroll__content > :nth-child(1) > .sticky').click();
|
||||
cy.location('href').should('contain', '#/ticket/negative/5');
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue