431 lines
16 KiB
Vue
431 lines
16 KiB
Vue
<script setup>
|
|
import { ref, computed, watchEffect } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
|
import { usePrintService } from 'src/composables/usePrintService';
|
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
|
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
|
|
import { toCurrency, toDate } from 'src/filters/index';
|
|
import { QBtn } from 'quasar';
|
|
import axios from 'axios';
|
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
import InvoiceOutFilter from './InvoiceOutFilter.vue';
|
|
import VnRow from 'src/components/ui/VnRow.vue';
|
|
import VnRadio from 'src/components/common/VnRadio.vue';
|
|
import VnInput from 'src/components/common/VnInput.vue';
|
|
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
|
|
|
|
const { t } = useI18n();
|
|
const { viewSummary } = useSummaryDialog();
|
|
const tableRef = ref();
|
|
const invoiceOutSerialsOptions = ref([]);
|
|
const customerOptions = ref([]);
|
|
const selectedRows = ref([]);
|
|
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
|
const MODEL = 'InvoiceOuts';
|
|
const { openReport } = usePrintService();
|
|
const addressOptions = ref([]);
|
|
const selectedOption = ref('ticket');
|
|
async function fetchClientAddress(id) {
|
|
const { data } = await axios.get(
|
|
`Clients/${id}/addresses?filter[order]=isActive DESC`
|
|
);
|
|
addressOptions.value = data;
|
|
}
|
|
|
|
const exprBuilder = (_, value) => {
|
|
return {
|
|
or: [{ code: value }, { description: { like: `%${value}%` } }],
|
|
};
|
|
};
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
align: 'center',
|
|
name: 'id',
|
|
label: t('invoiceOutList.tableVisibleColumns.id'),
|
|
chip: { condition: () => true },
|
|
isId: true,
|
|
columnFilter: {
|
|
name: 'id',
|
|
},
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'ref',
|
|
label: t('globals.reference'),
|
|
isTitle: true,
|
|
component: 'select',
|
|
attrs: {
|
|
url: MODEL,
|
|
optionLabel: 'ref',
|
|
optionValue: 'ref',
|
|
},
|
|
columnField: { component: null },
|
|
columnFilter: {
|
|
inWhere: true,
|
|
},
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'issued',
|
|
label: t('invoiceOut.summary.issued'),
|
|
component: 'date',
|
|
format: (row) => toDate(row.issued),
|
|
columnField: { component: null },
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'clientFk',
|
|
label: t('globals.client'),
|
|
cardVisible: true,
|
|
component: 'select',
|
|
attrs: {
|
|
url: 'Clients',
|
|
fields: ['id', 'socialName'],
|
|
optionLabel: 'socialName',
|
|
optionValue: 'id',
|
|
},
|
|
columnField: {
|
|
component: null,
|
|
},
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'companyCode',
|
|
label: t('globals.company'),
|
|
cardVisible: true,
|
|
component: 'select',
|
|
attrs: { url: 'Companies', optionLabel: 'code', optionValue: 'id' },
|
|
columnField: { component: null },
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'amount',
|
|
label: t('globals.amount'),
|
|
cardVisible: true,
|
|
format: (row) => toCurrency(row.amount),
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'created',
|
|
label: t('globals.created'),
|
|
component: 'date',
|
|
columnField: { component: null },
|
|
format: (row) => toDate(row.created),
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'dued',
|
|
label: t('invoiceOut.summary.dued'),
|
|
component: 'date',
|
|
columnField: { component: null },
|
|
format: (row) => toDate(row.dued),
|
|
},
|
|
{
|
|
align: 'left',
|
|
name: 'customsAgentFk',
|
|
label: t('invoiceOutList.tableVisibleColumns.customsAgent'),
|
|
cardVisible: true,
|
|
format: (row, dashIfEmpty) => dashIfEmpty(row.customsAgentName),
|
|
},
|
|
{
|
|
align: 'right',
|
|
name: 'tableActions',
|
|
actions: [
|
|
{
|
|
title: t('components.smartCard.viewSummary'),
|
|
icon: 'preview',
|
|
isPrimary: true,
|
|
action: (row) => viewSummary(row.id, InvoiceOutSummary),
|
|
},
|
|
{
|
|
title: t('globals.downloadPdf'),
|
|
icon: 'cloud_download',
|
|
isPrimary: true,
|
|
action: (row) => openPdf(row.id),
|
|
},
|
|
],
|
|
},
|
|
]);
|
|
|
|
function openPdf(id) {
|
|
openReport(`${MODEL}/${id}/download`);
|
|
}
|
|
|
|
function downloadPdf() {
|
|
if (selectedRows.value.size === 0) return;
|
|
const selectedCardsArray = Array.from(selectedRows.value.values());
|
|
|
|
if (selectedRows.value.size === 1) {
|
|
const [invoiceOut] = selectedCardsArray;
|
|
openPdf(invoiceOut.id);
|
|
} else {
|
|
const invoiceOutIdsArray = selectedCardsArray.map((invoiceOut) => invoiceOut.id);
|
|
const invoiceOutIds = invoiceOutIdsArray.join(',');
|
|
|
|
const params = {
|
|
ids: invoiceOutIds,
|
|
};
|
|
|
|
openReport(`${MODEL}/downloadZip`, params);
|
|
}
|
|
}
|
|
|
|
watchEffect(selectedRows);
|
|
</script>
|
|
|
|
<template>
|
|
<VnSearchbar
|
|
:info="t('youCanSearchByInvoiceReference')"
|
|
:label="t('Search invoice')"
|
|
data-key="invoiceOutList"
|
|
/>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<InvoiceOutFilter data-key="invoiceOutList" />
|
|
</template>
|
|
</RightMenu>
|
|
<VnSubToolbar>
|
|
<template #st-actions>
|
|
<QBtn
|
|
color="primary"
|
|
icon-right="cloud_download"
|
|
@click="downloadPdf()"
|
|
:disable="!hasSelectedCards"
|
|
data-cy="InvoiceOutDownloadPdfBtn"
|
|
>
|
|
<QTooltip>{{ t('downloadPdf') }}</QTooltip>
|
|
</QBtn>
|
|
</template>
|
|
</VnSubToolbar>
|
|
<VnTable
|
|
ref="tableRef"
|
|
data-key="invoiceOutList"
|
|
:url="`${MODEL}/filter`"
|
|
:create="{
|
|
urlCreate: 'InvoiceOuts/createManualInvoice',
|
|
title: t('createManualInvoice'),
|
|
onDataSaved: ({ id }) => tableRef.redirect(id),
|
|
formInitialData: { active: true },
|
|
}"
|
|
:right-search="false"
|
|
v-model:selected="selectedRows"
|
|
order="id DESC"
|
|
:columns="columns"
|
|
redirect="invoice-out"
|
|
:table="{
|
|
'row-key': 'id',
|
|
selection: 'multiple',
|
|
}"
|
|
>
|
|
<template #column-clientFk="{ row }">
|
|
<span class="link" @click.stop>
|
|
{{ row.clientSocialName }}
|
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
|
</span>
|
|
</template>
|
|
<template #more-create-dialog="{ data }">
|
|
<div class="row q-col-gutter-xs">
|
|
<div class="col-12">
|
|
<div class="q-col-gutter-xs">
|
|
<VnRow fixed>
|
|
<VnRadio
|
|
v-model="selectedOption"
|
|
val="ticket"
|
|
:label="t('globals.ticket')"
|
|
class="q-my-none q-mr-md"
|
|
/>
|
|
|
|
<VnInput
|
|
v-show="selectedOption === 'ticket'"
|
|
v-model="data.ticketFk"
|
|
:label="t('globals.ticket')"
|
|
style="flex: 1"
|
|
data-cy="InvoiceOutCreateTicketinput"
|
|
/>
|
|
|
|
<div
|
|
class="row q-col-gutter-xs q-ml-none"
|
|
v-show="selectedOption !== 'ticket'"
|
|
>
|
|
<div class="col">
|
|
<VnSelect
|
|
v-model="data.clientFk"
|
|
:label="t('globals.client')"
|
|
url="Clients"
|
|
:options="customerOptions"
|
|
option-label="name"
|
|
option-value="id"
|
|
@update:model-value="fetchClientAddress"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
#{{ scope.opt?.id }} -
|
|
{{ scope.opt?.name }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</div>
|
|
<div class="col">
|
|
<VnSelect
|
|
v-model="data.addressFk"
|
|
:label="t('ticket.summary.consignee')"
|
|
:options="addressOptions"
|
|
option-label="nickname"
|
|
option-value="id"
|
|
v-if="
|
|
data.clientFk &&
|
|
selectedOption === 'consignatario'
|
|
"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel
|
|
:class="{
|
|
'color-vn-label':
|
|
!scope.opt?.isActive,
|
|
}"
|
|
>
|
|
{{
|
|
`${
|
|
!scope.opt?.isActive
|
|
? t('inactive')
|
|
: ''
|
|
} `
|
|
}}
|
|
<span>{{
|
|
scope.opt?.nickname
|
|
}}</span>
|
|
<span
|
|
v-if="
|
|
scope.opt?.province ||
|
|
scope.opt?.city ||
|
|
scope.opt?.street
|
|
"
|
|
>
|
|
, {{ scope.opt?.street }},
|
|
{{ scope.opt?.city }},
|
|
{{
|
|
scope.opt?.province?.name
|
|
}}
|
|
-
|
|
{{
|
|
scope.opt?.agencyMode
|
|
?.name
|
|
}}
|
|
</span>
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
</div>
|
|
</div>
|
|
</VnRow>
|
|
<VnRow fixed>
|
|
<VnRadio
|
|
v-model="selectedOption"
|
|
val="cliente"
|
|
:label="t('globals.client')"
|
|
class="q-my-none q-mr-md"
|
|
/>
|
|
</VnRow>
|
|
<VnRow fixed>
|
|
<VnRadio
|
|
v-model="selectedOption"
|
|
val="consignatario"
|
|
:label="t('ticket.summary.consignee')"
|
|
class="q-my-none q-mr-md"
|
|
/>
|
|
</VnRow>
|
|
</div>
|
|
</div>
|
|
<div class="full-width">
|
|
<VnRow class="row q-col-gutter-xs">
|
|
<VnSelect
|
|
url="InvoiceOutSerials"
|
|
v-model="data.serial"
|
|
:label="t('invoicein.serial')"
|
|
:options="invoiceOutSerialsOptions"
|
|
option-label="description"
|
|
option-value="code"
|
|
option-filter
|
|
:expr-builder="exprBuilder"
|
|
data-cy="InvoiceOutCreateSerialSelect"
|
|
>
|
|
<template #option="scope">
|
|
<QItem v-bind="scope.itemProps">
|
|
<QItemSection>
|
|
<QItemLabel>
|
|
{{ scope.opt?.code }} -
|
|
{{ scope.opt?.description }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</template>
|
|
</VnSelect>
|
|
<VnInputDate
|
|
:label="t('invoiceOut.summary.dued')"
|
|
v-model="data.maxShipped"
|
|
/>
|
|
</VnRow>
|
|
<VnRow class="row q-col-gutter-xs">
|
|
<VnSelect
|
|
url="TaxAreas"
|
|
v-model="data.taxArea"
|
|
:label="t('invoiceOutList.tableVisibleColumns.taxArea')"
|
|
:options="taxAreasOptions"
|
|
option-label="code"
|
|
option-value="code"
|
|
/>
|
|
<VnInput
|
|
v-model="data.reference"
|
|
:label="t('globals.reference')"
|
|
/>
|
|
</VnRow>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</VnTable>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
#formModel .vn-row {
|
|
min-height: 45px;
|
|
|
|
.q-radio {
|
|
align-self: flex-end;
|
|
flex: 0.3;
|
|
}
|
|
|
|
> .q-input,
|
|
> .q-select {
|
|
flex: 0.75;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
en:
|
|
invoiceId: Invoice ID
|
|
youCanSearchByInvoiceReference: You can search by invoice reference
|
|
createManualInvoice: Create Manual Invoice
|
|
inactive: (Inactive)
|
|
|
|
es:
|
|
invoiceId: ID de factura
|
|
youCanSearchByInvoiceReference: Puedes buscar por referencia de la factura
|
|
createManualInvoice: Crear factura manual
|
|
inactive: (Inactivo)
|
|
</i18n>
|