387 lines
12 KiB
Vue
387 lines
12 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { QBtn, QCheckbox, useQuasar } from 'quasar';
|
|
import { toCurrency, toDate, dateRange } from 'filters/index';
|
|
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
|
import CustomerNotificationsFilter from './CustomerDefaulterFilter.vue';
|
|
import CustomerBalanceDueTotal from './CustomerBalanceDueTotal.vue';
|
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
import VnInput from 'src/components/common/VnInput.vue';
|
|
import CustomerDefaulterAddObservation from './CustomerDefaulterAddObservation.vue';
|
|
import axios from 'axios';
|
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
|
|
const { t } = useI18n();
|
|
const quasar = useQuasar();
|
|
const dataRef = ref(null);
|
|
|
|
const balanceDueTotal = ref(0);
|
|
const selected = ref([]);
|
|
|
|
const tableColumnComponents = {
|
|
clientFk: {
|
|
component: QBtn,
|
|
props: () => ({ flat: true, class: 'link', noCaps: true }),
|
|
event: () => {},
|
|
},
|
|
isWorker: {
|
|
component: QCheckbox,
|
|
props: (prop) => ({
|
|
disable: true,
|
|
'model-value': Boolean(prop.value),
|
|
}),
|
|
event: () => {},
|
|
},
|
|
salesPerson: {
|
|
component: QBtn,
|
|
props: () => ({ flat: true, class: 'link', noCaps: true }),
|
|
event: () => {},
|
|
},
|
|
departmentName: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
country: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
payMethod: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
balance: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
author: {
|
|
component: QBtn,
|
|
props: () => ({ flat: true, class: 'link', noCaps: true }),
|
|
event: () => {},
|
|
},
|
|
lastObservation: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
date: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
credit: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
from: {
|
|
component: 'span',
|
|
props: () => {},
|
|
event: () => {},
|
|
},
|
|
finished: {
|
|
component: QCheckbox,
|
|
|
|
props: (prop) => ({
|
|
disable: true,
|
|
'model-value': prop.value,
|
|
}),
|
|
event: () => {},
|
|
},
|
|
};
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
align: 'left',
|
|
field: 'clientName',
|
|
label: t('Client'),
|
|
name: 'clientFk',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: ({ isWorker }) => Boolean(isWorker),
|
|
label: t('Is worker'),
|
|
name: 'isWorker',
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'salesPersonName',
|
|
label: t('Salesperson'),
|
|
name: 'salesPerson',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'departmentName',
|
|
label: t('Department'),
|
|
name: 'departmentName',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'country',
|
|
label: t('Country'),
|
|
name: 'country',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'payMethod',
|
|
label: t('P. Method'),
|
|
name: 'payMethod',
|
|
sortable: true,
|
|
tooltip: t('Pay method'),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: ({ amount }) => toCurrency(amount),
|
|
label: t('Balance D.'),
|
|
name: 'balance',
|
|
sortable: true,
|
|
tooltip: t('Balance due'),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'workerName',
|
|
label: t('Author'),
|
|
name: 'author',
|
|
sortable: true,
|
|
tooltip: t('Worker who made the last observation'),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'observation',
|
|
label: t('Last observation'),
|
|
name: 'lastObservation',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: ({ created }) => toDate(created),
|
|
label: t('L. O. Date'),
|
|
name: 'date',
|
|
sortable: true,
|
|
tooltip: t('Last observation date'),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: ({ creditInsurance }) => toCurrency(creditInsurance),
|
|
label: t('Credit I.'),
|
|
name: 'credit',
|
|
sortable: true,
|
|
tooltip: t('Credit insurance'),
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: ({ defaulterSinced }) => toDate(defaulterSinced),
|
|
label: t('From'),
|
|
name: 'from',
|
|
sortable: true,
|
|
},
|
|
{
|
|
align: 'left',
|
|
field: 'finished',
|
|
label: t('Has recover'),
|
|
name: 'finished',
|
|
},
|
|
]);
|
|
|
|
const viewAddObservation = (rowsSelected) => {
|
|
quasar.dialog({
|
|
component: CustomerDefaulterAddObservation,
|
|
componentProps: {
|
|
clients: rowsSelected,
|
|
promise: async () => await dataRef.value.fetch(),
|
|
},
|
|
});
|
|
};
|
|
|
|
const onFetch = async (data) => {
|
|
const recoveryData = await axios.get('Recoveries');
|
|
const recoveries = recoveryData.data.map(({ clientFk, finished }) => ({
|
|
clientFk,
|
|
finished,
|
|
}));
|
|
|
|
data.forEach((item) => {
|
|
const recovery = recoveries.find(({ clientFk }) => clientFk === item.clientFk);
|
|
item.finished = recovery?.finished === null;
|
|
});
|
|
balanceDueTotal.value = data.reduce((acc, { amount = 0 }) => acc + amount, 0);
|
|
};
|
|
|
|
function exprBuilder(param, value) {
|
|
switch (param) {
|
|
case 'clientFk':
|
|
return { [`d.${param}`]: value };
|
|
case 'creditInsurance':
|
|
case 'amount':
|
|
case 'workerFk':
|
|
case 'departmentFk':
|
|
case 'countryFk':
|
|
case 'payMethod':
|
|
case 'salesPersonFk':
|
|
return { [`d.${param}`]: value };
|
|
case 'date':
|
|
return { 'd.created': { between: dateRange(value) } };
|
|
case 'defaulterSinced':
|
|
return { 'd.defaulterSinced': { between: dateRange(value) } };
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<RightMenu>
|
|
<template #right-panel>
|
|
<CustomerNotificationsFilter data-key="CustomerDefaulter" />
|
|
</template>
|
|
</RightMenu>
|
|
<VnSubToolbar>
|
|
<template #st-data>
|
|
<CustomerBalanceDueTotal :amount="balanceDueTotal" />
|
|
<div class="flex items-center q-ml-lg">
|
|
<QBtn
|
|
color="primary"
|
|
icon="vn:notes"
|
|
:disabled="!selected.length"
|
|
@click.stop="viewAddObservation(selected)"
|
|
>
|
|
<QTooltip>{{ t('Add observation') }}</QTooltip>
|
|
</QBtn>
|
|
</div>
|
|
</template>
|
|
</VnSubToolbar>
|
|
<QPage class="column items-center q-pa-md">
|
|
<VnPaginate
|
|
ref="dataRef"
|
|
@on-fetch="onFetch"
|
|
data-key="CustomerDefaulter"
|
|
:filter="filter"
|
|
:expr-builder="exprBuilder"
|
|
auto-load
|
|
url="Defaulters/filter"
|
|
>
|
|
<template #body="{ rows }">
|
|
<div class="q-pa-md">
|
|
<QTable
|
|
:columns="columns"
|
|
:rows="rows"
|
|
class="full-width"
|
|
row-key="clientFk"
|
|
selection="multiple"
|
|
v-model:selected="selected"
|
|
>
|
|
<template #header="props">
|
|
<QTr :props="props" class="bg" style="min-height: 200px">
|
|
<QTh>
|
|
<QCheckbox v-model="props.selected" />
|
|
</QTh>
|
|
<QTh
|
|
v-for="col in props.cols"
|
|
:key="col.name"
|
|
:props="props"
|
|
>
|
|
{{ t(col.label) }}
|
|
<QTooltip v-if="col.tooltip">{{
|
|
col.tooltip
|
|
}}</QTooltip>
|
|
</QTh>
|
|
</QTr>
|
|
</template>
|
|
|
|
<template #body-cell="props">
|
|
<QTd :props="props">
|
|
<QTr :props="props" class="cursor-pointer">
|
|
<component
|
|
:is="
|
|
tableColumnComponents[props.col.name]
|
|
.component
|
|
"
|
|
class="col-content"
|
|
v-bind="
|
|
tableColumnComponents[props.col.name].props(
|
|
props
|
|
)
|
|
"
|
|
@click="
|
|
tableColumnComponents[props.col.name].event(
|
|
props
|
|
)
|
|
"
|
|
>
|
|
<template v-if="typeof props.value !== 'boolean'">
|
|
<div
|
|
v-if="
|
|
props.col.name === 'lastObservation'
|
|
"
|
|
>
|
|
<VnInput
|
|
type="textarea"
|
|
v-model="props.value"
|
|
readonly
|
|
dense
|
|
rows="2"
|
|
/>
|
|
</div>
|
|
<div v-else>{{ props.value }}</div>
|
|
</template>
|
|
|
|
<WorkerDescriptorProxy
|
|
:id="props.row.salesPersonFk"
|
|
v-if="props.col.name === 'salesPerson'"
|
|
/>
|
|
<WorkerDescriptorProxy
|
|
:id="props.row.workerFk"
|
|
v-if="props.col.name === 'author'"
|
|
/>
|
|
<CustomerDescriptorProxy
|
|
:id="props.row.clientFk"
|
|
v-if="props.col.name === 'client'"
|
|
/>
|
|
</component>
|
|
</QTr>
|
|
</QTd>
|
|
</template>
|
|
</QTable>
|
|
</div>
|
|
</template>
|
|
</VnPaginate>
|
|
</QPage>
|
|
</template>
|
|
|
|
<style lang="scss" scoped>
|
|
.col-content {
|
|
border-radius: 4px;
|
|
padding: 6px;
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
es:
|
|
Add observation: Añadir observación
|
|
Client: Cliente
|
|
Is worker: Es trabajador
|
|
Salesperson: Comercial
|
|
Department: Departamento
|
|
Country: País
|
|
P. Method: F. Pago
|
|
Pay method: Forma de pago
|
|
Balance D.: Saldo V.
|
|
Balance due: Saldo vencido
|
|
Author: Autor
|
|
Worker who made the last observation: Trabajador que ha realizado la última observación
|
|
Last observation: Última observación
|
|
L. O. Date: Fecha Ú. O.
|
|
Last observation date: Fecha última observación
|
|
Credit I.: Crédito A.
|
|
Credit insurance: Crédito asegurado
|
|
From: Desde
|
|
</i18n>
|