6157-actionClaim #106

Merged
carlossa merged 22 commits from 6157-actionClaim into dev 2023-11-24 07:46:30 +00:00
8 changed files with 526 additions and 16 deletions
Showing only changes of commit f230fcbca2 - Show all commits

View File

@ -4,7 +4,7 @@ const emit = defineEmits(['update:modelValue', 'update:options']);
const $props = defineProps({ const $props = defineProps({
modelValue: { modelValue: {
type: [String, Number], type: [String, Number, Object],
default: null, default: null,
}, },
options: { options: {

View File

@ -2,6 +2,7 @@
import { onMounted, useSlots, ref, watch } from 'vue'; import { onMounted, useSlots, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import { useArrayData } from 'src/composables/useArrayData';
import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue'; import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
const $props = defineProps({ const $props = defineProps({
@ -26,18 +27,21 @@ const $props = defineProps({
default: 0, default: 0,
}, },
}); });
const arrayData = useArrayData('claimData');
const store = arrayData.store;
console.log('eee', store.data);
const slots = useSlots(); const slots = useSlots();
const { t } = useI18n(); const { t } = useI18n();
const entity = ref(); const entity = ref(null);
let lastUrl = ref(null);
carlossa marked this conversation as resolved
Review

Esta tb borrala

Esta tb borrala
onMounted(async () => { onMounted(async () => {
await fetch(); entity.value = await store.data;
}); });
const emit = defineEmits(['onFetch']); const emit = defineEmits(['onFetch']);
async function fetch() { async function fetch() {
lastUrl.value = $props.url;
const params = {}; const params = {};
if ($props.filter) params.filter = JSON.stringify($props.filter); if ($props.filter) params.filter = JSON.stringify($props.filter);
@ -49,6 +53,7 @@ async function fetch() {
} }
watch($props, async () => { watch($props, async () => {
if (lastUrl.value == $props.url) return;
entity.value = null; entity.value = null;
await fetch(); await fetch();
}); });

View File

@ -269,6 +269,7 @@ export default {
development: 'Development', development: 'Development',
log: 'Audit logs', log: 'Audit logs',
notes: 'Notes', notes: 'Notes',
action: 'Action',
}, },
list: { list: {
customer: 'Customer', customer: 'Customer',

View File

@ -268,6 +268,7 @@ export default {
photos: 'Fotos', photos: 'Fotos',
log: 'Registros de auditoría', log: 'Registros de auditoría',
notes: 'Notas', notes: 'Notas',
action: 'Action',
}, },
list: { list: {
customer: 'Cliente', customer: 'Cliente',

View File

@ -0,0 +1,454 @@
<script setup>
import { ref, computed, watchEffect, onMounted, onUnmounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import axios from 'axios';
import { useStateStore } from 'src/stores/useStateStore';
import { toDate, toPercentage, toCurrency } from 'filters/index';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import { useArrayData } from 'src/composables/useArrayData';
const { t } = useI18n();
const route = useRoute();
const stateStore = computed(() => useStateStore());
const claimId = route.params.id;
const dialog = ref(false);
const dialogOption = ref(null);
const resolvedStateId = ref(null);
const claimActionsForm = ref();
const rows = ref([]);
const selectedRows = ref([]);
const destinationTypes = ref([]);
const destinations = ref([]);
const totalClaimed = ref(null);
const responsibility = ref(5); // pending to get from ClaimDescriptor
const manaCharger = ref(false); // pending to get from ClaimDescriptor
const claimData = useArrayData('claimData');
// ClaimEnds/filter?filter={ claimFk: route.param.id}
// for update responsability and mana /Claims/id/updateClaimAction
// onMounted(() => (stateStore.value.rightDrawer = true));
// onUnmounted(() => (stateStore.value.rightDrawer = false));
const columns = computed(() => [
{
name: 'Id',
label: t('Id'),
field: (row) => row.itemFk,
},
{
name: 'ticket',
label: t('Ticket'),
field: (row) => row.ticketFk,
align: 'center',
},
{
carlossa marked this conversation as resolved
Review

Pq no pots possar row.claimDestinationFk ?

Pq no pots possar row.claimDestinationFk ?
name: 'destination',
label: t('Destination'),
field: (row) => getDestination(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',
},
]);
console.log(claimData.store.data);
watchEffect(() => {
if (rows.value.length) {
destinations.value = rows.value.map((row) =>
getDestination(row.claimDestinationFk)
);
totalClaimed.value = rows.value.reduce((total, row) => total + row.total, 0);
}
});
function getDestination(destinationId) {
return destinationTypes.value.find((type) => type.id == destinationId);
}
async function updateDestination(claimDestinationFk, row) {
if (claimDestinationFk) {
await axios.post('Claims/updateClaimDestination', {
claimDestinationFk,
rows: [row],
});
}
}
async function deleteSale(sale) {
await axios.post(`ClaimEnds/deleteClamedSales`, { sales: [sale] });
claimActionsForm.value.reload();
}
carlossa marked this conversation as resolved
Review

Y esto también!!

Y esto también!!
async function updateDestinations(claimDestinationFk) {
if (claimDestinationFk) {
await axios.post('Claims/updateClaimDestination', {
claimDestinationFk,
rows: [...selectedRows.value],
});
claimActionsForm.value.reload();
}
}
</script>
<template>
<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>
<QScrollArea class="fit text-grey-8 q-mt-lg">
<div class="totalClaim q-mb-md">
{{ `${t('Total claimed')}: ${toCurrency(totalClaimed)}` }}
</div>
<QCard class="q-mb-md q-pa-sm">
<QItem class="justify-between">
<QItemLabel class="slider-container">
<p class="text-primary">
{{ t('claim.summary.actions') }}
</p>
<QSlider
class="responsability"
v-model="responsibility"
label
:label-value="t('claim.summary.responsibility')"
label-always
color="primary"
markers
:marker-labels="[
{ value: 1, label: t('claim.summary.company') },
{ value: 5, label: t('claim.summary.person') },
]"
:min="1"
:max="5"
/>
</QItemLabel>
</QItem>
</QCard>
<QItemLabel class="mana q-mb-md">
<QCheckbox v-model="manaCharger" />
<span>{{ t('mana') }}</span>
</QItemLabel>
</QScrollArea>
</QDrawer>
<FetchData
url="ClaimDestinations"
auto-load
@on-fetch="(data) => (destinationTypes = data)"
/>
<FetchData
:url="`ClaimStates/findOne`"
:where="{ code: 'resolved' }"
auto-load
@on-fetch="(data) => (resolvedStateId = data)"
/>
<Teleport to="#st-data" v-if="stateStore.isSubToolbarShown()">
<QToolbar>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:disable="!selectedRows.length"
:label="t('Change destination')"
@click="dialog = !dialog"
/>
</QToolbar>
</Teleport>
<div class="claim-action">
<CrudModel
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="(data) => (rows = data)"
auto-load
>
<template #body>
<QTable
:columns="columns"
:rows="rows"
:dense="$q.screen.lt.md"
:pagination="{ rowsPerPage: 0 }"
row-key="id"
selection="multiple"
v-model:selected="selectedRows"
hide-pagination
:grid="$q.screen.lt.md"
>
<template #body-cell-ticket="{ value }">
<QTd align="center">
<span class="link">
{{ value }}
<TicketDescriptorProxy :id="value" />
</span>
</QTd>
</template>
<template #body-cell-destination="{ rowIndex }">
<QTd>
<VnSelectFilter
v-model="destinations[rowIndex]"
:options="destinationTypes"
option-value="id"
option-label="description"
@update:model-value="
(value) => updateDestination(value, rows[rowIndex])
"
/>
</QTd>
</template>
<template #body-cell-price="{ value }">
<QTd align="center">
{{ toCurrency(value) }}
</QTd>
</template>
carlossa marked this conversation as resolved
Review

Si, los labels cambian, tienes que venir hasta el HTML?
Quizás, mejor definirlo en el apartado de

Si, los labels cambian, tienes que venir hasta el HTML? Quizás, mejor definirlo en el apartado de <script setup>
<template #body-cell-total="{ value }">
<QTd align="center">
{{ toCurrency(value) }}
</QTd>
carlossa marked this conversation as resolved
Review

Podemos definir este valor como constante?
Tipo
DEFAULT_MIN_SLIDER =1
DEFAULT_MAX_SLIDER =5

Podemos definir este valor como constante? Tipo DEFAULT_MIN_SLIDER =1 DEFAULT_MAX_SLIDER =5
</template>
<template #body-cell-delete="{ rowIndex }">
<QTd>
<QBtn
icon="delete"
color="primary"
padding="xs"
round
flat
@click="deleteSale(rows[rowIndex])"
>
<QTooltip>
{{ t('Remove line') }}
</QTooltip>
</QBtn>
</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'"
>
{{ column.value.description }}
</QItemLabel>
<QItemLabel v-else>
{{ column.value }}
</QItemLabel>
</QItemSection>
</QItem>
</QList>
</QCard>
</div>
</template>
</QTable>
</template>
<template #moreActions>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:label="t('Regularize')"
/>
<!--disabled="(ClaimDescriptor)claimStateFk == resolvedStateId"-->
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:disable="!selectedRows.length"
:label="t('Change destination')"
@click="dialog = !dialog"
/>
<QBtn
color="primary"
text-color="white"
class="q-mx-sm"
:unelevated="true"
:label="t('Import claim')"
/>
<!--disabled="(ClaimDescriptor)claimStateFk == resolvedStateId"-->
</template>
</CrudModel>
<QDialog v-model="dialog">
<QCard>
<QCardSection>
<QItem class="q-pa-none">
<span class="q-dialog__title text-white">
{{ t('dialog title') }}
</span>
<QBtn icon="close" flat round dense v-close-popup />
</QItem>
</QCardSection>
<QCardSection>
<VnSelectFilter
v-model="dialogOption"
:options="destinationTypes"
option-label="description"
option-value="id"
/>
</QCardSection>
<QCardActions class="justify-end q-mr-sm">
<QBtn
flat
:label="t('globals.close')"
color="primary"
v-close-popup
/>
<QBtn
:disable="!dialogOption"
:label="t('globals.save')"
color="primary"
v-close-popup
@click="updateDestinations(dialogOption)"
/>
</QCardActions>
</QCard>
</QDialog>
</div>
</template>
<style lang="scss">
.claim-action {
.q-table {
.q-select .q-field__input {
display: none !important;
}
}
}
</style>
<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;
}
}
.totalClaim {
border: 3px solid black;
color: white;
padding: 10px;
margin: 5px;
}
.responsability {
max-width: 100%;
margin-left: 40px;
}
.mana {
color: white;
float: inline-start;
}
.qdrawer {
}
</style>
<i18n>
en:
mana: Is paid with mana
dialog title: Change destination to all selected rows
es:
mana: Cargado al maná
Delivered: Descripción
Quantity: Cantidad
Claimed: Rec
Description: Description
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
</i18n>

View File

@ -1,17 +1,58 @@
<script setup> <script setup>
import LeftMenu from 'components/LeftMenu.vue'; import { onMounted, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { useArrayData } from 'src/composables/useArrayData';
import { getUrl } from 'composables/getUrl'; import { getUrl } from 'composables/getUrl';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore'; import LeftMenu from 'components/LeftMenu.vue';
import { computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import ClaimDescriptor from './ClaimDescriptor.vue'; import ClaimDescriptor from './ClaimDescriptor.vue';
import { onMounted } from 'vue';
const stateStore = useStateStore(); const stateStore = useStateStore();
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const filter = {
include: [
{
relation: 'client',
scope: {
include: { relation: 'salesPersonUser' },
},
},
carlossa marked this conversation as resolved
Review

esto no se usa, no?

esto no se usa, no?
{
relation: 'claimState',
},
{
relation: 'ticket',
scope: {
include: [
{ relation: 'zone' },
{
relation: 'address',
scope: {
include: { relation: 'province' },
},
},
],
},
},
{
relation: 'worker',
scope: {
include: { relation: 'user' },
},
},
],
};
const arrayData = useArrayData('claimData', {
url: `Claims/${route.params.id}`,
filter,
});
const entityId = computed(() => {
return $props.id || route.params.id;
});
const $props = defineProps({ const $props = defineProps({
id: { id: {
type: Number, type: Number,
@ -19,13 +60,11 @@ const $props = defineProps({
default: null, default: null,
}, },
}); });
const entityId = computed(() => {
return $props.id || route.params.id;
});
let salixUrl; let salixUrl;
onMounted(async () => { onMounted(async () => {
salixUrl = await getUrl(`claim/${entityId.value}`); salixUrl = await getUrl(`claim/${entityId.value}`);
await arrayData.fetch({ append: false });
}); });
</script> </script>
<template> <template>

View File

@ -68,7 +68,7 @@ function viewSummary(id) {
</div> </div>
</Teleport> </Teleport>
</template> </template>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256">
<QScrollArea class="fit text-grey-8"> <QScrollArea class="fit text-grey-8">
<TicketFilter data-key="TicketList" /> <TicketFilter data-key="TicketList" />
</QScrollArea> </QScrollArea>

View File

@ -19,6 +19,7 @@ export default {
'ClaimLog', 'ClaimLog',
'ClaimNotes', 'ClaimNotes',
'ClaimDevelopment', 'ClaimDevelopment',
'ClaimAction',
], ],
}, },
children: [ children: [
@ -130,6 +131,15 @@ export default {
}, },
component: () => import('src/pages/Claim/Card/ClaimNotes.vue'), component: () => import('src/pages/Claim/Card/ClaimNotes.vue'),
}, },
{
name: 'ClaimAction',
path: 'action',
meta: {
title: 'action',
icon: 'vn:actions',
},
component: () => import('src/pages/Claim/Card/ClaimAction.vue'),
},
], ],
}, },
], ],