0
0
Fork 0

Merge branch 'master' of https://gitea.verdnatura.es/verdnatura/salix-front into Hotfix-ZoneLocationsTree

This commit is contained in:
Jon Elias 2024-11-18 09:48:02 +01:00
commit a64575c7cc
25 changed files with 282 additions and 167 deletions

View File

@ -38,7 +38,7 @@ const onDataSaved = (dataSaved) => {
@on-fetch="(data) => (warehousesOptions = data)" @on-fetch="(data) => (warehousesOptions = data)"
auto-load auto-load
url="Warehouses" url="Warehouses"
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }" :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
/> />
<FetchData <FetchData
@on-fetch="(data) => (temperaturesOptions = data)" @on-fetch="(data) => (temperaturesOptions = data)"

View File

@ -247,6 +247,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
} }
function updateStateParams() { function updateStateParams() {
if (!route?.path) return;
const newUrl = { path: route.path, query: { ...(route.query ?? {}) } }; const newUrl = { path: route.path, query: { ...(route.query ?? {}) } };
newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter); newUrl.query[store.searchUrl] = JSON.stringify(store.currentFilter);

View File

@ -5,7 +5,7 @@ import { useRoute } from 'vue-router';
import { useAcl } from 'src/composables/useAcl'; import { useAcl } from 'src/composables/useAcl';
import axios from 'axios'; import axios from 'axios';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import FetchData from 'components/FetchData.vue'; import { getClientRisk } from '../composables/getClientRisk';
import { toCurrency, toDate, toDateHourMin } from 'src/filters'; import { toCurrency, toDate, toDateHourMin } from 'src/filters';
import { useState } from 'composables/useState'; import { useState } from 'composables/useState';
@ -16,7 +16,7 @@ import { useVnConfirm } from 'composables/useVnConfirm';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import VnSubToolbar from 'components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'components/ui/VnSubToolbar.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnFilter from 'components/VnTable/VnFilter.vue';
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue'; import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue'; import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
@ -25,7 +25,7 @@ const { openConfirmationModal } = useVnConfirm();
const { sendEmail, openReport } = usePrintService(); const { sendEmail, openReport } = usePrintService();
const { t } = useI18n(); const { t } = useI18n();
const { hasAny } = useAcl(); const { hasAny } = useAcl();
const currentBalance = ref({});
const quasar = useQuasar(); const quasar = useQuasar();
const route = useRoute(); const route = useRoute();
const state = useState(); const state = useState();
@ -33,28 +33,53 @@ const stateStore = useStateStore();
const user = state.getUser(); const user = state.getUser();
const clientRisk = ref([]); const clientRisk = ref([]);
const companies = ref([]);
const tableRef = ref(); const tableRef = ref();
const companyId = ref(user.value.companyFk); const companyId = ref();
const companyUser = ref(user.value.companyFk);
const balances = ref([]); const balances = ref([]);
const vnFilterRef = ref({}); const vnFilterRef = ref({});
const filter = computed(() => { const filter = computed(() => {
return { return {
clientId: route.params.id, clientId: route.params.id,
companyId: companyId.value ?? user.value.companyFk, companyId: companyId.value ?? companyUser.value,
}; };
}); });
const companyFilterColumn = {
align: 'left',
name: 'companyId',
label: t('Company'),
component: 'select',
attrs: {
url: 'Companies',
optionLabel: 'code',
optionValue: 'id',
sortBy: 'code',
},
columnFilter: {
event: {
remove: () => (companyId.value = null),
'update:modelValue': (newCompanyFk) => {
if (!newCompanyFk) return;
vnFilterRef.value.addFilter(newCompanyFk);
companyUser.value = newCompanyFk;
},
blur: () => !companyId.value && (companyId.value = companyUser.value),
},
},
visible: false,
};
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'right', align: 'left',
name: 'payed', name: 'payed',
label: t('Date'), label: t('Date'),
format: ({ payed }) => toDate(payed), format: ({ payed }) => toDate(payed),
cardVisible: true, cardVisible: true,
}, },
{ {
align: 'right', align: 'left',
name: 'created', name: 'created',
label: t('Creation date'), label: t('Creation date'),
format: ({ created }) => toDateHourMin(created), format: ({ created }) => toDateHourMin(created),
@ -65,7 +90,12 @@ const columns = computed(() => [
label: t('Employee'), label: t('Employee'),
columnField: { columnField: {
component: 'userLink', component: 'userLink',
attrs: ({ row }) => ({ workerId: row.workerFk, name: row.userName }), attrs: ({ row }) => {
return {
workerId: row.workerFk,
name: row.userName,
};
},
}, },
cardVisible: true, cardVisible: true,
}, },
@ -77,13 +107,13 @@ const columns = computed(() => [
class: 'extend', class: 'extend',
}, },
{ {
align: 'right', align: 'left',
name: 'bankFk', name: 'bankFk',
label: t('Bank'), label: t('Bank'),
cardVisible: true, cardVisible: true,
}, },
{ {
align: 'right', align: 'left',
name: 'debit', name: 'debit',
label: t('Debit'), label: t('Debit'),
format: ({ debit }) => debit && toCurrency(debit), format: ({ debit }) => debit && toCurrency(debit),
@ -136,20 +166,37 @@ const columns = computed(() => [
onBeforeMount(() => { onBeforeMount(() => {
stateStore.rightDrawer = true; stateStore.rightDrawer = true;
companyId.value = companyUser.value;
}); });
async function getCurrentBalance(data) { async function getClientRisks() {
currentBalance.value[companyId.value] = { const filter = {
amount: 0, where: { clientFk: route.params.id, companyFk: companyUser.value },
code: companies.value.find((c) => c.id === companyId.value)?.code,
}; };
const { data } = await getClientRisk(filter);
clientRisk.value = data;
return clientRisk.value;
}
for (const balance of data) { async function getCurrentBalance() {
currentBalance.value[balance.companyFk] = { const currentBalance = (await getClientRisks()).find((balance) => {
code: balance.company.code, return balance.companyFk === companyId.value;
amount: balance.amount, });
}; return currentBalance && currentBalance.amount;
}
async function onFetch(data) {
balances.value = [];
for (const [index, balance] of data.entries()) {
if (index === 0) {
balance.balance = await getCurrentBalance();
continue;
}
const previousBalance = data[index - 1];
balance.balance =
previousBalance?.balance - (previousBalance?.debit - previousBalance?.credit);
} }
balances.value = data;
} }
const showNewPaymentDialog = () => { const showNewPaymentDialog = () => {
@ -169,43 +216,25 @@ const showBalancePdf = ({ id }) => {
</script> </script>
<template> <template>
<FetchData
url="Companies"
auto-load
@on-fetch="(data) => (companies = data)"
></FetchData>
<FetchData
v-if="companies.length > 0"
url="clientRisks"
:filter="{
include: { relation: 'company', scope: { fields: ['code'] } },
where: { clientFk: route.params.id },
}"
auto-load
@on-fetch="getCurrentBalance"
></FetchData>
<VnSubToolbar class="q-mb-md"> <VnSubToolbar class="q-mb-md">
<template #st-data> <template #st-data>
<div class="column justify-center q-px-md q-py-sm"> <div class="column justify-center q-px-md q-py-sm">
<span class="text-bold">{{ t('Total by company') }}</span> <span class="text-bold">{{ t('Total by company') }}</span>
<div class="row justify-center"> <div class="row justify-center" v-if="clientRisk?.length">
{{ currentBalance[companyId]?.code }}: {{ clientRisk[0].company.code }}:
{{ toCurrency(currentBalance[companyId]?.amount) }} {{ toCurrency(clientRisk[0].amount) }}
</div> </div>
</div> </div>
</template> </template>
<template #st-actions> <template #st-actions>
<div> <div>
<VnSelect <VnFilter
:label="t('Company')"
ref="vnFilterRef" ref="vnFilterRef"
v-model="companyId" v-model="companyId"
data-key="CustomerBalance" data-key="CustomerBalance"
:options="companies" :column="companyFilterColumn"
option-label="code" search-url="balance"
option-value="id" />
></VnSelect>
</div> </div>
</template> </template>
</VnSubToolbar> </VnSubToolbar>
@ -219,6 +248,7 @@ const showBalancePdf = ({ id }) => {
:right-search="false" :right-search="false"
:is-editable="false" :is-editable="false"
:column-search="false" :column-search="false"
@on-fetch="onFetch"
:disable-option="{ card: true }" :disable-option="{ card: true }"
auto-load auto-load
> >

View File

@ -37,6 +37,9 @@ const entityId = computed(() => {
const data = ref(useCardDescription()); const data = ref(useCardDescription());
const setData = (entity) => (data.value = useCardDescription(entity?.name, entity?.id)); const setData = (entity) => (data.value = useCardDescription(entity?.name, entity?.id));
const debtWarning = computed(() => {
return customer.value?.debt > customer.value?.credit ? 'negative' : 'primary';
});
</script> </script>
<template> <template>
@ -111,7 +114,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
v-if="customer.debt > customer.credit" v-if="customer.debt > customer.credit"
name="vn:risk" name="vn:risk"
size="xs" size="xs"
color="primary" :color="debtWarning"
> >
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip> <QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
</QIcon> </QIcon>

View File

@ -8,9 +8,6 @@ import { useQuasar } from 'quasar';
import useNotify from 'src/composables/useNotify'; import useNotify from 'src/composables/useNotify';
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue'; import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
import TicketCreateDialog from 'src/pages/Ticket/TicketCreateDialog.vue';
import OrderCreateDialog from 'src/pages/Order/Card/OrderCreateDialog.vue';
import { ref } from 'vue';
const $props = defineProps({ const $props = defineProps({
customer: { customer: {
@ -28,7 +25,7 @@ const showSmsDialog = () => {
quasar.dialog({ quasar.dialog({
component: VnSmsDialog, component: VnSmsDialog,
componentProps: { componentProps: {
phone: $props.customer.phone || $props.customer.mobile, phone: $props.customer.mobile || $props.customer.phone,
promise: sendSms, promise: sendSms,
}, },
}); });
@ -44,13 +41,38 @@ const sendSms = async (payload) => {
} }
}; };
const ticketCreateFormDialog = ref(null);
const openTicketCreateForm = () => { const openTicketCreateForm = () => {
ticketCreateFormDialog.value.show(); const query = {
table: {
clientFk: $props.customer.id,
},
createForm: {
clientId: $props.customer.id,
addressId: $props.customer.defaultAddressFk,
},
};
openWindow('ticket', query);
}; };
const orderCreateFormDialog = ref(null);
const openOrderCreateForm = () => { const openOrderCreateForm = () => {
orderCreateFormDialog.value.show(); const query = {
table: {
clientFk: $props.customer.id,
},
createForm: {
clientFk: $props.customer.id,
addressId: $props.customer.defaultAddressFk,
},
};
openWindow('order', query);
};
const openWindow = (type, { createForm, table }) => {
window.open(
`/#/${type}/list?createForm=${JSON.stringify(createForm)}&table=${JSON.stringify(
table
)}`,
'_blank'
);
}; };
</script> </script>
@ -58,17 +80,11 @@ const openOrderCreateForm = () => {
<QItem v-ripple clickable @click="openTicketCreateForm()"> <QItem v-ripple clickable @click="openTicketCreateForm()">
<QItemSection> <QItemSection>
{{ t('globals.pageTitles.createTicket') }} {{ t('globals.pageTitles.createTicket') }}
<QDialog ref="ticketCreateFormDialog">
<TicketCreateDialog />
</QDialog>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem v-ripple clickable @click="openOrderCreateForm()"> <QItem v-ripple clickable @click="openOrderCreateForm()">
<QItemSection> <QItemSection>
{{ t('globals.pageTitles.createOrder') }} {{ t('globals.pageTitles.createOrder') }}
<QDialog ref="orderCreateFormDialog">
<OrderCreateDialog :client-fk="customer.id" />
</QDialog>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem v-ripple clickable> <QItem v-ripple clickable>

View File

@ -11,6 +11,20 @@ defineProps({
required: true, required: true,
}, },
}); });
const handleSalesModelValue = (val) => ({
or: [
{ id: val },
{ name: val },
{ nickname: { like: '%' + val + '%' } },
{ code: { like: `${val}%` } },
],
});
const exprBuilder = (param, value) => {
return {
and: [{ active: { neq: false } }, handleSalesModelValue(value)],
};
};
</script> </script>
<template> <template>
@ -52,14 +66,18 @@ defineProps({
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnSelect <VnSelect
url="Workers/activeWithInheritedRole" url="Workers/search"
:filter="{ where: { role: 'salesPerson' } }" :params="{
departmentCodes: ['VT'],
}"
auto-load auto-load
:label="t('Salesperson')" :label="t('Salesperson')"
:expr-builder="exprBuilder"
v-model="params.salesPersonFk" v-model="params.salesPersonFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
option-value="id" option-value="id"
option-label="name" option-label="name"
sort-by="nickname ASC"
emit-value emit-value
map-options map-options
use-input use-input
@ -68,7 +86,18 @@ defineProps({
outlined outlined
rounded rounded
:input-debounce="0" :input-debounce="0"
/> >
<template #option="{ itemProps, opt }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.name }}</QItemLabel>
<QItemLabel caption>
{{ opt.nickname }},{{ opt.code }}
</QItemLabel>
</QItemSection>
</QItem>
</template></VnSelect
>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">

View File

@ -68,7 +68,6 @@ const columns = computed(() => [
fields: ['id', 'name'], fields: ['id', 'name'],
where: { role: 'salesPerson' }, where: { role: 'salesPerson' },
optionFilter: 'firstName', optionFilter: 'firstName',
useLike: false,
}, },
create: false, create: false,
columnField: { columnField: {
@ -429,9 +428,10 @@ function handleLocation(data, location) {
:params="{ :params="{
departmentCodes: ['VT', 'shopping'], departmentCodes: ['VT', 'shopping'],
}" }"
:fields="['id', 'nickname']" :fields="['id', 'nickname', 'code']"
sort-by="nickname ASC" sort-by="nickname ASC"
:use-like="false" option-label="nickname"
option-value="id"
emit-value emit-value
auto-load auto-load
> >

View File

@ -23,6 +23,7 @@ const incoterms = ref([]);
const customsAgents = ref([]); const customsAgents = ref([]);
const observationTypes = ref([]); const observationTypes = ref([]);
const notes = ref([]); const notes = ref([]);
let originalNotes = [];
const deletes = ref([]); const deletes = ref([]);
onBeforeMount(() => { onBeforeMount(() => {
@ -42,7 +43,8 @@ const getData = async (observations) => {
}); });
if (data.length) { if (data.length) {
notes.value = data originalNotes = data;
notes.value = originalNotes
.map((observation) => { .map((observation) => {
const type = observationTypes.value.find( const type = observationTypes.value.find(
(type) => type.id === observation.observationTypeFk (type) => type.id === observation.observationTypeFk
@ -81,14 +83,24 @@ const deleteNote = (id, index) => {
}; };
const onDataSaved = async () => { const onDataSaved = async () => {
let payload = {}; let payload = {
const creates = notes.value.filter((note) => note.$isNew); creates: notes.value.filter((note) => note.$isNew),
if (creates.length) { deletes: deletes.value,
payload.creates = creates; updates: notes.value
} .filter((note) =>
if (deletes.value.length) { originalNotes.some(
payload.deletes = deletes.value; (oNote) =>
} oNote.id === note.id &&
(note.description !== oNote.description ||
note.observationTypeFk !== oNote.observationTypeFk)
)
)
.map((note) => ({
data: note,
where: { id: note.id },
})),
};
await axios.post('AddressObservations/crud', payload); await axios.post('AddressObservations/crud', payload);
notes.value = []; notes.value = [];
deletes.value = []; deletes.value = [];

View File

@ -184,16 +184,17 @@ const getItemPackagingType = (ticketSales) => {
: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"
redirect="ticket"
> >
<template #column-nickname="{ row }"> <template #column-nickname="{ row }">
<span class="link"> <span class="link" @click.stop>
{{ row.nickname }} {{ row.nickname }}
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" />
</span> </span>
</template> </template>
<template #column-routeFk="{ row }"> <template #column-routeFk="{ row }">
<span class="link"> <span class="link" @click.stop>
{{ row.routeFk }} {{ row.routeFk }}
<RouteDescriptorProxy :id="row.routeFk" /> <RouteDescriptorProxy :id="row.routeFk" />
</span> </span>
@ -210,7 +211,7 @@ const getItemPackagingType = (ticketSales) => {
<span v-else> {{ toCurrency(row.totalWithVat) }}</span> <span v-else> {{ toCurrency(row.totalWithVat) }}</span>
</template> </template>
<template #column-state="{ row }"> <template #column-state="{ row }">
<span v-if="row.invoiceOut"> <span v-if="row.invoiceOut" @click.stop>
<span :class="{ link: row.invoiceOut.ref }"> <span :class="{ link: row.invoiceOut.ref }">
{{ row.invoiceOut.ref }} {{ row.invoiceOut.ref }}
<InvoiceOutDescriptorProxy :id="row.invoiceOut.id" /> <InvoiceOutDescriptorProxy :id="row.invoiceOut.id" />

View File

@ -0,0 +1,12 @@
import axios from 'axios';
export async function getClientRisk(_filter) {
const filter = {
..._filter,
include: { relation: 'company', scope: { fields: ['code'] } },
};
return await axios(`ClientRisks`, {
params: { filter: JSON.stringify(filter) },
});
}

View File

@ -99,7 +99,7 @@ const travelDialogRef = ref(false);
const tableRef = ref(); const tableRef = ref();
const travel = ref(null); const travel = ref(null);
const userParams = ref({ const userParams = ref({
dated: Date.vnNew(), dated: Date.vnNew().toJSON(),
}); });
const filter = ref({ const filter = ref({
@ -219,6 +219,7 @@ function round(value) {
data-key="StockBoughts" data-key="StockBoughts"
url="StockBoughts/getStockBought" url="StockBoughts/getStockBought"
save-url="StockBoughts/crud" save-url="StockBoughts/crud"
search-url="StockBoughts"
order="reserve DESC" order="reserve DESC"
:right-search="false" :right-search="false"
:is-editable="true" :is-editable="true"
@ -281,6 +282,7 @@ function round(value) {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
min-width: 35%;
} }
.text-negative { .text-negative {
color: $negative !important; color: $negative !important;

View File

@ -18,7 +18,7 @@ const $props = defineProps({
required: true, required: true,
}, },
}); });
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&date=${$props.dated}`; const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
const columns = [ const columns = [
{ {
align: 'left', align: 'left',

View File

@ -27,7 +27,7 @@ onMounted(async () => {
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:search-button="true" :search-button="true"
search-url="table" search-url="StockBoughts"
@set-user-params="setUserParams" @set-user-params="setUserParams"
> >
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
@ -36,12 +36,19 @@ onMounted(async () => {
<span>{{ formatFn(tag.value) }}</span> <span>{{ formatFn(tag.value) }}</span>
</div> </div>
</template> </template>
<template #body="{ params }"> <template #body="{ params, searchFn }">
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
id="date" id="date"
v-model="params.dated" v-model="params.dated"
@update:model-value="
(value) => {
params.dated = value;
setUserParams(params);
searchFn();
}
"
:label="t('Date')" :label="t('Date')"
is-outlined is-outlined
/> />

View File

@ -17,21 +17,6 @@ const props = defineProps({
}); });
const itemTypeWorkersOptions = ref([]); const itemTypeWorkersOptions = ref([]);
const exprBuilder = (param, value) => {
switch (param) {
case 'name':
return { 'i.name': { like: `%${value}%` } };
case 'itemFk':
case 'warehouseFk':
case 'rate2':
case 'rate3':
param = `fp.${param}`;
return { [param]: value };
case 'minPrice':
param = `i.${param}`;
return { [param]: value };
}
};
</script> </script>
<template> <template>
@ -66,7 +51,7 @@ const exprBuilder = (param, value) => {
url="Warehouses" url="Warehouses"
auto-load auto-load
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }" :filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
:label="t('components.itemsFilterPanel.warehouseFk')" :label="t('globals.warehouse')"
v-model="params.warehouseFk" v-model="params.warehouseFk"
option-label="name" option-label="name"
option-value="id" option-value="id"

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue'; import { computed, onMounted, ref } from 'vue';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters'; import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -14,7 +14,6 @@ import OrderFilter from './Card/OrderFilter.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date'; import { toDateTimeFormat } from 'src/filters/date';
import { onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
const { t } = useI18n(); const { t } = useI18n();
@ -142,8 +141,13 @@ const columns = computed(() => [
], ],
}, },
]); ]);
onMounted(() => {
async function fetchClientAddress(id, formData) { if (!route.query.createForm) return;
const clientId = route.query.createForm;
const id = JSON.parse(clientId);
fetchClientAddress(id.clientFk);
});
async function fetchClientAddress(id, formData = {}) {
const { data } = await axios.get(`Clients/${id}`, { const { data } = await axios.get(`Clients/${id}`, {
params: { filter: { include: { relation: 'addresses' } } }, params: { filter: { include: { relation: 'addresses' } } },
}); });
@ -170,13 +174,6 @@ const getDateColor = (date) => {
if (comparation == 0) return 'bg-warning'; if (comparation == 0) return 'bg-warning';
if (comparation < 0) return 'bg-success'; if (comparation < 0) return 'bg-success';
}; };
onMounted(() => {
if (!route.query.createForm) return;
const clientId = route.query.createForm;
const id = JSON.parse(clientId);
fetchClientAddress(id.clientFk, id);
});
</script> </script>
<template> <template>
<OrderSearchbar /> <OrderSearchbar />
@ -194,7 +191,7 @@ onMounted(() => {
urlCreate: 'Orders/new', urlCreate: 'Orders/new',
title: t('module.cerateOrder'), title: t('module.cerateOrder'),
onDataSaved: (url) => { onDataSaved: (url) => {
tableRef.redirect(url); tableRef.redirect(`${url}/catalog`);
}, },
formInitialData: { formInitialData: {
active: true, active: true,

View File

@ -271,6 +271,7 @@ onMounted(() => (stateStore.rightDrawer = false));
:label="t('purchaseRequest.price')" :label="t('purchaseRequest.price')"
type="number" type="number"
min="0" min="0"
step="any"
/> />
</template> </template>
</VnTable> </VnTable>

View File

@ -22,7 +22,6 @@ import { useVnConfirm } from 'composables/useVnConfirm';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import axios from 'axios'; import axios from 'axios';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -779,9 +778,6 @@ watch(
:label="t('ticketSale.discount')" :label="t('ticketSale.discount')"
type="number" type="number"
/> />
<div v-if="usesMana" class="column q-gutter-y-sm q-mt-sm">
<VnUsesMana :mana-code="manaCode" />
</div>
</TicketEditManaProxy> </TicketEditManaProxy>
</template> </template>
<span v-else>{{ toPercentage(row.discount / 100) }}</span> <span v-else>{{ toPercentage(row.discount / 100) }}</span>

View File

@ -19,7 +19,6 @@ import VnTitle from 'src/components/common/VnTitle.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue'; import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
import VnToSummary from 'src/components/ui/VnToSummary.vue'; import VnToSummary from 'src/components/ui/VnToSummary.vue';
const route = useRoute(); const route = useRoute();
@ -87,10 +86,6 @@ async function changeState(value) {
function toTicketUrl(section) { function toTicketUrl(section) {
return '#/ticket/' + entityId.value + '/' + section; return '#/ticket/' + entityId.value + '/' + section;
} }
function isOnTicketCard() {
const currentPath = route.path;
return currentPath.startsWith('/ticket');
}
</script> </script>
<template> <template>

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { computed, ref, onMounted } from 'vue'; import { computed, ref, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -24,6 +24,8 @@ import { toTimeFormat } from 'src/filters/date';
import InvoiceOutDescriptorProxy from '../InvoiceOut/Card/InvoiceOutDescriptorProxy.vue'; import InvoiceOutDescriptorProxy from '../InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
const route = useRoute(); const route = useRoute();
const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref(); const tableRef = ref();
@ -40,16 +42,18 @@ from.setDate(from.getDate() - 7);
const to = Date.vnNew(); const to = Date.vnNew();
to.setHours(23, 59, 0, 0); to.setHours(23, 59, 0, 0);
to.setDate(to.getDate() + 1); to.setDate(to.getDate() + 1);
const userParams = { const userParams = {
from: null, from: null,
to: null, to: null,
}; };
// Método para inicializar las variables desde la query string onMounted(() => {
initializeFromQuery();
stateStore.rightDrawer = true;
if (!route.query.createForm) return;
onClientSelected(JSON.parse(route.query.createForm));
});
const initializeFromQuery = () => { const initializeFromQuery = () => {
const query = route.query.table ? JSON.parse(route.query.table) : {}; const query = route.query.table ? JSON.parse(route.query.table) : {};
// Asigna los valores a las variables correspondientes
from.value = query.from || from.toISOString(); from.value = query.from || from.toISOString();
to.value = query.to || to.toISOString(); to.value = query.to || to.toISOString();
Object.assign(userParams, { from, to }); Object.assign(userParams, { from, to });
@ -206,13 +210,19 @@ const columns = computed(() => [
{ {
title: t('ticketList.summary'), title: t('ticketList.summary'),
icon: 'preview', icon: 'preview',
isPrimary: true, action: (row, evt) => {
action: (row) => viewSummary(row.id, TicketSummary), if (evt && evt.ctrlKey) {
const url = router.resolve({
params: { id: row.id },
name: 'TicketCard',
}).href;
window.open(url, '_blank');
} else viewSummary(row.id, TicketSummary);
},
}, },
], ],
}, },
]); ]);
function redirectToLines(id) { function redirectToLines(id) {
const url = `#/ticket/${id}/sale`; const url = `#/ticket/${id}/sale`;
window.open(url, '_blank'); window.open(url, '_blank');
@ -302,11 +312,6 @@ const getDateColor = (date) => {
if (comparation < 0) return 'bg-success'; if (comparation < 0) return 'bg-success';
}; };
onMounted(() => {
initializeFromQuery();
stateStore.rightDrawer = true;
});
async function makeInvoice(ticket) { async function makeInvoice(ticket) {
const ticketsIds = ticket.map((item) => item.id); const ticketsIds = ticket.map((item) => item.id);
const { data } = await axios.post(`Tickets/invoiceTicketsAndPdf`, { ticketsIds }); const { data } = await axios.post(`Tickets/invoiceTicketsAndPdf`, { ticketsIds });
@ -472,7 +477,7 @@ function setReference(data) {
urlCreate: 'Tickets/new', urlCreate: 'Tickets/new',
title: t('ticketList.createTicket'), title: t('ticketList.createTicket'),
onDataSaved: ({ id }) => tableRef.redirect(id), onDataSaved: ({ id }) => tableRef.redirect(id),
formInitialData: {}, formInitialData: { clientId: null },
}" }"
default-mode="table" default-mode="table"
:order="['shippedDate DESC', 'shippedHour ASC', 'zoneLanding ASC', 'id']" :order="['shippedDate DESC', 'shippedHour ASC', 'zoneLanding ASC', 'id']"
@ -574,17 +579,17 @@ function setReference(data) {
</span> </span>
</template> </template>
<template #column-stateFk="{ row }"> <template #column-stateFk="{ row }">
<span v-if="getColor(row)"> <span v-if="row.refFk">
<QChip :class="getColor(row)" dense square>
{{ row.state }}
</QChip>
</span>
<span v-else-if="row.state === 'Entregado'">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.refFk }} {{ row.refFk }}
<InvoiceOutDescriptorProxy :id="row.invoiceOutId" /> <InvoiceOutDescriptorProxy :id="row.invoiceOutId" />
</span> </span>
</span> </span>
<span v-else-if="getColor(row)">
<QChip :class="getColor(row)" dense square>
{{ row.state }}
</QChip>
</span>
<span v-else> <span v-else>
{{ row.state }} {{ row.state }}
</span> </span>
@ -616,6 +621,7 @@ function setReference(data) {
option-value="id" option-value="id"
option-label="name" option-label="name"
hide-selected hide-selected
required
@update:model-value="(client) => onClientSelected(data)" @update:model-value="(client) => onClientSelected(data)"
:sort-by="'id ASC'" :sort-by="'id ASC'"
> >
@ -635,7 +641,7 @@ function setReference(data) {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelect <VnSelect
url="Addresses" required
:label="t('ticket.create.address')" :label="t('ticket.create.address')"
v-model="data.addressId" v-model="data.addressId"
:options="addressesOptions" :options="addressesOptions"
@ -680,6 +686,7 @@ function setReference(data) {
option-value="id" option-value="id"
option-label="name" option-label="name"
hide-selected hide-selected
required
@update:model-value="() => fetchAvailableAgencies(data)" @update:model-value="() => fetchAvailableAgencies(data)"
/> />
</div> </div>
@ -693,7 +700,6 @@ function setReference(data) {
option-value="agencyModeFk" option-value="agencyModeFk"
option-label="agencyMode" option-label="agencyMode"
hide-selected hide-selected
:disable="!data.clientId || !data.landed || !data.warehouseId"
/> />
</div> </div>
</VnRow> </VnRow>
@ -829,7 +835,14 @@ function setReference(data) {
</QTooltip> </QTooltip>
</QPageSticky> </QPageSticky>
</template> </template>
<style scoped>
.disabled,
.disabled *,
[disabled],
[disabled] * {
cursor: pointer !important;
}
</style>
<i18n> <i18n>
es: es:
Search ticket: Buscar ticket Search ticket: Buscar ticket

View File

@ -205,8 +205,10 @@ const onThermographCreated = async (data) => {
}" }"
sort-by="thermographFk ASC" sort-by="thermographFk ASC"
option-label="thermographFk" option-label="thermographFk"
option-filter-value="thermographFk"
:disable="viewAction === 'edit'" :disable="viewAction === 'edit'"
:tooltip="t('New thermograph')" :tooltip="t('New thermograph')"
:roles-allowed-to-create="['logistic']"
> >
<template #form> <template #form>
<CreateThermographForm <CreateThermographForm

View File

@ -20,12 +20,13 @@ function notIsLocations(ifIsFalse, ifIsTrue) {
<template> <template>
<VnCard <VnCard
data-key="zone" data-key="zone"
base-url="Zones" :base-url="notIsLocations('Zones', undefined)"
:descriptor="ZoneDescriptor" :descriptor="ZoneDescriptor"
:filter-panel="ZoneFilterPanel" :filter-panel="notIsLocations(ZoneFilterPanel, undefined)"
:search-data-key="notIsLocations('ZoneList', 'ZoneLocations')" :search-data-key="notIsLocations('ZoneList', undefined)"
:custom-url="`Zones/${route.params?.id}/getLeaves`"
:searchbar-props="{ :searchbar-props="{
url: 'Zones', url: notIsLocations('Zones', 'ZoneLocations'),
label: notIsLocations(t('list.searchZone'), t('list.searchLocation')), label: notIsLocations(t('list.searchZone'), t('list.searchLocation')),
info: t('list.searchInfo'), info: t('list.searchInfo'),
whereFilter: notIsLocations((value) => { whereFilter: notIsLocations((value) => {

View File

@ -5,6 +5,7 @@ import VnInput from 'src/components/common/VnInput.vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
import axios from 'axios'; import axios from 'axios';
import { useArrayData } from 'composables/useArrayData'; import { useArrayData } from 'composables/useArrayData';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
const props = defineProps({ const props = defineProps({
rootLabel: { rootLabel: {
@ -33,22 +34,23 @@ const state = useState();
const treeRef = ref(); const treeRef = ref();
const expanded = ref([]); const expanded = ref([]);
const arrayData = useArrayData('ZoneLocations', { const datakey = 'ZoneLocations';
url: `Zones/${route.params.id}/getLeaves`, const url = computed(() => `Zones/${route.params.id}/getLeaves`);
const arrayData = useArrayData(datakey, {
url: url.value,
}); });
const { store } = arrayData; const { store } = arrayData;
const storeData = computed(() => store.data); const storeData = computed(() => store.data);
const nodes = ref([ const defaultNode = {
{ id: null,
id: null, name: props.rootLabel,
name: props.rootLabel, sons: true,
sons: true, tickable: false,
tickable: false, noTick: true,
noTick: true, children: [{}],
children: [{}], };
}, const nodes = ref([defaultNode]);
]);
const _tickedNodes = computed({ const _tickedNodes = computed({
get: () => props.tickedNodes, get: () => props.tickedNodes,
@ -229,6 +231,7 @@ onUnmounted(() => {
<QBtn color="primary" icon="search" dense flat @click="reFetch()" /> <QBtn color="primary" icon="search" dense flat @click="reFetch()" />
</template> </template>
</VnInput> </VnInput>
<VnSearchbar :data-key="datakey" :url="url" :redirect="false" />
<QTree <QTree
ref="treeRef" ref="treeRef"
:nodes="nodes" :nodes="nodes"

View File

@ -96,7 +96,7 @@ watch(
sort-by="code, townFk" sort-by="code, townFk"
option-value="geoFk" option-value="geoFk"
option-label="code" option-label="code"
:filter-options="['code', 'geoFk']" :filter-options="['code']"
hide-selected hide-selected
dense dense
outlined outlined
@ -105,11 +105,14 @@ watch(
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
<QItemSection v-if="opt.code"> <QItemSection v-if="opt.code">
<QItemLabel>{{ opt.code }}</QItemLabel> <QItemLabel>
<QItemLabel caption {{ `${opt.code}, ${opt.town?.name}` }}
>{{ opt.town?.province?.name }}, </QItemLabel>
{{ opt.town?.province?.country?.name }}</QItemLabel <QItemLabel caption>
> {{
`${opt.town?.province?.name}, ${opt.town?.province?.country?.name}`
}}
</QItemLabel>
</QItemSection> </QItemSection>
</QItem> </QItem>
</template> </template>

View File

@ -22,7 +22,12 @@ const agencies = ref([]);
</script> </script>
<template> <template>
<FetchData url="agencies" @on-fetch="(data) => (agencies = data)" auto-load /> <FetchData
url="AgencyModes"
:filter="{ fields: ['id', 'name'] }"
@on-fetch="(data) => (agencies = data)"
auto-load
/>
<VnFilterPanel <VnFilterPanel
:data-key="props.dataKey" :data-key="props.dataKey"
:search-button="true" :search-button="true"

View File

@ -73,6 +73,7 @@ const columns = computed(() => [
inWhere: true, inWhere: true,
attrs: { attrs: {
url: 'AgencyModes', url: 'AgencyModes',
fields: ['id', 'name'],
}, },
}, },
columnField: { columnField: {