refs #5835 migrateInvoiceIn #110
|
@ -15,6 +15,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
filterOptions: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
const { optionLabel, options } = toRefs($props);
|
||||
const myOptions = ref([]);
|
||||
|
@ -28,18 +32,22 @@ function setOptions(data) {
|
|||
setOptions(options.value);
|
||||
|
||||
const filter = (val, options) => {
|
||||
const search = val.toLowerCase();
|
||||
const search = val.toString().toLowerCase();
|
||||
|
||||
if (val === '') return options;
|
||||
if (!search) return options;
|
||||
|
||||
return options.filter((row) => {
|
||||
if ($props.filterOptions.length) {
|
||||
return $props.filterOptions.some((prop) => {
|
||||
const propValue = String(row[prop]).toLowerCase();
|
||||
return propValue.includes(search);
|
||||
});
|
||||
}
|
||||
|
||||
const id = row.id;
|
||||
const name = row[$props.optionLabel].toLowerCase();
|
||||
const optionLabel = String(row[$props.optionLabel]).toLowerCase();
|
||||
|
||||
const idMatches = id == search;
|
||||
const nameMatches = name.indexOf(search) > -1;
|
||||
|
||||
return idMatches || nameMatches;
|
||||
return id == search || optionLabel.includes(search);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -89,7 +97,7 @@ const value = computed({
|
|||
<QIcon name="close" @click.stop="value = null" class="cursor-pointer" />
|
||||
</template>
|
||||
<template v-for="(_, slotName) in $slots" #[slotName]="slotData">
|
||||
<slot :name="slotName" v-bind="slotData" />
|
||||
<slot :name="slotName" v-bind="slotData ?? {}" />
|
||||
</template>
|
||||
</QSelect>
|
||||
</template>
|
||||
|
|
|
@ -76,9 +76,9 @@ async function search() {
|
|||
const module = route.matched[1];
|
||||
if (rows.length === 1) {
|
||||
const [firstRow] = rows;
|
||||
await router.push({ path: `/${module.name}/${firstRow.id}` });
|
||||
await router.push({ path: `${module.path}/${firstRow.id}` });
|
||||
} else if (route.matched.length > 3) {
|
||||
await router.push({ path: `/${module.name}` });
|
||||
await router.push({ path: `/${module.path}` });
|
||||
arrayData.updateStateParams();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import { useSession } from 'src/composables/useSession';
|
||||
import { getUrl } from './getUrl';
|
||||
|
||||
const session = useSession();
|
||||
const token = session.getToken();
|
||||
|
||||
export async function downloadFile(dmsId) {
|
||||
let appUrl = await getUrl('', 'lilium');
|
||||
jorgep marked this conversation as resolved
|
||||
appUrl = appUrl.replace('/#/', '');
|
||||
window.open(`${appUrl}/api/dms/${dmsId}/downloadFile?access_token=${token}`);
|
||||
}
|
|
@ -1,11 +1,10 @@
|
|||
import axios from 'axios';
|
||||
|
||||
export async function getUrl(route, appName = 'salix') {
|
||||
const filter = {
|
||||
where: { and: [{ appName: appName }, { environment: process.env.NODE_ENV }] },
|
||||
};
|
||||
export async function getUrl(route, app = 'salix') {
|
||||
let url;
|
||||
|
||||
const { data } = await axios.get('Urls/findOne', { params: { filter } });
|
||||
const url = data.url;
|
||||
return route ? url + route : url;
|
||||
await axios.get('Urls/getUrl', { params: { app } }).then((res) => {
|
||||
url = res.data + route;
|
||||
});
|
||||
return url;
|
||||
}
|
||||
|
|
|
@ -390,6 +390,71 @@ export default {
|
|||
totalWithVat: 'Amount',
|
||||
},
|
||||
},
|
||||
invoiceIn: {
|
||||
pageTitles: {
|
||||
invoiceIns: 'Invoices In',
|
||||
list: 'List',
|
||||
createInvoiceIn: 'Create invoice in',
|
||||
summary: 'Summary',
|
||||
basicData: 'Basic Data',
|
||||
vat: 'VAT',
|
||||
dueDay: 'Due day',
|
||||
intrastat: 'Intrastat',
|
||||
log: 'Logs',
|
||||
},
|
||||
list: {
|
||||
ref: 'Reference',
|
||||
supplier: 'Supplier',
|
||||
supplierRef: 'Supplier ref.',
|
||||
serialNumber: 'Serial number',
|
||||
serial: 'Serial',
|
||||
file: 'File',
|
||||
issued: 'Issued',
|
||||
isBooked: 'Is booked',
|
||||
awb: 'AWB',
|
||||
amount: 'Amount',
|
||||
},
|
||||
card: {
|
||||
issued: 'Issued',
|
||||
amount: 'Amount',
|
||||
client: 'Client',
|
||||
company: 'Company',
|
||||
customerCard: 'Customer card',
|
||||
ticketList: 'Ticket List',
|
||||
vat: 'Vat',
|
||||
dueDay: 'Due day',
|
||||
intrastat: 'Intrastat',
|
||||
},
|
||||
summary: {
|
||||
supplier: 'Supplier',
|
||||
supplierRef: 'Supplier ref.',
|
||||
currency: 'Currency',
|
||||
docNumber: 'Doc number',
|
||||
issued: 'Expedition date',
|
||||
operated: 'Operation date',
|
||||
bookEntried: 'Entry date',
|
||||
bookedDate: 'Booked date',
|
||||
sage: 'Sage withholding',
|
||||
vat: 'Undeductible VAT',
|
||||
company: 'Company',
|
||||
booked: 'Booked',
|
||||
expense: 'Expense',
|
||||
taxableBase: 'Taxable base',
|
||||
rate: 'Rate',
|
||||
sageVat: 'Sage vat',
|
||||
sageTransaction: 'Sage transaction',
|
||||
dueDay: 'Date',
|
||||
bank: 'Bank',
|
||||
amount: 'Amount',
|
||||
foreignValue: 'Foreign value',
|
||||
dueTotal: 'Due day',
|
||||
noMatch: 'Do not match',
|
||||
code: 'Code',
|
||||
net: 'Net',
|
||||
stems: 'Stems',
|
||||
country: 'Country',
|
||||
},
|
||||
},
|
||||
worker: {
|
||||
pageTitles: {
|
||||
workers: 'Workers',
|
||||
|
@ -514,6 +579,7 @@ export default {
|
|||
openCard: 'View card',
|
||||
openSummary: 'Open summary',
|
||||
viewDescription: 'View description',
|
||||
downloadFile: 'Download file',
|
||||
},
|
||||
cardDescriptor: {
|
||||
mainList: 'Main list',
|
||||
|
|
|
@ -390,6 +390,69 @@ export default {
|
|||
totalWithVat: 'Importe',
|
||||
},
|
||||
},
|
||||
invoiceIn: {
|
||||
pageTitles: {
|
||||
invoiceIns: 'Fact. recibidas',
|
||||
list: 'Listado',
|
||||
createInvoiceOut: 'Crear fact. recibida',
|
||||
summary: 'Resumen',
|
||||
jorgep marked this conversation as resolved
Outdated
jgallego
commented
invoice Out es factura emitida invoice Out es factura emitida
pero dejalo en Crear factura
|
||||
basicData: 'Datos básicos',
|
||||
vat: 'IVA',
|
||||
dueDay: 'Vencimiento',
|
||||
intrastat: 'Intrastat',
|
||||
log: 'Registros de auditoría',
|
||||
},
|
||||
jorgep marked this conversation as resolved
jgallego
commented
aquí creo que en salix es historico, puede ser? aquí creo que en salix es historico, puede ser?
jorgep
commented
En salix se llama histórico pero en Lilium le han puesto ese nombre en las otras secciones En salix se llama histórico pero en Lilium le han puesto ese nombre en las otras secciones
|
||||
list: {
|
||||
ref: 'Referencia',
|
||||
supplier: 'Proveedor',
|
||||
supplierRef: 'Ref. proveedor',
|
||||
jorgep marked this conversation as resolved
Outdated
jgallego
commented
invoice out es emitida, mira si esta mal la clave o el valor invoice out es emitida, mira si esta mal la clave o el valor
|
||||
serialNumber: 'Num. serie',
|
||||
shortIssued: 'F. emisión',
|
||||
serial: 'Serie',
|
||||
file: 'Fichero',
|
||||
issued: 'Fecha emisión',
|
||||
isBooked: 'Conciliada',
|
||||
awb: 'AWB',
|
||||
amount: 'Importe',
|
||||
},
|
||||
card: {
|
||||
issued: 'Fecha emisión',
|
||||
amount: 'Importe',
|
||||
client: 'Cliente',
|
||||
company: 'Empresa',
|
||||
customerCard: 'Ficha del cliente',
|
||||
ticketList: 'Listado de tickets',
|
||||
vat: 'Vat',
|
||||
dueDay: 'Fecha de vencimiento',
|
||||
},
|
||||
summary: {
|
||||
supplier: 'Supplier',
|
||||
supplierRef: 'Supplier ref.',
|
||||
currency: 'Divisa',
|
||||
docNumber: 'Número documento',
|
||||
issued: 'Fecha de expedición',
|
||||
operated: 'Fecha operación',
|
||||
bookEntried: 'Fecha asiento',
|
||||
bookedDate: 'Fecha contable',
|
||||
sage: 'Retención sage',
|
||||
vat: 'Iva no deducible',
|
||||
company: 'Empresa',
|
||||
booked: 'Contabilizada',
|
||||
expense: 'Gasto',
|
||||
taxableBase: 'Base imp.',
|
||||
rate: 'Tasa',
|
||||
sageTransaction: 'Sage transación',
|
||||
dueDay: 'Fecha',
|
||||
bank: 'Caja',
|
||||
amount: 'Importe',
|
||||
foreignValue: 'Divisa',
|
||||
dueTotal: 'Vencimiento',
|
||||
code: 'Código',
|
||||
net: 'Neto',
|
||||
stems: 'Tallos',
|
||||
country: 'País',
|
||||
},
|
||||
},
|
||||
worker: {
|
||||
pageTitles: {
|
||||
workers: 'Trabajadores',
|
||||
|
@ -514,6 +577,7 @@ export default {
|
|||
openCard: 'Ver ficha',
|
||||
openSummary: 'Abrir detalles',
|
||||
viewDescription: 'Ver descripción',
|
||||
downloadFile: 'Descargar archivo',
|
||||
},
|
||||
cardDescriptor: {
|
||||
mainList: 'Listado principal',
|
||||
|
|
|
@ -0,0 +1,742 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import axios from 'axios';
|
||||
|
||||
const quasar = useQuasar();
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const dms = ref({});
|
||||
const editDownloadDisabled = ref(false);
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
const userConfig = ref(null);
|
||||
|
||||
const suppliers = ref([]);
|
||||
const suppliersRef = ref();
|
||||
const currencies = ref([]);
|
||||
const currenciesRef = ref();
|
||||
const companies = ref([]);
|
||||
const companiesRef = ref();
|
||||
const dmsTypes = ref([]);
|
||||
const dmsTypesRef = ref();
|
||||
const warehouses = ref([]);
|
||||
const warehousesRef = ref();
|
||||
const allowTypesRef = ref();
|
||||
const allowedContentTypes = ref([]);
|
||||
const inputFileRef = ref();
|
||||
const editDmsRef = ref();
|
||||
const createDmsRef = ref();
|
||||
|
||||
async function checkFileExists(dmsId) {
|
||||
if (!dmsId) return;
|
||||
try {
|
||||
await axios.get(`Dms/${dmsId}`, { fields: ['id'] });
|
||||
editDownloadDisabled.value = false;
|
||||
} catch (e) {
|
||||
editDownloadDisabled.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
async function setEditDms(dmsId) {
|
||||
const { data } = await axios.get(`Dms/${dmsId}`);
|
||||
dms.value = {
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
lo miramos lo miramos
|
||||
id: data.id,
|
||||
warehouseId: data.warehouseFk,
|
||||
companyId: data.companyFk,
|
||||
dmsTypeId: data.dmsTypeFk,
|
||||
reference: data.reference,
|
||||
description: data.description,
|
||||
hasFile: data.hasFile,
|
||||
hasFileAttached: data.hasFileAttached,
|
||||
};
|
||||
|
||||
if (!allowedContentTypes.value.length) await allowTypesRef.value.fetch();
|
||||
|
||||
editDmsRef.value.show();
|
||||
}
|
||||
|
||||
async function setCreateDms() {
|
||||
const { data } = await axios.get('DmsTypes/findOne', {
|
||||
where: { code: 'invoiceIn' },
|
||||
});
|
||||
dms.value = {
|
||||
reference: invoiceIn.value.supplierRef,
|
||||
warehouseId: userConfig.value.warehouseFk,
|
||||
companyId: userConfig.value.companyFk,
|
||||
dmsTypeId: data.id,
|
||||
description: invoiceIn.value.supplier.name,
|
||||
hasFile: true,
|
||||
hasFileAttached: true,
|
||||
files: null,
|
||||
};
|
||||
|
||||
createDmsRef.value.show();
|
||||
}
|
||||
|
||||
async function edit() {
|
||||
try {
|
||||
if (!dms.value.companyId) throw new Error(t(`The company can't be empty`));
|
||||
jorgep marked this conversation as resolved
Outdated
jsegarra
commented
Incluso te diría que en vez de tantos ifs, haría un objeto de validaciones, donde la key es el campo y el value es el mensaje a mostrar.
Para la que aplica en edit, usuaria la bandera que hemos comentado Incluso te diría que en vez de tantos ifs, haría un objeto de validaciones, donde la key es el campo y el value es el mensaje a mostrar.
```
const validations = {
companyId:'The company can\'t be empty'
}
Object.entries(validations).forEach(([key, value])=>{
if(!dms.value[key])
throw Error(t(value))
});
```
Para la que aplica en edit, usuaria la bandera que hemos comentado
|
||||
if (!dms.value.warehouseId) throw new Error(t(`The warehouse can't be empty`));
|
||||
if (!dms.value.dmsTypeId) throw new Error(t(`The DMS Type can't be empty`));
|
||||
if (!dms.value.description) throw new Error(t(`The description can't be empty`));
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
if (dms.value.files) {
|
||||
for (let i = 0; i < dms.value.files.length; i++)
|
||||
formData.append(dms.value.files[i].name, dms.value.files[i]);
|
||||
dms.value.hasFileAttached = true;
|
||||
}
|
||||
|
||||
const { data } = await axios.post(`dms/${dms.value.id}/updateFile`, formData, {
|
||||
params: dms.value,
|
||||
});
|
||||
|
||||
if (data.length) invoiceIn.value.dmsFk = data[0].id;
|
||||
editDmsRef.value.hide();
|
||||
|
||||
quasar.notify({
|
||||
message: t('globals.dataSaved'),
|
||||
type: 'positive',
|
||||
});
|
||||
} catch (error) {
|
||||
quasar.notify({
|
||||
message: t(`${error}`),
|
||||
type: 'negative',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function create() {
|
||||
jorgep marked this conversation as resolved
Outdated
jsegarra
commented
Yo movería la lógica de create y save a funciones constantes porque estás duplicando código que hacen lo mismo Yo movería la lógica de create y save a funciones constantes porque estás duplicando código que hacen lo mismo
|
||||
try {
|
||||
if (!dms.value.companyId) throw new Error(t(`The company can't be empty`));
|
||||
if (!dms.value.warehouseId) throw new Error(t(`The warehouse can't be empty`));
|
||||
if (!dms.value.dmsTypeId) throw new Error(t(`The DMS Type can't be empty`));
|
||||
if (!dms.value.description) throw new Error(t(`The description can't be empty`));
|
||||
if (!dms.value.files) throw new Error(t(`The files can't be empty`));
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
if (dms.value.files) {
|
||||
for (let i = 0; i < dms.value.files.length; i++)
|
||||
formData.append(dms.value.files[i].name, dms.value.files[i]);
|
||||
dms.value.hasFileAttached = true;
|
||||
}
|
||||
|
||||
const { data } = await axios.post('Dms/uploadFile', formData, {
|
||||
params: dms.value,
|
||||
});
|
||||
if (data.length) invoiceIn.value.dmsFk = data[0].id;
|
||||
editDmsRef.value.hide();
|
||||
|
||||
quasar.notify({
|
||||
message: t('globals.dataSaved'),
|
||||
type: 'positive',
|
||||
});
|
||||
} catch (error) {
|
||||
quasar.notify({
|
||||
message: t(`${error}`),
|
||||
type: 'negative',
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
ref="suppliersRef"
|
||||
url="Suppliers"
|
||||
:filter="{ fields: ['id', 'nickname'] }"
|
||||
limit="30"
|
||||
@on-fetch="(data) => (suppliers = data)"
|
||||
/>
|
||||
<FetchData
|
||||
ref="currenciesRef"
|
||||
url="Currencies"
|
||||
:filter="{ fields: ['id', 'code'] }"
|
||||
order="code"
|
||||
@on-fetch="(data) => (currencies = data)"
|
||||
/>
|
||||
<FetchData
|
||||
ref="companiesRef"
|
||||
url="Companies"
|
||||
:filter="{ fields: ['id', 'code'] }"
|
||||
order="code"
|
||||
@on-fetch="(data) => (companies = data)"
|
||||
/>
|
||||
<FetchData
|
||||
ref="dmsTypesRef"
|
||||
url="DmsTypes"
|
||||
:filter="{ fields: ['id', 'name'] }"
|
||||
order="name"
|
||||
@on-fetch="(data) => (dmsTypes = data)"
|
||||
/>
|
||||
<FetchData
|
||||
ref="warehousesRef"
|
||||
url="Warehouses"
|
||||
:filter="{ fields: ['id', 'name'] }"
|
||||
order="name"
|
||||
@on-fetch="(data) => (warehouses = data)"
|
||||
/>
|
||||
<FetchData
|
||||
ref="allowTypesRef"
|
||||
url="DmsContainers/allowedContentTypes"
|
||||
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||
/>
|
||||
<FetchData
|
||||
url="UserConfigs/getUserConfig"
|
||||
@on-fetch="(data) => (userConfig = data)"
|
||||
auto-load
|
||||
/>
|
||||
<div class="column items-center">
|
||||
<QCard>
|
||||
<FormModel
|
||||
v-if="invoiceIn"
|
||||
:url="`InvoiceIns/${route.params.id}`"
|
||||
model="invoiceIn"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
v-if="suppliersRef"
|
||||
:label="t('supplierFk')"
|
||||
v-model="data.supplierFk"
|
||||
:options="suppliers"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
@input-value="suppliersRef.fetch()"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
`${scope.opt.id} - ${scope.opt.nickname}`
|
||||
}}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:label="t('Supplier ref')"
|
||||
v-model="data.supplierRef"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput :label="t('Expedition date')" v-model="data.issued">
|
||||
<template #append>
|
||||
<QIcon
|
||||
name="event"
|
||||
class="cursor-pointer"
|
||||
mask="####-##-##"
|
||||
fill-mask="_"
|
||||
>
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate v-model="data.issued">
|
||||
<div class="row items-center justify-end">
|
||||
<QBtn
|
||||
v-close-popup
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('Operation date')"
|
||||
v-model="data.operated"
|
||||
mask="####-##-##"
|
||||
fill-mask="_"
|
||||
autofocus
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate
|
||||
v-model="data.operated"
|
||||
mask="YYYY-MM-DD"
|
||||
>
|
||||
<div class="row items-center justify-end">
|
||||
<QBtn
|
||||
v-close-popup
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('Undeductible VAT')"
|
||||
v-model="data.deductibleExpenseFk"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('Document')"
|
||||
v-model="data.dmsFk"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
@update:model-value="checkFileExists(data.dmsFk)"
|
||||
>
|
||||
<template #prepend>
|
||||
<QBtn
|
||||
v-if="data.dmsFk"
|
||||
:class="{
|
||||
'no-pointer-events': editDownloadDisabled,
|
||||
}"
|
||||
:disable="editDownloadDisabled"
|
||||
icon="cloud_download"
|
||||
:title="t('Download file')"
|
||||
padding="xs"
|
||||
round
|
||||
@click="downloadFile(data.dmsFk)"
|
||||
/>
|
||||
</template>
|
||||
<template #append>
|
||||
<QBtn
|
||||
:class="{
|
||||
'no-pointer-events': editDownloadDisabled,
|
||||
}"
|
||||
:disable="editDownloadDisabled"
|
||||
v-if="data.dmsFk"
|
||||
icon="edit"
|
||||
round
|
||||
padding="xs"
|
||||
@click="setEditDms(data.dmsFk)"
|
||||
>
|
||||
<QTooltip>{{ t('Edit document') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
v-else
|
||||
icon="add_circle"
|
||||
round
|
||||
padding="xs"
|
||||
@click="setCreateDms()"
|
||||
>
|
||||
<QTooltip>{{ t('Create document') }}</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</QInput>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('Entry date')"
|
||||
v-model="data.bookEntried"
|
||||
clearable
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
Los valores de las propiedades de mask, podrían ser globales en el componente? Los valores de las propiedades de mask, podrían ser globales en el componente?
|
||||
clear-icon="close"
|
||||
mask="####-##-##"
|
||||
fill-mask="_"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate
|
||||
v-model="data.bookEntried"
|
||||
mask="YYYY-MM-DD"
|
||||
>
|
||||
<div class="row items-center justify-end">
|
||||
<QBtn
|
||||
v-close-popup
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</div>
|
||||
<div class="col">
|
||||
<QInput
|
||||
:label="t('Accounted date')"
|
||||
v-model="data.booked"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
mask="####-##-##"
|
||||
fill-mask="_"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate
|
||||
v-model="data.booked"
|
||||
mask="YYYY-MM-DD"
|
||||
>
|
||||
<div class="row items-center justify-end">
|
||||
<QBtn
|
||||
v-close-popup
|
||||
label="Close"
|
||||
color="primary"
|
||||
flat
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
v-if="currenciesRef"
|
||||
:label="t('Currency')"
|
||||
v-model="data.currencyFk"
|
||||
:options="currencies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
@input-value="currenciesRef.fetch()"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
v-if="companiesRef"
|
||||
:label="t('Company')"
|
||||
v-model="data.companyFk"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
@input-value="companiesRef.fetch()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row q-gutter-md q-mb-md">
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
Esta rule esta muchas veces en el código y es la misma en todos los casos. Esta rule esta muchas veces en el código y es la misma en todos los casos.
Se podría sacar del HTML y definir en el script setup?
|
||||
<div class="col">
|
||||
<QCheckbox
|
||||
:label="t('invoiceIn.summary.booked')"
|
||||
v-model="data.isBooked"
|
||||
/>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QCard>
|
||||
</div>
|
||||
<QDialog ref="editDmsRef">
|
||||
<QCard>
|
||||
<QCardSection class="q-pb-none">
|
||||
<QItem class="q-px-none">
|
||||
<span class="text-primary text-h6 full-width">
|
||||
<QIcon name="edit" class="q-mr-xs" />
|
||||
{{ t('Edit document') }}
|
||||
</span>
|
||||
<QBtn icon="close" flat round dense v-close-popup />
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-py-none">
|
||||
<QItem>
|
||||
<QInput
|
||||
class="full-width q-pa-xs"
|
||||
:label="t('Reference')"
|
||||
v-model="dms.reference"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Company')}*`"
|
||||
v-model="dms.companyId"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
@input-value="companiesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Warehouse')}*`"
|
||||
v-model="dms.warehouseId"
|
||||
:options="warehouses"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
@input-value="warehousesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Type')}*`"
|
||||
v-model="dms.dmsTypeId"
|
||||
:options="dmsTypes"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
@input-value="dmsTypesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
class="full-width q-pa-xs"
|
||||
type="textarea"
|
||||
size="lg"
|
||||
autogrow
|
||||
:label="`${t('Description')}*`"
|
||||
v-model="dms.description"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:rules="[(val) => val.length || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
class="full-width q-pa-xs"
|
||||
:label="t('File')"
|
||||
v-model="dms.files"
|
||||
multiple
|
||||
:accept="allowedContentTypes.join(',')"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QBtn
|
||||
icon="attach_file_add"
|
||||
flat
|
||||
round
|
||||
padding="xs"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
<QTooltip max-width="30rem">
|
||||
{{
|
||||
`${t(
|
||||
'Allowed content types'
|
||||
)}: ${allowedContentTypes.join(', ')}`
|
||||
}}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</QFile>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QCheckbox
|
||||
:label="t('Generate identifier for original file')"
|
||||
v-model="dms.hasFile"
|
||||
/>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardActions class="justify-end">
|
||||
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
||||
<QBtn :label="t('globals.save')" color="primary" @click="edit" />
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
<QDialog ref="createDmsRef">
|
||||
<QCard>
|
||||
<QCardSection class="q-pb-none">
|
||||
<QItem>
|
||||
<span class="text-primary text-h6 full-width">
|
||||
<QIcon name="edit" class="q-mr-xs" />
|
||||
{{ t('Create document') }}
|
||||
</span>
|
||||
<QBtn icon="close" flat round dense v-close-popup align="right" />
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-pb-none">
|
||||
<QItem>
|
||||
<QInput
|
||||
class="full-width q-pa-xs"
|
||||
:label="t('Reference')"
|
||||
v-model="dms.reference"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Company')}*`"
|
||||
v-model="dms.companyId"
|
||||
:options="companies"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
@input-value="companiesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Warehouse')}*`"
|
||||
v-model="dms.warehouseId"
|
||||
:options="warehouses"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
@input-value="warehousesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
<VnSelectFilter
|
||||
class="full-width q-pa-xs"
|
||||
:label="`${t('Type')}*`"
|
||||
v-model="dms.dmsTypeId"
|
||||
:options="dmsTypes"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
@input-value="dmsTypesRef.fetch()"
|
||||
:rules="[(val) => val || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
class="full-width q-pa-xs"
|
||||
type="textarea"
|
||||
size="lg"
|
||||
autogrow
|
||||
:label="`${t('Description')}*`"
|
||||
v-model="dms.description"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
:rules="[(val) => val.length || t('Required field')]"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QFile
|
||||
ref="inputFileRef"
|
||||
class="full-width q-pa-xs"
|
||||
:label="t('File')"
|
||||
v-model="dms.files"
|
||||
multiple
|
||||
:accept="allowedContentTypes.join(',')"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QBtn
|
||||
icon="attach_file_add"
|
||||
flat
|
||||
round
|
||||
padding="xs"
|
||||
@click="inputFileRef.pickFiles()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Select a file') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn icon="info" flat round padding="xs">
|
||||
<QTooltip max-width="30rem">
|
||||
{{
|
||||
`${t(
|
||||
'Allowed content types'
|
||||
)}: ${allowedContentTypes.join(', ')}`
|
||||
}}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</QFile>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QCheckbox
|
||||
:label="t('Generate identifier for original file')"
|
||||
v-model="dms.hasFile"
|
||||
/>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardActions align="right">
|
||||
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
||||
<QBtn :label="t('globals.save')" color="primary" @click="create()" />
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.column {
|
||||
.q-card {
|
||||
width: 100%;
|
||||
max-width: 60em;
|
||||
}
|
||||
}
|
||||
@media (max-width: $breakpoint-xs) {
|
||||
.q-dialog {
|
||||
.q-card {
|
||||
&__section:not(:first-child) {
|
||||
.q-item {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
supplierFk: Supplier
|
||||
es:
|
||||
supplierFk: Proveedor
|
||||
Supplier Ref: Ref. proveedor
|
||||
Expedition date: Fecha expedición
|
||||
Operation date: Fecha operación
|
||||
Undeductible VAT: Iva no deducible
|
||||
Document: Documento
|
||||
Download file: Descargar archivo
|
||||
Entry date: Fecha asiento
|
||||
Accounted date: Fecha contable
|
||||
Currency: Moneda
|
||||
Company: Empresa
|
||||
Edit document: Editar documento
|
||||
Reference: Referencia
|
||||
Type: Tipo
|
||||
Description: Descripción
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
Required field: Campo obligatorio
|
||||
File: Fichero
|
||||
Create document: Crear documento
|
||||
Select a file: Seleccione un fichero
|
||||
Allowed content types: Tipos de archivo permitidos
|
||||
The company can't be empty: La empresa no puede estar vacía
|
||||
The warehouse can't be empty: El almacén no puede estar vacío
|
||||
The DMS Type can't be empty: El dms no puede estar vacío
|
||||
The description can't be empty: La descripción no puede estar vacía
|
||||
The files can't be empty: Los archivos no pueden estar vacíos
|
||||
</i18n>
|
|
@ -0,0 +1,91 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import InvoiceInDescriptor from './InvoiceInDescriptor.vue';
|
||||
import LeftMenu from 'components/LeftMenu.vue';
|
||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { onMounted, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'supplier',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'contacts',
|
||||
scope: {
|
||||
where: {
|
||||
email: { neq: null },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'invoiceInDueDay',
|
||||
},
|
||||
{
|
||||
relation: 'company',
|
||||
},
|
||||
{
|
||||
relation: 'currency',
|
||||
},
|
||||
],
|
||||
};
|
||||
const arrayData = useArrayData('InvoiceIn', {
|
||||
url: `InvoiceIns/${route.params.id}`,
|
||||
filter,
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
await arrayData.fetch({ append: false });
|
||||
watch(
|
||||
() => route.params.id,
|
||||
async (newId, oldId) => {
|
||||
if (newId) {
|
||||
arrayData.store.url = `InvoiceIns/${newId}`;
|
||||
await arrayData.fetch({ append: false });
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<Teleport to="#searchbar" v-if="stateStore.isHeaderMounted()">
|
||||
<VnSearchbar
|
||||
data-key="InvoiceInList"
|
||||
url="InvoiceIns/filter"
|
||||
:label="t('Search invoice')"
|
||||
:info="t('You can search by invoice reference')"
|
||||
/>
|
||||
</Teleport>
|
||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
||||
<QScrollArea class="fit">
|
||||
<InvoiceInDescriptor />
|
||||
<QSeparator />
|
||||
<LeftMenu source="card" />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<QPageContainer>
|
||||
<QPage>
|
||||
<QToolbar class="bg-vn-dark justify-end">
|
||||
<div id="st-data"></div>
|
||||
<QSpace />
|
||||
<div id="st-actions"></div>
|
||||
</QToolbar>
|
||||
<div class="q-pa-md"><RouterView></RouterView></div>
|
||||
</QPage>
|
||||
</QPageContainer>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Search invoice: Buscar factura emitida
|
||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||
</i18n>
|
|
@ -0,0 +1,108 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const entityId = computed(() => {
|
||||
return $props.id || route.params.id;
|
||||
});
|
||||
const totalAmount = ref([]);
|
||||
// Cuando Carlossa acabe de crear la lógica de card, usar store arrayData en lugar de hacer el fetch en el descriptor
|
||||
const filter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'supplier',
|
||||
scope: {
|
||||
include: {
|
||||
relation: 'contacts',
|
||||
scope: {
|
||||
where: {
|
||||
email: { neq: null },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'invoiceInDueDay',
|
||||
},
|
||||
{
|
||||
relation: 'company',
|
||||
},
|
||||
{
|
||||
relation: 'currency',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const data = ref(useCardDescription());
|
||||
function setData(entity) {
|
||||
data.value = useCardDescription(entity.supplierRef, entity.id);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!--Refactor para añadir en el arrayData-->
|
||||
<FetchData
|
||||
:url="`InvoiceIns/${entityId}/getTotals`"
|
||||
@on-fetch="
|
||||
(data) => {
|
||||
totalAmount = data.totalDueDay;
|
||||
}
|
||||
"
|
||||
auto-load
|
||||
/>
|
||||
<CardDescriptor
|
||||
module="InvoiceIn"
|
||||
:url="`InvoiceIns/${entityId}`"
|
||||
:filter="filter"
|
||||
:title="data.title"
|
||||
:subtitle="data.subtitle"
|
||||
@on-fetch="setData"
|
||||
>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="t('invoiceIn.card.issued')" :value="toDate(entity.issued)" />
|
||||
<VnLv :label="t('invoiceIn.summary.booked')" :value="toDate(entity.booked)" />
|
||||
<VnLv :label="t('invoiceIn.card.amount')" :value="toCurrency(totalAmount)" />
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplier')"
|
||||
:value="entity.supplier?.nickname"
|
||||
/>
|
||||
</template>
|
||||
<template #actions="{ entity }">
|
||||
<QCardActions>
|
||||
<!--Sección proveedores no disponible-->
|
||||
<!--Sección entradas no disponible-->
|
||||
<QBtn
|
||||
size="md"
|
||||
icon="vn:ticket"
|
||||
color="primary"
|
||||
:to="{
|
||||
name: 'InvoiceInList',
|
||||
query: {
|
||||
params: JSON.stringify({ supplierFk: entity.supplierFk }),
|
||||
},
|
||||
}"
|
||||
>
|
||||
<QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip>
|
||||
</QBtn>
|
||||
</QCardActions>
|
||||
</template>
|
||||
</CardDescriptor>
|
||||
</template>
|
|
@ -0,0 +1,290 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toDate } from 'src/filters';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
|
||||
const rowsSelected = ref([]);
|
||||
const banks = ref([]);
|
||||
const invoiceInFormRef = ref();
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
invoiceInFk: route.params.id,
|
||||
},
|
||||
};
|
||||
|
||||
const isNotEuro = (code) => code != 'EUR';
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'duedate',
|
||||
label: t('Date'),
|
||||
field: (row) => toDate(row.dueDated),
|
||||
sortable: true,
|
||||
tabIndex: 1,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'bank',
|
||||
label: t('Bank'),
|
||||
field: (row) => row.bankFk,
|
||||
options: banks.value,
|
||||
model: 'bankFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'bank',
|
||||
sortable: true,
|
||||
tabIndex: 2,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: t('Amount'),
|
||||
field: (row) => row.amount,
|
||||
sortable: true,
|
||||
tabIndex: 3,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'foreignvalue',
|
||||
label: t('Foreign value'),
|
||||
field: (row) => row.foreignValue,
|
||||
sortable: true,
|
||||
tabIndex: 4,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
<template>
|
||||
<FetchData url="Banks" auto-load limit="30" @on-fetch="(data) => (banks = data)" />
|
||||
<CrudModel
|
||||
v-if="invoiceIn"
|
||||
jorgep marked this conversation as resolved
Outdated
jsegarra
commented
TIP: es igual poner Number(invoiceId) que +invoiceId TIP: es igual poner Number(invoiceId) que +invoiceId
|
||||
ref="invoiceInFormRef"
|
||||
data-key="InvoiceInDueDays"
|
||||
url="InvoiceInDueDays"
|
||||
:filter="filter"
|
||||
auto-load
|
||||
:data-required="{ invoiceInFk: route.params.id }"
|
||||
v-model:selected="rowsSelected"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
v-model:selected="rowsSelected"
|
||||
selection="multiple"
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
row-key="$index"
|
||||
hide-pagination
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell-duedate="{ row }">
|
||||
<QTd>
|
||||
<QInput
|
||||
v-model="row.dueDated"
|
||||
mask="date"
|
||||
placeholder="yyyy/mm/dd"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
Quizás debería ser una valor constante Quizás debería ser una valor constante
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate v-model="row.dueDated" landscape>
|
||||
<div
|
||||
class="row items-center justify-end q-gutter-sm"
|
||||
>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.confirm')"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-bank="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
`${scope.opt.id}: ${scope.opt.bank}`
|
||||
}}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-amount="{ row }">
|
||||
<QTd>
|
||||
<QInput v-model="row.amount" clearable clear-icon="close" />
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-foreignvalue="{ row }">
|
||||
<QTd>
|
||||
<QInput
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(invoiceIn.currency.code),
|
||||
}"
|
||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
||||
v-model="row.foreignValue"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard>
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QList>
|
||||
<QItem>
|
||||
<QInput
|
||||
class="full-width"
|
||||
:label="t('Date')"
|
||||
v-model="props.row.dueDated"
|
||||
mask="date"
|
||||
placeholder="yyyy/mm/dd"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate
|
||||
v-model="props.row.dueDated"
|
||||
landscape
|
||||
>
|
||||
<div
|
||||
class="row items-center justify-end q-gutter-sm"
|
||||
>
|
||||
<QBtn
|
||||
:label="
|
||||
t('globals.cancel')
|
||||
"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="
|
||||
t('globals.confirm')
|
||||
"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
:label="t('Bank')"
|
||||
class="full-width"
|
||||
v-model="props.row['bankFk']"
|
||||
:options="banks"
|
||||
option-value="id"
|
||||
option-label="bank"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
`${scope.opt.id}: ${scope.opt.bank}`
|
||||
}}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
:label="t('Amount')"
|
||||
class="full-width"
|
||||
v-model="props.row.amount"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
:label="t('Foreign value')"
|
||||
class="full-width"
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(
|
||||
invoiceIn.currency.code
|
||||
),
|
||||
}"
|
||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
||||
v-model="props.row.foreignValue"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="add"
|
||||
size="lg"
|
||||
round
|
||||
@click="invoiceInFormRef.insert()"
|
||||
/>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
<style lang="scss" scoped></style>
|
||||
<i18n>
|
||||
es:
|
||||
Date: Fecha
|
||||
Bank: Caja
|
||||
Amount: Importe
|
||||
Foreign value: Divisa
|
||||
</i18n>
|
|
@ -0,0 +1,280 @@
|
|||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toCurrency } from 'src/filters';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
||||
const invoceInIntrastat = ref([]);
|
||||
const amountTotal = computed(() => getTotal('amount'));
|
||||
const netTotal = computed(() => getTotal('net'));
|
||||
const stemsTotal = computed(() => getTotal('stems'));
|
||||
const rowsSelected = ref([]);
|
||||
const countries = ref([]);
|
||||
const intrastats = ref([]);
|
||||
const invoiceInFormRef = ref();
|
||||
|
||||
const filter = {
|
||||
where: {
|
||||
invoiceInFk: route.params.id,
|
||||
},
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'code',
|
||||
label: t('Code'),
|
||||
field: (row) => row.intrastatFk,
|
||||
options: intrastats.value,
|
||||
model: 'intrastatFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
sortable: true,
|
||||
tabIndex: 1,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: t('amount'),
|
||||
field: (row) => row.amount,
|
||||
sortable: true,
|
||||
tabIndex: 2,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'net',
|
||||
label: t('net'),
|
||||
field: (row) => row.net,
|
||||
sortable: true,
|
||||
tabIndex: 3,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'stems',
|
||||
label: t('stems'),
|
||||
field: (row) => row.stems,
|
||||
sortable: true,
|
||||
tabIndex: 4,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
label: t('country'),
|
||||
field: (row) => row.countryFk,
|
||||
options: countries.value,
|
||||
model: 'countryFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'code',
|
||||
sortable: true,
|
||||
tabIndex: 5,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
function getTotal(type) {
|
||||
if (!invoceInIntrastat.value.length) return 0.0;
|
||||
return invoceInIntrastat.value.reduce(
|
||||
(total, intrastat) => total + intrastat[type],
|
||||
0.0
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
url="Countries"
|
||||
auto-load
|
||||
@on-fetch="(data) => (countries = data)"
|
||||
sort-by="country"
|
||||
/>
|
||||
<FetchData
|
||||
url="Intrastats"
|
||||
sort-by="id"
|
||||
auto-load
|
||||
@on-fetch="(data) => (intrastats = data)"
|
||||
/>
|
||||
<div class="invoiceIn-intrastat">
|
||||
<QCard v-if="invoceInIntrastat.length" class="full-width q-mb-md q-pa-sm">
|
||||
<QItem class="justify-end">
|
||||
<div>
|
||||
<QItemLabel>
|
||||
<VnLv
|
||||
:label="t('Total amount')"
|
||||
:value="toCurrency(amountTotal)"
|
||||
/>
|
||||
</QItemLabel>
|
||||
<QItemLabel>
|
||||
<VnLv :label="t('Total net')" :value="netTotal" />
|
||||
</QItemLabel>
|
||||
<QItemLabel>
|
||||
<VnLv :label="t('Total stems')" :value="stemsTotal" />
|
||||
</QItemLabel>
|
||||
</div>
|
||||
</QItem>
|
||||
</QCard>
|
||||
<CrudModel
|
||||
ref="invoiceInFormRef"
|
||||
data-key="InvoiceInIntrastats"
|
||||
url="InvoiceInIntrastats"
|
||||
auto-load
|
||||
:data-required="{ invoiceInFk: route.params.id }"
|
||||
:filter="filter"
|
||||
v-model:selected="rowsSelected"
|
||||
@on-fetch="(data) => (invoceInIntrastat = data)"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
v-model:selected="rowsSelected"
|
||||
selection="multiple"
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
row-key="$index"
|
||||
hide-pagination
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell="{ row, col }">
|
||||
<QTd>
|
||||
<QInput
|
||||
v-model="row[col.name]"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-code="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:filter-options="['id', 'description']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{ `${scope.opt.id}: ${scope.opt.description}` }}
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-country="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard>
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QList>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
:label="t('code')"
|
||||
class="full-width"
|
||||
v-model="props.row['intrastatFk']"
|
||||
:options="intrastats"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
:filter-options="['id', 'description']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{
|
||||
`${scope.opt.id}: ${scope.opt.description}`
|
||||
}}
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-for="(value, index) of [
|
||||
'amount',
|
||||
'net',
|
||||
'stems',
|
||||
]"
|
||||
:key="index"
|
||||
>
|
||||
<QInput
|
||||
:label="t(value)"
|
||||
class="full-width"
|
||||
v-model="props.row[value]"
|
||||
clearable
|
||||
clear-icon="close"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
:label="t('country')"
|
||||
class="full-width"
|
||||
v-model="props.row['countryFk']"
|
||||
:options="countries"
|
||||
option-value="id"
|
||||
option-label="code"
|
||||
/>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</CrudModel>
|
||||
</div>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="add"
|
||||
size="lg"
|
||||
round
|
||||
@click="invoiceInFormRef.insert()"
|
||||
/>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
.invoiceIn-intrastat {
|
||||
> .q-card {
|
||||
.vn-label-value {
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
|
||||
.label {
|
||||
flex: 1;
|
||||
}
|
||||
.value {
|
||||
flex: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped></style>
|
||||
<i18n>
|
||||
en:
|
||||
amount: Amount
|
||||
net: Net
|
||||
stems: Stems
|
||||
country: Country
|
||||
es:
|
||||
Code: Código
|
||||
amount: Cantidad
|
||||
net: Neto
|
||||
stems: Tallos
|
||||
country: País
|
||||
Total amount: Total importe
|
||||
Total net: Total neto
|
||||
Total stems: Total tallos
|
||||
</i18n>
|
|
@ -0,0 +1,409 @@
|
|||
<script setup>
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { toCurrency, toDate } from 'src/filters';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
|
||||
import CardSummary from 'components/ui/CardSummary.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
|
||||
onMounted(async () => {
|
||||
salixUrl.value = await getUrl('');
|
||||
invoiceInUrl.value = salixUrl.value + `invoiceIn/${entityId.value}/`;
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
});
|
||||
|
||||
const entityId = computed(() => $props.id || route.params.id);
|
||||
|
||||
const salixUrl = ref();
|
||||
const invoiceInUrl = ref();
|
||||
const amountsNotMatch = ref(null);
|
||||
|
||||
const vatColumns = ref([
|
||||
{
|
||||
name: 'expense',
|
||||
label: 'invoiceIn.summary.expense',
|
||||
field: (row) => row.expenseFk,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'landed',
|
||||
label: 'invoiceIn.summary.taxableBase',
|
||||
field: (row) => row.taxableBase,
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'vat',
|
||||
label: 'invoiceIn.summary.sageVat',
|
||||
field: (row) => row.taxTypeSage?.vat,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'transaction',
|
||||
label: 'invoiceIn.summary.sageTransaction',
|
||||
field: (row) => row.transactionTypeSage?.transaction,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'rate',
|
||||
label: 'invoiceIn.summary.rate',
|
||||
field: (row) => row.taxRate,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'currency',
|
||||
label: 'invoiceIn.summary.currency',
|
||||
field: (row) => row.foreignValue,
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
const dueDayColumns = ref([
|
||||
{
|
||||
name: 'date',
|
||||
label: 'invoiceIn.summary.dueDay',
|
||||
field: (row) => toDate(row.dueDated),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'bank',
|
||||
label: 'invoiceIn.summary.bank',
|
||||
field: (row) => row.bank.bank,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: 'invoiceIn.summary.amount',
|
||||
field: (row) => row.amount,
|
||||
format: (value) => toCurrency(value),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'landed',
|
||||
label: 'invoiceIn.summary.foreignValue',
|
||||
field: (row) => row.foreignValue,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
const intrastatColumns = ref([
|
||||
{
|
||||
name: 'code',
|
||||
label: 'invoiceIn.summary.code',
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
({intrastat}) en vez de row ({intrastat}) en vez de row
|
||||
field: (row) => {
|
||||
return `${row.intrastat.id}: ${row.intrastat?.description}`;
|
||||
},
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: 'invoiceIn.summary.amount',
|
||||
field: (row) => toCurrency(row.amount),
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'net',
|
||||
label: 'invoiceIn.summary.net',
|
||||
field: (row) => row.net,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'amount',
|
||||
label: 'invoiceIn.summary.stems',
|
||||
field: (row) => row.stems,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'landed',
|
||||
label: 'invoiceIn.summary.country',
|
||||
field: (row) => row.country?.code,
|
||||
format: (value) => value,
|
||||
sortable: true,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
function setAmountNotMatch(entity) {
|
||||
if (!entity) return false;
|
||||
|
||||
const total = entity.totals;
|
||||
|
||||
amountsNotMatch.value =
|
||||
total.totalDueDay != total.totalTaxableBase &&
|
||||
total.totalDueDay != total.totalVat;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardSummary
|
||||
ref="summary"
|
||||
:url="`InvoiceIns/${entityId}/summary`"
|
||||
@on-fetch="(data) => setAmountNotMatch(data)"
|
||||
>
|
||||
<template #header="{ entity: invoiceIn }">
|
||||
<div>{{ invoiceIn.id }} - {{ invoiceIn.supplier.name }}</div>
|
||||
</template>
|
||||
<template #body="{ entity: invoiceIn }">
|
||||
<QCard class="vn-one">
|
||||
<QCardSection class="q-pa-none">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/basic-data`">
|
||||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
jorgep marked this conversation as resolved
Outdated
jsegarra
commented
Revisamos si añadiendo valores por defecto podemos quitar líneas Revisamos si añadiendo valores por defecto podemos quitar líneas
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplier')"
|
||||
:value="invoiceIn.supplier.name"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.supplierRef')"
|
||||
:value="invoiceIn.supplierRef"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.currency')"
|
||||
:value="invoiceIn.currency.code"
|
||||
/>
|
||||
<VnLv
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
4 llamadas al mismo formato de URL, podríamos tenerlo en un método con un argumento? 4 llamadas al mismo formato de URL, podríamos tenerlo en un método con un argumento?
|
||||
:label="t('invoiceIn.summary.docNumber')"
|
||||
:value="`${invoiceIn.serial}/${invoiceIn.serialNumber}`"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<QCardSection class="q-pa-none">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/basic-data`">
|
||||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.issued')"
|
||||
:value="toDate(invoiceIn.issued)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.operated')"
|
||||
:value="toDate(invoiceIn.operated)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.bookEntried')"
|
||||
:value="toDate(invoiceIn.bookEntried)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.bookedDate')"
|
||||
:value="toDate(invoiceIn.booked)"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="vn-one">
|
||||
<QCardSection class="q-pa-none">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/basic-data`">
|
||||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-pa-none">
|
||||
<div class="bordered q-px-sm">
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.taxableBase')"
|
||||
:value="toCurrency(invoiceIn.totals.totalTaxableBase)"
|
||||
/>
|
||||
<VnLv
|
||||
label="Total"
|
||||
:value="toCurrency(invoiceIn.totals.totalVat)"
|
||||
/>
|
||||
<VnLv :label="t('invoiceIn.summary.dueTotal')">
|
||||
<template #value>
|
||||
<QChip
|
||||
dense
|
||||
class="q-pa-xs"
|
||||
:color="amountsNotMatch ? 'negative' : 'transparent'"
|
||||
:title="
|
||||
amountsNotMatch
|
||||
? t('invoiceIn.summary.noMatch')
|
||||
: t('invoiceIn.summary.dueTotal')
|
||||
"
|
||||
>
|
||||
{{ toCurrency(invoiceIn.totals.totalDueDay) }}
|
||||
</QChip>
|
||||
</template>
|
||||
</VnLv>
|
||||
</div>
|
||||
</QCardSection>
|
||||
</QCard>
|
||||
<QCard class="q-mb-md">
|
||||
<QCardSection class="q-pa-none">
|
||||
<a class="header" :href="`#/invoice-in/${entityId}/basic-data`">
|
||||
{{ t('invoiceIn.pageTitles.basicData') }}
|
||||
<QIcon name="open_in_new" color="primary" />
|
||||
</a>
|
||||
<QBtn
|
||||
class="q-ml-sm"
|
||||
padding="xs"
|
||||
flat
|
||||
color="primary"
|
||||
round
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(invoiceIn.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardSection>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.sage')"
|
||||
:value="invoiceIn.sageWithholding.withholding"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.vat')"
|
||||
:value="invoiceIn.expenseDeductible?.name"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.company')"
|
||||
:value="invoiceIn.company.code"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.summary.booked')"
|
||||
:value="invoiceIn.isBooked"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard v-if="invoiceIn.invoiceInTax.length" class="vn-three">
|
||||
<a class="header">
|
||||
{{ t('invoiceIn.card.vat') }}
|
||||
</a>
|
||||
<QTable
|
||||
:columns="vatColumns"
|
||||
:rows="invoiceIn.invoiceInTax"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ t(col.label) }}
|
||||
</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
<QCard v-if="invoiceIn.invoiceInDueDay.length" class="vn-two">
|
||||
<div class="header">
|
||||
{{ t('invoiceIn.card.dueDay') }}
|
||||
</div>
|
||||
<QTable
|
||||
:columns="dueDayColumns"
|
||||
:rows="invoiceIn.invoiceInDueDay"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ t(col.label) }}
|
||||
</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
<QCard v-if="invoiceIn.invoiceInIntrastat.length">
|
||||
<div class="header">
|
||||
{{ t('invoiceIn.card.intrastat') }}
|
||||
</div>
|
||||
<QTable
|
||||
:columns="intrastatColumns"
|
||||
:rows="invoiceIn.invoiceInIntrastat"
|
||||
flat
|
||||
hide-pagination
|
||||
>
|
||||
<template #header="props">
|
||||
<QTr :props="props">
|
||||
<QTh v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ t(col.label) }}
|
||||
</QTh>
|
||||
</QTr>
|
||||
</template>
|
||||
</QTable>
|
||||
</QCard>
|
||||
</template>
|
||||
</CardSummary>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.bordered {
|
||||
border: 1px solid var(--vn-text);
|
||||
width: 16em;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
es:
|
||||
Search invoice: Buscar factura emitida
|
||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||
</i18n>
|
|
@ -0,0 +1,29 @@
|
|||
<script setup>
|
||||
import { useDialogPluginComponent } from 'quasar';
|
||||
import InvoiceInSummary from './InvoiceInSummary.vue';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
defineEmits([...useDialogPluginComponent.emits]);
|
||||
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QDialog ref="dialogRef" @hide="onDialogHide">
|
||||
<InvoiceInSummary v-if="$props.id" :id="$props.id" />
|
||||
</QDialog>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.q-dialog .summary .header {
|
||||
position: sticky;
|
||||
z-index: $z-max;
|
||||
top: 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,500 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { toCurrency } from 'src/filters';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const quasar = useQuasar();
|
||||
|
||||
const arrayData = useArrayData('InvoiceIn');
|
||||
const invoiceIn = computed(() => arrayData.store.data);
|
||||
|
||||
const expenses = ref([]);
|
||||
const sageTaxTypes = ref([]);
|
||||
const sageTransactionTypes = ref([]);
|
||||
const rowsSelected = ref([]);
|
||||
const newExpense = ref({
|
||||
code: undefined,
|
||||
isWithheld: false,
|
||||
description: undefined,
|
||||
});
|
||||
|
||||
const invoiceInFormRef = ref();
|
||||
const expensesRef = ref();
|
||||
const newExpenseRef = ref();
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'expense',
|
||||
label: t('Expense'),
|
||||
field: (row) => row.expenseFk,
|
||||
options: expenses.value,
|
||||
model: 'expenseFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'id',
|
||||
sortable: true,
|
||||
tabIndex: 1,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'taxablebase',
|
||||
label: t('Taxable base'),
|
||||
field: (row) => toCurrency(row.taxableBase),
|
||||
model: 'taxableBase',
|
||||
sortable: true,
|
||||
tabIndex: 2,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'sageiva',
|
||||
label: t('Sage iva'),
|
||||
field: (row) => row.taxTypeSageFk,
|
||||
options: sageTaxTypes.value,
|
||||
model: 'taxTypeSageFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'vat',
|
||||
sortable: true,
|
||||
tabindex: 3,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'sagetransaction',
|
||||
label: t('Sage transaction'),
|
||||
field: (row) => row.transactionTypeSageFk,
|
||||
options: sageTransactionTypes.value,
|
||||
model: 'transactionTypeSageFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'transaction',
|
||||
sortable: true,
|
||||
tabIndex: 4,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'rate',
|
||||
label: t('Rate'),
|
||||
sortable: true,
|
||||
tabIndex: 5,
|
||||
field: (row) => taxRate(row, row.taxTypeSageFk),
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'foreignvalue',
|
||||
label: t('Foreign value'),
|
||||
sortable: true,
|
||||
tabIndex: 6,
|
||||
field: (row) => row.foreignValue,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
|
||||
const filter = {
|
||||
fields: [
|
||||
'id',
|
||||
'invoiceInFk',
|
||||
'taxableBase',
|
||||
'expenseFk',
|
||||
'foreignValue',
|
||||
'taxTypeSageFk',
|
||||
'transactionTypeSageFk',
|
||||
],
|
||||
where: {
|
||||
invoiceInFk: route.params.id,
|
||||
},
|
||||
};
|
||||
|
||||
const isNotEuro = (code) => code != 'EUR';
|
||||
|
||||
function taxRate(invoiceInTax, sageTaxTypeId) {
|
||||
jorgep marked this conversation as resolved
Outdated
jsegarra
commented
Lo revisamos Lo revisamos
|
||||
const taxRateSelection = sageTaxTypes.value.find(
|
||||
(transaction) => transaction.id == sageTaxTypeId
|
||||
);
|
||||
const taxTypeSage = taxRateSelection && taxRateSelection.rate;
|
||||
const taxableBase = invoiceInTax && invoiceInTax.taxableBase;
|
||||
if (taxTypeSage && taxableBase) {
|
||||
return toCurrency((taxTypeSage / 100) * taxableBase);
|
||||
}
|
||||
return toCurrency(0);
|
||||
}
|
||||
|
||||
async function addExpense() {
|
||||
try {
|
||||
if (!newExpense.value.code) throw new Error(t(`The code can't be empty`));
|
||||
if (isNaN(newExpense.value.code))
|
||||
throw new Error(t(`The code have to be a number`));
|
||||
if (!newExpense.value.description)
|
||||
throw new Error(t(`The description can't be empty`));
|
||||
|
||||
const data = [
|
||||
{
|
||||
id: newExpense.value.code,
|
||||
isWithheld: newExpense.value.isWithheld,
|
||||
name: newExpense.value.description,
|
||||
},
|
||||
];
|
||||
|
||||
await axios.post(`Expenses`, data);
|
||||
await expensesRef.value.fetch();
|
||||
quasar.notify({
|
||||
type: 'positive',
|
||||
message: t('globals.dataSaved'),
|
||||
});
|
||||
} catch (error) {
|
||||
quasar.notify({
|
||||
type: 'negative',
|
||||
message: t(`${error}`),
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
ref="expensesRef"
|
||||
url="Expenses"
|
||||
auto-load
|
||||
@on-fetch="(data) => (expenses = data)"
|
||||
/>
|
||||
<FetchData url="SageTaxTypes" auto-load @on-fetch="(data) => (sageTaxTypes = data)" />
|
||||
<FetchData
|
||||
url="sageTransactionTypes"
|
||||
auto-load
|
||||
@on-fetch="(data) => (sageTransactionTypes = data)"
|
||||
/>
|
||||
<CrudModel
|
||||
ref="invoiceInFormRef"
|
||||
v-if="invoiceIn"
|
||||
data-key="InvoiceInTaxes"
|
||||
url="InvoiceInTaxes"
|
||||
:filter="filter"
|
||||
:data-required="{ invoiceInFk: route.params.id }"
|
||||
auto-load
|
||||
v-model:selected="rowsSelected"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QTable
|
||||
v-model:selected="rowsSelected"
|
||||
selection="multiple"
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
row-key="$index"
|
||||
hide-pagination
|
||||
:grid="$q.screen.lt.sm"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
>
|
||||
<template #body-cell-expense="{ row, col }">
|
||||
<QTd auto-width>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'name']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItem>
|
||||
</template>
|
||||
<template #append>
|
||||
<QIcon
|
||||
name="close"
|
||||
@click.stop="value = null"
|
||||
class="cursor-pointer"
|
||||
/>
|
||||
<QBtn
|
||||
padding="xs"
|
||||
round
|
||||
flat
|
||||
icon="add_circle"
|
||||
@click.stop="newExpenseRef.show()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Create expense') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-taxablebase="{ row }">
|
||||
<QTd>
|
||||
<QInput
|
||||
:class="{
|
||||
'no-pointer-events': isNotEuro(invoiceIn.currency.code),
|
||||
}"
|
||||
:disable="isNotEuro(invoiceIn.currency.code)"
|
||||
label=""
|
||||
clear-icon="close"
|
||||
v-model="row.taxableBase"
|
||||
clearable
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="euro" size="xs" flat />
|
||||
</template>
|
||||
</QInput>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-sageiva="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'vat']"
|
||||
:autofocus="col.tabIndex == 1"
|
||||
input-debounce="0"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt.vat }}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-sagetransaction="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:filter-options="['id', 'transaction']"
|
||||
:autofocus="col.tabIndex == 1"
|
||||
input-debounce="0"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.transaction
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-foreignvalue="{ row }">
|
||||
<QTd>
|
||||
<QInput
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(invoiceIn.currency.code),
|
||||
}"
|
||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
||||
v-model="row.foreignValue"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard bordered flat class="q-my-xs">
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QList>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
:label="t('Expense')"
|
||||
class="full-width"
|
||||
v-model="props.row['expenseFk']"
|
||||
:options="expenses"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:filter-options="['id', 'name']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
:label="t('Taxable base')"
|
||||
:class="{
|
||||
'no-pointer-events': isNotEuro(
|
||||
invoiceIn.currency.code
|
||||
jorgep marked this conversation as resolved
jsegarra
commented
En InvoiceInDueDay, la condición estaba al revés, correcto? En InvoiceInDueDay, la condición estaba al revés, correcto?
|
||||
),
|
||||
}"
|
||||
class="full-width"
|
||||
:disable="isNotEuro(invoiceIn.currency.code)"
|
||||
clear-icon="close"
|
||||
v-model="props.row.taxableBase"
|
||||
clearable
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="euro" size="xs" flat />
|
||||
</template>
|
||||
</QInput>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
:label="t('Sage iva')"
|
||||
class="full-width"
|
||||
v-model="props.row['taxTypeSageFk']"
|
||||
:options="sageTaxTypes"
|
||||
option-value="id"
|
||||
option-label="vat"
|
||||
:filter-options="['id', 'vat']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.vat
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<VnSelectFilter
|
||||
class="full-width"
|
||||
v-model="props.row['transactionTypeSageFk']"
|
||||
:options="sageTransactionTypes"
|
||||
option-value="id"
|
||||
option-label="transaction"
|
||||
:filter-options="['id', 'transaction']"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
scope.opt.transaction
|
||||
}}</QItemLabel>
|
||||
<QItemLabel>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</QItem>
|
||||
<QItem>
|
||||
{{ taxRate(props.row, props.row.taxTypeSageFk) }}
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
:label="t('Foreign value')"
|
||||
class="full-width"
|
||||
:class="{
|
||||
'no-pointer-events': !isNotEuro(
|
||||
invoiceIn.currency.code
|
||||
),
|
||||
}"
|
||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
||||
v-model="props.row.foreignValue"
|
||||
/>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QDialog ref="newExpenseRef">
|
||||
<QCard>
|
||||
<QCardSection class="q-pb-none">
|
||||
<QItem class="q-pa-none">
|
||||
<span class="text-primary text-h6 full-width">
|
||||
<QIcon name="edit" class="q-mr-xs" />
|
||||
{{ t('New expense') }}
|
||||
</span>
|
||||
<QBtn icon="close" flat round dense v-close-popup />
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardSection class="q-pt-none">
|
||||
<QItem>
|
||||
<QInput :label="`${t('Code')}*`" v-model="newExpense.code" />
|
||||
<QCheckbox
|
||||
dense
|
||||
size="sm"
|
||||
:label="`${t('It\'s a withholding')}`"
|
||||
v-model="newExpense.isWithheld"
|
||||
/>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QInput
|
||||
:label="`${t('Descripction')}*`"
|
||||
v-model="newExpense.description"
|
||||
/>
|
||||
</QItem>
|
||||
</QCardSection>
|
||||
<QCardActions class="justify-end">
|
||||
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
||||
<QBtn :label="t('globals.save')" color="primary" @click="addExpense" />
|
||||
</QCardActions>
|
||||
</QCard>
|
||||
</QDialog>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="add"
|
||||
size="lg"
|
||||
round
|
||||
@click="invoiceInFormRef.insert()"
|
||||
/>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
@media (max-width: $breakpoint-xs) {
|
||||
.q-dialog {
|
||||
.q-card {
|
||||
&__section:not(:first-child) {
|
||||
.q-item {
|
||||
flex-direction: column;
|
||||
|
||||
.q-checkbox {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.q-item {
|
||||
min-height: 0;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
es:
|
||||
Expense: Gasto
|
||||
Create expense: Crear gasto
|
||||
Add tax: Crear gasto
|
||||
Taxable base: Base imp.
|
||||
Sage tax: Sage iva
|
||||
Sage transaction: Sage transacción
|
||||
Rate: Tasa
|
||||
Foreign value: Divisa
|
||||
New expense: Nuevo gasto
|
||||
Code: Código
|
||||
It's a withholding: Es una retención
|
||||
Descripction: Descripción
|
||||
The code can't be empty: El código no puede estar vacío
|
||||
The description can't be empty: La descripción no puede estar vacía
|
||||
The code have to be a number: El código debe ser un número.
|
||||
</i18n>
|
|
@ -0,0 +1,307 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
dataKey: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const suppliers = ref([]);
|
||||
const suppliersRef = ref();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="suppliersRef"
|
||||
url="Suppliers"
|
||||
:filter="{ fields: ['id', 'nickname'] }"
|
||||
order="nickname"
|
||||
limit="30"
|
||||
@on-fetch="(data) => (suppliers = data)"
|
||||
/>
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #body="{ params, searchFn }">
|
||||
<QList dense>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput :label="t('Id or Supplier')" v-model="params.search">
|
||||
<template #prepend>
|
||||
<QIcon name="badge" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('params.supplierRef')"
|
||||
v-model="params.supplierRef"
|
||||
@input.
|
||||
lazy-rules
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="vn:client" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.supplierFk')"
|
||||
v-model="params.supplierFk"
|
||||
:options="suppliers"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
@input-value="suppliersRef.fetch()"
|
||||
>
|
||||
</VnSelectFilter>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput :label="t('params.fi')" v-model="params.fi" lazy-rules>
|
||||
<template #prepend>
|
||||
<QIcon name="badge" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('params.serialNumber')"
|
||||
v-model="params.serialNumber"
|
||||
lazy-rules
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="badge" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('params.serial')"
|
||||
v-model="params.serial"
|
||||
lazy-rules
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="badge" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput :label="t('Amount')" v-model="params.amount" lazy-rules>
|
||||
<template #prepend>
|
||||
<QIcon name="euro" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-mb-md">
|
||||
<QItemSection>
|
||||
<QCheckbox
|
||||
:label="t('params.isBooked')"
|
||||
v-model="params.isBooked"
|
||||
@update:model-value="searchFn()"
|
||||
toggle-indeterminate
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QExpansionItem :label="t('More options')" expand-separator>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('params.awb')"
|
||||
v-model="params.awbCode"
|
||||
lazy-rules
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="badge" size="sm"></QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('params.account')"
|
||||
v-model="params.account"
|
||||
lazy-rules
|
||||
>
|
||||
<template #prepend>
|
||||
<QIcon name="person" size="sm" />
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput :label="t('From')" v-model="params.from" mask="date">
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate v-model="params.from" landscape>
|
||||
<div
|
||||
class="row items-center justify-end q-gutter-sm"
|
||||
>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.confirm')"
|
||||
color="primary"
|
||||
flat
|
||||
@click="save"
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput :label="t('To')" v-model="params.to" mask="date">
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate v-model="params.to" landscape>
|
||||
<div
|
||||
class="row items-center justify-end q-gutter-sm"
|
||||
>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.confirm')"
|
||||
color="primary"
|
||||
flat
|
||||
@click="save"
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<QInput
|
||||
:label="t('Issued')"
|
||||
v-model="params.issued"
|
||||
mask="date"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="event" class="cursor-pointer">
|
||||
<QPopupProxy
|
||||
cover
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<QDate v-model="params.issued" landscape>
|
||||
<div
|
||||
class="row items-center justify-end q-gutter-sm"
|
||||
>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
color="primary"
|
||||
flat
|
||||
v-close-popup
|
||||
/>
|
||||
<QBtn
|
||||
:label="t('globals.confirm')"
|
||||
color="primary"
|
||||
flat
|
||||
@click="save"
|
||||
v-close-popup
|
||||
/>
|
||||
</div>
|
||||
</QDate>
|
||||
</QPopupProxy>
|
||||
</QIcon>
|
||||
</template>
|
||||
</QInput>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QExpansionItem>
|
||||
</QList>
|
||||
</template>
|
||||
</VnFilterPanel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
params:
|
||||
search: ID
|
||||
supplierRef: Supplier ref.
|
||||
supplierFk: Supplier
|
||||
fi: Supplier fiscal id
|
||||
clientFk: Customer
|
||||
amount: Amount
|
||||
created: Created
|
||||
awb: AWB
|
||||
dued: Dued
|
||||
serialNumber: Serial Number
|
||||
serial: Serial
|
||||
account: Account
|
||||
isBooked: is booked
|
||||
es:
|
||||
params:
|
||||
search: Contiene
|
||||
supplierRef: Ref. proveedor
|
||||
supplierFk: Proveedor
|
||||
clientFk: Cliente
|
||||
fi: CIF proveedor
|
||||
serialNumber: Num. serie
|
||||
serial: Serie
|
||||
awb: AWB
|
||||
amount: Importe
|
||||
issued: Emitida
|
||||
isBooked: Conciliada
|
||||
account: Cuenta
|
||||
created: Creada
|
||||
dued: Vencida
|
||||
From: Desde
|
||||
To: Hasta
|
||||
Amount: Importe
|
||||
Issued: Fecha factura
|
||||
Id or supplier: Id o proveedor
|
||||
More options: Más opciones
|
||||
</i18n>
|
|
@ -0,0 +1,179 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, onUnmounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import { toDate, toCurrency } from 'src/filters/index';
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import CardList from 'src/components/ui/CardList.vue';
|
||||
import InvoiceInFilter from './InvoiceInFilter.vue';
|
||||
import InvoiceInSummaryDialog from './Card/InvoiceInSummaryDialog.vue';
|
||||
import { getUrl } from 'src/composables/getUrl';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
const router = useRouter();
|
||||
const quasar = useQuasar();
|
||||
let url = ref();
|
||||
const { t } = useI18n();
|
||||
|
||||
onMounted(async () => {
|
||||
stateStore.rightDrawer = true;
|
||||
url.value = await getUrl('');
|
||||
});
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
function navigate(id) {
|
||||
router.push({ path: `/invoice-in/${id}` });
|
||||
}
|
||||
|
||||
function viewSummary(id) {
|
||||
quasar.dialog({
|
||||
component: InvoiceInSummaryDialog,
|
||||
componentProps: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="stateStore.isHeaderMounted()">
|
||||
<Teleport to="#searchbar">
|
||||
<VnSearchbar
|
||||
data-key="InvoiceInList"
|
||||
:label="t('Search invoice')"
|
||||
:info="t('You can search by invoice reference')"
|
||||
/>
|
||||
</Teleport>
|
||||
<Teleport to="#actions-append">
|
||||
<div class="row q-gutter-x-sm">
|
||||
<QBtn
|
||||
flat
|
||||
@click="stateStore.toggleRightDrawer()"
|
||||
round
|
||||
dense
|
||||
icon="menu"
|
||||
>
|
||||
<QTooltip bottom anchor="bottom right">
|
||||
{{ t('globals.collapseMenu') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above>
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<InvoiceInFilter data-key="InvoiceInList" />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<div class="card-list">
|
||||
<VnPaginate
|
||||
data-key="InvoiceInList"
|
||||
url="InvoiceIns/filter"
|
||||
order="issued DESC, id DESC"
|
||||
auto-load
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<CardList
|
||||
v-for="row of rows"
|
||||
:key="row.id"
|
||||
:title="row.supplierRef"
|
||||
@click="navigate(row.id)"
|
||||
>
|
||||
<template #list-items>
|
||||
<VnLv label="ID" :value="row.id" />
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.supplierRef')"
|
||||
:value="row.supplierRef"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.supplier')"
|
||||
:value="row.supplierName"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.serialNumber')"
|
||||
:value="row.serialNumber"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.serial')"
|
||||
:value="row.serial"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.issued')"
|
||||
:value="toDate(row.issued)"
|
||||
/>
|
||||
<VnLv :label="t('invoiceIn.list.awb')" :value="row.awbCode" />
|
||||
<VnLv
|
||||
:label="t('invoiceIn.list.amount')"
|
||||
:value="toCurrency(row.amount)"
|
||||
/>
|
||||
<VnLv :label="t('invoiceIn.list.isBooked')">
|
||||
<template #value>
|
||||
<QCheckbox
|
||||
class="no-pointer-events"
|
||||
v-model="row.isBooked"
|
||||
size="xs"
|
||||
:true-value="1"
|
||||
:false-value="0"
|
||||
/>
|
||||
</template>
|
||||
</VnLv>
|
||||
</template>
|
||||
<template #actions>
|
||||
<QBtn
|
||||
flat
|
||||
icon="arrow_circle_right"
|
||||
@click.stop="navigate(row.id)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.openCard') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn flat icon="preview" @click.stop="viewSummary(row.id)">
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.openSummary') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
flat
|
||||
icon="cloud_download"
|
||||
@click.stop="downloadFile(row.dmsFk)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('components.smartCard.downloadFile') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
</CardList>
|
||||
</template>
|
||||
</VnPaginate>
|
||||
</div>
|
||||
</QPage>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn
|
||||
color="primary"
|
||||
icon="add"
|
||||
size="lg"
|
||||
round
|
||||
:href="`${url}invoice-in/create`"
|
||||
/>
|
||||
</QPageSticky>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.card-list {
|
||||
width: 100%;
|
||||
max-width: 60em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Search invoice: Buscar factura emitida
|
||||
You can search by invoice reference: Puedes buscar por referencia de la factura
|
||||
</i18n>
|
|
@ -0,0 +1,17 @@
|
|||
<script setup>
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import LeftMenu from 'src/components/LeftMenu.vue';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QDrawer v-model="stateStore.leftDrawer" show-if-above :width="256">
|
||||
<QScrollArea class="fit text-grey-8">
|
||||
<LeftMenu />
|
||||
</QScrollArea>
|
||||
</QDrawer>
|
||||
<QPageContainer>
|
||||
<RouterView></RouterView>
|
||||
</QPageContainer>
|
||||
</template>
|
|
@ -2,16 +2,9 @@ import Customer from './customer';
|
|||
import Ticket from './ticket';
|
||||
import Claim from './claim';
|
||||
import InvoiceOut from './invoiceOut';
|
||||
import invoiceIn from './invoiceIn';
|
||||
import Worker from './worker';
|
||||
import Wagon from './wagon';
|
||||
import Route from './route';
|
||||
|
||||
export default [
|
||||
Customer,
|
||||
Ticket,
|
||||
Claim,
|
||||
InvoiceOut,
|
||||
Worker,
|
||||
Wagon,
|
||||
Route
|
||||
]
|
||||
export default [Customer, Ticket, Claim, InvoiceOut, invoiceIn, Worker, Wagon, Route];
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import { RouterView } from 'vue-router';
|
||||
|
||||
export default {
|
||||
path: '/invoice-in',
|
||||
name: 'InvoiceIn',
|
||||
meta: {
|
||||
title: 'invoiceIns',
|
||||
icon: 'vn:invoice-in',
|
||||
},
|
||||
component: RouterView,
|
||||
redirect: { name: 'InvoiceInMain' },
|
||||
menus: {
|
||||
main: ['InvoiceInList'],
|
||||
card: [
|
||||
'InvoiceInBasicData',
|
||||
'InvoiceInVat',
|
||||
'InvoiceInDueDay',
|
||||
'InvoiceInIntrastat',
|
||||
],
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'InvoiceInMain',
|
||||
component: () => import('src/pages/InvoiceIn/InvoiceInMain.vue'),
|
||||
redirect: { name: 'InvoiceInList' },
|
||||
children: [
|
||||
{
|
||||
path: 'list',
|
||||
name: 'InvoiceInList',
|
||||
meta: {
|
||||
title: 'list',
|
||||
icon: 'view_list',
|
||||
},
|
||||
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'InvoiceInCard',
|
||||
path: ':id',
|
||||
component: () => import('src/pages/InvoiceIn/Card/InvoiceInCard.vue'),
|
||||
redirect: { name: 'InvoiceInSummary' },
|
||||
children: [
|
||||
{
|
||||
name: 'InvoiceInSummary',
|
||||
path: 'summary',
|
||||
meta: {
|
||||
title: 'summary',
|
||||
icon: 'view_list',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/InvoiceIn/Card/InvoiceInSummary.vue'),
|
||||
},
|
||||
{
|
||||
name: 'InvoiceInBasicData',
|
||||
path: 'basic-data',
|
||||
meta: {
|
||||
title: 'basicData',
|
||||
icon: 'vn:settings',
|
||||
roles: ['salesPerson'],
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/InvoiceIn/Card/InvoiceInBasicData.vue'),
|
||||
},
|
||||
{
|
||||
name: 'InvoiceInVat',
|
||||
path: 'vat',
|
||||
meta: {
|
||||
title: 'vat',
|
||||
icon: 'vn:tax',
|
||||
},
|
||||
component: () => import('src/pages/InvoiceIn/Card/InvoiceInVat.vue'),
|
||||
},
|
||||
{
|
||||
name: 'InvoiceInDueDay',
|
||||
path: 'due-day',
|
||||
meta: {
|
||||
title: 'dueDay',
|
||||
icon: 'vn:calendar',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/InvoiceIn/Card/InvoiceInDueDay.vue'),
|
||||
},
|
||||
{
|
||||
name: 'InvoiceInIntrastat',
|
||||
path: 'intrastat',
|
||||
meta: {
|
||||
title: 'intrastat',
|
||||
icon: 'vn:lines',
|
||||
},
|
||||
component: () =>
|
||||
import('src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
|
@ -3,6 +3,7 @@ import ticket from './modules/ticket';
|
|||
import claim from './modules/claim';
|
||||
import worker from './modules/worker';
|
||||
import invoiceOut from './modules/invoiceOut';
|
||||
import invoiceIn from './modules/invoiceIn';
|
||||
import wagon from './modules/wagon';
|
||||
import route from './modules/route';
|
||||
|
||||
|
@ -49,6 +50,7 @@ const routes = [
|
|||
claim,
|
||||
worker,
|
||||
invoiceOut,
|
||||
invoiceIn,
|
||||
{
|
||||
path: '/:catchAll(.*)*',
|
||||
name: 'NotFound',
|
||||
|
|
|
@ -6,7 +6,16 @@ import { useRole } from 'src/composables/useRole';
|
|||
import routes from 'src/router/modules';
|
||||
|
||||
export const useNavigationStore = defineStore('navigationStore', () => {
|
||||
const modules = ['customer', 'claim', 'ticket', 'invoiceOut', 'worker', 'wagon', 'route'];
|
||||
const modules = [
|
||||
'customer',
|
||||
'claim',
|
||||
'ticket',
|
||||
'invoiceOut',
|
||||
'invoiceIn',
|
||||
'worker',
|
||||
'wagon',
|
||||
'route',
|
||||
];
|
||||
const pinnedModules = ref([]);
|
||||
const role = useRole();
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('InvoiceInList', () => {
|
||||
const firstCard = '.q-card:nth-child(1)';
|
||||
const firstId =
|
||||
'.q-card:nth-child(1) .list-items > .vn-label-value:first-child > .value > span';
|
||||
const firstDetailBtn = '.q-card:nth-child(1) .q-btn:nth-child(2)';
|
||||
const summaryHeaders = '.summaryBody .header';
|
||||
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/invoice-in`);
|
||||
});
|
||||
|
||||
it('should redirect on clicking a invoice', () => {
|
||||
cy.get(firstId)
|
||||
.invoke('text')
|
||||
.then((id) => {
|
||||
cy.get(firstCard).click();
|
||||
cy.url().should('include', `/invoice-in/${id}/summary`);
|
||||
});
|
||||
});
|
||||
|
||||
it('should open the details', () => {
|
||||
cy.get(firstDetailBtn).click();
|
||||
cy.get(summaryHeaders).eq(1).contains('Basic Data');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
import { vi, describe, expect, it } from 'vitest';
|
||||
import { axios } from 'app/test/vitest/helper';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
import { useSession } from 'src/composables/useSession';
|
||||
|
||||
const session = useSession();
|
||||
const token = session.getToken();
|
||||
|
||||
describe('downloadFile', () => {
|
||||
it('should open a new window to download the file', async () => {
|
||||
const url = 'http://localhost:9000';
|
||||
|
||||
vi.spyOn(axios, 'get').mockResolvedValueOnce({ data: url });
|
||||
|
||||
const mockWindowOpen = vi.spyOn(window, 'open');
|
||||
|
||||
await downloadFile(1);
|
||||
|
||||
expect(mockWindowOpen).toHaveBeenCalledWith(
|
||||
`${url}/api/dms/1/downloadFile?access_token=${token}`
|
||||
);
|
||||
|
||||
mockWindowOpen.mockRestore();
|
||||
});
|
||||
});
|
confirma con @alexm que lilum en el código a piñón es correcto
Lo veo bien. Si se llega a repetir mucho, se podria llegar a hacer getUrlLilium o alho