HOTFIX #8217 Update Customer Credit #986
|
@ -10,6 +10,7 @@ import VnPaginate from 'components/ui/VnPaginate.vue';
|
|||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import SkeletonTable from 'components/ui/SkeletonTable.vue';
|
||||
import { tMobile } from 'src/composables/tMobile';
|
||||
import getDifferences from 'src/filters/getDifferences';
|
||||
|
||||
const { push } = useRouter();
|
||||
const quasar = useQuasar();
|
||||
|
@ -268,28 +269,6 @@ function getChanges() {
|
|||
return changes;
|
||||
}
|
||||
|
||||
function getDifferences(obj1, obj2) {
|
||||
let diff = {};
|
||||
delete obj1.$index;
|
||||
delete obj2.$index;
|
||||
|
||||
for (let key in obj1) {
|
||||
if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
for (let key in obj2) {
|
||||
if (
|
||||
obj1[key] === undefined ||
|
||||
JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])
|
||||
) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
function isEmpty(obj) {
|
||||
if (obj == null) return true;
|
||||
if (obj === undefined) return true;
|
||||
|
|
|
@ -106,6 +106,7 @@ const originalData = ref({});
|
|||
const formData = computed(() => state.get(modelValue));
|
||||
const defaultButtons = computed(() => ({
|
||||
save: {
|
||||
dataCy: 'saveDefaultBtn',
|
||||
color: 'primary',
|
||||
icon: 'save',
|
||||
label: 'globals.save',
|
||||
|
@ -113,6 +114,7 @@ const defaultButtons = computed(() => ({
|
|||
type: 'submit',
|
||||
},
|
||||
reset: {
|
||||
dataCy: 'resetDefaultBtn',
|
||||
color: 'primary',
|
||||
icon: 'restart_alt',
|
||||
label: 'globals.reset',
|
||||
|
@ -203,7 +205,9 @@ async function save() {
|
|||
isLoading.value = true;
|
||||
try {
|
||||
formData.value = trimData(formData.value);
|
||||
const body = $props.mapper ? $props.mapper(formData.value) : formData.value;
|
||||
const body = $props.mapper
|
||||
? $props.mapper(formData.value, originalData.value)
|
||||
: formData.value;
|
||||
const method = $props.urlCreate ? 'post' : 'patch';
|
||||
const url =
|
||||
$props.urlCreate || $props.urlUpdate || $props.url || arrayData.store.url;
|
||||
|
@ -317,6 +321,7 @@ defineExpose({
|
|||
:title="t(defaultButtons.reset.label)"
|
||||
/>
|
||||
<QBtnDropdown
|
||||
data-cy="saveAndContinueDefaultBtn"
|
||||
v-if="$props.goTo"
|
||||
@click="saveAndGo"
|
||||
:label="tMobile('globals.saveAndContinue')"
|
||||
|
|
|
@ -101,6 +101,7 @@ onBeforeRouteLeave((to, from, next) => {
|
|||
@click="insert"
|
||||
class="q-mb-xs"
|
||||
dense
|
||||
data-cy="saveNote"
|
||||
/>
|
||||
</template>
|
||||
</VnInput>
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
export default function getDifferences(obj1, obj2) {
|
||||
let diff = {};
|
||||
delete obj1.$index;
|
||||
delete obj2.$index;
|
||||
|
||||
for (let key in obj1) {
|
||||
if (obj2[key] && JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
for (let key in obj2) {
|
||||
if (
|
||||
obj1[key] === undefined ||
|
||||
JSON.stringify(obj1[key]) !== JSON.stringify(obj2[key])
|
||||
) {
|
||||
diff[key] = obj2[key];
|
||||
}
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export default function getUpdatedValues(keys, formData) {
|
||||
return keys.reduce((acc, key) => {
|
||||
acc[key] = formData[key];
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
|
@ -11,11 +11,15 @@ import dashIfEmpty from './dashIfEmpty';
|
|||
import dateRange from './dateRange';
|
||||
import toHour from './toHour';
|
||||
import dashOrCurrency from './dashOrCurrency';
|
||||
import getDifferences from './getDifferences';
|
||||
import getUpdatedValues from './getUpdatedValues';
|
||||
import getParamWhere from './getParamWhere';
|
||||
import parsePhone from './parsePhone';
|
||||
import isDialogOpened from './isDialogOpened';
|
||||
|
||||
export {
|
||||
getUpdatedValues,
|
||||
getDifferences,
|
||||
isDialogOpened,
|
||||
parsePhone,
|
||||
toLowerCase,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { onBeforeMount, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
|
@ -52,7 +53,6 @@ const addressFilter = {
|
|||
|
||||
onBeforeMount(() => {
|
||||
const { id } = route.params;
|
||||
getAddressesData(id);
|
||||
getClientData(id);
|
||||
jsegarra marked this conversation as resolved
Outdated
|
||||
});
|
||||
|
||||
|
@ -60,23 +60,10 @@ watch(
|
|||
() => route.params.id,
|
||||
(newValue) => {
|
||||
if (!newValue) return;
|
||||
getAddressesData(newValue);
|
||||
getClientData(newValue);
|
||||
}
|
||||
);
|
||||
|
||||
const getAddressesData = async (id) => {
|
||||
try {
|
||||
const { data } = await axios.get(`Clients/${id}/addresses`, {
|
||||
params: { filter: JSON.stringify(addressFilter) },
|
||||
});
|
||||
addresses.value = data;
|
||||
sortAddresses();
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
const getClientData = async (id) => {
|
||||
try {
|
||||
const { data } = await axios.get(`Clients/${id}`);
|
||||
|
@ -101,9 +88,9 @@ const setDefault = (address) => {
|
|||
});
|
||||
};
|
||||
|
||||
const sortAddresses = () => {
|
||||
if (!client.value || !addresses.value) return;
|
||||
addresses.value = addresses.value.sort((a, b) => {
|
||||
const sortAddresses = (data) => {
|
||||
if (!client.value || !data) return;
|
||||
addresses.value = data.sort((a, b) => {
|
||||
return isDefaultAddress(b) - isDefaultAddress(a);
|
||||
});
|
||||
};
|
||||
|
@ -124,8 +111,17 @@ const toCustomerAddressEdit = (addressId) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
@on-fetch="sortAddresses"
|
||||
auto-load
|
||||
data-key="CustomerAddresses"
|
||||
order="id DESC"
|
||||
ref="vnPaginateRef"
|
||||
:filter="addressFilter"
|
||||
:url="`Clients/${route.params.id}/addresses`"
|
||||
/>
|
||||
alexm
commented
Ahora tiene un VnPaginate? Ahora tiene un VnPaginate?
jsegarra
commented
Me parece "rudimentario" dejar el codigo como estaba y preferia usar componentes nuestros. Me parece "rudimentario" dejar el codigo como estaba y preferia usar componentes nuestros.
Sin embargo, veo que el VnPagiante no tiene contenido, pero el resultado es el mismo
Voy a cambiarlo por FetchData
|
||||
<div class="full-width flex justify-center">
|
||||
<QCard class="card-width q-pa-lg" v-if="addresses.length">
|
||||
<QCard class="card-width q-pa-lg">
|
||||
<QCardSection>
|
||||
<div
|
||||
v-for="(item, index) in addresses"
|
||||
|
|
|
@ -9,6 +9,7 @@ import VnRow from 'components/ui/VnRow.vue';
|
|||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -30,6 +31,13 @@ const exprBuilder = (param, value) => {
|
|||
and: [{ active: { neq: false } }, handleSalesModelValue(value)],
|
||||
};
|
||||
};
|
||||
|
||||
function onBeforeSave(formData, originalData) {
|
||||
return getUpdatedValues(
|
||||
Object.keys(getDifferences(formData, originalData)),
|
||||
formData
|
||||
);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
|
@ -43,7 +51,12 @@ const exprBuilder = (param, value) => {
|
|||
@on-fetch="(data) => (businessTypes = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FormModel :url="`Clients/${route.params.id}`" auto-load model="customer">
|
||||
<FormModel
|
||||
:url="`Clients/${route.params.id}`"
|
||||
auto-load
|
||||
model="customer"
|
||||
:mapper="onBeforeSave"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnInput
|
||||
|
@ -94,6 +107,7 @@ const exprBuilder = (param, value) => {
|
|||
:rules="validate('client.phone')"
|
||||
clearable
|
||||
v-model="data.phone"
|
||||
data-cy="customerPhone"
|
||||
/>
|
||||
<VnInput
|
||||
:label="t('customer.summary.mobile')"
|
||||
|
|
|
@ -28,12 +28,7 @@ const getBankEntities = (data, formData) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<FormModel
|
||||
:url-update="`Clients/${route.params.id}`"
|
||||
:url="`Clients/${route.params.id}/getCard`"
|
||||
auto-load
|
||||
model="customer"
|
||||
>
|
||||
<FormModel :url-update="`Clients/${route.params.id}`" auto-load model="customer">
|
||||
alexm
commented
En salix usaba :url=" En salix usaba :url="`Clients/${route.params.id}/getCard`" dado que venia del card
jsegarra
commented
Pero el tema está en que CustomerDescriptor no muestra la misma info siempre. Segun la seccion en la que estes muestra o esconde iconos. Pero el tema está en que CustomerDescriptor no muestra la misma info siempre. Segun la seccion en la que estes muestra o esconde iconos.
De esta manera no he encontrado fallos en el customer 1109
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
|
|
|
@ -93,22 +93,6 @@ const columns = computed(() => [
|
|||
<WorkerDescriptorProxy :id="row.worker.id" />
|
||||
</template>
|
||||
</VnTable>
|
||||
<!-- <QTable
|
||||
alexm
commented
Comentado? Comentado?
jsegarra
commented
Parece que es asi como estaba antes cuando se fusionó la #136 pero ahora se ha quitado Parece que es asi como estaba antes cuando se fusionó la #136 pero ahora se ha quitado
alexm
commented
Comentado? Comentado?
|
||||
:columns="columns"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
:rows="rows"
|
||||
hide-bottom
|
||||
row-key="id"
|
||||
v-model:selected="selected"
|
||||
class="card-width q-px-lg"
|
||||
>
|
||||
<template #body-cell-employee="{ row }">
|
||||
<QTd @click.stop>
|
||||
<span class="link">{{ row.worker.user.nickname }}</span>
|
||||
<WorkerDescriptorProxy :id="row.clientFk" />
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable> -->
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -36,7 +36,10 @@ const entityId = computed(() => {
|
|||
});
|
||||
|
||||
const data = ref(useCardDescription());
|
||||
const setData = (entity) => (data.value = useCardDescription(entity?.name, entity?.id));
|
||||
const setData = (entity) => {
|
||||
data.value = useCardDescription(entity?.name, entity?.id);
|
||||
if (customer.value) customer.value.webAccess = data.value?.account?.isActive;
|
||||
alexm
commented
Donde se use, usar Donde se use, usar `data.value?.account?.isActive`
jsegarra
commented
En el icono noWeb, En el icono noWeb,
Hay veces que no se sincroniza bien con el CustomerBasicData/CustomerFiscalData
Probar con el customer 1109
|
||||
};
|
||||
const debtWarning = computed(() => {
|
||||
return customer.value?.debt > customer.value?.credit ? 'negative' : 'primary';
|
||||
});
|
||||
|
|
|
@ -34,7 +34,6 @@ function handleLocation(data, location) {
|
|||
/>
|
||||
<FormModel
|
||||
:url-update="`Clients/${route.params.id}/updateFiscalData`"
|
||||
:url="`Clients/${route.params.id}/getCard`"
|
||||
alexm
commented
En salix usaba :url=" En salix usaba :url="`Clients/${route.params.id}/getCard`" dado que venia del card
jsegarra
commented
Misma situación que en el comentario anterior Misma situación que en el comentario anterior
"Pero el tema está en que CustomerDescriptor no muestra la misma info siempre. Segun la seccion en la que estes muestra o esconde iconos.
De esta manera no he encontrado fallos en el customer 1109"
|
||||
auto-load
|
||||
model="customer"
|
||||
>
|
||||
|
|
|
@ -1,164 +1,82 @@
|
|||
<script setup>
|
||||
import { computed, onBeforeMount, ref, watch, nextTick } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import axios from 'axios';
|
||||
import useNotify from 'src/composables/useNotify';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
const formModelRef = ref(false);
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const { notify } = useNotify();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const amountInputRef = ref(null);
|
||||
const initialDated = Date.vnNew();
|
||||
const unpaidClient = ref(false);
|
||||
const isLoading = ref(false);
|
||||
const amount = ref(null);
|
||||
const dated = ref(initialDated);
|
||||
|
||||
const initialData = ref({
|
||||
dated: initialDated,
|
||||
dated: Date.vnNew(),
|
||||
amount: null,
|
||||
});
|
||||
|
||||
const hasChanged = computed(() => {
|
||||
return (
|
||||
initialData.value.dated !== dated.value ||
|
||||
initialData.value.amount !== amount.value
|
||||
);
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
getData(route.params.id);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
(newValue) => {
|
||||
if (!newValue) return;
|
||||
getData(newValue);
|
||||
}
|
||||
);
|
||||
|
||||
const getData = async (id) => {
|
||||
const filter = { where: { clientFk: id } };
|
||||
try {
|
||||
const { data } = await axios.get('ClientUnpaids', {
|
||||
params: { filter: JSON.stringify(filter) },
|
||||
});
|
||||
if (data.length) {
|
||||
setValues(data[0]);
|
||||
} else {
|
||||
defaultValues();
|
||||
}
|
||||
} catch (error) {
|
||||
defaultValues();
|
||||
}
|
||||
};
|
||||
|
||||
const setValues = (data) => {
|
||||
unpaidClient.value = true;
|
||||
amount.value = data.amount;
|
||||
dated.value = data.dated;
|
||||
initialData.value = data;
|
||||
};
|
||||
|
||||
const defaultValues = () => {
|
||||
unpaidClient.value = false;
|
||||
initialData.value.amount = null;
|
||||
setInitialData();
|
||||
};
|
||||
|
||||
const setInitialData = () => {
|
||||
amount.value = initialData.value.amount;
|
||||
dated.value = initialData.value.dated;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
isLoading.value = true;
|
||||
|
||||
const payload = {
|
||||
amount: amount.value,
|
||||
const filterClientFindOne = {
|
||||
fields: ['unpaid', 'dated', 'amount'],
|
||||
where: {
|
||||
clientFk: route.params.id,
|
||||
dated: dated.value,
|
||||
};
|
||||
try {
|
||||
await axios.patch('ClientUnpaids', payload);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
unpaidClient.value = true;
|
||||
} catch (error) {
|
||||
notify('errors.writeRequest', 'negative');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
watch(
|
||||
() => unpaidClient.value,
|
||||
async (val) => {
|
||||
await nextTick();
|
||||
if (val) amountInputRef.value.focus();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport v-if="stateStore?.isSubToolbarShown()" to="#st-actions">
|
||||
<QBtnGroup push class="q-gutter-x-sm">
|
||||
<QBtn
|
||||
:disabled="!hasChanged"
|
||||
:label="t('globals.reset')"
|
||||
:loading="isLoading"
|
||||
@click="setInitialData"
|
||||
color="primary"
|
||||
flat
|
||||
icon="restart_alt"
|
||||
type="reset"
|
||||
/>
|
||||
<QBtn
|
||||
:disabled="!hasChanged"
|
||||
:label="t('globals.save')"
|
||||
:loading="isLoading"
|
||||
@click="onSubmit"
|
||||
color="primary"
|
||||
icon="save"
|
||||
/>
|
||||
</QBtnGroup>
|
||||
</Teleport>
|
||||
|
||||
<div class="full-width flex justify-center">
|
||||
<QCard class="card-width q-pa-lg">
|
||||
<QForm>
|
||||
<FetchData
|
||||
:filter="filterClientFindOne"
|
||||
auto-load
|
||||
url="ClientUnpaids"
|
||||
@on-fetch="
|
||||
(data) => {
|
||||
const unpaid = data.length == 1;
|
||||
initialData = { ...data[0], unpaid };
|
||||
}
|
||||
"
|
||||
/>
|
||||
<QCard>
|
||||
<FormModel
|
||||
v-if="'unpaid' in initialData"
|
||||
:observe-form-changes="false"
|
||||
ref="formModelRef"
|
||||
model="unpaid"
|
||||
url-update="ClientUnpaids"
|
||||
:mapper="(formData) => ({ ...formData, clientFk: route.params.id })"
|
||||
alexm
commented
formInitialData ? formInitialData ?
jsegarra
commented
La tienes una linea mas abajo La tienes una linea mas abajo
|
||||
:form-initial-data="initialData"
|
||||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow>
|
||||
<div class="col">
|
||||
<QCheckbox :label="t('Unpaid client')" v-model="unpaidClient" />
|
||||
</div>
|
||||
<QCheckbox :label="t('Unpaid client')" v-model="data.unpaid" />
|
||||
</VnRow>
|
||||
|
||||
<VnRow class="row q-gutter-md q-mb-md" v-show="unpaidClient">
|
||||
<VnRow class="row q-gutter-md q-mb-md" v-show="data.unpaid">
|
||||
<div class="col">
|
||||
<VnInputDate :label="t('Date')" v-model="dated" />
|
||||
<VnInputDate
|
||||
data-cy="customerUnpaidDate"
|
||||
:label="t('Date')"
|
||||
v-model="data.dated"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<VnInput
|
||||
<VnInputNumber
|
||||
data-cy="customerUnpaidAmount"
|
||||
ref="amountInputRef"
|
||||
:label="t('Amount')"
|
||||
clearable
|
||||
type="number"
|
||||
v-model="amount"
|
||||
v-model="data.amount"
|
||||
autofocus
|
||||
>
|
||||
<template #append>€</template></VnInput
|
||||
<template #append>€</template></VnInputNumber
|
||||
>
|
||||
</div>
|
||||
</VnRow>
|
||||
</QForm>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</FormModel>
|
||||
</QCard>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -25,10 +25,9 @@ async function hasCustomerRole() {
|
|||
</script>
|
||||
<template>
|
||||
<FormModel
|
||||
url="VnUsers/preview"
|
||||
:url-update="`Clients/${route.params.id}/updateUser`"
|
||||
:filter="filter"
|
||||
model="webAccess"
|
||||
model="customer"
|
||||
:mapper="
|
||||
({ active, name, email }) => {
|
||||
return {
|
||||
|
@ -42,7 +41,7 @@ async function hasCustomerRole() {
|
|||
auto-load
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<QCheckbox :label="t('Enable web access')" v-model="data.active" />
|
||||
<QCheckbox :label="t('Enable web access')" v-model="data.account.active" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.name" />
|
||||
<VnInput
|
||||
:label="t('Recovery email')"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import axios from 'axios';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
|
||||
import { toCurrency, toDateHourMin } from 'src/filters';
|
||||
|
||||
|
@ -20,10 +20,11 @@ const filter = {
|
|||
{ relation: 'mandateType', scope: { fields: ['id', 'name'] } },
|
||||
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
||||
],
|
||||
where: { clientFk: null },
|
||||
where: { clientFk: route.params.id },
|
||||
order: ['created DESC'],
|
||||
limit: 20,
|
||||
};
|
||||
const ClientDmsRef = ref(false);
|
||||
|
||||
const tableColumnComponents = {
|
||||
state: {
|
||||
|
@ -50,7 +51,7 @@ const tableColumnComponents = {
|
|||
component: CustomerCheckIconTooltip,
|
||||
props: ({ row }) => ({
|
||||
transaction: row,
|
||||
promise: refreshData,
|
||||
promise: () => ClientDmsRef.value.fetch(),
|
||||
}),
|
||||
event: () => {},
|
||||
},
|
||||
|
@ -89,72 +90,45 @@ const columns = computed(() => [
|
|||
name: 'validate',
|
||||
},
|
||||
]);
|
||||
|
||||
onBeforeMount(() => {
|
||||
getData(route.params.id);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
(newValue) => {
|
||||
if (!newValue) return;
|
||||
getData(newValue);
|
||||
}
|
||||
);
|
||||
|
||||
const getData = async (id) => {
|
||||
filter.where.clientFk = id;
|
||||
try {
|
||||
const { data } = await axios.get('clients/transactions', {
|
||||
params: { filter: JSON.stringify(filter) },
|
||||
});
|
||||
rows.value = data;
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
const refreshData = () => {
|
||||
getData(route.params.id);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="full-width flex justify-center">
|
||||
<QPage class="card-width q-pa-lg">
|
||||
<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">
|
||||
<component
|
||||
:is="tableColumnComponents[props.col.name].component"
|
||||
@click="
|
||||
tableColumnComponents[props.col.name].event(props)
|
||||
"
|
||||
class="rounded-borders q-pa-sm"
|
||||
v-bind="
|
||||
tableColumnComponents[props.col.name].props(props)
|
||||
"
|
||||
>
|
||||
{{ props.value }}
|
||||
</component>
|
||||
</QTr>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
<FetchData
|
||||
ref="ClientDmsRef"
|
||||
:filter="filter"
|
||||
@on-fetch="(data) => (rows = data)"
|
||||
auto-load
|
||||
url="Clients/transactions"
|
||||
/>
|
||||
<QPage class="card-width q-pa-lg">
|
||||
<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">
|
||||
<component
|
||||
:is="tableColumnComponents[props.col.name].component"
|
||||
@click="tableColumnComponents[props.col.name].event(props)"
|
||||
class="rounded-borders q-pa-sm"
|
||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
||||
>
|
||||
{{ props.value }}
|
||||
</component>
|
||||
</QTr>
|
||||
</QTd>
|
||||
</template>
|
||||
</QTable>
|
||||
|
||||
<h5 class="flex justify-center color-vn-label" v-else>
|
||||
{{ t('globals.noResults') }}
|
||||
</h5>
|
||||
</QPage>
|
||||
</div>
|
||||
<h5 class="flex justify-center color-vn-label" v-else>
|
||||
{{ t('globals.noResults') }}
|
||||
</h5>
|
||||
</QPage>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script setup>
|
||||
import { onBeforeMount, reactive, ref } from 'vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import axios from 'axios';
|
||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
|
@ -25,20 +24,6 @@ const agencyModes = ref([]);
|
|||
const incoterms = ref([]);
|
||||
const customsAgents = ref([]);
|
||||
|
||||
onBeforeMount(() => {
|
||||
urlCreate.value = `Clients/${route.params.id}/createAddress`;
|
||||
getCustomsAgents();
|
||||
});
|
||||
|
||||
const getCustomsAgents = async () => {
|
||||
const { data } = await axios.get('CustomsAgents');
|
||||
customsAgents.value = data;
|
||||
};
|
||||
|
||||
const refreshData = () => {
|
||||
getCustomsAgents();
|
||||
};
|
||||
|
||||
const toCustomerAddress = () => {
|
||||
router.push({
|
||||
name: 'CustomerAddress',
|
||||
|
@ -54,6 +39,11 @@ function handleLocation(data, location) {
|
|||
data.provinceFk = provinceFk;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
|
||||
function onAgentCreated(requestResponse, data) {
|
||||
customsAgents.value.push(requestResponse);
|
||||
data.customsAgentFk = requestResponse.id;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -139,6 +129,7 @@ function handleLocation(data, location) {
|
|||
/>
|
||||
|
||||
<VnSelectDialog
|
||||
url="CustomsAgents"
|
||||
:label="t('Customs agent')"
|
||||
:options="customsAgents"
|
||||
hide-selected
|
||||
|
@ -148,7 +139,12 @@ function handleLocation(data, location) {
|
|||
:tooltip="t('Create a new expense')"
|
||||
>
|
||||
<template #form>
|
||||
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
|
||||
<CustomerNewCustomsAgent
|
||||
@on-data-saved="
|
||||
(_, requestResponse) =>
|
||||
onAgentCreated(requestResponse, data)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</VnSelectDialog>
|
||||
</VnRow>
|
||||
|
|
|
@ -144,7 +144,7 @@ function handleLocation(data, location) {
|
|||
:url="`Addresses/${route.params.addressId}`"
|
||||
@on-data-saved="onDataSaved()"
|
||||
auto-load
|
||||
model="client"
|
||||
model="customer"
|
||||
>
|
||||
<template #moreActions>
|
||||
<QBtn
|
||||
|
|
|
@ -321,10 +321,6 @@ onUnmounted(() => (stateStore.rightDrawer = false));
|
|||
<div class="column">
|
||||
<span v-for="(saleComponent, index) in row.components" :key="index">
|
||||
{{ toCurrency(saleComponent.value * row.quantity, 'EUR', 3) }}
|
||||
<!-- <QTooltip>
|
||||
{{ saleComponent.component?.name }}:
|
||||
{{ toCurrency(saleComponent.value, 'EUR', 3) }}
|
||||
</QTooltip> -->
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -3,11 +3,17 @@ describe('Client basic data', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/basic-data', {
|
||||
timeout: 5000,
|
||||
});
|
||||
cy.visit('#/customer/1102/basic-data');
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.dataCy('customerPhone').filter('input').should('be.visible');
|
||||
cy.dataCy('customerPhone').filter('input').type('123456789');
|
||||
cy.get('.q-btn-group > .q-btn--standard').click();
|
||||
cy.intercept('PATCH', '/api/Clients/1102', (req) => {
|
||||
const { body } = req;
|
||||
cy.wrap(body).should('have.property', 'phone', '123456789');
|
||||
});
|
||||
cy.get('.q-notification__message').should('have.text', 'Data saved');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,6 +8,6 @@ describe('Client billing data', () => {
|
|||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.get('.q-page').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,12 +17,14 @@ describe('Client list', () => {
|
|||
|
||||
it('Client list create new client', () => {
|
||||
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||
const randomInt = Math.floor(Math.random() * 90) + 10;
|
||||
|
||||
const data = {
|
||||
Name: { val: 'Name 1' },
|
||||
'Social name': { val: 'TEST 1' },
|
||||
'Tax number': { val: '20852113Z' },
|
||||
'Web user': { val: 'user_test_1' },
|
||||
Street: { val: 'C/ STREET 1' },
|
||||
Name: { val: `Name ${randomInt}` },
|
||||
'Social name': { val: `TEST ${randomInt}` },
|
||||
'Tax number': { val: `20852${randomInt.length}3Z` },
|
||||
'Web user': { val: `user_test_${randomInt}` },
|
||||
Street: { val: `C/ STREET ${randomInt}` },
|
||||
Email: { val: 'user.test@1.com' },
|
||||
'Sales person': { val: 'employee', type: 'select' },
|
||||
Location: { val: '46000, Valencia(Province one), España', type: 'select' },
|
||||
|
@ -32,7 +34,7 @@ describe('Client list', () => {
|
|||
|
||||
cy.get('.q-mt-lg > .q-btn--standard').click();
|
||||
|
||||
cy.checkNotification('created');
|
||||
cy.checkNotification('Data saved');
|
||||
cy.url().should('include', '/summary');
|
||||
});
|
||||
it('Client list search client', () => {
|
||||
|
@ -54,8 +56,8 @@ describe('Client list', () => {
|
|||
cy.openActionDescriptor('Create ticket');
|
||||
cy.waitForElement('#formModel');
|
||||
cy.waitForElement('.q-form');
|
||||
cy.checkValueSelectForm(1, search);
|
||||
cy.checkValueSelectForm(2, search);
|
||||
cy.checkValueForm(1, search);
|
||||
cy.checkValueForm(2, search);
|
||||
});
|
||||
it('Client founded create order', () => {
|
||||
const search = 'Jessica Jones';
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('Client notes', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1101/sms');
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-page').should('be.visible');
|
||||
cy.get('.q-page > :nth-child(2) > :nth-child(1)').should('be.visible');
|
||||
});
|
||||
});
|
|
@ -3,11 +3,26 @@ describe('Client web-access', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/web-access', {
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
it('Should test buttons ', () => {
|
||||
cy.visit('#/customer/1101/web-access');
|
||||
cy.get('.q-page').should('be.visible');
|
||||
cy.get('#formModel').should('be.visible');
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.get('.q-btn-group > :nth-child(1)').should('not.be.disabled');
|
||||
cy.get('.q-checkbox__inner').click();
|
||||
cy.get('.q-btn-group > .q-btn--standard.q-btn--actionable').should(
|
||||
'not.be.disabled'
|
||||
);
|
||||
cy.get('.q-btn-group > .q-btn--flat').should('not.be.disabled');
|
||||
cy.get('.q-btn-group > :nth-child(1)').click();
|
||||
cy.get('.q-dialog__inner > .q-card > :nth-child(1)')
|
||||
.should('be.visible')
|
||||
.find('.text-h6')
|
||||
.should('have.text', 'Change password');
|
||||
});
|
||||
it('Should disabled buttons', () => {
|
||||
cy.visit('#/customer/1110/web-access');
|
||||
cy.get('.q-btn-group > :nth-child(1)').should('be.disabled');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/// <reference types="cypress" />
|
||||
describe('Client credit opinion', () => {
|
||||
describe('Client credit contracts', () => {
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
|
@ -8,6 +8,6 @@ describe('Client credit opinion', () => {
|
|||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.get('.q-page').should('be.visible');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,11 +3,17 @@ describe('Client unpaid', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/others/unpaid', {
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
it('Should add unpaid', () => {
|
||||
cy.visit('#/customer/1102/others/unpaid');
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.get('.q-checkbox__inner').click();
|
||||
cy.dataCy('customerUnpaidAmount').find('input').type('100');
|
||||
cy.dataCy('customerUnpaidDate').find('input').type('01/01/2001');
|
||||
cy.get('.q-btn-group > .q-btn--standard').click();
|
||||
cy.reload();
|
||||
cy.get('.q-checkbox__inner')
|
||||
.should('be.visible')
|
||||
.and('not.have.class', 'q-checkbox__inner--active');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -254,6 +254,7 @@ Cypress.Commands.add('writeSearchbar', (value) => {
|
|||
value
|
||||
);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('validateContent', (selector, expectedValue) => {
|
||||
cy.get(selector).should('have.text', expectedValue);
|
||||
});
|
||||
|
@ -275,16 +276,38 @@ Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
|||
.click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActionDescriptor', (opt) => {
|
||||
cy.openActionsDescriptor();
|
||||
const listItem = '[role="menu"] .q-list .q-item';
|
||||
cy.contains(listItem, opt).click();
|
||||
1;
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
||||
.invoke('removeAttr', 'target')
|
||||
.click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActionDescriptor', (opt) => {
|
||||
cy.openActionsDescriptor();
|
||||
const listItem = '[role="menu"] .q-list .q-item';
|
||||
cy.contains(listItem, opt).click();
|
||||
1;
|
||||
});
|
||||
|
||||
Cypress.Commands.add('clickButtonsDescriptor', (id) => {
|
||||
cy.get(`.actions > .q-card__actions> .q-btn:nth-child(${id})`)
|
||||
.invoke('removeAttr', 'target')
|
||||
.click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openUserPanel', () => {
|
||||
cy.get(
|
||||
'.column > .q-avatar > .q-avatar__content > .q-img > .q-img__container > .q-img__image'
|
||||
).click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActions', (row) => {
|
||||
cy.get('tbody > tr').eq(row).find('.actions > .q-btn').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkNotification', (text) => {
|
||||
cy.get('.q-notification')
|
||||
.should('be.visible')
|
||||
|
@ -295,10 +318,14 @@ Cypress.Commands.add('checkNotification', (text) => {
|
|||
});
|
||||
});
|
||||
|
||||
Cypress.Commands.add('openActions', (row) => {
|
||||
cy.get('tbody > tr').eq(row).find('.actions > .q-btn').click();
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkValueForm', (id, search) => {
|
||||
cy.get(
|
||||
`.grid-create > :nth-child(${id}) > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > .q-field__input`
|
||||
).should('have.value', search);
|
||||
cy.get(`.grid-create > :nth-child(${id}) `)
|
||||
.find('input')
|
||||
.should('have.value', search);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkValueSelectForm', (id, search) => {
|
||||
|
@ -310,3 +337,7 @@ Cypress.Commands.add('checkValueSelectForm', (id, search) => {
|
|||
Cypress.Commands.add('searchByLabel', (label, value) => {
|
||||
cy.get(`[label="${label}"] > .q-field > .q-field__inner`).type(`${value}{enter}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('dataCy', (tag, attr = 'data-cy') => {
|
||||
return cy.get(`[${attr}="${tag}"]`);
|
||||
});
|
||||
|
|
Comentado?