forked from verdnatura/salix-front
508 lines
17 KiB
Vue
508 lines
17 KiB
Vue
<script setup>
|
|
import { ref, computed, onMounted } from 'vue';
|
|
import { useQuasar } from 'quasar';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
import axios from 'axios';
|
|
import { useStateStore } from 'src/stores/useStateStore';
|
|
import { toDate, toPercentage, toCurrency } from 'filters/index';
|
|
import { tMobile } from 'src/composables/tMobile';
|
|
import CrudModel from 'src/components/CrudModel.vue';
|
|
import FetchData from 'src/components/FetchData.vue';
|
|
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
|
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
|
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
|
import { useArrayData } from 'composables/useArrayData';
|
|
|
|
const { t } = useI18n();
|
|
const quasar = useQuasar();
|
|
const route = useRoute();
|
|
const router = useRouter();
|
|
const stateStore = computed(() => useStateStore());
|
|
const claim = ref(null);
|
|
const claimRef = ref();
|
|
const claimId = route.params.id;
|
|
const dialogDestination = ref(false);
|
|
const claimDestinationFk = ref(null);
|
|
const resolvedStateId = ref(null);
|
|
const claimActionsForm = ref();
|
|
const rows = ref([]);
|
|
const selectedRows = ref([]);
|
|
const destinationTypes = ref([]);
|
|
const totalClaimed = ref(null);
|
|
const DEFAULT_MAX_RESPONSABILITY = 5;
|
|
const DEFAULT_MIN_RESPONSABILITY = 1;
|
|
const arrayData = useArrayData('claimData');
|
|
const marker_labels = [
|
|
{ value: DEFAULT_MIN_RESPONSABILITY, label: t('claim.summary.company') },
|
|
{ value: DEFAULT_MAX_RESPONSABILITY, label: t('claim.summary.person') },
|
|
];
|
|
const multiplicatorValue = ref();
|
|
|
|
const columns = computed(() => [
|
|
{
|
|
name: 'Id',
|
|
label: t('Id item'),
|
|
field: (row) => row.itemFk,
|
|
},
|
|
{
|
|
name: 'ticket',
|
|
label: t('Ticket'),
|
|
field: (row) => row.ticketFk,
|
|
align: 'center',
|
|
},
|
|
{
|
|
name: 'destination',
|
|
label: t('Destination'),
|
|
field: (row) => row.claimDestinationFk,
|
|
align: 'left',
|
|
},
|
|
{
|
|
name: 'Landed',
|
|
label: t('Landed'),
|
|
field: (row) => toDate(row.landed),
|
|
},
|
|
{
|
|
name: 'quantity',
|
|
label: t('Quantity'),
|
|
field: (row) => row.quantity,
|
|
},
|
|
{
|
|
name: 'concept',
|
|
label: t('Description'),
|
|
field: (row) => row.concept,
|
|
align: 'left',
|
|
},
|
|
{
|
|
name: 'price',
|
|
label: t('Price'),
|
|
field: (row) => row.price,
|
|
format: (value) => value,
|
|
align: 'center',
|
|
},
|
|
{
|
|
name: 'discount',
|
|
label: t('Discount'),
|
|
field: (row) => row.discount,
|
|
format: (value) => toPercentage(value / 100),
|
|
align: 'left',
|
|
},
|
|
{
|
|
name: 'total',
|
|
label: t('Total'),
|
|
field: (row) => row.total,
|
|
format: (value) => value,
|
|
align: 'center',
|
|
},
|
|
{
|
|
name: 'delete',
|
|
},
|
|
]);
|
|
|
|
onMounted(() => {
|
|
getTotal();
|
|
});
|
|
|
|
function setData(data) {
|
|
rows.value = data;
|
|
getTotal();
|
|
}
|
|
function getTotal() {
|
|
if (rows.value.length) {
|
|
totalClaimed.value = rows.value.reduce((total, row) => total + row.total, 0);
|
|
}
|
|
}
|
|
|
|
async function updateDestinations(claimDestinationFk) {
|
|
await updateDestination(claimDestinationFk, selectedRows.value, { reload: true });
|
|
}
|
|
|
|
async function updateDestination(claimDestinationFk, row, options = {}) {
|
|
if (claimDestinationFk) {
|
|
await axios.post('Claims/updateClaimDestination', {
|
|
claimDestinationFk,
|
|
rows: Array.isArray(row) ? row : [row],
|
|
});
|
|
options.reload && claimActionsForm.value.reload();
|
|
}
|
|
}
|
|
|
|
async function regularizeClaim() {
|
|
await axios.post(`Claims/${claimId}/regularizeClaim`);
|
|
await claimRef.value.fetch();
|
|
await arrayData.fetch({ append: false });
|
|
quasar.notify({
|
|
message: t('globals.dataSaved'),
|
|
type: 'positive',
|
|
});
|
|
if (multiplicatorValue.value) await onUpdateGreugeAccept();
|
|
}
|
|
|
|
async function onUpdateGreugeAccept() {
|
|
const greugeTypeFreightId = (
|
|
await axios.get(`GreugeTypes/findOne`, {
|
|
filter: { where: { code: 'freightPickUp' } },
|
|
})
|
|
).data.id;
|
|
const freightPickUpPrice =
|
|
(await axios.get(`GreugeConfigs/findOne`)).data.freightPickUpPrice *
|
|
multiplicatorValue.value;
|
|
await axios.post(`Greuges`, {
|
|
clientFk: claim.value.clientFk,
|
|
description: `${t('ClaimGreugeDescription')} ${claimId}`.toUpperCase(),
|
|
amount: freightPickUpPrice,
|
|
greugeTypeFk: greugeTypeFreightId,
|
|
ticketFk: claim.value.ticketFk,
|
|
});
|
|
quasar.notify({
|
|
message: t('globals.dataSaved'),
|
|
type: 'positive',
|
|
});
|
|
}
|
|
|
|
async function save(data) {
|
|
const query = `Claims/${claimId}/updateClaimAction`;
|
|
await axios.patch(query, data);
|
|
}
|
|
|
|
async function importToNewRefundTicket() {
|
|
const query = `ClaimBeginnings/${claimId}/importToNewRefundTicket`;
|
|
await axios.post(query);
|
|
claimActionsForm.value.reload();
|
|
quasar.notify({
|
|
message: t('globals.dataSaved'),
|
|
type: 'positive',
|
|
});
|
|
}
|
|
</script>
|
|
<template>
|
|
<FetchData
|
|
ref="claimRef"
|
|
:url="`Claims/${claimId}`"
|
|
@on-fetch="(data) => (claim = data)"
|
|
auto-load
|
|
/>
|
|
<FetchData
|
|
url="ClaimStates/findOne"
|
|
@on-fetch="(data) => (resolvedStateId = data.id)"
|
|
auto-load
|
|
:where="{ code: 'resolved' }"
|
|
/>
|
|
<FetchData
|
|
url="ClaimDestinations"
|
|
auto-load
|
|
@on-fetch="(data) => (destinationTypes = data)"
|
|
/>
|
|
<template v-if="stateStore.isHeaderMounted()">
|
|
<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="300"
|
|
show-if-above
|
|
v-if="claim"
|
|
>
|
|
<QCard class="totalClaim q-my-md q-pa-sm no-box-shadow">
|
|
{{ `${t('Total claimed')}: ${toCurrency(totalClaimed)}` }}
|
|
</QCard>
|
|
<QCard class="q-mb-md q-pa-sm no-box-shadow">
|
|
<QItem class="justify-between">
|
|
<QItemLabel class="slider-container">
|
|
<p class="text-primary">
|
|
{{ t('claim.summary.actions') }}
|
|
</p>
|
|
<QSlider
|
|
class="responsibility { 'background-color:primary': quasar.platform.is.mobile }"
|
|
v-model="claim.responsibility"
|
|
:label-value="t('claim.summary.responsibility')"
|
|
@change="(value) => save({ responsibility: value })"
|
|
label-always
|
|
color="primary"
|
|
markers
|
|
:marker-labels="marker_labels"
|
|
:min="DEFAULT_MIN_RESPONSABILITY"
|
|
:max="DEFAULT_MAX_RESPONSABILITY"
|
|
/>
|
|
</QItemLabel>
|
|
</QItem>
|
|
</QCard>
|
|
<QCard class="q-mb-md q-pa-sm no-box-shadow" style="margin-bottom: 1em">
|
|
<QItemLabel class="mana q-mb-md">
|
|
<QCheckbox
|
|
v-model="claim.isChargedToMana"
|
|
@update:model-value="(value) => save({ isChargedToMana: value })"
|
|
/>
|
|
<span>{{ t('mana') }}</span>
|
|
</QItemLabel>
|
|
</QCard>
|
|
<QCard class="q-mb-md q-pa-sm no-box-shadow" style="position: static">
|
|
<QInput
|
|
:disable="
|
|
!(claim.responsibility >= Math.ceil(DEFAULT_MAX_RESPONSABILITY) / 2)
|
|
"
|
|
:label="t('confirmGreuges')"
|
|
class="q-field__native text-grey-2"
|
|
type="number"
|
|
placeholder="0"
|
|
id="multiplicatorValue"
|
|
name="multiplicatorValue"
|
|
min="0"
|
|
max="50"
|
|
v-model="multiplicatorValue"
|
|
/>
|
|
</QCard>
|
|
</QDrawer>
|
|
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown()"> </Teleport>
|
|
<CrudModel
|
|
v-if="claim"
|
|
data-key="ClaimEnds"
|
|
url="ClaimEnds/filter"
|
|
save-url="ClaimEnds/crud"
|
|
ref="claimActionsForm"
|
|
v-model:selected="selectedRows"
|
|
:filter="{ where: { claimFk: claimId } }"
|
|
:default-remove="true"
|
|
:default-save="false"
|
|
:default-reset="false"
|
|
@on-fetch="setData"
|
|
auto-load
|
|
>
|
|
<template #body>
|
|
<QTable
|
|
:columns="columns"
|
|
:rows="rows"
|
|
:dense="$q.screen.lt.md"
|
|
row-key="id"
|
|
selection="multiple"
|
|
v-model:selected="selectedRows"
|
|
:grid="$q.screen.lt.md"
|
|
:pagination="{ rowsPerPage: 0 }"
|
|
:hide-bottom="true"
|
|
>
|
|
<template #body-cell-ticket="{ value }">
|
|
<QTd align="center">
|
|
<span class="link">
|
|
{{ value }}
|
|
<TicketDescriptorProxy :id="value" />
|
|
</span>
|
|
</QTd>
|
|
</template>
|
|
<template #body-cell-destination="{ row }">
|
|
<QTd>
|
|
<VnSelectFilter
|
|
v-model="row.claimDestinationFk"
|
|
:options="destinationTypes"
|
|
option-label="description"
|
|
option-value="id"
|
|
:autofocus="true"
|
|
dense
|
|
input-debounce="0"
|
|
hide-selected
|
|
@update:model-value="(value) => updateDestination(value, row)"
|
|
/>
|
|
</QTd>
|
|
</template>
|
|
<template #body-cell-price="{ value }">
|
|
<QTd align="center">
|
|
{{ toCurrency(value) }}
|
|
</QTd>
|
|
</template>
|
|
<template #body-cell-total="{ value }">
|
|
<QTd align="center">
|
|
{{ toCurrency(value) }}
|
|
</QTd>
|
|
</template>
|
|
<!-- View for grid mode -->
|
|
<template #item="props">
|
|
<div class="q-mb-md col-12 grid-style-transition">
|
|
<QCard>
|
|
<QCardSection class="row justify-between">
|
|
<QCheckbox v-model="props.selected" />
|
|
<QBtn color="primary" icon="delete" flat round />
|
|
</QCardSection>
|
|
|
|
<QSeparator inset />
|
|
<QList dense>
|
|
<QItem v-for="column of props.cols" :key="column.name">
|
|
<QItemSection>
|
|
<QItemLabel caption>
|
|
{{ column.label }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
<QItemSection side>
|
|
<QItemLabel v-if="column.name === 'destination'">
|
|
<VnSelectFilter
|
|
v-model="props.row.claimDestinationFk"
|
|
:options="destinationTypes"
|
|
option-label="description"
|
|
option-value="id"
|
|
:autofocus="true"
|
|
dense
|
|
input-debounce="0"
|
|
hide-selected
|
|
@update:model-value="
|
|
(value) =>
|
|
updateDestination(
|
|
value,
|
|
props.row
|
|
)
|
|
"
|
|
/>
|
|
</QItemLabel>
|
|
<QItemLabel v-else>
|
|
{{ column.value }}
|
|
</QItemLabel>
|
|
</QItemSection>
|
|
</QItem>
|
|
</QList>
|
|
</QCard>
|
|
</div>
|
|
</template>
|
|
</QTable>
|
|
</template>
|
|
<template #moreBeforeActions>
|
|
<QBtn
|
|
color="primary"
|
|
text-color="white"
|
|
:unelevated="true"
|
|
:label="tMobile('Regularize')"
|
|
:title="t('Regularize')"
|
|
icon="check"
|
|
@click="regularizeClaim"
|
|
:disable="claim.claimStateFk == resolvedStateId"
|
|
/>
|
|
|
|
<QBtn
|
|
color="primary"
|
|
text-color="white"
|
|
:unelevated="true"
|
|
:disable="!selectedRows.length"
|
|
:label="tMobile('Change destination')"
|
|
:title="t('Change destination')"
|
|
icon="swap_horiz"
|
|
@click="dialogDestination = !dialogDestination"
|
|
/>
|
|
<QBtn
|
|
color="primary"
|
|
text-color="white"
|
|
:unelevated="true"
|
|
:label="tMobile('Import claim')"
|
|
:title="t('Import claim')"
|
|
icon="Upload"
|
|
@click="importToNewRefundTicket"
|
|
:disable="claim.claimStateFk == resolvedStateId"
|
|
/>
|
|
</template>
|
|
</CrudModel>
|
|
<QDialog v-model="dialogDestination">
|
|
<QCard>
|
|
<QCardSection>
|
|
<QItem class="q-pa-sm">
|
|
<span class="q-dialog__title text-white">
|
|
{{ t('dialog title') }}
|
|
</span>
|
|
<QBtn icon="close" flat round dense v-close-popup />
|
|
</QItem>
|
|
</QCardSection>
|
|
<QItemSection>
|
|
<VnSelectFilter
|
|
class="q-pa-sm"
|
|
v-model="claimDestinationFk"
|
|
:options="destinationTypes"
|
|
option-label="description"
|
|
option-value="id"
|
|
:autofocus="true"
|
|
dense
|
|
input-debounce="0"
|
|
hide-selected
|
|
/>
|
|
</QItemSection>
|
|
<QCardActions class="justify-end q-mr-sm">
|
|
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup />
|
|
<QBtn
|
|
:disable="!claimDestinationFk"
|
|
:label="t('globals.save')"
|
|
color="primary"
|
|
v-close-popup
|
|
@click="updateDestinations(claimDestinationFk)"
|
|
/>
|
|
</QCardActions>
|
|
</QCard>
|
|
</QDialog>
|
|
</template>
|
|
<style lang="scss" scoped>
|
|
.slider-container {
|
|
width: 50%;
|
|
}
|
|
@media (max-width: $breakpoint-xs) {
|
|
.slider-container {
|
|
width: 90%;
|
|
}
|
|
}
|
|
.q-table {
|
|
.q-item {
|
|
min-height: min-content;
|
|
height: 0;
|
|
}
|
|
}
|
|
.q-dialog {
|
|
.q-btn {
|
|
height: min-content;
|
|
}
|
|
}
|
|
.responsibility {
|
|
max-width: 100%;
|
|
margin-left: 40px;
|
|
}
|
|
|
|
.mana {
|
|
float: inline-start;
|
|
}
|
|
</style>
|
|
<i18n>
|
|
en:
|
|
mana: Is paid with mana
|
|
dialog title: Change destination to all selected rows
|
|
confirmGreuges: Do you want to insert complaints?
|
|
confirmGreugesMessage: Insert complaints into the client's record
|
|
|
|
es:
|
|
mana: Cargado al maná
|
|
Delivered: Descripción
|
|
Quantity: Cantidad
|
|
Claimed: Rec
|
|
Description: Descripción
|
|
Price: Precio
|
|
Discount: Dto.
|
|
Destination: Destino
|
|
Landed: F.entrega
|
|
Remove line: Eliminar línea
|
|
Total claimed: Total reclamado
|
|
Regularize: Regularizar
|
|
Change destination: Cambiar destino
|
|
Import claim: Importar reclamación
|
|
dialog title: Cambiar destino en todas las filas seleccionadas
|
|
Remove: Eliminar
|
|
dialogGreuge title: Insertar greuges en la ficha del cliente
|
|
ClaimGreugeDescription: Id reclamación
|
|
Id item: Id artículo
|
|
confirmGreuges: ¿Desea insertar greuges?
|
|
confirmGreugesMessage: Insertar greuges en la ficha del cliente
|
|
Apply Greuges: Aplicar Greuges
|
|
</i18n>
|