Merge branch 'hotfix_8217_updateCustomerCredit' into 6943_improve_sections_and_e2e
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
08f673f12c
|
@ -12,7 +12,7 @@ module.exports = defineConfig({
|
|||
supportFile: 'test/cypress/support/index.js',
|
||||
videosFolder: 'test/cypress/videos',
|
||||
video: false,
|
||||
specPattern: 'test/cypress/integration/vnComponent/vnLocation.spec.js',
|
||||
specPattern: 'test/cypress/integration/**/*.spec.js',
|
||||
experimentalRunAllSpecs: true,
|
||||
watchForFileChanges: true,
|
||||
reporter: 'cypress-mochawesome-reporter',
|
||||
|
|
|
@ -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();
|
||||
|
@ -267,28 +268,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')"
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
|
|||
|
||||
const emit = defineEmits(['onSubmit']);
|
||||
|
||||
defineProps({
|
||||
const $props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: '',
|
||||
|
@ -25,16 +25,21 @@ defineProps({
|
|||
type: String,
|
||||
default: '',
|
||||
},
|
||||
submitOnEnter: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const closeButton = ref(null);
|
||||
const isLoading = ref(false);
|
||||
|
||||
const onSubmit = () => {
|
||||
emit('onSubmit');
|
||||
closeForm();
|
||||
if ($props.submitOnEnter) {
|
||||
emit('onSubmit');
|
||||
closeForm();
|
||||
}
|
||||
};
|
||||
|
||||
const closeForm = () => {
|
||||
|
|
|
@ -101,6 +101,7 @@ onBeforeRouteLeave((to, from, next) => {
|
|||
@click="insert"
|
||||
class="q-mb-xs"
|
||||
dense
|
||||
data-cy="saveNote"
|
||||
/>
|
||||
</template>
|
||||
</VnInput>
|
||||
|
|
|
@ -132,10 +132,24 @@ const addFilter = async (filter, params) => {
|
|||
|
||||
async function fetch(params) {
|
||||
useArrayData(props.dataKey, params);
|
||||
arrayData.reset(['filter.skip', 'skip']);
|
||||
arrayData.reset(['filter.skip', 'skip', 'page']);
|
||||
await arrayData.fetch({ append: false });
|
||||
if (!store.hasMoreData) isLoading.value = false;
|
||||
return emitStoreData();
|
||||
}
|
||||
|
||||
async function update(params) {
|
||||
useArrayData(props.dataKey, params);
|
||||
const { limit, skip } = store;
|
||||
store.limit = limit + skip;
|
||||
store.skip = 0;
|
||||
await arrayData.fetch({ append: false });
|
||||
store.limit = limit;
|
||||
store.skip = skip;
|
||||
return emitStoreData();
|
||||
}
|
||||
|
||||
function emitStoreData() {
|
||||
if (!store.hasMoreData) isLoading.value = false;
|
||||
emit('onFetch', store.data);
|
||||
return store.data;
|
||||
}
|
||||
|
@ -181,7 +195,7 @@ async function onLoad(index, done) {
|
|||
done(isDone);
|
||||
}
|
||||
|
||||
defineExpose({ fetch, addFilter, paginate });
|
||||
defineExpose({ fetch, update, addFilter, paginate });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -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 isDialogOpened from './isDialogOpened';
|
||||
|
||||
export {
|
||||
isDialogOpened,
|
||||
getUpdatedValues,
|
||||
getDifferences,
|
||||
toLowerCase,
|
||||
toLowerCamel,
|
||||
toDate,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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`"
|
||||
/>
|
||||
<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">
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
|
|
|
@ -93,22 +93,6 @@ const columns = computed(() => [
|
|||
<WorkerDescriptorProxy :id="row.worker.id" />
|
||||
</template>
|
||||
</VnTable>
|
||||
<!-- <QTable
|
||||
: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;
|
||||
};
|
||||
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`"
|
||||
auto-load
|
||||
model="customer"
|
||||
>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -350,7 +350,7 @@ const openTab = (id) =>
|
|||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
@click="$refs.tableRef.reload()"
|
||||
@click="tableRef.CrudModelRef.vnPaginateRef.update()"
|
||||
>
|
||||
<QTooltip>{{ $t('globals.refresh') }}</QTooltip>
|
||||
</QBtn>
|
||||
|
|
|
@ -43,7 +43,7 @@ const { t } = useI18n();
|
|||
const { openConfirmationModal } = useVnConfirm();
|
||||
|
||||
const isNew = computed(() => props.isNewMode);
|
||||
const dated = ref(null);
|
||||
const dated = ref(props.date);
|
||||
const tickedNodes = ref();
|
||||
|
||||
const _excludeType = ref('all');
|
||||
|
@ -73,7 +73,6 @@ const exclusionCreate = async () => {
|
|||
await axios.post(`Zones/${route.params.id}/exclusions`, {
|
||||
dated: dated.value,
|
||||
});
|
||||
|
||||
await refetchEvents();
|
||||
};
|
||||
|
||||
|
@ -115,13 +114,14 @@ onMounted(() => {
|
|||
@on-submit="onSubmit()"
|
||||
:default-cancel-button="false"
|
||||
:default-submit-button="false"
|
||||
:submit-on-enter="false"
|
||||
>
|
||||
<template #form-inputs>
|
||||
<VnRow class="row q-gutter-md q-mb-lg">
|
||||
<VnInputDate
|
||||
:label="t('eventsInclusionForm.day')"
|
||||
v-model="dated"
|
||||
:model-value="props.date"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
<div class="column q-gutter-y-sm q-mb-md">
|
||||
|
@ -182,6 +182,7 @@ onMounted(() => {
|
|||
:label="isNew ? t('globals.add') : t('globals.save')"
|
||||
type="submit"
|
||||
color="primary"
|
||||
@click="onSubmit()"
|
||||
/>
|
||||
</template>
|
||||
</FormPopup>
|
||||
|
|
|
@ -38,6 +38,7 @@ const datakey = 'ZoneLocations';
|
|||
const url = computed(() => `Zones/${route.params.id}/getLeaves`);
|
||||
const arrayData = useArrayData(datakey, {
|
||||
url: url.value,
|
||||
limit: null,
|
||||
});
|
||||
const store = arrayData.store;
|
||||
|
||||
|
@ -74,6 +75,7 @@ const onNodeExpanded = async (nodeKeysArray) => {
|
|||
if (response.data) {
|
||||
node.childs = response.data.map((n) => {
|
||||
if (n.sons > 0) n.childs = [{}];
|
||||
n.selected = isSelected(n.selected);
|
||||
return n;
|
||||
});
|
||||
}
|
||||
|
@ -90,21 +92,16 @@ const onNodeExpanded = async (nodeKeysArray) => {
|
|||
previousExpandedNodes.value = nodeKeysSet;
|
||||
};
|
||||
|
||||
const formatNodeSelected = (node) => {
|
||||
if (node.selected === 1) node.selected = true;
|
||||
else if (node.selected === 0) node.selected = false;
|
||||
|
||||
if (node.sons > 0 && !node.childs) node.childs = [{}];
|
||||
};
|
||||
|
||||
const fetchNodeLeaves = async (nodeKey) => {
|
||||
if (!treeRef.value) return;
|
||||
const node = treeRef.value?.getNodeByKey(nodeKey);
|
||||
if (node.selected === 1) node.selected = true;
|
||||
else if (node.selected === 0) node.selected = false;
|
||||
if (typeof node.selected === 'number') node.selected = !!node.selected;
|
||||
if (node.sons > 0 && !node.childs) {
|
||||
node.childs = [{}];
|
||||
const index = expanded.value.indexOf(node.id);
|
||||
expanded.value.splice(index, 1);
|
||||
}
|
||||
if (!node || node.sons === 0) return;
|
||||
|
||||
state.set('Tree', node);
|
||||
};
|
||||
|
||||
function getNodeIds(node) {
|
||||
|
@ -119,6 +116,10 @@ function getNodeIds(node) {
|
|||
return ids;
|
||||
}
|
||||
|
||||
function isSelected(selected) {
|
||||
if (typeof selected === 'number') return !!selected;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => store.data,
|
||||
async (val) => {
|
||||
|
@ -128,18 +129,9 @@ watch(
|
|||
nodes.value[0].childs = [...val];
|
||||
const fetchedNodeKeys = val.flatMap(getNodeIds);
|
||||
state.set('Tree', [...fetchedNodeKeys]);
|
||||
|
||||
if (!store.userParams?.search) {
|
||||
val.forEach((n) => {
|
||||
formatNodeSelected(n);
|
||||
});
|
||||
store.data = null;
|
||||
expanded.value = [null];
|
||||
} else {
|
||||
for (let n of state.get('Tree')) {
|
||||
await fetchNodeLeaves(n);
|
||||
}
|
||||
expanded.value = [null, ...fetchedNodeKeys];
|
||||
expanded.value = [null, ...fetchedNodeKeys];
|
||||
for (let n of state.get('Tree')) {
|
||||
await fetchNodeLeaves(n);
|
||||
}
|
||||
previousExpandedNodes.value = new Set(expanded.value);
|
||||
},
|
||||
|
@ -147,13 +139,11 @@ watch(
|
|||
);
|
||||
|
||||
const reFetch = async () => {
|
||||
const { data } = await arrayData.fetch({ append: false });
|
||||
nodes.value = data;
|
||||
expanded.value = [null];
|
||||
await arrayData.fetch({});
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
if (store.userParams?.search) await arrayData.fetch({});
|
||||
await reFetch();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
|
@ -167,13 +157,13 @@ onUnmounted(() => {
|
|||
v-if="showSearchBar"
|
||||
v-model="store.userParams.search"
|
||||
:placeholder="$t('globals.search')"
|
||||
@update:model-value="reFetch()"
|
||||
@keydown.enter.stop.prevent="reFetch"
|
||||
>
|
||||
<template #prepend>
|
||||
<QBtn color="primary" icon="search" dense flat @click="reFetch()" />
|
||||
</template>
|
||||
</VnInput>
|
||||
<VnSearchbar :data-key="datakey" :url="url" :redirect="false" />
|
||||
<VnSearchbar v-if="!showSearchBar" :data-key="datakey" :url="url" :redirect="false" />
|
||||
<QTree
|
||||
ref="treeRef"
|
||||
:nodes="nodes"
|
||||
|
|
|
@ -3,11 +3,18 @@ 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');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -300,22 +300,22 @@ Cypress.Commands.add('checkNotification', (text) => {
|
|||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkValueSelectForm', (id, search) => {
|
||||
cy.get(
|
||||
`.grid-create > :nth-child(${id}) > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > .q-field__native > .q-field__input`
|
||||
).should('have.value', search);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('searchByLabel', (label, value) => {
|
||||
cy.get(`[label="${label}"] > .q-field > .q-field__inner`).type(`${value}{enter}`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('dataCy', (dataTestId, attr = 'data-cy') => {
|
||||
return cy.get(`[${attr}="${dataTestId}"]`);
|
||||
Cypress.Commands.add('dataCy', (tag, attr = 'data-cy') => {
|
||||
return cy.get(`[${attr}="${tag}"]`);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue