forked from verdnatura/salix-front
Customer description corrections and creation of tickets create view
This commit is contained in:
parent
d06271b91d
commit
1b67b7ab36
|
@ -170,6 +170,7 @@ export default {
|
|||
hasDebt: 'Customer has debt',
|
||||
notChecked: 'Customer not checked',
|
||||
noWebAccess: 'Web access is disabled',
|
||||
businessType: 'Business type',
|
||||
passwordRequirements:
|
||||
'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n',
|
||||
},
|
||||
|
@ -492,6 +493,13 @@ export default {
|
|||
weight: 'Weight',
|
||||
goTo: 'Go to',
|
||||
},
|
||||
create: {
|
||||
client: 'Client',
|
||||
address: 'Address',
|
||||
landed: 'Landed',
|
||||
warehouse: 'Warehouse',
|
||||
agency: 'Agency',
|
||||
},
|
||||
},
|
||||
claim: {
|
||||
pageTitles: {
|
||||
|
|
|
@ -169,6 +169,7 @@ export default {
|
|||
hasDebt: 'El cliente tiene riesgo',
|
||||
notChecked: 'El cliente no está comprobado',
|
||||
noWebAccess: 'El acceso web está desactivado',
|
||||
businessType: 'Tipo de negocio',
|
||||
passwordRequirements:
|
||||
'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)',
|
||||
},
|
||||
|
@ -492,6 +493,13 @@ export default {
|
|||
weight: 'Peso',
|
||||
goTo: 'Ir a',
|
||||
},
|
||||
create: {
|
||||
client: 'Cliente',
|
||||
address: 'Dirección',
|
||||
landed: 'F. entrega',
|
||||
warehouse: 'Almacén',
|
||||
agency: 'Agencia',
|
||||
},
|
||||
},
|
||||
claim: {
|
||||
pageTitles: {
|
||||
|
|
|
@ -3,15 +3,14 @@ import { ref, computed } from 'vue';
|
|||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { toCurrency } from 'src/filters';
|
||||
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
|
||||
import CardDescriptor from 'components/ui/CardDescriptor.vue';
|
||||
import VnLv from 'src/components/ui/VnLv.vue';
|
||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
||||
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
import { toCurrency } from 'src/filters';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
|
@ -23,8 +22,10 @@ const $props = defineProps({
|
|||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const entityId = computed(() => {
|
||||
return $props.id || route.params.id;
|
||||
});
|
||||
|
@ -43,54 +44,68 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
|||
:summary="$props.summary"
|
||||
data-key="customerData"
|
||||
>
|
||||
<template #header-extra-action>
|
||||
<QBtn
|
||||
round
|
||||
flat
|
||||
size="sm"
|
||||
icon="vn:Person"
|
||||
color="white"
|
||||
:to="{ name: 'CustomerList' }"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Go to module index') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</template>
|
||||
<template #menu="{ entity }">
|
||||
<CustomerDescriptorMenu :customer="entity" />
|
||||
</template>
|
||||
<template #body="{ entity }">
|
||||
<VnLv v-if="entity.salesPersonUser" :label="t('customer.card.salesPerson')">
|
||||
<VnLv :label="t('customer.card.payMethod')" :value="entity.payMethod.name" />
|
||||
<VnLv :label="t('customer.card.credit')" :value="toCurrency(entity.credit)" />
|
||||
<VnLv
|
||||
:label="t('customer.card.securedCredit')"
|
||||
:value="entity.creditInsurance ? toCurrency(entity.creditInsurance) : '-'"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('customer.card.risk')"
|
||||
:value="entity.debt ? toCurrency(entity.debt) : '-'"
|
||||
:info="t('customer.summary.descriptorInfo')"
|
||||
/>
|
||||
<VnLv :label="t('customer.card.salesPerson')">
|
||||
<template #value>
|
||||
<VnUserLink
|
||||
v-if="entity.salesPersonUser"
|
||||
:name="entity.salesPersonUser?.name"
|
||||
:worker-id="entity.salesPersonFk"
|
||||
/>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv :label="t('customer.card.credit')" :value="toCurrency(entity.credit)" />
|
||||
<VnLv
|
||||
:label="t('customer.card.risk')"
|
||||
:value="toCurrency(entity.debt)"
|
||||
:info="t('customer.summary.descriptorInfo')"
|
||||
:label="t('customer.card.businessType')"
|
||||
:value="entity.businessType.description"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('customer.card.securedCredit')"
|
||||
:value="toCurrency(entity.creditInsurance)"
|
||||
/>
|
||||
<VnLv :label="t('customer.card.payMethod')" :value="entity.payMethod.name" />
|
||||
<VnLv :label="t('customer.card.debt')" :value="toCurrency(entity.debt)" />
|
||||
</template>
|
||||
<template #icons="{ entity }">
|
||||
<QCardActions>
|
||||
<QCardActions class="q-gutter-x-md">
|
||||
<QIcon
|
||||
v-if="entity.isActive == false"
|
||||
v-if="!entity.isActive"
|
||||
name="vn:disabled"
|
||||
size="xs"
|
||||
color="primary"
|
||||
>
|
||||
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="entity.isFreezed == true"
|
||||
name="vn:frozen"
|
||||
size="xs"
|
||||
color="primary"
|
||||
>
|
||||
<QIcon v-if="entity.isFreezed" name="vn:frozen" size="xs" color="primary">
|
||||
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="!entity.account.active"
|
||||
color="primary"
|
||||
name="vn:noweb"
|
||||
size="sm"
|
||||
v-if="entity.account.active == false"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>{{ t('customer.card.webAccountInactive') }}</QTooltip>
|
||||
</QIcon>
|
||||
|
@ -103,13 +118,25 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
|||
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="entity.isTaxDataChecked == false"
|
||||
v-if="!entity.isTaxDataChecked"
|
||||
name="vn:no036"
|
||||
size="xs"
|
||||
color="primary"
|
||||
>
|
||||
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QBtn
|
||||
v-if="entity.unpaid"
|
||||
flat
|
||||
size="sm"
|
||||
icon="vn:noPayMethod"
|
||||
color="primary"
|
||||
:to="{ name: 'CustomerUnpaid' }"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Customer unpaid') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QCardActions>
|
||||
</template>
|
||||
<template #actions="{ entity }">
|
||||
|
@ -123,7 +150,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
|||
icon="vn:ticket"
|
||||
color="primary"
|
||||
>
|
||||
<QTooltip>{{ t('ticketList') }}</QTooltip>
|
||||
<QTooltip>{{ t('Customer ticket list') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
:to="{
|
||||
|
@ -134,35 +161,33 @@ const setData = (entity) => (data.value = useCardDescription(entity.name, entity
|
|||
icon="vn:invoice-out"
|
||||
color="primary"
|
||||
>
|
||||
<QTooltip>{{ t('invoiceOutList') }}</QTooltip>
|
||||
<QTooltip>{{ t('Customer invoice out list') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn
|
||||
:to="{
|
||||
name: 'OrderCreate',
|
||||
params: { id: entity.id },
|
||||
query: { clientFk: entity.id },
|
||||
}"
|
||||
size="md"
|
||||
icon="vn:basketadd"
|
||||
color="primary"
|
||||
>
|
||||
<QTooltip>{{ t('invoiceOutList') }}</QTooltip>
|
||||
<QTooltip>{{ t('New order') }}</QTooltip>
|
||||
</QBtn>
|
||||
<QBtn size="md" icon="vn:Person" color="primary">
|
||||
<QTooltip>{{ t('invoiceOutList') }}</QTooltip>
|
||||
<QBtn size="md" icon="face" color="primary">
|
||||
<!-- TODO:: Redirigir a la vista de usuario cuando exista -->
|
||||
<QTooltip>{{ t('Go to user') }}</QTooltip>
|
||||
</QBtn>
|
||||
</QCardActions>
|
||||
</template>
|
||||
</CardDescriptor>
|
||||
</template>
|
||||
<i18n>
|
||||
{
|
||||
"en": {
|
||||
"ticketList": "Customer ticket list",
|
||||
"invoiceOutList": "Customer invoice out list"
|
||||
},
|
||||
"es": {
|
||||
"ticketList": "Listado de tickets del cliente",
|
||||
"invoiceOutList": "Listado de facturas del cliente"
|
||||
}
|
||||
}
|
||||
es:
|
||||
Go to module index: Ir al índice del módulo
|
||||
Customer ticket list: Listado de tickets del cliente
|
||||
Customer invoice out list: Listado de facturas del cliente
|
||||
New order: Nuevo pedido
|
||||
Go to user: Ir al usuario
|
||||
Customer unpaid: Cliente impago
|
||||
</i18n>
|
||||
|
|
|
@ -25,7 +25,7 @@ const showSmsDialog = () => {
|
|||
quasar.dialog({
|
||||
component: VnSmsDialog,
|
||||
componentProps: {
|
||||
phone: $props.customer.phone,
|
||||
phone: $props.customer.phone || $props.customer.mobile,
|
||||
promise: sendSms,
|
||||
},
|
||||
});
|
||||
|
@ -45,7 +45,13 @@ const sendSms = async (payload) => {
|
|||
<template>
|
||||
<QItem v-ripple clickable>
|
||||
<QItemSection>
|
||||
<RouterLink :to="{ name: 'TicketCreate' }" class="color-vn-text">
|
||||
<RouterLink
|
||||
:to="{
|
||||
name: 'TicketCreate',
|
||||
query: { clientFk: customer.id },
|
||||
}"
|
||||
class="color-vn-text"
|
||||
>
|
||||
{{ t('Simple ticket') }}
|
||||
</RouterLink>
|
||||
</QItemSection>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { useRoute } from 'vue-router';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { reactive, ref, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
import { useState } from 'composables/useState';
|
||||
|
@ -27,6 +27,23 @@ const clientList = ref([]);
|
|||
const agencyList = ref([]);
|
||||
const addressList = ref([]);
|
||||
|
||||
const onClientsFetched = async (data) => {
|
||||
try {
|
||||
clientList.value = data;
|
||||
initialFormState.clientFk = Number(route.query?.clientFk) || null;
|
||||
|
||||
if (initialFormState.clientFk) {
|
||||
const { defaultAddressFk } = clientList.value.find(
|
||||
(client) => client.id === initialFormState.clientFk
|
||||
);
|
||||
|
||||
if (defaultAddressFk) await fetchAddressList(defaultAddressFk);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error fetching clients', err);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAddressList = async (addressId) => {
|
||||
try {
|
||||
const { data } = await axios.get('addresses', {
|
||||
|
@ -47,6 +64,7 @@ const fetchAddressList = async (addressId) => {
|
|||
return err.response;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAgencyList = async (landed, addressFk) => {
|
||||
if (!landed || !addressFk) {
|
||||
return;
|
||||
|
@ -108,7 +126,7 @@ const orderFilter = {
|
|||
<template>
|
||||
<FetchData
|
||||
url="Clients"
|
||||
@on-fetch="(data) => (clientList = data)"
|
||||
@on-fetch="(data) => onClientsFetched(data)"
|
||||
:filter="{ fields: ['id', 'name', 'defaultAddressFk'] }"
|
||||
auto-load
|
||||
/>
|
||||
|
|
|
@ -168,7 +168,7 @@ async function changeState(value) {
|
|||
</VnLv>
|
||||
<VnLv
|
||||
:label="t('ticket.summary.agency')"
|
||||
:value="ticket.agencyMode.name"
|
||||
:value="ticket.agencyMode?.name"
|
||||
/>
|
||||
<VnLv :label="t('ticket.summary.zone')" :value="ticket?.zone?.name" />
|
||||
<VnLv
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
<script setup>
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { onBeforeMount, reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||
|
||||
import { useState } from 'composables/useState';
|
||||
import axios from 'axios';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const state = useState();
|
||||
const user = state.getUser();
|
||||
|
||||
const initialFormState = reactive({
|
||||
clientId: Number(route.query?.clientFk) || null,
|
||||
addressId: null,
|
||||
agencyModeId: null,
|
||||
warehouseId: user.value.warehouseFk,
|
||||
landed: null,
|
||||
});
|
||||
const clientOptions = ref([]);
|
||||
const agenciesOptions = ref([]);
|
||||
const addressesOptions = ref([]);
|
||||
const warehousesOptions = ref([]);
|
||||
const selectedClient = ref(null);
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await onClientSelected(initialFormState);
|
||||
});
|
||||
|
||||
const fetchClient = async (formData) => {
|
||||
try {
|
||||
const filter = {
|
||||
include: {
|
||||
relation: 'defaultAddress',
|
||||
scope: {
|
||||
fields: ['id', 'agencyModeFk'],
|
||||
},
|
||||
},
|
||||
where: { id: formData.clientId },
|
||||
};
|
||||
const params = { filter: JSON.stringify(filter) };
|
||||
const { data } = await axios.get('Clients', { params });
|
||||
const [client] = data;
|
||||
selectedClient.value = client;
|
||||
} catch (err) {
|
||||
console.error('Error fetching client');
|
||||
}
|
||||
};
|
||||
|
||||
const fetchAddresses = async (formData) => {
|
||||
try {
|
||||
if (!formData.clientId) return;
|
||||
|
||||
const filter = {
|
||||
fields: ['nickname', 'street', 'city', 'id'],
|
||||
where: { isActive: true },
|
||||
order: 'nickname ASC',
|
||||
};
|
||||
const params = { filter: JSON.stringify(filter) };
|
||||
const { data } = await axios.get(`Clients/${formData.clientId}/addresses`, {
|
||||
params,
|
||||
});
|
||||
addressesOptions.value = data;
|
||||
|
||||
const { defaultAddress } = selectedClient.value;
|
||||
formData.addressId = defaultAddress.id;
|
||||
console.log();
|
||||
} catch (err) {
|
||||
console.error(`Error fetching addresses`, err);
|
||||
return err.response;
|
||||
}
|
||||
};
|
||||
|
||||
const onClientSelected = async (formData) => {
|
||||
await fetchClient(formData);
|
||||
await fetchAddresses(formData);
|
||||
};
|
||||
|
||||
const fetchAvailableAgencies = async (formData) => {
|
||||
if (!formData.warehouseId || !formData.addressId || !formData.landed) return;
|
||||
let params = {
|
||||
warehouseFk: formData.warehouseId,
|
||||
addressFk: formData.addressId,
|
||||
landed: formData.landed,
|
||||
};
|
||||
|
||||
const { data } = await axios.get('Agencies/getAgenciesWithWarehouse', { params });
|
||||
|
||||
agenciesOptions.value = data;
|
||||
|
||||
const defaultAgency = agenciesOptions.value.find(
|
||||
(agency) =>
|
||||
agency.agencyModeFk === selectedClient.value.defaultAddress.agencyModeFk
|
||||
);
|
||||
|
||||
if (defaultAgency) formData.agencyModeId = defaultAgency.agencyModeFk;
|
||||
};
|
||||
|
||||
const redirectToTicketList = (_, { id }) => {
|
||||
router.push({ name: 'TicketSummary', params: { id } });
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Clients"
|
||||
@on-fetch="(data) => (clientOptions = data)"
|
||||
:filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Warehouses"
|
||||
@on-fetch="(data) => (warehousesOptions = data)"
|
||||
order="name"
|
||||
auto-load
|
||||
/>
|
||||
<VnSubToolbar />
|
||||
<div class="q-pa-md">
|
||||
<FormModel
|
||||
url-create="Tickets/new"
|
||||
model="ticket"
|
||||
:form-initial-data="initialFormState"
|
||||
@on-data-saved="redirectToTicketList"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('ticket.create.client')"
|
||||
v-model="data.clientId"
|
||||
:options="clientOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="(client) => onClientSelected(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.name }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `#${scope.opt.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('ticket.create.address')"
|
||||
v-model="data.addressId"
|
||||
:options="addressesOptions"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
hide-selected
|
||||
:disable="!data.clientId"
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.nickname }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `${scope.opt.street}, ${scope.opt.city}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelectFilter>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnInputDate
|
||||
placeholder="dd-mm-aaa"
|
||||
:label="t('ticket.create.landed')"
|
||||
v-model="data.landed"
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('ticket.create.warehouse')"
|
||||
v-model="data.warehouseId"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
@update:model-value="() => fetchAvailableAgencies(data)"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
<VnRow class="row q-gutter-md q-mb-md">
|
||||
<div class="col">
|
||||
<VnSelectFilter
|
||||
:label="t('ticket.create.agency')"
|
||||
v-model="data.agencyModeId"
|
||||
:options="agenciesOptions"
|
||||
option-value="agencyModeFk"
|
||||
option-label="agencyMode"
|
||||
hide-selected
|
||||
:disable="!data.clientId || !data.landed || !data.warehouseId"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModel>
|
||||
</div>
|
||||
</template>
|
|
@ -122,6 +122,13 @@ function navigate(id) {
|
|||
</template>
|
||||
</VnPaginate>
|
||||
</div>
|
||||
<QPageSticky :offset="[20, 20]">
|
||||
<QBtn :to="{ name: 'TicketCreate' }" fab icon="add" color="primary">
|
||||
<QTooltip>
|
||||
{{ t('New ticket') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QPageSticky>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
|
@ -130,4 +137,5 @@ es:
|
|||
Search ticket: Buscar ticket
|
||||
You can search by ticket id or alias: Puedes buscar por id o alias del ticket
|
||||
Zone: Zona
|
||||
New ticket: Nuevo ticket
|
||||
</i18n>
|
||||
|
|
|
@ -37,7 +37,7 @@ export default {
|
|||
icon: 'vn:ticketAdd',
|
||||
roles: ['developer'],
|
||||
},
|
||||
component: () => import('src/pages/Ticket/TicketList.vue'),
|
||||
component: () => import('src/pages/Ticket/TicketCreate.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue