Merge remote-tracking branch 'origin/dev' into formModel_mapper
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
4892e96755
3095
CHANGELOG.md
3095
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "25.08.0",
|
||||
"version": "25.10.0",
|
||||
"description": "Salix frontend",
|
||||
"productName": "Salix",
|
||||
"author": "Verdnatura",
|
||||
|
@ -71,4 +71,4 @@
|
|||
"vite": "^6.0.11",
|
||||
"vitest": "^0.31.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,22 +30,5 @@ export default {
|
|||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
form.addEventListener('keyup', function (evt) {
|
||||
if (evt.key === 'Enter' && !that.$attrs['prevent-submit']) {
|
||||
const input = evt.target;
|
||||
if (input.type == 'textarea' && evt.shiftKey) {
|
||||
evt.preventDefault();
|
||||
let { selectionStart, selectionEnd } = input;
|
||||
input.value =
|
||||
input.value.substring(0, selectionStart) +
|
||||
'\n' +
|
||||
input.value.substring(selectionEnd);
|
||||
selectionStart = selectionEnd = selectionStart + 1;
|
||||
return;
|
||||
}
|
||||
evt.preventDefault();
|
||||
that.onSubmit();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
import { reactive, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectProvince from 'src/components/VnSelectProvince.vue';
|
||||
|
@ -21,14 +20,11 @@ const postcodeFormData = reactive({
|
|||
provinceFk: null,
|
||||
townFk: null,
|
||||
});
|
||||
const townsFetchDataRef = ref(false);
|
||||
const townFilter = ref({});
|
||||
|
||||
const countriesRef = ref(false);
|
||||
const provincesOptions = ref([]);
|
||||
const townsOptions = ref([]);
|
||||
const town = ref({});
|
||||
const countryFilter = ref({});
|
||||
|
||||
function onDataSaved(formData) {
|
||||
const newPostcode = {
|
||||
|
@ -51,7 +47,6 @@ async function setCountry(countryFk, data) {
|
|||
data.townFk = null;
|
||||
data.provinceFk = null;
|
||||
data.countryFk = countryFk;
|
||||
await fetchTowns();
|
||||
}
|
||||
|
||||
// Province
|
||||
|
@ -60,22 +55,11 @@ async function setProvince(id, data) {
|
|||
const newProvince = provincesOptions.value.find((province) => province.id == id);
|
||||
if (newProvince) data.countryFk = newProvince.countryFk;
|
||||
postcodeFormData.provinceFk = id;
|
||||
await fetchTowns();
|
||||
}
|
||||
|
||||
async function onProvinceCreated(data) {
|
||||
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;
|
||||
|
@ -88,18 +72,6 @@ async function onCityCreated(newTown, formData) {
|
|||
formData.townFk = newTown;
|
||||
setTown(newTown, formData);
|
||||
}
|
||||
async function fetchTowns(countryFk = postcodeFormData.countryFk) {
|
||||
if (!countryFk) return;
|
||||
const provinces = postcodeFormData.provinceFk
|
||||
? [postcodeFormData.provinceFk]
|
||||
: provinceByCountry();
|
||||
townFilter.value.where = {
|
||||
provinceFk: {
|
||||
inq: provinces,
|
||||
},
|
||||
};
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
|
||||
async function filterTowns(name) {
|
||||
if (name !== '') {
|
||||
|
@ -108,22 +80,11 @@ async function filterTowns(name) {
|
|||
like: `%${name}%`,
|
||||
},
|
||||
};
|
||||
await townsFetchDataRef.value?.fetch();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
ref="townsFetchDataRef"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
:filter="townFilter"
|
||||
@on-fetch="handleTowns"
|
||||
auto-load
|
||||
url="Towns/location"
|
||||
/>
|
||||
|
||||
<FormModelPopup
|
||||
url-create="postcodes"
|
||||
model="postcode"
|
||||
|
@ -149,14 +110,13 @@ async function filterTowns(name) {
|
|||
@filter="filterTowns"
|
||||
:tooltip="t('Create city')"
|
||||
v-model="data.townFk"
|
||||
:options="townsOptions"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
url="Towns/location"
|
||||
:rules="validate('postcode.city')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
:emit-value="false"
|
||||
required
|
||||
data-cy="locationTown"
|
||||
sort-by="name ASC"
|
||||
>
|
||||
<template #option="{ itemProps, opt }">
|
||||
<QItem v-bind="itemProps">
|
||||
|
@ -197,16 +157,12 @@ async function filterTowns(name) {
|
|||
/>
|
||||
<VnSelect
|
||||
ref="countriesRef"
|
||||
:limit="30"
|
||||
:filter="countryFilter"
|
||||
:sort-by="['name ASC']"
|
||||
auto-load
|
||||
url="Countries"
|
||||
required
|
||||
:label="t('Country')"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="data.countryFk"
|
||||
:rules="validate('postcode.countryFk')"
|
||||
@update:model-value="(value) => setCountry(value, data)"
|
||||
|
|
|
@ -62,12 +62,9 @@ const where = computed(() => {
|
|||
auto-load
|
||||
:where="where"
|
||||
url="Autonomies/location"
|
||||
:sort-by="['name ASC']"
|
||||
:limit="30"
|
||||
sort-by="name ASC"
|
||||
:label="t('Autonomy')"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="data.autonomyFk"
|
||||
:rules="validate('province.autonomyFk')"
|
||||
>
|
||||
|
|
|
@ -42,7 +42,6 @@ const itemFilter = {
|
|||
const itemFilterParams = reactive({});
|
||||
const closeButton = ref(null);
|
||||
const isLoading = ref(false);
|
||||
const producersOptions = ref([]);
|
||||
const ItemTypesOptions = ref([]);
|
||||
const InksOptions = ref([]);
|
||||
const tableRows = ref([]);
|
||||
|
@ -121,23 +120,17 @@ const selectItem = ({ id }) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="Producers"
|
||||
@on-fetch="(data) => (producersOptions = data)"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="ItemTypes"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
order="name"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||
order="name ASC"
|
||||
@on-fetch="(data) => (ItemTypesOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
url="Inks"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
order="name"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||
order="name ASC"
|
||||
@on-fetch="(data) => (InksOptions = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
@ -152,11 +145,11 @@ const selectItem = ({ id }) => {
|
|||
<VnInput :label="t('entry.buys.size')" v-model="itemFilterParams.size" />
|
||||
<VnSelect
|
||||
:label="t('globals.producer')"
|
||||
:options="producersOptions"
|
||||
hide-selected
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
v-model="itemFilterParams.producerFk"
|
||||
url="Producers"
|
||||
:fields="['id', 'name']"
|
||||
sort-by="name ASC"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('globals.type')"
|
||||
|
|
|
@ -124,7 +124,7 @@ const selectTravel = ({ id }) => {
|
|||
<FetchData
|
||||
url="AgencyModes"
|
||||
@on-fetch="(data) => (agenciesOptions = data)"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import axios from 'axios';
|
||||
import { onMounted, onUnmounted, computed, ref, watch, nextTick } from 'vue';
|
||||
import { onMounted, onUnmounted, computed, ref, watch, nextTick, useAttrs } from 'vue';
|
||||
import { onBeforeRouteLeave, useRouter, useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useQuasar } from 'quasar';
|
||||
|
@ -23,6 +23,7 @@ const { validate } = useValidator();
|
|||
const { notify } = useNotify();
|
||||
const route = useRoute();
|
||||
const myForm = ref(null);
|
||||
const attrs = useAttrs();
|
||||
const $props = defineProps({
|
||||
url: {
|
||||
type: String,
|
||||
|
@ -107,14 +108,14 @@ const isLoading = ref(false);
|
|||
const isResetting = ref(false);
|
||||
const hasChanges = ref(!$props.observeFormChanges);
|
||||
const originalData = computed(() => state.get(modelValue));
|
||||
const formData = ref({});
|
||||
const formData = ref();
|
||||
const defaultButtons = computed(() => ({
|
||||
save: {
|
||||
dataCy: 'saveDefaultBtn',
|
||||
color: 'primary',
|
||||
icon: 'save',
|
||||
label: 'globals.save',
|
||||
click: () => myForm.value.onSubmit(false),
|
||||
click: async () => await save(),
|
||||
type: 'submit',
|
||||
},
|
||||
reset: {
|
||||
|
@ -135,7 +136,8 @@ onMounted(async () => {
|
|||
|
||||
if (!$props.formInitialData) {
|
||||
if ($props.autoLoad && $props.url) await fetch();
|
||||
else if (arrayData.store.data) updateAndEmit('onFetch', arrayData.store.data);
|
||||
else if (arrayData.store.data)
|
||||
updateAndEmit('onFetch', { val: arrayData.store.data });
|
||||
}
|
||||
if ($props.observeFormChanges) {
|
||||
watch(
|
||||
|
@ -155,7 +157,7 @@ onMounted(async () => {
|
|||
if (!$props.url)
|
||||
watch(
|
||||
() => arrayData.store.data,
|
||||
(val) => updateAndEmit('onFetch', val),
|
||||
(val) => updateAndEmit('onFetch', { val }),
|
||||
);
|
||||
|
||||
watch(
|
||||
|
@ -201,15 +203,14 @@ async function fetch() {
|
|||
});
|
||||
if (Array.isArray(data)) data = data[0] ?? {};
|
||||
|
||||
updateAndEmit('onFetch', data);
|
||||
updateAndEmit('onFetch', { val: data });
|
||||
} catch (e) {
|
||||
state.set(modelValue, {});
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async function save(prevent = false) {
|
||||
if (prevent) return;
|
||||
async function save() {
|
||||
if ($props.observeFormChanges && !hasChanges.value)
|
||||
return notify('globals.noChanges', 'negative');
|
||||
|
||||
|
@ -229,7 +230,11 @@ async function save(prevent = false) {
|
|||
|
||||
if ($props.urlCreate) notify('globals.dataCreated', 'positive');
|
||||
|
||||
updateAndEmit('onDataSaved', formData.value, response?.data);
|
||||
updateAndEmit('onDataSaved', {
|
||||
val: formData.value,
|
||||
res: response?.data,
|
||||
old: originalData.value,
|
||||
});
|
||||
if ($props.reload) await arrayData.fetch({});
|
||||
hasChanges.value = false;
|
||||
} finally {
|
||||
|
@ -244,7 +249,7 @@ async function saveAndGo() {
|
|||
|
||||
function reset() {
|
||||
formData.value = JSON.parse(JSON.stringify(originalData.value));
|
||||
updateAndEmit('onFetch', originalData.value);
|
||||
updateAndEmit('onFetch', { val: originalData.value });
|
||||
if ($props.observeFormChanges) {
|
||||
hasChanges.value = false;
|
||||
isResetting.value = true;
|
||||
|
@ -266,11 +271,11 @@ function filter(value, update, filterOptions) {
|
|||
);
|
||||
}
|
||||
|
||||
function updateAndEmit(evt, val, res) {
|
||||
function updateAndEmit(evt, { val, res, old } = { val: null, res: null, old: null }) {
|
||||
state.set(modelValue, val);
|
||||
if (!$props.url) arrayData.store.data = val;
|
||||
|
||||
emit(evt, state.get(modelValue), res);
|
||||
emit(evt, state.get(modelValue), res, old);
|
||||
}
|
||||
|
||||
function trimData(data) {
|
||||
|
@ -286,6 +291,22 @@ function onBeforeSave(formData, originalData) {
|
|||
formData,
|
||||
);
|
||||
}
|
||||
async function onKeyup(evt) {
|
||||
if (evt.key === 'Enter' && !('prevent-submit' in attrs)) {
|
||||
const input = evt.target;
|
||||
if (input.type == 'textarea' && evt.shiftKey) {
|
||||
let { selectionStart, selectionEnd } = input;
|
||||
input.value =
|
||||
input.value.substring(0, selectionStart) +
|
||||
'\n' +
|
||||
input.value.substring(selectionEnd);
|
||||
selectionStart = selectionEnd = selectionStart + 1;
|
||||
return;
|
||||
}
|
||||
await save();
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
save,
|
||||
isLoading,
|
||||
|
@ -300,12 +321,12 @@ defineExpose({
|
|||
<QForm
|
||||
ref="myForm"
|
||||
v-if="formData"
|
||||
@submit="save(!!$event)"
|
||||
@submit.prevent
|
||||
@keyup.prevent="onKeyup"
|
||||
@reset="reset"
|
||||
class="q-pa-md"
|
||||
:style="maxWidth ? 'max-width: ' + maxWidth : ''"
|
||||
id="formModel"
|
||||
:prevent-submit="$attrs['prevent-submit']"
|
||||
:mapper="onBeforeSave"
|
||||
>
|
||||
<QCard>
|
||||
|
|
|
@ -27,10 +27,15 @@ const formModelRef = ref(null);
|
|||
const closeButton = ref(null);
|
||||
const isSaveAndContinue = ref(false);
|
||||
const onDataSaved = (formData, requestResponse) => {
|
||||
if (closeButton.value && isSaveAndContinue) closeButton.value.click();
|
||||
if (closeButton.value && !isSaveAndContinue.value) closeButton.value.click();
|
||||
emit('onDataSaved', formData, requestResponse);
|
||||
};
|
||||
|
||||
const onClick = async (saveAndContinue) => {
|
||||
isSaveAndContinue.value = saveAndContinue;
|
||||
await formModelRef.value.save();
|
||||
};
|
||||
|
||||
const isLoading = computed(() => formModelRef.value?.isLoading);
|
||||
const reset = computed(() => formModelRef.value?.reset);
|
||||
|
||||
|
@ -78,10 +83,7 @@ defineExpose({
|
|||
:flat="showSaveAndContinueBtn"
|
||||
:label="t('globals.save')"
|
||||
:title="t('globals.save')"
|
||||
@click="
|
||||
formModelRef.save();
|
||||
isSaveAndContinue = false;
|
||||
"
|
||||
@click="onClick(false)"
|
||||
color="primary"
|
||||
class="q-ml-sm"
|
||||
:disabled="isLoading"
|
||||
|
@ -99,10 +101,7 @@ defineExpose({
|
|||
:loading="isLoading"
|
||||
data-cy="FormModelPopup_isSaveAndContinue"
|
||||
z-max
|
||||
@click="
|
||||
isSaveAndContinue = true;
|
||||
formModelRef.save();
|
||||
"
|
||||
@click="onClick(true)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -121,23 +121,25 @@ const removeTag = (index, params, search) => {
|
|||
applyTags(params, search);
|
||||
};
|
||||
const setCategoryList = (data) => {
|
||||
categoryList.value = (data || [])
|
||||
.filter((category) => category.display)
|
||||
.map((category) => ({
|
||||
...category,
|
||||
icon: `vn:${(category.icon || '').split('-')[1]}`,
|
||||
}));
|
||||
categoryList.value = (data || []).map((category) => ({
|
||||
...category,
|
||||
icon: `vn:${(category.icon || '').split('-')[1]}`,
|
||||
}));
|
||||
fetchItemTypes();
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData url="ItemCategories" limit="30" auto-load @on-fetch="setCategoryList" />
|
||||
<FetchData
|
||||
url="ItemCategories"
|
||||
auto-load
|
||||
@on-fetch="setCategoryList"
|
||||
:where="{ display: { neq: 0 } }"
|
||||
/>
|
||||
<FetchData
|
||||
url="Tags"
|
||||
:filter="{ fields: ['id', 'name', 'isFree'] }"
|
||||
auto-load
|
||||
limit="30"
|
||||
@on-fetch="(data) => (tagOptions = data)"
|
||||
/>
|
||||
<VnFilterPanel
|
||||
|
@ -195,8 +197,6 @@ const setCategoryList = (data) => {
|
|||
:label="t('components.itemsFilterPanel.typeFk')"
|
||||
v-model="params.typeFk"
|
||||
:options="itemTypesOptions"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
@ -234,7 +234,6 @@ const setCategoryList = (data) => {
|
|||
:label="t('globals.tag')"
|
||||
v-model="value.selectedTag"
|
||||
:options="tagOptions"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
|
|
@ -1,8 +1,22 @@
|
|||
<script setup>
|
||||
import { toCurrency } from 'src/filters';
|
||||
|
||||
defineProps({ row: { type: Object, required: true } });
|
||||
</script>
|
||||
<template>
|
||||
<span class="q-gutter-x-xs">
|
||||
<router-link
|
||||
v-if="row.claim?.claimFk"
|
||||
:to="{ name: 'ClaimBasicData', params: { id: row.claim?.claimFk } }"
|
||||
class="link"
|
||||
>
|
||||
<QIcon name="vn:claims" size="xs">
|
||||
<QTooltip>
|
||||
{{ t('ticketSale.claim') }}:
|
||||
{{ row.claim?.claimFk }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</router-link>
|
||||
<QIcon
|
||||
v-if="row?.risk"
|
||||
name="vn:risk"
|
||||
|
@ -10,7 +24,8 @@ defineProps({ row: { type: Object, required: true } });
|
|||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ $t('salesTicketsTable.risk') }}: {{ row.risk - row.credit }}
|
||||
{{ $t('salesTicketsTable.risk') }}:
|
||||
{{ toCurrency(row.risk - row.credit) }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
|
@ -53,7 +68,7 @@ defineProps({ row: { type: Object, required: true } });
|
|||
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="!row?.isTaxDataChecked === 0"
|
||||
v-if="row?.isTaxDataChecked !== 0"
|
||||
name="vn:no036"
|
||||
color="primary"
|
||||
size="xs"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { markRaw, computed } from 'vue';
|
||||
import { QIcon, QCheckbox, QToggle } from 'quasar';
|
||||
import { QIcon, QToggle } from 'quasar';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
|
|
|
@ -10,14 +10,15 @@ import {
|
|||
render,
|
||||
inject,
|
||||
useAttrs,
|
||||
nextTick,
|
||||
} from 'vue';
|
||||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import { useQuasar, date } from 'quasar';
|
||||
import { useStateStore } from 'stores/useStateStore';
|
||||
import { useFilterParams } from 'src/composables/useFilterParams';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import { dashIfEmpty, toDate } from 'src/filters';
|
||||
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||
|
@ -164,7 +165,6 @@ const app = inject('app');
|
|||
const editingRow = ref(null);
|
||||
const editingField = ref(null);
|
||||
const isTableMode = computed(() => mode.value == TABLE_MODE);
|
||||
const showRightIcon = computed(() => $props.rightSearch || $props.rightSearchIcon);
|
||||
const selectRegex = /select/;
|
||||
const emit = defineEmits(['onFetch', 'update:selected', 'saveChanges']);
|
||||
const tableModes = [
|
||||
|
@ -345,7 +345,7 @@ const clickHandler = async (event) => {
|
|||
if (isDateElement || isTimeElement || isQselectDropDown) return;
|
||||
|
||||
if (clickedElement === null) {
|
||||
destroyInput(editingRow.value, editingField.value);
|
||||
await destroyInput(editingRow.value, editingField.value);
|
||||
return;
|
||||
}
|
||||
const rowIndex = clickedElement.getAttribute('data-row-index');
|
||||
|
@ -353,19 +353,19 @@ const clickHandler = async (event) => {
|
|||
const column = $props.columns.find((col) => col.name === colField);
|
||||
|
||||
if (editingRow.value !== null && editingField.value !== null) {
|
||||
if (editingRow.value === rowIndex && editingField.value === colField) {
|
||||
return;
|
||||
}
|
||||
if (editingRow.value == rowIndex && editingField.value == colField) return;
|
||||
|
||||
destroyInput(editingRow.value, editingField.value);
|
||||
await destroyInput(editingRow.value, editingField.value);
|
||||
}
|
||||
if (isEditableColumn(column))
|
||||
|
||||
if (isEditableColumn(column)) {
|
||||
await renderInput(Number(rowIndex), colField, clickedElement);
|
||||
}
|
||||
};
|
||||
|
||||
async function handleTabKey(event, rowIndex, colField) {
|
||||
if (editingRow.value == rowIndex && editingField.value == colField)
|
||||
destroyInput(editingRow.value, editingField.value);
|
||||
await destroyInput(editingRow.value, editingField.value);
|
||||
|
||||
const direction = event.shiftKey ? -1 : 1;
|
||||
const { nextRowIndex, nextColumnName } = await handleTabNavigation(
|
||||
|
@ -425,7 +425,8 @@ async function renderInput(rowId, field, clickedElement) {
|
|||
await column?.cellEvent?.['update:modelValue']?.(value, oldValue, row);
|
||||
},
|
||||
keyup: async (event) => {
|
||||
if (event.key === 'Enter') handleBlur(rowId, field, clickedElement);
|
||||
if (event.key === 'Enter')
|
||||
await destroyInput(rowIndex, field, clickedElement);
|
||||
},
|
||||
keydown: async (event) => {
|
||||
switch (event.key) {
|
||||
|
@ -434,7 +435,7 @@ async function renderInput(rowId, field, clickedElement) {
|
|||
event.stopPropagation();
|
||||
break;
|
||||
case 'Escape':
|
||||
destroyInput(rowId, field, clickedElement);
|
||||
await destroyInput(rowId, field, clickedElement);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -456,12 +457,13 @@ async function renderInput(rowId, field, clickedElement) {
|
|||
node.el?.querySelector('span > div > div').focus();
|
||||
}
|
||||
|
||||
function destroyInput(rowIndex, field, clickedElement) {
|
||||
async function destroyInput(rowIndex, field, clickedElement) {
|
||||
if (!clickedElement)
|
||||
clickedElement = document.querySelector(
|
||||
`[data-row-index="${rowIndex}"][data-col-field="${field}"]`,
|
||||
);
|
||||
if (clickedElement) {
|
||||
await nextTick();
|
||||
render(null, clickedElement);
|
||||
Array.from(clickedElement.childNodes).forEach((child) => {
|
||||
child.style.visibility = 'visible';
|
||||
|
@ -473,10 +475,6 @@ function destroyInput(rowIndex, field, clickedElement) {
|
|||
editingField.value = null;
|
||||
}
|
||||
|
||||
function handleBlur(rowIndex, field, clickedElement) {
|
||||
destroyInput(rowIndex, field, clickedElement);
|
||||
}
|
||||
|
||||
async function handleTabNavigation(rowIndex, colName, direction) {
|
||||
const columns = $props.columns;
|
||||
const totalColumns = columns.length;
|
||||
|
@ -492,9 +490,7 @@ async function handleTabNavigation(rowIndex, colName, direction) {
|
|||
if (isEditableColumn(columns[newColumnIndex])) break;
|
||||
} while (iterations < totalColumns);
|
||||
|
||||
if (iterations >= totalColumns) {
|
||||
return;
|
||||
}
|
||||
if (iterations >= totalColumns + 1) return;
|
||||
|
||||
if (direction === 1 && newColumnIndex <= currentColumnIndex) {
|
||||
rowIndex++;
|
||||
|
@ -529,11 +525,36 @@ function formatColumnValue(col, row, dashIfEmpty) {
|
|||
} else {
|
||||
return col.format(row, dashIfEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
if (col?.component === 'date') return dashIfEmpty(toDate(row[col?.name]));
|
||||
|
||||
if (col?.component === 'time')
|
||||
return row[col?.name] >= 5
|
||||
? dashIfEmpty(date.formatDate(new Date(row[col?.name]), 'HH:mm'))
|
||||
: row[col?.name];
|
||||
|
||||
if (selectRegex.test(col?.component) && $props.isEditable) {
|
||||
const { find, url } = col.attrs;
|
||||
const urlRelation = url?.charAt(0)?.toLocaleLowerCase() + url?.slice(1, -1);
|
||||
|
||||
if (col?.attrs.options) {
|
||||
const find = col?.attrs.options.find((option) => option.id === row[col.name]);
|
||||
if (!col.attrs?.optionLabel || !find) return dashIfEmpty(row[col?.name]);
|
||||
return dashIfEmpty(find[col.attrs?.optionLabel ?? 'name']);
|
||||
}
|
||||
|
||||
if (typeof row[urlRelation] == 'object') {
|
||||
if (typeof find == 'object')
|
||||
return dashIfEmpty(row[urlRelation][find?.label ?? 'name']);
|
||||
|
||||
return dashIfEmpty(row[urlRelation][col?.attrs.optionLabel ?? 'name']);
|
||||
}
|
||||
if (typeof row[urlRelation] == 'string') return dashIfEmpty(row[urlRelation]);
|
||||
} else {
|
||||
return dashIfEmpty(row[col?.name]);
|
||||
}
|
||||
}
|
||||
const checkbox = ref(null);
|
||||
function cardClick(_, row) {
|
||||
if ($props.redirect) router.push({ path: `/${$props.redirect}/${row.id}` });
|
||||
}
|
||||
|
@ -620,14 +641,6 @@ function cardClick(_, row) {
|
|||
dense
|
||||
:options="tableModes.filter((mode) => !mode.disable)"
|
||||
/>
|
||||
|
||||
<QBtn
|
||||
v-if="showRightIcon"
|
||||
icon="filter_alt"
|
||||
class="bg-vn-section-color q-ml-sm"
|
||||
dense
|
||||
@click="stateStore.toggleRightDrawer()"
|
||||
/>
|
||||
</template>
|
||||
<template #header-cell="{ col }">
|
||||
<QTh
|
||||
|
@ -732,7 +745,11 @@ function cardClick(_, row) {
|
|||
<span
|
||||
v-else
|
||||
:class="hasEditableFormat(col)"
|
||||
:style="col?.style ? col.style(row) : null"
|
||||
:style="
|
||||
typeof col?.style == 'function'
|
||||
? col.style(row)
|
||||
: col?.style
|
||||
"
|
||||
style="bottom: 0"
|
||||
>
|
||||
{{ formatColumnValue(col, row, dashIfEmpty) }}
|
||||
|
@ -759,7 +776,7 @@ function cardClick(_, row) {
|
|||
flat
|
||||
dense
|
||||
:class="
|
||||
btn.isPrimary ? 'text-primary-light' : 'color-vn-text '
|
||||
btn.isPrimary ? 'text-primary-light' : 'color-vn-label'
|
||||
"
|
||||
:style="`visibility: ${
|
||||
((btn.show && btn.show(row)) ?? true)
|
||||
|
@ -767,6 +784,7 @@ function cardClick(_, row) {
|
|||
: 'hidden'
|
||||
}`"
|
||||
@click="btn.action(row)"
|
||||
:data-cy="btn?.name ?? `tableAction-${index}`"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
|
@ -815,7 +833,7 @@ function cardClick(_, row) {
|
|||
</QCardSection>
|
||||
<!-- Fields -->
|
||||
<QCardSection
|
||||
class="q-pl-sm q-pr-lg q-py-xs"
|
||||
class="q-pl-sm q-py-xs"
|
||||
:class="$props.cardClass"
|
||||
>
|
||||
<div
|
||||
|
@ -862,13 +880,14 @@ function cardClick(_, row) {
|
|||
:key="index"
|
||||
:title="btn.title"
|
||||
:icon="btn.icon"
|
||||
data-cy="cardBtn"
|
||||
class="q-pa-xs"
|
||||
flat
|
||||
:class="
|
||||
btn.isPrimary
|
||||
? 'text-primary-light'
|
||||
: 'color-vn-text '
|
||||
: 'color-vn-label'
|
||||
"
|
||||
flat
|
||||
@click="btn.action(row)"
|
||||
/>
|
||||
</QCardSection>
|
||||
|
@ -1121,6 +1140,7 @@ es:
|
|||
.vn-label-value {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
color: var(--vn-text-color);
|
||||
.value {
|
||||
overflow: hidden;
|
||||
|
|
|
@ -57,6 +57,7 @@ describe('FormModel', () => {
|
|||
vm.state.set(model, formInitialData);
|
||||
expect(vm.hasChanges).toBe(false);
|
||||
|
||||
await vm.$nextTick();
|
||||
vm.formData.mockKey = 'newVal';
|
||||
await vm.$nextTick();
|
||||
expect(vm.hasChanges).toBe(true);
|
||||
|
@ -94,8 +95,12 @@ describe('FormModel', () => {
|
|||
it('should call axios.patch with the right data', async () => {
|
||||
const spy = vi.spyOn(axios, 'patch').mockResolvedValue({ data: {} });
|
||||
const { vm } = mount({ propsData: { url, model } });
|
||||
vm.formData.mockKey = 'newVal';
|
||||
|
||||
vm.formData = {};
|
||||
await vm.$nextTick();
|
||||
vm.formData = { mockKey: 'newVal' };
|
||||
await vm.$nextTick();
|
||||
|
||||
await vm.save();
|
||||
expect(spy).toHaveBeenCalled();
|
||||
vm.formData.mockKey = 'mockVal';
|
||||
|
|
|
@ -39,6 +39,13 @@ onBeforeMount(async () => {
|
|||
});
|
||||
|
||||
onBeforeRouteUpdate(async (to, from) => {
|
||||
if (hasRouteParam(to.params)) {
|
||||
const { matched } = router.currentRoute.value;
|
||||
const { name } = matched.at(-3);
|
||||
if (name) {
|
||||
router.push({ name, params: to.params });
|
||||
}
|
||||
}
|
||||
const id = to.params.id;
|
||||
if (id !== from.params.id) await fetch(id, true);
|
||||
});
|
||||
|
@ -50,6 +57,9 @@ async function fetch(id, append = false) {
|
|||
else arrayData.store.url = props.url.replace(regex, `/${id}`);
|
||||
await arrayData.fetch({ append, updateRouter: false });
|
||||
}
|
||||
function hasRouteParam(params, valueToCheck = ':addressId') {
|
||||
return Object.values(params).includes(valueToCheck);
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Teleport to="#left-panel" v-if="stateStore.isHeaderMounted()">
|
||||
|
|
|
@ -85,6 +85,7 @@ const handleModelValue = (data) => {
|
|||
:tooltip="t('Create new location')"
|
||||
:rules="mixinRules"
|
||||
:lazy-rules="true"
|
||||
required
|
||||
>
|
||||
<template #form>
|
||||
<CreateNewPostcode
|
||||
|
|
|
@ -193,22 +193,24 @@ const toModule = computed(() =>
|
|||
</div>
|
||||
</QItemLabel>
|
||||
<QItem>
|
||||
<QItemLabel class="subtitle" caption>
|
||||
<QItemLabel class="subtitle">
|
||||
#{{ getValueFromPath(subtitle) ?? entity.id }}
|
||||
<QBtn
|
||||
round
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="content_copy"
|
||||
color="primary"
|
||||
@click.stop="copyIdText(entity.id)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('globals.copyId') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
</QItemLabel>
|
||||
|
||||
<QBtn
|
||||
round
|
||||
flat
|
||||
dense
|
||||
size="sm"
|
||||
icon="content_copy"
|
||||
color="primary"
|
||||
@click.stop="copyIdText(entity.id)"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('globals.copyId') }}
|
||||
</QTooltip>
|
||||
</QBtn>
|
||||
<!-- </QItemLabel> -->
|
||||
</QItem>
|
||||
</QList>
|
||||
<div class="list-box q-mt-xs">
|
||||
|
|
|
@ -53,3 +53,8 @@ const manaCode = ref(props.manaCode);
|
|||
/>
|
||||
</div>
|
||||
</template>
|
||||
<i18n>
|
||||
es:
|
||||
Promotion mana: Maná promoción
|
||||
Claim mana: Maná reclamación
|
||||
</i18n>
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { useRequired } from '../useRequired';
|
||||
|
||||
vi.mock('../useValidator', () => ({
|
||||
useValidator: () => ({
|
||||
validations: () => ({
|
||||
required: vi.fn((isRequired, val) => {
|
||||
if (!isRequired) return true;
|
||||
return val !== null && val !== undefined && val !== '';
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('useRequired', () => {
|
||||
it('should detect required when attr is boolean true', () => {
|
||||
const attrs = { required: true };
|
||||
const { isRequired } = useRequired(attrs);
|
||||
expect(isRequired).toBe(true);
|
||||
});
|
||||
|
||||
it('should detect required when attr is boolean false', () => {
|
||||
const attrs = { required: false };
|
||||
const { isRequired } = useRequired(attrs);
|
||||
expect(isRequired).toBe(false);
|
||||
});
|
||||
|
||||
it('should detect required when attr exists without value', () => {
|
||||
const attrs = { required: '' };
|
||||
const { isRequired } = useRequired(attrs);
|
||||
expect(isRequired).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when required attr does not exist', () => {
|
||||
const attrs = { someOtherAttr: 'value' };
|
||||
const { isRequired } = useRequired(attrs);
|
||||
expect(isRequired).toBe(false);
|
||||
});
|
||||
|
||||
describe('requiredFieldRule', () => {
|
||||
it('should validate required field with value', () => {
|
||||
const attrs = { required: true };
|
||||
const { requiredFieldRule } = useRequired(attrs);
|
||||
expect(requiredFieldRule('some value')).toBe(true);
|
||||
});
|
||||
|
||||
it('should validate required field with empty value', () => {
|
||||
const attrs = { required: true };
|
||||
const { requiredFieldRule } = useRequired(attrs);
|
||||
expect(requiredFieldRule('')).toBe(false);
|
||||
});
|
||||
|
||||
it('should pass validation when field is not required', () => {
|
||||
const attrs = { required: false };
|
||||
const { requiredFieldRule } = useRequired(attrs);
|
||||
expect(requiredFieldRule('')).toBe(true);
|
||||
});
|
||||
|
||||
it('should handle null and undefined values', () => {
|
||||
const attrs = { required: true };
|
||||
const { requiredFieldRule } = useRequired(attrs);
|
||||
expect(requiredFieldRule(null)).toBe(false);
|
||||
expect(requiredFieldRule(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -7,6 +7,7 @@ export function getColAlign(col) {
|
|||
case 'number':
|
||||
align = 'right';
|
||||
break;
|
||||
case 'time':
|
||||
case 'date':
|
||||
case 'checkbox':
|
||||
align = 'center';
|
||||
|
|
|
@ -11,7 +11,7 @@ export async function useCau(res, message) {
|
|||
const { config, headers, request, status, statusText, data } = res || {};
|
||||
const { params, url, method, signal, headers: confHeaders } = config || {};
|
||||
const { message: resMessage, code, name } = data?.error || {};
|
||||
delete confHeaders.Authorization;
|
||||
delete confHeaders?.Authorization;
|
||||
|
||||
const additionalData = {
|
||||
path: location.hash,
|
||||
|
|
|
@ -2,14 +2,10 @@ import { useValidator } from 'src/composables/useValidator';
|
|||
|
||||
export function useRequired($attrs) {
|
||||
const { validations } = useValidator();
|
||||
const hasRequired = Object.keys($attrs).includes('required');
|
||||
let isRequired = false;
|
||||
if (hasRequired) {
|
||||
const required = $attrs['required'];
|
||||
if (typeof required === 'boolean') {
|
||||
isRequired = required;
|
||||
}
|
||||
}
|
||||
const isRequired =
|
||||
typeof $attrs['required'] === 'boolean'
|
||||
? $attrs['required']
|
||||
: Object.keys($attrs).includes('required');
|
||||
const requiredFieldRule = (val) => validations().required(isRequired, val);
|
||||
|
||||
return {
|
||||
|
|
|
@ -335,3 +335,7 @@ input::-webkit-inner-spin-button {
|
|||
border: 1px solid;
|
||||
box-shadow: 0 4px 6px #00000000;
|
||||
}
|
||||
|
||||
.containerShrinked {
|
||||
width: 80%;
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ globals:
|
|||
rowRemoved: Row removed
|
||||
pleaseWait: Please wait...
|
||||
noPinnedModules: You don't have any pinned modules
|
||||
enterToConfirm: Press Enter to confirm
|
||||
summary:
|
||||
basicData: Basic data
|
||||
daysOnward: Days onward
|
||||
|
@ -830,6 +831,8 @@ travel:
|
|||
CloneTravelAndEntries: Clone travel and his entries
|
||||
deleteTravel: Delete travel
|
||||
AddEntry: Add entry
|
||||
availabled: Availabled
|
||||
availabledHour: Availabled hour
|
||||
thermographs: Thermographs
|
||||
hb: HB
|
||||
basicData:
|
||||
|
|
|
@ -51,6 +51,7 @@ globals:
|
|||
pleaseWait: Por favor espera...
|
||||
noPinnedModules: No has fijado ningún módulo
|
||||
split: Split
|
||||
enterToConfirm: Pulsa Enter para confirmar
|
||||
summary:
|
||||
basicData: Datos básicos
|
||||
daysOnward: Días adelante
|
||||
|
@ -839,6 +840,7 @@ supplier:
|
|||
verified: Verificado
|
||||
isActive: Está activo
|
||||
billingData: Forma de pago
|
||||
financialData: Datos financieros
|
||||
payDeadline: Plazo de pago
|
||||
payDay: Día de pago
|
||||
account: Cuenta
|
||||
|
@ -916,6 +918,8 @@ travel:
|
|||
deleteTravel: Eliminar envío
|
||||
AddEntry: Añadir entrada
|
||||
thermographs: Termógrafos
|
||||
availabled: F. Disponible
|
||||
availabledHour: Hora Disponible
|
||||
hb: HB
|
||||
basicData:
|
||||
daysInForward: Desplazamiento automatico (redada)
|
||||
|
|
|
@ -158,7 +158,7 @@ onMounted(() => {
|
|||
>
|
||||
<QItemSection>{{ t('globals.delete') }}</QItemSection>
|
||||
</QItem>
|
||||
<QItem v-if="hasSysadminAccess" v-ripple clickable>
|
||||
<QItem v-if="hasSysadminAccess || isHimself" v-ripple clickable>
|
||||
<QItemSection @click="onChangePass(isHimself)">
|
||||
{{ isHimself ? t('globals.changePass') : t('globals.setPass') }}
|
||||
</QItemSection>
|
||||
|
|
|
@ -156,7 +156,6 @@ function onDrag() {
|
|||
url="Claims"
|
||||
:filter="claimDmsFilter"
|
||||
@on-fetch="([data]) => setClaimDms(data)"
|
||||
limit="20"
|
||||
auto-load
|
||||
ref="claimDmsRef"
|
||||
/>
|
||||
|
|
|
@ -17,8 +17,7 @@ const bankEntitiesRef = ref(null);
|
|||
|
||||
const filter = {
|
||||
fields: ['id', 'bic', 'name'],
|
||||
order: 'bic ASC',
|
||||
limit: 30,
|
||||
order: 'bic ASC'
|
||||
};
|
||||
|
||||
const getBankEntities = (data, formData) => {
|
||||
|
|
|
@ -232,7 +232,6 @@ const updateDateParams = (value, params) => {
|
|||
:include="'category'"
|
||||
:sortBy="'name ASC'"
|
||||
dense
|
||||
@update:model-value="(data) => updateDateParams(data, params)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -254,7 +253,6 @@ const updateDateParams = (value, params) => {
|
|||
:fields="['id', 'name']"
|
||||
:sortBy="'name ASC'"
|
||||
dense
|
||||
@update:model-value="(data) => updateDateParams(data, params)"
|
||||
/>
|
||||
<VnSelect
|
||||
v-model="params.campaign"
|
||||
|
@ -303,12 +301,14 @@ en:
|
|||
valentinesDay: Valentine's Day
|
||||
mothersDay: Mother's Day
|
||||
allSaints: All Saints' Day
|
||||
frenchMothersDay: Mother's Day in France
|
||||
es:
|
||||
Enter a new search: Introduce una nueva búsqueda
|
||||
Group by items: Agrupar por artículos
|
||||
valentinesDay: Día de San Valentín
|
||||
mothersDay: Día de la Madre
|
||||
allSaints: Día de Todos los Santos
|
||||
frenchMothersDay: (Francia) Día de la Madre
|
||||
Campaign consumption: Consumo campaña
|
||||
Campaign: Campaña
|
||||
From: Desde
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useQuasar } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import FormModel from 'components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
|
@ -11,9 +14,12 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
|||
import VnLocation from 'src/components/common/VnLocation.vue';
|
||||
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
|
||||
import { getDifferences, getUpdatedValues } from 'src/filters';
|
||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
|
||||
const quasar = useQuasar();
|
||||
const { t } = useI18n();
|
||||
const route = useRoute();
|
||||
const { notify } = useNotify();
|
||||
|
||||
const typesTaxes = ref([]);
|
||||
const typesTransactions = ref([]);
|
||||
|
@ -31,6 +37,31 @@ function onBeforeSave(formData, originalData) {
|
|||
formData,
|
||||
);
|
||||
}
|
||||
|
||||
async function checkEtChanges(data, _, originalData) {
|
||||
const equalizatedHasChanged = originalData.isEqualizated != data.isEqualizated;
|
||||
const hasToInvoiceByAddress =
|
||||
originalData.hasToInvoiceByAddress || data.hasToInvoiceByAddress;
|
||||
if (equalizatedHasChanged && hasToInvoiceByAddress) {
|
||||
quasar.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('You changed the equalization tax'),
|
||||
message: t('Do you want to spread the change?'),
|
||||
promise: () => acceptPropagate(data),
|
||||
},
|
||||
});
|
||||
} else if (equalizatedHasChanged) {
|
||||
await acceptPropagate(data);
|
||||
}
|
||||
}
|
||||
|
||||
async function acceptPropagate({ isEqualizated }) {
|
||||
await axios.patch(`Clients/${route.params.id}/addressesPropagateRe`, {
|
||||
isEqualizated,
|
||||
});
|
||||
notify(t('Equivalent tax spreaded'), 'warning');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -45,6 +76,8 @@ function onBeforeSave(formData, originalData) {
|
|||
auto-load
|
||||
model="Customer"
|
||||
:mapper="onBeforeSave"
|
||||
observe-form-changes
|
||||
@on-data-saved="checkEtChanges"
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
|
@ -180,6 +213,9 @@ es:
|
|||
whenActivatingIt: Al activarlo, no informar el código del país en el campo nif
|
||||
inOrderToInvoice: Para facturar no se consulta este campo, sino el RE de consignatario. Al modificar este campo si no esta marcada la casilla Facturar por consignatario, se propagará automaticamente el cambio a todos lo consignatarios, en caso contrario preguntará al usuario si quiere o no propagar
|
||||
Daily invoice: Facturación diaria
|
||||
Equivalent tax spreaded: Recargo de equivalencia propagado
|
||||
You changed the equalization tax: Has cambiado el recargo de equivalencia
|
||||
Do you want to spread the change?: ¿Deseas propagar el cambio a sus consignatarios?
|
||||
en:
|
||||
onlyLetters: Only letters, numbers and spaces can be used
|
||||
whenActivatingIt: When activating it, do not enter the country code in the ID field
|
||||
|
|
|
@ -270,7 +270,7 @@ const sumRisk = ({ clientRisks }) => {
|
|||
<VnTitle
|
||||
target="_blank"
|
||||
:url="`${grafanaUrl}/d/40buzE4Vk/comportamiento-pagos-clientes?orgId=1&var-clientFk=${entityId}`"
|
||||
:text="t('customer.summary.payMethodFk')"
|
||||
:text="t('customer.summary.financialData')"
|
||||
icon="vn:grafana"
|
||||
/>
|
||||
<VnLv
|
||||
|
|
|
@ -87,7 +87,7 @@ onMounted(async () => {
|
|||
<FetchData
|
||||
url="Campaigns/latest"
|
||||
@on-fetch="(data) => (campaignsOptions = data)"
|
||||
:filter="{ fields: ['id', 'code', 'dated'], order: 'code ASC', limit: 30 }"
|
||||
:filter="{ fields: ['id', 'code', 'dated'], order: 'code ASC' }"
|
||||
auto-load
|
||||
/>
|
||||
<FetchData
|
||||
|
|
|
@ -98,7 +98,6 @@ function onAgentCreated({ id, fiscalName }, data) {
|
|||
:rules="validate('Worker.postcode')"
|
||||
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||
v-model="data.location"
|
||||
:required="true"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
/>
|
||||
|
||||
|
|
|
@ -96,11 +96,11 @@ const updateObservations = async (payload) => {
|
|||
await axios.post('AddressObservations/crud', payload);
|
||||
notes.value = [];
|
||||
deletes.value = [];
|
||||
toCustomerAddress();
|
||||
};
|
||||
async function updateAll({ data, payload }) {
|
||||
await updateObservations(payload);
|
||||
await updateAddress(data);
|
||||
toCustomerAddress();
|
||||
}
|
||||
function getPayload() {
|
||||
return {
|
||||
|
@ -137,15 +137,12 @@ async function handleDialog(data) {
|
|||
.onOk(async () => {
|
||||
await updateAddressTicket();
|
||||
await updateAll(body);
|
||||
toCustomerAddress();
|
||||
})
|
||||
.onCancel(async () => {
|
||||
await updateAll(body);
|
||||
toCustomerAddress();
|
||||
});
|
||||
} else {
|
||||
updateAll(body);
|
||||
toCustomerAddress();
|
||||
await updateAll(body);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -236,7 +233,7 @@ function handleLocation(data, location) {
|
|||
postcode: data.postalCode,
|
||||
city: data.city,
|
||||
province: data.province,
|
||||
country: data.province.country,
|
||||
country: data.province?.country,
|
||||
}"
|
||||
@update:model-value="(location) => handleLocation(data, location)"
|
||||
></VnLocation>
|
||||
|
|
|
@ -114,7 +114,7 @@ function onBeforeSave(data) {
|
|||
if (isCash.value && shouldSendEmail.value && !data.email)
|
||||
return notify(t('There is no assigned email for this client'), 'negative');
|
||||
|
||||
data.bankFk = data.bankFk.id;
|
||||
data.bankFk = data.bankFk?.id;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -189,7 +189,7 @@ async function getAmountPaid() {
|
|||
:url-create="urlCreate"
|
||||
:mapper="onBeforeSave"
|
||||
@on-data-saved="onDataSaved"
|
||||
:prevent-submit="true"
|
||||
prevent-submit
|
||||
>
|
||||
<template #form="{ data, validate }">
|
||||
<span ref="closeButton" class="row justify-end close-icon" v-close-popup>
|
||||
|
|
|
@ -209,13 +209,14 @@ const columns = [
|
|||
row['amount'] = row['quantity'] * row['buyingValue'];
|
||||
},
|
||||
},
|
||||
width: '20px',
|
||||
width: '30px',
|
||||
style: (row) => {
|
||||
if (row.groupingMode === 'grouping')
|
||||
return { color: 'var(--vn-label-color)' };
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'center',
|
||||
labelAbbreviation: 'GM',
|
||||
label: t('Grouping selector'),
|
||||
toolTip: t('Grouping selector'),
|
||||
|
@ -249,7 +250,7 @@ const columns = [
|
|||
toolTip: 'Grouping',
|
||||
name: 'grouping',
|
||||
component: 'number',
|
||||
width: '20px',
|
||||
width: '30px',
|
||||
create: true,
|
||||
style: (row) => {
|
||||
if (row.groupingMode === 'packing') return { color: 'var(--vn-label-color)' };
|
||||
|
@ -508,7 +509,7 @@ async function setBuyUltimate(itemFk, data) {
|
|||
|
||||
allowedKeys.forEach((key) => {
|
||||
if (buyUltimateData.hasOwnProperty(key) && key !== 'entryFk') {
|
||||
data[key] = buyUltimateData[key];
|
||||
if (!['stickers', 'quantity'].includes(key)) data[key] = buyUltimateData[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -600,7 +601,6 @@ onMounted(() => {
|
|||
ref="entryBuysRef"
|
||||
data-key="EntryBuys"
|
||||
:url="`Entries/${entityId}/getBuyList`"
|
||||
order="name DESC"
|
||||
save-url="Buys/crud"
|
||||
:disable-option="{ card: true }"
|
||||
v-model:selected="selectedRows"
|
||||
|
@ -644,7 +644,8 @@ onMounted(() => {
|
|||
:is-editable="editableMode"
|
||||
:without-header="!editableMode"
|
||||
:with-filters="editableMode"
|
||||
:right-search="editableMode"
|
||||
:right-search="false"
|
||||
:right-search-icon="false"
|
||||
:row-click="false"
|
||||
:columns="columns"
|
||||
:beforeSaveFn="beforeSave"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
|
@ -18,18 +16,10 @@ defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const itemTypeWorkersOptions = ref([]);
|
||||
const tagValues = ref([]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="TicketRequests/getItemTypeWorker"
|
||||
limit="30"
|
||||
auto-load
|
||||
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC', limit: 30 }"
|
||||
@on-fetch="(data) => (itemTypeWorkersOptions = data)"
|
||||
/>
|
||||
<ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']">
|
||||
<template #body="{ params, searchFn }">
|
||||
<QItem class="q-my-md">
|
||||
|
@ -37,9 +27,10 @@ const tagValues = ref([]);
|
|||
<VnSelect
|
||||
:label="t('components.itemsFilterPanel.salesPersonFk')"
|
||||
v-model="params.salesPersonFk"
|
||||
:options="itemTypeWorkersOptions"
|
||||
option-value="id"
|
||||
url="TicketRequests/getItemTypeWorker"
|
||||
option-label="nickname"
|
||||
:fields="['id', 'nickname']"
|
||||
sort-by="nickname ASC"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
@ -52,8 +43,9 @@ const tagValues = ref([]);
|
|||
<QItemSection>
|
||||
<VnSelectSupplier
|
||||
v-model="params.supplierFk"
|
||||
@update:model-value="searchFn()"
|
||||
hide-selected
|
||||
url="Suppliers"
|
||||
:fields="['id', 'name', 'nickname']"
|
||||
sort-by="name ASC"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
|
|
@ -44,28 +44,32 @@ const entryQueryFilter = {
|
|||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
label: 'Ex',
|
||||
labelAbbreviation: 'Ex',
|
||||
label: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
||||
toolTip: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
||||
name: 'isExcludedFromAvailable',
|
||||
component: 'checkbox',
|
||||
width: '35px',
|
||||
},
|
||||
{
|
||||
label: 'Pe',
|
||||
labelAbbreviation: 'Pe',
|
||||
label: t('entry.list.tableVisibleColumns.isOrdered'),
|
||||
toolTip: t('entry.list.tableVisibleColumns.isOrdered'),
|
||||
name: 'isOrdered',
|
||||
component: 'checkbox',
|
||||
width: '35px',
|
||||
},
|
||||
{
|
||||
label: 'Le',
|
||||
labelAbbreviation: 'LE',
|
||||
label: t('entry.list.tableVisibleColumns.isConfirmed'),
|
||||
toolTip: t('entry.list.tableVisibleColumns.isConfirmed'),
|
||||
name: 'isConfirmed',
|
||||
component: 'checkbox',
|
||||
width: '35px',
|
||||
},
|
||||
{
|
||||
label: 'Re',
|
||||
labelAbbreviation: 'Re',
|
||||
label: t('entry.list.tableVisibleColumns.isReceived'),
|
||||
toolTip: t('entry.list.tableVisibleColumns.isReceived'),
|
||||
name: 'isReceived',
|
||||
component: 'checkbox',
|
||||
|
@ -89,6 +93,7 @@ const columns = computed(() => [
|
|||
chip: {
|
||||
condition: () => true,
|
||||
},
|
||||
width: '50px',
|
||||
},
|
||||
{
|
||||
label: t('entry.list.tableVisibleColumns.supplierFk'),
|
||||
|
@ -99,8 +104,10 @@ const columns = computed(() => [
|
|||
attrs: {
|
||||
url: 'suppliers',
|
||||
fields: ['id', 'name'],
|
||||
where: { order: 'name DESC' },
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
|
||||
width: '110px',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -124,6 +131,7 @@ const columns = computed(() => [
|
|||
label: 'AWB',
|
||||
name: 'awbCode',
|
||||
component: 'input',
|
||||
width: '100px',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -160,6 +168,7 @@ const columns = computed(() => [
|
|||
component: null,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseOutName),
|
||||
width: '65px',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -175,12 +184,24 @@ const columns = computed(() => [
|
|||
component: null,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.warehouseInName),
|
||||
width: '65px',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
labelAbbreviation: t('Type'),
|
||||
label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||
toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
|
||||
name: 'entryTypeCode',
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'entryTypes',
|
||||
fields: ['code', 'description'],
|
||||
optionValue: 'code',
|
||||
optionLabel: 'description',
|
||||
},
|
||||
cardVisible: true,
|
||||
width: '65px',
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),
|
||||
},
|
||||
{
|
||||
name: 'companyFk',
|
||||
|
@ -320,4 +341,5 @@ es:
|
|||
Search entries: Buscar entradas
|
||||
You can search by entry reference: Puedes buscar por referencia de la entrada
|
||||
Create entry: Crear entrada
|
||||
Type: Tipo
|
||||
</i18n>
|
||||
|
|
|
@ -34,18 +34,20 @@ const columns = computed(() => [
|
|||
label: t('entryStockBought.buyer'),
|
||||
isTitle: true,
|
||||
component: 'select',
|
||||
isEditable: false,
|
||||
cardVisible: true,
|
||||
create: true,
|
||||
attrs: {
|
||||
url: 'Workers/activeWithInheritedRole',
|
||||
fields: ['id', 'name'],
|
||||
fields: ['id', 'name', 'nickname'],
|
||||
where: { role: 'buyer' },
|
||||
optionFilter: 'firstName',
|
||||
optionLabel: 'name',
|
||||
optionLabel: 'nickname',
|
||||
optionValue: 'id',
|
||||
useLike: false,
|
||||
},
|
||||
columnFilter: false,
|
||||
width: '70px',
|
||||
},
|
||||
{
|
||||
align: 'center',
|
||||
|
@ -55,6 +57,7 @@ const columns = computed(() => [
|
|||
create: true,
|
||||
component: 'number',
|
||||
summation: true,
|
||||
width: '60px',
|
||||
},
|
||||
{
|
||||
align: 'center',
|
||||
|
@ -78,6 +81,7 @@ const columns = computed(() => [
|
|||
actions: [
|
||||
{
|
||||
title: t('entryStockBought.viewMoreDetails'),
|
||||
name: 'searchBtn',
|
||||
icon: 'search',
|
||||
isPrimary: true,
|
||||
action: (row) => {
|
||||
|
@ -91,6 +95,7 @@ const columns = computed(() => [
|
|||
},
|
||||
},
|
||||
],
|
||||
'data-cy': 'table-actions',
|
||||
},
|
||||
]);
|
||||
|
||||
|
@ -158,7 +163,7 @@ function round(value) {
|
|||
@on-fetch="
|
||||
(data) => {
|
||||
travel = data.find(
|
||||
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh'
|
||||
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh',
|
||||
);
|
||||
}
|
||||
"
|
||||
|
@ -179,6 +184,7 @@ function round(value) {
|
|||
@click="openDialog()"
|
||||
:title="t('entryStockBought.editTravel')"
|
||||
color="primary"
|
||||
data-cy="edit-travel"
|
||||
/>
|
||||
</div>
|
||||
</VnRow>
|
||||
|
@ -239,10 +245,11 @@ function round(value) {
|
|||
table-height="80vh"
|
||||
auto-load
|
||||
:column-search="false"
|
||||
:without-header="true"
|
||||
>
|
||||
<template #column-workerFk="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
{{ row?.worker?.user?.name }}
|
||||
{{ row?.worker?.user?.nickname }}
|
||||
<WorkerDescriptorProxy :id="row?.workerFk" />
|
||||
</span>
|
||||
</template>
|
||||
|
@ -279,10 +286,11 @@ function round(value) {
|
|||
justify-content: center;
|
||||
}
|
||||
.column {
|
||||
min-width: 30%;
|
||||
margin-top: 5%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 35%;
|
||||
}
|
||||
.text-negative {
|
||||
color: $negative !important;
|
||||
|
|
|
@ -21,7 +21,7 @@ const $props = defineProps({
|
|||
const customUrl = `StockBoughts/getStockBoughtDetail?workerFk=${$props.workerFk}&dated=${$props.dated}`;
|
||||
const columns = [
|
||||
{
|
||||
align: 'left',
|
||||
align: 'right',
|
||||
label: t('Entry'),
|
||||
name: 'entryFk',
|
||||
isTitle: true,
|
||||
|
@ -29,7 +29,7 @@ const columns = [
|
|||
columnFilter: false,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
align: 'right',
|
||||
name: 'itemFk',
|
||||
label: t('Item'),
|
||||
columnFilter: false,
|
||||
|
@ -44,21 +44,21 @@ const columns = [
|
|||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
align: 'right',
|
||||
name: 'volume',
|
||||
label: t('Volume'),
|
||||
columnFilter: false,
|
||||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
align: 'right',
|
||||
label: t('Packaging'),
|
||||
name: 'packagingFk',
|
||||
columnFilter: false,
|
||||
cardVisible: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
align: 'right',
|
||||
label: 'Packing',
|
||||
name: 'packing',
|
||||
columnFilter: false,
|
||||
|
@ -73,12 +73,14 @@ const columns = [
|
|||
ref="tableRef"
|
||||
data-key="StockBoughtsDetail"
|
||||
:url="customUrl"
|
||||
order="itemName DESC"
|
||||
order="volume DESC"
|
||||
:columns="columns"
|
||||
:right-search="false"
|
||||
:disable-infinite-scroll="true"
|
||||
:disable-option="{ card: true }"
|
||||
:limit="0"
|
||||
:without-header="true"
|
||||
:with-filters="false"
|
||||
auto-load
|
||||
>
|
||||
<template #column-entryFk="{ row }">
|
||||
|
@ -105,7 +107,7 @@ const columns = [
|
|||
align-items: center;
|
||||
margin: auto;
|
||||
background-color: var(--vn-section-color);
|
||||
padding: 4px;
|
||||
padding: 2%;
|
||||
}
|
||||
.container > div > div > .q-table__top.relative-position.row.items-center {
|
||||
background-color: red !important;
|
||||
|
|
|
@ -7,7 +7,6 @@ import { toDate } from 'src/filters';
|
|||
import { useArrayData } from 'src/composables/useArrayData';
|
||||
import { getTotal } from 'src/composables/getTotal';
|
||||
import CrudModel from 'src/components/CrudModel.vue';
|
||||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import useNotify from 'src/composables/useNotify.js';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
|
@ -22,7 +21,6 @@ const invoiceIn = computed(() => arrayData.store.data);
|
|||
const currency = computed(() => invoiceIn.value?.currency?.code);
|
||||
|
||||
const rowsSelected = ref([]);
|
||||
const banks = ref([]);
|
||||
const invoiceInFormRef = ref();
|
||||
const invoiceId = +route.params.id;
|
||||
const filter = { where: { invoiceInFk: invoiceId } };
|
||||
|
@ -41,10 +39,9 @@ const columns = computed(() => [
|
|||
name: 'bank',
|
||||
label: t('Bank'),
|
||||
field: (row) => row.bankFk,
|
||||
options: banks.value,
|
||||
model: 'bankFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'bank',
|
||||
url: 'Accountings',
|
||||
sortable: true,
|
||||
tabIndex: 2,
|
||||
align: 'left',
|
||||
|
@ -82,12 +79,6 @@ onBeforeMount(async () => {
|
|||
});
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
url="Accountings"
|
||||
auto-load
|
||||
limit="30"
|
||||
@on-fetch="(data) => (banks = data)"
|
||||
/>
|
||||
<CrudModel
|
||||
v-if="invoiceIn"
|
||||
ref="invoiceInFormRef"
|
||||
|
@ -117,9 +108,9 @@ onBeforeMount(async () => {
|
|||
<QTd>
|
||||
<VnSelect
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:url="col.url"
|
||||
:option-label="col.optionLabel"
|
||||
:option-value="col.optionValue"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -193,8 +184,7 @@ onBeforeMount(async () => {
|
|||
:label="t('Bank')"
|
||||
class="full-width"
|
||||
v-model="props.row['bankFk']"
|
||||
:options="banks"
|
||||
option-value="id"
|
||||
url="Accountings"
|
||||
option-label="bank"
|
||||
>
|
||||
<template #option="scope">
|
||||
|
|
|
@ -103,7 +103,7 @@ const refundInvoice = async (withWarehouse) => {
|
|||
t('refundInvoiceSuccessMessage', {
|
||||
refundTicket: data[0].id,
|
||||
}),
|
||||
'positive'
|
||||
'positive',
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -124,6 +124,13 @@ const showRefundInvoiceForm = () => {
|
|||
},
|
||||
});
|
||||
};
|
||||
|
||||
const showExportationLetter = () => {
|
||||
openReport(`InvoiceOuts/${$props.invoiceOutData.ref}/exportation-pdf`, {
|
||||
recipientId: $props.invoiceOutData.client.id,
|
||||
refFk: $props.invoiceOutData.ref,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -172,7 +179,7 @@ const showRefundInvoiceForm = () => {
|
|||
t('Confirm deletion'),
|
||||
t('Are you sure you want to delete this invoice?'),
|
||||
deleteInvoice,
|
||||
redirectToInvoiceOutList
|
||||
redirectToInvoiceOutList,
|
||||
)
|
||||
"
|
||||
>
|
||||
|
@ -185,7 +192,7 @@ const showRefundInvoiceForm = () => {
|
|||
openConfirmationModal(
|
||||
'',
|
||||
t('Are you sure you want to book this invoice?'),
|
||||
bookInvoice
|
||||
bookInvoice,
|
||||
)
|
||||
"
|
||||
>
|
||||
|
@ -198,7 +205,7 @@ const showRefundInvoiceForm = () => {
|
|||
openConfirmationModal(
|
||||
t('Generate PDF invoice document'),
|
||||
t('Are you sure you want to generate/regenerate the PDF invoice?'),
|
||||
generateInvoicePdf
|
||||
generateInvoicePdf,
|
||||
)
|
||||
"
|
||||
>
|
||||
|
@ -226,6 +233,14 @@ const showRefundInvoiceForm = () => {
|
|||
{{ t('Create a single ticket with all the content of the current invoice') }}
|
||||
</QTooltip>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="$props.invoiceOutData.serial === 'E'"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="showExportationLetter()"
|
||||
>
|
||||
<QItemSection>{{ t('Show CITES letter') }}</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
@ -255,7 +270,7 @@ es:
|
|||
Create a single ticket with all the content of the current invoice: Crear un ticket único con todo el contenido de la factura actual
|
||||
refundInvoiceSuccessMessage: Se ha creado el siguiente ticket de abono {refundTicket}
|
||||
The email can't be empty: El email no puede estar vacío
|
||||
|
||||
Show CITES letter: Ver carta CITES
|
||||
en:
|
||||
refundInvoiceSuccessMessage: The following refund ticket have been created {refundTicket}
|
||||
</i18n>
|
||||
|
|
|
@ -125,7 +125,7 @@ const ticketsColumns = ref([
|
|||
:value="toDate(invoiceOut.issued)"
|
||||
/>
|
||||
<VnLv
|
||||
:label="t('invoiceOut.summary.dued')"
|
||||
:label="t('invoiceOut.summary.expirationDate')"
|
||||
:value="toDate(invoiceOut.dued)"
|
||||
/>
|
||||
<VnLv :label="t('globals.created')" :value="toDate(invoiceOut.created)" />
|
||||
|
|
|
@ -22,7 +22,7 @@ const states = ref();
|
|||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
<strong>{{ t(`invoiceOut.params.${tag.label}`) }}: </strong>
|
||||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -84,15 +84,6 @@ const states = ref();
|
|||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
v-model="params.issued"
|
||||
:label="t('Issued')"
|
||||
is-outlined
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
|
@ -110,37 +101,3 @@ const states = ref();
|
|||
</template>
|
||||
</VnFilterPanel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
params:
|
||||
search: Contains
|
||||
clientFk: Customer
|
||||
fi: FI
|
||||
amount: Amount
|
||||
min: Min
|
||||
max: Max
|
||||
hasPdf: Has PDF
|
||||
issued: Issued
|
||||
created: Created
|
||||
dued: Dued
|
||||
es:
|
||||
params:
|
||||
search: Contiene
|
||||
clientFk: Cliente
|
||||
fi: CIF
|
||||
amount: Importe
|
||||
min: Min
|
||||
max: Max
|
||||
hasPdf: Tiene PDF
|
||||
issued: Emitida
|
||||
created: Creada
|
||||
dued: Vencida
|
||||
Customer ID: ID cliente
|
||||
FI: CIF
|
||||
Amount: Importe
|
||||
Has PDF: Tiene PDF
|
||||
Issued: Fecha emisión
|
||||
Created: Fecha creación
|
||||
Dued: Fecha vencimiento
|
||||
</i18n>
|
||||
|
|
|
@ -71,14 +71,6 @@ const columns = computed(() => [
|
|||
inWhere: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'issued',
|
||||
label: t('invoiceOut.summary.issued'),
|
||||
component: 'date',
|
||||
format: (row) => toDate(row.issued),
|
||||
columnField: { component: null },
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'clientFk',
|
||||
|
|
|
@ -10,6 +10,8 @@ import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vu
|
|||
import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
|
||||
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import InvoiceOutNegativeBasesFilter from './InvoiceOutNegativeBasesFilter.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const tableRef = ref();
|
||||
|
@ -97,16 +99,19 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
name: 'isActive',
|
||||
label: t('invoiceOut.negativeBases.active'),
|
||||
component: 'checkbox',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'hasToInvoice',
|
||||
label: t('invoiceOut.negativeBases.hasToInvoice'),
|
||||
component: 'checkbox',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'hasVerifiedData',
|
||||
name: 'isTaxDataChecked',
|
||||
label: t('invoiceOut.negativeBases.verifiedData'),
|
||||
component: 'checkbox',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -142,7 +147,7 @@ const downloadCSV = async () => {
|
|||
await invoiceOutGlobalStore.getNegativeBasesCsv(
|
||||
userParams.from,
|
||||
userParams.to,
|
||||
filterParams
|
||||
filterParams,
|
||||
);
|
||||
};
|
||||
</script>
|
||||
|
@ -154,6 +159,11 @@ const downloadCSV = async () => {
|
|||
</QBtn>
|
||||
</template>
|
||||
</VnSubToolbar>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
<InvoiceOutNegativeBasesFilter data-key="negativeFilter" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="negativeFilter"
|
||||
|
@ -174,6 +184,7 @@ const downloadCSV = async () => {
|
|||
auto-load
|
||||
:is-editable="false"
|
||||
:use-model="true"
|
||||
:right-search="false"
|
||||
>
|
||||
<template #column-clientId="{ row }">
|
||||
<span class="link" @click.stop>
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps({
|
||||
|
@ -24,11 +25,11 @@ const props = defineProps({
|
|||
>
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
<strong>{{ t(`invoiceOut.params.${tag.label}`) }}: </strong>
|
||||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #body="{ params }">
|
||||
<template #body="{ params, searchFn }">
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
|
@ -49,38 +50,70 @@ const props = defineProps({
|
|||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.company"
|
||||
<VnSelect
|
||||
url="Companies"
|
||||
:label="t('globals.company')"
|
||||
is-outlined
|
||||
/>
|
||||
v-model="params.company"
|
||||
option-label="code"
|
||||
option-value="code"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
@update:model-value="searchFn()"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt?.code }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `#${scope.opt?.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
<VnSelect
|
||||
url="Countries"
|
||||
:label="t('globals.params.countryFk')"
|
||||
v-model="params.country"
|
||||
:label="t('globals.country')"
|
||||
is-outlined
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.clientId"
|
||||
:label="t('invoiceOut.negativeBases.clientId')"
|
||||
is-outlined
|
||||
/>
|
||||
option-label="name"
|
||||
option-value="name"
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
@update:model-value="searchFn()"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
<QItemSection>
|
||||
<QItemLabel>
|
||||
{{ scope.opt?.name }}
|
||||
</QItemLabel>
|
||||
<QItemLabel caption>
|
||||
{{ `#${scope.opt?.id}` }}
|
||||
</QItemLabel>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</template>
|
||||
</VnSelect>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.clientSocialName"
|
||||
<VnSelect
|
||||
url="Clients"
|
||||
:label="t('globals.client')"
|
||||
is-outlined
|
||||
v-model="params.clientId"
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
@update:model-value="searchFn()"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
@ -90,15 +123,18 @@ const props = defineProps({
|
|||
v-model="params.amount"
|
||||
:label="t('globals.amount')"
|
||||
is-outlined
|
||||
:positive="false"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.comercialName"
|
||||
<VnSelectWorker
|
||||
:label="t('invoiceOut.negativeBases.comercial')"
|
||||
v-model="params.workerName"
|
||||
option-value="name"
|
||||
is-outlined
|
||||
@update:model-value="searchFn()"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
|
|
@ -4,7 +4,7 @@ invoiceOut:
|
|||
params:
|
||||
company: Company
|
||||
country: Country
|
||||
clientId: Client ID
|
||||
clientId: Client
|
||||
clientSocialName: Client
|
||||
taxableBase: Base
|
||||
ticketFk: Ticket
|
||||
|
@ -12,6 +12,18 @@ invoiceOut:
|
|||
hasToInvoice: Has to invoice
|
||||
hasVerifiedData: Verified data
|
||||
workerName: Worker
|
||||
isTaxDataChecked: Verified data
|
||||
amount: Amount
|
||||
clientFk: Client
|
||||
companyFk: Company
|
||||
created: Created
|
||||
dued: Dued
|
||||
customsAgentFk: Custom Agent
|
||||
ref: Reference
|
||||
fi: FI
|
||||
min: Min
|
||||
max: Max
|
||||
hasPdf: Has PDF
|
||||
card:
|
||||
issued: Issued
|
||||
customerCard: Customer card
|
||||
|
@ -19,6 +31,7 @@ invoiceOut:
|
|||
summary:
|
||||
issued: Issued
|
||||
dued: Due
|
||||
expirationDate: Expiration date
|
||||
booked: Booked
|
||||
taxBreakdown: Tax breakdown
|
||||
taxableBase: Taxable base
|
||||
|
@ -52,7 +65,7 @@ invoiceOut:
|
|||
active: Active
|
||||
hasToInvoice: Has to Invoice
|
||||
verifiedData: Verified Data
|
||||
comercial: Commercial
|
||||
comercial: Sales person
|
||||
errors:
|
||||
downloadCsvFailed: CSV download failed
|
||||
invoiceOutModule:
|
||||
|
|
|
@ -4,7 +4,7 @@ invoiceOut:
|
|||
params:
|
||||
company: Empresa
|
||||
country: País
|
||||
clientId: ID del cliente
|
||||
clientId: Cliente
|
||||
clientSocialName: Cliente
|
||||
taxableBase: Base
|
||||
ticketFk: Ticket
|
||||
|
@ -12,6 +12,18 @@ invoiceOut:
|
|||
hasToInvoice: Debe facturar
|
||||
hasVerifiedData: Datos verificados
|
||||
workerName: Comercial
|
||||
isTaxDataChecked: Datos comprobados
|
||||
amount: Importe
|
||||
clientFk: Cliente
|
||||
companyFk: Empresa
|
||||
created: Creada
|
||||
dued: Vencida
|
||||
customsAgentFk: Agente aduanas
|
||||
ref: Referencia
|
||||
fi: CIF
|
||||
min: Min
|
||||
max: Max
|
||||
hasPdf: Tiene PDF
|
||||
card:
|
||||
issued: Fecha emisión
|
||||
customerCard: Ficha del cliente
|
||||
|
@ -19,6 +31,7 @@ invoiceOut:
|
|||
summary:
|
||||
issued: Fecha
|
||||
dued: Fecha límite
|
||||
expirationDate: Fecha vencimiento
|
||||
booked: Contabilizada
|
||||
taxBreakdown: Desglose impositivo
|
||||
taxableBase: Base imp.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import VnSelect from 'components/common/VnSelect.vue';
|
||||
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
|
||||
|
@ -16,17 +14,9 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const itemTypeWorkersOptions = ref([]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
url="TicketRequests/getItemTypeWorker"
|
||||
limit="30"
|
||||
auto-load
|
||||
:filter="{ fields: ['id', 'nickname'], order: 'nickname ASC', limit: 30 }"
|
||||
@on-fetch="(data) => (itemTypeWorkersOptions = data)"
|
||||
/>
|
||||
<ItemsFilterPanel :data-key="props.dataKey" :custom-tags="['tags']">
|
||||
<template #body="{ params, searchFn }">
|
||||
<QItem class="q-my-md">
|
||||
|
@ -34,14 +24,15 @@ const itemTypeWorkersOptions = ref([]);
|
|||
<VnSelect
|
||||
:label="t('params.buyerFk')"
|
||||
v-model="params.buyerFk"
|
||||
:options="itemTypeWorkersOptions"
|
||||
option-value="id"
|
||||
url="TicketRequests/getItemTypeWorker"
|
||||
:fields="['id', 'nickname']"
|
||||
option-label="nickname"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
use-input
|
||||
@update:model-value="searchFn()"
|
||||
sort-by="nickname ASC"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
|
@ -50,11 +41,10 @@ const itemTypeWorkersOptions = ref([]);
|
|||
<VnSelect
|
||||
url="Warehouses"
|
||||
auto-load
|
||||
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
|
||||
:fields="['id', 'name']"
|
||||
sort-by="name ASC"
|
||||
:label="t('params.warehouseFk')"
|
||||
v-model="params.warehouseFk"
|
||||
option-label="name"
|
||||
option-value="id"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
|
|
@ -46,7 +46,6 @@ const exprBuilder = (param, value) => {
|
|||
url="AgencyModes"
|
||||
:filter="{ fields: ['id', 'name'] }"
|
||||
sort-by="name ASC"
|
||||
limit="30"
|
||||
@on-fetch="(data) => (agencyList = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
@ -54,7 +53,6 @@ const exprBuilder = (param, value) => {
|
|||
url="Agencies"
|
||||
:filter="{ fields: ['id', 'name'] }"
|
||||
sort-by="name ASC"
|
||||
limit="30"
|
||||
@on-fetch="(data) => (agencyAgreementList = data)"
|
||||
auto-load
|
||||
/>
|
||||
|
@ -120,7 +118,11 @@ const exprBuilder = (param, value) => {
|
|||
<VnSelectSupplier
|
||||
:label="t('Autonomous')"
|
||||
v-model="params.supplierFk"
|
||||
hide-selected
|
||||
url="Suppliers"
|
||||
:fields="['name']"
|
||||
sort-by="name ASC"
|
||||
option-value="name"
|
||||
option-label="name"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
|
|
@ -6,6 +6,8 @@ import VnLv from 'components/ui/VnLv.vue';
|
|||
import { dashIfEmpty, toDate } from 'src/filters';
|
||||
import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue';
|
||||
import filter from './RouteFilter.js';
|
||||
import useCardDescription from 'src/composables/useCardDescription';
|
||||
import axios from 'axios';
|
||||
|
||||
const $props = defineProps({
|
||||
id: {
|
||||
|
@ -16,7 +18,6 @@ const $props = defineProps({
|
|||
});
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const zone = ref();
|
||||
const zoneId = ref();
|
||||
const entityId = computed(() => {
|
||||
|
@ -50,9 +51,9 @@ onMounted(async () => {
|
|||
width="lg-width"
|
||||
>
|
||||
<template #body="{ entity }">
|
||||
<VnLv :label="t('Date')" :value="toDate(entity?.dated)" />
|
||||
<VnLv :label="t('Agency')" :value="entity?.agencyMode?.name" />
|
||||
<VnLv :label="t('Zone')" :value="zone" />
|
||||
<VnLv :label="$t('Date')" :value="toDate(entity?.dated)" />
|
||||
<VnLv :label="$t('Agency')" :value="entity?.agencyMode?.name" />
|
||||
<VnLv :label="$t('Zone')" :value="zone" />
|
||||
<VnLv
|
||||
:label="$t('Volume')"
|
||||
:value="`${dashIfEmpty(entity?.m3)} / ${dashIfEmpty(
|
||||
|
|
|
@ -14,7 +14,6 @@ export default {
|
|||
'started',
|
||||
'finished',
|
||||
'cost',
|
||||
'zoneFk',
|
||||
'isOk',
|
||||
],
|
||||
include: [
|
||||
|
@ -23,7 +22,6 @@ export default {
|
|||
relation: 'vehicle',
|
||||
scope: { fields: ['id', 'm3'] },
|
||||
},
|
||||
{ relation: 'zone', scope: { fields: ['id', 'name'] } },
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
|
|
|
@ -28,52 +28,6 @@ const defaultInitialData = {
|
|||
isOk: false,
|
||||
};
|
||||
const maxDistance = ref();
|
||||
|
||||
const routeFilter = {
|
||||
fields: [
|
||||
'id',
|
||||
'workerFk',
|
||||
'agencyModeFk',
|
||||
'dated',
|
||||
'm3',
|
||||
'warehouseFk',
|
||||
'description',
|
||||
'vehicleFk',
|
||||
'kmStart',
|
||||
'kmEnd',
|
||||
'started',
|
||||
'finished',
|
||||
'cost',
|
||||
'isOk',
|
||||
],
|
||||
include: [
|
||||
{ relation: 'agencyMode', scope: { fields: ['id', 'name'] } },
|
||||
{
|
||||
relation: 'vehicle',
|
||||
scope: { fields: ['id', 'm3'] },
|
||||
},
|
||||
{
|
||||
relation: 'ticket',
|
||||
scope: {
|
||||
fields: ['id', 'name', 'zoneFk'],
|
||||
include: { relation: 'zone', scope: { fields: ['id', 'name'] } },
|
||||
},
|
||||
},
|
||||
{
|
||||
relation: 'worker',
|
||||
scope: {
|
||||
fields: ['id'],
|
||||
include: {
|
||||
relation: 'user',
|
||||
scope: {
|
||||
fields: ['id'],
|
||||
include: { relation: 'emailUser', scope: { fields: ['email'] } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
const onSave = (data, response) => {
|
||||
if (isNew) {
|
||||
axios.post(`Routes/${response?.id}/updateWorkCenter`);
|
||||
|
|
|
@ -48,7 +48,6 @@ const onFetch = (data) => {
|
|||
},
|
||||
],
|
||||
}"
|
||||
limit="30"
|
||||
@on-fetch="onFetch"
|
||||
/>
|
||||
<div :class="[isDialog ? 'column' : 'form-gap', 'full-width flex']">
|
||||
|
|
|
@ -18,6 +18,7 @@ const onSave = (data, response) => {
|
|||
<template>
|
||||
<FormModel
|
||||
:update-url="`Roadmaps/${$route.params?.id}`"
|
||||
:url="`Roadmaps/${$route.params?.id}`"
|
||||
observe-form-changes
|
||||
model="Roadmap"
|
||||
auto-load
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInput from 'components/common/VnInput.vue';
|
||||
|
@ -65,6 +63,7 @@ const emit = defineEmits(['search']);
|
|||
<QItemSection>
|
||||
<VnSelectSupplier
|
||||
:label="t('Carrier')"
|
||||
:fields="['id', 'nickname']"
|
||||
v-model="params.supplierFk"
|
||||
dense
|
||||
outlined
|
||||
|
|
|
@ -21,6 +21,10 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: 'mana',
|
||||
},
|
||||
sale: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['save', 'cancel']);
|
||||
|
@ -29,8 +33,8 @@ const { t } = useI18n();
|
|||
const QPopupProxyRef = ref(null);
|
||||
const manaCode = ref($props.manaCode);
|
||||
|
||||
const save = () => {
|
||||
emit('save');
|
||||
const save = (sale = $props.sale) => {
|
||||
emit('save', sale);
|
||||
QPopupProxyRef.value.hide();
|
||||
};
|
||||
|
||||
|
@ -38,16 +42,20 @@ const cancel = () => {
|
|||
emit('cancel');
|
||||
QPopupProxyRef.value.hide();
|
||||
};
|
||||
defineExpose({ save });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<QPopupProxy ref="QPopupProxyRef">
|
||||
<QPopupProxy ref="QPopupProxyRef" data-cy="ticketEditManaProxy">
|
||||
<div class="container">
|
||||
<QSpinner v-if="!mana" color="primary" size="md" />
|
||||
<div v-else>
|
||||
<div class="header">Mana: {{ toCurrency(mana) }}</div>
|
||||
<div class="q-pa-md">
|
||||
<slot />
|
||||
<slot :popup="QPopupProxyRef" />
|
||||
<div v-if="usesMana" class="column q-gutter-y-sm q-mt-sm">
|
||||
<VnUsesMana :mana-code="manaCode" />
|
||||
</div>
|
||||
<div v-if="newPrice" class="column items-center q-mt-lg">
|
||||
<span class="text-primary">{{ t('New price') }}</span>
|
||||
<span class="text-subtitle1">
|
||||
|
@ -56,9 +64,6 @@ const cancel = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="usesMana" class="column q-gutter-y-sm q-mt-sm">
|
||||
<VnUsesMana :mana-code="manaCode" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<QBtn
|
||||
color="primary"
|
||||
|
|
|
@ -49,7 +49,7 @@ watch(
|
|||
<FetchData
|
||||
@on-fetch="(data) => (listPackagingsOptions = data)"
|
||||
auto-load
|
||||
:filter="{ fields: ['packagingFk', 'name'], order: 'name ASC', limit: 30 }"
|
||||
:filter="{ fields: ['packagingFk', 'name'], order: 'name ASC' }"
|
||||
url="Packagings/listPackaging"
|
||||
/>
|
||||
<div class="flex justify-center">
|
||||
|
|
|
@ -22,7 +22,6 @@ import { useVnConfirm } from 'composables/useVnConfirm';
|
|||
import useNotify from 'src/composables/useNotify.js';
|
||||
import axios from 'axios';
|
||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||
import VnUsesMana from 'src/components/ui/VnUsesMana.vue';
|
||||
import VnConfirm from 'src/components/ui/VnConfirm.vue';
|
||||
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||
|
@ -33,6 +32,7 @@ const { t } = useI18n();
|
|||
const { notify } = useNotify();
|
||||
const { openConfirmationModal } = useVnConfirm();
|
||||
const editPriceProxyRef = ref(null);
|
||||
const editManaProxyRef = ref(null);
|
||||
const stateBtnDropdownRef = ref(null);
|
||||
const quasar = useQuasar();
|
||||
const arrayData = useArrayData('Ticket');
|
||||
|
@ -53,7 +53,6 @@ const transfer = ref({
|
|||
sales: [],
|
||||
});
|
||||
const tableRef = ref([]);
|
||||
const canProceed = ref();
|
||||
|
||||
watch(
|
||||
() => route.params.id,
|
||||
|
@ -133,7 +132,6 @@ const columns = computed(() => [
|
|||
align: 'left',
|
||||
label: t('globals.amount'),
|
||||
name: 'amount',
|
||||
format: (row) => parseInt(row.amount * row.quantity),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -183,8 +181,6 @@ const resetChanges = async () => {
|
|||
};
|
||||
const rowToUpdate = ref(null);
|
||||
const changeQuantity = async (sale) => {
|
||||
canProceed.value = await isSalePrepared(sale);
|
||||
if (!canProceed.value) return;
|
||||
if (
|
||||
!sale.itemFk ||
|
||||
sale.quantity == null ||
|
||||
|
@ -193,11 +189,21 @@ const changeQuantity = async (sale) => {
|
|||
return;
|
||||
if (!sale.id) return addSale(sale);
|
||||
|
||||
if (await isSalePrepared(sale)) {
|
||||
await confirmUpdate(() => updateQuantity(sale));
|
||||
} else await updateQuantity(sale);
|
||||
};
|
||||
|
||||
const updateQuantity = async (sale) => {
|
||||
try {
|
||||
let { quantity, id } = sale;
|
||||
if (!rowToUpdate.value) return;
|
||||
rowToUpdate.value = null;
|
||||
sale.isNew = false;
|
||||
await updateQuantity(sale);
|
||||
const params = { quantity: quantity };
|
||||
await axios.post(`Sales/${id}/updateQuantity`, params);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
tableRef.value.reload();
|
||||
} catch (e) {
|
||||
const { quantity } = tableRef.value.CrudModelRef.originalData.find(
|
||||
(s) => s.id === sale.id,
|
||||
|
@ -207,12 +213,6 @@ const changeQuantity = async (sale) => {
|
|||
}
|
||||
};
|
||||
|
||||
const updateQuantity = async ({ quantity, id }) => {
|
||||
const params = { quantity: quantity };
|
||||
await axios.post(`Sales/${id}/updateQuantity`, params);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
};
|
||||
|
||||
const addSale = async (sale) => {
|
||||
const params = {
|
||||
barcode: sale.itemFk,
|
||||
|
@ -237,13 +237,17 @@ const addSale = async (sale) => {
|
|||
sale.isNew = false;
|
||||
arrayData.fetch({});
|
||||
};
|
||||
const changeConcept = async (sale) => {
|
||||
if (await isSalePrepared(sale)) {
|
||||
await confirmUpdate(() => updateConcept(sale));
|
||||
} else await updateConcept(sale);
|
||||
};
|
||||
|
||||
const updateConcept = async (sale) => {
|
||||
canProceed.value = await isSalePrepared(sale);
|
||||
if (!canProceed.value) return;
|
||||
const data = { newConcept: sale.concept };
|
||||
await axios.post(`Sales/${sale.id}/updateConcept`, data);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
tableRef.value.reload();
|
||||
};
|
||||
|
||||
const DEFAULT_EDIT = {
|
||||
|
@ -295,33 +299,43 @@ const onOpenEditDiscountPopover = async (sale) => {
|
|||
};
|
||||
}
|
||||
};
|
||||
|
||||
const updatePrice = async (sale) => {
|
||||
canProceed.value = await isSalePrepared(sale);
|
||||
if (!canProceed.value) return;
|
||||
const changePrice = async (sale) => {
|
||||
const newPrice = edit.value.price;
|
||||
if (newPrice != null && newPrice != sale.price) {
|
||||
await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
|
||||
sale.price = newPrice;
|
||||
edit.value = { ...DEFAULT_EDIT };
|
||||
notify('globals.dataSaved', 'positive');
|
||||
if (await isSalePrepared(sale)) {
|
||||
await confirmUpdate(() => updatePrice(sale, newPrice));
|
||||
} else updatePrice(sale, newPrice);
|
||||
}
|
||||
|
||||
await getMana();
|
||||
};
|
||||
const updatePrice = async (sale, newPrice) => {
|
||||
await axios.post(`Sales/${sale.id}/updatePrice`, { newPrice });
|
||||
sale.price = newPrice;
|
||||
edit.value = { ...DEFAULT_EDIT };
|
||||
notify('globals.dataSaved', 'positive');
|
||||
tableRef.value.reload();
|
||||
};
|
||||
|
||||
const changeDiscount = async (sale) => {
|
||||
canProceed.value = await isSalePrepared(sale);
|
||||
if (!canProceed.value) return;
|
||||
const newDiscount = edit.value.discount;
|
||||
if (newDiscount != null && newDiscount != sale.discount) updateDiscount([sale]);
|
||||
if (newDiscount != null && newDiscount != sale.discount) {
|
||||
if (await isSalePrepared(sale))
|
||||
await confirmUpdate(() => updateDiscount([sale], newDiscount));
|
||||
else await updateDiscount([sale], newDiscount);
|
||||
}
|
||||
};
|
||||
|
||||
const updateDiscounts = async (sales, newDiscount = null) => {
|
||||
const salesTracking = await fetchSalesTracking();
|
||||
|
||||
const someSaleIsPrepared = salesTracking.some((sale) =>
|
||||
matchSale(salesTracking, sale),
|
||||
);
|
||||
if (someSaleIsPrepared) await confirmUpdate(() => updateDiscount(sales, newDiscount));
|
||||
else updateDiscount(sales, newDiscount);
|
||||
};
|
||||
|
||||
const updateDiscount = async (sales, newDiscount = null) => {
|
||||
for (const sale of sales) {
|
||||
const canProceed = await isSalePrepared(sale);
|
||||
if (!canProceed) return;
|
||||
}
|
||||
const saleIds = sales.map((sale) => sale.id);
|
||||
const _newDiscount = newDiscount || edit.value.discount;
|
||||
const params = {
|
||||
|
@ -331,8 +345,7 @@ const updateDiscount = async (sales, newDiscount = null) => {
|
|||
};
|
||||
await axios.post(`Tickets/${route.params.id}/updateDiscount`, params);
|
||||
notify('globals.dataSaved', 'positive');
|
||||
for (let sale of sales) sale.discount = _newDiscount;
|
||||
edit.value = { ...DEFAULT_EDIT };
|
||||
tableRef.value.reload();
|
||||
};
|
||||
|
||||
const getNewPrice = computed(() => {
|
||||
|
@ -425,9 +438,13 @@ onMounted(async () => {
|
|||
const items = ref([]);
|
||||
const newRow = ref({});
|
||||
|
||||
const changeItem = async (sale) => {
|
||||
if (await isSalePrepared(sale)) {
|
||||
await confirmUpdate(() => updateItem(sale));
|
||||
} else await updateItem(sale);
|
||||
};
|
||||
|
||||
const updateItem = async (row) => {
|
||||
canProceed.value = await isSalePrepared(row);
|
||||
if (!canProceed.value) return;
|
||||
const selectedItem = items.value.find((item) => item.id === row.itemFk);
|
||||
if (selectedItem) {
|
||||
row.item = selectedItem;
|
||||
|
@ -471,7 +488,18 @@ const endNewRow = (row) => {
|
|||
}
|
||||
};
|
||||
|
||||
async function isSalePrepared(item) {
|
||||
async function confirmUpdate(cb) {
|
||||
await quasar
|
||||
.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('Item prepared'),
|
||||
message: t('This item is already prepared. Do you want to continue?'),
|
||||
},
|
||||
})
|
||||
.onOk(cb);
|
||||
}
|
||||
async function fetchSalesTracking() {
|
||||
const filter = {
|
||||
params: {
|
||||
where: { ticketFk: route.params.id },
|
||||
|
@ -483,48 +511,37 @@ async function isSalePrepared(item) {
|
|||
filter: JSON.stringify(filter),
|
||||
},
|
||||
});
|
||||
|
||||
const matchingSale = data.find((sale) => sale.itemFk === item.itemFk);
|
||||
if (!matchingSale) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
matchingSale.hasSaleGroupDetail ||
|
||||
matchingSale.isControled ||
|
||||
matchingSale.isPrepared ||
|
||||
matchingSale.isPrevious ||
|
||||
matchingSale.isPreviousSelected
|
||||
) {
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
quasar
|
||||
.dialog({
|
||||
component: VnConfirm,
|
||||
componentProps: {
|
||||
title: t('Item prepared'),
|
||||
message: t(
|
||||
'This item is already prepared. Do you want to continue?',
|
||||
),
|
||||
data: item,
|
||||
},
|
||||
})
|
||||
.onOk(() => resolve(true))
|
||||
.onCancel(() => reject(new Error('cancelled')));
|
||||
});
|
||||
} catch (error) {
|
||||
tableRef.value.reload();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return data;
|
||||
}
|
||||
|
||||
async function isSalePrepared(sale) {
|
||||
const data = await fetchSalesTracking();
|
||||
return matchSale(data, sale);
|
||||
}
|
||||
function matchSale(data, sale) {
|
||||
const matchingSale = data.find(({ itemFk }) => itemFk === sale.itemFk);
|
||||
|
||||
if (!matchingSale) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isPrepared(matchingSale);
|
||||
}
|
||||
function isPrepared(sale) {
|
||||
const flagsToCheck = [
|
||||
'hasSaleGroupDetail',
|
||||
'isControled',
|
||||
'isPrepared',
|
||||
'isPrevious',
|
||||
'isPreviousSelected',
|
||||
];
|
||||
return flagsToCheck.some((flag) => sale[flag] === 1);
|
||||
}
|
||||
watch(
|
||||
() => newRow.value.itemFk,
|
||||
(newItemFk) => {
|
||||
if (newItemFk) {
|
||||
updateItem(newRow.value);
|
||||
changeItem(newRow.value);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
@ -585,7 +602,7 @@ watch(
|
|||
:mana="mana"
|
||||
:ticket-config="ticketConfig"
|
||||
@get-mana="getMana()"
|
||||
@update-discounts="updateDiscount"
|
||||
@update-discounts="updateDiscounts"
|
||||
@refresh-table="resetChanges"
|
||||
/>
|
||||
<QBtn
|
||||
|
@ -716,7 +733,7 @@ watch(
|
|||
option-value="id"
|
||||
v-model="row.itemFk"
|
||||
:use-like="false"
|
||||
@update:model-value="updateItem(row)"
|
||||
@update:model-value="changeItem(row)"
|
||||
>
|
||||
<template #option="scope">
|
||||
<QItem v-bind="scope.itemProps">
|
||||
|
@ -742,16 +759,21 @@ watch(
|
|||
</div>
|
||||
<FetchedTags :item="row" :max-length="6" />
|
||||
<QPopupProxy v-if="row.id && isTicketEditable">
|
||||
<VnInput v-model="row.concept" @change="updateConcept(row)" />
|
||||
<VnInput
|
||||
v-model="row.concept"
|
||||
@keyup.enter.stop="changeConcept(row)"
|
||||
:hint="t('globals.enterToConfirm')"
|
||||
/>
|
||||
</QPopupProxy>
|
||||
</template>
|
||||
<template #column-quantity="{ row }">
|
||||
<VnInput
|
||||
data-cy="ticketSaleQuantityInput"
|
||||
v-if="row.isNew || isTicketEditable"
|
||||
type="number"
|
||||
v-model.number="row.quantity"
|
||||
@blur="changeQuantity(row)"
|
||||
@keyup.enter="changeQuantity(row)"
|
||||
@keyup.enter.stop="changeQuantity(row)"
|
||||
@update:model-value="() => (rowToUpdate = row)"
|
||||
@focus="edit.oldQuantity = row.quantity"
|
||||
/>
|
||||
|
@ -765,10 +787,12 @@ watch(
|
|||
<TicketEditManaProxy
|
||||
ref="editPriceProxyRef"
|
||||
:mana="mana"
|
||||
:sale="row"
|
||||
:new-price="getNewPrice"
|
||||
@save="updatePrice(row)"
|
||||
@save="changePrice"
|
||||
>
|
||||
<VnInput
|
||||
@keyup.enter.stop="() => editManaProxyRef.save(row)"
|
||||
v-model.number="edit.price"
|
||||
:label="t('basicData.price')"
|
||||
type="number"
|
||||
|
@ -782,27 +806,29 @@ watch(
|
|||
<QBtn flat class="link" dense @click="onOpenEditDiscountPopover(row)">
|
||||
{{ toPercentage(row.discount / 100) }}
|
||||
</QBtn>
|
||||
|
||||
<TicketEditManaProxy
|
||||
ref="editManaProxyRef"
|
||||
:mana="mana"
|
||||
:sale="row"
|
||||
:new-price="getNewPrice"
|
||||
:uses-mana="usesMana"
|
||||
:mana-code="manaCode"
|
||||
@save="changeDiscount(row)"
|
||||
@save="changeDiscount"
|
||||
>
|
||||
<VnInput
|
||||
autofocus
|
||||
@keyup.enter.stop="() => editManaProxyRef.save(row)"
|
||||
v-model.number="edit.discount"
|
||||
:label="t('ticketSale.discount')"
|
||||
type="number"
|
||||
/>
|
||||
<div v-if="usesMana" class="column q-gutter-y-sm q-mt-sm">
|
||||
<VnUsesMana :mana-code="manaCode" />
|
||||
</div>
|
||||
</TicketEditManaProxy>
|
||||
</template>
|
||||
<span v-else>{{ toPercentage(row.discount / 100) }}</span>
|
||||
</template>
|
||||
<template #column-amount="{ row }">
|
||||
{{ toCurrency(row.quantity * row.price) }}
|
||||
{{ toCurrency(getSaleTotal(row)) }}
|
||||
</template>
|
||||
</VnTable>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import useNotify from 'src/composables/useNotify.js';
|
|||
import { useState } from 'src/composables/useState';
|
||||
import { toDateTimeFormat } from 'src/filters/date.js';
|
||||
import axios from 'axios';
|
||||
import TicketProblems from 'src/components/TicketProblems.vue';
|
||||
|
||||
const state = useState();
|
||||
const { t } = useI18n();
|
||||
|
@ -286,71 +287,7 @@ watch(
|
|||
</span>
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.isTaxDataChecked === 0"
|
||||
color="primary"
|
||||
name="vn:no036"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.noVerified') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.hasTicketRequest"
|
||||
color="primary"
|
||||
name="vn:buyrequest"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.purchaseRequest') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.itemShortage"
|
||||
color="primary"
|
||||
name="vn:unavailable"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('ticketSale.noVisible') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.isFreezed"
|
||||
color="primary"
|
||||
name="vn:frozen"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.clientFrozen') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon v-if="row.risk" color="primary" name="vn:risk" size="xs">
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.risk') }}: {{ row.risk }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.hasComponentLack"
|
||||
color="primary"
|
||||
name="vn:components"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.componentLack') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QIcon
|
||||
v-if="row.hasRounding"
|
||||
color="primary"
|
||||
name="sync_problem"
|
||||
size="xs"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('futureTickets.rounding') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<TicketProblems :row />
|
||||
</span>
|
||||
</template>
|
||||
<template #column-id="{ row }">
|
||||
|
|
|
@ -9,6 +9,7 @@ import VnRow from 'components/ui/VnRow.vue';
|
|||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -53,7 +54,16 @@ const warehousesOptionsIn = ref([]);
|
|||
<VnInputDate v-model="data.shipped" :label="t('globals.shipped')" />
|
||||
<VnInputDate v-model="data.landed" :label="t('globals.landed')" />
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<VnInputDate
|
||||
v-model="data.availabled"
|
||||
:label="t('travel.summary.availabled')"
|
||||
/>
|
||||
<VnInputTime
|
||||
v-model="data.availabled"
|
||||
:label="t('travel.summary.availabledHour')"
|
||||
/>
|
||||
</VnRow>
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
:label="t('globals.warehouseOut')"
|
||||
|
@ -101,10 +111,3 @@ const warehousesOptionsIn = ref([]);
|
|||
</template>
|
||||
</FormModel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
raidDays: El travel se desplaza automáticamente cada día para estar desde hoy al número de días indicado. Si se deja vacio no se moverá
|
||||
en:
|
||||
raidDays: The travel adjusts itself daily to match the number of days set, starting from today. If left blank, it won’t move
|
||||
</i18n>
|
||||
|
|
|
@ -11,6 +11,7 @@ export default {
|
|||
'agencyModeFk',
|
||||
'isRaid',
|
||||
'daysInForward',
|
||||
'availabled',
|
||||
],
|
||||
include: [
|
||||
{
|
||||
|
|
|
@ -10,6 +10,8 @@ import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue'
|
|||
import FetchData from 'src/components/FetchData.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import { toDate, toCurrency, toCelsius } from 'src/filters';
|
||||
import { toDateTimeFormat } from 'src/filters/date.js';
|
||||
import { dashIfEmpty } from 'src/filters';
|
||||
import axios from 'axios';
|
||||
import TravelDescriptorMenuItems from './TravelDescriptorMenuItems.vue';
|
||||
|
||||
|
@ -333,6 +335,12 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
|
|||
<VnLv :label="t('globals.reference')" :value="travel.ref" />
|
||||
<VnLv label="m³" :value="travel.m3" />
|
||||
<VnLv :label="t('globals.totalEntries')" :value="travel.totalEntries" />
|
||||
<VnLv
|
||||
:label="t('travel.summary.availabled')"
|
||||
:value="
|
||||
dashIfEmpty(toDateTimeFormat(travel.availabled))
|
||||
"
|
||||
/>
|
||||
</QCard>
|
||||
<QCard class="full-width">
|
||||
<VnTitle :text="t('travel.summary.entries')" />
|
||||
|
|
|
@ -209,7 +209,7 @@ const onThermographCreated = async (data) => {
|
|||
}"
|
||||
sort-by="thermographFk ASC"
|
||||
option-label="thermographFk"
|
||||
option-filter-value="id"
|
||||
option-filter-value="thermographFk"
|
||||
:disable="viewAction === 'edit'"
|
||||
:tooltip="t('New thermograph')"
|
||||
:roles-allowed-to-create="['logistic']"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { QBtn } from 'quasar';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
||||
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
|
||||
|
@ -22,6 +23,8 @@ import VnPopup from 'src/components/common/VnPopup.vue';
|
|||
const stateStore = useStateStore();
|
||||
const { t } = useI18n();
|
||||
const { openReport } = usePrintService();
|
||||
const route = useRoute();
|
||||
const tableParams = ref();
|
||||
|
||||
const shippedFrom = ref(Date.vnNew());
|
||||
const landedTo = ref(Date.vnNew());
|
||||
|
@ -143,7 +146,7 @@ const columns = computed(() => [
|
|||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: t('globals.pageTitles.supplier'),
|
||||
label: t('extraCommunity.cargoShip'),
|
||||
field: 'cargoSupplierNickname',
|
||||
name: 'cargoSupplierNickname',
|
||||
align: 'left',
|
||||
|
@ -171,7 +174,7 @@ const columns = computed(() => [
|
|||
? value.reduce((sum, entry) => {
|
||||
return sum + (entry.invoiceAmount || 0);
|
||||
}, 0)
|
||||
: 0
|
||||
: 0,
|
||||
),
|
||||
},
|
||||
{
|
||||
|
@ -200,7 +203,7 @@ const columns = computed(() => [
|
|||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: t('kg'),
|
||||
label: t('extraCommunity.kg'),
|
||||
field: 'kg',
|
||||
name: 'kg',
|
||||
align: 'left',
|
||||
|
@ -208,7 +211,7 @@ const columns = computed(() => [
|
|||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: t('physicKg'),
|
||||
label: t('extraCommunity.physicKg'),
|
||||
field: 'loadedKg',
|
||||
name: 'loadedKg',
|
||||
align: 'left',
|
||||
|
@ -232,7 +235,7 @@ const columns = computed(() => [
|
|||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: t('shipped'),
|
||||
label: t('extraCommunity.shipped'),
|
||||
field: 'shipped',
|
||||
name: 'shipped',
|
||||
align: 'left',
|
||||
|
@ -249,7 +252,7 @@ const columns = computed(() => [
|
|||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: t('landed'),
|
||||
label: t('extraCommunity.landed'),
|
||||
field: 'landed',
|
||||
name: 'landed',
|
||||
align: 'left',
|
||||
|
@ -258,7 +261,7 @@ const columns = computed(() => [
|
|||
format: (value) => toDate(value),
|
||||
},
|
||||
{
|
||||
label: t('notes'),
|
||||
label: t('extraCommunity.notes'),
|
||||
field: '',
|
||||
name: 'notes',
|
||||
align: 'center',
|
||||
|
@ -284,7 +287,7 @@ watch(
|
|||
if (!arrayData.store.data) return;
|
||||
onStoreDataChange();
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
{ deep: true, immediate: true },
|
||||
);
|
||||
|
||||
const openReportPdf = () => {
|
||||
|
@ -451,13 +454,24 @@ const getColor = (percentage) => {
|
|||
for (const { value, className } of travelKgPercentages.value)
|
||||
if (percentage > value) return className;
|
||||
};
|
||||
|
||||
const filteredEntries = (entries) => {
|
||||
if (!tableParams?.value?.entrySupplierFk) return entries;
|
||||
return entries?.filter(
|
||||
(entry) => entry.supplierFk === tableParams?.value?.entrySupplierFk,
|
||||
);
|
||||
};
|
||||
|
||||
watch(route, () => {
|
||||
tableParams.value = JSON.parse(route.query.table);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<VnSearchbar
|
||||
data-key="ExtraCommunity"
|
||||
:limit="20"
|
||||
:label="t('searchExtraCommunity')"
|
||||
:label="t('extraCommunity.searchExtraCommunity')"
|
||||
/>
|
||||
<RightMenu>
|
||||
<template #right-panel>
|
||||
|
@ -521,7 +535,7 @@ const getColor = (percentage) => {
|
|||
? tableColumnComponents[col.name].event(
|
||||
rows[props.rowIndex][col.field],
|
||||
col.field,
|
||||
props.rowIndex
|
||||
props.rowIndex,
|
||||
)
|
||||
: {}
|
||||
"
|
||||
|
@ -546,7 +560,7 @@ const getColor = (percentage) => {
|
|||
},
|
||||
{
|
||||
link: ['id', 'cargoSupplierNickname'].includes(
|
||||
col.name
|
||||
col.name,
|
||||
),
|
||||
},
|
||||
]"
|
||||
|
@ -564,9 +578,8 @@ const getColor = (percentage) => {
|
|||
</component>
|
||||
</QTd>
|
||||
</QTr>
|
||||
|
||||
<QTr
|
||||
v-for="(entry, index) in props.row.entries"
|
||||
v-for="(entry, index) in filteredEntries(props.row.entries)"
|
||||
:key="index"
|
||||
:props="props"
|
||||
class="bg-vn-secondary-row cursor-pointer"
|
||||
|
@ -598,7 +611,7 @@ const getColor = (percentage) => {
|
|||
name="warning"
|
||||
color="negative"
|
||||
size="md"
|
||||
:title="t('requiresInspection')"
|
||||
:title="t('extraCommunity.requiresInspection')"
|
||||
>
|
||||
</QIcon>
|
||||
</QTd>
|
||||
|
@ -709,24 +722,3 @@ const getColor = (percentage) => {
|
|||
width: max-content;
|
||||
}
|
||||
</style>
|
||||
<i18n>
|
||||
en:
|
||||
searchExtraCommunity: Search for extra community shipping
|
||||
kg: BI. KG
|
||||
physicKg: Phy. KG
|
||||
shipped: W. shipped
|
||||
landed: W. landed
|
||||
requiresInspection: Requires inspection
|
||||
BIP: Boder Inspection Point
|
||||
notes: Notes
|
||||
es:
|
||||
searchExtraCommunity: Buscar por envío extra comunitario
|
||||
kg: KG Bloq.
|
||||
physicKg: KG físico
|
||||
shipped: F. envío
|
||||
landed: F. llegada
|
||||
notes: Notas
|
||||
Open as PDF: Abrir como PDF
|
||||
requiresInspection: Requiere inspección
|
||||
BIP: Punto de Inspección Fronteriza
|
||||
</i18n>
|
||||
|
|
|
@ -79,7 +79,7 @@ warehouses();
|
|||
<VnFilterPanel :data-key="props.dataKey" :search-button="true">
|
||||
<template #tags="{ tag, formatFn }">
|
||||
<div class="q-gutter-x-xs">
|
||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||
<strong>{{ t(`extraCommunity.filter.${tag.label}`) }}: </strong>
|
||||
<span>{{ formatFn(tag.value) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -92,7 +92,7 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
:label="t('params.reference')"
|
||||
:label="t('extraCommunity.filter.reference')"
|
||||
v-model="params.reference"
|
||||
is-outlined
|
||||
/>
|
||||
|
@ -103,7 +103,7 @@ warehouses();
|
|||
<QInput
|
||||
v-model="params.totalEntries"
|
||||
type="number"
|
||||
:label="t('params.totalEntries')"
|
||||
:label="t('extraCommunity.filter.totalEntries')"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
@ -133,10 +133,10 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('params.agencyModeFk')"
|
||||
:label="t('extraCommunity.filter.agencyModeFk')"
|
||||
v-model="params.agencyModeFk"
|
||||
:options="agenciesOptions"
|
||||
option-value="agencyFk"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
hide-selected
|
||||
dense
|
||||
|
@ -148,7 +148,7 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
:label="t('params.shippedFrom')"
|
||||
:label="t('extraCommunity.filter.shippedFrom')"
|
||||
v-model="params.shippedFrom"
|
||||
@update:model-value="searchFn()"
|
||||
is-outlined
|
||||
|
@ -158,7 +158,7 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInputDate
|
||||
:label="t('params.landedTo')"
|
||||
:label="t('extraCommunity.filter.landedTo')"
|
||||
v-model="params.landedTo"
|
||||
@update:model-value="searchFn()"
|
||||
is-outlined
|
||||
|
@ -168,7 +168,7 @@ warehouses();
|
|||
<QItem v-if="warehousesByContinent[params.continent]">
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('params.warehouseOutFk')"
|
||||
:label="t('extraCommunity.filter.warehouseOutFk')"
|
||||
v-model="params.warehouseOutFk"
|
||||
:options="warehousesByContinent[params.continent]"
|
||||
option-value="id"
|
||||
|
@ -183,7 +183,7 @@ warehouses();
|
|||
<QItem v-else>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('params.warehouseOutFk')"
|
||||
:label="t('extraCommunity.filter.warehouseOutFk')"
|
||||
v-model="params.warehouseOutFk"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
|
@ -198,7 +198,7 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('params.warehouseInFk')"
|
||||
:label="t('extraCommunity.filter.warehouseInFk')"
|
||||
v-model="params.warehouseInFk"
|
||||
:options="warehousesOptions"
|
||||
option-value="id"
|
||||
|
@ -213,6 +213,7 @@ warehouses();
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectSupplier
|
||||
:label="t('extraCommunity.cargoShip')"
|
||||
v-model="params.cargoSupplierFk"
|
||||
hide-selected
|
||||
dense
|
||||
|
@ -221,10 +222,21 @@ warehouses();
|
|||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectSupplier
|
||||
v-model="params.entrySupplierFk"
|
||||
hide-selected
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelect
|
||||
:label="t('params.continent')"
|
||||
:label="t('extraCommunity.filter.continent')"
|
||||
v-model="params.continent"
|
||||
:options="continentsOptions"
|
||||
option-value="code"
|
||||
|
@ -240,30 +252,3 @@ warehouses();
|
|||
</template>
|
||||
</VnFilterPanel>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
en:
|
||||
params:
|
||||
id: Id
|
||||
reference: Reference
|
||||
totalEntries: Total entries
|
||||
agencyModeFk: Agency
|
||||
warehouseInFk: Warehouse In
|
||||
warehouseOutFk: Warehouse Out
|
||||
shippedFrom: Shipped from
|
||||
landedTo: Landed to
|
||||
cargoSupplierFk: Supplier
|
||||
continent: Continent out
|
||||
es:
|
||||
params:
|
||||
id: Id
|
||||
reference: Referencia
|
||||
totalEntries: Ent. totales
|
||||
agencyModeFk: Agencia
|
||||
warehouseInFk: Alm. entrada
|
||||
warehouseOutFk: Alm. salida
|
||||
shippedFrom: Llegada desde
|
||||
landedTo: Llegada hasta
|
||||
cargoSupplierFk: Proveedor
|
||||
continent: Cont. Salida
|
||||
</i18n>
|
||||
|
|
|
@ -10,6 +10,9 @@ import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
|
|||
import TravelFilter from './TravelFilter.vue';
|
||||
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||
import VnSection from 'src/components/common/VnSection.vue';
|
||||
import VnInputTime from 'src/components/common/VnInputTime.vue';
|
||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||
import { toDateTimeFormat } from 'src/filters/date';
|
||||
|
||||
const { viewSummary } = useSummaryDialog();
|
||||
const router = useRouter();
|
||||
|
@ -167,6 +170,17 @@ const columns = computed(() => [
|
|||
cardVisible: true,
|
||||
create: true,
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'availabled',
|
||||
label: t('travel.summary.availabled'),
|
||||
component: 'input',
|
||||
columnClass: 'expand',
|
||||
columnField: {
|
||||
component: null,
|
||||
},
|
||||
format: (row, dashIfEmpty) => dashIfEmpty(toDateTimeFormat(row.availabled)),
|
||||
},
|
||||
{
|
||||
align: 'right',
|
||||
label: '',
|
||||
|
@ -269,6 +283,16 @@ const columns = computed(() => [
|
|||
:class="{ 'is-active': row.isReceived }"
|
||||
/>
|
||||
</template>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnInputDate
|
||||
v-model="data.availabled"
|
||||
:label="t('travel.summary.availabled')"
|
||||
/>
|
||||
<VnInputTime
|
||||
v-model="data.availabled"
|
||||
:label="t('travel.summary.availabledHour')"
|
||||
/>
|
||||
</template>
|
||||
<template #moreFilterPanel="{ params }">
|
||||
<VnInputNumber
|
||||
:label="t('params.scopeDays')"
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
extraCommunity:
|
||||
cargoShip: Cargo ship
|
||||
searchExtraCommunity: Search for extra community shipping
|
||||
kg: BI. KG
|
||||
physicKg: Phy. KG
|
||||
shipped: W. shipped
|
||||
landed: W. landed
|
||||
requiresInspection: Requires inspection
|
||||
BIP: Boder Inspection Point
|
||||
notes: Notes
|
||||
filter:
|
||||
id: Id
|
||||
reference: Reference
|
||||
totalEntries: Total entries
|
||||
agencyModeFk: Agency
|
||||
warehouseInFk: Warehouse In
|
||||
warehouseOutFk: Warehouse Out
|
||||
shippedFrom: Shipped from
|
||||
landedTo: Landed to
|
||||
cargoSupplierFk: Cargo supplier
|
||||
continent: Continent out
|
||||
entrySupplierFk: Supplier
|
|
@ -0,0 +1,23 @@
|
|||
extraCommunity:
|
||||
cargoShip: Carguera
|
||||
searchExtraCommunity: Buscar por envío extra comunitario
|
||||
kg: KG Bloq.
|
||||
physicKg: KG físico
|
||||
shipped: F. envío
|
||||
landed: F. llegada
|
||||
notes: Notas
|
||||
Open as PDF: Abrir como PDF
|
||||
requiresInspection: Requiere inspección
|
||||
BIP: Punto de Inspección Fronteriza
|
||||
filter:
|
||||
id: Id
|
||||
reference: Referencia
|
||||
totalEntries: Ent. totales
|
||||
agencyModeFk: Agencia
|
||||
warehouseInFk: Alm. entrada
|
||||
warehouseOutFk: Alm. salida
|
||||
shippedFrom: Llegada desde
|
||||
landedTo: Llegada hasta
|
||||
cargoSupplierFk: Carguera
|
||||
continent: Cont. Salida
|
||||
entrySupplierFk: Proveedor
|
|
@ -53,7 +53,7 @@ const showChangePasswordDialog = () => {
|
|||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem
|
||||
v-if="!worker.user.emailVerified && user.id == worker.id"
|
||||
v-if="!worker.user.emailVerified && user.id != worker.id"
|
||||
v-ripple
|
||||
clickable
|
||||
@click="showChangePasswordDialog"
|
||||
|
|
|
@ -119,7 +119,7 @@ const columns = computed(() => [
|
|||
:url="`Workers/${entityId}/trainingCourse`"
|
||||
:url-create="`Workers/${entityId}/trainingCourse`"
|
||||
save-url="TrainingCourses/crud"
|
||||
:filter="courseFilter"
|
||||
:user-filter="courseFilter"
|
||||
:create="{
|
||||
urlCreate: 'trainingCourses',
|
||||
title: t('Create training course'),
|
||||
|
|
|
@ -8,6 +8,17 @@ const { t } = useI18n();
|
|||
const route = useRoute();
|
||||
const entityId = computed(() => route.params.id);
|
||||
|
||||
const centerFilter = {
|
||||
include: [
|
||||
{
|
||||
relation: 'center',
|
||||
scope: {
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -33,7 +44,7 @@ const columns = [
|
|||
create: true,
|
||||
component: 'select',
|
||||
attrs: {
|
||||
url: 'medicalCenters',
|
||||
url: 'centers',
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
},
|
||||
|
@ -84,6 +95,7 @@ const columns = [
|
|||
ref="tableRef"
|
||||
data-key="WorkerMedical"
|
||||
:url="`Workers/${entityId}/medicalReview`"
|
||||
:user-filter="centerFilter"
|
||||
save-url="MedicalReviews/crud"
|
||||
:create="{
|
||||
urlCreate: 'medicalReviews',
|
||||
|
|
|
@ -176,6 +176,7 @@ const deleteRelative = async (id) => {
|
|||
:label="t('isDescendant')"
|
||||
v-model="row.isDescendant"
|
||||
class="q-gutter-xs q-mb-xs"
|
||||
data-cy="Descendant/Ascendant"
|
||||
/>
|
||||
<VnSelect
|
||||
:label="t('disabilityGrades')"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { computed, ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import FormModel from 'src/components/FormModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
|
@ -9,33 +9,23 @@ import VnInputTime from 'src/components/common/VnInputTime.vue';
|
|||
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const agencyFilter = {
|
||||
fields: ['id', 'name'],
|
||||
order: 'name ASC',
|
||||
limit: 30,
|
||||
};
|
||||
const agencyOptions = ref([]);
|
||||
const validAddresses = ref([]);
|
||||
const addresses = ref([]);
|
||||
|
||||
const filterWhere = computed(() => ({
|
||||
id: { inq: validAddresses.value.map((item) => item.addressFk) },
|
||||
}));
|
||||
const setFilteredAddresses = (data) => {
|
||||
const validIds = new Set(validAddresses.value.map((item) => item.addressFk));
|
||||
addresses.value = data.filter((address) => validIds.has(address.id));
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FetchData
|
||||
:filter="agencyFilter"
|
||||
@on-fetch="(data) => (agencyOptions = data)"
|
||||
auto-load
|
||||
url="AgencyModes/isActive"
|
||||
/>
|
||||
<FetchData
|
||||
url="RoadmapAddresses"
|
||||
auto-load
|
||||
@on-fetch="(data) => (validAddresses = data)"
|
||||
/>
|
||||
<FormModel :url="`Zones/${$route.params.id}`" auto-load data-key="Zone">
|
||||
<FetchData url="Addresses" auto-load @on-fetch="setFilteredAddresses" />
|
||||
<FormModel auto-load model="Zone">
|
||||
<template #form="{ data, validate }">
|
||||
<VnRow>
|
||||
<VnInput
|
||||
|
@ -43,9 +33,9 @@ const filterWhere = computed(() => ({
|
|||
:label="t('Name')"
|
||||
clearable
|
||||
v-model="data.name"
|
||||
:required="true"
|
||||
/>
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
<VnSelect
|
||||
v-model="data.agencyModeFk"
|
||||
|
@ -94,7 +84,7 @@ const filterWhere = computed(() => ({
|
|||
type="number"
|
||||
min="0"
|
||||
/>
|
||||
<VnInputTime v-model="data.hour" :label="t('Closing')" />
|
||||
<VnInputTime v-model="data.hour" :label="t('Closing')" :required="true" />
|
||||
</VnRow>
|
||||
|
||||
<VnRow>
|
||||
|
@ -103,7 +93,7 @@ const filterWhere = computed(() => ({
|
|||
:label="t('Price')"
|
||||
type="number"
|
||||
min="0"
|
||||
required="true"
|
||||
:required="true"
|
||||
clearable
|
||||
/>
|
||||
<VnInput
|
||||
|
@ -111,7 +101,7 @@ const filterWhere = computed(() => ({
|
|||
:label="t('Price optimum')"
|
||||
type="number"
|
||||
min="0"
|
||||
required="true"
|
||||
:required="true"
|
||||
clearable
|
||||
/>
|
||||
</VnRow>
|
||||
|
@ -128,7 +118,7 @@ const filterWhere = computed(() => ({
|
|||
v-model="data.addressFk"
|
||||
option-value="id"
|
||||
option-label="nickname"
|
||||
url="Addresses"
|
||||
:options="addresses"
|
||||
:fields="['id', 'nickname']"
|
||||
sort-by="id"
|
||||
hide-selected
|
||||
|
|
|
@ -38,7 +38,12 @@ const agencies = ref([]);
|
|||
<template #body="{ params, searchFn }">
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput :label="t('list.name')" v-model="params.name" is-outlined />
|
||||
<VnInput
|
||||
:label="t('list.name')"
|
||||
v-model="params.name"
|
||||
is-outlined
|
||||
data-cy="zoneFilterPanelNameInput"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
|
@ -53,6 +58,7 @@ const agencies = ref([]);
|
|||
dense
|
||||
outlined
|
||||
rounded
|
||||
data-cy="zoneFilterPanelAgencySelect"
|
||||
>
|
||||
</VnSelect>
|
||||
</QItemSection>
|
||||
|
|
|
@ -65,7 +65,6 @@ const tableFilter = {
|
|||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
align: 'left',
|
||||
name: 'id',
|
||||
label: t('list.id'),
|
||||
chip: {
|
||||
|
@ -75,6 +74,8 @@ const columns = computed(() => [
|
|||
columnFilter: {
|
||||
inWhere: true,
|
||||
},
|
||||
columnClass: 'shrink-column',
|
||||
component: 'number',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -106,7 +107,6 @@ const columns = computed(() => [
|
|||
format: (row, dashIfEmpty) => dashIfEmpty(row?.agencyMode?.name),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
name: 'price',
|
||||
label: t('list.price'),
|
||||
cardVisible: true,
|
||||
|
@ -114,9 +114,11 @@ const columns = computed(() => [
|
|||
columnFilter: {
|
||||
inWhere: true,
|
||||
},
|
||||
columnClass: 'shrink-column',
|
||||
component: 'number',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
align: 'center',
|
||||
name: 'hour',
|
||||
label: t('list.close'),
|
||||
cardVisible: true,
|
||||
|
@ -129,6 +131,7 @@ const columns = computed(() => [
|
|||
label: t('list.addressFk'),
|
||||
cardVisible: true,
|
||||
columnFilter: false,
|
||||
columnClass: 'expand',
|
||||
},
|
||||
{
|
||||
align: 'right',
|
||||
|
@ -177,67 +180,73 @@ function formatRow(row) {
|
|||
<ZoneFilterPanel data-key="ZonesList" />
|
||||
</template>
|
||||
</RightMenu>
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="ZonesList"
|
||||
url="Zones"
|
||||
:create="{
|
||||
urlCreate: 'Zones',
|
||||
title: t('list.createZone'),
|
||||
onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`),
|
||||
formInitialData: {},
|
||||
}"
|
||||
:user-filter="tableFilter"
|
||||
:columns="columns"
|
||||
redirect="zone"
|
||||
:right-search="false"
|
||||
>
|
||||
<template #column-addressFk="{ row }">
|
||||
{{ dashIfEmpty(formatRow(row)) }}
|
||||
</template>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnSelect
|
||||
url="AgencyModes"
|
||||
v-model="data.agencyModeFk"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:label="t('list.agency')"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.price"
|
||||
:label="t('list.price')"
|
||||
min="0"
|
||||
type="number"
|
||||
required="true"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.bonus"
|
||||
:label="t('zone.bonus')"
|
||||
min="0"
|
||||
type="number"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.travelingDays"
|
||||
:label="t('zone.travelingDays')"
|
||||
type="number"
|
||||
min="0"
|
||||
/>
|
||||
<VnInputTime v-model="data.hour" :label="t('list.close')" />
|
||||
<VnSelect
|
||||
url="Warehouses"
|
||||
v-model="data.warehouseFK"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:label="t('list.warehouse')"
|
||||
:options="warehouseOptions"
|
||||
/>
|
||||
<QCheckbox
|
||||
v-model="data.isVolumetric"
|
||||
:label="t('list.isVolumetric')"
|
||||
:toggle-indeterminate="false"
|
||||
/>
|
||||
</template>
|
||||
</VnTable>
|
||||
<div class="table-container">
|
||||
<div class="column items-center">
|
||||
<VnTable
|
||||
ref="tableRef"
|
||||
data-key="ZonesList"
|
||||
url="Zones"
|
||||
:create="{
|
||||
urlCreate: 'Zones',
|
||||
title: t('list.createZone'),
|
||||
onDataSaved: ({ id }) => tableRef.redirect(`${id}/location`),
|
||||
formInitialData: {},
|
||||
}"
|
||||
:user-filter="tableFilter"
|
||||
:columns="columns"
|
||||
redirect="zone"
|
||||
:right-search="false"
|
||||
table-height="85vh"
|
||||
order="id ASC"
|
||||
>
|
||||
<template #column-addressFk="{ row }">
|
||||
{{ dashIfEmpty(formatRow(row)) }}
|
||||
</template>
|
||||
<template #more-create-dialog="{ data }">
|
||||
<VnSelect
|
||||
url="AgencyModes"
|
||||
v-model="data.agencyModeFk"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:label="t('list.agency')"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.price"
|
||||
:label="t('list.price')"
|
||||
min="0"
|
||||
type="number"
|
||||
required="true"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.bonus"
|
||||
:label="t('zone.bonus')"
|
||||
min="0"
|
||||
type="number"
|
||||
/>
|
||||
<VnInput
|
||||
v-model="data.travelingDays"
|
||||
:label="t('zone.travelingDays')"
|
||||
type="number"
|
||||
min="0"
|
||||
/>
|
||||
<VnInputTime v-model="data.hour" :label="t('list.close')" />
|
||||
<VnSelect
|
||||
url="Warehouses"
|
||||
v-model="data.warehouseFK"
|
||||
option-value="id"
|
||||
option-label="name"
|
||||
:label="t('list.warehouse')"
|
||||
:options="warehouseOptions"
|
||||
/>
|
||||
<QCheckbox
|
||||
v-model="data.isVolumetric"
|
||||
:label="t('list.isVolumetric')"
|
||||
:toggle-indeterminate="false"
|
||||
/>
|
||||
</template>
|
||||
</VnTable>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
|
@ -245,3 +254,20 @@ es:
|
|||
Search zone: Buscar zona
|
||||
You can search zones by id or name: Puedes buscar zonas por id o nombre
|
||||
</i18n>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
min-width: 70%;
|
||||
}
|
||||
|
||||
:deep(.shrink-column) {
|
||||
width: 8%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -56,7 +56,7 @@ onMounted(() => weekdayStore.initStore());
|
|||
<ZoneSearchbar />
|
||||
<VnSubToolbar />
|
||||
<QPage class="column items-center q-pa-md">
|
||||
<QCard class="full-width q-pa-md">
|
||||
<QCard class="containerShrinked q-pa-md">
|
||||
<div
|
||||
v-for="(detail, index) in details"
|
||||
:key="index"
|
||||
|
|
|
@ -44,6 +44,8 @@ summary:
|
|||
filterPanel:
|
||||
name: Name
|
||||
agencyModeFk: Agency
|
||||
id: ID
|
||||
price: Price
|
||||
deliveryPanel:
|
||||
pickup: Pick up
|
||||
delivery: Delivery
|
||||
|
|
|
@ -45,6 +45,8 @@ summary:
|
|||
filterPanel:
|
||||
name: Nombre
|
||||
agencyModeFk: Agencia
|
||||
id: ID
|
||||
price: Precio
|
||||
deliveryPanel:
|
||||
pickup: Recogida
|
||||
delivery: Entrega
|
||||
|
|
|
@ -45,7 +45,6 @@ describe('OrderCatalog', () => {
|
|||
).type('{enter}');
|
||||
cy.get(':nth-child(1) > [data-cy="catalogFilterCategory"]').click();
|
||||
cy.dataCy('catalogFilterValueDialogBtn').last().click();
|
||||
cy.get('[data-cy="catalogFilterValueDialogTagSelect"]').click();
|
||||
cy.selectOption("[data-cy='catalogFilterValueDialogTagSelect']", 'Tallos');
|
||||
cy.dataCy('catalogFilterValueDialogValueInput').find('input').focus();
|
||||
cy.dataCy('catalogFilterValueDialogValueInput').find('input').type('2');
|
||||
|
|
|
@ -3,11 +3,46 @@ describe('Client consignee', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1110/address', {
|
||||
timeout: 5000,
|
||||
});
|
||||
cy.visit('#/customer/1107/address');
|
||||
cy.domContentLoad();
|
||||
});
|
||||
it('Should load layout', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
});
|
||||
|
||||
it('check as equalizated', function () {
|
||||
cy.get('.q-card__section > .address-card').then(($el) => {
|
||||
let addressCards_before = $el.length;
|
||||
|
||||
cy.get('.q-page-sticky > div > .q-btn').click();
|
||||
const addressName = 'test';
|
||||
cy.dataCy('Consignee_input').type(addressName);
|
||||
cy.dataCy('Location_select').click();
|
||||
cy.get('[role="listbox"] .q-item:nth-child(1)').click();
|
||||
cy.dataCy('Street address_input').type('TEST ADDRESS');
|
||||
cy.get('.q-btn-group > .q-btn--standard').click();
|
||||
cy.location('href').should('contain', '#/customer/1107/address');
|
||||
cy.get('.q-card__section > .address-card').should(
|
||||
'have.length',
|
||||
addressCards_before + 1,
|
||||
);
|
||||
cy.get('.q-card__section > .address-card')
|
||||
.eq(addressCards_before)
|
||||
.should('be.visible')
|
||||
.get('.text-weight-bold')
|
||||
.eq(addressCards_before - 1)
|
||||
.should('contain', addressName)
|
||||
.click();
|
||||
});
|
||||
cy.get(
|
||||
'.q-card > :nth-child(1) > :nth-child(2) > .q-checkbox > .q-checkbox__inner',
|
||||
)
|
||||
.should('have.class', 'q-checkbox__inner--falsy')
|
||||
.click();
|
||||
|
||||
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click();
|
||||
cy.get(
|
||||
':nth-child(2) > :nth-child(2) > .flex > .q-mr-lg > .q-checkbox__inner',
|
||||
).should('have.class', 'q-checkbox__inner--truthy');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,9 +3,8 @@ describe('Client fiscal data', () => {
|
|||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
cy.visit('#/customer/1107/fiscal-data', {
|
||||
timeout: 5000,
|
||||
});
|
||||
cy.visit('#/customer/1107/fiscal-data');
|
||||
cy.domContentLoad();
|
||||
});
|
||||
it('Should change required value when change customer', () => {
|
||||
cy.get('.q-card').should('be.visible');
|
||||
|
@ -15,4 +14,25 @@ describe('Client fiscal data', () => {
|
|||
cy.get('.q-item > .q-item__label').should('have.text', ' #1');
|
||||
cy.dataCy('sageTaxTypeFk').filter('input').should('have.attr', 'required');
|
||||
});
|
||||
|
||||
it('check as equalizated', () => {
|
||||
cy.get(
|
||||
':nth-child(1) > .q-checkbox > .q-checkbox__inner > .q-checkbox__bg',
|
||||
).click();
|
||||
cy.get('.q-btn-group > .q-btn--standard > .q-btn__content').click();
|
||||
|
||||
cy.get('.q-card > :nth-child(1) > span').should(
|
||||
'contain',
|
||||
'You changed the equalization tax',
|
||||
);
|
||||
|
||||
cy.get('.q-card > :nth-child(2) > span').should(
|
||||
'have.text',
|
||||
'Do you want to spread the change?',
|
||||
);
|
||||
cy.get('[data-cy="VnConfirm_confirm"] > .q-btn__content > .block').click();
|
||||
cy.get(
|
||||
'.bg-warning > .q-notification__wrapper > .q-notification__content > .q-notification__message',
|
||||
).should('have.text', 'Equivalent tax spreaded');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -106,8 +106,9 @@ describe('Entry', () => {
|
|||
cy.get(`td[data-col-field="${field}"][data-row-index="${row}"]`);
|
||||
const selectSpan = (field, row = 0) => selectCell(field, row).find('div > span');
|
||||
const selectButton = (cySelector) => cy.get(`button[data-cy="${cySelector}"]`);
|
||||
const clickAndType = (field, value, row = 0) =>
|
||||
selectCell(field, row).click().type(value);
|
||||
const clickAndType = (field, value, row = 0) => {
|
||||
selectCell(field, row).click().type(`${value}{esc}`);
|
||||
};
|
||||
const checkText = (field, expectedText, row = 0) =>
|
||||
selectCell(field, row).should('have.text', expectedText);
|
||||
const checkColor = (field, expectedColor, row = 0) =>
|
||||
|
@ -115,21 +116,18 @@ describe('Entry', () => {
|
|||
|
||||
createEntryAndBuy();
|
||||
|
||||
selectCell('isIgnored')
|
||||
.click()
|
||||
.click()
|
||||
.trigger('keydown', { key: 'Tab', keyCode: 9, which: 9 });
|
||||
checkText('isIgnored', 'check');
|
||||
checkColor('quantity', COLORS.negative);
|
||||
selectCell('isIgnored').click().click().type('{esc}');
|
||||
checkText('isIgnored', 'close');
|
||||
|
||||
clickAndType('stickers', '1');
|
||||
checkText('quantity', '11');
|
||||
checkText('amount', '550.00');
|
||||
checkText('stickers', '0/01');
|
||||
checkText('quantity', '1');
|
||||
checkText('amount', '50.00');
|
||||
clickAndType('packing', '2');
|
||||
checkText('packing', '12close');
|
||||
checkText('packing', '12');
|
||||
checkText('weight', '12.0');
|
||||
checkText('quantity', '132');
|
||||
checkText('amount', '6600.00');
|
||||
checkText('quantity', '12');
|
||||
checkText('amount', '600.00');
|
||||
checkColor('packing', COLORS.enabled);
|
||||
|
||||
selectCell('groupingMode').click().click().click();
|
||||
|
@ -137,7 +135,7 @@ describe('Entry', () => {
|
|||
checkColor('grouping', COLORS.enabled);
|
||||
|
||||
selectCell('buyingValue').click().clear().type('{backspace}{backspace}1');
|
||||
checkText('amount', '132.00');
|
||||
checkText('amount', '12.00');
|
||||
checkColor('minPrice', COLORS.disable);
|
||||
|
||||
selectCell('hasMinPrice').click().click();
|
||||
|
@ -145,7 +143,7 @@ describe('Entry', () => {
|
|||
selectCell('hasMinPrice').click();
|
||||
|
||||
cy.saveCard();
|
||||
cy.get('span[data-cy="footer-stickers"]').should('have.text', '11');
|
||||
cy.get('span[data-cy="footer-stickers"]').should('have.text', '1');
|
||||
cy.get('.q-notification__message').contains('Data saved');
|
||||
|
||||
selectButton('change-quantity-sign').should('be.disabled');
|
||||
|
@ -156,9 +154,9 @@ describe('Entry', () => {
|
|||
|
||||
selectButton('change-quantity-sign').click();
|
||||
selectButton('set-negative-quantity').click();
|
||||
checkText('quantity', '-132');
|
||||
checkText('quantity', '-12');
|
||||
selectButton('set-positive-quantity').click();
|
||||
checkText('quantity', '132');
|
||||
checkText('quantity', '12');
|
||||
checkColor('amount', COLORS.disable);
|
||||
|
||||
selectButton('check-buy-amount').click();
|
||||
|
|
|
@ -8,11 +8,9 @@ describe('EntryMy when is supplier', () => {
|
|||
},
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should open buyLabel when is supplier', () => {
|
||||
cy.get(
|
||||
'[to="/null/3"] > .q-card > :nth-child(2) > .q-btn > .q-btn__content > .q-icon'
|
||||
).click();
|
||||
cy.dataCy('cardBtn').eq(2).click();
|
||||
cy.dataCy('printLabelsBtn').click();
|
||||
cy.window().its('open').should('be.called');
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ describe('EntryStockBought', () => {
|
|||
});
|
||||
it('Should edit the reserved space', () => {
|
||||
cy.get('.q-field__native.q-placeholder').should('have.value', '01/01/2001');
|
||||
cy.get('td[data-col-field="reserve"]').click();
|
||||
cy.get('[data-col-field="reserve"][data-row-index="0"]').click();
|
||||
cy.get('input[name="reserve"]').type('10{enter}');
|
||||
cy.get('button[title="Save"]').click();
|
||||
cy.get('.q-notification__message').should('have.text', 'Data saved');
|
||||
|
@ -16,25 +16,35 @@ describe('EntryStockBought', () => {
|
|||
cy.get('input[aria-label="Reserve"]').type('1');
|
||||
cy.get('input[aria-label="Date"]').eq(1).clear();
|
||||
cy.get('input[aria-label="Date"]').eq(1).type('01-01');
|
||||
cy.get('input[aria-label="Buyer"]').type('buyerboss{downarrow}{enter}');
|
||||
cy.get('input[aria-label="Buyer"]').type('buyerBossNick');
|
||||
cy.get('div[role="listbox"] > div > div[role="option"]')
|
||||
.eq(0)
|
||||
.should('be.visible')
|
||||
.click();
|
||||
|
||||
cy.get('[data-cy="FormModelPopup_save"]').click();
|
||||
cy.get('.q-notification__message').should('have.text', 'Data created');
|
||||
|
||||
cy.get('[data-col-field="reserve"][data-row-index="1"]').click().clear();
|
||||
cy.get('[data-cy="searchBtn"]').eq(1).click();
|
||||
cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata')
|
||||
.should('have.text', 'warningNo data available')
|
||||
.type('{esc}');
|
||||
cy.get('[data-col-field="reserve"][data-row-index="1"]')
|
||||
.click()
|
||||
.type('{backspace}{enter}');
|
||||
cy.get('[data-cy="crudModelDefaultSaveBtn"]').should('be.enabled').click();
|
||||
cy.get('.q-notification__message').eq(1).should('have.text', 'Data saved');
|
||||
});
|
||||
it('Should check detail for the buyer', () => {
|
||||
cy.get(':nth-child(1) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
|
||||
cy.get('[data-cy="searchBtn"]').eq(0).click();
|
||||
cy.get('tBody > tr').eq(1).its('length').should('eq', 1);
|
||||
});
|
||||
it('Should check detail for the buyerBoss and had no content', () => {
|
||||
cy.get(':nth-child(2) > .sticky > .q-btn > .q-btn__content > .q-icon').click();
|
||||
cy.get('.q-table__bottom.row.items-center.q-table__bottom--nodata').should(
|
||||
'have.text',
|
||||
'warningNo data available',
|
||||
);
|
||||
});
|
||||
|
||||
it('Should edit travel m3 and refresh', () => {
|
||||
cy.get('.vn-row > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||
cy.get('input[aria-label="m3"]').clear();
|
||||
cy.get('input[aria-label="m3"]').type('60');
|
||||
cy.get('.q-mt-lg > .q-btn--standard > .q-btn__content > .block').click();
|
||||
cy.get('[data-cy="edit-travel"]').should('be.visible').click();
|
||||
cy.get('input[aria-label="m3"]').clear().type('60');
|
||||
cy.get('[data-cy="FormModelPopup_save"]').click();
|
||||
cy.get('.vn-row > div > :nth-child(2)').should('have.text', '60');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -36,7 +36,7 @@ describe('InvoiceInVat', () => {
|
|||
cy.get(dialogInputs).eq(0).type(randomInt);
|
||||
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
|
||||
|
||||
cy.get('button[type="submit"]').click();
|
||||
cy.get('[data-cy="FormModelPopup_save"]').click();
|
||||
cy.get('.q-notification__message').should('have.text', 'Data created');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,122 +1,208 @@
|
|||
/// <reference types="cypress" />
|
||||
|
||||
describe('TicketSale', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.viewport(1920, 1080);
|
||||
cy.visit('/#/ticket/31/sale');
|
||||
});
|
||||
|
||||
const firstRow = 'tbody > :nth-child(1)';
|
||||
|
||||
const selectFirstRow = () => {
|
||||
cy.waitForElement(firstRow);
|
||||
cy.get(firstRow).find('.q-checkbox__inner').click();
|
||||
};
|
||||
|
||||
it('it should add item to basket', () => {
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'open').as('windowOpen');
|
||||
describe('Free ticket #31', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.viewport(1920, 1080);
|
||||
cy.visit('/#/ticket/31/sale');
|
||||
});
|
||||
cy.dataCy('ticketSaleAddToBasketBtn').should('exist');
|
||||
cy.dataCy('ticketSaleAddToBasketBtn').click();
|
||||
cy.get('@windowOpen').should('be.calledWithMatch', /\/order\/\d+\/catalog/);
|
||||
});
|
||||
|
||||
it('should send SMS', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="sendShortageSMSItem"]');
|
||||
cy.dataCy('sendShortageSMSItem').should('exist');
|
||||
cy.dataCy('sendShortageSMSItem').click();
|
||||
cy.dataCy('vnSmsDialog').should('exist');
|
||||
cy.dataCy('sendSmsBtn').click();
|
||||
cy.checkNotification('SMS sent');
|
||||
});
|
||||
const firstRow = 'tbody > :nth-child(1)';
|
||||
|
||||
it('should recalculate price when "Recalculate price" is clicked', () => {
|
||||
cy.intercept('POST', '**/recalculatePrice').as('recalculatePrice');
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="recalculatePriceItem"]');
|
||||
cy.dataCy('recalculatePriceItem').should('exist');
|
||||
cy.dataCy('recalculatePriceItem').click();
|
||||
cy.wait('@recalculatePrice').its('response.statusCode').should('eq', 200);
|
||||
cy.checkNotification('Data saved');
|
||||
});
|
||||
const selectFirstRow = () => {
|
||||
cy.waitForElement(firstRow);
|
||||
cy.get(firstRow).find('.q-checkbox__inner').click();
|
||||
};
|
||||
|
||||
it('should update discount when "Update discount" is clicked', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="updateDiscountItem"]');
|
||||
cy.dataCy('updateDiscountItem').should('exist');
|
||||
cy.dataCy('updateDiscountItem').click();
|
||||
cy.waitForElement('[data-cy="ticketSaleDiscountInput"]');
|
||||
cy.dataCy('ticketSaleDiscountInput').find('input').focus();
|
||||
cy.dataCy('ticketSaleDiscountInput').find('input').type('10');
|
||||
cy.dataCy('saveManaBtn').click();
|
||||
cy.waitForElement('.q-notification__message');
|
||||
cy.checkNotification('Data saved');
|
||||
});
|
||||
it('it should add item to basket', () => {
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, 'open').as('windowOpen');
|
||||
});
|
||||
cy.dataCy('ticketSaleAddToBasketBtn').should('exist');
|
||||
cy.dataCy('ticketSaleAddToBasketBtn').click();
|
||||
cy.get('@windowOpen').should('be.calledWithMatch', /\/order\/\d+\/catalog/);
|
||||
});
|
||||
|
||||
it('adds claim', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('createClaimItem').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.url().should('contain', 'claim/');
|
||||
// Delete created claim to avoid cluttering the database
|
||||
cy.dataCy('descriptor-more-opts').click();
|
||||
cy.dataCy('deleteClaim').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.checkNotification('Data deleted');
|
||||
});
|
||||
it('should send SMS', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="sendShortageSMSItem"]');
|
||||
cy.dataCy('sendShortageSMSItem').should('exist');
|
||||
cy.dataCy('sendShortageSMSItem').click();
|
||||
cy.dataCy('vnSmsDialog').should('exist');
|
||||
cy.dataCy('sendSmsBtn').click();
|
||||
cy.checkNotification('SMS sent');
|
||||
});
|
||||
|
||||
it('marks row as reserved', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="markAsReservedItem"]');
|
||||
cy.dataCy('markAsReservedItem').click();
|
||||
cy.dataCy('ticketSaleReservedIcon').should('exist');
|
||||
});
|
||||
it('should recalculate price when "Recalculate price" is clicked', () => {
|
||||
cy.intercept('POST', '**/recalculatePrice').as('recalculatePrice');
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="recalculatePriceItem"]');
|
||||
cy.dataCy('recalculatePriceItem').should('exist');
|
||||
cy.dataCy('recalculatePriceItem').click();
|
||||
cy.wait('@recalculatePrice').its('response.statusCode').should('eq', 200);
|
||||
cy.checkNotification('Data saved');
|
||||
});
|
||||
|
||||
it('unmarks row as reserved', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="unmarkAsReservedItem"]');
|
||||
cy.dataCy('unmarkAsReservedItem').click();
|
||||
cy.dataCy('ticketSaleReservedIcon').should('not.exist');
|
||||
});
|
||||
it('should update discount when "Update discount" is clicked', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="updateDiscountItem"]');
|
||||
cy.dataCy('updateDiscountItem').should('exist');
|
||||
cy.dataCy('updateDiscountItem').click();
|
||||
cy.waitForElement('[data-cy="ticketSaleDiscountInput"]');
|
||||
cy.dataCy('ticketSaleDiscountInput').find('input').focus();
|
||||
cy.dataCy('ticketSaleDiscountInput').find('input').type('10');
|
||||
cy.dataCy('saveManaBtn').click();
|
||||
cy.waitForElement('.q-notification__message');
|
||||
cy.checkNotification('Data saved');
|
||||
});
|
||||
|
||||
it('refunds row with warehouse', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('ticketSaleRefundItem').click();
|
||||
cy.dataCy('ticketSaleRefundWithWarehouse').click();
|
||||
cy.checkNotification('The following refund ticket have been created');
|
||||
});
|
||||
it('adds claim', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('createClaimItem').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.url().should('contain', 'claim/');
|
||||
// Delete created claim to avoid cluttering the database
|
||||
cy.dataCy('descriptor-more-opts').click();
|
||||
cy.dataCy('deleteClaim').click();
|
||||
cy.dataCy('VnConfirm_confirm').click();
|
||||
cy.checkNotification('Data deleted');
|
||||
});
|
||||
|
||||
it('refunds row without warehouse', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('ticketSaleRefundItem').click();
|
||||
cy.dataCy('ticketSaleRefundWithoutWarehouse').click();
|
||||
cy.checkNotification('The following refund ticket have been created');
|
||||
});
|
||||
it('marks row as reserved', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="markAsReservedItem"]');
|
||||
cy.dataCy('markAsReservedItem').click();
|
||||
cy.dataCy('ticketSaleReservedIcon').should('exist');
|
||||
});
|
||||
|
||||
it('transfer sale to a new ticket', () => {
|
||||
cy.visit('/#/ticket/32/sale');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #32');
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleTransferBtn').click();
|
||||
cy.dataCy('ticketTransferPopup').should('exist');
|
||||
cy.dataCy('ticketTransferNewTicketBtn').click();
|
||||
//check the new ticket has been created succesfully
|
||||
cy.get('.q-item > .q-item__label').should('not.have.text', ' #32');
|
||||
});
|
||||
it('unmarks row as reserved', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.waitForElement('[data-cy="unmarkAsReservedItem"]');
|
||||
cy.dataCy('unmarkAsReservedItem').click();
|
||||
cy.dataCy('ticketSaleReservedIcon').should('not.exist');
|
||||
});
|
||||
|
||||
it('should redirect to ticket logs', () => {
|
||||
cy.get(firstRow).find('.q-btn:last').click();
|
||||
cy.url().should('match', /\/ticket\/31\/log/);
|
||||
it('refunds row with warehouse', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('ticketSaleRefundItem').click();
|
||||
cy.dataCy('ticketSaleRefundWithWarehouse').click();
|
||||
cy.checkNotification('The following refund ticket have been created');
|
||||
});
|
||||
|
||||
it('refunds row without warehouse', () => {
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleMoreActionsDropdown').click();
|
||||
cy.dataCy('ticketSaleRefundItem').click();
|
||||
cy.dataCy('ticketSaleRefundWithoutWarehouse').click();
|
||||
cy.checkNotification('The following refund ticket have been created');
|
||||
});
|
||||
|
||||
it('transfer sale to a new ticket', () => {
|
||||
cy.visit('/#/ticket/32/sale');
|
||||
cy.get('.q-item > .q-item__label').should('have.text', ' #32');
|
||||
selectFirstRow();
|
||||
cy.dataCy('ticketSaleTransferBtn').click();
|
||||
cy.dataCy('ticketTransferPopup').should('exist');
|
||||
cy.dataCy('ticketTransferNewTicketBtn').click();
|
||||
//check the new ticket has been created succesfully
|
||||
cy.get('.q-item > .q-item__label').should('not.have.text', ' #32');
|
||||
});
|
||||
|
||||
it('should redirect to ticket logs', () => {
|
||||
cy.get(firstRow).find('.q-btn:last').click();
|
||||
cy.url().should('match', /\/ticket\/31\/log/);
|
||||
});
|
||||
});
|
||||
describe('Ticket prepared #23', () => {
|
||||
beforeEach(() => {
|
||||
cy.login('developer');
|
||||
cy.viewport(1920, 1080);
|
||||
cy.visit('/#/ticket/23/sale');
|
||||
});
|
||||
|
||||
const firstRow = 'tbody > :nth-child(1)';
|
||||
|
||||
const selectFirstRow = () => {
|
||||
cy.waitForElement(firstRow);
|
||||
cy.get(firstRow).find('.q-checkbox__inner').click();
|
||||
};
|
||||
|
||||
it('update price', () => {
|
||||
const price = Number((Math.random() * 99 + 1).toFixed(2));
|
||||
cy.waitForElement(firstRow);
|
||||
cy.get(':nth-child(10) > .q-btn').click();
|
||||
cy.waitForElement('[data-cy="ticketEditManaProxy"]');
|
||||
cy.dataCy('ticketEditManaProxy').should('exist');
|
||||
cy.waitForElement('[data-cy="Price_input"]');
|
||||
cy.dataCy('Price_input').clear();
|
||||
cy.dataCy('Price_input').type(price);
|
||||
cy.dataCy('saveManaBtn').click();
|
||||
handleVnConfirm();
|
||||
|
||||
cy.get(':nth-child(10) > .q-btn > .q-btn__content').should(
|
||||
'have.text',
|
||||
`€${price}`,
|
||||
);
|
||||
});
|
||||
it('update dicount', () => {
|
||||
const discount = Math.floor(Math.random() * 100) + 1;
|
||||
selectFirstRow();
|
||||
cy.get(':nth-child(11) > .q-btn').click();
|
||||
cy.waitForElement('[data-cy="ticketEditManaProxy"]');
|
||||
cy.dataCy('ticketEditManaProxy').should('exist');
|
||||
cy.waitForElement('[data-cy="Disc_input"]');
|
||||
cy.dataCy('Disc_input').clear();
|
||||
cy.dataCy('Disc_input').type(discount);
|
||||
cy.dataCy('saveManaBtn').click();
|
||||
handleVnConfirm();
|
||||
|
||||
cy.get(':nth-child(11) > .q-btn > .q-btn__content').should(
|
||||
'have.text',
|
||||
`${discount}.00%`,
|
||||
);
|
||||
});
|
||||
|
||||
it('change concept', () => {
|
||||
const quantity = Math.floor(Math.random() * 100) + 1;
|
||||
cy.waitForElement(firstRow);
|
||||
cy.get(':nth-child(8) > .row').click();
|
||||
cy.get(
|
||||
'.q-menu > [data-v-ca3f07a4=""] > .q-field > .q-field__inner > .q-field__control > .q-field__control-container > [data-cy="undefined_input"]',
|
||||
)
|
||||
.type(quantity)
|
||||
.type('{enter}');
|
||||
handleVnConfirm();
|
||||
|
||||
cy.get(':nth-child(8) >.row').should('contain.text', `${quantity}`);
|
||||
});
|
||||
it('changequantity ', () => {
|
||||
const quantity = Math.floor(Math.random() * 100) + 1;
|
||||
cy.waitForElement(firstRow);
|
||||
cy.dataCy('ticketSaleQuantityInput').clear();
|
||||
cy.dataCy('ticketSaleQuantityInput').type(quantity).trigger('tab');
|
||||
cy.get('.q-page > :nth-child(6)').click();
|
||||
|
||||
handleVnConfirm();
|
||||
|
||||
cy.get('[data-cy="ticketSaleQuantityInput"]')
|
||||
.find('[data-cy="undefined_input"]')
|
||||
.should('have.value', `${quantity}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function handleVnConfirm() {
|
||||
cy.get('[data-cy="VnConfirm_confirm"] > .q-btn__content > .block').click();
|
||||
cy.waitForElement('.q-notification__message');
|
||||
|
||||
cy.get('.q-notification__message').should('be.visible');
|
||||
cy.checkNotification('Data saved');
|
||||
}
|
||||
|
|
|
@ -2,9 +2,24 @@ describe('WorkerCreate', () => {
|
|||
const externalRadio = '.q-radio:nth-child(2)';
|
||||
const developerBossId = 120;
|
||||
const payMethodCross =
|
||||
'.grid-create .full-width > :nth-child(9) .q-select .q-field__append:not(.q-anchor--skip)';
|
||||
':nth-child(9) > .q-select > .q-field__inner > .q-field__control > :nth-child(2)';
|
||||
const saveBtn = '.q-mt-lg > .q-btn--standard';
|
||||
|
||||
const internalWithOutPay = {
|
||||
Fi: { val: '78457139E' },
|
||||
'Web user': { val: 'manolo' },
|
||||
Name: { val: 'Manolo' },
|
||||
'Last name': { val: 'Hurtado' },
|
||||
'Personal email': { val: 'manolo@mydomain.com' },
|
||||
Company: { val: 'VNL', type: 'select' },
|
||||
Street: { val: 'S/ DEFAULTWORKERSTREET' },
|
||||
Location: { val: 1, type: 'select' },
|
||||
Phone: { val: '123456789' },
|
||||
'Worker code': { val: 'DWW' },
|
||||
Boss: { val: developerBossId, type: 'select' },
|
||||
Birth: { val: '11-12-2022', type: 'date' },
|
||||
};
|
||||
|
||||
const internal = {
|
||||
Fi: { val: '78457139E' },
|
||||
'Web user': { val: 'manolo' },
|
||||
|
@ -14,6 +29,7 @@ describe('WorkerCreate', () => {
|
|||
Company: { val: 'VNL', type: 'select' },
|
||||
Street: { val: 'S/ DEFAULTWORKERSTREET' },
|
||||
Location: { val: 1, type: 'select' },
|
||||
'Pay method': { val: 1, type: 'select' },
|
||||
Phone: { val: '123456789' },
|
||||
'Worker code': { val: 'DWW' },
|
||||
Boss: { val: developerBossId, type: 'select' },
|
||||
|
@ -37,17 +53,14 @@ describe('WorkerCreate', () => {
|
|||
});
|
||||
|
||||
it('should throw an error if a pay method has not been selected', () => {
|
||||
cy.fillInForm(internal);
|
||||
cy.fillInForm(internalWithOutPay);
|
||||
cy.get(payMethodCross).click();
|
||||
cy.get(saveBtn).click();
|
||||
cy.checkNotification('Payment method is required');
|
||||
});
|
||||
|
||||
it('should create an internal', () => {
|
||||
cy.fillInForm({
|
||||
...internal,
|
||||
'Pay method': { val: 'PayMethod one', type: 'select' },
|
||||
});
|
||||
cy.fillInForm(internal);
|
||||
cy.get(saveBtn).click();
|
||||
cy.checkNotification('Data created');
|
||||
});
|
||||
|
|
|
@ -18,7 +18,7 @@ describe('WorkerNotificationsManager', () => {
|
|||
cy.visit(`/#/worker/${salesPersonId}/notifications`);
|
||||
cy.get(firstAvailableNotification).click();
|
||||
cy.checkNotification(
|
||||
'The notification subscription of this worker cant be modified'
|
||||
'The notification subscription of this worker cant be modified',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ describe('WorkerPit', () => {
|
|||
const spousePensionInput = '[data-cy="Spouse Pension_input"]';
|
||||
const spousePension = '120';
|
||||
const addRelative = '[data-cy="addRelative"]';
|
||||
const isDescendantSelect = '[data-cy="Descendant/Ascendant_select"]';
|
||||
const isDescendantSelect = '[data-cy="Descendant/Ascendant"]';
|
||||
const Descendant = 'Descendiente';
|
||||
const birthedInput = '[data-cy="Birth Year_input"]';
|
||||
const birthed = '2002';
|
||||
const adoptionYearInput = '[data-cy="Adoption Year_input"]';
|
||||
|
@ -28,11 +29,8 @@ describe('WorkerPit', () => {
|
|||
cy.get(spouseNifInput).type(spouseNif);
|
||||
cy.get(spousePensionInput).type(spousePension);
|
||||
cy.get(savePIT).click();
|
||||
});
|
||||
|
||||
it('complete relative', () => {
|
||||
cy.get(addRelative).click();
|
||||
cy.get(isDescendantSelect).type('{downArrow}{downArrow}{enter}');
|
||||
cy.get(isDescendantSelect).type(Descendant);
|
||||
cy.get(birthedInput).type(birthed);
|
||||
cy.get(adoptionYearInput).type(adoptionYear);
|
||||
cy.get(saveRelative).click();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
describe('ZoneList', () => {
|
||||
const agency = 'inhouse pickup';
|
||||
beforeEach(() => {
|
||||
cy.viewport(1280, 720);
|
||||
cy.login('developer');
|
||||
|
@ -6,11 +7,15 @@ describe('ZoneList', () => {
|
|||
});
|
||||
|
||||
it('should filter by agency', () => {
|
||||
cy.get('input[aria-label="Agency"]').type('{downArrow}{enter}');
|
||||
cy.dataCy('zoneFilterPanelNameInput').type('{downArrow}{enter}');
|
||||
});
|
||||
|
||||
it('should open the zone summary', () => {
|
||||
cy.get('input[aria-label="Name"]').type('zone refund');
|
||||
cy.get('.q-scrollarea__content > .q-btn--standard > .q-btn__content').click();
|
||||
cy.dataCy('zoneFilterPanelAgencySelect').type(agency);
|
||||
cy.get('.q-menu .q-item').contains(agency).click();
|
||||
cy.get(':nth-child(1) > [data-col-field="agencyModeFk"]').should(
|
||||
'include.text',
|
||||
agency,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue