0
0
Fork 0

Merge branch 'Fix-Items-Module' of https://gitea.verdnatura.es/verdnatura/salix-front into Fix-Items-Module

This commit is contained in:
Jon Elias 2024-12-09 08:49:27 +01:00
commit b26d07f605
14 changed files with 162 additions and 91 deletions

6
Jenkinsfile vendored
View File

@ -4,7 +4,8 @@ def PROTECTED_BRANCH
def BRANCH_ENV = [ def BRANCH_ENV = [
test: 'test', test: 'test',
master: 'production' master: 'production',
beta: 'production'
] ]
node { node {
@ -15,7 +16,8 @@ node {
PROTECTED_BRANCH = [ PROTECTED_BRANCH = [
'dev', 'dev',
'test', 'test',
'master' 'master',
'beta'
].contains(env.BRANCH_NAME) ].contains(env.BRANCH_NAME)
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables // https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables

View File

@ -2,7 +2,7 @@
import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue'; import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue';
import VnSelectDialog from 'components/common/VnSelectDialog.vue'; import VnSelectDialog from 'components/common/VnSelectDialog.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { ref } from 'vue'; import { computed } from 'vue';
import { useAttrs } from 'vue'; import { useAttrs } from 'vue';
import { useRequired } from 'src/composables/useRequired'; import { useRequired } from 'src/composables/useRequired';
const { t } = useI18n(); const { t } = useI18n();
@ -43,7 +43,7 @@ const formatLocation = (obj, properties) => {
return filteredParts.join(', '); return filteredParts.join(', ');
}; };
const modelValue = ref( const modelValue = computed(() =>
props.location ? formatLocation(props.location, locationProperties) : null props.location ? formatLocation(props.location, locationProperties) : null
); );

View File

@ -79,7 +79,7 @@ const userParams = ref({});
defineExpose({ search, sanitizer, params: userParams }); defineExpose({ search, sanitizer, params: userParams });
onMounted(() => { onMounted(() => {
userParams.value = $props.modelValue ?? {}; if (!userParams.value) userParams.value = $props.modelValue ?? {};
emit('init', { params: userParams.value }); emit('init', { params: userParams.value });
}); });
@ -105,7 +105,8 @@ watch(
watch( watch(
() => arrayData.store.userParams, () => arrayData.store.userParams,
(val, oldValue) => (val || oldValue) && setUserParams(val) (val, oldValue) => (val || oldValue) && setUserParams(val),
{ immediate: true }
); );
watch( watch(

View File

@ -331,6 +331,7 @@ globals:
fi: FI fi: FI
myTeam: My team myTeam: My team
departmentFk: Department departmentFk: Department
countryFk: Country
changePass: Change password changePass: Change password
deleteConfirmTitle: Delete selected elements deleteConfirmTitle: Delete selected elements
changeState: Change state changeState: Change state

View File

@ -335,6 +335,7 @@ globals:
SSN: NSS SSN: NSS
fi: NIF fi: NIF
myTeam: Mi equipo myTeam: Mi equipo
countryFk: País
changePass: Cambiar contraseña changePass: Cambiar contraseña
deleteConfirmTitle: Eliminar los elementos seleccionados deleteConfirmTitle: Eliminar los elementos seleccionados
changeState: Cambiar estado changeState: Cambiar estado

View File

@ -7,6 +7,7 @@ import AccountSummary from './Card/AccountSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import AccountFilter from './AccountFilter.vue'; import AccountFilter from './AccountFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref(); const tableRef = ref();
@ -22,10 +23,27 @@ const columns = computed(() => [
field: 'id', field: 'id',
cardVisible: true, cardVisible: true,
}, },
{
align: 'left',
name: 'name',
label: t('Name'),
component: 'input',
columnField: {
component: null,
},
cardVisible: true,
create: true,
},
{ {
align: 'left', align: 'left',
name: 'roleFk', name: 'roleFk',
label: t('role'), label: t('Role'),
component: 'select',
attrs: {
url: 'VnRoles',
optionValue: 'id',
optionLabel: 'name',
},
columnFilter: { columnFilter: {
component: 'select', component: 'select',
name: 'roleFk', name: 'roleFk',
@ -35,7 +53,11 @@ const columns = computed(() => [
optionLabel: 'name', optionLabel: 'name',
}, },
}, },
columnField: {
component: null,
},
format: ({ role }, dashIfEmpty) => dashIfEmpty(role?.name), format: ({ role }, dashIfEmpty) => dashIfEmpty(role?.name),
create: true,
}, },
{ {
align: 'left', align: 'left',
@ -51,20 +73,32 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'name', name: 'email',
label: t('Name'), label: t('Email'),
component: 'input', component: 'input',
columnField: { columnField: {
component: null, component: null,
}, },
cardVisible: true,
create: true, create: true,
visible: false,
}, },
{ {
align: 'left', align: 'left',
name: 'email', name: 'password',
label: t('email'), label: t('Password'),
component: 'input', columnField: {
component: null,
},
attrs: {},
required: true,
visible: false,
},
{
align: 'left',
name: 'active',
label: t('Active'),
component: 'checkbox',
create: true, create: true,
visible: false, visible: false,
}, },
@ -101,7 +135,6 @@ const exprBuilder = (param, value) => {
} }
}; };
</script> </script>
<template> <template>
<VnSearchbar <VnSearchbar
data-key="AccountList" data-key="AccountList"
@ -119,6 +152,12 @@ const exprBuilder = (param, value) => {
ref="tableRef" ref="tableRef"
data-key="AccountList" data-key="AccountList"
url="VnUsers/preview" url="VnUsers/preview"
:create="{
urlCreate: 'VnUsers',
title: t('Create user'),
onDataSaved: ({ id }) => tableRef.redirect(id),
formInitialData: {},
}"
:filter="filter" :filter="filter"
order="id DESC" order="id DESC"
:columns="columns" :columns="columns"
@ -127,7 +166,19 @@ const exprBuilder = (param, value) => {
:use-model="true" :use-model="true"
:right-search="false" :right-search="false"
auto-load auto-load
/> >
<template #more-create-dialog="{ data }">
<QCardSection>
<VnInput
:label="t('Password')"
v-model="data.password"
type="password"
:required="true"
autocomplete="new-password"
/>
</QCardSection>
</template>
</VnTable>
</template> </template>
<i18n> <i18n>
@ -135,4 +186,7 @@ const exprBuilder = (param, value) => {
Id: Id Id: Id
Nickname: Nickname Nickname: Nickname
Name: Nombre Name: Nombre
Password: Contraseña
Active: Activo
Role: Rol
</i18n> </i18n>

View File

@ -29,7 +29,8 @@ async function hasCustomerRole() {
:filter="filter" :filter="filter"
model="customer" model="customer"
:mapper=" :mapper="
({ active, name, email }) => { ({ account }) => {
const { name, email, active } = account;
return { return {
active, active,
name, name,

View File

@ -52,7 +52,9 @@ const columns = computed(() => [
label: t('invoiceOutList.tableVisibleColumns.id'), label: t('invoiceOutList.tableVisibleColumns.id'),
chip: { condition: () => true }, chip: { condition: () => true },
isId: true, isId: true,
columnFilter: { name: 'search' }, columnFilter: {
name: 'id',
},
}, },
{ {
align: 'left', align: 'left',
@ -84,8 +86,15 @@ const columns = computed(() => [
label: t('globals.client'), label: t('globals.client'),
cardVisible: true, cardVisible: true,
component: 'select', component: 'select',
attrs: { url: 'Clients', fields: ['id', 'name'] }, attrs: {
columnField: { component: null }, url: 'Clients',
fields: ['id', 'socialName'],
optionLabel: 'socialName',
optionValue: 'id',
},
columnField: {
component: null,
},
}, },
{ {
align: 'left', align: 'left',

View File

@ -59,7 +59,11 @@ const getLocale = (label) => {
</template> </template>
<template #customTags="{ params, searchFn, formatFn }"> <template #customTags="{ params, searchFn, formatFn }">
<VnFilterPanelChip <VnFilterPanelChip
v-if="params.scopeDays !== null" v-if="
params.scopeDays !== undefined ||
params.scopeDays !== '' ||
params.scopeDays !== null
"
removable removable
@remove="handleScopeDays(params, null, searchFn)" @remove="handleScopeDays(params, null, searchFn)"
> >
@ -197,6 +201,18 @@ const getLocale = (label) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnSelect
outlined
dense
rounded
:label="t('globals.params.countryFk')"
v-model="params.countryFk"
url="Countries"
/>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelect <VnSelect

View File

@ -1,9 +1,8 @@
<script setup> <script setup>
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { reactive, onMounted, ref } from 'vue'; import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import axios from 'axios'; import axios from 'axios';
import { useState } from 'composables/useState';
import FormModelPopup from 'components/FormModelPopup.vue'; import FormModelPopup from 'components/FormModelPopup.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
@ -11,29 +10,12 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import { useDialogPluginComponent } from 'quasar'; import { useDialogPluginComponent } from 'quasar';
const { t } = useI18n(); const { t } = useI18n();
const state = useState();
const ORDER_MODEL = 'order'; const ORDER_MODEL = 'order';
const router = useRouter(); const router = useRouter();
const agencyList = ref([]); const agencyList = ref([]);
const addressList = ref([]);
defineEmits(['confirm', ...useDialogPluginComponent.emits]); defineEmits(['confirm', ...useDialogPluginComponent.emits]);
const fetchAddressList = async (addressId) => {
const { data } = await axios.get('addresses', {
params: {
filter: JSON.stringify({
fields: ['id', 'nickname', 'street', 'city'],
where: { id: addressId },
}),
},
});
addressList.value = data;
if (addressList.value?.length === 1) {
state.get(ORDER_MODEL).addressId = addressList.value[0].id;
}
};
const fetchAgencyList = async (landed, addressFk) => { const fetchAgencyList = async (landed, addressFk) => {
if (!landed || !addressFk) { if (!landed || !addressFk) {
return; return;
@ -59,17 +41,9 @@ const initialFormState = reactive({
clientFk: $props.clientFk, clientFk: $props.clientFk,
}); });
const onClientChange = async (clientId = $props.clientFk) => {
const { data } = await axios.get(`Clients/${clientId}`);
await fetchAddressList(data.defaultAddressFk);
};
async function onDataSaved(_, id) { async function onDataSaved(_, id) {
await router.push({ path: `/order/${id}/catalog` }); await router.push({ path: `/order/${id}/catalog` });
} }
onMounted(async () => {
await onClientChange();
});
</script> </script>
<template> <template>
@ -90,10 +64,9 @@ onMounted(async () => {
option-value="id" option-value="id"
option-label="name" option-label="name"
:filter="{ :filter="{
fields: ['id', 'name', 'defaultAddressFk'], fields: ['id', 'name'],
}" }"
hide-selected hide-selected
@update:model-value="onClientChange"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -110,7 +83,7 @@ onMounted(async () => {
:label="t('order.form.addressFk')" :label="t('order.form.addressFk')"
v-model="data.addressId" v-model="data.addressId"
url="addresses" url="addresses"
:fields="['id', 'nickname', 'defaultAddressFk', 'street', 'city']" :fields="['id', 'nickname', 'street', 'city']"
sort-by="id" sort-by="id"
option-value="id" option-value="id"
option-label="street" option-label="street"

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import axios from 'axios'; import axios from 'axios';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, onMounted, ref } from 'vue'; import { computed, ref, onMounted } from 'vue';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters'; import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -15,14 +15,13 @@ import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vu
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date'; import { toDateTimeFormat } from 'src/filters/date';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import dataByOrder from 'src/utils/dataByOrder';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref(); const tableRef = ref();
const agencyList = ref([]); const agencyList = ref([]);
const addressesList = ref([]);
const route = useRoute(); const route = useRoute();
const addressOptions = ref([]);
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'left', align: 'left',
@ -148,16 +147,12 @@ onMounted(() => {
const id = JSON.parse(clientId); const id = JSON.parse(clientId);
fetchClientAddress(id.clientFk); fetchClientAddress(id.clientFk);
}); });
async function fetchClientAddress(id, formData = {}) { async function fetchClientAddress(id, formData = {}) {
const { data } = await axios.get(`Clients/${id}`, { const { data } = await axios.get(
params: { `Clients/${id}/addresses?filter[order]=isActive DESC`
filter: { );
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'], addressOptions.value = data;
include: { relation: 'addresses' },
},
},
});
addressesList.value = data.addresses;
formData.addressId = data.defaultAddressFk; formData.addressId = data.defaultAddressFk;
fetchAgencies(formData); fetchAgencies(formData);
} }
@ -168,7 +163,7 @@ async function fetchAgencies({ landed, addressId }) {
const { data } = await axios.get('Agencies/landsThatDay', { const { data } = await axios.get('Agencies/landsThatDay', {
params: { addressFk: addressId, landed }, params: { addressFk: addressId, landed },
}); });
agencyList.value = dataByOrder(data, 'agencyMode ASC'); agencyList.value = data;
} }
const getDateColor = (date) => { const getDateColor = (date) => {
@ -252,34 +247,29 @@ const getDateColor = (date) => {
</VnSelect> </VnSelect>
<VnSelect <VnSelect
v-model="data.addressId" v-model="data.addressId"
:options="addressesList" :options="addressOptions"
:label="t('module.address')" :label="t('module.address')"
option-value="id" option-value="id"
option-label="nickname" option-label="nickname"
@update:model-value="() => fetchAgencies(data)" @update:model-value="() => fetchAgencies(data)"
> >
<template #option="scope"> <template #option="scope">
<QItem <QItem v-bind="scope.itemProps">
v-bind="scope.itemProps"
:class="{ disabled: !scope.opt.isActive }"
>
<QItemSection style="min-width: min-content" avatar>
<QIcon
v-if="
scope.opt.isActive && data.addressId === scope.opt.id
"
size="sm"
color="grey"
name="star"
class="fill-icon"
/>
</QItemSection>
<QItemSection> <QItemSection>
<QItemLabel> <QItemLabel
{{ scope.opt.nickname }} :class="{
</QItemLabel> 'color-vn-label': !scope.opt?.isActive,
<QItemLabel caption> }"
{{ `${scope.opt.street}, ${scope.opt.city}` }} >
{{
`${
!scope.opt?.isActive
? t('basicData.inactive')
: ''
} `
}}
{{ scope.opt?.nickname }}: {{ scope.opt?.street }},
{{ scope.opt?.city }}
</QItemLabel> </QItemLabel>
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -768,7 +768,7 @@ watch(
</template> </template>
<template #column-item="{ row }"> <template #column-item="{ row }">
<div class="row column full-width justify-between items-start"> <div class="row column full-width justify-between items-start">
{{ row?.item?.name }} {{ row?.concept }}
<div v-if="row?.item?.subName" class="subName"> <div v-if="row?.item?.subName" class="subName">
{{ row?.item?.subName.toUpperCase() }} {{ row?.item?.subName.toUpperCase() }}
</div> </div>

View File

@ -57,7 +57,7 @@ const travelKgPercentages = ref([]);
const tableColumnComponents = { const tableColumnComponents = {
id: { id: {
component: QBtn, component: QBtn,
attrs: { flat: true, color: 'primary' }, attrs: { flat: true, color: 'primary', dense: true },
}, },
cargoSupplierNickname: { cargoSupplierNickname: {
component: QBtn, component: QBtn,
@ -178,6 +178,7 @@ const columns = computed(() => [
align: 'left', align: 'left',
showValue: false, showValue: false,
sortable: true, sortable: true,
style: 'min-width: 170px;',
}, },
{ {
label: t('globals.packages'), label: t('globals.packages'),
@ -237,7 +238,7 @@ const columns = computed(() => [
format: (value) => toDate(value), format: (value) => toDate(value),
}, },
{ {
label: t('globals.wareHhuseIn'), label: t('globals.warehouseIn'),
field: 'warehouseInName', field: 'warehouseInName',
name: 'warehouseInName', name: 'warehouseInName',
align: 'left', align: 'left',
@ -506,7 +507,7 @@ const getColor = (percentage) => {
:key="col.name" :key="col.name"
:props="props" :props="props"
@click="stopEventPropagation($event, col)" @click="stopEventPropagation($event, col)"
auto-width :style="col.style"
> >
<component <component
:is="tableColumnComponents[col.name].component" :is="tableColumnComponents[col.name].component"
@ -581,7 +582,7 @@ const getColor = (percentage) => {
}" }"
> >
<QTd> <QTd>
<QBtn flat class="link">{{ entry.id }} </QBtn> <QBtn dense flat class="link">{{ entry.id }} </QBtn>
<EntryDescriptorProxy :id="entry.id" /> <EntryDescriptorProxy :id="entry.id" />
</QTd> </QTd>
<QTd> <QTd>
@ -637,6 +638,18 @@ const getColor = (percentage) => {
:deep(.q-table) { :deep(.q-table) {
border-collapse: collapse; border-collapse: collapse;
th {
padding: 0;
}
tbody tr td {
&:nth-child(1) {
max-width: 65px;
}
&:nth-child(4) {
padding: 0;
}
}
} }
.q-td :deep(input) { .q-td :deep(input) {
@ -684,7 +697,6 @@ const getColor = (percentage) => {
width: max-content; width: max-content;
} }
</style> </style>
<i18n> <i18n>
en: en:
searchExtraCommunity: Search for extra community shipping searchExtraCommunity: Search for extra community shipping

View File

@ -44,7 +44,18 @@ vi.mock('vue-router', () => ({
vi.mock('axios'); vi.mock('axios');
vi.spyOn(useValidator, 'useValidator').mockImplementation(() => { vi.spyOn(useValidator, 'useValidator').mockImplementation(() => {
return { validate: vi.fn() }; return {
validate: vi.fn(),
validations: () => ({
format: vi.fn(),
presence: vi.fn(),
required: vi.fn(),
length: vi.fn(),
numericality: vi.fn(),
min: vi.fn(),
custom: vi.fn(),
}),
};
}); });
class FormDataMock { class FormDataMock {