Merge branch 'dev' of https: refs #8220//gitea.verdnatura.es/verdnatura/salix-front into 8220-ItemsE2E
gitea/salix-front/pipeline/pr-dev There was a failure building this commit
Details
gitea/salix-front/pipeline/pr-dev There was a failure building this commit
Details
This commit is contained in:
commit
2ab5ade072
|
@ -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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "24.50.0",
|
||||
"version": "24.52.0",
|
||||
"description": "Salix frontend",
|
||||
"productName": "Salix",
|
||||
"author": "Verdnatura",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
import routes from 'src/router/modules';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
let isNotified = false;
|
||||
|
||||
export default {
|
||||
created: function () {
|
||||
const router = useRouter();
|
||||
const keyBindingMap = routes
|
||||
.filter((route) => route.meta.keyBinding)
|
||||
.reduce((map, route) => {
|
||||
map['Key' + route.meta.keyBinding.toUpperCase()] = route.path;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
const { ctrlKey, altKey, code } = event;
|
||||
|
||||
if (ctrlKey && altKey && keyBindingMap[code] && !isNotified) {
|
||||
event.preventDefault();
|
||||
router.push(keyBindingMap[code]);
|
||||
isNotified = true;
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUp = (event) => {
|
||||
const { ctrlKey, altKey } = event;
|
||||
if (!ctrlKey || !altKey) {
|
||||
isNotified = false;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
window.addEventListener('keyup', handleKeyUp);
|
||||
},
|
||||
};
|
|
@ -1,13 +1,37 @@
|
|||
import { getCurrentInstance } from 'vue';
|
||||
|
||||
function focusFirstInput(input) {
|
||||
input.focus();
|
||||
return;
|
||||
}
|
||||
export default {
|
||||
mounted: function () {
|
||||
const vm = getCurrentInstance();
|
||||
if (vm.type.name === 'QForm') {
|
||||
if (!['searchbarForm', 'filterPanelForm'].includes(this.$el?.id)) {
|
||||
// TODO: AUTOFOCUS IS NOT FOCUSING
|
||||
const that = this;
|
||||
this.$el.addEventListener('keyup', function (evt) {
|
||||
|
||||
const form = document.querySelector('.q-form#formModel');
|
||||
if (!form) return;
|
||||
try {
|
||||
const inputsFormCard = form.querySelectorAll(
|
||||
`input:not([disabled]):not([type="checkbox"])`
|
||||
);
|
||||
if (inputsFormCard.length) {
|
||||
focusFirstInput(inputsFormCard[0]);
|
||||
}
|
||||
const textareas = document.querySelectorAll(
|
||||
'textarea:not([disabled]), [contenteditable]:not([disabled])'
|
||||
);
|
||||
if (textareas.length) {
|
||||
focusFirstInput(textareas[textareas.length - 1]);
|
||||
}
|
||||
const inputs = document.querySelectorAll(
|
||||
'form#formModel input:not([disabled]):not([type="checkbox"])'
|
||||
);
|
||||
const input = inputs[0];
|
||||
if (!input) return;
|
||||
|
||||
focusFirstInput(input);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
form.addEventListener('keyup', function (evt) {
|
||||
if (evt.key === 'Enter') {
|
||||
const input = evt.target;
|
||||
if (input.type == 'textarea' && evt.shiftKey) {
|
||||
|
@ -24,7 +48,5 @@ export default {
|
|||
that.onSubmit();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,11 +3,16 @@ import qFormMixin from './qformMixin';
|
|||
import keyShortcut from './keyShortcut';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import { CanceledError } from 'axios';
|
||||
import { QForm } from 'quasar';
|
||||
import { QLayout } from 'quasar';
|
||||
import mainShortcutMixin from './mainShortcutMixin';
|
||||
|
||||
const { notify } = useNotify();
|
||||
|
||||
export default boot(({ app }) => {
|
||||
app.mixin(qFormMixin);
|
||||
QForm.mixins = [qFormMixin];
|
||||
QLayout.mixins = [mainShortcutMixin];
|
||||
|
||||
app.directive('shortcut', keyShortcut);
|
||||
app.config.errorHandler = (error) => {
|
||||
let message;
|
||||
|
|
|
@ -40,6 +40,7 @@ const onDataSaved = (...args) => {
|
|||
url-create="towns"
|
||||
model="city"
|
||||
@on-data-saved="onDataSaved"
|
||||
data-cy="newCityForm"
|
||||
>
|
||||
<template #form-inputs="{ data, validate }">
|
||||
<VnRow>
|
||||
|
@ -48,12 +49,14 @@ const onDataSaved = (...args) => {
|
|||
v-model="data.name"
|
||||
:rules="validate('city.name')"
|
||||
required
|
||||
data-cy="cityName"
|
||||
/>
|
||||
<VnSelectProvince
|
||||
:province-selected="$props.provinceSelected"
|
||||
:country-fk="$props.countryFk"
|
||||
v-model="data.provinceFk"
|
||||
required
|
||||
data-cy="provinceCity"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
|
@ -21,14 +21,14 @@ const postcodeFormData = reactive({
|
|||
provinceFk: null,
|
||||
townFk: null,
|
||||
});
|
||||
|
||||
const townsFetchDataRef = ref(false);
|
||||
const townFilter = ref({});
|
||||
|
||||
const countriesRef = ref(false);
|
||||
const townsRef = ref(false);
|
||||
const provincesFetchDataRef = ref(false);
|
||||
const provincesOptions = ref([]);
|
||||
const townsOptions = ref([]);
|
||||
const town = ref({});
|
||||
const townFilter = ref({});
|
||||
const countryFilter = ref({});
|
||||
|
||||
function onDataSaved(formData) {
|
||||
|
@ -48,6 +48,49 @@ function onDataSaved(formData) {
|
|||
emit('onDataSaved', newPostcode);
|
||||
}
|
||||
|
||||
async function setCountry(countryFk, data) {
|
||||
data.townFk = null;
|
||||
data.provinceFk = null;
|
||||
data.countryFk = countryFk;
|
||||
await fetchTowns();
|
||||
}
|
||||
|
||||
// Province
|
||||
|
||||
async function handleProvinces(data) {
|
||||
provincesOptions.value = data;
|
||||
if (postcodeFormData.countryFk) {
|
||||
await fetchTowns();
|
||||
}
|
||||
}
|
||||
async function setProvince(id, data) {
|
||||
if (data.provinceFk === id) return;
|
||||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||
if (newProvince) data.countryFk = newProvince.countryFk;
|
||||
postcodeFormData.provinceFk = id;
|
||||
await fetchTowns();
|
||||
}
|
||||
async function onProvinceCreated(data) {
|
||||
await provincesFetchDataRef.value.fetch({
|
||||
where: { countryFk: postcodeFormData.countryFk },
|
||||
});
|
||||
postcodeFormData.provinceFk = data.id;
|
||||
}
|
||||
function provinceByCountry(countryFk = postcodeFormData.countryFk) {
|
||||
return provincesOptions.value
|
||||
.filter((province) => province.countryFk === countryFk)
|
||||
.map(({ id }) => id);
|
||||
}
|
||||
|
||||
// Town
|
||||
async function handleTowns(data) {
|
||||
townsOptions.value = data;
|
||||
}
|
||||
function setTown(newTown, data) {
|
||||
town.value = newTown;
|
||||
data.provinceFk = newTown?.provinceFk ?? newTown;
|
||||
data.countryFk = newTown?.province?.countryFk ?? newTown;
|
||||
}
|
||||
async function onCityCreated(newTown, formData) {
|
||||
await provincesFetchDataRef.value.fetch();
|
||||
newTown.province = provincesOptions.value.find(
|
||||
|
@ -56,44 +99,29 @@ async function onCityCreated(newTown, formData) {
|
|||
formData.townFk = newTown;
|
||||
setTown(newTown, formData);
|
||||
}
|
||||
|
||||
function setTown(newTown, data) {
|
||||
town.value = newTown;
|
||||
data.provinceFk = newTown?.provinceFk ?? newTown;
|
||||
data.countryFk = newTown?.province?.countryFk ?? newTown;
|
||||
}
|
||||
|
||||
async function setCountry(countryFk, data) {
|
||||
data.townFk = null;
|
||||
data.provinceFk = null;
|
||||
data.countryFk = countryFk;
|
||||
}
|
||||
|
||||
async function handleProvinces(data) {
|
||||
provincesOptions.value = data;
|
||||
}
|
||||
|
||||
async function setProvince(id, data) {
|
||||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||
if (!newProvince) return;
|
||||
|
||||
data.countryFk = newProvince.countryFk;
|
||||
}
|
||||
|
||||
async function onProvinceCreated(data) {
|
||||
await provincesFetchDataRef.value.fetch({
|
||||
where: { countryFk: postcodeFormData.countryFk },
|
||||
});
|
||||
postcodeFormData.provinceFk = data.id;
|
||||
}
|
||||
|
||||
const whereTowns = computed(() => {
|
||||
return {
|
||||
async function fetchTowns(countryFk = postcodeFormData.countryFk) {
|
||||
if (!countryFk) return;
|
||||
const provinces = postcodeFormData.provinceFk
|
||||
? [postcodeFormData.provinceFk]
|
||||
: provinceByCountry();
|
||||
townFilter.value.where = {
|
||||
provinceFk: {
|
||||
inq: provincesOptions.value.map(({ id }) => id),
|
||||
inq: provinces,
|
||||
},
|
||||
};
|
||||
});
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
|
||||
async function filterTowns(name) {
|
||||
if (name !== '') {
|
||||
townFilter.value.where = {
|
||||
name: {
|
||||
like: `%${name}%`,
|
||||
},
|
||||
};
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -105,6 +133,15 @@ const whereTowns = computed(() => {
|
|||
auto-load
|
||||
url="Provinces/location"
|
||||
/>
|
||||
<FetchData
|
||||
ref="townsFetchDataRef"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
:filter="townFilter"
|
||||
@on-fetch="handleTowns"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
/>
|
||||
|
||||
<FormModelPopup
|
||||
url-create="postcodes"
|
||||
|
@ -123,25 +160,22 @@ const whereTowns = computed(() => {
|
|||
:rules="validate('postcode.code')"
|
||||
clearable
|
||||
required
|
||||
data-cy="locationPostcode"
|
||||
/>
|
||||
<VnSelectDialog
|
||||
ref="townsRef"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
:where="whereTowns"
|
||||
:label="t('City')"
|
||||
@update:model-value="(value) => setTown(value, data)"
|
||||
@filter="filterTowns"
|
||||
:tooltip="t('Create city')"
|
||||
v-model="data.townFk"
|
||||
:options="townsOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
:rules="validate('postcode.city')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
:emit-value="false"
|
||||
:clearable="true"
|
||||
required
|
||||
data-cy="locationTown"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
|
@ -172,7 +206,6 @@ const whereTowns = computed(() => {
|
|||
:province-selected="data.provinceFk"
|
||||
@update:model-value="(value) => setProvince(value, data)"
|
||||
v-model="data.provinceFk"
|
||||
@on-province-fetched="handleProvinces"
|
||||
@on-province-created="onProvinceCreated"
|
||||
required
|
||||
/>
|
||||
|
@ -191,6 +224,7 @@ const whereTowns = computed(() => {
|
|||
v-model="data.countryFk"
|
||||
:rules="validate('postcode.countryFk')"
|
||||
@update:model-value="(value) => setCountry(value, data)"
|
||||
data-cy="locationCountry"
|
||||
/>
|
||||
</VnRow>
|
||||
</template>
|
||||
|
|
|
@ -53,8 +53,10 @@ const where = computed(() => {
|
|||
v-model="data.name"
|
||||
:rules="validate('province.name')"
|
||||
required
|
||||
data-cy="provinceName"
|
||||
/>
|
||||
<VnSelect
|
||||
data-cy="autonomyProvince"
|
||||
required
|
||||
ref="autonomiesRef"
|
||||
auto-load
|
||||
|
|
|
@ -177,6 +177,7 @@ function normalize(text) {
|
|||
class="full-width"
|
||||
filled
|
||||
dense
|
||||
autofocus
|
||||
/>
|
||||
</QItem>
|
||||
<QSeparator />
|
||||
|
|
|
@ -64,11 +64,11 @@ watch(
|
|||
auto-load
|
||||
/>
|
||||
<VnSelectDialog
|
||||
data-cy="locationProvince"
|
||||
:label="t('Province')"
|
||||
:options="provincesOptions"
|
||||
:tooltip="t('Create province')"
|
||||
hide-selected
|
||||
:clearable="true"
|
||||
v-model="provinceFk"
|
||||
:rules="validate && validate('postcode.provinceFk')"
|
||||
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
||||
|
|
|
@ -610,6 +610,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
|
|||
$props.rowClick && $props.rowClick(row);
|
||||
}
|
||||
"
|
||||
style="height: 100%"
|
||||
>
|
||||
<QCardSection
|
||||
vertical
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import CreateNewPostcode from 'src/components/CreateNewPostcodeForm.vue';
|
||||
import VnSelectDialog from 'components/common/VnSelectDialog.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import { useAttrs } from 'vue';
|
||||
import { useRequired } from 'src/composables/useRequired';
|
||||
const { t } = useI18n();
|
||||
|
@ -43,7 +43,7 @@ const formatLocation = (obj, properties) => {
|
|||
return filteredParts.join(', ');
|
||||
};
|
||||
|
||||
const modelValue = ref(
|
||||
const modelValue = computed(() =>
|
||||
props.location ? formatLocation(props.location, locationProperties) : null
|
||||
);
|
||||
|
||||
|
@ -75,7 +75,6 @@ const handleModelValue = (data) => {
|
|||
:input-debounce="300"
|
||||
:class="{ required: isRequired }"
|
||||
v-bind="$attrs"
|
||||
clearable
|
||||
:emit-value="false"
|
||||
:tooltip="t('Create new location')"
|
||||
:rules="mixinRules"
|
||||
|
|
|
@ -238,6 +238,7 @@ async function openPointRecord(id, modelLog) {
|
|||
pointRecord.value = parseProps(propNames, locale, data);
|
||||
}
|
||||
async function setLogTree(data) {
|
||||
if (!data) return;
|
||||
logTree.value = getLogTree(data);
|
||||
}
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -43,6 +43,7 @@ const isAllowedToCreate = computed(() => {
|
|||
>
|
||||
<template v-if="isAllowedToCreate" #append>
|
||||
<QIcon
|
||||
:data-cy="$attrs.dataCy ?? $attrs.label + '_icon'"
|
||||
@click.stop.prevent="$refs.dialog.show()"
|
||||
:name="actionIcon"
|
||||
:size="actionIcon === 'add' ? 'xs' : 'sm'"
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<script setup>
|
||||
import { computed, useAttrs } from 'vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||
|
||||
const emit = defineEmits(['update:modelValue']);
|
||||
const $props = defineProps({
|
||||
hasAvatar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
hasInfo: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number, Object],
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const $attrs = useAttrs();
|
||||
|
||||
const value = computed({
|
||||
get() {
|
||||
return $props.modelValue;
|
||||
},
|
||||
set(val) {
|
||||
emit('update:modelValue', val);
|
||||
},
|
||||
});
|
||||
|
||||
const url = computed(() => {
|
||||
let url = 'Workers/search';
|
||||
const { departmentCodes } = $attrs.params ?? {};
|
||||
if (!departmentCodes) return url;
|
||||
const params = new URLSearchParams({
|
||||
departmentCodes: JSON.stringify(departmentCodes),
|
||||
});
|
||||
|
||||
return url.concat(`?${params.toString()}`);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VnSelect
|
||||
:label="$t('globals.worker')"
|
||||
v-bind="$attrs"
|
||||
v-model="value"
|
||||
:url="url"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
:fields="['id', 'name', 'nickname', 'code']"
|
||||
sort-by="nickname ASC"
|
||||
>
|
||||
<template #prepend v-if="$props.hasAvatar">
|
||||
<VnAvatar :worker-id="value" color="primary" :title="title" />
|
||||
</template>
|
||||
<template #append v-if="$props.hasInfo">
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{ $t($props.hasInfo) }}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.name }}
|
||||
</QItemLabel>
|
||||
<QItemLabel v-if="!scope.opt.id">
|
||||
{{ scope.opt.nickname }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption v-else>
|
||||
{{ scope.opt.nickname }}, {{ scope.opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Responsible for approving invoices: Responsable de aprobar las facturas
|
||||
</i18n>
|
|
@ -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));
|
|||
<template v-if="showLetter">
|
||||
{{ title.charAt(0) }}
|
||||
</template>
|
||||
<QImg v-else :src="src" spinner-color="white" @error="showLetter = true" />
|
||||
<QImg
|
||||
v-else-if="workerId"
|
||||
:src="src"
|
||||
spinner-color="white"
|
||||
@error="showLetter = true"
|
||||
/>
|
||||
<QIcon v-else name="mood" size="xs" />
|
||||
</QAvatar>
|
||||
<div class="description">
|
||||
<slot name="description" v-if="description">
|
||||
|
|
|
@ -61,6 +61,7 @@ const emit = defineEmits([
|
|||
'update:modelValue',
|
||||
'refresh',
|
||||
'clear',
|
||||
'search',
|
||||
'init',
|
||||
'remove',
|
||||
'setUserParams',
|
||||
|
@ -78,7 +79,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 +105,8 @@ watch(
|
|||
|
||||
watch(
|
||||
() => arrayData.store.userParams,
|
||||
(val, oldValue) => (val || oldValue) && setUserParams(val)
|
||||
(val, oldValue) => (val || oldValue) && setUserParams(val),
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
<script setup>
|
||||
import { reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
|
||||
import { ref, reactive, useAttrs, onBeforeMount, capitalize } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { parsePhone } from 'src/filters';
|
||||
import useOpenURL from 'src/composables/useOpenURL';
|
||||
|
||||
const props = defineProps({
|
||||
phoneNumber: { type: [String, Number], default: null },
|
||||
channel: { type: Number, default: null },
|
||||
country: { type: String, default: null },
|
||||
});
|
||||
|
||||
const phone = ref(props.phoneNumber);
|
||||
const config = reactive({
|
||||
sip: { icon: 'phone', href: `sip:${props.phoneNumber}` },
|
||||
'say-simple': {
|
||||
icon: 'vn:saysimple',
|
||||
href: null,
|
||||
url: null,
|
||||
channel: props.channel,
|
||||
},
|
||||
});
|
||||
const type = Object.keys(config).find((key) => key in useAttrs()) || 'sip';
|
||||
|
||||
onBeforeMount(async () => {
|
||||
if (!phone.value) return;
|
||||
let { channel } = config[type];
|
||||
|
||||
if (type === 'say-simple') {
|
||||
|
@ -25,23 +30,28 @@ onBeforeMount(async () => {
|
|||
.data;
|
||||
if (!channel) channel = defaultChannel;
|
||||
|
||||
config[type].href = `${url}?customerIdentity=%2B${parsePhone(
|
||||
props.phoneNumber
|
||||
)}&channelId=${channel}`;
|
||||
phone.value = await parsePhone(props.phoneNumber, props.country.toLowerCase());
|
||||
config[
|
||||
type
|
||||
].url = `${url}?customerIdentity=%2B${phone.value}&channelId=${channel}`;
|
||||
}
|
||||
});
|
||||
|
||||
function handleClick() {
|
||||
if (config[type].url) useOpenURL(config[type].url);
|
||||
else if (config[type].href) window.location.href = config[type].href;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<QBtn
|
||||
v-if="phoneNumber"
|
||||
v-if="phone"
|
||||
flat
|
||||
round
|
||||
:icon="config[type].icon"
|
||||
size="sm"
|
||||
color="primary"
|
||||
padding="none"
|
||||
:href="config[type].href"
|
||||
@click.stop
|
||||
@click.stop="handleClick"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ capitalize(type).replace('-', '') }}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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}`;
|
||||
}
|
||||
|
|
|
@ -331,6 +331,7 @@ globals:
|
|||
fi: FI
|
||||
myTeam: My team
|
||||
departmentFk: Department
|
||||
countryFk: Country
|
||||
changePass: Change password
|
||||
deleteConfirmTitle: Delete selected elements
|
||||
changeState: Change state
|
||||
|
@ -397,8 +398,8 @@ entry:
|
|||
buys: Buys
|
||||
stickers: Stickers
|
||||
package: Package
|
||||
packing: Packing
|
||||
grouping: Grouping
|
||||
packing: Pack.
|
||||
grouping: Group.
|
||||
buyingValue: Buying value
|
||||
import: Import
|
||||
pvp: PVP
|
||||
|
|
|
@ -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
|
||||
|
@ -400,8 +401,8 @@ entry:
|
|||
buys: Compras
|
||||
stickers: Etiquetas
|
||||
package: Embalaje
|
||||
packing: Packing
|
||||
grouping: Grouping
|
||||
packing: Pack.
|
||||
grouping: Group.
|
||||
buyingValue: Coste
|
||||
import: Importe
|
||||
pvp: PVP
|
||||
|
|
|
@ -1,50 +1,10 @@
|
|||
<script setup>
|
||||
import { useQuasar } from 'quasar';
|
||||
import Navbar from 'src/components/NavBar.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import routes from 'src/router/modules';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const quasar = useQuasar();
|
||||
|
||||
onMounted(() => {
|
||||
let isNotified = false;
|
||||
|
||||
const router = useRouter();
|
||||
const keyBindingMap = routes
|
||||
.filter((route) => route.meta.keyBinding)
|
||||
.reduce((map, route) => {
|
||||
map['Key' + route.meta.keyBinding.toUpperCase()] = route.path;
|
||||
return map;
|
||||
}, {});
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
const { ctrlKey, altKey, code } = event;
|
||||
|
||||
if (ctrlKey && altKey && keyBindingMap[code] && !isNotified) {
|
||||
event.preventDefault();
|
||||
router.push(keyBindingMap[code]);
|
||||
isNotified = true;
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUp = (event) => {
|
||||
const { ctrlKey, altKey } = event;
|
||||
|
||||
if (!ctrlKey || !altKey) {
|
||||
isNotified = false;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
window.addEventListener('keyup', handleKeyUp);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QLayout view="hHh LpR fFf" v-shortcut>
|
||||
<Navbar />
|
||||
<RouterView></RouterView>
|
||||
<QFooter v-if="quasar.platform.is.mobile"></QFooter>
|
||||
<QFooter v-if="$q.platform.is.mobile"></QFooter>
|
||||
</QLayout>
|
||||
</template>
|
||||
|
|
|
@ -31,7 +31,6 @@ const rolesOptions = ref([]);
|
|||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="['search']"
|
||||
:redirect="false"
|
||||
search-url="table"
|
||||
>
|
||||
|
|
|
@ -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) => {
|
|||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VnSearchbar
|
||||
data-key="AccountList"
|
||||
|
@ -119,6 +152,12 @@ 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
|
||||
>
|
||||
<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>
|
||||
|
||||
<i18n>
|
||||
|
@ -135,4 +186,7 @@ const exprBuilder = (param, value) => {
|
|||
Id: Id
|
||||
Nickname: Nickname
|
||||
Name: Nombre
|
||||
Password: Contraseña
|
||||
Active: Activo
|
||||
Role: Rol
|
||||
</i18n>
|
||||
|
|
|
@ -37,11 +37,7 @@ onBeforeMount(() => {
|
|||
@on-fetch="(data) => (rolesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="['search']"
|
||||
>
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`acls.aclFilter.${tag.label}`) }}: </strong>
|
||||
|
|
|
@ -13,12 +13,7 @@ const props = defineProps({
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="['search']"
|
||||
:redirect="false"
|
||||
>
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true" :redirect="false">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`role.${tag.label}`) }}: </strong>
|
||||
|
|
|
@ -8,7 +8,7 @@ import FormModel from 'components/FormModel.vue';
|
|||
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 VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||
|
||||
const route = useRoute();
|
||||
|
@ -16,7 +16,6 @@ const { t } = useI18n();
|
|||
|
||||
const businessTypes = ref([]);
|
||||
const contactChannels = ref([]);
|
||||
const title = ref();
|
||||
const handleSalesModelValue = (val) => ({
|
||||
or: [
|
||||
{ id: val },
|
||||
|
@ -117,41 +116,17 @@ function onBeforeSave(formData, originalData) {
|
|||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
url="Workers/search"
|
||||
v-model="data.salesPersonFk"
|
||||
<VnSelectWorker
|
||||
:label="t('customer.summary.salesPerson')"
|
||||
v-model="data.salesPersonFk"
|
||||
:params="{
|
||||
departmentCodes: ['VT', 'shopping'],
|
||||
}"
|
||||
:fields="['id', 'nickname']"
|
||||
sort-by="nickname ASC"
|
||||
option-label="nickname"
|
||||
option-value="id"
|
||||
:has-avatar="true"
|
||||
:rules="validate('client.salesPersonFk')"
|
||||
:expr-builder="exprBuilder"
|
||||
emit-value
|
||||
auto-load
|
||||
>
|
||||
<template #prepend>
|
||||
<VnAvatar
|
||||
:worker-id="data.salesPersonFk"
|
||||
color="primary"
|
||||
:title="title"
|
||||
/>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt?.nickname }},
|
||||
{{ scope.opt?.code }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
<VnSelect
|
||||
v-model="data.contactChannelFk"
|
||||
:options="contactChannels"
|
||||
|
@ -169,7 +144,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
|
||||
|
|
|
@ -67,6 +67,7 @@ function handleLocation(data, location) {
|
|||
option-label="vat"
|
||||
option-value="id"
|
||||
v-model="data.sageTaxTypeFk"
|
||||
data-cy="sageTaxTypeFk"
|
||||
:required="data.isTaxDataChecked"
|
||||
/>
|
||||
<VnSelect
|
||||
|
@ -75,6 +76,7 @@ function handleLocation(data, location) {
|
|||
hide-selected
|
||||
option-label="transaction"
|
||||
option-value="id"
|
||||
data-cy="sageTransactionTypeFk"
|
||||
v-model="data.sageTransactionTypeFk"
|
||||
:required="data.isTaxDataChecked"
|
||||
>
|
||||
|
|
|
@ -95,6 +95,7 @@ const sumRisk = ({ clientRisks }) => {
|
|||
:phone-number="entity.mobile"
|
||||
:channel="entity.country?.saySimpleCountry?.channel"
|
||||
class="q-ml-xs"
|
||||
:country="entity.country?.code"
|
||||
/>
|
||||
</template>
|
||||
</VnLv>
|
||||
|
|
|
@ -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() {
|
|||
>
|
||||
<template #form="{ data, validate }">
|
||||
<QCheckbox :label="t('Enable web access')" v-model="data.account.active" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.name" />
|
||||
<VnInput :label="t('User')" clearable v-model="data.account.name" />
|
||||
<VnInput
|
||||
:label="t('Recovery email')"
|
||||
:rules="validate('client.email')"
|
||||
clearable
|
||||
type="email"
|
||||
v-model="data.email"
|
||||
v-model="data.account.email"
|
||||
class="q-mt-sm"
|
||||
:info="t('This email is used for user to regain access their account')"
|
||||
/>
|
||||
|
|
|
@ -3,6 +3,7 @@ import { useI18n } from 'vue-i18n';
|
|||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
defineProps({
|
||||
|
@ -65,19 +66,14 @@ const exprBuilder = (param, value) => {
|
|||
</QItem>
|
||||
<QItem class="q-mb-sm">
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
url="Workers/search"
|
||||
<VnSelectWorker
|
||||
:label="t('Salesperson')"
|
||||
v-model="params.salesPersonFk"
|
||||
:params="{
|
||||
departmentCodes: ['VT'],
|
||||
}"
|
||||
auto-load
|
||||
:label="t('Salesperson')"
|
||||
:expr-builder="exprBuilder"
|
||||
v-model="params.salesPersonFk"
|
||||
@update:model-value="searchFn()"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
sort-by="nickname ASC"
|
||||
emit-value
|
||||
map-options
|
||||
use-input
|
||||
|
@ -86,18 +82,7 @@ const exprBuilder = (param, value) => {
|
|||
outlined
|
||||
rounded
|
||||
:input-debounce="0"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ opt.nickname }},{{ opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template></VnSelect
|
||||
>
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-mb-sm">
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { ref, computed, markRaw } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnTable from 'components/VnTable/VnTable.vue';
|
||||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||
|
@ -12,6 +11,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 VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const router = useRouter();
|
||||
|
@ -421,40 +421,17 @@ function handleLocation(data, location) {
|
|||
auto-load
|
||||
>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnSelect
|
||||
url="Workers/search"
|
||||
v-model="data.salesPersonFk"
|
||||
<VnSelectWorker
|
||||
:label="t('customer.summary.salesPerson')"
|
||||
v-model="data.salesPersonFk"
|
||||
:params="{
|
||||
departmentCodes: ['VT', 'shopping'],
|
||||
}"
|
||||
:fields="['id', 'nickname', 'code']"
|
||||
sort-by="nickname ASC"
|
||||
option-label="nickname"
|
||||
option-value="id"
|
||||
:has-avatar="true"
|
||||
:id-value="data.salesPersonFk"
|
||||
emit-value
|
||||
auto-load
|
||||
>
|
||||
<template #prepend>
|
||||
<VnAvatar
|
||||
:worker-id="data.salesPersonFk"
|
||||
color="primary"
|
||||
:title="title"
|
||||
/>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt?.nickname }},
|
||||
{{ scope.opt?.code }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
|
||||
<VnLocation
|
||||
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
||||
v-model="data.location"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (customsAgents = data)"
|
||||
auto-load
|
||||
url="CustomsAgents"
|
||||
/>
|
||||
<FetchData
|
||||
@on-fetch="(data) => (agencyModes = data)"
|
||||
auto-load
|
||||
|
@ -57,7 +60,7 @@ function onAgentCreated(requestResponse, data) {
|
|||
<FormModel
|
||||
:form-initial-data="formInitialData"
|
||||
:observe-form-changes="false"
|
||||
:url-create="urlCreate"
|
||||
:url-create="`Clients/${route.params.id}/createAddress`"
|
||||
@on-data-saved="toCustomerAddress()"
|
||||
model="client"
|
||||
>
|
||||
|
@ -141,8 +144,7 @@ function onAgentCreated(requestResponse, data) {
|
|||
<template #form>
|
||||
<CustomerNewCustomsAgent
|
||||
@on-data-saved="
|
||||
(_, requestResponse) =>
|
||||
onAgentCreated(requestResponse, data)
|
||||
(requestResponse) => onAgentCreated(requestResponse, data)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -6,6 +6,7 @@ import FormModel from 'components/FormModel.vue';
|
|||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -48,14 +49,9 @@ const { t } = useI18n();
|
|||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
<VnSelectWorker
|
||||
:label="t('department.bossDepartment')"
|
||||
v-model="data.workerFk"
|
||||
url="Workers/search"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
map-options
|
||||
:rules="validate('department.workerFk')"
|
||||
/>
|
||||
<VnSelect
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
import { ref, nextTick } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import axios from 'axios';
|
||||
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
|
||||
const itemBarcodeRef = ref(null);
|
||||
|
||||
|
@ -23,6 +26,24 @@ const focusLastInput = () => {
|
|||
if (lastInput) lastInput.focus();
|
||||
});
|
||||
};
|
||||
|
||||
const removeRow = (row) => {
|
||||
itemBarcodeRef.value.remove([row]);
|
||||
};
|
||||
|
||||
const submit = async (rows) => {
|
||||
const params = rows[rows.length - 1];
|
||||
let { data } = await axios.get('ItemBarcodes');
|
||||
const code = params.code;
|
||||
|
||||
if (data.some((codes) => codes.code === code)) {
|
||||
notify(t('Codes can not be repeated'), 'negative');
|
||||
itemBarcodeRef.value.reset();
|
||||
return;
|
||||
}
|
||||
await axios.patch(`ItemBarcodes`, params);
|
||||
notify(t('globals.dataSaved'), 'positive');
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="full-width flex justify-center">
|
||||
|
@ -39,6 +60,7 @@ const focusLastInput = () => {
|
|||
ref="itemBarcodeRef"
|
||||
url="ItemBarcodes"
|
||||
auto-load
|
||||
:save-fn="submit"
|
||||
>
|
||||
<template #body="{ rows }">
|
||||
<QCard class="q-px-lg q-py-md">
|
||||
|
@ -54,7 +76,7 @@ const focusLastInput = () => {
|
|||
focusable-input
|
||||
/>
|
||||
<QIcon
|
||||
@click="itemBarcodeRef.remove([row])"
|
||||
@click="removeRow(row)"
|
||||
class="cursor-pointer q-ml-md"
|
||||
color="primary"
|
||||
name="delete"
|
||||
|
@ -89,4 +111,5 @@ es:
|
|||
Code: Código
|
||||
Remove barcode: Quitar código de barras
|
||||
Add barcode: Añadir código de barras
|
||||
Codes can not be repeated: Los códigos no puden ser repetidos
|
||||
</i18n>
|
||||
|
|
|
@ -70,6 +70,7 @@ const onIntrastatCreated = (response, formData) => {
|
|||
option-label="name"
|
||||
hide-selected
|
||||
map-options
|
||||
required
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
|
|
@ -67,7 +67,7 @@ const handlePhotoUpdated = (evt = false) => {
|
|||
|
||||
<template>
|
||||
<div class="relative-position">
|
||||
<VnImg ref="image" :id="$props.entityId" zoom-resolution="1600x900">
|
||||
<VnImg ref="image" :id="parseInt($props.entityId)" zoom-resolution="1600x900">
|
||||
<template #error>
|
||||
<div class="absolute-full picture text-center q-pa-md flex flex-center">
|
||||
<div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { onMounted, computed, onUnmounted, reactive, ref, nextTick, watch } from 'vue';
|
||||
import { onMounted, computed, reactive, ref, nextTick, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
|
@ -145,8 +145,6 @@ onMounted(async () => {
|
|||
await updateWarehouse(warehouseFk.value);
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
watch(
|
||||
() => router.currentRoute.value.params.id,
|
||||
(newId) => {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
<script setup>
|
||||
import { onMounted, computed, onUnmounted, ref, watch } from 'vue';
|
||||
import { onMounted, computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { dateRange } from 'src/filters';
|
||||
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { toDateTimeFormat } from 'src/filters/date.js';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import { toCurrency } from 'filters/index';
|
||||
|
@ -15,7 +13,6 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const stateStore = useStateStore();
|
||||
|
||||
const exprBuilder = (param, value) => {
|
||||
switch (param) {
|
||||
|
@ -180,8 +177,6 @@ onMounted(async () => {
|
|||
updateFilter();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,19 +1,15 @@
|
|||
<script setup>
|
||||
import { onMounted, ref, computed, reactive } from 'vue';
|
||||
import { onMounted, ref, computed, reactive, watchEffect } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
|
||||
import { toDateFormat } from 'src/filters/date.js';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||
import axios from 'axios';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
|
||||
const stateStore = useStateStore();
|
||||
|
||||
|
@ -21,8 +17,9 @@ const route = useRoute();
|
|||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
|
||||
const rowsSelected = ref([]);
|
||||
const tableRef = ref();
|
||||
const selectedRows = ref([]);
|
||||
const hasSelectedCards = computed(() => selectedRows.value.length > 0);
|
||||
|
||||
const exprBuilder = (param, value) => {
|
||||
switch (param) {
|
||||
|
@ -36,6 +33,11 @@ const exprBuilder = (param, value) => {
|
|||
};
|
||||
|
||||
const params = reactive({ itemFk: route.params.id });
|
||||
const filter = reactive({
|
||||
where: {
|
||||
itemFk: route.params.id,
|
||||
},
|
||||
});
|
||||
|
||||
const arrayData = useArrayData('ItemShelvings', {
|
||||
url: 'ItemShelvingPlacementSupplyStocks',
|
||||
|
@ -44,58 +46,32 @@ const arrayData = useArrayData('ItemShelvings', {
|
|||
});
|
||||
const rows = computed(() => arrayData.store.data || []);
|
||||
|
||||
const applyColumnFilter = async (col) => {
|
||||
const paramKey = col.columnFilter?.filterParamKey || col.field;
|
||||
params[paramKey] = col.columnFilter.filterValue;
|
||||
await arrayData.addFilter({ filter: null, params });
|
||||
};
|
||||
|
||||
const getInputEvents = (col) => {
|
||||
return col.columnFilter.type === 'select'
|
||||
? { 'update:modelValue': () => applyColumnFilter(col) }
|
||||
: {
|
||||
'keyup.enter': () => applyColumnFilter(col),
|
||||
};
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
label: t('shelvings.created'),
|
||||
name: 'created',
|
||||
field: 'created',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
columnFilter: null,
|
||||
format: (val) => toDateFormat(val),
|
||||
columnFilter: false,
|
||||
format: (row) => toDateFormat(row.created),
|
||||
},
|
||||
|
||||
{
|
||||
label: t('shelvings.item'),
|
||||
name: 'item',
|
||||
field: 'itemFk',
|
||||
name: 'itemFk',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
columnFilter: null,
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
label: t('shelvings.concept'),
|
||||
name: 'concept',
|
||||
name: 'longName',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
columnFilter: null,
|
||||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
label: t('shelvings.parking'),
|
||||
name: 'parking',
|
||||
field: 'parking',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
format: (val) => dashIfEmpty(val),
|
||||
columnFilter: {
|
||||
component: VnSelect,
|
||||
type: 'select',
|
||||
filterValue: null,
|
||||
event: getInputEvents,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'parkings',
|
||||
fields: ['code'],
|
||||
|
@ -104,20 +80,13 @@ const columns = computed(() => [
|
|||
'option-label': 'code',
|
||||
dense: true,
|
||||
},
|
||||
},
|
||||
columnField: { component: null },
|
||||
},
|
||||
{
|
||||
label: t('shelvings.shelving'),
|
||||
name: 'shelving',
|
||||
field: 'shelving',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
format: (val) => dashIfEmpty(val),
|
||||
columnFilter: {
|
||||
component: VnSelect,
|
||||
type: 'select',
|
||||
filterValue: null,
|
||||
event: getInputEvents,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'shelvings',
|
||||
fields: ['code'],
|
||||
|
@ -126,41 +95,20 @@ const columns = computed(() => [
|
|||
'option-label': 'code',
|
||||
dense: true,
|
||||
},
|
||||
},
|
||||
columnField: { component: null },
|
||||
},
|
||||
{
|
||||
label: t('shelvings.label'),
|
||||
name: 'label',
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
format: (_, row) => (row.stock / row.packing).toFixed(2),
|
||||
columnFilter: {
|
||||
component: VnInput,
|
||||
type: 'text',
|
||||
filterParamKey: 'label',
|
||||
filterValue: null,
|
||||
event: getInputEvents,
|
||||
attrs: {
|
||||
dense: true,
|
||||
},
|
||||
},
|
||||
columnFilter: { inWhere: true },
|
||||
format: (row) => (row.stock / row.packing).toFixed(2),
|
||||
},
|
||||
{
|
||||
label: t('shelvings.packing'),
|
||||
field: 'packing',
|
||||
name: 'packing',
|
||||
attrs: { inWhere: true },
|
||||
align: 'left',
|
||||
sortable: true,
|
||||
columnFilter: {
|
||||
component: VnInput,
|
||||
type: 'text',
|
||||
filterValue: null,
|
||||
event: getInputEvents,
|
||||
attrs: {
|
||||
dense: true,
|
||||
},
|
||||
},
|
||||
format: (val) => dashIfEmpty(val),
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -169,15 +117,16 @@ const totalLabels = computed(() =>
|
|||
);
|
||||
|
||||
const removeLines = async () => {
|
||||
const itemShelvingIds = rowsSelected.value.map((row) => row.itemShelvingFk);
|
||||
const itemShelvingIds = selectedRows.value.map((row) => row.itemShelvingFk);
|
||||
await axios.post('ItemShelvings/deleteItemShelvings', { itemShelvingIds });
|
||||
rowsSelected.value = [];
|
||||
selectedRows.value = [];
|
||||
notify('shelvings.shelvingsRemoved', 'positive');
|
||||
await arrayData.fetch({ append: false });
|
||||
await tableRef.value.reload();
|
||||
};
|
||||
onMounted(async () => {
|
||||
await arrayData.fetch({ append: false });
|
||||
});
|
||||
watchEffect(selectedRows);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -203,7 +152,7 @@ onMounted(async () => {
|
|||
<QBtn
|
||||
color="primary"
|
||||
icon="delete"
|
||||
:disabled="!rowsSelected.length"
|
||||
:disabled="!hasSelectedCards"
|
||||
@click="
|
||||
openConfirmationModal(
|
||||
t('shelvings.removeConfirmTitle'),
|
||||
|
@ -219,41 +168,27 @@ onMounted(async () => {
|
|||
</Teleport>
|
||||
</template>
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<QTable
|
||||
:rows="rows"
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="ItemShelving"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
class="full-width q-mt-md"
|
||||
selection="multiple"
|
||||
v-model:selected="rowsSelected"
|
||||
:no-data-label="t('globals.noResults')"
|
||||
:url="`ItemShelvingPlacementSupplyStocks`"
|
||||
:filter="filter"
|
||||
:expr-builder="exprBuilder"
|
||||
:right-search="false"
|
||||
v-model:selected="selectedRows"
|
||||
:table="{
|
||||
'row-key': 'itemShelvingFk',
|
||||
selection: 'multiple',
|
||||
}"
|
||||
auto-load
|
||||
>
|
||||
<template #top-row="{ cols }">
|
||||
<QTr>
|
||||
<QTd />
|
||||
<QTd
|
||||
v-for="(col, index) in cols"
|
||||
:key="index"
|
||||
style="max-width: 100px"
|
||||
>
|
||||
<component
|
||||
:is="col.columnFilter.component"
|
||||
v-if="col.columnFilter"
|
||||
v-model="col.columnFilter.filterValue"
|
||||
v-bind="col.columnFilter.attrs"
|
||||
v-on="col.columnFilter.event(col)"
|
||||
dense
|
||||
/>
|
||||
</QTd>
|
||||
</QTr>
|
||||
</template>
|
||||
<template #body-cell-concept="{ row }">
|
||||
<QTd @click.stop>
|
||||
<span class="link">{{ row.longName }}</span>
|
||||
<template #column-longName="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.longName }}
|
||||
<ItemDescriptorProxy :id="row.itemFk" />
|
||||
</QTd>
|
||||
</span>
|
||||
</template>
|
||||
</QTable>
|
||||
</VnTable>
|
||||
</QPage>
|
||||
</template>
|
||||
|
|
|
@ -89,7 +89,7 @@ const getUrl = (id, param) => `#/Item/${id}/${param}`;
|
|||
<QCard class="vn-one">
|
||||
<VnTitle
|
||||
:url="getUrl(entityId, 'basic-data')"
|
||||
:text="t('item.summary.otherData')"
|
||||
:text="t('item.summary.basicData')"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('item.summary.intrastatCode')"
|
||||
|
|
|
@ -8,7 +8,6 @@ import VnRow from 'components/ui/VnRow.vue';
|
|||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
const route = useRoute();
|
||||
|
@ -60,6 +59,10 @@ const insertTag = (rows) => {
|
|||
itemTagsRef.value.formData[itemTagsRef.value.formData.length - 1].priority =
|
||||
getHighestPriority(rows);
|
||||
};
|
||||
|
||||
const submitTags = async (data) => {
|
||||
itemTagsRef.value.onSubmit(data);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -77,7 +80,6 @@ const insertTag = (rows) => {
|
|||
data-key="ItemTags"
|
||||
model="ItemTags"
|
||||
url="ItemTags"
|
||||
update-url="Tags/onSubmit"
|
||||
:data-required="{
|
||||
$index: undefined,
|
||||
itemFk: route.params.id,
|
||||
|
@ -138,6 +140,7 @@ const insertTag = (rows) => {
|
|||
:required="false"
|
||||
:rules="validate('itemTag.tagFk')"
|
||||
:use-like="false"
|
||||
sort-by="value"
|
||||
/>
|
||||
<VnInput
|
||||
v-else-if="
|
||||
|
@ -146,6 +149,7 @@ const insertTag = (rows) => {
|
|||
v-model="row.value"
|
||||
:label="t('itemTags.value')"
|
||||
:is-clearable="false"
|
||||
@keyup.enter.stop="submitTags(row)"
|
||||
/>
|
||||
<VnInput
|
||||
:label="t('itemBasicData.relevancy')"
|
||||
|
@ -153,6 +157,7 @@ const insertTag = (rows) => {
|
|||
v-model="row.priority"
|
||||
:required="true"
|
||||
:rules="validate('itemTag.priority')"
|
||||
@keyup.enter.stop="submitTags(row)"
|
||||
/>
|
||||
<div class="row justify-center" style="flex: 0">
|
||||
<QIcon
|
||||
|
@ -188,3 +193,8 @@ const insertTag = (rows) => {
|
|||
</QPage>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Tags can not be repeated: Las etiquetas no pueden repetirse
|
||||
</i18n>
|
||||
|
|
|
@ -28,7 +28,7 @@ const taxesFilter = {
|
|||
],
|
||||
};
|
||||
|
||||
const ItemTaxRef = ref(null);
|
||||
const ItemTaxRef = ref();
|
||||
const taxesOptions = ref([]);
|
||||
|
||||
const submitTaxes = async (data) => {
|
||||
|
@ -36,7 +36,10 @@ const submitTaxes = async (data) => {
|
|||
id: tax.id,
|
||||
taxClassFk: tax.taxClassFk,
|
||||
}));
|
||||
|
||||
if (payload.some((item) => item.taxClassFk === null)) {
|
||||
notify(t('Tax class cannot be blank'), 'negative');
|
||||
return;
|
||||
}
|
||||
await axios.post(`Items/updateTaxes`, payload);
|
||||
notify(t('globals.dataSaved'), 'positive');
|
||||
};
|
||||
|
|
|
@ -413,7 +413,6 @@ function handleOnDataSave({ CrudModelRef }) {
|
|||
save-url="FixedPrices/crud"
|
||||
:user-params="{ warehouseFk: user.warehouseFk }"
|
||||
ref="tableRef"
|
||||
dense
|
||||
:columns="columns"
|
||||
default-mode="table"
|
||||
auto-load
|
||||
|
|
|
@ -55,17 +55,6 @@ const columns = computed(() => [
|
|||
label: '',
|
||||
name: 'image',
|
||||
align: 'left',
|
||||
columnField: {
|
||||
component: VnImg,
|
||||
attrs: ({ row }) => {
|
||||
return {
|
||||
id: row?.id,
|
||||
zoomResolution: '1600x900',
|
||||
zoom: true,
|
||||
class: 'rounded',
|
||||
};
|
||||
},
|
||||
},
|
||||
columnFilter: false,
|
||||
cardVisible: true,
|
||||
},
|
||||
|
@ -184,7 +173,7 @@ const columns = computed(() => [
|
|||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
label: t('globals.origin'),
|
||||
label: t('item.list.origin'),
|
||||
name: 'origin',
|
||||
align: 'left',
|
||||
component: 'select',
|
||||
|
@ -228,7 +217,8 @@ const columns = computed(() => [
|
|||
},
|
||||
},
|
||||
{
|
||||
label: t('item.list.weightByPiece'),
|
||||
label: t('item.list.weight'),
|
||||
toolTip: t('item.list.weightByPiece'),
|
||||
name: 'weightByPiece',
|
||||
align: 'left',
|
||||
component: 'input',
|
||||
|
@ -322,7 +312,6 @@ const columns = computed(() => [
|
|||
ref="tableRef"
|
||||
data-key="ItemList"
|
||||
url="Items/filter"
|
||||
url-create="Items"
|
||||
:create="{
|
||||
urlCreate: 'Items',
|
||||
title: t('Create Item'),
|
||||
|
@ -333,12 +322,19 @@ const columns = computed(() => [
|
|||
}"
|
||||
:order="['isActive DESC', 'name', 'id']"
|
||||
:columns="columns"
|
||||
auto-load
|
||||
redirect="Item"
|
||||
:is-editable="false"
|
||||
:right-search="false"
|
||||
:filer="itemFilter"
|
||||
:filter="itemFilter"
|
||||
>
|
||||
<template #column-image="{ row }">
|
||||
<VnImg
|
||||
:id="row?.id"
|
||||
zoom-resolution="1600x900"
|
||||
:zoom="true"
|
||||
class="rounded"
|
||||
/>
|
||||
</template>
|
||||
<template #column-id="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.id }}
|
||||
|
@ -348,7 +344,7 @@ const columns = computed(() => [
|
|||
<template #column-userName="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.userName }}
|
||||
<WorkerDescriptorProxy :id="row.workerFk" />
|
||||
<WorkerDescriptorProxy :id="row.buyerFk" />
|
||||
</span>
|
||||
</template>
|
||||
<template #column-description="{ row }">
|
||||
|
|
|
@ -200,7 +200,17 @@ onMounted(async () => {
|
|||
outlined
|
||||
rounded
|
||||
data-cy="ItemFilterCategorySelect"
|
||||
/>
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{
|
||||
t(`params.${scope.opt?.name}`)
|
||||
}}</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
|
@ -436,6 +446,13 @@ en:
|
|||
description: Description
|
||||
name: Name
|
||||
id: Id
|
||||
Accessories: Accessories
|
||||
Artificial: Artificial
|
||||
Flower: Flower
|
||||
Fruit: Fruit
|
||||
Green: Green
|
||||
Handmade: Handmade
|
||||
Plant: Plant
|
||||
es:
|
||||
More fields: Más campos
|
||||
params:
|
||||
|
@ -452,4 +469,11 @@ es:
|
|||
description: Descripción
|
||||
name: Nombre
|
||||
id: Id
|
||||
Accessories: Accesorios
|
||||
Artificial: Artificial
|
||||
Flower: Flor
|
||||
Fruit: Fruta
|
||||
Green: Verde
|
||||
Handmade: Hecho a mano
|
||||
Plant: Planta
|
||||
</i18n>
|
||||
|
|
|
@ -5,13 +5,16 @@ import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.v
|
|||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useArrayData } from 'composables/useArrayData';
|
||||
import { dashIfEmpty, toCurrency } from 'filters/index';
|
||||
import { toCurrency } from 'filters/index';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import axios from 'axios';
|
||||
import ItemRequestDenyForm from './ItemRequestDenyForm.vue';
|
||||
import { toDate } from 'src/filters';
|
||||
import VnTable from 'components/VnTable/VnTable.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import ItemRequestFilter from './ItemRequestFilter.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
const { t } = useI18n();
|
||||
const { notify } = useNotify();
|
||||
const stateStore = useStateStore();
|
||||
|
@ -228,6 +231,11 @@ onMounted(async () => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
<ItemRequestFilter data-key="itemRequest" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="itemRequest"
|
||||
|
@ -239,6 +247,7 @@ onMounted(async () => {
|
|||
auto-load
|
||||
:disable-option="{ card: true }"
|
||||
chip-locale="item.params"
|
||||
:right-search="false"
|
||||
>
|
||||
<template #column-ticketFk="{ row }">
|
||||
<span class="link">
|
||||
|
@ -306,7 +315,6 @@ onMounted(async () => {
|
|||
/>
|
||||
</template>
|
||||
<template #column-denyOptions="{ row, rowIndex }">
|
||||
<QTd class="sticky no-padding">
|
||||
<QIcon
|
||||
v-if="row.response?.length"
|
||||
name="insert_drive_file"
|
||||
|
@ -329,7 +337,6 @@ onMounted(async () => {
|
|||
{{ t('Discard') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
</template>
|
||||
</VnTable>
|
||||
<QDialog ref="denyFormRef" transition-show="scale" transition-hide="scale">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { dateRange } from 'src/filters';
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
|
@ -7,6 +7,8 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
|||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -21,7 +23,8 @@ const stateOptions = [
|
|||
{ code: 'accepted', name: t('accepted') },
|
||||
{ code: 'denied', name: t('denied') },
|
||||
];
|
||||
|
||||
const arrayData = useArrayData(props.dataKey);
|
||||
const fieldFiltersValues = ref([]);
|
||||
const itemTypesOptions = ref([]);
|
||||
const warehousesOptions = ref([]);
|
||||
|
||||
|
@ -56,6 +59,19 @@ const decrement = (paramsObj, key) => {
|
|||
|
||||
paramsObj[key]--;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
if (arrayData.store?.userParams) {
|
||||
fieldFiltersValues.value = Object.entries(arrayData.store.userParams).map(
|
||||
([key, value]) => ({
|
||||
name: key,
|
||||
value,
|
||||
selectedField: { name: key, label: t(`params.${key}`) },
|
||||
})
|
||||
);
|
||||
}
|
||||
exprBuilder('state', arrayData.store?.userParams?.state);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -145,33 +161,17 @@ const decrement = (paramsObj, key) => {
|
|||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
<VnSelectWorker
|
||||
:label="t('params.requesterFk')"
|
||||
v-model="params.requesterFk"
|
||||
@update:model-value="searchFn()"
|
||||
url="Workers/search"
|
||||
:fields="['id', 'name']"
|
||||
order="name ASC"
|
||||
:params="{ departmentCodes: ['VT'] }"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt?.nickname }},
|
||||
{{ scope.opt?.code }}</QItemLabel
|
||||
>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
|
|
|
@ -10,7 +10,6 @@ const { t } = useI18n();
|
|||
url="ItemTypes"
|
||||
:label="t('Search item type')"
|
||||
:info="t('Search itemType by id, name or code')"
|
||||
search-url="table"
|
||||
/>
|
||||
</template>
|
||||
<i18n>
|
||||
|
|
|
@ -6,6 +6,7 @@ import VnTable from 'components/VnTable/VnTable.vue';
|
|||
import FetchData from 'components/FetchData.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
import ItemTypeFilter from './ItemType/ItemTypeFilter.vue';
|
||||
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableRef = ref();
|
||||
|
@ -31,7 +32,7 @@ const columns = computed(() => [
|
|||
{
|
||||
align: 'left',
|
||||
name: 'name',
|
||||
label: t('name'),
|
||||
label: t('globals.name'),
|
||||
cardVisible: true,
|
||||
create: true,
|
||||
},
|
||||
|
@ -39,6 +40,7 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
label: t('worker'),
|
||||
name: 'workerFk',
|
||||
name: 'workerFk',
|
||||
create: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
|
@ -46,17 +48,20 @@ const columns = computed(() => [
|
|||
optionLabel: 'nickname',
|
||||
optionValue: 'id',
|
||||
},
|
||||
format: (row) => row.worker?.user?.name,
|
||||
cardVisible: true,
|
||||
visible: true,
|
||||
columnField: {
|
||||
component: 'userLink',
|
||||
attrs: ({ row }) => {
|
||||
return {
|
||||
workerId: row?.worker?.id,
|
||||
name: row.worker?.user?.name,
|
||||
defaultName: true,
|
||||
};
|
||||
columnField: { component: null },
|
||||
columnFilter: {
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
where: { role: 'buyer' },
|
||||
optionFilter: 'firstName',
|
||||
optionLabel: 'name',
|
||||
optionValue: 'id',
|
||||
useLike: false,
|
||||
},
|
||||
inWhere: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -133,24 +138,27 @@ const columns = computed(() => [
|
|||
:columns="columns"
|
||||
auto-load
|
||||
:right-search="false"
|
||||
:is-editable="false"
|
||||
:use-model="true"
|
||||
redirect="item/item-type"
|
||||
/>
|
||||
>
|
||||
<template #column-workerFk="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row.worker?.user?.name }}
|
||||
<WorkerDescriptorProxy :id="row.workerFk" />
|
||||
</span>
|
||||
</template>
|
||||
</VnTable>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
id: Id
|
||||
code: Código
|
||||
name: Nombre
|
||||
worker: Trabajador
|
||||
ItemCategory: Reino
|
||||
Temperature: Temperatura
|
||||
Create ItemTypes: Crear familia
|
||||
en:
|
||||
code: Code
|
||||
name: Name
|
||||
worker: Worker
|
||||
ItemCategory: ItemCategory
|
||||
Temperature: Temperature
|
||||
|
|
|
@ -95,6 +95,15 @@ item:
|
|||
mine: For me
|
||||
state: State
|
||||
myTeam: My team
|
||||
shipped: Shipped
|
||||
description: Description
|
||||
quantity: Quantity
|
||||
price: Price
|
||||
item: Item
|
||||
achieved: Achieved
|
||||
concept: Concept
|
||||
denyOptions: Deny
|
||||
scopeDays: Scope days
|
||||
searchbar:
|
||||
label: Search item
|
||||
descriptor:
|
||||
|
@ -112,7 +121,7 @@ item:
|
|||
title: All its properties will be copied
|
||||
subTitle: Do you want to clone this item?
|
||||
list:
|
||||
id: Identifier
|
||||
id: Id
|
||||
grouping: Grouping
|
||||
packing: Packing
|
||||
description: Description
|
||||
|
@ -122,8 +131,9 @@ item:
|
|||
intrastat: Intrastat
|
||||
isActive: Active
|
||||
size: Size
|
||||
origin: Origin
|
||||
origin: Orig.
|
||||
userName: Buyer
|
||||
weight: Weight
|
||||
weightByPiece: Weight/Piece
|
||||
stemMultiplier: Multiplier
|
||||
producer: Producer
|
||||
|
|
|
@ -97,6 +97,15 @@ item:
|
|||
mine: Para mi
|
||||
state: Estado
|
||||
myTeam: Mi equipo
|
||||
shipped: Enviado
|
||||
description: Descripción
|
||||
quantity: Cantidad
|
||||
price: Precio
|
||||
item: Artículo
|
||||
achieved: Conseguido
|
||||
concept: Concepto
|
||||
denyOptions: Denegado
|
||||
scopeDays: Días en adelante
|
||||
searchbar:
|
||||
label: Buscar artículo
|
||||
descriptor:
|
||||
|
@ -114,7 +123,7 @@ item:
|
|||
title: Todas sus propiedades serán copiadas
|
||||
subTitle: ¿Desea clonar este artículo?
|
||||
list:
|
||||
id: Identificador
|
||||
id: Id
|
||||
grouping: Grouping
|
||||
packing: Packing
|
||||
description: Descripción
|
||||
|
@ -124,7 +133,8 @@ item:
|
|||
intrastat: Intrastat
|
||||
isActive: Activo
|
||||
size: Medida
|
||||
origin: Origen
|
||||
origin: Orig.
|
||||
weight: Peso
|
||||
weightByPiece: Peso (gramos)/tallo
|
||||
userName: Comprador
|
||||
stemMultiplier: Multiplicador
|
||||
|
|
|
@ -9,6 +9,7 @@ import VnInput from 'src/components/common/VnInput.vue';
|
|||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import { dateRange } from 'src/filters';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
defineProps({ dataKey: { type: String, required: true } });
|
||||
const { t, te } = useI18n();
|
||||
|
@ -59,7 +60,11 @@ const getLocale = (label) => {
|
|||
</template>
|
||||
<template #customTags="{ params, searchFn, formatFn }">
|
||||
<VnFilterPanelChip
|
||||
v-if="params.scopeDays !== null"
|
||||
v-if="
|
||||
params.scopeDays !== undefined ||
|
||||
params.scopeDays !== '' ||
|
||||
params.scopeDays !== null
|
||||
"
|
||||
removable
|
||||
@remove="handleScopeDays(params, null, searchFn)"
|
||||
>
|
||||
|
@ -108,33 +113,16 @@ const getLocale = (label) => {
|
|||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
<VnSelectWorker
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
:label="t('globals.params.salesPersonFk')"
|
||||
v-model="params.salesPersonFk"
|
||||
url="Workers/search"
|
||||
:params="{ departmentCodes: ['VT'] }"
|
||||
is-outlined
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:no-one="true"
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||
<QItemLabel
|
||||
v-if="opt.code"
|
||||
class="text-grey text-caption"
|
||||
>
|
||||
{{ `${opt.nickname}, ${opt.code}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</VnSelectWorker>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
|
@ -197,6 +185,18 @@ const getLocale = (label) => {
|
|||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
:label="t('globals.params.countryFk')"
|
||||
v-model="params.countryFk"
|
||||
url="Countries"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { onMounted, onUnmounted, ref, computed, watch } from 'vue';
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import axios from 'axios';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnPaginate from 'src/components/ui/VnPaginate.vue';
|
||||
|
@ -29,8 +29,6 @@ onMounted(() => {
|
|||
checkOrderConfirmation();
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
async function checkOrderConfirmation() {
|
||||
const response = await axios.get(`Orders/${route.params.id}`);
|
||||
if (response.data.isConfirmed === 1) {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
<script setup>
|
||||
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();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -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"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -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"
|
||||
|
|
|
@ -6,6 +6,7 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
|||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -61,28 +62,16 @@ const sourceList = ref([]);
|
|||
outlined
|
||||
rounded
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('salesPerson')"
|
||||
<VnSelectWorker
|
||||
:label="t('globals.salesPerson')"
|
||||
v-model="params.workerFk"
|
||||
url="Workers/search"
|
||||
:filter="{ departmentCodes: ['VT'] }"
|
||||
sort-by="nickname ASC"
|
||||
option-label="nickname"
|
||||
:params="{
|
||||
departmentCodes: ['VT'],
|
||||
}"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ opt.nickname }},{{ opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
<VnInputDate
|
||||
v-model="params.from"
|
||||
:label="t('fromLanded')"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
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 OrderSummary from 'pages/Order/Card/OrderSummary.vue';
|
||||
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 { toDateTimeFormat } from 'src/filters/date';
|
||||
import { useRoute } from 'vue-router';
|
||||
import dataByOrder from 'src/utils/dataByOrder';
|
||||
|
||||
const { t } = useI18n();
|
||||
const { viewSummary } = useSummaryDialog();
|
||||
const tableRef = ref();
|
||||
const agencyList = ref([]);
|
||||
const addressesList = ref([]);
|
||||
const route = useRoute();
|
||||
const addressOptions = ref([]);
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -148,16 +147,12 @@ onMounted(() => {
|
|||
const id = JSON.parse(clientId);
|
||||
fetchClientAddress(id.clientFk);
|
||||
});
|
||||
|
||||
async function fetchClientAddress(id, formData = {}) {
|
||||
const { data } = await axios.get(`Clients/${id}`, {
|
||||
params: {
|
||||
filter: {
|
||||
order: ['isDefaultAddress DESC', 'isActive DESC', 'nickname ASC'],
|
||||
include: { relation: 'addresses' },
|
||||
},
|
||||
},
|
||||
});
|
||||
addressesList.value = data.addresses;
|
||||
const { data } = await axios.get(
|
||||
`Clients/${id}/addresses?filter[order]=isActive DESC`
|
||||
);
|
||||
addressOptions.value = data;
|
||||
formData.addressId = data.defaultAddressFk;
|
||||
fetchAgencies(formData);
|
||||
}
|
||||
|
@ -168,7 +163,7 @@ async function fetchAgencies({ landed, addressId }) {
|
|||
const { data } = await axios.get('Agencies/landsThatDay', {
|
||||
params: { addressFk: addressId, landed },
|
||||
});
|
||||
agencyList.value = dataByOrder(data, 'agencyMode ASC');
|
||||
agencyList.value = data;
|
||||
}
|
||||
|
||||
const getDateColor = (date) => {
|
||||
|
@ -252,34 +247,29 @@ const getDateColor = (date) => {
|
|||
</VnSelect>
|
||||
<VnSelect
|
||||
v-model="data.addressId"
|
||||
:options="addressesList"
|
||||
:options="addressOptions"
|
||||
:label="t('module.address')"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
@update:model-value="() => fetchAgencies(data)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem
|
||||
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>
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt.nickname }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `${scope.opt.street}, ${scope.opt.city}` }}
|
||||
<QItemLabel
|
||||
:class="{
|
||||
'color-vn-label': !scope.opt?.isActive,
|
||||
}"
|
||||
>
|
||||
{{
|
||||
`${
|
||||
!scope.opt?.isActive
|
||||
? t('basicData.inactive')
|
||||
: ''
|
||||
} `
|
||||
}}
|
||||
{{ scope.opt?.nickname }}: {{ scope.opt?.street }},
|
||||
{{ scope.opt?.city }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
|
|
@ -4,6 +4,7 @@ import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
|||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -31,29 +32,13 @@ const emit = defineEmits(['search']);
|
|||
<template #body="{ params }">
|
||||
<QItem class="q-my-sm">
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('Worker')"
|
||||
<VnSelectWorker
|
||||
v-model="params.workerFk"
|
||||
url="Workers/search"
|
||||
sort-by="nickname ASC"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
:input-debounce="0"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ opt.nickname }},{{ opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-my-sm">
|
||||
|
|
|
@ -11,6 +11,7 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
|||
import VnInput from 'components/common/VnInput.vue';
|
||||
import axios from 'axios';
|
||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
|
@ -94,26 +95,7 @@ const onSave = (data, response) => {
|
|||
>
|
||||
<template #form="{ data }">
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('Worker')"
|
||||
v-model="data.workerFk"
|
||||
url="Workers/search"
|
||||
sort-by="nickname ASC"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
:input-debounce="0"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ opt.nickname }}, {{ opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
<VnSelectWorker v-model="data.workerFk" />
|
||||
<VnSelect
|
||||
:label="t('Vehicle')"
|
||||
v-model="data.vehicleFk"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { onMounted, onUnmounted } from 'vue';
|
||||
import { onMounted } from 'vue';
|
||||
import CardList from 'components/ui/CardList.vue';
|
||||
import VnLv from 'components/ui/VnLv.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
@ -21,7 +21,6 @@ const filter = {
|
|||
};
|
||||
|
||||
onMounted(() => (stateStore.rightDrawer = true));
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
function navigate(id) {
|
||||
router.push({ path: `/shelving/${id}` });
|
||||
|
|
|
@ -5,6 +5,7 @@ import FormModel from 'components/FormModel.vue';
|
|||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -30,31 +31,11 @@ const companySizes = [
|
|||
:rules="validate('supplier.nickname')"
|
||||
clearable
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('supplier.basicData.workerFk')"
|
||||
<VnSelectWorker
|
||||
v-model="data.workerFk"
|
||||
url="Workers/search"
|
||||
sort-by="nickname ASC"
|
||||
has-info="Responsible for approving invoices"
|
||||
:rules="validate('supplier.workerFk')"
|
||||
>
|
||||
<template #append>
|
||||
<QIcon name="info" class="cursor-pointer">
|
||||
<QTooltip>{{
|
||||
t('Responsible for approving invoices')
|
||||
}}</QTooltip>
|
||||
</QIcon>
|
||||
</template>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ scope.opt?.nickname }}, {{ scope.opt?.id }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('supplier.basicData.size')"
|
||||
v-model="data.companySize"
|
||||
|
@ -102,6 +83,5 @@ const companySizes = [
|
|||
|
||||
<i18n>
|
||||
es:
|
||||
Responsible for approving invoices: Responsable de aprobar las facturas
|
||||
Small(1-5), Medium(6-50), Big(> 50): Pequeño(1-5), Mediano(6-50), Grande(> 50)
|
||||
</i18n>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { ref, computed, onMounted, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
|
@ -134,8 +134,6 @@ onMounted(() => {
|
|||
loadDefaultTicketAction();
|
||||
ticketHaveNegatives();
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import { ref, computed, onMounted, watch, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
|
@ -168,8 +168,6 @@ const getTicketVolume = async () => {
|
|||
onMounted(() => {
|
||||
stateStore.rightDrawer = true;
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -9,6 +9,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
|||
import FetchData from 'components/FetchData.vue';
|
||||
|
||||
import { useState } from 'src/composables/useState';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const emit = defineEmits(['onRequestCreated']);
|
||||
|
||||
|
@ -46,29 +47,7 @@ const onStateFkChange = (formData) => (formData.userFk = user.value.id);
|
|||
option-label="name"
|
||||
option-value="id"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('expedition.worker')"
|
||||
v-model="data.userFk"
|
||||
url="Workers/search"
|
||||
fields=" ['id', 'name']"
|
||||
sort-by="name ASC"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
>
|
||||
<template #option="{ opt, itemProps }">
|
||||
<QItem v-bind="itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ opt.name }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ opt.nickname }}, {{ opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template></VnSelect
|
||||
>
|
||||
<VnSelectWorker v-model="data.userFk" :fields="['id', 'name']" />
|
||||
</VnRow>
|
||||
</template>
|
||||
</FormModelPopup>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { onMounted, ref, computed, onUnmounted } from 'vue';
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
|
@ -197,8 +197,6 @@ onMounted(async () => {
|
|||
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
||||
allColumnNames.value = filteredColumns.map((col) => col.name);
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { onMounted, ref, computed, onUnmounted, watch } from 'vue';
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -421,8 +421,6 @@ onMounted(async () => {
|
|||
getConfig();
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
|
||||
const items = ref([]);
|
||||
const newRow = ref({});
|
||||
|
||||
|
@ -770,7 +768,7 @@ watch(
|
|||
</template>
|
||||
<template #column-item="{ row }">
|
||||
<div class="row column full-width justify-between items-start">
|
||||
{{ row?.item?.name }}
|
||||
{{ row?.concept }}
|
||||
<div v-if="row?.item?.subName" class="subName">
|
||||
{{ row?.item?.subName.toUpperCase() }}
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import { ref, computed, onMounted, watch, nextTick } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
|
@ -90,8 +90,6 @@ const applyVolumes = async (salesData) => {
|
|||
};
|
||||
|
||||
onMounted(() => (stateStore.rightDrawer = true));
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -57,7 +57,6 @@ onMounted(async () => await getItemPackingTypes());
|
|||
search-url="advanceTickets"
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="['search']"
|
||||
:unremovable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
|
||||
>
|
||||
<template #tags="{ tag, formatFn }">
|
||||
|
|
|
@ -59,7 +59,6 @@ onMounted(async () => {
|
|||
/>
|
||||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:hidden-tags="['search']"
|
||||
:un-removable-params="['warehouseFk', 'originScopeDays ', 'futureScopeDays']"
|
||||
>
|
||||
<template #tags="{ tag, formatFn }">
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { onMounted, ref, computed, onUnmounted } from 'vue';
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectCache from 'src/components/common/VnSelectCache.vue';
|
||||
|
@ -170,8 +170,6 @@ onMounted(async () => {
|
|||
const filteredColumns = columns.value.filter((col) => col.name !== 'actions');
|
||||
allColumnNames.value = filteredColumns.map((col) => col.name);
|
||||
});
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -7,13 +7,13 @@ import filter from './TravelFilter.js';
|
|||
<VnCard
|
||||
data-key="Travel"
|
||||
base-url="Travels"
|
||||
search-data-key="TravelList"
|
||||
:filter="filter"
|
||||
:descriptor="TravelDescriptor"
|
||||
:filter="filter"
|
||||
search-data-key="TravelList"
|
||||
:searchbar-props="{
|
||||
url: 'Travels',
|
||||
url: 'Travels/filter',
|
||||
searchUrl: 'table',
|
||||
label: 'Search travel',
|
||||
info: 'You can search by travel id or name',
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -57,7 +57,7 @@ const travelKgPercentages = ref([]);
|
|||
const tableColumnComponents = {
|
||||
id: {
|
||||
component: QBtn,
|
||||
attrs: { flat: true, color: 'primary' },
|
||||
attrs: { flat: true, color: 'primary', dense: true },
|
||||
},
|
||||
cargoSupplierNickname: {
|
||||
component: QBtn,
|
||||
|
@ -178,6 +178,7 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
showValue: false,
|
||||
sortable: true,
|
||||
style: 'min-width: 170px;',
|
||||
},
|
||||
{
|
||||
label: t('globals.packages'),
|
||||
|
@ -237,7 +238,7 @@ const columns = computed(() => [
|
|||
format: (value) => toDate(value),
|
||||
},
|
||||
{
|
||||
label: t('globals.wareHhuseIn'),
|
||||
label: t('globals.warehouseIn'),
|
||||
field: 'warehouseInName',
|
||||
name: 'warehouseInName',
|
||||
align: 'left',
|
||||
|
@ -506,7 +507,7 @@ const getColor = (percentage) => {
|
|||
:key="col.name"
|
||||
:props="props"
|
||||
@click="stopEventPropagation($event, col)"
|
||||
auto-width
|
||||
:style="col.style"
|
||||
>
|
||||
<component
|
||||
:is="tableColumnComponents[col.name].component"
|
||||
|
@ -581,7 +582,7 @@ const getColor = (percentage) => {
|
|||
}"
|
||||
>
|
||||
<QTd>
|
||||
<QBtn flat class="link">{{ entry.id }} </QBtn>
|
||||
<QBtn dense flat class="link">{{ entry.id }} </QBtn>
|
||||
<EntryDescriptorProxy :id="entry.id" />
|
||||
</QTd>
|
||||
<QTd>
|
||||
|
@ -637,6 +638,18 @@ const getColor = (percentage) => {
|
|||
|
||||
:deep(.q-table) {
|
||||
border-collapse: collapse;
|
||||
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
tbody tr td {
|
||||
&:nth-child(1) {
|
||||
max-width: 65px;
|
||||
}
|
||||
&:nth-child(4) {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.q-td :deep(input) {
|
||||
|
@ -684,7 +697,6 @@ const getColor = (percentage) => {
|
|||
width: max-content;
|
||||
}
|
||||
</style>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
searchExtraCommunity: Search for extra community shipping
|
||||
|
|
|
@ -208,6 +208,7 @@ const columns = computed(() => [
|
|||
ref="tableRef"
|
||||
data-key="TravelList"
|
||||
url="Travels/filter"
|
||||
redirect="travel"
|
||||
:create="{
|
||||
urlCreate: 'Travels',
|
||||
title: t('Create Travels'),
|
||||
|
@ -221,9 +222,7 @@ const columns = computed(() => [
|
|||
order="landed DESC"
|
||||
:columns="columns"
|
||||
auto-load
|
||||
redirect="travel"
|
||||
:is-editable="false"
|
||||
:use-model="true"
|
||||
>
|
||||
<template #column-status="{ row }">
|
||||
<div class="row">
|
||||
|
|
|
@ -133,6 +133,7 @@ function reloadData() {
|
|||
option-value="id"
|
||||
id="deviceProductionFk"
|
||||
hide-selected
|
||||
data-cy="pda-dialog-select"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
|
|
@ -14,6 +14,7 @@ import FormModel from 'components/FormModel.vue';
|
|||
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
||||
import VnRadio from 'src/components/common/VnRadio.vue';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const user = useState().getUser();
|
||||
|
@ -149,27 +150,11 @@ async function autofillBic(worker) {
|
|||
hide-selected
|
||||
:rules="validate('Worker.company')"
|
||||
/>
|
||||
<VnSelect
|
||||
<VnSelectWorker
|
||||
:label="t('worker.summary.boss')"
|
||||
v-model="data.bossFk"
|
||||
url="Workers/search"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
:rules="validate('Worker.boss')"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt.name }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt.nickname }},
|
||||
{{ scope.opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInput
|
||||
|
|
|
@ -18,6 +18,7 @@ import RightMenu from 'src/components/common/RightMenu.vue';
|
|||
import WorkerFilter from './WorkerFilter.vue';
|
||||
import { useState } from 'src/composables/useState';
|
||||
import axios from 'axios';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableRef = ref();
|
||||
|
@ -260,26 +261,10 @@ async function autofillBic(worker) {
|
|||
option-label="code"
|
||||
hide-selected
|
||||
/>
|
||||
<VnSelect
|
||||
<VnSelectWorker
|
||||
:label="t('worker.summary.boss')"
|
||||
v-model="data.bossFk"
|
||||
url="Workers/search"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>{{ scope.opt.name }}</QItemLabel>
|
||||
<QItemLabel caption
|
||||
>{{ scope.opt.nickname }},
|
||||
{{ scope.opt.code }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnInput v-model="data.fi" :label="t('worker.create.fi')" />
|
||||
|
@ -376,6 +361,7 @@ async function autofillBic(worker) {
|
|||
|
||||
<i18n>
|
||||
es:
|
||||
Create worker: Crear trabajador
|
||||
Search worker: Buscar trabajador
|
||||
You can search by worker id or name: Puedes buscar por id o nombre del trabajador
|
||||
</i18n>
|
||||
|
|
|
@ -32,7 +32,12 @@ const agencyOptions = ref([]);
|
|||
<FormModel :url="`Zones/${route.params.id}`" auto-load model="zone">
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnInput :label="t('Name')" clearable v-model="data.name" />
|
||||
<VnInput
|
||||
data-cy="zone-basic-data-name"
|
||||
:label="t('Name')"
|
||||
clearable
|
||||
v-model="data.name"
|
||||
/>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { ref, onUnmounted } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import ZoneEventsPanel from './ZoneEventsPanel.vue';
|
||||
|
@ -40,8 +40,6 @@ const onZoneEventFormClose = () => {
|
|||
showZoneEventForm.value = false;
|
||||
zoneEventsFormProps.value = {};
|
||||
};
|
||||
|
||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -28,11 +28,7 @@ const agencies = ref([]);
|
|||
@on-fetch="(data) => (agencies = data)"
|
||||
auto-load
|
||||
/>
|
||||
<VnFilterPanel
|
||||
:data-key="props.dataKey"
|
||||
:search-button="true"
|
||||
:hidden-tags="['search']"
|
||||
>
|
||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`filterPanel.${tag.label}`) }}: </strong>
|
||||
|
|
|
@ -75,9 +75,9 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'TravelHistory',
|
||||
path: 'history',
|
||||
path: 'log',
|
||||
meta: {
|
||||
title: 'history',
|
||||
title: 'log',
|
||||
icon: 'history',
|
||||
},
|
||||
component: () => import('src/pages/Travel/Card/TravelLog.vue'),
|
||||
|
|
|
@ -106,7 +106,7 @@ export default {
|
|||
},
|
||||
{
|
||||
name: 'ZoneHistory',
|
||||
path: 'history',
|
||||
path: 'log',
|
||||
meta: {
|
||||
title: 'log',
|
||||
icon: 'history',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
function orderData(data, order) {
|
||||
if (typeof order === 'function') return data.sort(data);
|
||||
if (typeof order === 'string') order = [order];
|
||||
if (!Array.isArray(data)) return [];
|
||||
if (Array.isArray(order)) {
|
||||
let orderComp = [];
|
||||
|
||||
|
|
|
@ -3,11 +3,16 @@ describe('Client fiscal data', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/fiscal-data', {
|
||||
cy.visit('#/customer/1107/fiscal-data', {
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
it('Should change required value when change customer', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
cy.dataCy('sageTaxTypeFk').filter('input').should('not.have.attr', 'required');
|
||||
cy.get('#searchbar input').clear();
|
||||
cy.get('#searchbar input').type('1{enter}');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
|
||||
cy.dataCy('sageTaxTypeFk').filter('input').should('have.attr', 'required');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,11 +43,9 @@ describe('VnLocation', () => {
|
|||
province
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(3) > .q-icon`
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(3) `
|
||||
).click();
|
||||
cy.get(
|
||||
`#q-portal--dialog--5 > .q-dialog > ${createForm.prefix} > .vn-row > .q-select > ${createForm.sufix} > :nth-child(1) input`
|
||||
).should('have.value', province);
|
||||
cy.dataCy('locationProvince').should('have.value', province);
|
||||
});
|
||||
});
|
||||
describe('Worker Create', () => {
|
||||
|
@ -123,32 +121,16 @@ describe('VnLocation', () => {
|
|||
const province = randomString({ length: 4 });
|
||||
cy.get(createLocationButton).click();
|
||||
cy.get(dialogInputs).eq(0).type(postCode);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(2) > .q-icon`
|
||||
).click();
|
||||
cy.selectOption('#q-portal--dialog--3 .q-select', 'one');
|
||||
cy.get('#q-portal--dialog--3 .q-input').type(province);
|
||||
cy.get('#q-portal--dialog--3 .q-btn--standard').click();
|
||||
cy.get('#q-portal--dialog--1 .q-btn--standard').click();
|
||||
cy.dataCy('City_icon').click();
|
||||
cy.selectOption('[data-cy="locationProvince"]:last', 'Province one');
|
||||
cy.dataCy('cityName').type(province);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
cy.dataCy('FormModelPopup_save').eq(0).click();
|
||||
|
||||
cy.waitForElement('.q-form');
|
||||
checkVnLocation(postCode, province);
|
||||
});
|
||||
|
||||
it('Create province without country', () => {
|
||||
const provinceName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(5) > .q-select > ${createForm.sufix} > :nth-child(2) `
|
||||
)
|
||||
.eq(0)
|
||||
.click();
|
||||
cy.selectOption('#q-portal--dialog--3 .q-select', 'one');
|
||||
cy.countSelectOptions('#q-portal--dialog--3 .q-select', 4);
|
||||
cy.get('#q-portal--dialog--3 .q-input').type(provinceName);
|
||||
|
||||
cy.get('#q-portal--dialog--3 .q-btn--standard').click();
|
||||
});
|
||||
|
||||
it('Create city with country', () => {
|
||||
const cityName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
|
@ -156,14 +138,23 @@ describe('VnLocation', () => {
|
|||
`${createForm.prefix} > :nth-child(5) > :nth-child(3) `,
|
||||
'Italia'
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(4) > .q-select > ${createForm.sufix} > :nth-child(2) > .q-icon`
|
||||
).click();
|
||||
cy.selectOption('#q-portal--dialog--4 .q-select', 'Province four');
|
||||
cy.countSelectOptions('#q-portal--dialog--4 .q-select', 1);
|
||||
cy.dataCy('City_icon').click();
|
||||
cy.selectOption('[data-cy="locationProvince"]:last', 'Province four');
|
||||
cy.countSelectOptions('[data-cy="locationProvince"]:last', 1);
|
||||
|
||||
cy.get('#q-portal--dialog--4 .q-input').type(cityName);
|
||||
cy.get('#q-portal--dialog--4 .q-btn--standard').click();
|
||||
cy.dataCy('cityName').type(cityName);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
it('Create province without country', () => {
|
||||
const provinceName = 'Saskatchew'.concat(Math.random(1 * 100));
|
||||
cy.get(createLocationButton).click();
|
||||
cy.dataCy('Province_icon').click();
|
||||
cy.selectOption('[data-cy="autonomyProvince"] ', 'Autonomy one');
|
||||
cy.countSelectOptions('[data-cy="autonomyProvince"]', 4);
|
||||
cy.dataCy('provinceName').type(provinceName);
|
||||
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
it('Create province with country', () => {
|
||||
|
@ -173,17 +164,13 @@ describe('VnLocation', () => {
|
|||
`${createForm.prefix} > :nth-child(5) > :nth-child(3) `,
|
||||
'España'
|
||||
);
|
||||
cy.get(
|
||||
`${createForm.prefix} > :nth-child(5) > .q-select > ${createForm.sufix} > :nth-child(2) `
|
||||
)
|
||||
.eq(0)
|
||||
.click();
|
||||
cy.dataCy('Province_icon').click();
|
||||
|
||||
cy.selectOption('#q-portal--dialog--4 .q-select', 'one');
|
||||
cy.countSelectOptions('#q-portal--dialog--4 .q-select', 2);
|
||||
cy.selectOption('[data-cy="autonomyProvince"] ', 'Autonomy one');
|
||||
cy.countSelectOptions('[data-cy="autonomyProvince"]', 2);
|
||||
|
||||
cy.get('#q-portal--dialog--4 .q-input').type(provinceName);
|
||||
cy.get('#q-portal--dialog--4 .q-btn--standard').click();
|
||||
cy.dataCy('provinceName').type(provinceName);
|
||||
cy.dataCy('FormModelPopup_save').eq(1).click();
|
||||
});
|
||||
|
||||
function checkVnLocation(postCode, province) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
describe('WorkerPda', () => {
|
||||
const deviceProductionField =
|
||||
'.vn-row > .q-field > .q-field__inner > .q-field__control > .q-field__control-container';
|
||||
const select = '[data-cy="pda-dialog-select"]';
|
||||
beforeEach(() => {
|
||||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
|
@ -9,7 +8,8 @@ describe('WorkerPda', () => {
|
|||
|
||||
it('assign pda', () => {
|
||||
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||
cy.get(deviceProductionField).type('{downArrow}{enter}');
|
||||
cy.get(select).click();
|
||||
cy.get(select).type('{downArrow}{enter}');
|
||||
cy.get('.q-notification__message').should('have.text', 'Data created');
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ describe('ZoneBasicData', () => {
|
|||
});
|
||||
|
||||
it('should throw an error if the name is empty', () => {
|
||||
cy.get('.q-card > :nth-child(1)').clear();
|
||||
cy.get('[data-cy="zone-basic-data-name"] input').type('{selectall}{backspace}');
|
||||
cy.get('.q-btn-group > .q-btn--standard').click();
|
||||
cy.get(notification).should('contains.text', "can't be blank");
|
||||
});
|
||||
|
|
|
@ -1,29 +1,50 @@
|
|||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
||||
import { axios } from 'app/test/vitest/helper';
|
||||
import parsePhone from 'src/filters/parsePhone';
|
||||
|
||||
describe('parsePhone filter', () => {
|
||||
it("adds prefix +34 if it doesn't have one", () => {
|
||||
const resultado = parsePhone('123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
beforeAll(async () => {
|
||||
vi.spyOn(axios, 'get').mockReturnValue({ data: { prefix: '34' } });
|
||||
});
|
||||
|
||||
it('maintains prefix +34 if it is already correct', () => {
|
||||
const resultado = parsePhone('+34123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it('no phone', async () => {
|
||||
const phone = await parsePhone(null, '34');
|
||||
expect(phone).toBe(undefined);
|
||||
});
|
||||
|
||||
it('converts prefix 0034 to +34', () => {
|
||||
const resultado = parsePhone('0034123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it("adds prefix +34 if it doesn't have one", async () => {
|
||||
const phone = await parsePhone('123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('converts prefix 34 without symbol to +34', () => {
|
||||
const resultado = parsePhone('34123456789', '34');
|
||||
expect(resultado).toBe('34123456789');
|
||||
it('maintains prefix +34 if it is already correct', async () => {
|
||||
const phone = await parsePhone('+34123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('replaces incorrect prefix with the correct one', () => {
|
||||
const resultado = parsePhone('+44123456789', '34');
|
||||
expect(resultado).toBe('44123456789');
|
||||
it('converts prefix 0034 to +34', async () => {
|
||||
const phone = await parsePhone('0034123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('converts prefix 34 without symbol to +34', async () => {
|
||||
const phone = await parsePhone('34123456789', '34');
|
||||
expect(phone).toBe('34123456789');
|
||||
});
|
||||
|
||||
it('replaces incorrect prefix with the correct one', async () => {
|
||||
const phone = await parsePhone('+44123456789', '34');
|
||||
expect(phone).toBe('44123456789');
|
||||
});
|
||||
|
||||
it('adds default prefix on error', async () => {
|
||||
vi.spyOn(axios, 'get').mockImplementation((url) => {
|
||||
if (url.includes('Prefixes'))
|
||||
return Promise.reject(new Error('Network error'));
|
||||
else if (url.includes('PbxConfigs'))
|
||||
return Promise.resolve({ data: { defaultPrefix: '39' } });
|
||||
});
|
||||
const phone = await parsePhone('123456789', '34');
|
||||
expect(phone).toBe('39123456789');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -44,7 +44,18 @@ vi.mock('vue-router', () => ({
|
|||
vi.mock('axios');
|
||||
|
||||
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 {
|
||||
|
|
Loading…
Reference in New Issue