588 lines
21 KiB
Vue
588 lines
21 KiB
Vue
<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 { downloadFile } from 'src/composables/downloadFile';
|
|
import FormModel from 'components/FormModel.vue';
|
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
import FetchData from 'src/components/FetchData.vue';
|
|
import VnRow from 'components/ui/VnRow.vue';
|
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
|
import VnInput from 'src/components/common/VnInput.vue';
|
|
|
|
const quasar = useQuasar();
|
|
const { t } = useI18n();
|
|
|
|
const dms = ref({});
|
|
const route = useRoute();
|
|
const editDownloadDisabled = ref(false);
|
|
const invoiceIn = computed(() => useArrayData(route.meta.moduleName).store.data);
|
|
const userConfig = ref(null);
|
|
const invoiceId = computed(() => +route.params.id);
|
|
|
|
const expenses = 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 sageWithholdings = 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 = {
|
|
warehouseId: data.warehouseFk,
|
|
companyId: data.companyFk,
|
|
dmsTypeId: data.dmsTypeFk,
|
|
...data,
|
|
};
|
|
|
|
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 upsert() {
|
|
try {
|
|
const isEdit = !!dms.value.id;
|
|
const errors = {
|
|
companyId: `The company can't be empty`,
|
|
warehouseId: `The warehouse can't be empty`,
|
|
dmsTypeId: `The DMS Type can't be empty`,
|
|
description: `The description can't be empty`,
|
|
};
|
|
|
|
Object.keys(errors).forEach((key) => {
|
|
if (!dms.value[key]) throw Error(t(errors[key]));
|
|
});
|
|
|
|
if (!isEdit && !dms.value.files) throw 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 url = isEdit ? `dms/${dms.value.id}/updateFile` : 'Dms/uploadFile';
|
|
const { data } = await axios.post(url, formData, {
|
|
params: dms.value,
|
|
});
|
|
|
|
if (data.length) invoiceIn.value.dmsFk = data[0].id;
|
|
|
|
if (!isEdit) {
|
|
createDmsRef.value.hide();
|
|
} else {
|
|
editDmsRef.value.hide();
|
|
}
|
|
|
|
quasar.notify({
|
|
message: t('globals.dataSaved'),
|
|
type: 'positive',
|
|
});
|
|
} catch (error) {
|
|
quasar.notify({
|
|
message: t(`${error.message}`),
|
|
type: 'negative',
|
|
});
|
|
}
|
|
}
|
|
</script>
|
|
<template>
|
|
<FetchData
|
|
ref="currenciesRef"
|
|
url="Currencies"
|
|
:filter="{ fields: ['id', 'code'] }"
|
|
sort-by="code"
|
|
@on-fetch="(data) => (currencies = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
ref="companiesRef"
|
|
url="Companies"
|
|
:filter="{ fields: ['id', 'code'] }"
|
|
sort-by="code"
|
|
@on-fetch="(data) => (companies = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
ref="dmsTypesRef"
|
|
url="DmsTypes"
|
|
:filter="{ fields: ['id', 'name'] }"
|
|
sort-by="name"
|
|
@on-fetch="(data) => (dmsTypes = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
ref="warehousesRef"
|
|
url="Warehouses"
|
|
:filter="{ fields: ['id', 'name'] }"
|
|
sort-by="name"
|
|
@on-fetch="(data) => (warehouses = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
ref="allowTypesRef"
|
|
url="DmsContainers/allowedContentTypes"
|
|
@on-fetch="(data) => (allowedContentTypes = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
url="UserConfigs/getUserConfig"
|
|
@on-fetch="(data) => (userConfig = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData url="Expenses" auto-load @on-fetch="(data) => (expenses = data)" />
|
|
<FetchData
|
|
url="SageWithholdings"
|
|
auto-load
|
|
@on-fetch="(data) => (sageWithholdings = data)"
|
|
/>
|
|
<FormModel
|
|
model="InvoiceIn"
|
|
:go-to="`/invoice-in/${invoiceId}/vat`"
|
|
auto-load
|
|
:url-update="`InvoiceIns/${invoiceId}/updateInvoiceIn`"
|
|
>
|
|
<template #form="{ data }">
|
|
<VnRow>
|
|
<VnSelect
|
|
:label="t('supplierFk')"
|
|
v-model="data.supplierFk"
|
|
option-value="id"
|
|
option-label="nickname"
|
|
url="Suppliers"
|
|
:fields="['id', 'nickname']"
|
|
sort-by="nickname"
|
|
:is-clearable="false"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>{{
|
|
`${scope.opt.id} - ${scope.opt.nickname}`
|
|
}}</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
<VnInput
|
|
clearable
|
|
clear-icon="close"
|
|
:label="t('Supplier ref')"
|
|
v-model="data.supplierRef"
|
|
/>
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnInputDate :label="t('Expedition date')" v-model="data.issued" />
|
|
<VnInputDate
|
|
:label="t('Operation date')"
|
|
v-model="data.operated"
|
|
autofocus
|
|
/>
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnSelect
|
|
:label="t('Undeductible VAT')"
|
|
v-model="data.deductibleExpenseFk"
|
|
:options="expenses"
|
|
option-value="id"
|
|
option-label="id"
|
|
:filter-options="['id', 'name']"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
<VnInput
|
|
: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>
|
|
</VnInput>
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnInputDate :label="t('Entry date')" v-model="data.bookEntried" />
|
|
<VnInputDate :label="t('Accounted date')" v-model="data.booked" />
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnSelect
|
|
:label="t('Currency')"
|
|
v-model="data.currencyFk"
|
|
:options="currencies"
|
|
option-value="id"
|
|
option-label="code"
|
|
/>
|
|
|
|
<VnSelect
|
|
v-if="companiesRef"
|
|
:label="t('Company')"
|
|
v-model="data.companyFk"
|
|
:options="companies"
|
|
option-value="id"
|
|
option-label="code"
|
|
/>
|
|
</VnRow>
|
|
<VnRow>
|
|
<VnSelect
|
|
:label="t('invoiceIn.summary.sage')"
|
|
v-model="data.withholdingSageFk"
|
|
:options="sageWithholdings"
|
|
option-value="id"
|
|
option-label="withholding"
|
|
/>
|
|
</VnRow>
|
|
</template>
|
|
</FormModel>
|
|
<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>
|
|
<VnInput
|
|
class="full-width q-pa-xs"
|
|
:label="t('Reference')"
|
|
v-model="dms.reference"
|
|
clearable
|
|
clear-icon="close"
|
|
/>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="t('Company')"
|
|
v-model="dms.companyId"
|
|
:options="companies"
|
|
option-value="id"
|
|
option-label="code"
|
|
:required="true"
|
|
/>
|
|
</QItem>
|
|
<QItem>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="t('Warehouse')"
|
|
v-model="dms.warehouseId"
|
|
:options="warehouses"
|
|
option-value="id"
|
|
option-label="name"
|
|
:required="true"
|
|
/>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="t('Type')"
|
|
v-model="dms.dmsTypeId"
|
|
:options="dmsTypes"
|
|
option-value="id"
|
|
option-label="name"
|
|
:required="true"
|
|
/>
|
|
</QItem>
|
|
<QItem>
|
|
<VnInput
|
|
:label="t('Description')"
|
|
v-model="dms.description"
|
|
:required="true"
|
|
type="textarea"
|
|
class="full-width q-pa-xs"
|
|
size="lg"
|
|
autogrow
|
|
clearable
|
|
clear-icon="close"
|
|
/>
|
|
</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('globals.selectFile') }}
|
|
</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="upsert" />
|
|
</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>
|
|
<VnInput
|
|
class="full-width q-pa-xs"
|
|
:label="t('Reference')"
|
|
v-model="dms.reference"
|
|
/>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="`${t('Company')}*`"
|
|
v-model="dms.companyId"
|
|
:options="companies"
|
|
option-value="id"
|
|
option-label="code"
|
|
:required="true"
|
|
/>
|
|
</QItem>
|
|
<QItem>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="`${t('Warehouse')}*`"
|
|
v-model="dms.warehouseId"
|
|
:options="warehouses"
|
|
option-value="id"
|
|
option-label="name"
|
|
:required="true"
|
|
/>
|
|
<VnSelect
|
|
class="full-width q-pa-xs"
|
|
:label="`${t('Type')}*`"
|
|
v-model="dms.dmsTypeId"
|
|
:options="dmsTypes"
|
|
option-value="id"
|
|
option-label="name"
|
|
:required="true"
|
|
/>
|
|
</QItem>
|
|
<QItem>
|
|
<VnInput
|
|
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('globals.selectFile') }}
|
|
</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="upsert" />
|
|
</QCardActions>
|
|
</QCard>
|
|
</QDialog>
|
|
</template>
|
|
<style lang="scss" scoped>
|
|
@media (max-width: $breakpoint-xs) {
|
|
.column {
|
|
.row:not(:last-child) {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
.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
|
|
File: Fichero
|
|
Create document: Crear documento
|
|
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>
|