diff --git a/Jenkinsfile b/Jenkinsfile
index 1766e3aea..c20da8ab2 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -4,7 +4,8 @@ def PROTECTED_BRANCH
def BRANCH_ENV = [
test: 'test',
- master: 'production'
+ master: 'production',
+ beta: 'production'
]
node {
@@ -15,7 +16,8 @@ node {
PROTECTED_BRANCH = [
'dev',
'test',
- 'master'
+ 'master',
+ 'beta'
].contains(env.BRANCH_NAME)
// https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables
diff --git a/package.json b/package.json
index 04b75a0b0..39d49519b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "salix-front",
- "version": "24.50.0",
+ "version": "24.52.0",
"description": "Salix frontend",
"productName": "Salix",
"author": "Verdnatura",
@@ -64,4 +64,4 @@
"vite": "^5.1.4",
"vitest": "^0.31.1"
}
-}
\ No newline at end of file
+}
diff --git a/src/components/common/VnSelect.vue b/src/components/common/VnSelect.vue
index cd8716194..e116be32a 100644
--- a/src/components/common/VnSelect.vue
+++ b/src/components/common/VnSelect.vue
@@ -8,7 +8,14 @@ import dataByOrder from 'src/utils/dataByOrder';
const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
const $attrs = useAttrs();
const { t } = useI18n();
-const { isRequired, requiredFieldRule } = useRequired($attrs);
+
+const isRequired = computed(() => {
+ return useRequired($attrs).isRequired;
+});
+const requiredFieldRule = computed(() => {
+ return useRequired($attrs).requiredFieldRule;
+});
+
const $props = defineProps({
modelValue: {
type: [String, Number, Object],
diff --git a/src/components/ui/VnAvatar.vue b/src/components/ui/VnAvatar.vue
index 1deb105db..0fe943ee2 100644
--- a/src/components/ui/VnAvatar.vue
+++ b/src/components/ui/VnAvatar.vue
@@ -6,7 +6,7 @@ import { useColor } from 'src/composables/useColor';
import { getCssVar } from 'quasar';
const $props = defineProps({
- workerId: { type: Number, required: true },
+ workerId: { type: [Number, undefined], default: null },
description: { type: String, default: null },
title: { type: String, default: null },
color: { type: String, default: null },
@@ -38,7 +38,13 @@ watch(src, () => (showLetter.value = false));
{{ title.charAt(0) }}
-
+
+
diff --git a/src/components/ui/VnFilterPanel.vue b/src/components/ui/VnFilterPanel.vue
index 8c0dbda94..76dfd574f 100644
--- a/src/components/ui/VnFilterPanel.vue
+++ b/src/components/ui/VnFilterPanel.vue
@@ -78,7 +78,7 @@ const userParams = ref({});
defineExpose({ search, sanitizer, params: userParams });
onMounted(() => {
- userParams.value = $props.modelValue ?? {};
+ if (!userParams.value) userParams.value = $props.modelValue ?? {};
emit('init', { params: userParams.value });
});
@@ -104,7 +104,8 @@ watch(
watch(
() => arrayData.store.userParams,
- (val, oldValue) => (val || oldValue) && setUserParams(val)
+ (val, oldValue) => (val || oldValue) && setUserParams(val),
+ { immediate: true }
);
watch(
diff --git a/src/components/ui/VnLinkPhone.vue b/src/components/ui/VnLinkPhone.vue
index 4068498cd..c5d5df394 100644
--- a/src/components/ui/VnLinkPhone.vue
+++ b/src/components/ui/VnLinkPhone.vue
@@ -1,23 +1,28 @@
{{ capitalize(type).replace('-', '') }}
diff --git a/src/composables/useRequired.js b/src/composables/useRequired.js
index e650c91f5..d211b96b4 100644
--- a/src/composables/useRequired.js
+++ b/src/composables/useRequired.js
@@ -2,8 +2,14 @@ import { useValidator } from 'src/composables/useValidator';
export function useRequired($attrs) {
const { validations } = useValidator();
-
- const isRequired = Object.keys($attrs).includes('required');
+ const hasRequired = Object.keys($attrs).includes('required');
+ let isRequired = false;
+ if (hasRequired) {
+ const required = $attrs['required'];
+ if (typeof required === 'boolean') {
+ isRequired = required;
+ }
+ }
const requiredFieldRule = (val) => validations().required(isRequired, val);
return {
diff --git a/src/filters/parsePhone.js b/src/filters/parsePhone.js
index 696f55007..6cb1bea17 100644
--- a/src/filters/parsePhone.js
+++ b/src/filters/parsePhone.js
@@ -1,12 +1,18 @@
-export default function (phone, prefix = 34) {
- if (phone.startsWith('+')) {
- return `${phone.slice(1)}`;
- }
- if (phone.startsWith('00')) {
- return `${phone.slice(2)}`;
- }
- if (phone.startsWith(prefix) && phone.length === prefix.length + 9) {
- return `${prefix}${phone.slice(prefix.length)}`;
+import axios from 'axios';
+
+export default async function parsePhone(phone, country) {
+ if (!phone) return;
+ if (phone.startsWith('+')) return `${phone.slice(1)}`;
+ if (phone.startsWith('00')) return `${phone.slice(2)}`;
+
+ let prefix;
+ try {
+ prefix = (await axios.get(`Prefixes/${country.toLowerCase()}`)).data?.prefix;
+ } catch (e) {
+ prefix = (await axios.get('PbxConfigs/findOne')).data?.defaultPrefix;
}
+ prefix = prefix.replace(/^0+/, '');
+
+ if (phone.startsWith(prefix)) return phone;
return `${prefix}${phone}`;
}
diff --git a/src/i18n/locale/en.yml b/src/i18n/locale/en.yml
index ecfa2c8fe..073aee4d5 100644
--- a/src/i18n/locale/en.yml
+++ b/src/i18n/locale/en.yml
@@ -331,6 +331,7 @@ globals:
fi: FI
myTeam: My team
departmentFk: Department
+ countryFk: Country
changePass: Change password
deleteConfirmTitle: Delete selected elements
changeState: Change state
diff --git a/src/i18n/locale/es.yml b/src/i18n/locale/es.yml
index def0b0696..fa615294b 100644
--- a/src/i18n/locale/es.yml
+++ b/src/i18n/locale/es.yml
@@ -335,6 +335,7 @@ globals:
SSN: NSS
fi: NIF
myTeam: Mi equipo
+ countryFk: País
changePass: Cambiar contraseña
deleteConfirmTitle: Eliminar los elementos seleccionados
changeState: Cambiar estado
diff --git a/src/pages/Account/AccountList.vue b/src/pages/Account/AccountList.vue
index cbaaf8e26..341dd92a2 100644
--- a/src/pages/Account/AccountList.vue
+++ b/src/pages/Account/AccountList.vue
@@ -7,6 +7,7 @@ import AccountSummary from './Card/AccountSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import AccountFilter from './AccountFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
+import VnInput from 'src/components/common/VnInput.vue';
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const tableRef = ref();
@@ -22,10 +23,27 @@ const columns = computed(() => [
field: 'id',
cardVisible: true,
},
+ {
+ align: 'left',
+ name: 'name',
+ label: t('Name'),
+ component: 'input',
+ columnField: {
+ component: null,
+ },
+ cardVisible: true,
+ create: true,
+ },
{
align: 'left',
name: 'roleFk',
- label: t('role'),
+ label: t('Role'),
+ component: 'select',
+ attrs: {
+ url: 'VnRoles',
+ optionValue: 'id',
+ optionLabel: 'name',
+ },
columnFilter: {
component: 'select',
name: 'roleFk',
@@ -35,7 +53,11 @@ const columns = computed(() => [
optionLabel: 'name',
},
},
+ columnField: {
+ component: null,
+ },
format: ({ role }, dashIfEmpty) => dashIfEmpty(role?.name),
+ create: true,
},
{
align: 'left',
@@ -51,20 +73,32 @@ const columns = computed(() => [
},
{
align: 'left',
- name: 'name',
- label: t('Name'),
+ name: 'email',
+ label: t('Email'),
component: 'input',
columnField: {
component: null,
},
- cardVisible: true,
create: true,
+ visible: false,
},
{
align: 'left',
- name: 'email',
- label: t('email'),
- component: 'input',
+ name: 'password',
+ label: t('Password'),
+ columnField: {
+ component: null,
+ },
+ attrs: {},
+ required: true,
+ visible: false,
+ },
+
+ {
+ align: 'left',
+ name: 'active',
+ label: t('Active'),
+ component: 'checkbox',
create: true,
visible: false,
},
@@ -101,7 +135,6 @@ const exprBuilder = (param, value) => {
}
};
-
{
ref="tableRef"
data-key="AccountList"
url="VnUsers/preview"
+ :create="{
+ urlCreate: 'VnUsers',
+ title: t('Create user'),
+ onDataSaved: ({ id }) => tableRef.redirect(id),
+ formInitialData: {},
+ }"
:filter="filter"
order="id DESC"
:columns="columns"
@@ -127,7 +166,19 @@ const exprBuilder = (param, value) => {
:use-model="true"
:right-search="false"
auto-load
- />
+ >
+
+
+
+
+
+
@@ -135,4 +186,7 @@ const exprBuilder = (param, value) => {
Id: Id
Nickname: Nickname
Name: Nombre
+ Password: Contraseña
+ Active: Activo
+ Role: Rol
diff --git a/src/pages/Customer/Card/CustomerBasicData.vue b/src/pages/Customer/Card/CustomerBasicData.vue
index c6e987fa8..1a86d9f31 100644
--- a/src/pages/Customer/Card/CustomerBasicData.vue
+++ b/src/pages/Customer/Card/CustomerBasicData.vue
@@ -169,7 +169,6 @@ function onBeforeSave(formData, originalData) {
url="Clients"
:input-debounce="0"
:label="t('customer.basicData.previousClient')"
- :options="clients"
:rules="validate('client.transferorFk')"
emit-value
map-options
diff --git a/src/pages/Customer/Card/CustomerFiscalData.vue b/src/pages/Customer/Card/CustomerFiscalData.vue
index 09492b0fd..f0eb11e7c 100644
--- a/src/pages/Customer/Card/CustomerFiscalData.vue
+++ b/src/pages/Customer/Card/CustomerFiscalData.vue
@@ -67,6 +67,7 @@ function handleLocation(data, location) {
option-label="vat"
option-value="id"
v-model="data.sageTaxTypeFk"
+ data-cy="sageTaxTypeFk"
:required="data.isTaxDataChecked"
/>
diff --git a/src/pages/Customer/Card/CustomerSummary.vue b/src/pages/Customer/Card/CustomerSummary.vue
index 4fa7b9bdc..2cad13115 100644
--- a/src/pages/Customer/Card/CustomerSummary.vue
+++ b/src/pages/Customer/Card/CustomerSummary.vue
@@ -95,6 +95,7 @@ const sumRisk = ({ clientRisks }) => {
:phone-number="entity.mobile"
:channel="entity.country?.saySimpleCountry?.channel"
class="q-ml-xs"
+ :country="entity.country?.code"
/>
diff --git a/src/pages/Customer/Card/CustomerWebAccess.vue b/src/pages/Customer/Card/CustomerWebAccess.vue
index eec127fde..3c4106846 100644
--- a/src/pages/Customer/Card/CustomerWebAccess.vue
+++ b/src/pages/Customer/Card/CustomerWebAccess.vue
@@ -29,7 +29,8 @@ async function hasCustomerRole() {
:filter="filter"
model="customer"
:mapper="
- ({ active, name, email }) => {
+ ({ account }) => {
+ const { name, email, active } = account;
return {
active,
name,
@@ -42,13 +43,13 @@ async function hasCustomerRole() {
>
-
+
diff --git a/src/pages/Customer/CustomerList.vue b/src/pages/Customer/CustomerList.vue
index 3cb17332c..865287aeb 100644
--- a/src/pages/Customer/CustomerList.vue
+++ b/src/pages/Customer/CustomerList.vue
@@ -12,6 +12,7 @@ import RightMenu from 'src/components/common/RightMenu.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import { toDate } from 'src/filters';
import CustomerFilter from './CustomerFilter.vue';
+import VnAvatar from 'src/components/ui/VnAvatar.vue';
const { t } = useI18n();
const router = useRouter();
diff --git a/src/pages/Customer/components/CustomerAddressCreate.vue b/src/pages/Customer/components/CustomerAddressCreate.vue
index f4a188243..bc4d6a128 100644
--- a/src/pages/Customer/components/CustomerAddressCreate.vue
+++ b/src/pages/Customer/components/CustomerAddressCreate.vue
@@ -18,8 +18,6 @@ const router = useRouter();
const formInitialData = reactive({ isDefaultAddress: false });
-const urlCreate = ref('');
-
const agencyModes = ref([]);
const incoterms = ref([]);
const customsAgents = ref([]);
@@ -40,13 +38,18 @@ function handleLocation(data, location) {
data.countryFk = countryFk;
}
-function onAgentCreated(requestResponse, data) {
- customsAgents.value.push(requestResponse);
- data.customsAgentFk = requestResponse.id;
+function onAgentCreated({ id, fiscalName }, data) {
+ customsAgents.value.push({ id, fiscalName });
+ data.customsAgentFk = id;
}
+ (customsAgents = data)"
+ auto-load
+ url="CustomsAgents"
+ />
(agencyModes = data)"
auto-load
@@ -57,7 +60,7 @@ function onAgentCreated(requestResponse, data) {
@@ -141,8 +144,7 @@ function onAgentCreated(requestResponse, data) {
- onAgentCreated(requestResponse, data)
+ (requestResponse) => onAgentCreated(requestResponse, data)
"
/>
diff --git a/src/pages/InvoiceOut/InvoiceOutList.vue b/src/pages/InvoiceOut/InvoiceOutList.vue
index c8fffb0ef..0aeae622d 100644
--- a/src/pages/InvoiceOut/InvoiceOutList.vue
+++ b/src/pages/InvoiceOut/InvoiceOutList.vue
@@ -52,7 +52,9 @@ const columns = computed(() => [
label: t('invoiceOutList.tableVisibleColumns.id'),
chip: { condition: () => true },
isId: true,
- columnFilter: { name: 'search' },
+ columnFilter: {
+ name: 'id',
+ },
},
{
align: 'left',
@@ -84,8 +86,15 @@ const columns = computed(() => [
label: t('globals.client'),
cardVisible: true,
component: 'select',
- attrs: { url: 'Clients', fields: ['id', 'name'] },
- columnField: { component: null },
+ attrs: {
+ url: 'Clients',
+ fields: ['id', 'socialName'],
+ optionLabel: 'socialName',
+ optionValue: 'id',
+ },
+ columnField: {
+ component: null,
+ },
},
{
align: 'left',
diff --git a/src/pages/InvoiceOut/locale/es.yml b/src/pages/InvoiceOut/locale/es.yml
index bf5126641..106168a5d 100644
--- a/src/pages/InvoiceOut/locale/es.yml
+++ b/src/pages/InvoiceOut/locale/es.yml
@@ -11,7 +11,7 @@ invoiceOutList:
ref: Referencia
issued: Fecha emisión
created: F. creación
- dueDate: F. máxima
+ dueDate: Fecha vencimiento
invoiceOutSerial: Serial
ticket: Ticket
taxArea: Area
diff --git a/src/pages/Item/Card/ItemTags.vue b/src/pages/Item/Card/ItemTags.vue
index f4ab90d93..a077c72c6 100644
--- a/src/pages/Item/Card/ItemTags.vue
+++ b/src/pages/Item/Card/ItemTags.vue
@@ -138,6 +138,7 @@ const insertTag = (rows) => {
:required="false"
:rules="validate('itemTag.tagFk')"
:use-like="false"
+ sort-by="value"
/>
@@ -197,6 +201,18 @@ const getLocale = (label) => {
/>
+
+
+
+
+
import { useRouter } from 'vue-router';
-import { reactive, onMounted, ref } from 'vue';
+import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
-import { useState } from 'composables/useState';
import FormModelPopup from 'components/FormModelPopup.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'components/common/VnSelect.vue';
@@ -11,29 +10,12 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import { useDialogPluginComponent } from 'quasar';
const { t } = useI18n();
-const state = useState();
const ORDER_MODEL = 'order';
const router = useRouter();
const agencyList = ref([]);
-const addressList = ref([]);
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) => {
if (!landed || !addressFk) {
return;
@@ -59,17 +41,9 @@ const initialFormState = reactive({
clientFk: $props.clientFk,
});
-const onClientChange = async (clientId = $props.clientFk) => {
- const { data } = await axios.get(`Clients/${clientId}`);
- await fetchAddressList(data.defaultAddressFk);
-};
-
async function onDataSaved(_, id) {
await router.push({ path: `/order/${id}/catalog` });
}
-onMounted(async () => {
- await onClientChange();
-});
@@ -90,10 +64,9 @@ onMounted(async () => {
option-value="id"
option-label="name"
:filter="{
- fields: ['id', 'name', 'defaultAddressFk'],
+ fields: ['id', 'name'],
}"
hide-selected
- @update:model-value="onClientChange"
>
@@ -110,7 +83,7 @@ onMounted(async () => {
:label="t('order.form.addressFk')"
v-model="data.addressId"
url="addresses"
- :fields="['id', 'nickname', 'defaultAddressFk', 'street', 'city']"
+ :fields="['id', 'nickname', 'street', 'city']"
sort-by="id"
option-value="id"
option-label="street"
diff --git a/src/pages/Order/OrderList.vue b/src/pages/Order/OrderList.vue
index c47a9b2ec..dfeb0f6e2 100644
--- a/src/pages/Order/OrderList.vue
+++ b/src/pages/Order/OrderList.vue
@@ -1,7 +1,7 @@