Merge branch 'master' into Hotfix-OpenFilesInsteadOfDownloading
gitea/salix-front/pipeline/pr-master This commit looks good
Details
gitea/salix-front/pipeline/pr-master This commit looks good
Details
This commit is contained in:
commit
a8f6a31cef
|
@ -56,26 +56,6 @@ const defaultColumnAttrs = {
|
||||||
sortable: false,
|
sortable: false,
|
||||||
};
|
};
|
||||||
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
|
const emit = defineEmits(['onDialogClosed', 'itemReplaced']);
|
||||||
|
|
||||||
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(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
...defaultColumnAttrs,
|
...defaultColumnAttrs,
|
||||||
|
@ -196,7 +176,6 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
title: t('Replace'),
|
title: t('Replace'),
|
||||||
icon: 'change_circle',
|
icon: 'change_circle',
|
||||||
show: (row) => isSelectionAvailable(row),
|
|
||||||
action: change,
|
action: change,
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
|
@ -204,11 +183,18 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
function extractMatchValues(obj) {
|
const priceStatusClass = (proposalPrice) => {
|
||||||
return Object.keys(obj)
|
const originalPrice = sale.value?.price;
|
||||||
.filter((key) => key.startsWith(MATCH))
|
const { lackAlertPrice: lackAlert } = ticketConfig.value;
|
||||||
.map((key) => parseInt(key.replace(MATCH, ''), 10));
|
if (!originalPrice || !ticketConfig.value || typeof lackAlert !== 'number') {
|
||||||
|
return 'price-ok';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const percentage = ((proposalPrice - originalPrice) / originalPrice) * 100;
|
||||||
|
|
||||||
|
return percentage > lackAlert ? 'price-alert' : 'price-ok';
|
||||||
|
};
|
||||||
|
|
||||||
const gradientStyleClass = (row) => {
|
const gradientStyleClass = (row) => {
|
||||||
let color = 'white';
|
let color = 'white';
|
||||||
const value = parseFloat(row);
|
const value = parseFloat(row);
|
||||||
|
@ -226,28 +212,49 @@ const gradientStyleClass = (row) => {
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const extractMatchValues = (obj) => {
|
||||||
|
return Object.keys(obj)
|
||||||
|
.filter((key) => key.startsWith(MATCH))
|
||||||
|
.map((key) => parseInt(key.replace(MATCH, ''), 10));
|
||||||
|
};
|
||||||
|
|
||||||
const statusConditionalValue = (row) => {
|
const statusConditionalValue = (row) => {
|
||||||
const matches = extractMatchValues(row);
|
const matches = extractMatchValues(row);
|
||||||
const value = matches.reduce((acc, i) => acc + row[`${MATCH}${i}`], 0);
|
const value = matches.reduce((acc, i) => acc + row[`${MATCH}${i}`], 0);
|
||||||
return 100 * (value / matches.length);
|
return 100 * (value / matches.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSelectionAvailable = (itemProposal) => {
|
const canReplace = (itemProposal) => {
|
||||||
const { price2, available } = itemProposal;
|
if (!canReplaceByPrice(itemProposal)) {
|
||||||
const salePrice = sale.value.price;
|
return false;
|
||||||
const { lackAlertPrice } = ticketConfig.value;
|
|
||||||
const isPriceTooHigh = (100 * price2) / salePrice > lackAlertPrice;
|
|
||||||
if (isPriceTooHigh) {
|
|
||||||
return isPriceTooHigh;
|
|
||||||
}
|
}
|
||||||
const hasEnoughQuantity =
|
return canReplaceByQuantity(itemProposal);
|
||||||
(100 * available) / Math.abs($props.itemLack.lack) < lackAlertPrice;
|
};
|
||||||
return hasEnoughQuantity;
|
const differenceByPrice = ({ price2: proposalPrice }) => {
|
||||||
|
const { price: salePrice } = sale.value;
|
||||||
|
const percentage = ((proposalPrice - salePrice) / salePrice) * 100;
|
||||||
|
return percentage;
|
||||||
|
};
|
||||||
|
const canReplaceByPrice = (itemProposal) =>
|
||||||
|
differenceByPrice(itemProposal) < ticketConfig.value.lackAlertPrice;
|
||||||
|
|
||||||
|
const differenceByQuantity = ({ available }) => {
|
||||||
|
const { quantity: saleQuantity } = sale.value;
|
||||||
|
const percentage = ((saleQuantity - available) / available) * 100;
|
||||||
|
return percentage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const canReplaceByQuantity = (itemProposal) =>
|
||||||
|
differenceByQuantity(itemProposal) < ticketConfig.value.lackAlertPrice;
|
||||||
|
|
||||||
async function change(itemSubstitution) {
|
async function change(itemSubstitution) {
|
||||||
if (!isSelectionAvailable(itemSubstitution)) {
|
if (!canReplaceByPrice(itemSubstitution)) {
|
||||||
notify(t('notAvailable'), 'warning');
|
notify(t('notAvailableByPrice'), 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!canReplaceByQuantity(itemSubstitution)) {
|
||||||
|
notify(t('notAvailableByQuantity'), 'warning');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { itemFk: substitutionFk } = itemSubstitution;
|
const { itemFk: substitutionFk } = itemSubstitution;
|
||||||
|
@ -277,9 +284,7 @@ async function handleTicketConfig(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterRows(data) {
|
function filterRows(data) {
|
||||||
const filteredRows = data.sort(
|
const filteredRows = data.sort((a, b) => canReplace(b) - canReplace(a));
|
||||||
(a, b) => isSelectionAvailable(b) - isSelectionAvailable(a),
|
|
||||||
);
|
|
||||||
proposalTableRef.value.CrudModelRef.formData = filteredRows;
|
proposalTableRef.value.CrudModelRef.formData = filteredRows;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -315,6 +320,7 @@ function filterRows(data) {
|
||||||
>
|
>
|
||||||
<template #top-right>
|
<template #top-right>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
:disable="false"
|
||||||
flat
|
flat
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -369,16 +375,19 @@ function filterRows(data) {
|
||||||
</template>
|
</template>
|
||||||
<template #column-price2="{ row }">
|
<template #column-price2="{ row }">
|
||||||
<div class="flex column items-center content-center">
|
<div class="flex column items-center content-center">
|
||||||
<!-- Use class binding for tooltip background -->
|
|
||||||
<QTooltip :offset="[0, 5]" anchor="top middle" self="bottom middle">
|
<QTooltip :offset="[0, 5]" anchor="top middle" self="bottom middle">
|
||||||
<div>{{ $t('proposal.price2') }}: {{ toCurrency(row.price2) }}</div>
|
<div>{{ $t('proposal.price2') }}: {{ toCurrency(row.price2) }}</div>
|
||||||
<div>
|
<div>
|
||||||
{{ $t('proposal.itemOldPrice') }}:
|
{{ $t('proposal.itemOldPrice') }}:{{
|
||||||
{{ toCurrency(sales[0]?.price) }}
|
toCurrency(sales[0]?.price)
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
<div>{{ $t('%€') }}: {{ differenceByPrice(row) }}%</div>
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
<VnStockValueDisplay :format="'currency'" :value="-row.price2 / 100" />
|
<VnStockValueDisplay
|
||||||
<!-- Use class binding for text color -->
|
:format="'currency'"
|
||||||
|
:value="row.price2 - sales[0]?.price"
|
||||||
|
/>
|
||||||
<span :class="[priceStatusClass(row.price2)]">{{
|
<span :class="[priceStatusClass(row.price2)]">{{
|
||||||
toCurrency(row.price2)
|
toCurrency(row.price2)
|
||||||
}}</span>
|
}}</span>
|
||||||
|
@ -434,7 +443,12 @@ function filterRows(data) {
|
||||||
</style>
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
notAvailable: 'Not available for replacement'
|
notAvailable: Not available for replacement
|
||||||
|
notAvailableByPrice: Not available for replacement by price
|
||||||
|
notAvailableByQuantity: Not available for replacement by quantity
|
||||||
es:
|
es:
|
||||||
notAvailable: 'No disponible para reemplazo'
|
notAvailable: No disponible para reemplazo
|
||||||
|
notAvailableByPrice: No disponible para reemplazo por precio
|
||||||
|
notAvailableByQuantity: No disponible para reemplazo por cantidad
|
||||||
|
Replace: Remplazar
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -26,7 +26,8 @@ const { notify } = useNotify();
|
||||||
const totalRows = ref({});
|
const totalRows = ref({});
|
||||||
const arrayData = useArrayData('SupplierConsumption', {
|
const arrayData = useArrayData('SupplierConsumption', {
|
||||||
url: 'Suppliers/consumption',
|
url: 'Suppliers/consumption',
|
||||||
order: ['itemTypeFk', 'itemName', 'itemSize'],
|
order: ['shipped DESC', 'itemTypeFk', 'itemName', 'itemSize'],
|
||||||
|
limit: 0,
|
||||||
userFilter: { where: { supplierFk: route.params.id } },
|
userFilter: { where: { supplierFk: route.params.id } },
|
||||||
});
|
});
|
||||||
const headerColumns = computed(() => [
|
const headerColumns = computed(() => [
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
import split from './components/split';
|
import split from './components/split';
|
||||||
import { displayResults } from 'src/pages/Ticket/Negative/composables/notifyResults';
|
import { displayResults } from 'src/pages/Ticket/Negative/composables/notifyResults';
|
||||||
const { notifyResults } = displayResults();
|
const { notifyResults } = displayResults();
|
||||||
const emit = defineEmits(['ticketTransferred']);
|
const emit = defineEmits(['ticketTransferred']);
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
ticket: {
|
ticket: {
|
||||||
|
@ -27,7 +29,7 @@ const splitSelectedRows = async () => {
|
||||||
<template>
|
<template>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
:label="$t('New date')"
|
:label="t('New date')"
|
||||||
v-model="splitDate"
|
v-model="splitDate"
|
||||||
clearable
|
clearable
|
||||||
autofocus
|
autofocus
|
||||||
|
@ -41,6 +43,9 @@ const splitSelectedRows = async () => {
|
||||||
</style>
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
|
New date: Nueva fecha
|
||||||
|
Split: Separar
|
||||||
|
Transfer lines: Transferir líneas
|
||||||
Sales to transfer: Líneas a transferir
|
Sales to transfer: Líneas a transferir
|
||||||
Destination ticket: Ticket destinatario
|
Destination ticket: Ticket destinatario
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import '../commands.js';
|
import '../commands.js';
|
||||||
describe('EntryBuys', () => {
|
describe.skip('EntryBuys', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1920, 1080);
|
cy.viewport(1920, 1080);
|
||||||
cy.login('buyer');
|
cy.login('buyer');
|
||||||
|
|
|
@ -13,7 +13,7 @@ const clickNotificationAction = () => {
|
||||||
expect(firstArg).to.include(`/ticket/${ticketId}/sale`);
|
expect(firstArg).to.include(`/ticket/${ticketId}/sale`);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
describe('Ticket Lack detail', { testIsolation: true }, () => {
|
describe.skip('Ticket Lack detail', { testIsolation: true }, () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.viewport(1980, 1020);
|
cy.viewport(1980, 1020);
|
||||||
cy.login('developer');
|
cy.login('developer');
|
||||||
|
|
Loading…
Reference in New Issue