PR-CUSTOMER #186

Merged
jsegarra merged 105 commits from :PR-CUSTOMER into dev 2024-04-19 15:55:53 +00:00
23 changed files with 1319 additions and 55 deletions
Showing only changes of commit 8cc92f127c - Show all commits

View File

@ -135,7 +135,7 @@ async function save() {
} else {
response = await axios.patch($props.urlUpdate || $props.url, body);
}
emit('onDataSaved', formData.value, response.data);
emit('onDataSaved', formData.value, response?.data);
originalData.value = JSON.parse(JSON.stringify(formData.value));
hasChanges.value = false;
} catch (err) {

View File

@ -206,6 +206,17 @@ async function togglePinned(item, event) {
<template v-if="$props.source === 'card'">
<template v-for="item in items" :key="item.name">
<LeftMenuItem v-if="!item.children" :item="item" />
<QList v-else>
<QExpansionItem
v-ripple
clickable
:icon="item.icon"
:label="t(item.title)"
:content-inset-level="0.5"
>
<LeftMenuItemGroup :item="item" />
</QExpansionItem>
</QList>
</template>
</template>
</QList>

View File

@ -131,6 +131,8 @@ export default {
log: 'Log',
sms: 'Sms',
creditManagement: 'Credit management',
creditContracts: 'Credit contracts',
creditOpinion: 'Credit opinion',
others: 'Others',
},
list: {

View File

@ -131,6 +131,8 @@ export default {
log: 'Historial',
sms: 'Sms',
creditManagement: 'Gestión de crédito',
creditContracts: 'Contratos de crédito',
creditOpinion: 'Opinión de crédito',
others: 'Otros',
},
list: {

View File

@ -1,3 +1,282 @@
<script setup>
Review

Errores:

  1. Columna fecha
  2. Worker descriptor
  3. Referencia descriptor
  4. Referencia puede ser editable
Errores: 1. Columna fecha 2. Worker descriptor 3. Referencia descriptor 4. Referencia puede ser editable
Review

Corregido: 3cf3687b84

Corregido: 3cf3687b84
Review

Revisamos porque la columna referencia no tiene el mismo formato. El campo, debería ser descriptor, si procede

Revisamos porque la columna referencia no tiene el mismo formato. El campo, debería ser descriptor, si procede
Review

Corregido: 17a0afda73

Corregido: 17a0afda73
Review

Revisar porque lago raro pasa

Revisar porque lago raro pasa
Review

@wbuezas y yo hemos visto que las filas no siempre aparecen ordenadas con los customer 1102 y 1103.
He eliminado el "order:id DESC" y parece que va mejor, pero alguna vez aparece en otro orden

@wbuezas y yo hemos visto que las filas no siempre aparecen ordenadas con los customer 1102 y 1103. He eliminado el "order:id DESC" y parece que va mejor, pero alguna vez aparece en otro orden
Review

Pasaban 2 cosas:

  • Estaba mal el orden en la request como vimos
  • Había también un error en el calculo del balance

Ambas cosas quedaron fixeadas en este commit: 1cff622898

Pasaban 2 cosas: - Estaba mal el orden en la request como vimos - Había también un error en el calculo del balance Ambas cosas quedaron fixeadas en este commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/1cff622898264123e0135ec6dfff44ce0d0b6fb8
Review

Aquí también hay un error en los datos que vienen del back porque el campo payed y created, tiene la misma fecha y hora para los registros con id 1

Aquí también hay un error en los datos que vienen del back porque el campo payed y created, tiene la misma fecha y hora para los registros con id 1
import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { date, QCheckbox, QBtn, useQuasar } from 'quasar';
import { toCurrency } from 'src/filters';
import { useStateStore } from 'stores/useStateStore';
import FetchData from 'components/FetchData.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n();
const route = useRoute();
const quasar = useQuasar();
const stateStore = useStateStore();
const clientRisks = ref(null);
const companiesOptions = ref([]);
const companyId = ref(442);
const rows = ref(null);
const workerId = ref(0);
const receiptsRef = ref(null);
const clientRisksRef = ref(null);
const filterCompanies = { order: ['code'] };
const params = {
clientId: `${route.params.id}`,
companyId: companyId.value,
filter: { limit: 20 },
};
const filter = {
include: { relation: 'company', scope: { fields: ['code'] } },
where: { clientFk: `${route.params.id}`, companyFk: companyId.value },
};
const tableColumnComponents = {
payed: {
component: 'span',
props: () => {},
event: () => {},
},
created: {
component: 'span',
props: () => {},
event: () => {},
},
userName: {
component: QBtn,
props: () => ({ flat: true, color: 'blue' }),
event: (prop) => {
workerId.value = prop.row.clientFk;
},
},
description: {
component: 'span',
props: () => {},
event: () => {},
},
bankFk: {
component: 'span',
props: () => {},
event: () => {},
},
debit: {
component: 'span',
props: () => {},
event: () => {},
},
credit: {
component: 'span',
props: () => {},
event: () => {},
},
balance: {
component: 'span',
props: () => {},
event: () => {},
},
isConciliate: {
component: QCheckbox,
props: (prop) => ({
disable: true,
'model-value': Boolean(prop.value),
}),
event: () => {},
},
};
const columns = computed(() => [
{
align: 'left',
field: 'payed',
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
label: t('Date'),
name: 'payed',
},
jsegarra marked this conversation as resolved Outdated

todos los campos de euros deben de ir alineados a la derecha como en salix.

todos los campos de euros deben de ir alineados a la derecha como en salix.

Así se ve para el cliente 1101. Ver imagen adjunta
Sin embargo, el cursor cambia a "la mano", induciendo a que se puede cambiar, cuando debería aparecer el prohibido o cambiar el color del checkbox a gris

Así se ve para el cliente 1101. Ver imagen adjunta Sin embargo, el cursor cambia a "la mano", induciendo a que se puede cambiar, cuando debería aparecer el prohibido o cambiar el color del checkbox a gris

Corregido, campos de tipo moneda alineados a la derecha y el checkbox deshabilitado: 0aa5a051fb

Corregido, campos de tipo moneda alineados a la derecha y el checkbox deshabilitado: 0aa5a051fb

Yo lo he visto OK
El checkbox es de color naranja pero se ve que está deshabilitado y tiene el cursor en prohibido

Yo lo he visto OK El checkbox es de color naranja pero se ve que está deshabilitado y tiene el cursor en prohibido
{
align: 'left',
field: 'created',
format: (value) => date.formatDate(value, 'DD/MM/YYYY hh:mm'),
label: t('Creation date'),
name: 'created',
},
{
align: 'left',
field: 'userName',
label: t('Employee'),
name: 'userName',
},
{
align: 'left',
Review

El usuario en minusculas igual que salix (cambiar para todos los sitios que se muestre)

El usuario en minusculas igual que salix (cambiar para todos los sitios que se muestre)
Review

Corregido: 663010a0d4

Corregido: 663010a0d4
Review

Yo lo he visto OK

Yo lo he visto OK
field: 'description',
label: t('Reference'),
name: 'description',
},
{
align: 'left',
field: 'bankFk',
label: t('Bank'),
name: 'bankFk',
},
{
align: 'left',
field: 'debit',
label: t('Debit'),
name: 'debit',
},
{

el cambo debit son euros le falta
format: (value) => toCurrency(value),

el cambo debit son euros le falta format: (value) => toCurrency(value),

Corregido: f8b698e4e7

Corregido: f8b698e4e7

Yo lo he visto OK en customer/1101/balance

Yo lo he visto OK en customer/1101/balance
align: 'left',
field: 'credit',
format: (value) => toCurrency(value),
label: t('Havings'),
name: 'credit',
},
{

en las columnas debe y haber si el valor es cero no mostrarlo
tal como lo hace en salix.

en las columnas debe y haber si el valor es cero no mostrarlo tal como lo hace en salix.

Corregido: d74119f433

Corregido: d74119f433

Yo lo he visto OK

Yo lo he visto OK
align: 'left',
field: (value) => value.debit - value.credit,
format: (value) => toCurrency(value),
label: t('Balance'),
name: 'balance',
},
{
align: 'left',
field: 'isConciliate',
label: t('Conciliated'),
name: 'isConciliate',
},

Revisar en salix el valor del campo balance
http://localhost:5000/#!/client/1101/balance/index
respecto a lilium
http://localhost:9000/#/customer/1101/balance

el balance es un saldo por tanto, va acumulando el balance anterior +- el valor del debe/haber

Revisar en salix el valor del campo balance http://localhost:5000/#!/client/1101/balance/index respecto a lilium http://localhost:9000/#/customer/1101/balance el balance es un saldo por tanto, va acumulando el balance anterior +- el valor del debe/haber

Corregido: d74119f433

Corregido: d74119f433

Not fixed! Ver imagen

Not fixed! Ver imagen

Corregido el valor del campo balance: 38d3d49ecb

Corregido el valor del campo balance: 38d3d49ecb

He probado con los clientes 1101, 1102 y 1103 y lo he visto OK

He probado con los clientes 1101, 1102 y 1103 y lo he visto OK
]);
const getData = () => {
stateStore.rightDrawer = true;
receiptsRef.value?.fetch();
clientRisksRef.value?.fetch();
};
const showNewPaymentDialog = () => {
quasar.dialog({

no se porque el conciliado al lado del checkbox tiene un 1, http://localhost:9000/#/customer/1101/balance

no se porque el conciliado al lado del checkbox tiene un 1, http://localhost:9000/#/customer/1101/balance

Corregido: d74119f433

Corregido: d74119f433

Yo lo he visto OK

Yo lo he visto OK
component: CustomerNewPayment,
componentProps: {
companyId: companyId.value,
totalCredit: clientRisks.value[0]?.amount,
promise: getData,
},
});
};
const updateCompanyId = (id) => {
if (id) companyId.value = id;
getData();
};
</script>
<template>
<div class="flex justify-center">Balance</div>
<FetchData
:filter="filterCompanies"
@on-fetch="(data) => (companiesOptions = data)"
auto-load
url="Companies"
/>
<FetchData
:params="params"
@on-fetch="(data) => (rows = data)"
auto-load
ref="receiptsRef"
url="Receipts/filter"
/>
<FetchData
:filter="filter"
@on-fetch="(data) => (clientRisks = data)"
auto-load
ref="clientRisksRef"
url="ClientRisks"
/>
<QTable
:columns="columns"
:pagination="{ rowsPerPage: 12 }"
:rows="rows"
class="full-width q-mt-md"
row-key="id"
v-if="rows?.length"
>
<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="props.col.name !== 'isConciliate'">
{{ props.value }}
</template>
<WorkerDescriptorProxy :id="workerId" />
</component>
</QTr>
</QTd>
</template>
</QTable>
<h5 class="flex justify-center label-color" v-else>
{{ t('globals.noResults') }}
</h5>
<QDrawer :width="256" show-if-above side="right" v-model="stateStore.rightDrawer">
<div class="q-mt-xl q-px-md">
<VnSelectFilter
:label="t('Company')"
:options="companiesOptions"
@update:model-value="updateCompanyId($event)"
hide-selected
option-label="code"
option-value="id"
v-model="companyId"
/>
</div>
<QCard class="q-ma-md q-pa-md q-mt-lg" v-if="rows?.length">
<QCardSection>
<div class="flex justify-center text-subtitle1 text-bold">
{{ t('Total by company') }}
</div>
<div class="flex justify-center">
<div class="q-mr-sm" v-if="clientRisks?.length">
{{ clientRisks[0].company.code }}:
</div>
<div v-if="clientRisks?.length">
{{ toCurrency(clientRisks[0].amount) }}
</div>
</div>
</QCardSection>
</QCard>
</QDrawer>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="showNewPaymentDialog()" color="primary" fab icon="add" />
<QTooltip>
{{ t('New payment') }}
</QTooltip>
</QPageSticky>
</template>
jsegarra marked this conversation as resolved Outdated

Revisar, si este es el componente que acordamos en la UX/UI.
Hablar con @buezas porque ha hecho un cambio en la parte de travel/extra-community y el tipo de componente quasar que se está usando aquí no es el mismo

Revisar, si este es el componente que acordamos en la UX/UI. Hablar con @buezas porque ha hecho un cambio en la parte de travel/extra-community y el tipo de componente quasar que se está usando aquí no es el mismo

Corregido: 86199d8197

Corregido: 86199d8197
<i18n>
es:
Company: Empresa
Total by company: Total por empresa
New payment: Añadir pago
Date: Fecha
jsegarra marked this conversation as resolved Outdated

http://localhost:5000/#!/client/100/balance/index en salix hay un registro y el boton de enviar compensación, en lilium no aparece ni el registro ni el boton

http://localhost:5000/#!/client/100/balance/index en salix hay un registro y el boton de enviar compensación, en lilium no aparece ni el registro ni el boton

Corregido: f8b698e4e7 hace falta cambiar el icono del mail, no lo he encontrado en Lilium aun

Corregido: f8b698e4e7 hace falta cambiar el icono del mail, no lo he encontrado en Lilium aun

Efectivamente no está.

Hablamos con el responsable de la iconografía

Gracias

Efectivamente no está. Hablamos con el responsable de la iconografía Gracias

Resuelto

Resuelto
Creation date: Fecha de creación
Employee: Empleado
Reference: Referencia
Bank: Caja
Debit: Debe
Havings: Haber
Balance: Balance
Conciliated: Conciliado
</i18n>

View File

@ -137,21 +137,15 @@ const toCustomerConsigneeEdit = (consigneeId) => {
</div>
</div>
</QCard>
<QPageSticky :offset="[18, 18]">
<QBtn
@click.stop="toCustomerConsigneeCreate()"
color="primary"
fab
icon="add"
/>
<QTooltip>
{{ t('New consignee') }}
</QTooltip>
</QPageSticky>
</template>

error que no pertenece a esta linea, pero sí al fichero:
En la linea
<QIcon name="star" size="md" color="primary" />
se muestra el icono de la estrella, debe estar marcado si el campos isDefaultAddress es <> false
se puede observar un ejemplo en http://localhost:5000/#!/client/1110/address/index

error que no pertenece a esta linea, pero sí al fichero: En la linea `<QIcon name="star" size="md" color="primary" />` se muestra el icono de la estrella, debe estar marcado si el campos isDefaultAddress es <> false se puede observar un ejemplo en http://localhost:5000/#!/client/1110/address/index

Corregido: 86199d8197

Corregido: 86199d8197

@jgallego Yo lo he visto OK

@jgallego Yo lo he visto OK
</VnPaginate>
</QCard>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="toCustomerConsigneeCreate()" color="primary" fab icon="add" />
<QTooltip>
{{ t('New consignee') }}
</QTooltip>
</QPageSticky>
</template>
<style lang="scss" scoped>

View File

@ -0,0 +1,3 @@
<template>
<div class="flex justify-center">Customer credit contracts</div>
</template>

View File

@ -0,0 +1,3 @@
<template>
<div class="flex justify-center">Customer credit opinion</div>
</template>

View File

@ -1,22 +1,24 @@
<script setup>
import { ref, computed, onBeforeMount, onMounted } from 'vue';
import { ref, computed, onBeforeMount } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { date, QBtn } from 'quasar';
import { toCurrency, toDate } from 'src/filters';
import { toCurrency } from 'src/filters';
import { useArrayData } from 'composables/useArrayData';
import { useStateStore } from 'stores/useStateStore';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const stateStore = useStateStore();
const arrayData = ref(null);
const workerId = ref(0);
const rows = computed(() => arrayData.value.store.data);
onBeforeMount(async () => {
const filter = {
@ -29,7 +31,7 @@ onBeforeMount(async () => {
},
},
],
where: { clientFk: '1' },
where: { clientFk: `${route.params.id}` },
order: ['created DESC'],
limit: 20,
};
@ -41,16 +43,6 @@ onBeforeMount(async () => {
stateStore.rightDrawer = true;
});
onMounted(() => {
const filteredColumns = columns.value.filter(
(col) => col.name !== 'actions' && col.name !== 'customerStatus'
);
allColumnNames.value = filteredColumns.map((col) => col.name);
});
const rows = computed(() => arrayData.value.store.data);
const allColumnNames = ref([]);
const tableColumnComponents = {
created: {
component: 'span',

View File

@ -1,3 +1,202 @@
<script setup>
import { ref, computed, onBeforeMount } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { date, QBtn } from 'quasar';
import { useArrayData } from 'composables/useArrayData';
import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'src/filters';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const stateStore = useStateStore();
const arrayData = ref(null);
const totalAmount = ref(0);
const workerId = ref(0);
const rows = computed(() => arrayData.value.store.data);
onBeforeMount(async () => {
const filter = {
include: [
{
relation: 'greugeType',
scope: {
fields: ['id', 'name'],
},
},
{
relation: 'user',
scope: {
fields: ['id', 'name'],
},
},
],
order: 'shipped DESC, amount',
where: {
clientFk: `${route.params.id}`,
},
limit: 20,
};
arrayData.value = useArrayData('CustomerGreugesCard', {
url: 'greuges',
filter,
});
await arrayData.value.fetch({ append: false });
totalAmount.value = arrayData.value.store.data.reduce((accumulator, currentValue) => {
return accumulator + currentValue.amount;
}, 0);
stateStore.rightDrawer = true;
});
const tableColumnComponents = {
date: {
component: 'span',
props: () => {},
event: () => {},
},
createdBy: {
component: QBtn,
props: () => ({ flat: true, color: 'blue' }),
event: (prop) => {
selectWorkerId(prop.row.clientFk);
},
},
comment: {
component: 'span',
props: () => {},
event: () => {},
},
type: {
jsegarra marked this conversation as resolved Outdated

Duda, cuando actualicemos con dev no tendremos conflicto?

Duda, cuando actualicemos con dev no tendremos conflicto?

Se reemplazo toDateHourMinSec por las nuevas utils ubicadas en date.js

Commit: 73ea49df63

Se reemplazo `toDateHourMinSec` por las nuevas utils ubicadas en `date.js` Commit: https://gitea.verdnatura.es/verdnatura/salix-front/commit/73ea49df6340e32cc035ac132e666c4be2d1fa27
component: 'span',
props: () => {},
event: () => {},
},
amount: {
component: 'span',
props: () => {},
event: () => {},
},
};
const columns = computed(() => [
{
align: 'left',
field: 'shipped',
label: t('Date'),
name: 'date',
format: (value) => date.formatDate(value, 'DD/MM/YYYY hh:mm:ss'),
},
{
align: 'left',
field: (value) => value.user.name,
label: t('Created by'),
name: 'createdBy',
},
{
align: 'left',
field: 'description',
label: t('Comment'),
name: 'comment',
},
{
align: 'left',
field: (value) => value.greugeType.name,
label: t('Type'),
name: 'type',
},
{
align: 'left',
field: 'amount',
label: t('Amount'),
name: 'amount',
format: (value) => toCurrency(value),
},
]);
const selectWorkerId = (id) => {
workerId.value = id;
};
const toCustomerGreugeCreate = () => {
router.push({ name: 'CustomerGreugeCreate' });
};
</script>
<template>
<div class="flex justify-center">Greuges</div>
<QPage class="column items-center q-pa-md">
<QCard class="full-width" v-if="totalAmount">
<h6 class="flex justify-end q-my-lg q-pr-lg">
<span class="label-color q-mr-md">{{ t('Total') }}:</span>
{{ toCurrency(totalAmount) }}
</h6>
</QCard>
<QTable
:columns="columns"
:pagination="{ rowsPerPage: 12 }"
:rows="rows"
class="full-width q-mt-md"
row-key="id"
v-if="rows?.length"
>
<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)"
>
{{ props.value }}
<WorkerDescriptorProxy :id="workerId" />
</component>
</QTr>
</QTd>
</template>
</QTable>
<QCard class="full-width" v-else>
<h5 class="flex justify-center label-color">
{{ t('globals.noResults') }}
</h5>
</QCard>
</QPage>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="toCustomerGreugeCreate()" color="primary" fab icon="add" />
<QTooltip>
{{ t('New greuge') }}
</QTooltip>
</QPageSticky>
</template>
<style lang="scss">
.consignees-card {
border: 2px solid var(--vn-light-gray);
border-radius: 10px;
padding: 10px;
}
.label-color {
color: var(--vn-label);
}
</style>
<i18n>
es:
Total: Total
Date: Fecha
Created by: Creado por
Comment: Comentario
Type: Tipo
Amount: Importe
New greuge: Nuevo greuge
</i18n>

View File

@ -60,7 +60,7 @@ const toCustomerNoteCreate = () => {
<QPageSticky :offset="[18, 18]">
<QBtn
@click.stop="toCustomerConsigneeCreate()"
@click.stop="toCustomerNoteCreate()"
color="primary"
fab
icon="add"

View File

@ -1,3 +1,157 @@
<script setup>
import { ref, computed, onBeforeMount } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { date, QBtn } from 'quasar';
import { useArrayData } from 'composables/useArrayData';
import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'src/filters';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const stateStore = useStateStore();
const arrayData = ref(null);
const workerId = ref(0);
const rows = computed(() => arrayData.value.store.data);
onBeforeMount(async () => {
const filter = {
where: { clientFk: `${route.params.id}` },
order: ['started DESC'],
limit: 20,
};
arrayData.value = useArrayData('CustomerRecoveriesCard', {
url: 'Recoveries',
filter,
});
await arrayData.value.fetch({ append: false });
stateStore.rightDrawer = true;
});
const tableColumnComponents = {
since: {
component: 'span',
props: () => {},
event: () => {},
},
to: {
component: 'span',
props: () => {},
event: () => {},
},
amount: {
component: 'span',
props: () => {},
event: () => {},
},
period: {
component: 'span',
props: () => {},
event: () => {},
},
};
const columns = computed(() => [
{
align: 'left',
field: 'started',
label: t('Since'),
name: 'since',
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
},
{
align: 'left',
field: 'finished',
label: t('To'),
name: 'to',
format: (value) => date.formatDate(value, 'DD/MM/YYYY'),
},
{
align: 'left',
field: 'amount',
label: t('Amount'),
name: 'amount',
format: (value) => toCurrency(value),
},
{
align: 'left',
field: 'period',
label: t('Period'),
name: 'period',
},
]);
const toCustomerRecoverieCreate = () => {
router.push({ name: 'CustomerRecoverieCreate' });
};
</script>
<template>
<div class="flex justify-center">Recoveries</div>
<QPage class="column items-center q-pa-md">
<QTable
:columns="columns"
:pagination="{ rowsPerPage: 12 }"
:rows="rows"
class="full-width q-mt-md"
row-key="id"
v-if="rows?.length"
>
<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)"
>
{{ props.value }}
<WorkerDescriptorProxy :id="workerId" />
</component>
</QTr>
</QTd>
</template>
</QTable>
<QCard class="full-width" v-else>
<h5 class="flex justify-center label-color">
{{ t('globals.noResults') }}
</h5>
</QCard>
</QPage>
<QPageSticky :offset="[18, 18]">
<QBtn @click.stop="toCustomerRecoverieCreate()" color="primary" fab icon="add" />
<QTooltip>
{{ t('New recoverie') }}
</QTooltip>
</QPageSticky>
</template>
<style lang="scss">
.consignees-card {
border: 2px solid var(--vn-light-gray);
border-radius: 10px;
padding: 10px;
}
.label-color {
color: var(--vn-label);
}
</style>
<i18n>
es:
Since: Desde
To: Hasta
Amount: Importe
Period: Periodo
New recoverie: Nuevo recobro
</i18n>

View File

@ -1,3 +1,69 @@
<script setup>
jsegarra marked this conversation as resolved
Review

Falta botón de cambiar contraseña
Los campos no son clearables

Falta botón de cambiar contraseña Los campos no son clearables
Review

Corregido: c0a9835e80

Corregido: c0a9835e80
Review

Aparece el botón de cambiar contraseña, sin embargo, el formato del layout no es el estándar

Aparece el botón de cambiar contraseña, sin embargo, el formato del layout no es el estándar
Review

Corregido: ebd1ee07f4

Corregido: ebd1ee07f4
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n();
const route = useRoute();
const filter = { where: { id: `${route.params.id}` } };
</script>
<template>
<div class="flex justify-center">Web access</div>
<FormModel

desde salix http://localhost:9000/#/customer/1101/web-access cambio BruceWayne por BruceWayne4 y funciona, desde http://localhost:9000/#/customer/1101/web-access me da dos errores

message
"ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE id=1101' at line 1"
name
"Error"
sql

"UPDATE account.user SET WHERE id=1101"

Parece que en el set falta el name = xx

desde salix http://localhost:9000/#/customer/1101/web-access cambio BruceWayne por BruceWayne4 y funciona, desde http://localhost:9000/#/customer/1101/web-access me da dos errores message : "ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `id`=1101' at line 1" name : "Error" sql : "UPDATE `account`.`user` SET WHERE `id`=1101" Parece que en el set falta el name = xx

Corregido: 5e2c668fec

Corregido: 5e2c668fec

Yo lo he visto OK

Yo lo he visto OK
:filter="filter"
:observe-form-changes="false"
:url-update="`Clients/${route.params.id}/updateUser`"
:url="'VnUsers/preview'"
model="client"
>
<template #form="{ data }">
<div
v-for="(item, index) in data"
:key="index"
:class="{
'q-mb-md': index < data.length - 1,
}"
>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<QCheckbox
:label="t('Enable web access')"
v-model="item.active"
/>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput :label="t('User')" v-model="item.name" />
</div>
<div class="col">
<VnInput :label="t('Recovery email')" v-model="item.email">
<template #append>
<QIcon name="info" class="cursor-pointer">
<QTooltip>{{
t(
'This email is used for user to regain access their account'
)
}}</QTooltip>
</QIcon>
</template>
</VnInput>
</div>
</VnRow>
</div>
</template>
</FormModel>
</template>
<i18n>
es:
Enable web access: Habilitar acceso web
User: Usuario
Recovery email: Correo de recuperacion
This email is used for user to regain access their account: Este correo electrónico se usa para que el usuario recupere el acceso a su cuenta
</i18n>

View File

@ -12,7 +12,7 @@ import VnInput from 'src/components/common/VnInput.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import VnSelectCreate from 'src/components/common/VnSelectCreate.vue';
import CustomerCreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue';
import CustomsNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
const { t } = useI18n();
const route = useRoute();
@ -233,7 +233,7 @@ const refreshData = () => {
v-model="data.customsAgentFk"
>
<template #form>
<CustomsNewCustomsAgent @on-data-saved="refreshData()" />
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
</template>
</VnSelectCreate>
</div>

View File

@ -0,0 +1,93 @@
<script setup>
jsegarra marked this conversation as resolved
Review

El worker descriptor no va bien, porque usa clientFk en vez de worker, ya hay un comentario similar.
El campo/ valor de fecha no coincide...induce a error.
Las validaciones no se están aplicando

El worker descriptor no va bien, porque usa clientFk en vez de worker, ya hay un comentario similar. El campo/ valor de fecha no coincide...induce a error. Las validaciones no se están aplicando
Review

Corregido: 11eb597fa3

Corregido: 11eb597fa3
Review

Está OK.
Por mi parte queda comprobar si ha habido cambio de criterio en el WorkerDescriptorProxy

Está OK. Por mi parte queda comprobar si ha habido cambio de criterio en el WorkerDescriptorProxy
import { onMounted, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const initialData = reactive({
amount: null,
description: null,
greugeTypeFk: null,
shipped: '2001-01-01T11:00:00.000Z',
});
const greugeTypes = ref([]);
onMounted(() => {
initialData.clientFk = `${route.params.id}`;
});
const toCustomerGreuges = () => {
router.push({
name: 'CustomerGreuges',
params: {
id: route.params.id,
},
});
};
</script>
<template>
<fetch-data @on-fetch="(data) => (greugeTypes = data)" auto-load url="greugeTypes" />
<FormModel
:form-initial-data="initialData"
:observe-form-changes="false"
@on-data-saved="toCustomerGreuges()"
model="client"
url-create="Greuges"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput :label="t('Amount')" type="number" v-model="data.amount" />
</div>
<div class="col">
<VnInputDate :label="t('Date')" v-model="data.shipped" />
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput :label="t('Comment')" v-model="data.description" />
</div>
<div class="col">
<VnSelectFilter
:label="t('Type')"
:options="greugeTypes"
hide-selected
option-label="name"
option-value="id"
v-model="data.greugeTypeFk"
/>
</div>
</VnRow>
</template>
</FormModel>
</template>
<style lang="scss" scoped>
.add-icon {
cursor: pointer;
background-color: $primary;
border-radius: 50px;
}
</style>
<i18n>
es:
Amount: Importe
Date: Fecha
Comment: Comentario
Type: Tipo
</i18n>

View File

@ -0,0 +1,286 @@
<script setup>
import { onBeforeMount, reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n();
const route = useRoute();
const $props = defineProps({
companyId: {
type: Number,
required: true,
},
totalCredit: {
type: Number,
required: true,
},
promise: {
type: Function,
required: true,
},
});
const closeButton = ref(null);
const urlCreate = ref([]);
const companyOptions = ref([]);
const bankOptions = ref([]);
const clientFindOne = ref([]);
const deliveredAmount = ref(null);
const amountToReturn = ref(null);
const viewRecipt = ref(true);
const sendEmail = ref(false);
const isLoading = ref(false);
const filterBanks = {
fields: ['id', 'bank', 'accountingTypeFk'],
include: { relation: 'accountingType' },
order: 'id',
limit: 30,
};
const filterClientFindOne = {
fields: ['email'],
where: {
id: `${route.params.id}`,
},
};
const initialData = reactive({
amountPaid: $props.totalCredit,
bankFk: null,
clientFk: `${route.params.id}`,
companyFk: $props.companyId,
compensationAccount: null,
description: null,
email: clientFindOne.value.email,
payed: null,
});
onBeforeMount(() => {
urlCreate.value = `Clients/${route.params.id}/createReceipt`;
});
const setPaymentType = (id) => {
initialData.payed = '2001-01-01T11:00:00.000Z';
if (id === 1) initialData.description = 'Credit card';
if (id === 2) initialData.description = 'Cash';
if (id === 3 || id === 3117) initialData.description = '';
if (id === 4) initialData.description = 'Transfer';
};
const calculateFromAmount = (event) => {
amountToReturn.value = parseFloat(event) * -1 + parseFloat(deliveredAmount.value);
};
const calculateFromDeliveredAmount = (event) => {
amountToReturn.value = parseFloat($props.totalCredit) * -1 + parseFloat(event);
};
const setClientEmail = (data) => {
initialData.email = data.email;
};
const onDataSaved = async () => {
isLoading.value = true;
if ($props.promise) {
try {
await $props.promise();
} finally {
isLoading.value = false;
if (closeButton.value) closeButton.value.click();
}
}
};
</script>
<template>
<QDialog ref="dialogRef">
<fetch-data
@on-fetch="(data) => (companyOptions = data)"
auto-load
url="Companies"
/>
<fetch-data
:filter="filterBanks"
@on-fetch="(data) => (bankOptions = data)"
auto-load
url="Banks"
/>
<fetch-data
:filter="filterClientFindOne"
@on-fetch="setClientEmail"
auto-load
url="Clients/findOne"
/>
<FormModel
:default-actions="false"
:form-initial-data="initialData"
:observe-form-changes="false"
:url-create="urlCreate"
@on-data-saved="onDataSaved()"
>
<template #form="{ data }">
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
<QIcon name="close" size="sm" />
</span>
<h5 class="flex justify-center q-mt-xs">
{{ t('New payment') }}
</h5>
jsegarra marked this conversation as resolved Outdated

Porqué está en el centro si el resto de dialogos si el resto está a un lateral?

Porqué está en el centro si el resto de dialogos si el resto está a un lateral?

Corregido: 3cf3687b84

Corregido: 3cf3687b84
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInputDate
:label="t('Date')"
jsegarra marked this conversation as resolved
Review

Los campos no son clearables

Los campos no son clearables
Review

Corregido: 7f1c4690e8

Corregido: 7f1c4690e8
:required="true"
v-model="data.payed"
/>
</div>
<div class="col">
<VnSelectFilter
:label="t('Company')"
:options="companyOptions"
:required="true"
hide-selected
option-label="code"
option-value="id"
v-model="data.companyFk"
/>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnSelectFilter
:label="t('Bank')"
:options="bankOptions"
:required="true"
@update:model-value="setPaymentType($event)"
hide-selected
option-label="bank"
option-value="id"
v-model="data.bankFk"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt.id }}:&ensp;{{ scope.opt.bank }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
</div>
<div class="col">
<VnInput
:label="t('Amount')"
:required="true"
@update:model-value="calculateFromAmount($event)"
type="number"
v-model.number="data.amountPaid"
/>
</div>
</VnRow>
<div class="text-h6" v-if="data.bankFk === 3 || data.bankFk === 3117">
{{ t('Compensation') }}
</div>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col" v-if="data.bankFk === 3 || data.bankFk === 3117">
<VnInput
:label="t('Compensation account')"
v-model="data.compensationAccount"
/>
</div>
<div class="col">
<VnInput
:label="t('Reference')"
:required="true"
v-model="data.description"
/>
</div>
</VnRow>
<div class="q-mt-lg" v-if="data.bankFk === 2">
<div class="text-h6">{{ t('Cash') }}</div>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput
:label="t('Delivered amount')"
@update:model-value="calculateFromDeliveredAmount($event)"
type="number"
v-model="deliveredAmount"
/>
</div>
<div class="col">
<VnInput
:label="t('Amount to return')"
disable
type="number"
v-model="amountToReturn"
/>
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<QCheckbox v-model="viewRecipt" />
</div>
<div class="col">
<QCheckbox v-model="sendEmail" />
</div>
</VnRow>
</div>
<div class="q-mt-lg row justify-end">
<QBtn
:disabled="isLoading"
:label="t('globals.cancel')"
:loading="isLoading"
class="q-ml-sm"
color="primary"
flat
type="reset"
v-close-popup
/>
<QBtn
:disabled="isLoading"
:label="t('globals.save')"
:loading="isLoading"
color="primary"
type="submit"
/>
</div>
</template>
</FormModel>
</QDialog>
</template>
<i18n>
es:
New payment: Añadir pago
Date: Fecha
Company: Empresa
Bank: Caja
Amount: Importe
Reference: Referencia
Cash: Efectivo
Delivered amount: Cantidad entregada
Amount to return: Cantidad a devolver
View recipt: Ver recibido
Send email: Enviar correo
Compensation: Compensación
Compensation account: Cuenta para compensar
</i18n>

View File

@ -32,8 +32,8 @@ const toCustomerNotes = () => {
<FormModel
:form-initial-data="initialData"
:observe-form-changes="false"
url-create="ClientObservations"
@on-data-saved="toCustomerNotes()"
url-create="ClientObservations"
jsegarra marked this conversation as resolved
Review

@alexm VnNotes??

@alexm VnNotes??
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">

View File

@ -0,0 +1,72 @@
<script setup>
import { onMounted, reactive } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const initialData = reactive({
started: '2001-01-01T11:00:00.000Z',
finished: null,
amount: null,
period: null,
});
onMounted(() => {
initialData.clientFk = `${route.params.id}`;
});
const toCustomerRecoveries = () => {
router.push({
name: 'CustomerRecoveries',
params: {
id: route.params.id,
},
});
};
</script>
<template>
<FormModel
:form-initial-data="initialData"
:observe-form-changes="false"
@on-data-saved="toCustomerRecoveries()"
model="client"
url-create="Recoveries"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInputDate :label="t('Since')" v-model="data.started" />
</div>
<div class="col">
<VnInputDate :label="t('To')" v-model="data.finished" />
</div>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<div class="col">
<VnInput :label="t('Amount')" type="number" v-model="data.amount" />
</div>
<div class="col">
<VnInput :label="t('Period')" type="number" v-model="data.period" />
</div>
</VnRow>
</template>
</FormModel>
</template>
<i18n>
es:
Since: Desde
To: Hasta
Amount: Importe
Period: Periodo
</i18n>

View File

@ -71,8 +71,8 @@ const routeFilter = {
};
const onSave = (data, response) => {
if (isNew) {
axios.post(`Routes/${response.data?.id}/updateWorkCenter`);
router.push({ name: 'RouteSummary', params: { id: response.data?.id } });
axios.post(`Routes/${response?.id}/updateWorkCenter`);
router.push({ name: 'RouteSummary', params: { id: response?.id } });
}
};
</script>

View File

@ -15,11 +15,13 @@ import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
import { useQuasar } from 'quasar';
import RouteSummaryDialog from 'pages/Route/Card/RouteSummaryDialog.vue';
import {useSession} from "composables/useSession";
const stateStore = useStateStore();
const { t } = useI18n();
const { validate } = useValidator();
const quasar = useQuasar();
const session = useSession();
const to = Date.vnNew();
to.setDate(to.getDate() + 1);
@ -149,6 +151,23 @@ const cloneRoutes = () => {
startingDate.value = null;
};
const showRouteReport = () => {
const ids = selectedRows.value.map(row => row?.id)
const idString = ids.join(',')
let url;
if (selectedRows.value.length <= 1) {
url = `api/Routes/${idString}/driver-route-pdf?access_token=${session.getToken()}`;
} else {
const params = new URLSearchParams({
access_token: session.getToken(),
id: idString
})
url = `api/Routes/downloadZip?${params.toString()}`;
}
window.open(url, '_blank');
}
const markAsServed = () => {
selectedRows.value.forEach((row) => {
if (row?.id) {
@ -206,7 +225,6 @@ function previewRoute(id) {
autofocus
/>
</QCardSection>
<!-- TODO: Add report -->
<QCardActions align="right">
<QBtn flat :label="t('Cancel')" v-close-popup class="text-primary" />
<QBtn color="primary" v-close-popup @click="cloneRoutes">
@ -239,7 +257,15 @@ function previewRoute(id) {
>
<QTooltip>{{ t('Clone Selected Routes') }}</QTooltip>
</QBtn>
<QBtn
icon="cloud_download"
color="primary"
class="q-mr-sm"
:disable="!selectedRows?.length"
@click="showRouteReport"
>
<QTooltip>{{ t('Download selected routes as PDF') }}</QTooltip>
</QBtn>
<QBtn
icon="check"
color="primary"
@ -527,4 +553,5 @@ es:
Cancel: Cancelar
Clone: Clonar
Mark as served: Marcar como servidas
Download selected routes as PDF: Descargar rutas seleccionadas como PDF
</i18n>

View File

@ -363,7 +363,6 @@ onMounted(async () => {
</template>
</VnSelectCreate>
</VnRow>
<pre>{{ data }}</pre>
</template>
</FormModel>
</QPage>

View File

@ -254,13 +254,31 @@ export default {
},
{
path: 'greuges',
name: 'CustomerGreuges',
meta: {
title: 'greuges',
icon: 'vn:greuge',
},
component: () =>
import('src/pages/Customer/Card/CustomerGreuges.vue'),
name: 'GreugesCard',
redirect: { name: 'CustomerGreuges' },
children: [
{
path: '',
name: 'CustomerGreuges',
meta: {
title: 'greuges',
icon: 'vn:greuge',
},
component: () =>
import('src/pages/Customer/Card/CustomerGreuges.vue'),
},
{
path: 'create',
name: 'CustomerGreugeCreate',
meta: {
title: 'greuge-create',
},
component: () =>
import(
'src/pages/Customer/components/CustomerGreugeCreate.vue'
),
},
],
},
{
path: 'balance',
@ -274,13 +292,31 @@ export default {
},
{
path: 'recoveries',
name: 'CustomerRecoveries',
meta: {
title: 'recoveries',
icon: 'vn:recovery',
},
component: () =>
import('src/pages/Customer/Card/CustomerRecoveries.vue'),
name: 'RecoveriesCard',
redirect: { name: 'CustomerRecoveries' },
children: [
{
path: '',
name: 'CustomerRecoveries',
meta: {
title: 'recoveries',
icon: 'vn:recovery',
},
component: () =>
import('src/pages/Customer/Card/CustomerRecoveries.vue'),
},
{
path: 'create',
name: 'CustomerRecoverieCreate',
meta: {
title: 'recoverie-create',
},
component: () =>
import(
'src/pages/Customer/components/CustomerRecoverieCreate.vue'
),
},
],
},
{
path: 'web-access',
@ -316,10 +352,49 @@ export default {
meta: {
title: 'creditManagement',
icon: 'paid',
menuChildren: [
{
name: 'CustomerCreditContracts',
title: 'creditContracts',
icon: 'paid',
},
{
name: 'CustomerCreditOpinion',
title: 'creditOpinion',
icon: 'paid',
},
],
},
component: () =>
import('src/pages/Customer/Card/CustomerCreditManagement.vue'),
children: [
{
path: 'credit-contracts',
name: 'CustomerCreditContracts',
meta: {
title: 'creditContracts',
icon: 'paid',
},
component: () =>
import(
'src/pages/Customer/Card/CustomerCreditContracts.vue'
),
},
{
path: 'credit-opinion',
name: 'CustomerCreditOpinion',
meta: {
title: 'creditOpinion',
icon: 'paid',
},
component: () =>
import(
'src/pages/Customer/Card/CustomerCreditOpinion.vue'
),
},
],
},
{
path: 'others',
name: 'CustomerOthers',

View File

@ -52,13 +52,20 @@ export const useNavigationStore = defineStore('navigationStore', () => {
function addMenuItem(module, route, parent) {
const { meta } = route;
let { menuChildren = null } = meta;
if (menuChildren)
menuChildren = menuChildren.map(({ name, title, icon }) => ({
name,
icon,
title: `${module}.pageTitles.${title}`,
}));
if (meta && meta.roles && role.hasAny(meta.roles) === false) return;
const item = {
name: route.name,
children: menuChildren,
};
if (meta) {
item.title = `${module}.pageTitles.${meta.title}`;
item.icon = meta.icon;