Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/salix-front into beta
gitea/salix-front/pipeline/head There was a failure building this commit Details

This commit is contained in:
Alex Moreno 2025-04-07 14:25:57 +02:00
commit 308b14c3bc
40 changed files with 219 additions and 277 deletions

2
Jenkinsfile vendored
View File

@ -125,7 +125,7 @@ pipeline {
sh "docker-compose ${env.COMPOSE_PARAMS} up -d" sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") { image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") {
sh 'sh test/cypress/cypressParallel.sh 2' sh 'sh test/cypress/cypressParallel.sh 1'
} }
} }
} }

View File

@ -17,17 +17,6 @@ defineProps({ row: { type: Object, required: true } });
</QTooltip> </QTooltip>
</QIcon> </QIcon>
</router-link> </router-link>
<QIcon
v-if="row?.reserved"
color="primary"
name="vn:reserva"
size="xs"
data-cy="ticketSaleReservedIcon"
>
<QTooltip>
{{ t('ticketSale.reserved') }}
</QTooltip>
</QIcon>
<QIcon <QIcon
v-if="row?.isDeleted" v-if="row?.isDeleted"
color="primary" color="primary"

View File

@ -1,35 +1,14 @@
<script setup> <script setup>
import { nextTick, ref } from 'vue';
import VnInput from './VnInput.vue'; import VnInput from './VnInput.vue';
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard'; import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
const $props = defineProps({
insertable: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['update:modelValue', 'accountShortToStandard']);
const model = defineModel({ prop: 'modelValue' }); const model = defineModel({ prop: 'modelValue' });
const inputRef = ref(false);
function setCursorPosition(pos) {
const input = inputRef.value.vnInputRef.$el.querySelector('input');
input.focus();
input.setSelectionRange(pos, pos);
}
async function handleUpdateModel(val) {
model.value = val?.at(-1) === '.' ? useAccountShortToStandard(val) : val;
await nextTick(() => setCursorPosition(0));
}
</script> </script>
<template> <template>
<VnInput <VnInput
v-model="model" v-model="model"
ref="inputRef" ref="inputRef"
:insertable @keydown.tab="model = useAccountShortToStandard($event.target.value) ?? model"
@update:model-value="handleUpdateModel" @input="model = $event.target.value.replace(/[^\d.]/g, '')"
/> />
</template> </template>

View File

@ -15,7 +15,7 @@ const editDownloadDisabled = ref(false);
const $props = defineProps({ const $props = defineProps({
defaultDmsCode: { defaultDmsCode: {
type: String, type: String,
default: 'InvoiceIn', default: 'invoiceIn',
}, },
disable: { disable: {
type: Boolean, type: Boolean,

View File

@ -841,6 +841,7 @@ travel:
availabledHour: Availabled hour availabledHour: Availabled hour
thermographs: Thermographs thermographs: Thermographs
hb: HB hb: HB
roundedCc: Rounded CC
basicData: basicData:
daysInForward: Automatic movement (Raid) daysInForward: Automatic movement (Raid)
isRaid: Raid isRaid: Raid

View File

@ -924,6 +924,7 @@ travel:
availabled: F. Disponible availabled: F. Disponible
availabledHour: Hora Disponible availabledHour: Hora Disponible
hb: HB hb: HB
roundedCc: CC redondeado
basicData: basicData:
daysInForward: Desplazamiento automatico (redada) daysInForward: Desplazamiento automatico (redada)
isRaid: Redada isRaid: Redada

View File

@ -105,15 +105,6 @@ const debtWarning = computed(() => {
> >
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip> <QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
</QIcon> </QIcon>
<QIcon
v-if="entity?.substitutionAllowed"
name="help"
size="xs"
color="primary"
>
<QTooltip>{{ t('Allowed substitution') }}</QTooltip>
</QIcon>
<QIcon <QIcon
v-if="!entity.account?.active" v-if="!entity.account?.active"
color="primary" color="primary"

View File

@ -61,16 +61,6 @@ const openCreateForm = (type) => {
.join('&'); .join('&');
useOpenURL(`/#/${type}/list?${params}`); useOpenURL(`/#/${type}/list?${params}`);
}; };
const updateSubstitutionAllowed = async () => {
try {
await axios.patch(`Clients/${route.params.id}`, {
substitutionAllowed: !$props.customer.substitutionAllowed,
});
notify('globals.notificationSent', 'positive');
} catch (error) {
notify(error.message, 'positive');
}
};
</script> </script>
<template> <template>
@ -79,13 +69,6 @@ const updateSubstitutionAllowed = async () => {
{{ t('globals.pageTitles.createTicket') }} {{ t('globals.pageTitles.createTicket') }}
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem v-ripple clickable>
<QItemSection @click="updateSubstitutionAllowed()">{{
$props.customer.substitutionAllowed
? t('Disable substitution')
: t('Allow substitution')
}}</QItemSection>
</QItem>
<QItem v-ripple clickable> <QItem v-ripple clickable>
<QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection> <QItemSection @click="showSmsDialog()">{{ t('Send SMS') }}</QItemSection>
</QItem> </QItem>

View File

@ -73,6 +73,7 @@ const exprBuilder = (param, value) => {
option-value="id" option-value="id"
option-label="name" option-label="name"
url="Departments" url="Departments"
no-one="true"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -161,6 +162,7 @@ en:
city: City city: City
phone: Phone phone: Phone
email: Email email: Email
departmentFk: Department
isToBeMailed: Mailed isToBeMailed: Mailed
isEqualizated: Equailized isEqualizated: Equailized
businessTypeFk: Business type businessTypeFk: Business type
@ -176,6 +178,7 @@ es:
search: Contiene search: Contiene
fi: NIF fi: NIF
isActive: Activo isActive: Activo
departmentFk: Departamento
isToBeMailed: A enviar isToBeMailed: A enviar
isEqualizated: Recargo de equivalencia isEqualizated: Recargo de equivalencia
businessTypeFk: Tipo de negocio businessTypeFk: Tipo de negocio

View File

@ -127,6 +127,7 @@ es:
Identifier: Identificador Identifier: Identificador
Social name: Razón social Social name: Razón social
Phone: Teléfono Phone: Teléfono
Postcode: Código postal
City: Población City: Población
Email: Email Email: Email
Campaign consumption: Consumo campaña Campaign consumption: Consumo campaña

View File

@ -93,10 +93,26 @@ const updateAddressTicket = async () => {
}; };
const updateObservations = async (payload) => { const updateObservations = async (payload) => {
await axios.post('AddressObservations/crud', payload); await axios.post('AddressObservations/crud', cleanPayload(payload));
notes.value = []; notes.value = [];
deletes.value = []; deletes.value = [];
}; };
function cleanPayload(payload) {
['creates', 'deletes', 'updates'].forEach((prop) => {
if (prop === 'creates' || prop === 'updates') {
payload[prop] = payload[prop].filter(
(item) => item.description !== '' && item.observationTypeFk !== '',
);
} else {
payload[prop] = payload[prop].filter(
(item) => item !== null && item !== undefined,
);
}
});
return payload;
}
async function updateAll({ data, payload }) { async function updateAll({ data, payload }) {
await updateObservations(payload); await updateObservations(payload);
await updateAddress(data); await updateAddress(data);

View File

@ -191,7 +191,7 @@ const getItemPackagingType = (ticketSales) => {
:without-header="true" :without-header="true"
auto-load auto-load
:row-click="rowClick" :row-click="rowClick"
order="shipped DESC, id" order="shipped DESC, id DESC"
:disable-option="{ card: true, table: true }" :disable-option="{ card: true, table: true }"
class="full-width" class="full-width"
:disable-infinite-scroll="true" :disable-infinite-scroll="true"

View File

@ -648,7 +648,7 @@ onMounted(() => {
:url="`Entries/${entityId}/getBuyList`" :url="`Entries/${entityId}/getBuyList`"
search-url="EntryBuys" search-url="EntryBuys"
save-url="Buys/crud" save-url="Buys/crud"
:filter="filter" :filter="editableMode ? filter : {}"
:disable-option="{ card: true }" :disable-option="{ card: true }"
v-model:selected="selectedRows" v-model:selected="selectedRows"
@on-fetch="() => footerFetchDataRef.fetch()" @on-fetch="() => footerFetchDataRef.fetch()"

View File

@ -8,6 +8,6 @@ import filter from './EntryFilter.js';
data-key="Entry" data-key="Entry"
url="Entries" url="Entries"
:descriptor="EntryDescriptor" :descriptor="EntryDescriptor"
:filter="filter" :filter="{ ...filter, where: { id: $route.params.id } }"
/> />
</template> </template>

View File

@ -147,7 +147,7 @@ async function deleteEntry() {
<template> <template>
<CardDescriptor <CardDescriptor
:url="`Entries/${entityId}`" :url="`Entries/${entityId}`"
:user-filter="entryFilter" :filter="entryFilter"
title="supplier.nickname" title="supplier.nickname"
data-key="Entry" data-key="Entry"
width="lg-width" width="lg-width"

View File

@ -248,7 +248,6 @@ function getBadgeAttrs(row) {
let timeDiff = today - timeTicket; let timeDiff = today - timeTicket;
if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' }; if (timeDiff < 0) return { color: 'warning', 'text-color': 'black' };
switch (row.entryTypeCode) { switch (row.entryTypeCode) {
case 'regularization': case 'regularization':
@ -274,6 +273,7 @@ function getBadgeAttrs(row) {
default: default:
break; break;
} }
if (timeDiff > 0) return { color: 'info', 'text-color': 'black' };
return { color: 'transparent' }; return { color: 'transparent' };
} }

View File

@ -116,6 +116,7 @@ const filter = computed(() => ({
hour: 0, hour: 0,
minute: 0, minute: 0,
second: 0, second: 0,
milliseconds: 0,
}), }),
m3: { neq: null }, m3: { neq: null },
}, },

View File

@ -26,7 +26,7 @@ const routes = reactive({
getSupplier: (id) => { getSupplier: (id) => {
return { name: 'SupplierCard', params: { id } }; return { name: 'SupplierCard', params: { id } };
}, },
getTickets: (id) => { getInvoices: (id) => {
return { return {
name: 'InvoiceInList', name: 'InvoiceInList',
query: { query: {
@ -135,11 +135,11 @@ async function setInvoiceCorrection(id) {
</QBtn> </QBtn>
<QBtn <QBtn
size="md" size="md"
icon="vn:ticket" icon="vn:invoice-in"
color="primary" color="primary"
:to="routes.getTickets(entity.supplierFk)" :to="routes.getInvoices(entity.supplierFk)"
> >
<QTooltip>{{ t('globals.ticketList') }}</QTooltip> <QTooltip>{{ t('invoiceIn.descriptor.invoices') }}</QTooltip>
</QBtn> </QBtn>
<QBtn <QBtn
v-if=" v-if="

View File

@ -14,6 +14,7 @@ invoiceIn:
amount: Amount amount: Amount
descriptor: descriptor:
ticketList: Ticket list ticketList: Ticket list
invoices: Supplier invoices
descriptorMenu: descriptorMenu:
book: Book book: Book
unbook: Unbook unbook: Unbook

View File

@ -13,7 +13,7 @@ invoiceIn:
awb: AWB awb: AWB
amount: Importe amount: Importe
descriptor: descriptor:
ticketList: Listado de tickets invoices: Facturas de proveedor
descriptorMenu: descriptorMenu:
book: Contabilizar book: Contabilizar
unbook: Descontabilizar unbook: Descontabilizar

View File

@ -1,13 +1,14 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import { toDateFormat } from 'src/filters/date.js'; import { toDateFormat } from 'src/filters/date.js';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnRow from 'src/components/ui/VnRow.vue'; import VnRow from 'src/components/ui/VnRow.vue';
import { dateRange } from 'src/filters'; import { dateRange } from 'src/filters';
import useOpenURL from 'src/composables/useOpenURL';
const { t } = useI18n(); const { t } = useI18n();
const dates = dateRange(Date.vnNew()); const dates = dateRange(Date.vnNew());
@ -94,6 +95,7 @@ const columns = computed(() => [
columnClass: 'no-padding', columnClass: 'no-padding',
}, },
]); ]);
const openTab = (id) => useOpenURL(`#/customer/${id}/summary`);
</script> </script>
<template> <template>
@ -113,6 +115,8 @@ const columns = computed(() => [
:disable-option="{ card: true }" :disable-option="{ card: true }"
dense dense
class="q-px-none" class="q-px-none"
:row-click="({ id }) => openTab(id)"
:row-ctrl-click="(_, { id }) => openTab(id)"
> >
<template #top-left> <template #top-left>
<VnRow> <VnRow>
@ -121,12 +125,16 @@ const columns = computed(() => [
</VnRow> </VnRow>
</template> </template>
<template #column-departmentFk="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" :title="row.department" v-text="row.department" /> <span @click.stop.prevent class="link" :title="row.department">
<WorkerDescriptorProxy :id="row.departmentFk" dense /> {{ row.department }}
<DepartmentDescriptorProxy :id="row.departmentFk" dense
/></span>
</template> </template>
<template #column-clientFk="{ row }"> <template #column-clientFk="{ row }">
<span class="link" :title="row.clientName" v-text="row.clientName" /> <span @click.stop.prevent class="link" :title="row.clientName">
<CustomerDescriptorProxy :id="row.clientFk" /> {{ row.clientName }}
<CustomerDescriptorProxy :id="row.clientFk" dense
/></span>
</template> </template>
</VnTable> </VnTable>
</template> </template>

View File

@ -9,6 +9,7 @@ import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
import { useVnConfirm } from 'composables/useVnConfirm'; import { useVnConfirm } from 'composables/useVnConfirm';
import axios from 'axios'; import axios from 'axios';
import useOpenURL from 'src/composables/useOpenURL';
const { t } = useI18n(); const { t } = useI18n();
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
@ -108,8 +109,7 @@ const removeOrders = async () => {
await table.value.reload(); await table.value.reload();
}; };
const openTab = (id) => const openTab = (id) => useOpenURL(`#/order/${id}/summary`);
window.open(`#/order/${id}/summary`, '_blank', 'noopener, noreferrer');
</script> </script>
<template> <template>
<VnTable <VnTable
@ -129,6 +129,7 @@ const openTab = (id) =>
}" }"
default-mode="table" default-mode="table"
:row-click="({ id }) => openTab(id)" :row-click="({ id }) => openTab(id)"
:row-ctrl-click="(_, { id }) => openTab(id)"
v-model:selected="selectedRows" v-model:selected="selectedRows"
:disable-option="{ card: true }" :disable-option="{ card: true }"
> >
@ -177,16 +178,16 @@ const openTab = (id) =>
</template> </template>
<template #column-clientFk="{ row }"> <template #column-clientFk="{ row }">
<QTd @click.stop> <span class="link" @click.stop :title="row.clientName">
<span class="link" v-text="row.clientName" :title="row.clientName" /> {{ row.clientName }}
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" dense
</QTd> /></span>
</template> </template>
<template #column-departmentFk="{ row }"> <template #column-departmentFk="{ row }">
<QTd @click.stop> <span class="link" @click.stop :title="row.departmentName">
<span class="link" v-text="row.departmentName" /> {{ row.departmentName }}
<DepartmentDescriptorProxy :id="row.departmentFk" dense /> <DepartmentDescriptorProxy :id="row.departmentFk" dense
</QTd> /></span>
</template> </template>
</VnTable> </VnTable>
</template> </template>

View File

@ -209,20 +209,6 @@ const getLocale = (label) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnSelect
outlined
dense
rounded
:label="t('globals.params.departmentFk')"
v-model="params.department"
option-label="name"
option-value="name"
url="Departments"
/>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelect <VnSelect

View File

@ -449,21 +449,19 @@ const openTab = (id) => useOpenURL(`#/ticket/${id}/sale`);
<span :title="row.province" v-text="row.province" /> <span :title="row.province" v-text="row.province" />
</template> </template>
<template #column-state="{ row }"> <template #column-state="{ row }">
<div @click.stop.prevent> <div v-if="row.refFk" @click.stop.prevent>
<div v-if="row.refFk"> <span class="link">{{ row.refFk }}</span>
<span class="link">{{ row.refFk }}</span> <InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
<InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
</div>
<QBadge
v-else
:color="stateColors[row.classColor] || 'transparent'"
:text-color="stateColors[row.classColor] ? 'black' : 'white'"
class="q-pa-sm"
style="font-size: 14px"
>
{{ row.state }}
</QBadge>
</div> </div>
<QBadge
v-else
:color="stateColors[row.classColor] || 'transparent'"
:text-color="stateColors[row.classColor] ? 'black' : 'white'"
class="q-pa-sm"
style="font-size: 14px"
>
{{ row.state }}
</QBadge>
</template> </template>
<template #column-isFragile="{ row }"> <template #column-isFragile="{ row }">
<QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm"> <QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm">

View File

@ -65,7 +65,6 @@ const columns = computed(() => [
attrs: { attrs: {
url: 'Departments', url: 'Departments',
}, },
create: true,
columnField: { columnField: {
component: null, component: null,
}, },

View File

@ -46,7 +46,6 @@ const columns = computed(() => [
}, },
isId: true, isId: true,
columnFilter: false, columnFilter: false,
width: '25px',
}, },
{ {
name: 'workerFk', name: 'workerFk',
@ -142,7 +141,6 @@ const columns = computed(() => [
label: 'm3', label: 'm3',
cardVisible: true, cardVisible: true,
columnClass: 'shrink', columnClass: 'shrink',
width: '50px',
}, },
{ {
name: 'started', name: 'started',
@ -150,7 +148,6 @@ const columns = computed(() => [
component: 'time', component: 'time',
columnFilter: false, columnFilter: false,
format: ({ started }) => toHour(started), format: ({ started }) => toHour(started),
width: '50px',
}, },
{ {
name: 'finished', name: 'finished',
@ -158,7 +155,6 @@ const columns = computed(() => [
component: 'time', component: 'time',
columnFilter: false, columnFilter: false,
format: ({ finished }) => toHour(finished), format: ({ finished }) => toHour(finished),
width: '50px',
}, },
{ {
align: 'right', align: 'right',

View File

@ -46,7 +46,6 @@ const columns = computed(() => [
condition: () => true, condition: () => true,
}, },
columnFilter: false, columnFilter: false,
width: '25px',
}, },
{ {
align: 'left', align: 'left',
@ -57,7 +56,6 @@ const columns = computed(() => [
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef), format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
columnFilter: false, columnFilter: false,
cardVisible: true, cardVisible: true,
width: '100px',
}, },
{ {
label: t('globals.agency'), label: t('globals.agency'),
@ -102,7 +100,6 @@ const columns = computed(() => [
cardVisible: true, cardVisible: true,
columnFilter: false, columnFilter: false,
format: ({ started }) => toHour(started), format: ({ started }) => toHour(started),
width: '50px',
}, },
{ {
align: 'center', align: 'center',
@ -111,7 +108,6 @@ const columns = computed(() => [
cardVisible: true, cardVisible: true,
columnFilter: false, columnFilter: false,
format: ({ finished }) => toHour(finished), format: ({ finished }) => toHour(finished),
width: '50px',
}, },
{ {
align: 'left', align: 'left',

View File

@ -44,7 +44,7 @@ const getPriceDifference = async () => {
shipped: ticket.value.shipped, shipped: ticket.value.shipped,
}; };
const { data } = await axios.post( const { data } = await axios.post(
`tickets/${formData.value.id}/priceDifference`, `tickets/${ticket.value.id}/priceDifference`,
params, params,
); );
ticket.value.sale = data; ticket.value.sale = data;
@ -71,7 +71,7 @@ const submit = async () => {
}; };
const { data } = await axios.post( const { data } = await axios.post(
`tickets/${formData.value.id}/componentUpdate`, `tickets/${ticket.value.id}/componentUpdate`,
params, params,
); );

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, ref, computed, watch } from 'vue'; import { onMounted, ref, computed, watch, inject } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -25,7 +25,7 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue';
import TicketProblems from 'src/components/TicketProblems.vue'; import TicketProblems from 'src/components/TicketProblems.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
const app = inject('app');
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
@ -187,20 +187,26 @@ const getRowUpdateInputEvents = (sale) => {
const resetChanges = async () => { const resetChanges = async () => {
arrayData.fetch({ append: false }); arrayData.fetch({ append: false });
tableRef.value.reload(); tableRef.value.CrudModelRef.hasChanges = false;
await tableRef.value.reload();
selectedRows.value = []; selectedRows.value = [];
}; };
const changeQuantity = async (sale) => { const changeQuantity = async (sale) => {
if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity) if (!sale.itemFk || sale.quantity == null || sale?.originalQuantity === sale.quantity)
return; return;
else sale.originalQuantity = sale.quantity; else sale.originalQuantity = sale.quantity;
if (!sale.id) return addSale(sale); try {
if (!sale.id) await addSale(sale);
} catch (e) {
app.config.errorHandler(e);
return;
}
if (await isSalePrepared(sale)) { if (await isSalePrepared(sale)) {
await confirmUpdate(() => updateQuantity(sale)); await confirmUpdate(() => updateQuantity(sale));
} else await updateQuantity(sale); } else await updateQuantity(sale);
}; };
const updateQuantity = async (sale) => { const updateQuantity = async (sale) => {
try { try {
let { quantity, id } = sale; let { quantity, id } = sale;
@ -213,7 +219,7 @@ const updateQuantity = async (sale) => {
(s) => s.id === sale.id, (s) => s.id === sale.id,
); );
sale.quantity = quantity; sale.quantity = quantity;
throw e; app.config.errorHandler(e);
} }
}; };
@ -222,24 +228,27 @@ const addSale = async (sale) => {
barcode: sale.itemFk, barcode: sale.itemFk,
quantity: sale.quantity, quantity: sale.quantity,
}; };
try {
const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params);
const { data } = await axios.post(`tickets/${route.params.id}/addSale`, params); if (!data) return;
if (!data) return; const newSale = data;
sale.id = newSale.id;
sale.image = newSale.item.image;
sale.subName = newSale.item.subName;
sale.concept = newSale.concept;
sale.quantity = newSale.quantity;
sale.discount = newSale.discount;
sale.price = newSale.price;
sale.item = newSale.item;
const newSale = data; notify('globals.dataSaved', 'positive');
sale.id = newSale.id; sale.isNew = false;
sale.image = newSale.item.image; resetChanges();
sale.subName = newSale.item.subName; } catch (e) {
sale.concept = newSale.concept; app.config.errorHandler(e);
sale.quantity = newSale.quantity; }
sale.discount = newSale.discount;
sale.price = newSale.price;
sale.item = newSale.item;
notify('globals.dataSaved', 'positive');
sale.isNew = false;
resetChanges();
}; };
const changeConcept = async (sale) => { const changeConcept = async (sale) => {
if (await isSalePrepared(sale)) { if (await isSalePrepared(sale)) {
@ -248,10 +257,14 @@ const changeConcept = async (sale) => {
}; };
const updateConcept = async (sale) => { const updateConcept = async (sale) => {
const data = { newConcept: sale.concept }; try {
await axios.post(`Sales/${sale.id}/updateConcept`, data); const data = { newConcept: sale.concept };
notify('globals.dataSaved', 'positive'); await axios.post(`Sales/${sale.id}/updateConcept`, data);
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const DEFAULT_EDIT = { const DEFAULT_EDIT = {
@ -262,18 +275,6 @@ const DEFAULT_EDIT = {
oldQuantity: null, oldQuantity: null,
}; };
const edit = ref({ ...DEFAULT_EDIT }); const edit = ref({ ...DEFAULT_EDIT });
const usesMana = ref(null);
const getUsesMana = async () => {
const { data } = await axios.get('Sales/usesMana');
usesMana.value = data;
};
const getMana = async () => {
const { data } = await axios.get(`Tickets/${route.params.id}/getDepartmentMana`);
mana.value = data;
await getUsesMana();
};
const selectedValidSales = computed(() => { const selectedValidSales = computed(() => {
if (!sales.value) return; if (!sales.value) return;
@ -310,11 +311,15 @@ const changePrice = async (sale) => {
} }
}; };
const updatePrice = async (sale, newPrice) => { const updatePrice = async (sale, newPrice) => {
await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice }); try {
sale.price = newPrice; await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
edit.value = { ...DEFAULT_EDIT }; sale.price = newPrice;
notify('globals.dataSaved', 'positive'); edit.value = { ...DEFAULT_EDIT };
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const changeDiscount = async (sale) => { const changeDiscount = async (sale) => {
@ -337,15 +342,20 @@ const updateDiscounts = async (sales, newDiscount) => {
}; };
const updateDiscount = async (sales, newDiscount = 0) => { const updateDiscount = async (sales, newDiscount = 0) => {
const salesIds = sales.map(({ id }) => id); try {
const params = { const salesIds = sales.map(({ id }) => id);
salesIds, const params = {
newDiscount, salesIds,
manaCode: manaCode.value, newDiscount,
}; manaCode: manaCode.value,
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params); };
notify('globals.dataSaved', 'positive'); await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
return;
}
}; };
const getNewPrice = computed(() => { const getNewPrice = computed(() => {
@ -367,11 +377,15 @@ const getNewPrice = computed(() => {
}); });
const newOrderFromTicket = async () => { const newOrderFromTicket = async () => {
const { data } = await axios.post(`Orders/newFromTicket`, { try {
ticketFk: Number(route.params.id), const { data } = await axios.post(`Orders/newFromTicket`, {
}); ticketFk: Number(route.params.id),
const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } }); });
window.open(routeData.href, '_blank'); const routeData = router.resolve({ name: 'OrderCatalog', params: { id: data } });
window.open(routeData.href, '_blank');
} catch (e) {
app.config.errorHandler(e);
}
}; };
const goToLog = (saleId) => { const goToLog = (saleId) => {
@ -386,11 +400,15 @@ const goToLog = (saleId) => {
}; };
const changeTicketState = async (val) => { const changeTicketState = async (val) => {
stateBtnDropdownRef.value.hide(); try {
const params = { ticketFk: route.params.id, code: val }; stateBtnDropdownRef.value.hide();
await axios.post('Tickets/state', params); const params = { ticketFk: route.params.id, code: val };
notify('globals.dataSaved', 'positive'); await axios.post('Tickets/state', params);
await resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const removeSelectedSales = () => { const removeSelectedSales = () => {
@ -410,10 +428,14 @@ const removeSales = async () => {
.forEach((sale) => tableRef.value.CrudModelRef.formData.splice(sale.$index, 1)); .forEach((sale) => tableRef.value.CrudModelRef.formData.splice(sale.$index, 1));
if (params.sales.length == 0) return; if (params.sales.length == 0) return;
await axios.post('Sales/deleteSales', params); try {
removeSelectedSales(); await axios.post('Sales/deleteSales', params);
notify('globals.dataSaved', 'positive'); removeSelectedSales();
resetChanges(); notify('globals.dataSaved', 'positive');
resetChanges();
} catch (e) {
app.config.errorHandler(e);
}
}; };
const setTransferParams = async () => { const setTransferParams = async () => {

View File

@ -62,6 +62,7 @@ const isClaimable = computed(() => {
} }
return false; return false;
}); });
const sendSms = async (params) => { const sendSms = async (params) => {
await axios.post(`Tickets/${ticket.value.id}/sendSms`, params); await axios.post(`Tickets/${ticket.value.id}/sendSms`, params);
notify(t('SMS sent'), 'positive'); notify(t('SMS sent'), 'positive');
@ -230,18 +231,6 @@ const createRefund = async (withWarehouse) => {
<QItemLabel>{{ t('Add claim') }}</QItemLabel> <QItemLabel>{{ t('Add claim') }}</QItemLabel>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem
v-if="isTicketEditable"
clickable
v-close-popup
v-ripple
@click="setReserved(true)"
data-cy="markAsReservedItem"
>
<QItemSection>
<QItemLabel>{{ t('Mark as reserved') }}</QItemLabel>
</QItemSection>
</QItem>
<QItem clickable v-ripple data-cy="ticketSaleRefundItem"> <QItem clickable v-ripple data-cy="ticketSaleRefundItem">
<QItemSection> <QItemSection>
<QItemLabel>{{ t('Refund') }}</QItemLabel> <QItemLabel>{{ t('Refund') }}</QItemLabel>
@ -287,8 +276,6 @@ es:
Recalculate price: Recalcular precio Recalculate price: Recalcular precio
Update discount: Actualizar descuento Update discount: Actualizar descuento
Add claim: Crear reclamación Add claim: Crear reclamación
Mark as reserved: Marcar como reservado
Unmark as reserved: Desmarcar como reservado
Refund: Abono Refund: Abono
with warehouse: con almacén with warehouse: con almacén
without warehouse: sin almacén without warehouse: sin almacén

View File

@ -8,6 +8,6 @@ import filter from './TravelFilter.js';
data-key="Travel" data-key="Travel"
url="Travels" url="Travels"
:descriptor="TravelDescriptor" :descriptor="TravelDescriptor"
:filter="filter" :filter="{ ...filter, where: { id: $route.params.id } }"
/> />
</template> </template>

View File

@ -91,6 +91,13 @@ const entriesTableColumns = computed(() => {
showValue: true, showValue: true,
}, },
{ label: 'CC', field: 'cc', name: 'cc', align: 'left', showValue: true }, { label: 'CC', field: 'cc', name: 'cc', align: 'left', showValue: true },
{
label: t('travel.summary.roundedCc'),
field: 'cc',
name: 'roundedCc',
align: 'left',
showValue: true,
},
{ {
label: 'Pallet', label: 'Pallet',
field: 'pallet', field: 'pallet',
@ -193,13 +200,18 @@ const entriesTotals = computed(() => {
freightValue: 0, freightValue: 0,
packageValue: 0, packageValue: 0,
cc: 0, cc: 0,
roundedCc: 0,
pallet: 0, pallet: 0,
m3: 0, m3: 0,
}; };
entriesTableRows.value.forEach((row) => { entriesTableRows.value.forEach((row) => {
for (const key in totals) { for (const key in totals) {
totals[key] += row[key] || 0; if (key === 'roundedCc') {
totals['roundedCc'] += Math.ceil(row['cc'] || 0);
} else {
totals[key] += row[key] || 0;
}
} }
}); });
@ -208,6 +220,7 @@ const entriesTotals = computed(() => {
freight: toCurrency(totals.freightValue), freight: toCurrency(totals.freightValue),
packageValue: toCurrency(totals.packageValue), packageValue: toCurrency(totals.packageValue),
cc: totals.cc.toFixed(2), cc: totals.cc.toFixed(2),
roundedCc: totals.roundedCc,
pallet: totals.pallet.toFixed(2), pallet: totals.pallet.toFixed(2),
m3: totals.m3.toFixed(2), m3: totals.m3.toFixed(2),
}; };
@ -255,13 +268,6 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
</script> </script>
<template> <template>
<FetchData
url="Warehouses"
:filter="{ fields: ['id', 'name'] }"
order="name"
@on-fetch="(data) => (warehouses = data)"
auto-load
/>
<CardSummary <CardSummary
ref="summaryRef" ref="summaryRef"
:url="`Travels/${entityId}/getTravel`" :url="`Travels/${entityId}/getTravel`"
@ -337,9 +343,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<VnLv :label="t('globals.totalEntries')" :value="travel.totalEntries" /> <VnLv :label="t('globals.totalEntries')" :value="travel.totalEntries" />
<VnLv <VnLv
:label="t('travel.summary.availabled')" :label="t('travel.summary.availabled')"
:value=" :value="dashIfEmpty(toDateTimeFormat(travel.availabled))"
dashIfEmpty(toDateTimeFormat(travel.availabled))
"
/> />
</QCard> </QCard>
<QCard class="full-width"> <QCard class="full-width">
@ -376,6 +380,11 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
</QBtn> </QBtn>
</QTd> </QTd>
</template> </template>
<template #body-cell-roundedCc="{ col, value }">
<QTd>
{{ Math.ceil(value) || 0 }}
</QTd>
</template>
<template #body-cell-observation="{ value }"> <template #body-cell-observation="{ value }">
<QTd> <QTd>
<QIcon name="insert_drive_file" color="primary" size="24px"> <QIcon name="insert_drive_file" color="primary" size="24px">
@ -392,23 +401,24 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QTd class="text-bold">{{ entriesTotals.freight }}</QTd> <QTd class="text-bold">{{ entriesTotals.freight }}</QTd>
<QTd class="text-bold">{{ entriesTotals.packageValue }}</QTd> <QTd class="text-bold">{{ entriesTotals.packageValue }}</QTd>
<QTd class="text-bold">{{ entriesTotals.cc }}</QTd> <QTd class="text-bold">{{ entriesTotals.cc }}</QTd>
<QTd class="text-bold">{{ entriesTotals.roundedCc }}</QTd>
<QTd class="text-bold">{{ entriesTotals.pallet }}</QTd> <QTd class="text-bold">{{ entriesTotals.pallet }}</QTd>
<QTd class="text-bold">{{ entriesTotals.m3 }}</QTd> <QTd class="text-bold">{{ entriesTotals.m3 }}</QTd>
</template> </template>
</QTable> </QTable>
</QCard> </QCard>
<QCard class="full-width" v-if="thermographs.length > 0"> <QCard class="full-width" v-if="thermographs.length > 0">
<RouterLink <FetchData
class="header header-link" url="Warehouses"
:to="{ :filter="{ fields: ['id', 'name'] }"
name: 'TravelThermographsIndex', order="name"
params: { id: travel.id }, @on-fetch="(data) => (warehouses = data)"
}" auto-load
> />
{{ t('travel.summary.thermographs') }} <VnTitle
<QIcon name="open_in_new" /> :url="getLink('thermographs')"
</RouterLink> :text="t('travel.summary.thermographs')"
/>
<QTable <QTable
:rows="thermographs" :rows="thermographs"
:columns="thermographsTableColumns" :columns="thermographsTableColumns"

View File

@ -89,7 +89,7 @@ defineExpose({ states });
/> />
<VnSelect <VnSelect
:label="t('travel.warehouseOut')" :label="t('travel.warehouseOut')"
v-model="params.warehouseOut" v-model="params.warehouseOutFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
url="warehouses" url="warehouses"
:use-like="false" :use-like="false"
@ -140,6 +140,7 @@ en:
ref: Reference ref: Reference
agency: Agency agency: Agency
warehouseInFk: Warehouse In warehouseInFk: Warehouse In
warehouseOutFk: Warehouse Out
shipped: Shipped shipped: Shipped
shipmentHour: Shipment Hour shipmentHour: Shipment Hour
warehouseOut: Warehouse Out warehouseOut: Warehouse Out
@ -153,6 +154,7 @@ es:
ref: Referencia ref: Referencia
agency: Agencia agency: Agencia
warehouseInFk: Alm.Entrada warehouseInFk: Alm.Entrada
warehouseOutFk: Alm.Salida
shipped: F.Envío shipped: F.Envío
shipmentHour: Hora de envío shipmentHour: Hora de envío
warehouseOut: Alm.Salida warehouseOut: Alm.Salida

View File

@ -201,7 +201,7 @@ const columns = computed(() => [
{ {
title: t('components.smartCard.viewSummary'), title: t('components.smartCard.viewSummary'),
icon: 'preview', icon: 'preview',
action: (row) => viewSummary(row.id, TravelSummary), action: (row) => viewSummary(row.id, TravelSummary, 'lg-width'),
isPrimary: true, isPrimary: true,
}, },
], ],

View File

@ -1,4 +1,4 @@
describe('ClaimNotes', () => { describe('Account descriptor', () => {
const descriptorOptions = '[data-cy="descriptor-more-opts-menu"] > .q-list'; const descriptorOptions = '[data-cy="descriptor-more-opts-menu"] > .q-list';
const url = '/#/account/1/summary'; const url = '/#/account/1/summary';
@ -7,6 +7,9 @@ describe('ClaimNotes', () => {
cy.visit(url); cy.visit(url);
cy.dataCy('descriptor-more-opts').click(); cy.dataCy('descriptor-more-opts').click();
cy.get(descriptorOptions) cy.get(descriptorOptions)
.should('exist')
.should('be.visible')
.find('.q-item') .find('.q-item')
.its('length') .its('length')
.then((count) => { .then((count) => {

View File

@ -44,11 +44,12 @@ describe('EntryList', () => {
}, },
); );
checkBadgeDate( // fix on task https://redmine.verdnatura.es/issues/8638
/* checkBadgeDate(
'td[data-col-field="landed"] > div .bg-info', 'td[data-col-field="landed"] > div .bg-info',
(badgeDate, compareDate) => { (badgeDate, compareDate) => {
expect(badgeDate.getTime()).to.be.lessThan(compareDate.getTime()); expect(badgeDate.getTime()).to.be.lessThan(compareDate.getTime());
}, },
); ); */
}); });
}); });

View File

@ -30,9 +30,11 @@ describe('OrderList', () => {
cy.url().should('include', `/order`); cy.url().should('include', `/order`);
}); });
it.skip('filter list and create order', () => { it('filter list and create order', () => {
cy.dataCy('Customer ID_input').type('1101{enter}'); cy.dataCy('Customer ID_input').type('1101{enter}');
cy.intercept('GET', /\/api\/Clients/).as('clientFilter');
cy.dataCy('vnTableCreateBtn').click(); cy.dataCy('vnTableCreateBtn').click();
cy.wait('@clientFilter');
cy.dataCy('landedDate').find('input').type('06/01/2001'); cy.dataCy('landedDate').find('input').type('06/01/2001');
cy.selectOption(agencyCreateSelect, 1); cy.selectOption(agencyCreateSelect, 1);

View File

@ -118,8 +118,8 @@ describe('Route extended list', () => {
cy.validateContent(selector, value); cy.validateContent(selector, value);
}); });
}); });
// task https://redmine.verdnatura.es/issues/8814
it('Should clone selected route and add ticket', () => { xit('Should clone selected route and add ticket', () => {
cy.get(selectors.firstRowSelectCheckBox).click(); cy.get(selectors.firstRowSelectCheckBox).click();
cy.get(selectors.cloneBtn).click(); cy.get(selectors.cloneBtn).click();
cy.dataCy('Starting date_inputDate').type('01-01-2001'); cy.dataCy('Starting date_inputDate').type('01-01-2001');
@ -146,7 +146,8 @@ describe('Route extended list', () => {
cy.readFile(`${downloadsFolder}/${fileName}`).should('exist'); cy.readFile(`${downloadsFolder}/${fileName}`).should('exist');
}); });
it('Should mark as served the selected route', () => { // task https://redmine.verdnatura.es/issues/8814
xit('Should mark as served the selected route', () => {
cy.get(selectors.lastRowSelectCheckBox).click(); cy.get(selectors.lastRowSelectCheckBox).click();
cy.get(selectors.markServedBtn).click(); cy.get(selectors.markServedBtn).click();

View File

@ -1,5 +1,5 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
describe('TicketList', () => { describe.skip('TicketList', () => {
const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)'; const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
beforeEach(() => { beforeEach(() => {
@ -35,7 +35,8 @@ describe('TicketList', () => {
cy.get('.summaryBody').should('exist'); cy.get('.summaryBody').should('exist');
}); });
it('filter client and create ticket', () => { // task https://redmine.verdnatura.es/issues/8779
xit('filter client and create ticket', () => {
cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar'); cy.intercept('GET', /\/api\/Tickets\/filter/).as('ticketSearchbar');
searchResults(); searchResults();
cy.wait('@ticketSearchbar'); cy.wait('@ticketSearchbar');

View File

@ -1,37 +0,0 @@
describe('VnAccountNumber', () => {
const accountInput = 'input[data-cy="supplierFiscalDataAccount_input"]';
beforeEach(() => {
cy.login('developer');
cy.viewport(1920, 1080);
cy.visit('/#/supplier/1/fiscal-data');
});
describe('VnInput handleInsertMode()', () => {
it('should replace character at cursor position in insert mode', () => {
cy.get(accountInput).type('{selectall}4100000001');
cy.get(accountInput).type('{movetostart}');
cy.get(accountInput).type('999');
cy.get(accountInput).should('have.value', '9990000001');
});
it('should replace character at cursor position in insert mode', () => {
cy.get(accountInput).clear();
cy.get(accountInput).type('4100000001');
cy.get(accountInput).type('{movetostart}');
cy.get(accountInput).type('999');
cy.get(accountInput).should('have.value', '9990000001');
});
it('should respect maxlength prop', () => {
cy.get(accountInput).clear();
cy.get(accountInput).type('123456789012345');
cy.get(accountInput).should('have.value', '1234567890');
});
});
it('should convert short account number to standard format', () => {
cy.get(accountInput).clear();
cy.get(accountInput).type('123.');
cy.get(accountInput).should('have.value', '1230000000');
});
});