#8448 - devToTest #1254

Merged
alexm merged 365 commits from 8448-devToTest into test 2025-01-21 10:44:46 +00:00
53 changed files with 253 additions and 118 deletions
Showing only changes of commit 1941e896e8 - Show all commits

View File

@ -55,13 +55,6 @@ async function setCountry(countryFk, data) {
} }
// Province // Province
async function handleProvinces(data) {
provincesOptions.value = data;
if (postcodeFormData.countryFk) {
await fetchTowns();
}
}
async function setProvince(id, data) { async function setProvince(id, data) {
if (data.provinceFk === id) return; if (data.provinceFk === id) return;
const newProvince = provincesOptions.value.find((province) => province.id == id); const newProvince = provincesOptions.value.find((province) => province.id == id);

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { onMounted, onUnmounted, computed, ref, watch, nextTick } from 'vue'; import { onMounted, onUnmounted, computed, ref, watch, nextTick } from 'vue';
import { onBeforeRouteLeave, useRouter } from 'vue-router'; import { onBeforeRouteLeave, useRouter, useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
@ -12,7 +12,6 @@ import SkeletonForm from 'components/ui/SkeletonForm.vue';
import VnConfirm from './ui/VnConfirm.vue'; import VnConfirm from './ui/VnConfirm.vue';
import { tMobile } from 'src/composables/tMobile'; import { tMobile } from 'src/composables/tMobile';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useRoute } from 'vue-router';
const { push } = useRouter(); const { push } = useRouter();
const quasar = useQuasar(); const quasar = useQuasar();

View File

@ -59,8 +59,8 @@ const $props = defineProps({
default: true, default: true,
}, },
bottom: { bottom: {
type: Object, type: Boolean,
default: null, default: false,
}, },
cardClass: { cardClass: {
type: String, type: String,
@ -478,29 +478,6 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
/> />
</QTd> </QTd>
</template> </template>
<template #bottom v-if="bottom">
<slot name="bottom-table">
<QBtn
@click="
() =>
createAsDialog
? (showForm = !showForm)
: handleOnDataSaved(create)
"
class="cursor-pointer fill-icon"
color="primary"
icon="add_circle"
size="md"
round
flat
shortcut="+"
:disabled="!disabledAttr"
/>
<QTooltip>
{{ createForm.title }}
</QTooltip>
</slot>
</template>
<template #item="{ row, colsMap }"> <template #item="{ row, colsMap }">
<component <component
:is="$props.redirect ? 'router-link' : 'span'" :is="$props.redirect ? 'router-link' : 'span'"
@ -625,6 +602,27 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
</QTr> </QTr>
</template> </template>
</QTable> </QTable>
<div class="full-width bottomButton" v-if="bottom">
<QBtn
@click="
() =>
createAsDialog
? (showForm = !showForm)
: handleOnDataSaved(create)
"
class="cursor-pointer fill-icon"
color="primary"
icon="add_circle"
size="md"
round
flat
shortcut="+"
:disabled="!disabledAttr"
/>
<QTooltip>
{{ createForm.title }}
</QTooltip>
</div>
</template> </template>
</CrudModel> </CrudModel>
<QPageSticky v-if="$props.create" :offset="[20, 20]" style="z-index: 2"> <QPageSticky v-if="$props.create" :offset="[20, 20]" style="z-index: 2">

View File

@ -0,0 +1,56 @@
import { createWrapper, axios } from 'app/test/vitest/helper';
import EditForm from 'components/EditTableCellValueForm.vue';
import { vi, afterEach, beforeAll, describe, expect, it } from 'vitest';
const fieldA = 'fieldA';
const fieldB = 'fieldB';
describe('EditForm', () => {
let vm;
const mockRows = [
{ id: 1, itemFk: 101 },
{ id: 2, itemFk: 102 },
];
const mockFieldsOptions = [
{ label: 'Field A', field: fieldA, component: 'input', attrs: {} },
{ label: 'Field B', field: fieldB, component: 'date', attrs: {} },
];
const editUrl = '/api/edit';
beforeAll(() => {
vi.spyOn(axios, 'post').mockResolvedValue({ status: 200 });
vm = createWrapper(EditForm, {
props: {
rows: mockRows,
fieldsOptions: mockFieldsOptions,
editUrl,
},
}).vm;
});
afterEach(() => {
vi.clearAllMocks();
});
describe('onSubmit()', () => {
it('should call axios.post with the correct parameters in the payload', async () => {
const selectedField = { field: fieldA, component: 'input', attrs: {} };
const newValue = 'Test Value';
vm.selectedField = selectedField;
vm.newValue = newValue;
await vm.onSubmit();
const payload = axios.post.mock.calls[0][1];
expect(axios.post).toHaveBeenCalledWith(editUrl, expect.any(Object));
expect(payload.field).toEqual(fieldA);
expect(payload.newValue).toEqual(newValue);
expect(payload.lines).toEqual(expect.arrayContaining(mockRows));
expect(vm.isLoading).toEqual(false);
});
});
});

View File

@ -166,7 +166,11 @@ onMounted(() => {
const arrayDataKey = const arrayDataKey =
$props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label); $props.dataKey ?? ($props.url?.length > 0 ? $props.url : $attrs.name ?? $attrs.label);
const arrayData = useArrayData(arrayDataKey, { url: $props.url, searchUrl: false }); const arrayData = useArrayData(arrayDataKey, {
url: $props.url,
searchUrl: false,
mapKey: $attrs['map-key'],
});
function findKeyInOptions() { function findKeyInOptions() {
if (!$props.options) return; if (!$props.options) return;

View File

@ -202,7 +202,11 @@ const getLocale = (label) => {
style="position: fixed; z-index: 1; right: 0; bottom: 0" style="position: fixed; z-index: 1; right: 0; bottom: 0"
icon="search" icon="search"
@click="search()" @click="search()"
></QBtn> >
<QTooltip bottom anchor="bottom right">
{{ t('globals.search') }}
</QTooltip>
</QBtn>
<QForm @submit="search" id="filterPanelForm" @keyup.enter="search()"> <QForm @submit="search" id="filterPanelForm" @keyup.enter="search()">
<QList dense> <QList dense>
<QItem class="q-mt-xs"> <QItem class="q-mt-xs">

View File

@ -54,6 +54,7 @@ function formatNumber(number) {
:offset="100" :offset="100"
:limit="5" :limit="5"
auto-load auto-load
map-key="smsFk"
> >
<template #body="{ rows }"> <template #body="{ rows }">
<QCard <QCard

View File

@ -151,7 +151,8 @@ select:-webkit-autofill {
.q-card, .q-card,
.q-table, .q-table,
.q-table__bottom, .q-table__bottom,
.q-drawer { .q-drawer,
.bottomButton {
background-color: var(--vn-section-color); background-color: var(--vn-section-color);
} }

View File

@ -612,7 +612,7 @@ worker:
fi: DNI/NIE/NIF fi: DNI/NIE/NIF
birth: Birth birth: Birth
isFreelance: Freelance isFreelance: Freelance
isSsDiscounted: Bonificación SS isSsDiscounted: SS Bonification
hasMachineryAuthorized: Machinery authorized hasMachineryAuthorized: Machinery authorized
isDisable: Disable isDisable: Disable
notificationsManager: notificationsManager:
@ -858,11 +858,11 @@ components:
value: Value value: Value
# ItemFixedPriceFilter # ItemFixedPriceFilter
buyerFk: Buyer buyerFk: Buyer
warehouseFk: Warehouse
started: From started: From
ended: To ended: To
mine: For me mine: For me
hasMinPrice: Minimum price hasMinPrice: Minimum price
warehouseFk: Warehouse
# LatestBuysFilter # LatestBuysFilter
salesPersonFk: Buyer salesPersonFk: Buyer
from: From from: From

View File

@ -608,6 +608,15 @@ worker:
role: Rol role: Rol
sipExtension: Extensión sipExtension: Extensión
locker: Taquilla locker: Taquilla
fiDueDate: F. caducidad DNI
sex: Sexo
seniority: Antigüedad
fi: DNI/NIE/NIF
birth: F. nacimiento
isFreelance: Autónomo
isSsDiscounted: Bonificación SS
hasMachineryAuthorized: Autorizado para maquinaria
isDisable: Deshabilitado
notificationsManager: notificationsManager:
activeNotifications: Notificaciones activas activeNotifications: Notificaciones activas
availableNotifications: Notificaciones disponibles availableNotifications: Notificaciones disponibles
@ -849,6 +858,7 @@ components:
value: Valor value: Valor
# ItemFixedPriceFilter # ItemFixedPriceFilter
buyerFk: Comprador buyerFk: Comprador
warehouseFk: Almacen
started: Desde started: Desde
ended: Hasta ended: Hasta
mine: Para mi mine: Para mi

View File

@ -53,7 +53,6 @@ const hasAccount = ref(false);
<AccountDescriptorMenu :has-account="hasAccount" /> <AccountDescriptorMenu :has-account="hasAccount" />
</template> </template>
<template #before> <template #before>
<!-- falla id :id="entityId.value" collection="user" size="160x160" -->
<VnImg :id="entityId" collection="user" resolution="520x520" class="photo"> <VnImg :id="entityId" collection="user" resolution="520x520" class="photo">
<template #error> <template #error>
<div <div
@ -75,7 +74,7 @@ const hasAccount = ref(false);
<VnLv :label="t('account.card.nickname')" :value="entity.name" /> <VnLv :label="t('account.card.nickname')" :value="entity.name" />
<VnLv :label="t('account.card.role')" :value="entity.role.name" /> <VnLv :label="t('account.card.role')" :value="entity.role.name" />
</template> </template>
<template #actions="{ entity }"> <template #icons="{ entity }">
<QCardActions class="q-gutter-x-md"> <QCardActions class="q-gutter-x-md">
<QIcon <QIcon
v-if="!entity.active" v-if="!entity.active"
@ -83,7 +82,7 @@ const hasAccount = ref(false);
name="vn:disabled" name="vn:disabled"
flat flat
round round
size="sm" size="xs"
class="fill-icon" class="fill-icon"
> >
<QTooltip>{{ t('account.card.deactivated') }}</QTooltip> <QTooltip>{{ t('account.card.deactivated') }}</QTooltip>
@ -91,10 +90,10 @@ const hasAccount = ref(false);
<QIcon <QIcon
color="primary" color="primary"
name="contact_mail" name="contact_mail"
v-if="entity.hasAccount" v-if="hasAccount"
flat flat
round round
size="sm" size="xs"
class="fill-icon" class="fill-icon"
> >
<QTooltip>{{ t('account.card.enabled') }}</QTooltip> <QTooltip>{{ t('account.card.enabled') }}</QTooltip>

View File

@ -50,7 +50,7 @@ const removeRole = async () => {
> >
<template #menu> <template #menu>
<QItem v-ripple clickable @click="removeRole()"> <QItem v-ripple clickable @click="removeRole()">
<QItemSection>{{ t('Delete') }}</QItemSection> <QItemSection>{{ t('globals.delete') }}</QItemSection>
</QItem> </QItem>
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">

View File

@ -164,19 +164,7 @@ const columns = computed(() => [
:autofocus="col.tabIndex == 1" :autofocus="col.tabIndex == 1"
input-debounce="0" input-debounce="0"
hide-selected hide-selected
> />
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption>
{{ scope.opt?.nickname }}
{{ scope.opt?.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectWorker>
<VnSelect <VnSelect
v-else v-else
v-model="row[col.model]" v-model="row[col.model]"

View File

@ -230,7 +230,7 @@ async function saveWhenHasChanges() {
</QTd> </QTd>
</template> </template>
<template #body-cell-discount="{ row, value, rowIndex }"> <template #body-cell-discount="{ row, value, rowIndex }">
<QTd auto-width align="right" class="text-primary shrink"> <QTd auto-width align="right" class="link shrink">
{{ value }} {{ value }}
<VnDiscount <VnDiscount
:quantity="row.quantity" :quantity="row.quantity"

View File

@ -84,6 +84,7 @@ const columns = computed(() => [
label: t('Creation date'), label: t('Creation date'),
format: ({ created }) => toDateHourMin(created), format: ({ created }) => toDateHourMin(created),
cardVisible: true, cardVisible: true,
style: 'color: var(--vn-label-color)',
}, },
{ {
align: 'left', align: 'left',

View File

@ -2,7 +2,7 @@
import { ref, computed, onBeforeMount } from 'vue'; import { ref, computed, onBeforeMount } from 'vue';
import axios from 'axios'; import axios from 'axios';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { toDate } from 'src/filters/index'; import { dateRange, toDate } from 'src/filters/index';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
@ -104,18 +104,12 @@ function getParams() {
}; };
} }
const userParams = computed(() => { const userParams = computed(() => {
const minDate = Date.vnNew(); const campaign = campaignList.value[0]?.id;
minDate.setHours(0, 0, 0, 0); const userParams = {
minDate.setMonth(minDate.getMonth() - 2); campaign,
...updateDateParams(campaign, { from: Date.vnNew(), to: Date.vnNew() }),
const maxDate = Date.vnNew();
maxDate.setHours(23, 59, 59, 59);
return {
campaign: campaignList.value[0]?.id,
from: minDate,
to: maxDate,
}; };
return userParams;
}); });
const openReportPdf = () => { const openReportPdf = () => {
openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams()); openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams());
@ -134,6 +128,23 @@ const sendCampaignMetricsEmail = ({ address }) => {
...getParams(), ...getParams(),
}); });
}; };
const updateDateParams = (value, params) => {
if (!value) {
params.from = null;
params.to = null;
return;
}
const campaign = campaignList.value.find((c) => c.id === value);
if (!campaign) return;
const { dated, previousDays, scopeDays } = campaign;
const _date = new Date(dated);
const [from, to] = dateRange(_date);
params.from = new Date(from.setDate(from.getDate() - previousDays)).toISOString();
params.to = new Date(to.setDate(to.getDate() + scopeDays)).toISOString();
return params;
};
</script> </script>
<template> <template>
@ -144,7 +155,6 @@ const sendCampaignMetricsEmail = ({ address }) => {
:order="['itemTypeFk', 'itemName', 'itemSize', 'description']" :order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
:columns="columns" :columns="columns"
search-url="consumption" search-url="consumption"
:filter="filter"
:user-params="userParams" :user-params="userParams"
:default-remove="false" :default-remove="false"
:default-reset="false" :default-reset="false"
@ -201,6 +211,7 @@ const sendCampaignMetricsEmail = ({ address }) => {
class="q-px-sm q-pt-none fit" class="q-px-sm q-pt-none fit"
dense dense
option-label="code" option-label="code"
@update:model-value="(data) => updateDateParams(data, params)"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@ -14,7 +14,12 @@ import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
const state = useState(); const state = useState();
const customer = computed(() => state.get('customer')); const customer = ref();
onMounted(async () => {
customer.value = state.get('customer');
if (customer.value) customer.value.webAccess = data.value?.account?.isActive;
});
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -38,7 +43,6 @@ const entityId = computed(() => {
const data = ref(useCardDescription()); const data = ref(useCardDescription());
const setData = (entity) => { const setData = (entity) => {
data.value = useCardDescription(entity?.name, entity?.id); data.value = useCardDescription(entity?.name, entity?.id);
if (customer.value) customer.value.webAccess = data.value?.account?.isActive;
}; };
const debtWarning = computed(() => { const debtWarning = computed(() => {
return customer.value?.debt > customer.value?.credit ? 'negative' : 'primary'; return customer.value?.debt > customer.value?.credit ? 'negative' : 'primary';

View File

@ -173,6 +173,8 @@ en:
phone: Phone phone: Phone
email: Email email: Email
zoneFk: Zone zoneFk: Zone
socialName : Social name
name: Name
postcode: Postcode postcode: Postcode
es: es:
params: params:
@ -184,6 +186,8 @@ es:
phone: Teléfono phone: Teléfono
email: Email email: Email
zoneFk: Zona zoneFk: Zona
socialName : Razón social
name: Nombre
postcode: CP postcode: CP
FI: NIF FI: NIF
Salesperson: Comercial Salesperson: Comercial

View File

@ -240,6 +240,7 @@ es:
defaulterSinced: Desde defaulterSinced: Desde
Client: Cliente Client: Cliente
Salesperson: Comercial Salesperson: Comercial
Departments: Departamentos
Country: País Country: País
P. Method: F. Pago P. Method: F. Pago
Balance D.: Saldo V. Balance D.: Saldo V.

View File

@ -52,7 +52,7 @@ const { t } = useI18n();
<VnSelectWorker <VnSelectWorker
:label="t('department.bossDepartment')" :label="t('department.bossDepartment')"
v-model="data.workerFk" v-model="data.workerFk"
:rules="validate('department.workerFk')" :rules="validate('department.bossDepartment')"
/> />
<VnSelect <VnSelect
:label="t('department.selfConsumptionCustomer')" :label="t('department.selfConsumptionCustomer')"

View File

@ -74,8 +74,8 @@ const showEntryReport = () => {
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('globals.agency')" :value="entity.travel?.agency?.name" /> <VnLv :label="t('globals.agency')" :value="entity.travel?.agency?.name" />
<VnLv :label="t('shipped')" :value="toDate(entity.travel?.shipped)" /> <VnLv :label="t('globals.shipped')" :value="toDate(entity.travel?.shipped)" />
<VnLv :label="t('landed')" :value="toDate(entity.travel?.landed)" /> <VnLv :label="t('globals.landed')" :value="toDate(entity.travel?.landed)" />
<VnLv <VnLv
:label="t('globals.warehouseOut')" :label="t('globals.warehouseOut')"
:value="entity.travel?.warehouseOut?.name" :value="entity.travel?.warehouseOut?.name"

View File

@ -212,7 +212,7 @@ const fetchEntryBuys = async () => {
:label="t('entry.summary.travelAgency')" :label="t('entry.summary.travelAgency')"
:value="entry.travel.agency?.name" :value="entry.travel.agency?.name"
/> />
<VnLv :label="t('shipped')" :value="toDate(entry.travel.shipped)" /> <VnLv :label="t('globals.shipped')" :value="toDate(entry.travel.shipped)" />
<VnLv <VnLv
:label="t('globals.warehouseOut')" :label="t('globals.warehouseOut')"
:value="entry.travel.warehouseOut?.name" :value="entry.travel.warehouseOut?.name"
@ -222,7 +222,7 @@ const fetchEntryBuys = async () => {
v-model="entry.travel.isDelivered" v-model="entry.travel.isDelivered"
:disable="true" :disable="true"
/> />
<VnLv :label="t('landed')" :value="toDate(entry.travel.landed)" /> <VnLv :label="t('globals.landed')" :value="toDate(entry.travel.landed)" />
<VnLv <VnLv
:label="t('globals.warehouseIn')" :label="t('globals.warehouseIn')"
:value="entry.travel.warehouseIn?.name" :value="entry.travel.warehouseIn?.name"

View File

@ -58,7 +58,7 @@ const tagValues = ref([]);
<QItem class="q-my-md"> <QItem class="q-my-md">
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="t('components.itemsFilterPanel.supplierFk')" :label="t('globals.params.supplierFk')"
v-model="params.supplierFk" v-model="params.supplierFk"
:options="suppliersOptions" :options="suppliersOptions"
option-value="id" option-value="id"
@ -85,7 +85,7 @@ const tagValues = ref([]);
<QItem class="q-my-md"> <QItem class="q-my-md">
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
:label="t('components.itemsFilterPanel.from')" :label="t('components.itemsFilterPanel.started')"
v-model="params.from" v-model="params.from"
is-outlined is-outlined
@update:model-value="searchFn()" @update:model-value="searchFn()"
@ -95,7 +95,7 @@ const tagValues = ref([]);
<QItem class="q-my-md"> <QItem class="q-my-md">
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
:label="t('components.itemsFilterPanel.to')" :label="t('components.itemsFilterPanel.ended')"
v-model="params.to" v-model="params.to"
is-outlined is-outlined
@update:model-value="searchFn()" @update:model-value="searchFn()"
@ -113,7 +113,7 @@ const tagValues = ref([]);
</QItemSection> </QItemSection>
<QItemSection> <QItemSection>
<QCheckbox <QCheckbox
:label="t('components.itemsFilterPanel.visible')" :label="t('globals.visible')"
v-model="params.visible" v-model="params.visible"
toggle-indeterminate toggle-indeterminate
@update:model-value="searchFn()" @update:model-value="searchFn()"

View File

@ -65,6 +65,6 @@ onMounted(async () => {
es: es:
Date: Fecha Date: Fecha
params: params:
dated: Date dated: Fecha
workerFk: Trabajador workerFk: Trabajador
</i18n> </i18n>

View File

@ -161,7 +161,7 @@ const columns = computed(() => [
<QList> <QList>
<QItem> <QItem>
<VnSelect <VnSelect
:label="t('code')" :label="t('Code')"
class="full-width" class="full-width"
v-model="props.row['intrastatFk']" v-model="props.row['intrastatFk']"
:options="intrastats" :options="intrastats"

View File

@ -108,19 +108,6 @@ const cols = computed(() => [
}, },
format: (row) => row.code, format: (row) => row.code,
}, },
{
name: 'companyFk',
label: t('globals.company'),
columnFilter: {
component: 'select',
attrs: {
url: 'Companies',
fields: ['id', 'code'],
optionLabel: 'code',
},
},
format: (row) => row.code,
},
{ {
align: 'right', align: 'right',
name: 'tableActions', name: 'tableActions',

View File

@ -348,7 +348,7 @@ watchEffect(selectedRows);
<VnSelect <VnSelect
url="InvoiceOutSerials" url="InvoiceOutSerials"
v-model="data.serial" v-model="data.serial"
:label="t('invoiceIn.serial')" :label="t('InvoiceIn.serial')"
:options="invoiceOutSerialsOptions" :options="invoiceOutSerialsOptions"
option-label="description" option-label="description"
option-value="code" option-value="code"

View File

@ -203,6 +203,12 @@ const onIntrastatCreated = (response, formData) => {
v-model="data.hasKgPrice" v-model="data.hasKgPrice"
:label="t('item.basicData.hasKgPrice')" :label="t('item.basicData.hasKgPrice')"
/> />
<QCheckbox
v-model="data.isCustomInspectionRequired"
:label="t('item.basicData.isCustomInspectionRequired')"
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div> <div>
<QCheckbox <QCheckbox
v-model="data.isFragile" v-model="data.isFragile"

View File

@ -128,7 +128,7 @@ const submitTags = async (data) => {
<VnSelect <VnSelect
v-if="row.tag?.isFree === false" v-if="row.tag?.isFree === false"
:key="row.tagFk" :key="row.tagFk"
:label="t('Value')" :label="t('itemTags.value')"
v-model="row.value" v-model="row.value"
:url="`Tags/${row.tagFk}/filterValue`" :url="`Tags/${row.tagFk}/filterValue`"
option-label="value" option-label="value"

View File

@ -376,6 +376,8 @@ const columns = computed(() => [
<i18n> <i18n>
es: es:
New item: Nuevo artículo New item: Nuevo artículo
Create Item: Crear artículo
You can search by id: Puedes buscar por id
Preview: Vista previa Preview: Vista previa
Regularize stock: Regularizar stock Regularize stock: Regularizar stock
</i18n> </i18n>

View File

@ -201,6 +201,7 @@ en:
to: To to: To
mine: For me mine: For me
state: State state: State
daysOnward: Days onward
myTeam: My team myTeam: My team
dateFiltersTooltip: Cannot choose a range of dates and days onward at the same time dateFiltersTooltip: Cannot choose a range of dates and days onward at the same time
denied: Denied denied: Denied
@ -218,6 +219,7 @@ es:
to: Hasta to: Hasta
mine: Para mi mine: Para mi
state: Estado state: Estado
daysOnward: Días en adelante
myTeam: Mi equipo myTeam: Mi equipo
dateFiltersTooltip: No se puede seleccionar un rango de fechas y días en adelante a la vez dateFiltersTooltip: No se puede seleccionar un rango de fechas y días en adelante a la vez
denied: Denegada denied: Denegada

View File

@ -158,6 +158,7 @@ item:
isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...) isFragileTooltip: Is shown at website, app that this item cannot travel (wreath, palms, ...)
isPhotoRequested: Do photo isPhotoRequested: Do photo
isPhotoRequestedTooltip: This item does need a photo isPhotoRequestedTooltip: This item does need a photo
isCustomInspectionRequired: Needs physical inspection (PIF)
description: Description description: Description
fixedPrice: fixedPrice:
itemFk: Item ID itemFk: Item ID

View File

@ -160,6 +160,7 @@ item:
isFragileTooltip: Se muestra en la web, app que este artículo no puede viajar (coronas, palmas, ...) isFragileTooltip: Se muestra en la web, app que este artículo no puede viajar (coronas, palmas, ...)
isPhotoRequested: Hacer foto isPhotoRequested: Hacer foto
isPhotoRequestedTooltip: Este artículo necesita una foto isPhotoRequestedTooltip: Este artículo necesita una foto
isCustomInspectionRequired: Necesita inspección física (PIF)
description: Descripción description: Descripción
fixedPrice: fixedPrice:
itemFk: ID Artículo itemFk: ID Artículo

View File

@ -1,6 +1,6 @@
<script setup> <script setup>
import toCurrency from 'src/filters/toCurrency'; import toCurrency from 'src/filters/toCurrency';
import { computed, inject, ref } from 'vue'; import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';

View File

@ -128,6 +128,7 @@ en:
from: From from: From
to: To to: To
orderFk: Order orderFk: Order
workerFk: Worker
sourceApp: Application sourceApp: Application
myTeam: My Team myTeam: My Team
isConfirmed: Is Confirmed isConfirmed: Is Confirmed
@ -151,6 +152,7 @@ es:
from: Desde from: Desde
to: Hasta to: Hasta
orderFk: Cesta orderFk: Cesta
workerFk: Trabajador
sourceApp: Aplicación sourceApp: Aplicación
myTeam: Mi Equipo myTeam: Mi Equipo
isConfirmed: Confirmado isConfirmed: Confirmado

View File

@ -225,8 +225,8 @@ es:
params: params:
agencyModeFk: Agencia ruta agencyModeFk: Agencia ruta
m3: m3:
from: Desde From: Desde
to: Hasta To: Hasta
date: Fecha date: Fecha
agencyFk: Agencia Acuerdo agencyFk: Agencia Acuerdo
packages: Bultos packages: Bultos

View File

@ -161,6 +161,7 @@ en:
warehouseFk: Warehouse warehouseFk: Warehouse
description: Description description: Description
m3: m3:
scopeDays: Days Onward
vehicleFk: Vehicle vehicleFk: Vehicle
agencyModeFk: Agency agencyModeFk: Agency
workerFk: Worker workerFk: Worker
@ -172,6 +173,7 @@ es:
warehouseFk: Almacén warehouseFk: Almacén
description: Descripción description: Descripción
m3: m3:
scopeDays: Días en adelante
vehicleFk: Vehículo vehicleFk: Vehículo
agencyModeFk: Agencia agencyModeFk: Agencia
workerFk: Trabajador workerFk: Trabajador

View File

@ -271,6 +271,8 @@ es:
Date: Fecha Date: Fecha
Agency route: Agencia Ruta Agency route: Agencia Ruta
Agency agreement: Agencia Acuerdo Agency agreement: Agencia Acuerdo
From: Desde
To: Hasta
Packages: Bultos Packages: Bultos
Price: Precio Price: Precio
Received: Recibida Received: Recibida

View File

@ -6,9 +6,11 @@ import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue'; import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
import { useArrayData } from 'src/composables/useArrayData';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const arrayData = useArrayData();
const companySizes = [ const companySizes = [
{ id: 'small', name: t('globals.small'), size: '1-5' }, { id: 'small', name: t('globals.small'), size: '1-5' },
{ id: 'medium', name: t('globals.medium'), size: '6-50' }, { id: 'medium', name: t('globals.medium'), size: '6-50' },
@ -22,6 +24,7 @@ const companySizes = [
model="supplier" model="supplier"
auto-load auto-load
:clear-store-on-unmount="false" :clear-store-on-unmount="false"
@on-data-saved="arrayData.fetch({})"
> >
<template #form="{ data, validate }"> <template #form="{ data, validate }">
<VnRow> <VnRow>

View File

@ -134,6 +134,7 @@ defineProps({
<i18n> <i18n>
en: en:
params: params:
supplierFk: Supplier
search: General search search: General search
itemId: Item id itemId: Item id
buyerId: Buyer buyerId: Buyer
@ -143,6 +144,7 @@ en:
to: To to: To
es: es:
params: params:
supplierFk: Proveedor
search: Búsqueda general search: Búsqueda general
itemId: Id Artículo itemId: Id Artículo
buyerId: Comprador buyerId: Comprador

View File

@ -9,7 +9,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import { toDateString } from 'src/filters'; import { toDateString } from 'src/filters';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
import { getUrl } from 'src/composables/getUrl'; import { getUrl } from 'src/composables/getUrl';
import { useState } from 'src/composables/useState'; import { useArrayData } from 'src/composables/useArrayData';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -26,7 +26,7 @@ const $props = defineProps({
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const url = ref(); const url = ref();
const state = useState(); const arrayData = useArrayData();
const filter = { const filter = {
fields: [ fields: [
@ -77,7 +77,7 @@ const setData = (entity) => {
data.value = useCardDescription(entity.ref, entity.id); data.value = useCardDescription(entity.ref, entity.id);
}; };
const supplier = computed(() => state.get('supplier')); const supplier = computed(() => arrayData.store.data);
const getEntryQueryParams = (supplier) => { const getEntryQueryParams = (supplier) => {
if (!supplier) return null; if (!supplier) return null;

View File

@ -149,7 +149,7 @@ const getUrl = (section) => `#/supplier/${entityId.value}/${section}`;
<VnLv :label="t('supplier.summary.taxNumber')" :value="supplier.nif" /> <VnLv :label="t('supplier.summary.taxNumber')" :value="supplier.nif" />
<VnLv :label="t('globals.street')" :value="supplier.street" /> <VnLv :label="t('globals.street')" :value="supplier.street" />
<VnLv :label="t('supplier.summary.city')" :value="supplier.city" /> <VnLv :label="t('supplier.summary.city')" :value="supplier.city" />
<VnLv :label="t('globals.postCode')" :value="supplier.postCode" /> <VnLv :label="t('globals.postcode')" :value="supplier.postCode" />
<VnLv <VnLv
:label="t('supplier.summary.province')" :label="t('supplier.summary.province')"
:value="supplier.province?.name" :value="supplier.province?.name"

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed, onMounted, watch } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';

View File

@ -59,7 +59,7 @@ const columns = computed(() => [
}, },
{ {
label: t('basicData.item'), label: t('basicData.item'),
name: 'packagingItemFk', name: 'longName',
align: 'left', align: 'left',
cardVisible: true, cardVisible: true,
columnFilter: { columnFilter: {
@ -321,12 +321,18 @@ onMounted(async () => {
" "
order="created DESC" order="created DESC"
> >
<template #column-packagingItemFk="{ row }"> <template #column-freightItemName="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.packagingItemFk }} {{ row.freightItemName }}
<ItemDescriptorProxy :id="row.packagingItemFk" /> <ItemDescriptorProxy :id="row.packagingItemFk" />
</span> </span>
</template> </template>
<template #column-longName="{ row }">
<span class="link" @click.stop>
{{ row.longName }}
<ItemDescriptorProxy :id="row.itemFk" />
</span>
</template>
</VnTable> </VnTable>
<QDialog ref="newTicketDialogRef" transition-show="scale" transition-hide="scale"> <QDialog ref="newTicketDialogRef" transition-show="scale" transition-hide="scale">
<ExpeditionNewTicket <ExpeditionNewTicket

View File

@ -275,4 +275,5 @@ onMounted(() => (stateStore.rightDrawer = false));
New: Nueva New: Nueva
Denied: Denegada Denied: Denegada
Accepted: Aceptada Accepted: Aceptada
Create request: Crear petición de compra
</i18n> </i18n>

View File

@ -54,6 +54,7 @@ const transfer = ref({
}); });
const tableRef = ref([]); const tableRef = ref([]);
const canProceed = ref(); const canProceed = ref();
const isLoading = ref(false);
watch( watch(
() => route.params.id, () => route.params.id,
@ -213,6 +214,9 @@ const updateQuantity = async ({ quantity, id }) => {
}; };
const addSale = async (sale) => { const addSale = async (sale) => {
if (isLoading.value) return;
isLoading.value = true;
const params = { const params = {
barcode: sale.itemFk, barcode: sale.itemFk,
quantity: sale.quantity, quantity: sale.quantity,
@ -233,7 +237,7 @@ const addSale = async (sale) => {
sale.item = newSale.item; sale.item = newSale.item;
notify('globals.dataSaved', 'positive'); notify('globals.dataSaved', 'positive');
window.location.reload(); arrayData.fetch({});
}; };
const updateConcept = async (sale) => { const updateConcept = async (sale) => {
@ -464,6 +468,7 @@ const addRow = (original = null) => {
}; };
const endNewRow = (row) => { const endNewRow = (row) => {
if (!row) return;
if (row.itemFk && row.quantity) { if (row.itemFk && row.quantity) {
row.isNew = false; row.isNew = false;
} }

View File

@ -298,14 +298,19 @@ en:
to: To to: To
salesPersonFk: Salesperson salesPersonFk: Salesperson
stateFk: State stateFk: State
groupedStates: Grouped State
refFk: Invoice Ref. refFk: Invoice Ref.
scopeDays: Days onward
nickname: Nickname
myTeam: My team myTeam: My team
pending: Pending pending: Pending
hasInvoice: Invoiced hasInvoice: Invoiced
hasRoute: Routed hasRoute: Routed
problems: With problems
provinceFk: Province provinceFk: Province
agencyModeFk: Agency agencyModeFk: Agency
warehouseFk: Warehouse warehouseFk: Warehouse
collectionFk: Collection
FREE: Free FREE: Free
ON_PREPARATION: On preparation ON_PREPARATION: On preparation
PACKED: Packed PACKED: Packed
@ -320,11 +325,19 @@ es:
to: Hasta to: Hasta
salesPersonFk: Comercial salesPersonFk: Comercial
stateFk: Estado stateFk: Estado
groupedStates: Estado agrupado
refFk: Ref. Factura refFk: Ref. Factura
scopeDays: Días en adelante
nickname: Nombre mostrado
myTeam: Mi equipo myTeam: Mi equipo
pending: Pendiente pending: Pendiente
hasInvoice: Facturado hasInvoice: Facturado
hasRoute: Enrutado hasRoute: Enrutado
problems: Con problemas
provinceFk: Provincia
agencyModeFk: Agencia
warehouseFk: Almacén
collectionFk: Colección
Customer ID: ID Cliente Customer ID: ID Cliente
Order ID: ID Pedido Order ID: ID Pedido
From: Desde From: Desde

View File

@ -11,9 +11,8 @@ import VnInput from 'src/components/common/VnInput.vue';
import EntryDescriptorProxy from '../Entry/Card/EntryDescriptorProxy.vue'; import EntryDescriptorProxy from '../Entry/Card/EntryDescriptorProxy.vue';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'src/filters';
import { useArrayData } from 'composables/useArrayData'; import { useArrayData } from 'composables/useArrayData';
import { toDate } from 'src/filters'; import { toDate, toCurrency } from 'src/filters';
import { usePrintService } from 'composables/usePrintService'; import { usePrintService } from 'composables/usePrintService';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import axios from 'axios'; import axios from 'axios';
@ -128,6 +127,10 @@ const tableColumnComponents = {
component: 'span', component: 'span',
attrs: {}, attrs: {},
}, },
isCustomInspectionRequired: {
component: 'span',
attrs: {},
},
}; };
const columns = computed(() => [ const columns = computed(() => [
@ -589,7 +592,16 @@ const getColor = (percentage) => {
<QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn> <QBtn flat class="link" dense>{{ entry.supplierName }}</QBtn>
<SupplierDescriptorProxy :id="entry.supplierFk" /> <SupplierDescriptorProxy :id="entry.supplierFk" />
</QTd> </QTd>
<QTd /> <QTd>
<QIcon
v-if="entry.isCustomInspectionRequired"
name="warning"
color="negative"
size="xs"
:title="t('requiresInspection')"
>
</QIcon>
</QTd>
<QTd> <QTd>
<span>{{ toCurrency(entry.invoiceAmount) }}</span> <span>{{ toCurrency(entry.invoiceAmount) }}</span>
</QTd> </QTd>
@ -704,12 +716,17 @@ en:
physicKg: Phy. KG physicKg: Phy. KG
shipped: W. shipped shipped: W. shipped
landed: W. landed landed: W. landed
requiresInspection: Requires inspection
BIP: Boder Inspection Point
notes: Notes
es: es:
searchExtraCommunity: Buscar por envío extra comunitario searchExtraCommunity: Buscar por envío extra comunitario
kg: KG Bloq. kg: KG Bloq.
physicKg: KG físico physicKg: KG físico
shipped: F. envío shipped: F. envío
landed: F. llegada landed: F. llegada
notes: Notas
Open as PDF: Abrir como PDF Open as PDF: Abrir como PDF
requiresInspection: Requiere inspección
BIP: Punto de Inspección Fronteriza
</i18n> </i18n>

View File

@ -286,6 +286,7 @@ es:
Search travel: Buscar envio Search travel: Buscar envio
Clone: Clonar Clone: Clonar
Add entry: Añadir Entrada Add entry: Añadir Entrada
Create Travels: Crear envíos
</i18n> </i18n>
<style lang="scss" scoped> <style lang="scss" scoped>
.is-active { .is-active {

View File

@ -168,3 +168,8 @@ async function remove(row) {
</VnTable> </VnTable>
</QPage> </QPage>
</template> </template>
<i18n>
es:
Create new wagon: Crear nuevo vagón
</i18n>

View File

@ -89,7 +89,7 @@ watch(
v-model="formData.geoFk" v-model="formData.geoFk"
url="Postcodes/location" url="Postcodes/location"
:fields="['geoFk', 'code', 'townFk', 'countryFk']" :fields="['geoFk', 'code', 'townFk', 'countryFk']"
sort-by="code, townFk" :sort-by="['code ASC']"
option-value="geoFk" option-value="geoFk"
option-label="code" option-label="code"
:filter-options="['code']" :filter-options="['code']"
@ -97,6 +97,7 @@ watch(
dense dense
outlined outlined
rounded rounded
map-key="geoFk"
> >
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">

View File

@ -41,6 +41,7 @@ summary:
basicData: Basic data basicData: Basic data
closeHour: Close hour closeHour: Close hour
filterPanel: filterPanel:
name: Name
agencyModeFk: Agency agencyModeFk: Agency
deliveryPanel: deliveryPanel:
pickup: Pick up pickup: Pick up

View File

@ -41,6 +41,7 @@ summary:
basicData: Datos básicos basicData: Datos básicos
closeHour: Hora de cierre closeHour: Hora de cierre
filterPanel: filterPanel:
name: Nombre
agencyModeFk: Agencia agencyModeFk: Agencia
deliveryPanel: deliveryPanel:
pickup: Recogida pickup: Recogida