Merge branch 'dev' into 7050-testCrudModel
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
JOSE ANTONIO TUBAU RODRIGUEZ 2024-12-23 06:15:21 +00:00
commit 5cbff5035b
121 changed files with 1310 additions and 975 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "salix-front", "name": "salix-front",
"version": "24.52.0", "version": "25.02.0",
"description": "Salix frontend", "description": "Salix frontend",
"productName": "Salix", "productName": "Salix",
"author": "Verdnatura", "author": "Verdnatura",

View File

@ -3,12 +3,12 @@ import { useSession } from 'src/composables/useSession';
import { Router } from 'src/router'; import { Router } from 'src/router';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { useStateQueryStore } from 'src/stores/useStateQueryStore'; import { useStateQueryStore } from 'src/stores/useStateQueryStore';
import { i18n } from 'src/boot/i18n';
const session = useSession(); const session = useSession();
const { notify } = useNotify(); const { notify } = useNotify();
const stateQuery = useStateQueryStore(); const stateQuery = useStateQueryStore();
const baseUrl = '/api/'; const baseUrl = '/api/';
axios.defaults.baseURL = baseUrl; axios.defaults.baseURL = baseUrl;
const axiosNoError = axios.create({ baseURL: baseUrl }); const axiosNoError = axios.create({ baseURL: baseUrl });
@ -16,6 +16,7 @@ const onRequest = (config) => {
const token = session.getToken(); const token = session.getToken();
if (token.length && !config.headers.Authorization) { if (token.length && !config.headers.Authorization) {
config.headers.Authorization = token; config.headers.Authorization = token;
config.headers['Accept-Language'] = i18n.global.locale.value;
} }
stateQuery.add(config); stateQuery.add(config);
return config; return config;

View File

@ -1,9 +1,11 @@
import { boot } from 'quasar/wrappers'; import { boot } from 'quasar/wrappers';
import { createI18n } from 'vue-i18n'; import { createI18n } from 'vue-i18n';
import messages from 'src/i18n'; import messages from 'src/i18n';
import { useState } from 'src/composables/useState';
const user = useState().getUser();
const i18n = createI18n({ const i18n = createI18n({
locale: navigator.language || navigator.userLanguage, locale: user.value.lang || navigator.language || navigator.userLanguage,
fallbackLocale: 'en', fallbackLocale: 'en',
globalInjection: true, globalInjection: true,
messages, messages,

View File

@ -17,12 +17,10 @@ const stateQuery = useStateQueryStore();
const state = useState(); const state = useState();
const user = state.getUser(); const user = state.getUser();
const appName = 'Lilium'; const appName = 'Lilium';
const pinnedModulesRef = ref();
onMounted(() => stateStore.setMounted()); onMounted(() => stateStore.setMounted());
const pinnedModulesRef = ref();
</script> </script>
<template> <template>
<QHeader color="white" elevated> <QHeader color="white" elevated>
<QToolbar class="q-py-sm q-px-md"> <QToolbar class="q-py-sm q-px-md">
@ -65,16 +63,6 @@ const pinnedModulesRef = ref();
<QSpace /> <QSpace />
<div class="q-pl-sm q-gutter-sm row items-center no-wrap"> <div class="q-pl-sm q-gutter-sm row items-center no-wrap">
<div id="actions-prepend"></div> <div id="actions-prepend"></div>
<QBtn
flat
v-if="!quasar.platform.is.mobile"
@click="pinnedModulesRef.redirect($route.params.id)"
icon="more_up"
>
<QTooltip>
{{ t('Go to Salix') }}
</QTooltip>
</QBtn>
<QBtn <QBtn
:class="{ 'q-pa-none': quasar.platform.is.mobile }" :class="{ 'q-pa-none': quasar.platform.is.mobile }"
id="pinnedModules" id="pinnedModules"
@ -106,7 +94,6 @@ const pinnedModulesRef = ref();
<VnBreadcrumbs v-if="$q.screen.lt.md" class="q-ml-md" /> <VnBreadcrumbs v-if="$q.screen.lt.md" class="q-ml-md" />
</QHeader> </QHeader>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.searchbar { .searchbar {
width: max-content; width: max-content;
@ -115,9 +102,3 @@ const pinnedModulesRef = ref();
background-color: var(--vn-section-color); background-color: var(--vn-section-color);
} }
</style> </style>
<i18n>
en:
Go to Salix: Go to Salix
es:
Go to Salix: Ir a Salix
</i18n>

View File

@ -87,10 +87,10 @@ async function saveDarkMode(value) {
async function saveLanguage(value) { async function saveLanguage(value) {
const query = `/VnUsers/${user.value.id}`; const query = `/VnUsers/${user.value.id}`;
try { try {
await axios.patch(query, { await axios.patch(query, { lang: value });
lang: value,
});
user.value.lang = value; user.value.lang = value;
useState().setUser(user.value);
onDataSaved(); onDataSaved();
} catch (error) { } catch (error) {
onDataError(); onDataError();

View File

@ -150,6 +150,7 @@ const tableModes = [
disable: $props.disableOption?.card, disable: $props.disableOption?.card,
}, },
]; ];
onBeforeMount(() => { onBeforeMount(() => {
const urlParams = route.query[$props.searchUrl]; const urlParams = route.query[$props.searchUrl];
hasParams.value = urlParams && Object.keys(urlParams).length !== 0; hasParams.value = urlParams && Object.keys(urlParams).length !== 0;
@ -481,7 +482,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
:class="col.headerClass" :class="col.headerClass"
> >
<div <div
class="column self-start q-ml-xs ellipsis" class="column ellipsis"
:class="`text-${col?.align ?? 'left'}`" :class="`text-${col?.align ?? 'left'}`"
:style="$props.columnSearch ? 'height: 75px' : ''" :style="$props.columnSearch ? 'height: 75px' : ''"
> >
@ -523,7 +524,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
<!-- Columns --> <!-- Columns -->
<QTd <QTd
auto-width auto-width
class="no-margin q-px-xs" class="no-margin"
:class="[getColAlign(col), col.columnClass]" :class="[getColAlign(col), col.columnClass]"
:style="col.style" :style="col.style"
v-if="col.visible ?? true" v-if="col.visible ?? true"
@ -658,13 +659,7 @@ function handleSelection({ evt, added, rows: selectedRows }, rows) {
:key="col.name" :key="col.name"
class="fields" class="fields"
> >
<VnLv <VnLv :label="col.label + ':'">
:label="
!col.component && col.label
? `${col.label}:`
: ''
"
>
<template #value> <template #value>
<span <span
@click="stopEventPropagation($event)" @click="stopEventPropagation($event)"
@ -805,7 +800,7 @@ es:
.grid-three { .grid-three {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, max-content)); grid-template-columns: repeat(auto-fit, minmax(350px, max-content));
max-width: 100%; max-width: 100%;
grid-gap: 20px; grid-gap: 20px;
margin: 0 auto; margin: 0 auto;
@ -854,21 +849,6 @@ es:
top: 0; top: 0;
padding: 12px 0; padding: 12px 0;
} }
tbody {
.q-checkbox {
display: flex;
margin-bottom: 9px;
& .q-checkbox__label {
margin-left: 31px;
color: var(--vn-text-color);
}
& .q-checkbox__inner {
position: absolute;
left: 0;
color: var(--vn-label-color);
}
}
}
.sticky { .sticky {
position: sticky; position: sticky;
right: 0; right: 0;

View File

@ -2,7 +2,11 @@
import { ref, onMounted, useSlots } from 'vue'; import { ref, onMounted, useSlots } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { useQuasar } from 'quasar';
const { t } = useI18n();
const quasar = useQuasar();
const stateStore = useStateStore();
const slots = useSlots(); const slots = useSlots();
const hasContent = ref(false); const hasContent = ref(false);
const rightPanel = ref(null); const rightPanel = ref(null);
@ -11,7 +15,6 @@ onMounted(() => {
rightPanel.value = document.querySelector('#right-panel'); rightPanel.value = document.querySelector('#right-panel');
if (!rightPanel.value) return; if (!rightPanel.value) return;
// Check if there's content to display
const observer = new MutationObserver(() => { const observer = new MutationObserver(() => {
hasContent.value = rightPanel.value.childNodes.length; hasContent.value = rightPanel.value.childNodes.length;
}); });
@ -21,12 +24,9 @@ onMounted(() => {
childList: true, childList: true,
attributes: true, attributes: true,
}); });
if ((!slots['right-panel'] && !hasContent.value) || quasar.platform.is.mobile)
if (!slots['right-panel'] && !hasContent.value) stateStore.rightDrawer = false; stateStore.rightDrawer = false;
}); });
const { t } = useI18n();
const stateStore = useStateStore();
</script> </script>
<template> <template>
<Teleport to="#actions-append" v-if="stateStore.isHeaderMounted()"> <Teleport to="#actions-append" v-if="stateStore.isHeaderMounted()">
@ -45,7 +45,7 @@ const stateStore = useStateStore();
</QBtn> </QBtn>
</div> </div>
</Teleport> </Teleport>
<QDrawer v-model="stateStore.rightDrawer" side="right" :width="256" show-if-above> <QDrawer v-model="stateStore.rightDrawer" side="right" :width="256">
<QScrollArea class="fit"> <QScrollArea class="fit">
<div id="right-panel"></div> <div id="right-panel"></div>
<slot v-if="!hasContent" name="right-panel" /> <slot v-if="!hasContent" name="right-panel" />

View File

@ -106,7 +106,7 @@ const manageDate = (date) => {
:class="{ required: isRequired }" :class="{ required: isRequired }"
:rules="mixinRules" :rules="mixinRules"
:clearable="false" :clearable="false"
@click="isPopupOpen = true" @click="isPopupOpen = !isPopupOpen"
hide-bottom-space hide-bottom-space
> >
<template #append> <template #append>
@ -125,13 +125,6 @@ const manageDate = (date) => {
isPopupOpen = false; isPopupOpen = false;
" "
/> />
<QIcon
v-if="showEvent"
name="event"
class="cursor-pointer"
@click="isPopupOpen = !isPopupOpen"
:title="t('Open date')"
/>
</template> </template>
<QMenu <QMenu
v-if="$q.screen.gt.xs" v-if="$q.screen.gt.xs"
@ -151,15 +144,6 @@ const manageDate = (date) => {
</QInput> </QInput>
</div> </div>
</template> </template>
<style lang="scss">
.vn-input-date.q-field--standard.q-field--readonly .q-field__control:before {
border-bottom-style: solid;
}
.vn-input-date.q-field--outlined.q-field--readonly .q-field__control:before {
border-style: solid;
}
</style>
<i18n> <i18n>
es: es:
Open date: Abrir fecha Open date: Abrir fecha

View File

@ -1,13 +1,28 @@
<script setup> <script setup>
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import { ref } from 'vue';
import { useAttrs } from 'vue'; defineProps({
step: { type: Number, default: 0.01 },
decimalPlaces: { type: Number, default: 2 },
positive: { type: Boolean, default: true },
});
const model = defineModel({ type: [Number, String] }); const model = defineModel({ type: [Number, String] });
const $attrs = useAttrs();
const step = ref($attrs.step || 0.01);
</script> </script>
<template> <template>
<VnInput v-bind="$attrs" v-model.number="model" type="number" :step="step" /> <VnInput
v-bind="$attrs"
v-model.number="model"
type="number"
:step="step"
@input="
(evt) => {
const val = evt.target.value;
if (positive && val < 0) return (model = 0);
const [, decimal] = val.split('.');
if (val && decimal?.length > decimalPlaces)
model = parseFloat(val).toFixed(decimalPlaces);
}
"
/>
</template> </template>

View File

@ -80,7 +80,7 @@ function dateToTime(newDate) {
:class="{ required: isRequired }" :class="{ required: isRequired }"
style="min-width: 100px" style="min-width: 100px"
:rules="mixinRules" :rules="mixinRules"
@click="isPopupOpen = false" @click="isPopupOpen = !isPopupOpen"
type="time" type="time"
hide-bottom-space hide-bottom-space
> >
@ -100,12 +100,6 @@ function dateToTime(newDate) {
isPopupOpen = false; isPopupOpen = false;
" "
/> />
<QIcon
name="Schedule"
class="cursor-pointer"
@click="isPopupOpen = !isPopupOpen"
:title="t('Open time')"
/>
</template> </template>
<QMenu <QMenu
v-if="$q.screen.gt.xs" v-if="$q.screen.gt.xs"

View File

@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useRequired } from 'src/composables/useRequired'; import { useRequired } from 'src/composables/useRequired';
import dataByOrder from 'src/utils/dataByOrder'; import dataByOrder from 'src/utils/dataByOrder';
import { QItemLabel } from 'quasar';
const emit = defineEmits(['update:modelValue', 'update:options', 'remove']); const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
const $attrs = useAttrs(); const $attrs = useAttrs();
@ -33,6 +34,10 @@ const $props = defineProps({
type: String, type: String,
default: 'id', default: 'id',
}, },
optionCaption: {
type: String,
default: null,
},
optionFilter: { optionFilter: {
type: String, type: String,
default: null, default: null,
@ -101,6 +106,10 @@ const $props = defineProps({
type: String, type: String,
default: null, default: null,
}, },
isOutlined: {
type: Boolean,
default: false,
},
}); });
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])]; const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
@ -115,6 +124,15 @@ const noOneOpt = ref({
[optionValue.value]: false, [optionValue.value]: false,
[optionLabel.value]: noOneText, [optionLabel.value]: noOneText,
}); });
const styleAttrs = computed(() => {
return $props.isOutlined
? {
dense: true,
outlined: true,
rounded: true,
}
: {};
});
const isLoading = ref(false); const isLoading = ref(false);
const useURL = computed(() => $props.url); const useURL = computed(() => $props.url);
const value = computed({ const value = computed({
@ -288,7 +306,7 @@ function handleKeyDown(event) {
} }
const focusableElements = document.querySelectorAll( const focusableElements = document.querySelectorAll(
'a, button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])' 'a:not([disabled]), button:not([disabled]), input:not([disabled]), textarea:not([disabled]), select:not([disabled]), details:not([disabled]), [tabindex]:not([tabindex="-1"]):not([disabled])'
); );
const currentIndex = Array.prototype.indexOf.call( const currentIndex = Array.prototype.indexOf.call(
focusableElements, focusableElements,
@ -307,9 +325,8 @@ function handleKeyDown(event) {
:options="myOptions" :options="myOptions"
:option-label="optionLabel" :option-label="optionLabel"
:option-value="optionValue" :option-value="optionValue"
v-bind="$attrs" v-bind="{ ...$attrs, ...styleAttrs }"
@filter="filterHandler" @filter="filterHandler"
@keydown="handleKeyDown"
:emit-value="nullishToTrue($attrs['emit-value'])" :emit-value="nullishToTrue($attrs['emit-value'])"
:map-options="nullishToTrue($attrs['map-options'])" :map-options="nullishToTrue($attrs['map-options'])"
:use-input="nullishToTrue($attrs['use-input'])" :use-input="nullishToTrue($attrs['use-input'])"
@ -324,13 +341,15 @@ function handleKeyDown(event) {
:input-debounce="useURL ? '300' : '0'" :input-debounce="useURL ? '300' : '0'"
:loading="isLoading" :loading="isLoading"
@virtual-scroll="onScroll" @virtual-scroll="onScroll"
@keydown="handleKeyDown"
:data-cy="$attrs.dataCy ?? $attrs.label + '_select'" :data-cy="$attrs.dataCy ?? $attrs.label + '_select'"
:data-url="url"
> >
<template #append> <template #append>
<QIcon <QIcon
v-show="isClearable && value" v-show="isClearable && value"
name="close" name="close"
@click.stop=" @click="
() => { () => {
value = null; value = null;
emit('remove'); emit('remove');
@ -358,6 +377,22 @@ function handleKeyDown(event) {
</div> </div>
<slot v-else :name="slotName" v-bind="slotData ?? {}" :key="slotName" /> <slot v-else :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
</template> </template>
<template #option="{ opt, itemProps }">
<QItem v-bind="itemProps">
<QItemSection v-if="typeof opt !== 'object'"> {{ opt }}</QItemSection>
<QItemSection v-else-if="opt[optionValue] == opt[optionLabel]">
<QItemLabel>{{ opt[optionLabel] }}</QItemLabel>
</QItemSection>
<QItemSection v-else>
<QItemLabel>
{{ opt[optionLabel] }}
</QItemLabel>
<QItemLabel caption v-if="optionCaption !== false">
{{ `#${opt[optionCaption] || opt[optionValue]}` }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</QSelect> </QSelect>
</template> </template>

View File

@ -1,10 +1,10 @@
<script setup> <script setup>
import { ref, computed, watch, onBeforeMount } from 'vue'; import { ref, computed, watch, onBeforeMount, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import SkeletonSummary from 'components/ui/SkeletonSummary.vue'; import SkeletonSummary from 'components/ui/SkeletonSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { isDialogOpened } from 'src/filters'; import { isDialogOpened } from 'src/filters';
import { useStateStore } from 'src/stores/useStateStore';
const props = defineProps({ const props = defineProps({
url: { url: {
@ -40,6 +40,7 @@ const { store } = arrayData;
const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data)); const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
const isLoading = ref(false); const isLoading = ref(false);
const stateStore = useStateStore();
defineExpose({ defineExpose({
entity, entity,
fetch, fetch,
@ -51,6 +52,9 @@ onBeforeMount(async () => {
watch(props, async () => await fetch()); watch(props, async () => await fetch());
}); });
onMounted(() => {
stateStore.rightDrawerChangeValue(false);
});
async function fetch() { async function fetch() {
store.url = props.url; store.url = props.url;
store.filter = props.filter ?? {}; store.filter = props.filter ?? {};
@ -60,7 +64,6 @@ async function fetch() {
isLoading.value = false; isLoading.value = false;
} }
</script> </script>
<template> <template>
<div class="summary container"> <div class="summary container">
<QCard class="cardSummary"> <QCard class="cardSummary">
@ -81,7 +84,7 @@ async function fetch() {
<span v-else></span> <span v-else></span>
</slot> </slot>
<slot name="header" :entity="entity" dense> <slot name="header" :entity="entity" dense>
<VnLv :label="`${entity.id} -`" :value="entity.name" /> {{ entity.id + ' - ' + entity.name }}
</slot> </slot>
<slot name="header-right" :entity="entity"> <slot name="header-right" :entity="entity">
<span></span> <span></span>
@ -94,7 +97,6 @@ async function fetch() {
</QCard> </QCard>
</div> </div>
</template> </template>
<style lang="scss"> <style lang="scss">
.summary.container { .summary.container {
display: flex; display: flex;

View File

@ -16,7 +16,13 @@ const $props = defineProps({
required: false, required: false,
default: 'value', default: 'value',
}, },
columns: {
type: Number,
required: false,
default: null,
},
}); });
const tags = computed(() => { const tags = computed(() => {
return Object.keys($props.item) return Object.keys($props.item)
.filter((i) => i.startsWith(`${$props.tag}`)) .filter((i) => i.startsWith(`${$props.tag}`))
@ -28,10 +34,21 @@ const tags = computed(() => {
return acc; return acc;
}, {}); }, {});
}); });
const columnStyle = computed(() => {
if ($props.columns) {
return {
'grid-template-columns': `repeat(${$props.columns}, 1fr)`,
'max-width': `${$props.columns * 4}rem`,
};
}
return {};
});
</script> </script>
<template> <template>
<div class="fetchedTags"> <div class="fetchedTags">
<div class="wrap"> <div class="wrap" :style="columnStyle">
<div <div
v-for="(val, key) in tags" v-for="(val, key) in tags"
:key="key" :key="key"
@ -39,37 +56,43 @@ const tags = computed(() => {
:title="`${key}: ${val}`" :title="`${key}: ${val}`"
:class="{ empty: !val }" :class="{ empty: !val }"
> >
{{ val }} <span class="text">{{ val }} </span>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.fetchedTags { .fetchedTags {
align-items: center; align-items: center;
.wrap { .wrap {
width: 100%; display: grid;
flex-wrap: wrap;
display: flex;
} }
.inline-tag { .inline-tag {
display: flex;
align-items: center;
justify-content: center;
height: 1rem; height: 1rem;
margin: 0.05rem; margin: 0.05rem;
color: $color-font-secondary; color: var(--vn-label-color);
text-align: center; text-align: center;
font-size: smaller; font-size: smaller;
padding: 1px; padding: 1px;
flex: 1; border: 1px solid var(--vn-label-color);
border: 1px solid $color-spacer;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
min-width: 4rem; min-width: 4rem;
max-width: 4rem; max-width: 4rem;
} }
.text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: smaller;
}
.empty { .empty {
border: 1px solid #2b2b2b; border: 1px solid var(--vn-empty-tag);
} }
} }
</style> </style>

View File

@ -98,6 +98,7 @@ function cancel() {
/> />
<QBtn <QBtn
:label="t('globals.confirm')" :label="t('globals.confirm')"
:title="t('globals.confirm')"
color="primary" color="primary"
:loading="isLoading" :loading="isLoading"
@click="confirm()" @click="confirm()"

View File

@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
import toDate from 'filters/toDate'; import toDate from 'filters/toDate';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue'; import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
const { t } = useI18n(); const { t, te } = useI18n();
const $props = defineProps({ const $props = defineProps({
modelValue: { modelValue: {
type: Object, type: Object,
@ -228,6 +228,14 @@ function sanitizer(params) {
} }
return params; return params;
} }
const getLocale = (label) => {
const param = label.split('.').at(-1);
const globalLocale = `globals.params.${param}`;
if (te(globalLocale)) return t(globalLocale);
else if (te(t(`params.${param}`)));
else return t(`${route.meta.moduleName}.params.${param}`);
};
</script> </script>
<template> <template>
@ -277,7 +285,12 @@ function sanitizer(params) {
@remove="remove(chip.label)" @remove="remove(chip.label)"
data-cy="vnFilterPanelChip" data-cy="vnFilterPanelChip"
> >
<slot name="tags" :tag="chip" :format-fn="formatValue"> <slot
name="tags"
:tag="chip"
:format-fn="formatValue"
:get-locale="getLocale"
>
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ chip.label }}:</strong> <strong>{{ chip.label }}:</strong>
<span>"{{ formatValue(chip.value) }}"</span> <span>"{{ formatValue(chip.value) }}"</span>
@ -290,6 +303,7 @@ function sanitizer(params) {
:params="userParams" :params="userParams"
:tags="customTags" :tags="customTags"
:format-fn="formatValue" :format-fn="formatValue"
:get-locale="getLocale"
:search-fn="search" :search-fn="search"
/> />
</div> </div>
@ -297,7 +311,12 @@ function sanitizer(params) {
<QSeparator /> <QSeparator />
</QList> </QList>
<QList dense class="list q-gutter-y-sm q-mt-sm"> <QList dense class="list q-gutter-y-sm q-mt-sm">
<slot name="body" :params="sanitizer(userParams)" :search-fn="search"></slot> <slot
name="body"
:params="sanitizer(userParams)"
:get-locale="getLocale"
:search-fn="search"
></slot>
</QList> </QList>
</QForm> </QForm>
<QInnerLoading <QInnerLoading

View File

@ -39,7 +39,7 @@ const val = computed(() => $props.value);
<template v-else> <template v-else>
<div v-if="label || $slots.label" class="label"> <div v-if="label || $slots.label" class="label">
<slot name="label"> <slot name="label">
<span>{{ label }}</span> <span style="color: var(--vn-label-color)">{{ label }}</span>
</slot> </slot>
</div> </div>
<div class="value"> <div class="value">

View File

@ -74,6 +74,10 @@ const props = defineProps({
type: Boolean, type: Boolean,
default: false, default: false,
}, },
mapKey: {
type: String,
default: '',
},
}); });
const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']); const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']);
@ -96,6 +100,7 @@ const arrayData = useArrayData(props.dataKey, {
exprBuilder: props.exprBuilder, exprBuilder: props.exprBuilder,
keepOpts: props.keepOpts, keepOpts: props.keepOpts,
searchUrl: props.searchUrl, searchUrl: props.searchUrl,
mapKey: props.mapKey,
}); });
const store = arrayData.store; const store = arrayData.store;

View File

@ -0,0 +1,16 @@
import axios from 'axios';
export async function getExchange(amount, currencyFk, dated, decimalPlaces = 2) {
try {
const { data } = await axios.get('ReferenceRates/findOne', {
params: {
filter: {
fields: ['value'],
where: { currencyFk, dated },
},
},
});
return (amount / data.value).toFixed(decimalPlaces);
} catch (e) {
return null;
}
}

View File

@ -1,10 +1,10 @@
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
export function getTotal(rows, key, opts = {}) { export function getTotal(rows, key, opts = {}) {
const { currency, cb } = opts; const { currency, cb, decimalPlaces } = opts;
const total = rows.reduce((acc, row) => acc + +(cb ? cb(row) : row[key] || 0), 0); const total = rows.reduce((acc, row) => acc + +(cb ? cb(row) : row[key] || 0), 0);
return currency return currency
? toCurrency(total, currency == 'default' ? undefined : currency) ? toCurrency(total, currency == 'default' ? undefined : currency)
: total; : parseFloat(total).toFixed(decimalPlaces ?? 2);
} }

View File

@ -0,0 +1,4 @@
export function useAccountShortToStandard(val) {
if (!val || !/^\d+(\.\d*)$/.test(val)) return;
return val?.replace('.', '0'.repeat(11 - val.length));
}

View File

@ -49,6 +49,7 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
'exprBuilder', 'exprBuilder',
'searchUrl', 'searchUrl',
'navigate', 'navigate',
'mapKey',
]; ];
if (typeof userOptions === 'object') { if (typeof userOptions === 'object') {
for (const option in userOptions) { for (const option in userOptions) {
@ -119,17 +120,12 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const { limit } = filter; const { limit } = filter;
store.hasMoreData = limit && response.data.length >= limit; store.hasMoreData = limit && response.data.length >= limit;
if (append) { processData(response.data, { map: !!store.mapKey, append });
if (!store.data) store.data = []; if (!append && !isDialogOpened()) updateRouter && updateStateParams();
for (const row of response.data) store.data.push(row);
} else {
store.data = response.data;
if (!isDialogOpened()) updateRouter && updateStateParams();
}
store.isLoading = false; store.isLoading = false;
canceller = null; canceller = null;
return response; return response;
} }
@ -288,6 +284,31 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
router.replace(newUrl); router.replace(newUrl);
} }
function processData(data, { map = true, append = true }) {
if (!append) {
store.data = [];
store.map = new Map();
}
if (!Array.isArray(data)) store.data = data;
else if (!map && append) for (const row of data) store.data.push(row);
else
for (const row of data) {
const key = row[store.mapKey];
const val = { ...row, key };
if (store.map.has(key)) {
const { position } = store.map.get(key);
val.position = position;
store.map.set(key, val);
store.data[position] = val;
} else {
val.position = store.map.size;
store.map.set(key, val);
store.data.push(val);
}
}
}
const totalRows = computed(() => (store.data && store.data.length) || 0); const totalRows = computed(() => (store.data && store.data.length) || 0);
const isLoading = computed(() => store.isLoading || false); const isLoading = computed(() => store.isLoading || false);

View File

@ -11,6 +11,7 @@ body.body--light {
--vn-text-color: var(--font-color); --vn-text-color: var(--font-color);
--vn-label-color: #5f5f5f; --vn-label-color: #5f5f5f;
--vn-accent-color: #e7e3e3; --vn-accent-color: #e7e3e3;
--vn-empty-tag: #acacac;
background-color: var(--vn-page-color); background-color: var(--vn-page-color);
@ -26,6 +27,7 @@ body.body--dark {
--vn-text-color: white; --vn-text-color: white;
--vn-label-color: #a8a8a8; --vn-label-color: #a8a8a8;
--vn-accent-color: #424242; --vn-accent-color: #424242;
--vn-empty-tag: #2d2d2d;
background-color: var(--vn-page-color); background-color: var(--vn-page-color);
} }
@ -240,7 +242,7 @@ input::-webkit-inner-spin-button {
.q-table { .q-table {
th, th,
td { td {
padding: 1px 10px 1px 10px; padding: 1px 3px 1px 3px;
max-width: 130px; max-width: 130px;
div span { div span {
overflow: hidden; overflow: hidden;
@ -296,3 +298,20 @@ input::-webkit-inner-spin-button {
.no-visible { .no-visible {
visibility: hidden; visibility: hidden;
} }
.q-field__inner {
.q-field__control {
min-height: auto !important;
display: flex;
align-items: flex-end;
padding-bottom: 2px;
.q-field__native.row {
min-height: auto !important;
}
}
}
.q-date__header-today {
border-radius: 12px;
border: 1px solid;
box-shadow: 0 4px 6px #00000000;
}

View File

@ -142,7 +142,7 @@ globals:
workCenters: Work centers workCenters: Work centers
modes: Modes modes: Modes
zones: Zones zones: Zones
zonesList: Zones zonesList: List
deliveryDays: Delivery days deliveryDays: Delivery days
upcomingDeliveries: Upcoming deliveries upcomingDeliveries: Upcoming deliveries
role: Role role: Role
@ -333,11 +333,23 @@ globals:
packing: ITP packing: ITP
myTeam: My team myTeam: My team
departmentFk: Department departmentFk: Department
from: From
to: To
supplierFk: Supplier
supplierRef: Supplier ref
serial: Serial
amount: Importe
awbCode: AWB
correctedFk: Rectified
correctingFk: Rectificative
daysOnward: Days onward
countryFk: Country countryFk: Country
companyFk: Company
changePass: Change password changePass: Change password
deleteConfirmTitle: Delete selected elements deleteConfirmTitle: Delete selected elements
changeState: Change state changeState: Change state
raid: 'Raid {daysInForward} days' raid: 'Raid {daysInForward} days'
isVies: Vies
errors: errors:
statusUnauthorized: Access denied statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred statusInternalServerError: An internal server error has ocurred
@ -731,7 +743,6 @@ supplier:
sageTransactionTypeFk: Sage transaction type sageTransactionTypeFk: Sage transaction type
supplierActivityFk: Supplier activity supplierActivityFk: Supplier activity
isTrucker: Trucker isTrucker: Trucker
isVies: Vies
billingData: billingData:
payMethodFk: Billing data payMethodFk: Billing data
payDemFk: Payment deadline payDemFk: Payment deadline

View File

@ -144,7 +144,7 @@ globals:
workCenters: Centros de trabajo workCenters: Centros de trabajo
modes: Modos modes: Modos
zones: Zonas zones: Zonas
zonesList: Zonas zonesList: Listado
deliveryDays: Días de entrega deliveryDays: Días de entrega
upcomingDeliveries: Próximos repartos upcomingDeliveries: Próximos repartos
role: Role role: Role
@ -336,12 +336,22 @@ globals:
SSN: NSS SSN: NSS
fi: NIF fi: NIF
myTeam: Mi equipo myTeam: Mi equipo
from: Desde
to: Hasta
supplierFk: Proveedor
supplierRef: Ref. proveedor
serial: Serie
amount: Importe
awbCode: AWB
daysOnward: Días adelante
packing: ITP packing: ITP
countryFk: País countryFk: País
companyFk: Empresa
changePass: Cambiar contraseña changePass: Cambiar contraseña
deleteConfirmTitle: Eliminar los elementos seleccionados deleteConfirmTitle: Eliminar los elementos seleccionados
changeState: Cambiar estado changeState: Cambiar estado
raid: 'Redada {daysInForward} días' raid: 'Redada {daysInForward} días'
isVies: Vies
errors: errors:
statusUnauthorized: Acceso denegado statusUnauthorized: Acceso denegado
statusInternalServerError: Ha ocurrido un error interno del servidor statusInternalServerError: Ha ocurrido un error interno del servidor
@ -726,7 +736,6 @@ supplier:
sageTransactionTypeFk: Tipo de transacción sage sageTransactionTypeFk: Tipo de transacción sage
supplierActivityFk: Actividad proveedor supplierActivityFk: Actividad proveedor
isTrucker: Transportista isTrucker: Transportista
isVies: Vies
billingData: billingData:
payMethodFk: Forma de pago payMethodFk: Forma de pago
payDemFk: Plazo de pago payDemFk: Plazo de pago

View File

@ -57,6 +57,7 @@ function onFetch(rows, newRows) {
const price = row.quantity * sale.price; const price = row.quantity * sale.price;
const discount = (sale.discount * price) / 100; const discount = (sale.discount * price) / 100;
amountClaimed.value = amountClaimed.value + (price - discount); amountClaimed.value = amountClaimed.value + (price - discount);
} }
} }
@ -207,9 +208,10 @@ async function saveWhenHasChanges() {
selection="multiple" selection="multiple"
v-model:selected="selected" v-model:selected="selected"
:grid="$q.screen.lt.md" :grid="$q.screen.lt.md"
> >
<template #body-cell-claimed="{ row }"> <template #body-cell-claimed="{ row }">
<QTd auto-width align="right" class="text-primary"> <QTd auto-width align="right" class="text-primary shrink">
<QInput <QInput
v-model.number="row.quantity" v-model.number="row.quantity"
type="number" type="number"
@ -220,7 +222,7 @@ async function saveWhenHasChanges() {
</QTd> </QTd>
</template> </template>
<template #body-cell-description="{ row, value }"> <template #body-cell-description="{ row, value }">
<QTd auto-width align="right" class="text-primary"> <QTd auto-width align="right" class="link expand">
{{ value }} {{ value }}
<ItemDescriptorProxy <ItemDescriptorProxy
:id="row.sale.itemFk" :id="row.sale.itemFk"
@ -228,7 +230,7 @@ async function saveWhenHasChanges() {
</QTd> </QTd>
</template> </template>
<template #body-cell-discount="{ row, value, rowIndex }"> <template #body-cell-discount="{ row, value, rowIndex }">
<QTd auto-width align="right" class="text-primary"> <QTd auto-width align="right" class="text-primary shrink">
{{ value }} {{ value }}
<VnDiscount <VnDiscount
:quantity="row.quantity" :quantity="row.quantity"
@ -264,7 +266,7 @@ async function saveWhenHasChanges() {
</QItemSection> </QItemSection>
<QItemSection side> <QItemSection side>
<template v-if="column.name === 'claimed'"> <template v-if="column.name === 'claimed'">
<QItemLabel class="text-primary"> <QItemLabel class="text-primary shrink">
<QInput <QInput
v-model.number=" v-model.number="
props.row.quantity props.row.quantity
@ -282,7 +284,7 @@ async function saveWhenHasChanges() {
<template <template
v-else-if="column.name === 'discount'" v-else-if="column.name === 'discount'"
> >
<QItemLabel class="text-primary"> <QItemLabel class="text-primary shrink">
{{ column.value }} {{ column.value }}
<VnDiscount <VnDiscount
:quantity="props.row.quantity" :quantity="props.row.quantity"
@ -330,6 +332,7 @@ async function saveWhenHasChanges() {
.grid-style-transition { .grid-style-transition {
transition: transform 0.28s, background-color 0.28s; transition: transform 0.28s, background-color 0.28s;
} }
</style> </style>
<i18n> <i18n>

View File

@ -345,12 +345,9 @@ function claimUrl(section) {
<span v-if="col.name != 'description'">{{ <span v-if="col.name != 'description'">{{
t(col.value) t(col.value)
}}</span> }}</span>
<QBtn <span class="link" v-if="col.name === 'description'">{{
v-if="col.name == 'description'" t(col.value)
flat }}</span>
color="blue"
>{{ col.value }}</QBtn
>
<ItemDescriptorProxy <ItemDescriptorProxy
v-if="col.name == 'description'" v-if="col.name == 'description'"
:id="props.row.sale.itemFk" :id="props.row.sale.itemFk"

View File

@ -105,6 +105,7 @@ const columns = computed(() => [
title: t('components.smartCard.viewSummary'), title: t('components.smartCard.viewSummary'),
icon: 'preview', icon: 'preview',
action: (row) => viewSummary(row.id, ClaimSummary), action: (row) => viewSummary(row.id, ClaimSummary),
isPrimary: true,
}, },
], ],
}, },
@ -135,7 +136,6 @@ const STATE_COLOR = {
:columns="columns" :columns="columns"
redirect="claim" redirect="claim"
:right-search="false" :right-search="false"
auto-load
> >
<template #column-clientFk="{ row }"> <template #column-clientFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>

View File

@ -110,7 +110,7 @@ function handleLocation(data, location) {
<VnRow> <VnRow>
<QCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" /> <QCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" />
<div> <div>
<QCheckbox :label="t('Vies')" v-model="data.isVies" /> <QCheckbox :label="t('globals.isVies')" v-model="data.isVies" />
<QIcon name="info" class="cursor-info q-ml-sm" size="sm"> <QIcon name="info" class="cursor-info q-ml-sm" size="sm">
<QTooltip> <QTooltip>
{{ t('whenActivatingIt') }} {{ t('whenActivatingIt') }}
@ -169,7 +169,6 @@ es:
Active: Activo Active: Activo
Frozen: Congelado Frozen: Congelado
Has to invoice: Factura Has to invoice: Factura
Vies: Vies
Notify by email: Notificar vía e-mail Notify by email: Notificar vía e-mail
Invoice by address: Facturar por consignatario Invoice by address: Facturar por consignatario
Is equalizated: Recargo de equivalencia Is equalizated: Recargo de equivalencia

View File

@ -173,7 +173,7 @@ const sumRisk = ({ clientRisks }) => {
:label="t('customer.summary.notifyByEmail')" :label="t('customer.summary.notifyByEmail')"
:value="entity.isToBeMailed" :value="entity.isToBeMailed"
/> />
<VnLv :label="t('customer.summary.vies')" :value="entity.isVies" /> <VnLv :label="t('globals.isVies')" :value="entity.isVies" />
</VnRow> </VnRow>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">

View File

@ -2,22 +2,21 @@
import { ref, computed, markRaw } from 'vue'; import { ref, computed, markRaw } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { toDate } from 'src/filters';
import RightMenu from 'src/components/common/RightMenu.vue';
import CustomerSummary from './Card/CustomerSummary.vue';
import CustomerFilter from './CustomerFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnLocation from 'src/components/common/VnLocation.vue'; import VnLocation from 'src/components/common/VnLocation.vue';
import VnSearchbar from 'components/ui/VnSearchbar.vue'; import VnSearchbar from 'components/ui/VnSearchbar.vue';
import CustomerSummary from './Card/CustomerSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import { toDate } from 'src/filters';
import CustomerFilter from './CustomerFilter.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue'; import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter(); const router = useRouter();
const tableRef = ref(); const tableRef = ref();
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'left', align: 'left',
@ -263,7 +262,7 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.isVies'), label: t('globals.isVies'),
name: 'isVies', name: 'isVies',
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
@ -405,6 +404,7 @@ function handleLocation(data, location) {
ref="tableRef" ref="tableRef"
data-key="CustomerList" data-key="CustomerList"
url="Clients/filter" url="Clients/filter"
order="id DESC"
:create="{ :create="{
urlCreate: 'Clients/createWithUser', urlCreate: 'Clients/createWithUser',
title: t('globals.pageTitles.customerCreate'), title: t('globals.pageTitles.customerCreate'),
@ -414,11 +414,9 @@ function handleLocation(data, location) {
isEqualizated: false, isEqualizated: false,
}, },
}" }"
order="id DESC"
:columns="columns" :columns="columns"
redirect="customer"
:right-search="false" :right-search="false"
auto-load redirect="customer"
> >
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
<VnSelectWorker <VnSelectWorker
@ -431,7 +429,26 @@ function handleLocation(data, location) {
:id-value="data.salesPersonFk" :id-value="data.salesPersonFk"
emit-value emit-value
auto-load auto-load
/> >
<template #prepend>
<VnAvatar
:worker-id="data.salesPersonFk"
color="primary"
:title="title"
/>
</template>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.name }}</QItemLabel>
<QItemLabel caption
>{{ scope.opt?.nickname }},
{{ scope.opt?.code }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelectWorker>
<VnLocation <VnLocation
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]" :acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
v-model="data.location" v-model="data.location"
@ -452,7 +469,7 @@ function handleLocation(data, location) {
</template> </template>
<i18n> <i18n>
es: es:
Web user: Usuario Web Web user: Usuario web
</i18n> </i18n>
<style lang="scss" scoped> <style lang="scss" scoped>
.col-content { .col-content {

View File

@ -88,7 +88,6 @@ customer:
businessTypeFk: Business type businessTypeFk: Business type
sageTaxTypeFk: Sage tax type sageTaxTypeFk: Sage tax type
sageTransactionTypeFk: Sage tr. type sageTransactionTypeFk: Sage tr. type
isVies: Vies
isTaxDataChecked: Verified data isTaxDataChecked: Verified data
isFreezed: Freezed isFreezed: Freezed
hasToInvoice: Invoice hasToInvoice: Invoice

View File

@ -90,7 +90,6 @@ customer:
businessTypeFk: Tipo de negocio businessTypeFk: Tipo de negocio
sageTaxTypeFk: Tipo de impuesto Sage sageTaxTypeFk: Tipo de impuesto Sage
sageTransactionTypeFk: Tipo tr. sage sageTransactionTypeFk: Tipo tr. sage
isVies: Vies
isTaxDataChecked: Datos comprobados isTaxDataChecked: Datos comprobados
isFreezed: Congelado isFreezed: Congelado
hasToInvoice: Factura hasToInvoice: Factura

View File

@ -1,8 +1,6 @@
<script setup> <script setup>
import { ref } from 'vue'; import { ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { onMounted } from 'vue';
import { useStateStore } from 'stores/useStateStore';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
@ -20,11 +18,6 @@ const props = defineProps({
const currenciesOptions = ref([]); const currenciesOptions = ref([]);
const companiesOptions = ref([]); const companiesOptions = ref([]);
const stateStore = useStateStore();
onMounted(async () => {
stateStore.rightDrawer = true;
});
</script> </script>
<template> <template>

View File

@ -49,8 +49,10 @@ const columns = computed(() => [
align: 'left', align: 'left',
label: t('globals.id'), label: t('globals.id'),
name: 'id', name: 'id',
isTitle: true, isId: true,
cardVisible: true, chip: {
condition: () => true,
},
}, },
{ {
align: 'left', align: 'left',
@ -177,9 +179,6 @@ const columns = computed(() => [
], ],
}, },
]); ]);
onMounted(async () => {
stateStore.rightDrawer = true;
});
</script> </script>
<template> <template>
<VnSearchbar <VnSearchbar
@ -207,7 +206,6 @@ onMounted(async () => {
order="id DESC" order="id DESC"
:columns="columns" :columns="columns"
redirect="entry" redirect="entry"
auto-load
:right-search="false" :right-search="false"
> >
<template #column-status="{ row }"> <template #column-status="{ row }">

View File

@ -116,6 +116,7 @@ function deleteFile(dmsFk) {
<template #form="{ data }"> <template #form="{ data }">
<VnRow> <VnRow>
<VnSelect <VnSelect
:required="true"
:label="t('supplierFk')" :label="t('supplierFk')"
v-model="data.supplierFk" v-model="data.supplierFk"
option-value="id" option-value="id"
@ -244,14 +245,19 @@ function deleteFile(dmsFk) {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelect <VnSelect
:required="true"
:is-clearable="false"
:label="t('Currency')" :label="t('Currency')"
v-model="data.currencyFk" v-model="data.currencyFk"
:options="currencies" :options="currencies"
option-value="id" option-value="id"
option-label="code" option-label="code"
sort-by="id"
/> />
<VnSelect <VnSelect
:required="true"
:is-clearable="false"
v-if="companiesRef" v-if="companiesRef"
:label="t('Company')" :label="t('Company')"
v-model="data.companyFk" v-model="data.companyFk"
@ -262,7 +268,7 @@ function deleteFile(dmsFk) {
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelect <VnSelect
:label="t('invoiceIn.summary.sage')" :label="t('InvoiceIn.summary.sage')"
v-model="data.withholdingSageFk" v-model="data.withholdingSageFk"
:options="sageWithholdings" :options="sageWithholdings"
option-value="id" option-value="id"

View File

@ -1,23 +1,21 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed, capitalize } from 'vue';
import { useRouter } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useCapitalize } from 'src/composables/useCapitalize';
import CrudModel from 'src/components/CrudModel.vue'; import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
const { push, currentRoute } = useRouter(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const invoiceId = +currentRoute.value.params.id;
const arrayData = useArrayData(); const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data); const invoiceIn = computed(() => arrayData.store.data);
const invoiceInCorrectionRef = ref(); const invoiceInCorrectionRef = ref();
const filter = { const filter = {
include: { relation: 'invoiceIn' }, include: { relation: 'invoiceIn' },
where: { correctingFk: invoiceId }, where: { correctingFk: route.params.id },
}; };
const columns = computed(() => [ const columns = computed(() => [
{ {
@ -31,7 +29,7 @@ const columns = computed(() => [
}, },
{ {
name: 'type', name: 'type',
label: useCapitalize(t('globals.type')), label: capitalize(t('globals.type')),
field: (row) => row.cplusRectificationTypeFk, field: (row) => row.cplusRectificationTypeFk,
options: cplusRectificationTypes.value, options: cplusRectificationTypes.value,
model: 'cplusRectificationTypeFk', model: 'cplusRectificationTypeFk',
@ -43,10 +41,10 @@ const columns = computed(() => [
}, },
{ {
name: 'class', name: 'class',
label: useCapitalize(t('globals.class')), label: capitalize(t('globals.class')),
field: (row) => row.siiTypeInvoiceOutFk, field: (row) => row.siiTypeInvoiceInFk,
options: siiTypeInvoiceOuts.value, options: siiTypeInvoiceIns.value,
model: 'siiTypeInvoiceOutFk', model: 'siiTypeInvoiceInFk',
optionValue: 'id', optionValue: 'id',
optionLabel: 'code', optionLabel: 'code',
sortable: true, sortable: true,
@ -55,7 +53,7 @@ const columns = computed(() => [
}, },
{ {
name: 'reason', name: 'reason',
label: useCapitalize(t('globals.reason')), label: capitalize(t('globals.reason')),
field: (row) => row.invoiceCorrectionTypeFk, field: (row) => row.invoiceCorrectionTypeFk,
options: invoiceCorrectionTypes.value, options: invoiceCorrectionTypes.value,
model: 'invoiceCorrectionTypeFk', model: 'invoiceCorrectionTypeFk',
@ -67,13 +65,10 @@ const columns = computed(() => [
}, },
]); ]);
const cplusRectificationTypes = ref([]); const cplusRectificationTypes = ref([]);
const siiTypeInvoiceOuts = ref([]); const siiTypeInvoiceIns = ref([]);
const invoiceCorrectionTypes = ref([]); const invoiceCorrectionTypes = ref([]);
const rowsSelected = ref([]);
const requiredFieldRule = (val) => val || t('globals.requiredField'); const requiredFieldRule = (val) => val || t('globals.requiredField');
const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`);
</script> </script>
<template> <template>
<FetchData <FetchData
@ -82,9 +77,9 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
auto-load auto-load
/> />
<FetchData <FetchData
url="SiiTypeInvoiceOuts" url="SiiTypeInvoiceIns"
:where="{ code: { like: 'R%' } }" :where="{ code: { like: 'R%' } }"
@on-fetch="(data) => (siiTypeInvoiceOuts = data)" @on-fetch="(data) => (siiTypeInvoiceIns = data)"
auto-load auto-load
/> />
<FetchData <FetchData
@ -99,17 +94,14 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
url="InvoiceInCorrections" url="InvoiceInCorrections"
:filter="filter" :filter="filter"
auto-load auto-load
v-model:selected="rowsSelected"
primary-key="correctingFk" primary-key="correctingFk"
@save-changes="onSave" :default-remove="false"
> >
<template #body="{ rows }"> <template #body="{ rows }">
<QTable <QTable
v-model:selected="rowsSelected"
:columns="columns" :columns="columns"
:rows="rows" :rows="rows"
row-key="$index" row-key="$index"
selection="single"
:grid="$q.screen.lt.sm" :grid="$q.screen.lt.sm"
:pagination="{ rowsPerPage: 0 }" :pagination="{ rowsPerPage: 0 }"
> >
@ -121,8 +113,17 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:options="col.options" :options="col.options"
:option-value="col.optionValue" :option-value="col.optionValue"
:option-label="col.optionLabel" :option-label="col.optionLabel"
:readonly="row.invoiceIn.isBooked" :disable="row.invoiceIn.isBooked"
/> :filter-options="['description']"
>
<template #option="{ opt, itemProps }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel>{{ opt.description }}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QTd> </QTd>
</template> </template>
<template #body-cell-class="{ row, col }"> <template #body-cell-class="{ row, col }">
@ -134,8 +135,20 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:option-value="col.optionValue" :option-value="col.optionValue"
:option-label="col.optionLabel" :option-label="col.optionLabel"
:rules="[requiredFieldRule]" :rules="[requiredFieldRule]"
:readonly="row.invoiceIn.isBooked" :filter-options="['code', 'description']"
/> :disable="row.invoiceIn.isBooked"
>
<template #option="{ opt, itemProps }">
<QItem v-bind="itemProps">
<QItemSection>
<QItemLabel
>{{ opt.code }} -
{{ opt.description }}</QItemLabel
>
</QItemSection>
</QItem>
</template>
</VnSelect>
</QTd> </QTd>
</template> </template>
<template #body-cell-reason="{ row, col }"> <template #body-cell-reason="{ row, col }">
@ -147,7 +160,7 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
:option-value="col.optionValue" :option-value="col.optionValue"
:option-label="col.optionLabel" :option-label="col.optionLabel"
:rules="[requiredFieldRule]" :rules="[requiredFieldRule]"
:readonly="row.invoiceIn.isBooked" :disable="row.invoiceIn.isBooked"
/> />
</QTd> </QTd>
</template> </template>
@ -155,7 +168,6 @@ const onSave = (data) => data.deletes && push(`/invoice-in/${invoiceId}/summary`
</template> </template>
</CrudModel> </CrudModel>
</template> </template>
<style lang="scss" scoped></style>
<i18n> <i18n>
es: es:
Original invoice: Factura origen Original invoice: Factura origen

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, reactive, computed, onBeforeMount } from 'vue'; import { ref, reactive, computed, onBeforeMount, capitalize } from 'vue';
import { useRouter, onBeforeRouteUpdate } from 'vue-router'; import { useRouter, onBeforeRouteUpdate } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -15,7 +15,6 @@ import FetchData from 'src/components/FetchData.vue';
import SendEmailDialog from 'components/common/SendEmailDialog.vue'; import SendEmailDialog from 'components/common/SendEmailDialog.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import { useCapitalize } from 'src/composables/useCapitalize';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue'; import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
import InvoiceInToBook from '../InvoiceInToBook.vue'; import InvoiceInToBook from '../InvoiceInToBook.vue';
@ -37,7 +36,7 @@ const totalAmount = ref();
const currentAction = ref(); const currentAction = ref();
const config = ref(); const config = ref();
const cplusRectificationTypes = ref([]); const cplusRectificationTypes = ref([]);
const siiTypeInvoiceOuts = ref([]); const siiTypeInvoiceIns = ref([]);
const invoiceCorrectionTypes = ref([]); const invoiceCorrectionTypes = ref([]);
const actions = { const actions = {
unbook: { unbook: {
@ -91,7 +90,7 @@ const routes = reactive({
return { return {
name: 'InvoiceInList', name: 'InvoiceInList',
query: { query: {
params: JSON.stringify({ supplierFk: id }), table: JSON.stringify({ supplierFk: id }),
}, },
}; };
}, },
@ -100,7 +99,7 @@ const routes = reactive({
return { return {
name: 'InvoiceInList', name: 'InvoiceInList',
query: { query: {
params: JSON.stringify({ correctedFk: entityId.value }), table: JSON.stringify({ correctedFk: entityId.value }),
}, },
}; };
} }
@ -119,21 +118,21 @@ const routes = reactive({
const correctionFormData = reactive({ const correctionFormData = reactive({
invoiceReason: 2, invoiceReason: 2,
invoiceType: 2, invoiceType: 2,
invoiceClass: 6, invoiceClass: 8,
}); });
const isNotFilled = computed(() => Object.values(correctionFormData).includes(null)); const isNotFilled = computed(() => Object.values(correctionFormData).includes(null));
onBeforeMount(async () => { onBeforeMount(async () => {
await setInvoiceCorrection(entityId.value); await setInvoiceCorrection(entityId.value);
const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`); const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`);
totalAmount.value = data.totalDueDay; totalAmount.value = data.totalTaxableBase;
}); });
onBeforeRouteUpdate(async (to, from) => { onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) { if (to.params.id !== from.params.id) {
await setInvoiceCorrection(to.params.id); await setInvoiceCorrection(to.params.id);
const { data } = await axios.get(`InvoiceIns/${to.params.id}/getTotals`); const { data } = await axios.get(`InvoiceIns/${to.params.id}/getTotals`);
totalAmount.value = data.totalDueDay; totalAmount.value = data.totalTaxableBase;
} }
}); });
@ -207,7 +206,8 @@ const isAgricultural = () => {
}; };
function showPdfInvoice() { function showPdfInvoice() {
if (isAgricultural()) openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`); if (isAgricultural())
openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`, null, '_blank');
} }
function sendPdfInvoiceConfirmation() { function sendPdfInvoiceConfirmation() {
@ -262,9 +262,9 @@ const createInvoiceInCorrection = async () => {
auto-load auto-load
/> />
<FetchData <FetchData
url="SiiTypeInvoiceOuts" url="siiTypeInvoiceIns"
:where="{ code: { like: 'R%' } }" :where="{ code: { like: 'R%' } }"
@on-fetch="(data) => (siiTypeInvoiceOuts = data)" @on-fetch="(data) => (siiTypeInvoiceIns = data)"
auto-load auto-load
/> />
<FetchData <FetchData
@ -355,10 +355,13 @@ const createInvoiceInCorrection = async () => {
</QItem> </QItem>
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('invoiceIn.list.issued')" :value="toDate(entity.issued)" /> <VnLv :label="t('InvoiceIn.list.issued')" :value="toDate(entity.issued)" />
<VnLv :label="t('invoiceIn.summary.booked')" :value="toDate(entity.booked)" /> <VnLv
<VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" /> :label="t('InvoiceIn.summary.bookedDate')"
<VnLv :label="t('invoiceIn.list.supplier')"> :value="toDate(entity.booked)"
/>
<VnLv :label="t('InvoiceIn.list.amount')" :value="toCurrency(totalAmount)" />
<VnLv :label="t('InvoiceIn.list.supplier')">
<template #value> <template #value>
<span class="link"> <span class="link">
{{ entity?.supplier?.nickname }} {{ entity?.supplier?.nickname }}
@ -375,7 +378,7 @@ const createInvoiceInCorrection = async () => {
color="primary" color="primary"
:to="routes.getSupplier(entity.supplierFk)" :to="routes.getSupplier(entity.supplierFk)"
> >
<QTooltip>{{ t('invoiceIn.list.supplier') }}</QTooltip> <QTooltip>{{ t('InvoiceIn.list.supplier') }}</QTooltip>
</QBtn> </QBtn>
<QBtn <QBtn
size="md" size="md"
@ -391,7 +394,7 @@ const createInvoiceInCorrection = async () => {
color="primary" color="primary"
:to="routes.getTickets(entity.supplierFk)" :to="routes.getTickets(entity.supplierFk)"
> >
<QTooltip>{{ t('invoiceOut.card.ticketList') }}</QTooltip> <QTooltip>{{ t('InvoiceIn.descriptor.ticketList') }}</QTooltip>
</QBtn> </QBtn>
<QBtn <QBtn
v-if=" v-if="
@ -435,9 +438,9 @@ const createInvoiceInCorrection = async () => {
readonly readonly
/> />
<VnSelect <VnSelect
:label="`${useCapitalize(t('globals.class'))}`" :label="`${capitalize(t('globals.class'))}`"
v-model="correctionFormData.invoiceClass" v-model="correctionFormData.invoiceClass"
:options="siiTypeInvoiceOuts" :options="siiTypeInvoiceIns"
option-value="id" option-value="id"
option-label="code" option-label="code"
:required="true" :required="true"
@ -445,15 +448,27 @@ const createInvoiceInCorrection = async () => {
</QItemSection> </QItemSection>
<QItemSection> <QItemSection>
<VnSelect <VnSelect
:label="`${useCapitalize(t('globals.type'))}`" :label="`${capitalize(t('globals.type'))}`"
v-model="correctionFormData.invoiceType" v-model="correctionFormData.invoiceType"
:options="cplusRectificationTypes" :options="cplusRectificationTypes"
option-value="id" option-value="id"
option-label="description" option-label="description"
:required="true" :required="true"
/> >
<template #option="{ opt }">
<QItem>
<QItemSection>
<QItemLabel
>{{ opt.code }} -
{{ opt.description }}</QItemLabel
>
</QItemSection>
</QItem>
<div></div>
</template>
</VnSelect>
<VnSelect <VnSelect
:label="`${useCapitalize(t('globals.reason'))}`" :label="`${capitalize(t('globals.reason'))}`"
v-model="correctionFormData.invoiceReason" v-model="correctionFormData.invoiceReason"
:options="invoiceCorrectionTypes" :options="invoiceCorrectionTypes"
option-value="id" option-value="id"

View File

@ -25,6 +25,7 @@ const banks = ref([]);
const invoiceInFormRef = ref(); const invoiceInFormRef = ref();
const invoiceId = +route.params.id; const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } }; const filter = { where: { invoiceInFk: invoiceId } };
const areRows = ref(false);
const columns = computed(() => [ const columns = computed(() => [
{ {
@ -143,8 +144,6 @@ async function insert() {
}" }"
:disable="!isNotEuro(currency)" :disable="!isNotEuro(currency)"
v-model="row.foreignValue" v-model="row.foreignValue"
clearable
clear-icon="close"
/> />
</QTd> </QTd>
</template> </template>
@ -230,7 +229,14 @@ async function insert() {
</template> </template>
</CrudModel> </CrudModel>
<QPageSticky position="bottom-right" :offset="[25, 25]"> <QPageSticky position="bottom-right" :offset="[25, 25]">
<QBtn color="primary" icon="add" shortcut="+" size="lg" round @click="insert" /> <QBtn
color="primary"
icon="add"
shortcut="+"
size="lg"
round
@click="!areRows ? insert() : invoiceInFormRef.insert()"
/>
</QPageSticky> </QPageSticky>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@ -26,7 +26,7 @@ const columns = computed(() => [
options: intrastats.value, options: intrastats.value,
model: 'intrastatFk', model: 'intrastatFk',
optionValue: 'id', optionValue: 'id',
optionLabel: 'description', optionLabel: (row) => `${row.id}: ${row.description}`,
sortable: true, sortable: true,
tabIndex: 1, tabIndex: 1,
align: 'left', align: 'left',
@ -68,12 +68,6 @@ const columns = computed(() => [
align: 'left', align: 'left',
}, },
]); ]);
const formatOpt = (row, { model, options }, prop) => {
const obj = row[model];
const option = options.find(({ id }) => id == obj);
return option ? `${obj}:${option[prop]}` : '';
};
</script> </script>
<template> <template>
<FetchData <FetchData
@ -118,12 +112,10 @@ const formatOpt = (row, { model, options }, prop) => {
<VnSelect <VnSelect
v-model="row[col.model]" v-model="row[col.model]"
:options="col.options" :options="col.options"
option-value="id" :option-value="col.optionValue"
option-label="description" :option-label="col.optionLabel"
:filter-options="['id', 'description']" :filter-options="['id', 'description']"
:hide-selected="false" data-cy="intrastat-code"
:fill-input="false"
:display-value="formatOpt(row, col, 'description')"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -138,8 +130,8 @@ const formatOpt = (row, { model, options }, prop) => {
<VnSelect <VnSelect
v-model="row[col.model]" v-model="row[col.model]"
:options="col.options" :options="col.options"
option-value="id" :option-value="col.optionValue"
option-label="code" :option-label="col.optionLabel"
/> />
</QTd> </QTd>
</template> </template>
@ -154,7 +146,7 @@ const formatOpt = (row, { model, options }, prop) => {
{{ getTotal(rows, 'net') }} {{ getTotal(rows, 'net') }}
</QTd> </QTd>
<QTd> <QTd>
{{ getTotal(rows, 'stems') }} {{ getTotal(rows, 'stems', { decimalPlaces: 0 }) }}
</QTd> </QTd>
<QTd /> <QTd />
</QTr> </QTr>
@ -174,7 +166,9 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['intrastatFk']" v-model="props.row['intrastatFk']"
:options="intrastats" :options="intrastats"
option-value="id" option-value="id"
option-label="description" :option-label="
(row) => `${row.id}:${row.description}`
"
:filter-options="['id', 'description']" :filter-options="['id', 'description']"
> >
<template #option="scope"> <template #option="scope">
@ -248,11 +242,6 @@ const formatOpt = (row, { model, options }, prop) => {
} }
} }
</style> </style>
<style lang="scss" scoped>
:deep(.q-table tr .q-td:nth-child(2) input) {
display: none;
}
</style>
<i18n> <i18n>
en: en:
amount: Amount amount: Amount
@ -261,7 +250,7 @@ const formatOpt = (row, { model, options }, prop) => {
country: Country country: Country
es: es:
Code: Código Code: Código
amount: Cantidad amount: Valor mercancía
net: Neto net: Neto
stems: Tallos stems: Tallos
country: País country: País

View File

@ -26,14 +26,14 @@ const intrastatTotals = ref({ amount: 0, net: 0, stems: 0 });
const vatColumns = ref([ const vatColumns = ref([
{ {
name: 'expense', name: 'expense',
label: 'invoiceIn.summary.expense', label: 'InvoiceIn.summary.expense',
field: (row) => row.expenseFk, field: (row) => row.expenseFk,
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{ {
name: 'landed', name: 'landed',
label: 'invoiceIn.summary.taxableBase', label: 'InvoiceIn.summary.taxableBase',
field: (row) => row.taxableBase, field: (row) => row.taxableBase,
format: (value) => toCurrency(value), format: (value) => toCurrency(value),
sortable: true, sortable: true,
@ -41,7 +41,7 @@ const vatColumns = ref([
}, },
{ {
name: 'vat', name: 'vat',
label: 'invoiceIn.summary.sageVat', label: 'InvoiceIn.summary.sageVat',
field: (row) => { field: (row) => {
if (row.taxTypeSage) return `#${row.taxTypeSage.id} : ${row.taxTypeSage.vat}`; if (row.taxTypeSage) return `#${row.taxTypeSage.id} : ${row.taxTypeSage.vat}`;
}, },
@ -51,7 +51,7 @@ const vatColumns = ref([
}, },
{ {
name: 'transaction', name: 'transaction',
label: 'invoiceIn.summary.sageTransaction', label: 'InvoiceIn.summary.sageTransaction',
field: (row) => { field: (row) => {
if (row.transactionTypeSage) if (row.transactionTypeSage)
return `#${row.transactionTypeSage.id} : ${row.transactionTypeSage?.transaction}`; return `#${row.transactionTypeSage.id} : ${row.transactionTypeSage?.transaction}`;
@ -62,7 +62,7 @@ const vatColumns = ref([
}, },
{ {
name: 'rate', name: 'rate',
label: 'invoiceIn.summary.rate', label: 'InvoiceIn.summary.rate',
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate), field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
format: (value) => toCurrency(value), format: (value) => toCurrency(value),
sortable: true, sortable: true,
@ -70,7 +70,7 @@ const vatColumns = ref([
}, },
{ {
name: 'currency', name: 'currency',
label: 'invoiceIn.summary.currency', label: 'InvoiceIn.summary.currency',
field: (row) => row.foreignValue, field: (row) => row.foreignValue,
format: (val) => val && toCurrency(val, currency.value), format: (val) => val && toCurrency(val, currency.value),
sortable: true, sortable: true,
@ -81,21 +81,21 @@ const vatColumns = ref([
const dueDayColumns = ref([ const dueDayColumns = ref([
{ {
name: 'date', name: 'date',
label: 'invoiceIn.summary.dueDay', label: 'InvoiceIn.summary.dueDay',
field: (row) => toDate(row.dueDated), field: (row) => toDate(row.dueDated),
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{ {
name: 'bank', name: 'bank',
label: 'invoiceIn.summary.bank', label: 'InvoiceIn.summary.bank',
field: (row) => row.bank.bank, field: (row) => row.bank.bank,
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{ {
name: 'amount', name: 'amount',
label: 'invoiceIn.list.amount', label: 'InvoiceIn.list.amount',
field: (row) => row.amount, field: (row) => row.amount,
format: (value) => toCurrency(value), format: (value) => toCurrency(value),
sortable: true, sortable: true,
@ -103,7 +103,7 @@ const dueDayColumns = ref([
}, },
{ {
name: 'landed', name: 'landed',
label: 'invoiceIn.summary.foreignValue', label: 'InvoiceIn.summary.foreignValue',
field: (row) => row.foreignValue, field: (row) => row.foreignValue,
format: (val) => val && toCurrency(val, currency.value), format: (val) => val && toCurrency(val, currency.value),
sortable: true, sortable: true,
@ -114,7 +114,7 @@ const dueDayColumns = ref([
const intrastatColumns = ref([ const intrastatColumns = ref([
{ {
name: 'code', name: 'code',
label: 'invoiceIn.summary.code', label: 'InvoiceIn.summary.code',
field: (row) => { field: (row) => {
return `${row.intrastat.id}: ${row.intrastat?.description}`; return `${row.intrastat.id}: ${row.intrastat?.description}`;
}, },
@ -123,21 +123,21 @@ const intrastatColumns = ref([
}, },
{ {
name: 'amount', name: 'amount',
label: 'invoiceIn.list.amount', label: 'InvoiceIn.list.amount',
field: (row) => toCurrency(row.amount), field: (row) => toCurrency(row.amount),
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{ {
name: 'net', name: 'net',
label: 'invoiceIn.summary.net', label: 'InvoiceIn.summary.net',
field: (row) => row.net, field: (row) => row.net,
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{ {
name: 'stems', name: 'stems',
label: 'invoiceIn.summary.stems', label: 'InvoiceIn.summary.stems',
field: (row) => row.stems, field: (row) => row.stems,
format: (value) => value, format: (value) => value,
sortable: true, sortable: true,
@ -145,7 +145,7 @@ const intrastatColumns = ref([
}, },
{ {
name: 'landed', name: 'landed',
label: 'invoiceIn.summary.country', label: 'InvoiceIn.summary.country',
field: (row) => row.country?.code, field: (row) => row.country?.code,
format: (value) => value, format: (value) => value,
sortable: true, sortable: true,
@ -210,7 +210,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
/> />
</QCardSection> </QCardSection>
<VnLv <VnLv
:label="t('invoiceIn.list.supplier')" :label="t('InvoiceIn.list.supplier')"
:value="entity.supplier?.name" :value="entity.supplier?.name"
> >
<template #value> <template #value>
@ -221,14 +221,18 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</template> </template>
</VnLv> </VnLv>
<VnLv <VnLv
:label="t('invoiceIn.list.supplierRef')" :label="t('InvoiceIn.list.supplierRef')"
:value="entity.supplierRef" :value="entity.supplierRef"
/> />
<VnLv <VnLv
:label="t('invoiceIn.summary.currency')" :label="t('InvoiceIn.summary.currency')"
:value="entity.currency?.code" :value="entity.currency?.code"
/> />
<VnLv :label="t('invoiceIn.serial')" :value="`${entity.serial}`" /> <VnLv :label="t('InvoiceIn.serial')" :value="`${entity.serial}`" />
<VnLv
:label="t('globals.country')"
:value="entity.supplier?.country?.code"
/>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
@ -239,21 +243,22 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</QCardSection> </QCardSection>
<VnLv <VnLv
:ellipsis-value="false" :ellipsis-value="false"
:label="t('invoiceIn.summary.issued')" :label="t('InvoiceIn.summary.issued')"
:value="toDate(entity.issued)" :value="toDate(entity.issued)"
/> />
<VnLv <VnLv
:label="t('invoiceIn.summary.operated')" :label="t('InvoiceIn.summary.operated')"
:value="toDate(entity.operated)" :value="toDate(entity.operated)"
/> />
<VnLv <VnLv
:label="t('invoiceIn.summary.bookEntried')" :label="t('InvoiceIn.summary.bookEntried')"
:value="toDate(entity.bookEntried)" :value="toDate(entity.bookEntried)"
/> />
<VnLv <VnLv
:label="t('invoiceIn.summary.bookedDate')" :label="t('InvoiceIn.summary.bookedDate')"
:value="toDate(entity.booked)" :value="toDate(entity.booked)"
/> />
<VnLv :label="t('globals.isVies')" :value="entity.supplier?.isVies" />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
@ -263,18 +268,18 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
/> />
</QCardSection> </QCardSection>
<VnLv <VnLv
:label="t('invoiceIn.summary.sage')" :label="t('InvoiceIn.summary.sage')"
:value="entity.sageWithholding?.withholding" :value="entity.sageWithholding?.withholding"
/> />
<VnLv <VnLv
:label="t('invoiceIn.summary.vat')" :label="t('InvoiceIn.summary.vat')"
:value="entity.expenseDeductible?.name" :value="entity.expenseDeductible?.name"
/> />
<VnLv <VnLv
:label="t('invoiceIn.card.company')" :label="t('InvoiceIn.card.company')"
:value="entity.company?.code" :value="entity.company?.code"
/> />
<VnLv :label="t('invoiceIn.isBooked')" :value="invoiceIn?.isBooked" /> <VnLv :label="t('InvoiceIn.isBooked')" :value="invoiceIn?.isBooked" />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
@ -285,11 +290,11 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</QCardSection> </QCardSection>
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
<VnLv <VnLv
:label="t('invoiceIn.summary.taxableBase')" :label="t('InvoiceIn.summary.taxableBase')"
:value="toCurrency(entity.totals.totalTaxableBase)" :value="toCurrency(entity.totals.totalTaxableBase)"
/> />
<VnLv label="Total" :value="toCurrency(entity.totals.totalVat)" /> <VnLv label="Total" :value="toCurrency(entity.totals.totalVat)" />
<VnLv :label="t('invoiceIn.summary.dueTotal')"> <VnLv :label="t('InvoiceIn.summary.dueTotal')">
<template #value> <template #value>
<QChip <QChip
dense dense
@ -297,8 +302,8 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
:color="amountsNotMatch ? 'negative' : 'transparent'" :color="amountsNotMatch ? 'negative' : 'transparent'"
:title=" :title="
amountsNotMatch amountsNotMatch
? t('invoiceIn.summary.noMatch') ? t('InvoiceIn.summary.noMatch')
: t('invoiceIn.summary.dueTotal') : t('InvoiceIn.summary.dueTotal')
" "
> >
{{ toCurrency(entity.totals.totalDueDay) }} {{ toCurrency(entity.totals.totalDueDay) }}
@ -309,7 +314,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</QCard> </QCard>
<!--Vat--> <!--Vat-->
<QCard v-if="entity.invoiceInTax.length" class="vat"> <QCard v-if="entity.invoiceInTax.length" class="vat">
<VnTitle :url="getLink('vat')" :text="t('invoiceIn.card.vat')" /> <VnTitle :url="getLink('vat')" :text="t('InvoiceIn.card.vat')" />
<QTable <QTable
:columns="vatColumns" :columns="vatColumns"
:rows="entity.invoiceInTax" :rows="entity.invoiceInTax"
@ -357,7 +362,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
</QCard> </QCard>
<!--Due Day--> <!--Due Day-->
<QCard v-if="entity.invoiceInDueDay.length" class="due-day"> <QCard v-if="entity.invoiceInDueDay.length" class="due-day">
<VnTitle :url="getLink('due-day')" :text="t('invoiceIn.card.dueDay')" /> <VnTitle :url="getLink('due-day')" :text="t('InvoiceIn.card.dueDay')" />
<QTable :columns="dueDayColumns" :rows="entity.invoiceInDueDay" flat> <QTable :columns="dueDayColumns" :rows="entity.invoiceInDueDay" flat>
<template #header="dueDayProps"> <template #header="dueDayProps">
<QTr :props="dueDayProps" class="bg"> <QTr :props="dueDayProps" class="bg">
@ -395,7 +400,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
<QCard v-if="entity.invoiceInIntrastat.length"> <QCard v-if="entity.invoiceInIntrastat.length">
<VnTitle <VnTitle
:url="getLink('intrastat')" :url="getLink('intrastat')"
:text="t('invoiceIn.card.intrastat')" :text="t('InvoiceIn.card.intrastat')"
/> />
<QTable <QTable
:columns="intrastatColumns" :columns="intrastatColumns"

View File

@ -11,12 +11,14 @@ import CrudModel from 'src/components/CrudModel.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue'; import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
import CreateNewExpenseForm from 'src/components/CreateNewExpenseForm.vue'; import CreateNewExpenseForm from 'src/components/CreateNewExpenseForm.vue';
import { getExchange } from 'src/composables/getExchange';
import { useAccountShortToStandard } from 'src/composables/useAccountShortToStandard';
const { t } = useI18n(); const { t } = useI18n();
const arrayData = useArrayData(); const arrayData = useArrayData();
const route = useRoute();
const invoiceIn = computed(() => arrayData.store.data); const invoiceIn = computed(() => arrayData.store.data);
const invoiceId = +useRoute().params.id;
const currency = computed(() => invoiceIn.value?.currency?.code); const currency = computed(() => invoiceIn.value?.currency?.code);
const expenses = ref([]); const expenses = ref([]);
const sageTaxTypes = ref([]); const sageTaxTypes = ref([]);
@ -39,9 +41,8 @@ const columns = computed(() => [
options: expenses.value, options: expenses.value,
model: 'expenseFk', model: 'expenseFk',
optionValue: 'id', optionValue: 'id',
optionLabel: 'id', optionLabel: (row) => `${row.id}: ${row.name}`,
sortable: true, sortable: true,
tabIndex: 1,
align: 'left', align: 'left',
}, },
{ {
@ -50,7 +51,6 @@ const columns = computed(() => [
field: (row) => row.taxableBase, field: (row) => row.taxableBase,
model: 'taxableBase', model: 'taxableBase',
sortable: true, sortable: true,
tabIndex: 2,
align: 'left', align: 'left',
}, },
{ {
@ -60,9 +60,8 @@ const columns = computed(() => [
options: sageTaxTypes.value, options: sageTaxTypes.value,
model: 'taxTypeSageFk', model: 'taxTypeSageFk',
optionValue: 'id', optionValue: 'id',
optionLabel: 'id', optionLabel: (row) => `${row.id}: ${row.vat}`,
sortable: true, sortable: true,
tabindex: 3,
align: 'left', align: 'left',
}, },
{ {
@ -72,16 +71,14 @@ const columns = computed(() => [
options: sageTransactionTypes.value, options: sageTransactionTypes.value,
model: 'transactionTypeSageFk', model: 'transactionTypeSageFk',
optionValue: 'id', optionValue: 'id',
optionLabel: 'id', optionLabel: (row) => `${row.id}: ${row.transaction}`,
sortable: true, sortable: true,
tabIndex: 4,
align: 'left', align: 'left',
}, },
{ {
name: 'rate', name: 'rate',
label: t('Rate'), label: t('Rate'),
sortable: true, sortable: true,
tabIndex: 5,
field: (row) => taxRate(row, row.taxTypeSageFk), field: (row) => taxRate(row, row.taxTypeSageFk),
align: 'left', align: 'left',
}, },
@ -89,7 +86,6 @@ const columns = computed(() => [
name: 'foreignvalue', name: 'foreignvalue',
label: t('Foreign value'), label: t('Foreign value'),
sortable: true, sortable: true,
tabIndex: 6,
field: (row) => row.foreignValue, field: (row) => row.foreignValue,
align: 'left', align: 'left',
}, },
@ -106,7 +102,7 @@ const filter = {
'transactionTypeSageFk', 'transactionTypeSageFk',
], ],
where: { where: {
invoiceInFk: invoiceId, invoiceInFk: route.params.id,
}, },
}; };
@ -120,14 +116,20 @@ function taxRate(invoiceInTax) {
const taxTypeSage = taxRateSelection?.rate ?? 0; const taxTypeSage = taxRateSelection?.rate ?? 0;
const taxableBase = invoiceInTax?.taxableBase ?? 0; const taxableBase = invoiceInTax?.taxableBase ?? 0;
return (taxTypeSage / 100) * taxableBase; return ((taxTypeSage / 100) * taxableBase).toFixed(2);
} }
const formatOpt = (row, { model, options }, prop) => { function autocompleteExpense(evt, row, col) {
const obj = row[model]; const val = evt.target.value;
const option = options.find(({ id }) => id == obj); if (!val) return;
return option ? `${obj}:${option[prop]}` : '';
}; const param = isNaN(val) ? row[col.model] : val;
const lookup = expenses.value.find(
({ id }) => id == useAccountShortToStandard(param)
);
if (lookup) row[col.model] = lookup;
}
</script> </script>
<template> <template>
<FetchData <FetchData
@ -148,10 +150,10 @@ const formatOpt = (row, { model, options }, prop) => {
data-key="InvoiceInTaxes" data-key="InvoiceInTaxes"
url="InvoiceInTaxes" url="InvoiceInTaxes"
:filter="filter" :filter="filter"
:data-required="{ invoiceInFk: invoiceId }" :data-required="{ invoiceInFk: $route.params.id }"
auto-load auto-load
v-model:selected="rowsSelected" v-model:selected="rowsSelected"
:go-to="`/invoice-in/${invoiceId}/due-day`" :go-to="`/invoice-in/${$route.params.id}/due-day`"
> >
<template #body="{ rows }"> <template #body="{ rows }">
<QTable <QTable
@ -171,6 +173,7 @@ const formatOpt = (row, { model, options }, prop) => {
:option-label="col.optionLabel" :option-label="col.optionLabel"
:filter-options="['id', 'name']" :filter-options="['id', 'name']"
:tooltip="t('Create a new expense')" :tooltip="t('Create a new expense')"
@keydown.tab="autocompleteExpense($event, row, col)"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -187,13 +190,7 @@ const formatOpt = (row, { model, options }, prop) => {
</template> </template>
<template #body-cell-taxablebase="{ row }"> <template #body-cell-taxablebase="{ row }">
<QTd> <QTd>
{{ currency }}
<VnInputNumber <VnInputNumber
:class="{
'no-pointer-events': isNotEuro(currency),
}"
:disable="isNotEuro(currency)"
label=""
clear-icon="close" clear-icon="close"
v-model="row.taxableBase" v-model="row.taxableBase"
clearable clearable
@ -208,9 +205,7 @@ const formatOpt = (row, { model, options }, prop) => {
:option-value="col.optionValue" :option-value="col.optionValue"
:option-label="col.optionLabel" :option-label="col.optionLabel"
:filter-options="['id', 'vat']" :filter-options="['id', 'vat']"
:hide-selected="false" data-cy="vat-sageiva"
:fill-input="false"
:display-value="formatOpt(row, col, 'vat')"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -233,11 +228,6 @@ const formatOpt = (row, { model, options }, prop) => {
:option-value="col.optionValue" :option-value="col.optionValue"
:option-label="col.optionLabel" :option-label="col.optionLabel"
:filter-options="['id', 'transaction']" :filter-options="['id', 'transaction']"
:autofocus="col.tabIndex == 1"
input-debounce="0"
:hide-selected="false"
:fill-input="false"
:display-value="formatOpt(row, col, 'transaction')"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -262,6 +252,16 @@ const formatOpt = (row, { model, options }, prop) => {
}" }"
:disable="!isNotEuro(currency)" :disable="!isNotEuro(currency)"
v-model="row.foreignValue" v-model="row.foreignValue"
@update:model-value="
async (val) => {
if (!isNotEuro(currency)) return;
row.taxableBase = await getExchange(
val,
row.currencyFk,
invoiceIn.issued
);
}
"
/> />
</QTd> </QTd>
</template> </template>
@ -305,7 +305,7 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['expenseFk']" v-model="props.row['expenseFk']"
:options="expenses" :options="expenses"
option-value="id" option-value="id"
option-label="name" :option-label="(row) => `${row.id}:${row.name}`"
:filter-options="['id', 'name']" :filter-options="['id', 'name']"
:tooltip="t('Create a new expense')" :tooltip="t('Create a new expense')"
> >
@ -339,7 +339,7 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['taxTypeSageFk']" v-model="props.row['taxTypeSageFk']"
:options="sageTaxTypes" :options="sageTaxTypes"
option-value="id" option-value="id"
option-label="vat" :option-label="(row) => `${row.id}:${row.vat}`"
:filter-options="['id', 'vat']" :filter-options="['id', 'vat']"
> >
<template #option="scope"> <template #option="scope">
@ -362,7 +362,9 @@ const formatOpt = (row, { model, options }, prop) => {
v-model="props.row['transactionTypeSageFk']" v-model="props.row['transactionTypeSageFk']"
:options="sageTransactionTypes" :options="sageTransactionTypes"
option-value="id" option-value="id"
option-label="transaction" :option-label="
(row) => `${row.id}:${row.transaction}`
"
:filter-options="['id', 'transaction']" :filter-options="['id', 'transaction']"
> >
<template #option="scope"> <template #option="scope">
@ -418,11 +420,6 @@ const formatOpt = (row, { model, options }, prop) => {
.bg { .bg {
background-color: var(--vn-light-gray); background-color: var(--vn-light-gray);
} }
:deep(.q-table tr td:nth-child(n + 4):nth-child(-n + 5) input) {
display: none;
}
@media (max-width: $breakpoint-xs) { @media (max-width: $breakpoint-xs) {
.q-dialog { .q-dialog {
.q-card { .q-card {

View File

@ -83,7 +83,7 @@ const redirectToInvoiceInBasicData = (__, { id }) => {
</template> </template>
</VnSelect> </VnSelect>
<VnInput <VnInput
:label="t('invoiceIn.list.supplierRef')" :label="t('InvoiceIn.list.supplierRef')"
v-model="data.supplierRef" v-model="data.supplierRef"
/> />
</VnRow> </VnRow>
@ -97,10 +97,10 @@ const redirectToInvoiceInBasicData = (__, { id }) => {
map-options map-options
hide-selected hide-selected
:required="true" :required="true"
:rules="validate('invoiceIn.companyFk')" :rules="validate('InvoiceIn.companyFk')"
/> />
<VnInputDate <VnInputDate
:label="t('invoiceIn.summary.issued')" :label="t('InvoiceIn.summary.issued')"
v-model="data.issued" v-model="data.issued"
/> />
</VnRow> </VnRow>

View File

@ -1,41 +1,66 @@
<script setup> <script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import FetchData from 'components/FetchData.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import { dateRange } from 'src/filters';
import { date } from 'quasar';
const { t } = useI18n();
defineProps({ dataKey: { type: String, required: true } }); defineProps({ dataKey: { type: String, required: true } });
const activities = ref([]); const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
function handleDaysAgo(params, daysAgo) {
const [from, to] = dateRange(Date.vnNew());
if (!daysAgo && daysAgo !== 0) {
Object.assign(params, { from: undefined, to: undefined });
} else {
from.setDate(from.getDate() - daysAgo);
Object.assign(params, {
from: date.formatDate(from, dateFormat),
to: date.formatDate(to, dateFormat),
});
}
}
</script> </script>
<template> <template>
<FetchData <VnFilterPanel :data-key="dataKey" :search-button="true" :hidden-tags="['daysAgo']">
url="SupplierActivities" <template #tags="{ tag, formatFn, getLocale }">
auto-load
@on-fetch="(data) => (activities = data)"
/>
<VnFilterPanel :data-key="dataKey" :search-button="true">
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ getLocale(tag.label) }}: </strong>
<span>{{ formatFn(tag.value) }}</span> <span>{{ formatFn(tag.value) }}</span>
</div> </div>
</template> </template>
<template #body="{ params, searchFn }"> <template #body="{ params, searchFn, getLocale }">
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInputDate :label="t('From')" v-model="params.from" is-outlined /> <VnInputDate
:label="$t('globals.from')"
v-model="params.from"
is-outlined
/>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInputDate :label="t('To')" v-model="params.to" is-outlined /> <VnInputDate
:label="$t('globals.to')"
v-model="params.to"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInputNumber
:label="$t('globals.daysAgo')"
v-model="params.daysAgo"
is-outlined
:step="0"
@update:model-value="(val) => handleDaysAgo(params, val)"
@remove="(val) => handleDaysAgo(params, val)"
/>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem>
@ -44,20 +69,18 @@ const activities = ref([]);
v-model="params.supplierFk" v-model="params.supplierFk"
url="Suppliers" url="Suppliers"
:fields="['id', 'nickname']" :fields="['id', 'nickname']"
:label="t('params.supplierFk')" :label="getLocale('supplierFk')"
option-value="id"
option-label="nickname" option-label="nickname"
dense dense
outlined outlined
rounded rounded
:filter-options="['id', 'name']"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.supplierRef')" :label="getLocale('supplierRef')"
v-model="params.supplierRef" v-model="params.supplierRef"
is-outlined is-outlined
lazy-rules lazy-rules
@ -67,7 +90,7 @@ const activities = ref([]);
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.fi')" :label="getLocale('fi')"
v-model="params.fi" v-model="params.fi"
is-outlined is-outlined
lazy-rules lazy-rules
@ -77,7 +100,7 @@ const activities = ref([]);
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.serial')" :label="getLocale('serial')"
v-model="params.serial" v-model="params.serial"
is-outlined is-outlined
lazy-rules lazy-rules
@ -87,7 +110,7 @@ const activities = ref([]);
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.account')" :label="getLocale('account')"
v-model="params.account" v-model="params.account"
is-outlined is-outlined
lazy-rules lazy-rules
@ -97,7 +120,7 @@ const activities = ref([]);
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInput <VnInput
:label="t('params.awb')" :label="getLocale('globals.params.awbCode')"
v-model="params.awbCode" v-model="params.awbCode"
is-outlined is-outlined
lazy-rules lazy-rules
@ -107,24 +130,34 @@ const activities = ref([]);
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnInputNumber <VnInputNumber
:label="t('Amount')" :label="$t('globals.amount')"
v-model="params.amount" v-model="params.amount"
is-outlined is-outlined
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnSelect
v-model="params.companyFk"
:label="$t('globals.company')"
url="Companies"
option-label="code"
:fields="['id', 'code']"
is-outlined
/>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<QCheckbox <QCheckbox
:label="t('invoiceIn.isBooked')" :label="$t('InvoiceIn.isBooked')"
v-model="params.isBooked" v-model="params.isBooked"
@update:model-value="searchFn()" @update:model-value="searchFn()"
toggle-indeterminate toggle-indeterminate
/> />
</QItemSection>
<QItemSection>
<QCheckbox <QCheckbox
:label="t('params.correctingFk')" :label="getLocale('params.correctingFk')"
v-model="params.correctingFk" v-model="params.correctingFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"
toggle-indeterminate toggle-indeterminate
@ -134,54 +167,3 @@ const activities = ref([]);
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
<i18n>
en:
params:
search: Id or supplier name
supplierRef: Supplier ref.
supplierFk: Supplier
fi: Supplier fiscal id
clientFk: Customer
amount: Amount
created: Created
awb: AWB
dued: Dued
serialNumber: Serial Number
serial: Serial
account: Ledger account
isBooked: is booked
correctedFk: Rectified
issued: Issued
to: To
from: From
awbCode: AWB
correctingFk: Rectificative
supplierActivityFk: Supplier activity
es:
params:
search: Id o nombre proveedor
supplierRef: Ref. proveedor
supplierFk: Proveedor
clientFk: Cliente
fi: CIF proveedor
serialNumber: Num. serie
serial: Serie
awb: AWB
amount: Importe
issued: Emitida
isBooked: Contabilizada
account: Cuenta contable
created: Creada
dued: Vencida
correctedFk: Rectificada
correctingFk: Rectificativa
supplierActivityFk: Actividad proveedor
from: Desde
to: Hasta
From: Desde
To: Hasta
Amount: Importe
Issued: Fecha factura
Id or supplier: Id o proveedor
</i18n>

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore'; import { useState } from 'src/composables/useState';
import { downloadFile } from 'src/composables/downloadFile'; import { downloadFile } from 'src/composables/downloadFile';
import { toDate, toCurrency } from 'src/filters/index'; import { toDate, toCurrency } from 'src/filters/index';
import InvoiceInFilter from './InvoiceInFilter.vue'; import InvoiceInFilter from './InvoiceInFilter.vue';
@ -14,25 +14,34 @@ import VnTable from 'src/components/VnTable/VnTable.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import FetchData from 'src/components/FetchData.vue';
const stateStore = useStateStore(); const user = useState().getUser();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const { t } = useI18n(); const { t } = useI18n();
onMounted(async () => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
const tableRef = ref(); const tableRef = ref();
const companies = ref([]);
const cols = computed(() => [ const cols = computed(() => [
{
align: 'left',
name: 'isBooked',
label: t('InvoiceIn.isBooked'),
columnFilter: false,
},
{ {
align: 'left', align: 'left',
name: 'id', name: 'id',
label: 'Id', label: 'Id',
isId: true,
chip: {
condition: () => true,
},
}, },
{ {
align: 'left', align: 'left',
name: 'supplierFk', name: 'supplierFk',
label: t('invoiceIn.list.supplier'), label: t('InvoiceIn.list.supplier'),
columnFilter: { columnFilter: {
component: 'select', component: 'select',
attrs: { attrs: {
@ -41,20 +50,21 @@ const cols = computed(() => [
}, },
}, },
columnClass: 'expand', columnClass: 'expand',
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',
name: 'supplierRef', name: 'supplierRef',
label: t('invoiceIn.list.supplierRef'), label: t('InvoiceIn.list.supplierRef'),
}, },
{ {
align: 'left', align: 'left',
name: 'serial', name: 'serial',
label: t('invoiceIn.serial'), label: t('InvoiceIn.serial'),
}, },
{ {
align: 'left', align: 'left',
label: t('invoiceIn.list.issued'), label: t('InvoiceIn.list.issued'),
name: 'issued', name: 'issued',
component: null, component: null,
columnFilter: { columnFilter: {
@ -64,20 +74,52 @@ const cols = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'isBooked', label: t('InvoiceIn.list.dueDated'),
label: t('invoiceIn.isBooked'), name: 'dueDated',
columnFilter: false, component: null,
columnFilter: {
component: 'date',
},
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.dueDated)),
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',
name: 'awbCode', name: 'awbCode',
label: t('invoiceIn.list.awb'), label: t('InvoiceIn.list.awb'),
}, },
{ {
align: 'left', align: 'left',
name: 'amount', name: 'amount',
label: t('invoiceIn.list.amount'), label: t('InvoiceIn.list.amount'),
format: ({ amount }) => toCurrency(amount), format: ({ amount }) => toCurrency(amount),
cardVisible: true,
},
{
name: 'companyFk',
label: t('globals.company'),
columnFilter: {
component: 'select',
attrs: {
url: 'Companies',
fields: ['id', 'code'],
optionLabel: 'code',
},
},
format: (row) => row.code,
},
{
name: 'companyFk',
label: t('globals.company'),
columnFilter: {
component: 'select',
attrs: {
url: 'Companies',
fields: ['id', 'code'],
optionLabel: 'code',
},
},
format: (row) => row.code,
}, },
{ {
align: 'right', align: 'right',
@ -87,6 +129,7 @@ const cols = computed(() => [
title: t('components.smartCard.openSummary'), title: t('components.smartCard.openSummary'),
icon: 'preview', icon: 'preview',
type: 'submit', type: 'submit',
isPrimary: true,
action: (row) => viewSummary(row.id, InvoiceInSummary), action: (row) => viewSummary(row.id, InvoiceInSummary),
}, },
{ {
@ -101,6 +144,7 @@ const cols = computed(() => [
]); ]);
</script> </script>
<template> <template>
<FetchData url="Companies" @on-fetch="(data) => (companies = data)" auto-load />
<InvoiceInSearchbar /> <InvoiceInSearchbar />
<RightMenu> <RightMenu>
<template #right-panel> <template #right-panel>
@ -116,7 +160,7 @@ const cols = computed(() => [
urlCreate: 'InvoiceIns', urlCreate: 'InvoiceIns',
title: t('globals.createInvoiceIn'), title: t('globals.createInvoiceIn'),
onDataSaved: ({ id }) => tableRef.redirect(id), onDataSaved: ({ id }) => tableRef.redirect(id),
formInitialData: {}, formInitialData: { companyFk: user.companyFk, issued: Date.vnNew() },
}" }"
redirect="invoice-in" redirect="invoice-in"
:columns="cols" :columns="cols"
@ -151,7 +195,7 @@ const cols = computed(() => [
</template> </template>
</VnSelect> </VnSelect>
<VnInput <VnInput
:label="t('invoiceIn.list.supplierRef')" :label="t('InvoiceIn.list.supplierRef')"
v-model="data.supplierRef" v-model="data.supplierRef"
/> />
<VnSelect <VnSelect
@ -163,7 +207,7 @@ const cols = computed(() => [
option-label="code" option-label="code"
:required="true" :required="true"
/> />
<VnInputDate :label="t('invoiceIn.summary.issued')" v-model="data.issued" /> <VnInputDate :label="t('InvoiceIn.summary.issued')" v-model="data.issued" />
</template> </template>
</VnTable> </VnTable>
</template> </template>

View File

@ -58,6 +58,14 @@ onBeforeMount(async () => {
:right-search="false" :right-search="false"
:user-params="{ daysAgo }" :user-params="{ daysAgo }"
:disable-option="{ card: true }" :disable-option="{ card: true }"
:row-click="
(row) => {
$router.push({
name: 'InvoiceInList',
query: { table: JSON.stringify({ serial: row.serial }) },
});
}
"
auto-load auto-load
/> />
</template> </template>

View File

@ -8,7 +8,11 @@ defineProps({ dataKey: { type: String, required: true } });
const { t } = useI18n(); const { t } = useI18n();
</script> </script>
<template> <template>
<VnFilterPanel :data-key="dataKey" :search-button="true"> <VnFilterPanel
:data-key="dataKey"
:search-button="true"
:unremovable-params="['daysAgo']"
>
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ t(`params.${tag.label}`) }}: </strong>

View File

@ -1,4 +1,4 @@
invoiceIn: InvoiceIn:
serial: Serial serial: Serial
isBooked: Is booked isBooked: Is booked
list: list:
@ -7,8 +7,11 @@ invoiceIn:
supplierRef: Supplier ref. supplierRef: Supplier ref.
file: File file: File
issued: Issued issued: Issued
dueDated: Due dated
awb: AWB awb: AWB
amount: Amount amount: Amount
descriptor:
ticketList: Ticket list
card: card:
client: Client client: Client
company: Company company: Company
@ -39,3 +42,9 @@ invoiceIn:
net: Net net: Net
stems: Stems stems: Stems
country: Country country: Country
params:
search: Id or supplier name
account: Ledger account
correctingFk: Rectificative
correctedFk: Corrected
isBooked: Is booked

View File

@ -1,15 +1,17 @@
invoiceIn: InvoiceIn:
serial: Serie serial: Serie
isBooked: Contabilizada isBooked: Contabilizada
list: list:
ref: Referencia ref: Referencia
supplier: Proveedor supplier: Proveedor
supplierRef: Ref. proveedor supplierRef: Ref. proveedor
shortIssued: F. emisión issued: F. emisión
dueDated: F. vencimiento
file: Fichero file: Fichero
issued: Fecha emisión
awb: AWB awb: AWB
amount: Importe amount: Importe
descriptor:
ticketList: Listado de tickets
card: card:
client: Cliente client: Cliente
company: Empresa company: Empresa
@ -38,3 +40,8 @@ invoiceIn:
net: Neto net: Neto
stems: Tallos stems: Tallos
country: País country: País
params:
search: Id o nombre proveedor
account: Cuenta contable
correctingFk: Rectificativa
correctedFk: Rectificada

View File

@ -115,6 +115,9 @@ onMounted(async () => {
<VnSelect <VnSelect
:label="t('invoiceOutSerialType')" :label="t('invoiceOutSerialType')"
v-model="formData.serialType" v-model="formData.serialType"
@update:model-value="
invoiceOutGlobalStore.fetchInvoiceOutConfig(formData)
"
:options="serialTypesOptions" :options="serialTypesOptions"
option-value="type" option-value="type"
option-label="type" option-label="type"

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { onMounted, onUnmounted, ref, computed, watchEffect } from 'vue'; import { ref, computed, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
@ -10,7 +10,6 @@ import { usePrintService } from 'src/composables/usePrintService';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue'; import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
import { toCurrency, toDate } from 'src/filters/index'; import { toCurrency, toDate } from 'src/filters/index';
import { useStateStore } from 'stores/useStateStore';
import { QBtn } from 'quasar'; import { QBtn } from 'quasar';
import axios from 'axios'; import axios from 'axios';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
@ -21,7 +20,6 @@ import VnInput from 'src/components/common/VnInput.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref(); const tableRef = ref();
const invoiceOutSerialsOptions = ref([]); const invoiceOutSerialsOptions = ref([]);
@ -147,8 +145,6 @@ const columns = computed(() => [
], ],
}, },
]); ]);
onMounted(() => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
function openPdf(id) { function openPdf(id) {
openReport(`${MODEL}/${id}/download`); openReport(`${MODEL}/${id}/download`);
@ -214,7 +210,6 @@ watchEffect(selectedRows);
order="id DESC" order="id DESC"
:columns="columns" :columns="columns"
redirect="invoice-out" redirect="invoice-out"
auto-load
:table="{ :table="{
'row-key': 'id', 'row-key': 'id',
selection: 'multiple', selection: 'multiple',

View File

@ -361,7 +361,7 @@ function handleOnDataSave({ CrudModelRef }) {
@on-fetch="(data) => (warehousesOptions = data)" @on-fetch="(data) => (warehousesOptions = data)"
auto-load auto-load
url="Warehouses" url="Warehouses"
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }" :filter="{ fields: ['id', 'name'], order: 'name ASC' }"
/> />
<RightMenu> <RightMenu>
<template #right-panel> <template #right-panel>
@ -394,191 +394,186 @@ function handleOnDataSave({ CrudModelRef }) {
/> />
</template> </template>
</VnSubToolbar> </VnSubToolbar>
<QPage> <VnTable
<VnTable @on-fetch="
@on-fetch=" (data) =>
(data) => data.forEach((item) => {
data.forEach((item) => { item.hasMinPrice = `${item.hasMinPrice !== 0}`;
item.hasMinPrice = `${item.hasMinPrice !== 0}`; })
}) "
" :default-remove="false"
:default-remove="false" :default-reset="false"
:default-reset="false" :default-save="false"
:default-save="false" data-key="ItemFixedPrices"
data-key="ItemFixedPrices" url="FixedPrices/filter"
url="FixedPrices/filter" :order="['itemFk DESC', 'name DESC']"
:order="['itemFk DESC', 'name DESC']" save-url="FixedPrices/crud"
save-url="FixedPrices/crud" ref="tableRef"
ref="tableRef" dense
dense :filter="{
:filter="{ where: {
where: { warehouseFk: user.warehouseFk,
warehouseFk: user.warehouseFk, },
}, }"
}" :columns="columns"
:columns="columns" default-mode="table"
default-mode="table" auto-load
auto-load :is-editable="true"
:is-editable="true" :right-search="false"
:right-search="false" :table="{
:table="{ 'row-key': 'id',
'row-key': 'id', selection: 'multiple',
selection: 'multiple', }"
}" :use-model="true"
:crud-model="{ v-model:selected="rowsSelected"
disableInfiniteScroll: true, :create-as-dialog="false"
}" :create="{
v-model:selected="rowsSelected" onDataSaved: handleOnDataSave,
:create-as-dialog="false" }"
:create="{ :disable-option="{ card: true }"
onDataSaved: handleOnDataSave, >
}" <template #header-selection="scope">
:use-model="true" <QCheckbox v-model="scope.selected" />
:disable-option="{ card: true }" </template>
> <template #body-selection="scope">
<template #header-selection="scope"> {{ scope }}
<QCheckbox v-model="scope.selected" /> <QCheckbox flat v-model="scope.selected" />
</template> </template>
<template #body-selection="scope">
{{ scope }}
<QCheckbox flat v-model="scope.selected" />
</template>
<template #column-itemFk="props"> <template #column-itemFk="props">
<VnSelect <VnSelect
style="max-width: 100px" style="max-width: 100px"
url="Items/withName" url="Items/withName"
hide-selected hide-selected
option-label="id" option-label="id"
option-value="id" option-value="id"
v-model="props.row.itemFk" v-model="props.row.itemFk"
v-on="getRowUpdateInputEvents(props, true, 'select')" v-on="getRowUpdateInputEvents(props, true, 'select')"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel> #{{ scope.opt?.id }} </QItemLabel>
<QItemLabel caption>{{ scope.opt?.name }}</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelect>
</template>
<template #column-name="{ row }">
<span class="link">
{{ row.name }}
</span>
<span class="subName">{{ row.subName }}</span>
<ItemDescriptorProxy :id="row.itemFk" />
<FetchedTags :item="row" :columns="3" />
</template>
<template #column-rate2="props">
<QTd class="col">
<VnInput
type="currency"
style="width: 75px"
v-model.number="props.row.rate2"
v-on="getRowUpdateInputEvents(props)"
> >
<template #option="scope"> <template #append></template>
<QItem v-bind="scope.itemProps"> </VnInput>
<QItemSection> </QTd>
<QItemLabel> #{{ scope.opt?.id }} </QItemLabel> </template>
<QItemLabel caption>{{ scope.opt?.name }}</QItemLabel> <template #column-rate3="props">
</QItemSection> <QTd class="col">
</QItem> <VnInput
</template> style="width: 75px"
</VnSelect> type="currency"
</template> v-model.number="props.row.rate3"
<template #column-name="{ row }"> v-on="getRowUpdateInputEvents(props)"
<span class="link"> >
{{ row.name }} <template #append></template>
</span> </VnInput>
<span class="subName">{{ row.subName }}</span> </QTd>
<ItemDescriptorProxy :id="row.itemFk" /> </template>
<FetchedTags :item="row" /> <template #column-minPrice="props">
</template> <QTd class="col">
<template #column-rate2="props"> <div class="row" style="align-items: center">
<QTd class="col"> <QCheckbox
<VnInput :model-value="props.row.hasMinPrice"
type="currency" @update:model-value="updateMinPrice($event, props)"
style="width: 75px" :false-value="'false'"
v-model.number="props.row.rate2" :true-value="'true'"
v-on="getRowUpdateInputEvents(props)"
>
<template #append></template>
</VnInput>
</QTd>
</template>
<template #column-rate3="props">
<QTd class="col">
<VnInput
style="width: 75px"
type="currency"
v-model.number="props.row.rate3"
v-on="getRowUpdateInputEvents(props)"
>
<template #append></template>
</VnInput>
</QTd>
</template>
<template #column-minPrice="props">
<QTd class="col">
<div class="row" style="align-items: center">
<QCheckbox
:model-value="props.row.hasMinPrice"
@update:model-value="updateMinPrice($event, props)"
:false-value="'false'"
:true-value="'true'"
/>
<VnInput
class="col"
type="currency"
mask="###.##"
:disable="props.row.hasMinPrice === 1"
v-model.number="props.row.minPrice"
v-on="getRowUpdateInputEvents(props)"
>
<template #append></template>
</VnInput>
</div>
</QTd>
</template>
<template #column-started="props">
<VnInputDate
class="vnInputDate"
:show-event="true"
v-model="props.row.started"
v-on="getRowUpdateInputEvents(props, false, 'date')"
v-bind="dateStyle(isBigger(props.row.started))"
/>
</template>
<template #column-ended="props">
<VnInputDate
class="vnInputDate"
:show-event="true"
v-model="props.row.ended"
v-on="getRowUpdateInputEvents(props, false, 'date')"
v-bind="dateStyle(isLower(props.row.ended))"
/>
</template>
<template #column-warehouseFk="props">
<QTd class="col">
<VnSelect
style="max-width: 150px"
:options="warehousesOptions"
hide-selected
option-label="name"
option-value="id"
v-model="props.row.warehouseFk"
v-on="getRowUpdateInputEvents(props, false, 'select')"
/> />
</QTd> <VnInput
</template> class="col"
<template #column-deleteAction="{ row, rowIndex }"> type="currency"
<QIcon mask="###.##"
name="delete" :disable="props.row.hasMinPrice === 1"
size="sm" v-model.number="props.row.minPrice"
class="cursor-pointer fill-icon-on-hover" v-on="getRowUpdateInputEvents(props)"
color="primary" >
@click.stop=" <template #append></template>
openConfirmationModal( </VnInput>
t('globals.rowWillBeRemoved'), </div>
t('Do you want to clone this item?'), </QTd>
() => removePrice(row.id, rowIndex) </template>
) <template #column-started="props">
" <VnInputDate
> class="vnInputDate"
<QTooltip class="text-no-wrap"> :show-event="true"
{{ t('globals.delete') }} v-model="props.row.started"
</QTooltip> v-on="getRowUpdateInputEvents(props, false, 'date')"
</QIcon> v-bind="dateStyle(isBigger(props.row.started))"
</template>
</VnTable>
<QDialog ref="editTableCellDialogRef">
<EditTableCellValueForm
edit-url="FixedPrices/editFixedPrice"
:rows="rowsSelected"
:fields-options="editTableFieldsOptions"
@on-data-saved="onEditCellDataSaved()"
/> />
</QDialog> </template>
</QPage> <template #column-ended="props">
<VnInputDate
class="vnInputDate"
:show-event="true"
v-model="props.row.ended"
v-on="getRowUpdateInputEvents(props, false, 'date')"
v-bind="dateStyle(isLower(props.row.ended))"
/>
</template>
<template #column-warehouseFk="props">
<QTd class="col">
<VnSelect
style="max-width: 150px"
:options="warehousesOptions"
hide-selected
option-label="name"
option-value="id"
v-model="props.row.warehouseFk"
v-on="getRowUpdateInputEvents(props, false, 'select')"
/>
</QTd>
</template>
<template #column-deleteAction="{ row, rowIndex }">
<QIcon
name="delete"
size="sm"
class="cursor-pointer fill-icon-on-hover"
color="primary"
@click.stop="
openConfirmationModal(
t('globals.rowWillBeRemoved'),
t('Do you want to clone this item?'),
() => removePrice(row.id, rowIndex)
)
"
>
<QTooltip class="text-no-wrap">
{{ t('globals.delete') }}
</QTooltip>
</QIcon>
</template>
</VnTable>
<QDialog ref="editTableCellDialogRef">
<EditTableCellValueForm
edit-url="FixedPrices/editFixedPrice"
:rows="rowsSelected"
:fields-options="editTableFieldsOptions"
@on-data-saved="onEditCellDataSaved()"
/>
</QDialog>
</template> </template>
<style lang="scss"> <style lang="scss">
.q-table th, .q-table th,

View File

@ -11,6 +11,7 @@ import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import ItemSummary from '../Item/Card/ItemSummary.vue'; import ItemSummary from '../Item/Card/ItemSummary.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from './Card/ItemDescriptorProxy.vue';
import ItemTypeDescriptorProxy from './ItemType/Card/ItemTypeDescriptorProxy.vue';
import { cloneItem } from 'src/pages/Item/composables/cloneItem'; import { cloneItem } from 'src/pages/Item/composables/cloneItem';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import ItemListFilter from './ItemListFilter.vue'; import ItemListFilter from './ItemListFilter.vue';
@ -56,7 +57,6 @@ const columns = computed(() => [
name: 'image', name: 'image',
align: 'left', align: 'left',
columnFilter: false, columnFilter: false,
cardVisible: true,
}, },
{ {
label: t('item.list.id'), label: t('item.list.id'),
@ -94,7 +94,7 @@ const columns = computed(() => [
columnFilter: { columnFilter: {
name: 'search', name: 'search',
}, },
cardVisible: true, columnClass: 'expand',
}, },
{ {
label: t('item.list.stems'), label: t('item.list.stems'),
@ -132,10 +132,13 @@ const columns = computed(() => [
fields: ['id', 'name'], fields: ['id', 'name'],
}, },
}, },
columnField: {
component: null,
},
create: true, create: true,
visible: false,
},
{
label: t('item.list.typeName'),
name: 'typeName',
align: 'left',
}, },
{ {
label: t('item.list.category'), label: t('item.list.category'),
@ -220,7 +223,6 @@ const columns = computed(() => [
label: t('item.list.weight'), label: t('item.list.weight'),
toolTip: t('item.list.weightByPiece'), toolTip: t('item.list.weightByPiece'),
name: 'weightByPiece', name: 'weightByPiece',
align: 'left',
component: 'input', component: 'input',
columnField: { columnField: {
component: null, component: null,
@ -296,7 +298,6 @@ const columns = computed(() => [
}, },
]); ]);
</script> </script>
<template> <template>
<VnSearchbar <VnSearchbar
data-key="ItemList" data-key="ItemList"
@ -341,6 +342,13 @@ const columns = computed(() => [
<ItemDescriptorProxy :id="row.id" /> <ItemDescriptorProxy :id="row.id" />
</span> </span>
</template> </template>
<template #column-typeName="{ row }">
<span class="link" @click.stop>
{{ row.typeName }}
{{ row.typeFk }}
<ItemTypeDescriptorProxy :id="row.typeFk" />
</span>
</template>
<template #column-userName="{ row }"> <template #column-userName="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.userName }} {{ row.userName }}
@ -354,15 +362,15 @@ const columns = computed(() => [
{{ row?.subName.toUpperCase() }} {{ row?.subName.toUpperCase() }}
</div> </div>
</div> </div>
<FetchedTags :item="row" :max-length="6" /> <FetchedTags :item="row" :columns="3" />
</template> </template>
</VnTable> </VnTable>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
.subName { .subName {
text-transform: uppercase; text-transform: uppercase;
color: var(--vn-label-color); color: var(--vn-label-color);
font-size: small;
} }
</style> </style>
<i18n> <i18n>

View File

@ -6,13 +6,11 @@ import { useI18n } from 'vue-i18n';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
const $props = defineProps({ const $props = defineProps({
id: { id: {
type: Number, type: Number,
required: false,
default: null, default: null,
}, },
summary: { summary: {
@ -24,6 +22,10 @@ const $props = defineProps({
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const entityId = computed(() => {
return $props.id || route.params.id;
});
const itemTypeFilter = { const itemTypeFilter = {
include: [ include: [
{ relation: 'worker' }, { relation: 'worker' },
@ -33,10 +35,6 @@ const itemTypeFilter = {
], ],
}; };
const entityId = computed(() => {
return $props.id || route.params.id;
});
const data = ref(useCardDescription()); const data = ref(useCardDescription());
const setData = (entity) => (data.value = useCardDescription(entity.code, entity.id)); const setData = (entity) => (data.value = useCardDescription(entity.code, entity.id));
</script> </script>
@ -48,8 +46,8 @@ const setData = (entity) => (data.value = useCardDescription(entity.code, entity
:filter="itemTypeFilter" :filter="itemTypeFilter"
:title="data.title" :title="data.title"
:subtitle="data.subtitle" :subtitle="data.subtitle"
data-key="itemTypeDescriptor"
@on-fetch="setData" @on-fetch="setData"
data-key="entry"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('shared.code')" :value="entity.code" /> <VnLv :label="t('shared.code')" :value="entity.code" />

View File

@ -0,0 +1,17 @@
<script setup>
import ItemTypeDescriptor from './ItemTypeDescriptor.vue';
import ItemTypeSummary from './ItemTypeSummary.vue';
const $props = defineProps({
id: {
type: Number,
required: true,
},
});
</script>
<template>
<QPopupProxy>
<ItemTypeDescriptor v-if="$props.id" :id="$props.id" :summary="ItemTypeSummary" />
</QPopupProxy>
</template>

View File

@ -135,7 +135,7 @@ item:
origin: Orig. origin: Orig.
userName: Buyer userName: Buyer
weight: Weight weight: Weight
weightByPiece: Weight/Piece weightByPiece: Weight/stem
stemMultiplier: Multiplier stemMultiplier: Multiplier
producer: Producer producer: Producer
landed: Landed landed: Landed

View File

@ -136,7 +136,7 @@ item:
size: Medida size: Medida
origin: Orig. origin: Orig.
weight: Peso weight: Peso
weightByPiece: Peso (gramos)/tallo weightByPiece: Peso/tallo
userName: Comprador userName: Comprador
stemMultiplier: Multiplicador stemMultiplier: Multiplicador
producer: Productor producer: Productor

View File

@ -1,20 +1,22 @@
<script setup> <script setup>
import axios from 'axios';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, ref, onMounted } from 'vue'; import { computed, ref, onMounted } from 'vue';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters'; import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import { toDateTimeFormat } from 'src/filters/date';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { useRoute } from 'vue-router';
import axios from 'axios';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import OrderSearchbar from './Card/OrderSearchbar.vue';
import OrderFilter from './Card/OrderFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import OrderSearchbar from './Card/OrderSearchbar.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import OrderFilter from './Card/OrderFilter.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import { toDateTimeFormat } from 'src/filters/date';
import { useRoute } from 'vue-router';
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
@ -171,9 +173,9 @@ const getDateColor = (date) => {
today.setHours(0, 0, 0, 0); today.setHours(0, 0, 0, 0);
const timeTicket = new Date(date); const timeTicket = new Date(date);
timeTicket.setHours(0, 0, 0, 0); timeTicket.setHours(0, 0, 0, 0);
const comparation = today - timeTicket; const difference = today - timeTicket;
if (comparation == 0) return 'bg-warning'; if (difference == 0) return 'bg-warning';
if (comparation < 0) return 'bg-success'; if (difference < 0) return 'bg-success';
}; };
</script> </script>
<template> <template>
@ -201,8 +203,8 @@ const getDateColor = (date) => {
}, },
}" }"
:user-params="{ showEmpty: false }" :user-params="{ showEmpty: false }"
:right-search="false"
:columns="columns" :columns="columns"
:right-search="false"
redirect="order" redirect="order"
> >
<template #column-clientFk="{ row }"> <template #column-clientFk="{ row }">

View File

@ -29,7 +29,7 @@ const exprBuilder = (param, value) => {
return { 'a.supplierName': value }; return { 'a.supplierName': value };
case 'routeFk': case 'routeFk':
return { 'a.routeFk': value }; return { 'a.routeFk': value };
case 'created': case 'dated':
case 'agencyFk': case 'agencyFk':
case 'packages': case 'packages':
case 'm3': case 'm3':
@ -145,7 +145,7 @@ const exprBuilder = (param, value) => {
<QItem class="q-my-sm"> <QItem class="q-my-sm">
<QItemSection> <QItemSection>
<VnInputDate <VnInputDate
v-model="params.created" v-model="params.dated"
:label="t('Date')" :label="t('Date')"
is-outlined is-outlined
/> />

View File

@ -28,7 +28,7 @@ const filter = {
'id', 'id',
'workerFk', 'workerFk',
'agencyModeFk', 'agencyModeFk',
'created', 'dated',
'm3', 'm3',
'warehouseFk', 'warehouseFk',
'description', 'description',
@ -78,7 +78,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.code, entity
@on-fetch="setData" @on-fetch="setData"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('Date')" :value="toDate(entity?.created)" /> <VnLv :label="t('Date')" :value="toDate(entity?.dated)" />
<VnLv :label="t('Agency')" :value="entity?.agencyMode?.name" /> <VnLv :label="t('Agency')" :value="entity?.agencyMode?.name" />
<VnLv :label="t('Zone')" :value="entity?.zone?.name" /> <VnLv :label="t('Zone')" :value="entity?.zone?.name" />
<VnLv <VnLv

View File

@ -20,7 +20,7 @@ const shelvingId = ref(route.params?.id || null);
const isNew = Boolean(!shelvingId.value); const isNew = Boolean(!shelvingId.value);
const defaultInitialData = { const defaultInitialData = {
agencyModeFk: null, agencyModeFk: null,
created: null, dated: null,
description: '', description: '',
vehicleFk: null, vehicleFk: null,
workerFk: null, workerFk: null,
@ -33,7 +33,7 @@ const routeFilter = {
'id', 'id',
'workerFk', 'workerFk',
'agencyModeFk', 'agencyModeFk',
'created', 'dated',
'm3', 'm3',
'warehouseFk', 'warehouseFk',
'description', 'description',
@ -116,7 +116,7 @@ const onSave = (data, response) => {
option-label="name" option-label="name"
:input-debounce="0" :input-debounce="0"
/> />
<VnInputDate v-model="data.created" :label="t('Created')" /> <VnInputDate v-model="data.dated" :label="t('Dated')" />
</VnRow> </VnRow>
<template v-if="!isNew"> <template v-if="!isNew">
<VnRow> <VnRow>
@ -170,7 +170,7 @@ es:
Hour finished: Hora fin Hour finished: Hora fin
Description: Descripción Description: Descripción
Is served: Se ha servido Is served: Se ha servido
Created: Creado Dated: Fecha
The km can not exceed: La distancia debe ser inferior a {maxDistance} The km can not exceed: La distancia debe ser inferior a {maxDistance}
en: en:
The km can not exceed: Distance must be lesser than {maxDistance} The km can not exceed: Distance must be lesser than {maxDistance}

View File

@ -139,7 +139,7 @@ const ticketColumns = ref([
<QCard class="vn-one"> <QCard class="vn-one">
<VnLv <VnLv
:label="t('route.summary.date')" :label="t('route.summary.date')"
:value="toDate(entity?.route.created)" :value="toDate(entity?.route.dated)"
/> />
<VnLv <VnLv
:label="t('route.summary.agency')" :label="t('route.summary.agency')"

View File

@ -46,10 +46,10 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'created', name: 'dated',
label: t('Date'), label: t('Date'),
columnFilter: false, columnFilter: false,
format: ({ created }) => toDate(created), format: ({ dated }) => toDate(dated),
}, },
{ {
align: 'left', align: 'left',

View File

@ -111,7 +111,7 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'created', name: 'dated',
label: t('route.Date'), label: t('route.Date'),
columnFilter: false, columnFilter: false,
cardVisible: true, cardVisible: true,

View File

@ -26,7 +26,7 @@ const routeFilter = {
}; };
const columns = computed(() => [ const columns = computed(() => [
{ {
align: 'left', align: 'right',
isId: true, isId: true,
name: 'id', name: 'id',
label: 'Id', label: 'Id',

View File

@ -45,7 +45,7 @@ const columns = computed(() => [
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
}, },
format: ({ created }) => toDate(created), format: ({ dated }) => toDate(dated),
cardVisible: true, cardVisible: true,
}, },
{ {

View File

@ -109,7 +109,7 @@ const ticketList = ref([]);
const cloneRoutes = () => { const cloneRoutes = () => {
axios.post('Routes/clone', { axios.post('Routes/clone', {
created: startingDate.value, dated: startingDate.value,
ids: selectedRows.value.map((row) => row?.id), ids: selectedRows.value.map((row) => row?.id),
}); });
refreshKey.value++; refreshKey.value++;

View File

@ -5,7 +5,7 @@ route:
Description: Description Description: Description
hourStarted: H.Start hourStarted: H.Start
hourFinished: H.End hourFinished: H.End
createRoute: Create route dated: Dated
From: From From: From
To: To To: To
Date: Date Date: Date

View File

@ -43,7 +43,7 @@ const filter = {
data-key="ShelvingSummary" data-key="ShelvingSummary"
> >
<template #header="{ entity }"> <template #header="{ entity }">
<div>{{ entity.code }}</div> <div>{{ entity.id }} - {{ entity.code }}</div>
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<QCard class="vn-one"> <QCard class="vn-one">

View File

@ -1,8 +1,6 @@
<script setup> <script setup>
import VnPaginate from 'components/ui/VnPaginate.vue'; import VnPaginate from 'components/ui/VnPaginate.vue';
import { useStateStore } from 'stores/useStateStore';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { onMounted } from 'vue';
import CardList from 'components/ui/CardList.vue'; import CardList from 'components/ui/CardList.vue';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
@ -12,7 +10,6 @@ import ShelvingSearchbar from 'pages/Shelving/Card/ShelvingSearchbar.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
const stateStore = useStateStore();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
@ -20,8 +17,6 @@ const filter = {
include: [{ relation: 'parking' }], include: [{ relation: 'parking' }],
}; };
onMounted(() => (stateStore.rightDrawer = true));
function navigate(id) { function navigate(id) {
router.push({ path: `/shelving/${id}` }); router.push({ path: `/shelving/${id}` });
} }

View File

@ -14,10 +14,10 @@ import axios from 'axios';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
const quasar = useQuasar();
const { notify } = useNotify();
const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const { notify } = useNotify();
const quasar = useQuasar();
const route = useRoute();
const bankEntitiesRef = ref(null); const bankEntitiesRef = ref(null);
const supplier = ref(null); const supplier = ref(null);

View File

@ -180,10 +180,7 @@ function handleLocation(data, location) {
:label="t('supplier.fiscalData.isTrucker')" :label="t('supplier.fiscalData.isTrucker')"
/> />
<div class="row items-center"> <div class="row items-center">
<QCheckbox <QCheckbox v-model="data.isVies" :label="t('globals.isVies')" />
v-model="data.isVies"
:label="t('supplier.fiscalData.isVies')"
/>
<QIcon name="info" size="xs" class="cursor-pointer q-ml-sm"> <QIcon name="info" size="xs" class="cursor-pointer q-ml-sm">
<QTooltip> <QTooltip>
{{ {{

View File

@ -41,7 +41,7 @@ const getUrl = (section) => `#/supplier/${entityId.value}/${section}`;
data-key="SupplierSummary" data-key="SupplierSummary"
> >
<template #header> <template #header>
<span>{{ supplier.name }} - {{ supplier.id }}</span> <span>{{ supplier.id }} - {{ supplier.name }}</span>
</template> </template>
<template #body> <template #body>

View File

@ -14,7 +14,10 @@ const columns = computed(() => [
align: 'left', align: 'left',
label: t('globals.id'), label: t('globals.id'),
name: 'id', name: 'id',
isTitle: true, isId: true,
chip: {
condition: () => true,
},
}, },
{ {
align: 'left', align: 'left',
@ -24,6 +27,7 @@ const columns = computed(() => [
columnFilter: { columnFilter: {
name: 'search', name: 'search',
}, },
isTitle: true,
}, },
{ {
align: 'left', align: 'left',
@ -32,6 +36,7 @@ const columns = computed(() => [
columnFilter: { columnFilter: {
inWhere: true, inWhere: true,
}, },
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',
@ -40,6 +45,7 @@ const columns = computed(() => [
columnFilter: { columnFilter: {
name: 'search', name: 'search',
}, },
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',
@ -119,7 +125,6 @@ const columns = computed(() => [
:right-search="false" :right-search="false"
order="id ASC" order="id ASC"
:columns="columns" :columns="columns"
auto-load
/> />
</template> </template>

View File

@ -23,13 +23,13 @@ const countriesOptions = ref([]);
<template> <template>
<FetchData <FetchData
url="Provinces" url="Provinces"
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }" :filter="{ fields: ['id', 'name'], order: 'name ASC'}"
@on-fetch="(data) => (provincesOptions = data)" @on-fetch="(data) => (provincesOptions = data)"
auto-load auto-load
/> />
<FetchData <FetchData
url="countries" url="countries"
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }" :filter="{ fields: ['id', 'name'], order: 'name ASC'}"
@on-fetch="(data) => (countriesOptions = data)" @on-fetch="(data) => (countriesOptions = data)"
auto-load auto-load
/> />

View File

@ -86,71 +86,67 @@ async function getVideoList(expeditionId, timed) {
<template> <template>
<Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()"> <Teleport to="#right-panel" v-if="stateStore.isHeaderMounted()">
<QScrollArea class="fit"> <QList bordered separator style="max-width: 318px">
<QList bordered separator style="max-width: 318px"> <QItem v-if="lastExpedition && videoList.length">
<QItem v-if="lastExpedition && videoList.length"> <QItemSection>
<QItemSection> <QItemLabel class="text-h6">
<QItemLabel class="text-h6"> {{ t('ticket.boxing.selectTime') }} ({{ time.min }}-{{
{{ t('ticket.boxing.selectTime') }} ({{ time.min }}-{{ time.max
time.max }})
}}) </QItemLabel>
</QItemLabel> <QRange
<QRange v-model="time"
v-model="time" @change="getVideoList(lastExpedition, time)"
@change="getVideoList(lastExpedition, time)" :min="0"
:min="0" :max="24"
:max="24" :step="1"
:step="1" :left-label-value="time.min + ':00'"
:left-label-value="time.min + ':00'" :right-label-value="time.max + ':00'"
:right-label-value="time.max + ':00'" label
label markers
markers snap
snap color="primary"
color="primary" />
/> </QItemSection>
</QItemSection> </QItem>
</QItem> <QItem v-if="lastExpedition && videoList.length">
<QItem v-if="lastExpedition && videoList.length"> <QItemSection>
<QItemSection> <QSelect
<QSelect color="primary"
color="primary" v-model="slide"
v-model="slide" :options="videoList"
:options="videoList" :label="t('ticket.boxing.selectVideo')"
:label="t('ticket.boxing.selectVideo')" emit-value
emit-value map-options
map-options >
> <template #prepend>
<template #prepend> <QIcon name="schedule" />
<QIcon name="schedule" /> </template>
</template> </QSelect>
</QSelect> </QItemSection>
</QItemSection> </QItem>
</QItem> <QItem
<QItem v-for="expedition in expeditions"
v-for="expedition in expeditions" :key="expedition.id"
:key="expedition.id" @click="getVideoList(expedition.id)"
@click="getVideoList(expedition.id)" clickable
clickable v-ripple
v-ripple >
> <QItemSection>
<QItemSection> <QItemLabel class="text-h6">#{{ expedition.id }}</QItemLabel>
<QItemLabel class="text-h6">#{{ expedition.id }}</QItemLabel> </QItemSection>
</QItemSection> <QItemSection>
<QItemSection> <QItemLabel caption>{{ t('globals.created') }}</QItemLabel>
<QItemLabel caption>{{ t('globals.created') }}</QItemLabel> <QItemLabel>
<QItemLabel> {{ date.formatDate(expedition.created, 'YYYY-MM-DD HH:mm:ss') }}
{{ </QItemLabel>
date.formatDate(expedition.created, 'YYYY-MM-DD HH:mm:ss') <QItemLabel caption>{{ t('globals.item') }}</QItemLabel>
}} <QItemLabel>{{ expedition.packagingItemFk }}</QItemLabel>
</QItemLabel> <QItemLabel caption>{{ t('ticket.boxing.worker') }}</QItemLabel>
<QItemLabel caption>{{ t('globals.item') }}</QItemLabel> <QItemLabel>{{ expedition.userName }}</QItemLabel>
<QItemLabel>{{ expedition.packagingItemFk }}</QItemLabel> </QItemSection>
<QItemLabel caption>{{ t('ticket.boxing.worker') }}</QItemLabel> </QItem>
<QItemLabel>{{ expedition.userName }}</QItemLabel> </QList>
</QItemSection>
</QItem>
</QList>
</QScrollArea>
</Teleport> </Teleport>
<QCard> <QCard>

View File

@ -37,6 +37,7 @@ const userParams = reactive({
ipt: 'H', ipt: 'H',
futureIpt: 'H', futureIpt: 'H',
isFullMovable: true, isFullMovable: true,
onlyWithDestination: true,
}); });
const ticketColumns = computed(() => [ const ticketColumns = computed(() => [
@ -441,6 +442,7 @@ watch(
<QPage class="column items-center q-pa-md"> <QPage class="column items-center q-pa-md">
<VnTable <VnTable
data-key="advanceTickets" data-key="advanceTickets"
:map-key="false"
ref="vnTableRef" ref="vnTableRef"
url="Tickets/getTicketsAdvance" url="Tickets/getTicketsAdvance"
search-url="advanceTickets" search-url="advanceTickets"
@ -464,6 +466,7 @@ watch(
color="primary" color="primary"
name="vn:agency-term" name="vn:agency-term"
size="xs" size="xs"
class="q-mr-xs"
> >
<QTooltip class="column"> <QTooltip class="column">
<span> <span>
@ -482,6 +485,14 @@ watch(
</span> </span>
</QTooltip> </QTooltip>
</QIcon> </QIcon>
<QIcon
v-if="row.saleClonedFk"
color="primary"
name="content_copy"
size="xs"
>
<QTooltip>{{ t('advanceTickets.clonedSales') }}</QTooltip>
</QIcon>
</template> </template>
<template #column-id="{ row }"> <template #column-id="{ row }">
<QBtn flat class="link"> <QBtn flat class="link">

View File

@ -168,6 +168,16 @@ onMounted(async () => await getItemPackingTypes());
</VnSelect> </VnSelect>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<QCheckbox
toggle-indeterminate
label="only with destination"
v-model="params.onlyWithDestination"
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -182,6 +192,7 @@ en:
ipt: Destination IPT ipt: Destination IPT
isFullMovable: 100% movable isFullMovable: 100% movable
warehouseFk: Warehouse warehouseFk: Warehouse
onlyWithDestination: Only with destination
es: es:
Horizontal: Horizontal Horizontal: Horizontal
Vertical: Vertical Vertical: Vertical
@ -193,4 +204,5 @@ es:
ipt: IPT destino ipt: IPT destino
isFullMovable: 100% movible isFullMovable: 100% movible
warehouseFk: Almacén warehouseFk: Almacén
onlyWithDestination: Solo con destino
</i18n> </i18n>

View File

@ -100,6 +100,7 @@ const columns = computed(() => [
component: null, component: null,
}, },
columnClass: 'expand', columnClass: 'expand',
cardVisible: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson), format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson),
}, },
{ {
@ -131,12 +132,14 @@ const columns = computed(() => [
name: 'nickname', name: 'nickname',
label: t('ticketList.nickname'), label: t('ticketList.nickname'),
columnClass: 'expand', columnClass: 'expand',
isTitle: true,
}, },
{ {
align: 'left', align: 'left',
name: 'addressNickname', name: 'addressNickname',
label: t('ticketList.addressNickname'), label: t('ticketList.addressNickname'),
columnClass: 'expand', columnClass: 'expand',
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',

View File

@ -53,6 +53,7 @@ advanceTickets:
errorsList: Errors list errorsList: Errors list
search: Search advance tickets search: Search advance tickets
searchInfo: Search advance tickets by ID or client ID searchInfo: Search advance tickets by ID or client ID
clonedSales: Has turn lines
futureTickets: futureTickets:
problems: Problems problems: Problems
shipped: Date shipped: Date

View File

@ -91,6 +91,7 @@ advanceTickets:
errorsList: Lista de errores errorsList: Lista de errores
search: Buscar por tickets adelantados search: Buscar por tickets adelantados
searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente searchInfo: Buscar tickets adelantados por el identificador o el identificador del cliente
clonedSales: Tiene líneas de turno
futureTickets: futureTickets:
problems: Problemas problems: Problemas
shipped: Fecha shipped: Fecha

View File

@ -1,15 +1,44 @@
<script setup> <script setup>
import VnCard from 'components/common/VnCard.vue'; import VnCard from 'components/common/VnCard.vue';
import TravelDescriptor from './TravelDescriptor.vue'; import TravelDescriptor from './TravelDescriptor.vue';
import filter from './TravelFilter.js'; import TravelFilter from '../TravelFilter.vue';
const filter = {
fields: [
'id',
'ref',
'shipped',
'landed',
'totalEntries',
'warehouseInFk',
'warehouseOutFk',
'cargoSupplierFk',
'agencyModeFk',
],
include: [
{
relation: 'warehouseIn',
scope: {
fields: ['name'],
},
},
{
relation: 'warehouseOut',
scope: {
fields: ['name'],
},
},
],
};
</script> </script>
<template> <template>
<VnCard <VnCard
data-key="Travel" data-key="Travel"
base-url="Travels" base-url="Travels"
:descriptor="TravelDescriptor"
:filter="filter"
search-data-key="TravelList" search-data-key="TravelList"
:filter="filter"
:descriptor="TravelDescriptor"
:filter-panel="TravelFilter"
:searchbar-props="{ :searchbar-props="{
url: 'Travels/filter', url: 'Travels/filter',
searchUrl: 'table', searchUrl: 'table',

View File

@ -8,7 +8,7 @@ import VnLv from 'src/components/ui/VnLv.vue';
import VnTitle from 'src/components/common/VnTitle.vue'; import VnTitle from 'src/components/common/VnTitle.vue';
import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue'; import EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import { toDate, toCurrency } from 'src/filters'; import { toDate, toCurrency } from 'src/filters';
import axios from 'axios'; import axios from 'axios';
@ -240,7 +240,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
data-key="TravelSummary" data-key="TravelSummary"
> >
<template #header> <template #header>
<span>{{ travel.ref }} - {{ travel.id }}</span> <span>{{ travel.id }} - {{ travel.ref }}</span>
</template> </template>
<template #body> <template #body>
@ -256,16 +256,20 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
:label="t('globals.warehouseOut')" :label="t('globals.warehouseOut')"
:value="travel.warehouseOut?.name" :value="travel.warehouseOut?.name"
/> />
<QCheckbox <VnRow>
:label="t('travel.basicData.isRaid')" <QCheckbox
v-model="travel.isRaid" :label="t('travel.basicData.isRaid')"
:disable="true" v-model="travel.isRaid"
/> :disable="true"
<QCheckbox />
:label="t('travel.summary.delivered')" </VnRow>
v-model="travel.isDelivered" <VnRow>
:disable="true" <QCheckbox
/> :label="t('travel.summary.delivered')"
v-model="travel.isDelivered"
:disable="true"
/>
</VnRow>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<QCardSection class="q-pa-none"> <QCardSection class="q-pa-none">
@ -320,7 +324,6 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QTd> <QTd>
<QCheckbox <QCheckbox
v-if="col.name === 'isConfirmed'" v-if="col.name === 'isConfirmed'"
:label="t('travel.summary.received')"
:true-value="1" :true-value="1"
:false-value="0" :false-value="0"
v-model="row[col.name]" v-model="row[col.name]"

View File

@ -27,7 +27,7 @@ defineExpose({ states });
<VnFilterPanel :data-key="props.dataKey" :search-button="true"> <VnFilterPanel :data-key="props.dataKey" :search-button="true">
<template #tags="{ tag, formatFn }"> <template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs"> <div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong> <strong>{{ t(`travel.${tag.label}`) }}: </strong>
<span>{{ formatFn(tag.value) }}</span> <span>{{ formatFn(tag.value) }}</span>
</div> </div>
</template> </template>
@ -77,7 +77,6 @@ defineExpose({ states });
:label="t('travel.shipped')" :label="t('travel.shipped')"
v-model="params.shipped" v-model="params.shipped"
@update:model-value="searchFn()" @update:model-value="searchFn()"
dense
outlined outlined
rounded rounded
/> />
@ -125,7 +124,7 @@ defineExpose({ states });
is-outlined is-outlined
/> />
<VnInput <VnInput
:label="t('travel.travelList.tableVisibleColumns.daysOnward')" :label="t('travel.daysOnward')"
v-model="params.daysOnward" v-model="params.daysOnward"
lazy-rules lazy-rules
is-outlined is-outlined
@ -148,16 +147,18 @@ en:
landed: Landed landed: Landed
landingHour: Landing Hour landingHour: Landing Hour
totalEntries: Σ totalEntries: Σ
daysOnward: Days Onward
es: es:
travel: travel:
Id: Id Id: Id
ref: Referencia ref: Referencia
agency: Agencia agency: Agencia
warehouseInFk: Alm.Salida warehouseInFk: Alm.Entrada
shipped: F.Envío shipped: F.Envío
shipmentHour: Hora de envío shipmentHour: Hora de envío
warehouseOut: Alm.Entrada warehouseOut: Alm.Entrada
landed: F.Entrega landed: F.Entrega
landingHour: Hora de entrega landingHour: Hora de entrega
totalEntries: Σ totalEntries: Σ
daysOnward: Días en adelante
</i18n> </i18n>

View File

@ -1,8 +1,7 @@
<script setup> <script setup>
import { onMounted, ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { useStateStore } from 'stores/useStateStore';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import TravelSummary from './Card/TravelSummary.vue'; import TravelSummary from './Card/TravelSummary.vue';
@ -11,11 +10,11 @@ import { toDate } from 'src/filters';
import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js'; import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
import TravelFilter from './TravelFilter.vue'; import TravelFilter from './TravelFilter.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const router = useRouter(); const router = useRouter();
const { t } = useI18n(); const { t } = useI18n();
const stateStore = useStateStore();
const route = useRoute(); const route = useRoute();
const tableRef = ref(); const tableRef = ref();
const $props = defineProps({ const $props = defineProps({
@ -26,11 +25,6 @@ const $props = defineProps({
}); });
const entityId = computed(() => $props.id || route.params.id); const entityId = computed(() => $props.id || route.params.id);
const travelFilterRef = ref();
onMounted(async () => {
stateStore.rightDrawer = true;
});
const cloneTravel = (travelData) => { const cloneTravel = (travelData) => {
const stringifiedTravelData = JSON.stringify(travelData); const stringifiedTravelData = JSON.stringify(travelData);
redirectToCreateView(stringifiedTravelData); redirectToCreateView(stringifiedTravelData);
@ -52,9 +46,11 @@ const columns = computed(() => [
{ {
align: 'left', align: 'left',
name: 'id', name: 'id',
label: t('globals.id'), label: 'Id',
chip: {
condition: () => true,
},
isId: true, isId: true,
cardVisible: true,
}, },
{ {
align: 'left', align: 'left',
@ -64,7 +60,7 @@ const columns = computed(() => [
columnField: { columnField: {
component: null, component: null,
}, },
cardVisible: true, isTitle: true,
create: true, create: true,
}, },
{ {
@ -103,14 +99,14 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'shipped',
label: t('globals.shipped'), label: t('globals.shipped'),
name: 'shipped',
create: true,
cardVisible: true,
component: 'date', component: 'date',
columnField: { columnField: {
component: null, component: null,
}, },
cardVisible: true,
create: true,
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)), format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)),
}, },
{ {
@ -143,7 +139,6 @@ const columns = computed(() => [
columnField: { columnField: {
component: null, component: null,
}, },
cardVisible: true,
create: true, create: true,
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)), format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
}, },
@ -201,7 +196,7 @@ const columns = computed(() => [
/> />
<RightMenu> <RightMenu>
<template #right-panel> <template #right-panel>
<TravelFilter data-key="TravelList" ref="travelFilterRef" /> <TravelFilter data-key="TravelList" />
</template> </template>
</RightMenu> </RightMenu>
<VnTable <VnTable
@ -221,7 +216,6 @@ const columns = computed(() => [
:user-params="{ daysOnward: 7 }" :user-params="{ daysOnward: 7 }"
order="landed DESC" order="landed DESC"
:columns="columns" :columns="columns"
auto-load
:is-editable="false" :is-editable="false"
> >
<template #column-status="{ row }"> <template #column-status="{ row }">
@ -280,7 +274,6 @@ const columns = computed(() => [
</template> </template>
</VnTable> </VnTable>
</template> </template>
<i18n> <i18n>
en: en:
Add entry: Add entry Add entry: Add entry
@ -294,7 +287,6 @@ es:
Clone: Clonar Clone: Clonar
Add entry: Añadir Entrada Add entry: Añadir Entrada
</i18n> </i18n>
<style lang="scss" scoped> <style lang="scss" scoped>
.is-active { .is-active {
color: #c8e484; color: #c8e484;

View File

@ -98,9 +98,7 @@ async function remove(row) {
url="Wagons" url="Wagons"
:filter="filter" :filter="filter"
:columns="columns" :columns="columns"
auto-load
order="id DESC" order="id DESC"
:right-search="false"
:column-search="false" :column-search="false"
:default-mode="'card'" :default-mode="'card'"
:disable-option="{ table: true }" :disable-option="{ table: true }"

View File

@ -103,9 +103,12 @@ const formattedWeekTotalHours = computed(() =>
const onInputChange = async (date) => { const onInputChange = async (date) => {
if (!date) return; if (!date) return;
const { year, month, day } = date.scope.timestamp; const { timestamp, outside } = date.scope;
const { year, month, day } = timestamp;
const _date = new Date(year, month - 1, day); const _date = new Date(year, month - 1, day);
setDate(_date); setDate(_date);
if (outside) getMailStates(_date);
}; };
const setDate = async (date) => { const setDate = async (date) => {

View File

@ -107,6 +107,7 @@ const columns = computed(() => [
title: t('components.smartCard.viewSummary'), title: t('components.smartCard.viewSummary'),
icon: 'preview', icon: 'preview',
action: (row) => viewSummary(row.id, WorkerSummary), action: (row) => viewSummary(row.id, WorkerSummary),
isPrimary: true,
}, },
], ],
}, },

View File

@ -30,17 +30,15 @@ const warehousesOptions = ref([]);
> >
<template #form-inputs> <template #form-inputs>
<VnRow> <VnRow>
<div class="col"> <VnSelect
<VnSelect :label="t('list.warehouse')"
:label="t('list.warehouse')" v-model="ZoneWarehouseFormData.warehouseFk"
v-model="ZoneWarehouseFormData.warehouseFk" :options="warehousesOptions"
:options="warehousesOptions" option-value="id"
option-value="id" option-label="name"
option-label="name" hide-selected
hide-selected :required="true"
:required="true" />
/>
</div>
</VnRow> </VnRow>
</template> </template>
</FormPopup> </FormPopup>

View File

@ -1,7 +1,7 @@
<script setup> <script setup>
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { computed, ref, onMounted } from 'vue'; import { computed, ref } from 'vue';
import axios from 'axios'; import axios from 'axios';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
@ -9,7 +9,6 @@ import { toTimeFormat } from 'src/filters/date';
import { useVnConfirm } from 'composables/useVnConfirm'; import { useVnConfirm } from 'composables/useVnConfirm';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { useStateStore } from 'stores/useStateStore';
import ZoneSummary from 'src/pages/Zone/Card/ZoneSummary.vue'; import ZoneSummary from 'src/pages/Zone/Card/ZoneSummary.vue';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
@ -24,7 +23,6 @@ const router = useRouter();
const { notify } = useNotify(); const { notify } = useNotify();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const { openConfirmationModal } = useVnConfirm(); const { openConfirmationModal } = useVnConfirm();
const stateStore = useStateStore();
const tableRef = ref(); const tableRef = ref();
const warehouseOptions = ref([]); const warehouseOptions = ref([]);
@ -131,8 +129,6 @@ const handleClone = (id) => {
() => clone(id) () => clone(id)
); );
}; };
onMounted(() => (stateStore.rightDrawer = true));
</script> </script>
<template> <template>
@ -156,7 +152,6 @@ onMounted(() => (stateStore.rightDrawer = true));
:columns="columns" :columns="columns"
redirect="zone" redirect="zone"
:right-search="false" :right-search="false"
auto-load
> >
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
<VnSelect <VnSelect

View File

@ -25,7 +25,7 @@ export default {
path: 'list', path: 'list',
name: 'ShelvingList', name: 'ShelvingList',
meta: { meta: {
title: 'shelvingList', title: 'list',
icon: 'view_list', icon: 'view_list',
}, },
component: () => import('src/pages/Shelving/ShelvingList.vue'), component: () => import('src/pages/Shelving/ShelvingList.vue'),

View File

@ -25,7 +25,7 @@ export default {
path: 'list', path: 'list',
name: 'WagonList', name: 'WagonList',
meta: { meta: {
title: 'wagonsList', title: 'list',
icon: 'vn:trolley', icon: 'vn:trolley',
}, },
component: () => import('src/pages/Wagon/WagonList.vue'), component: () => import('src/pages/Wagon/WagonList.vue'),

View File

@ -38,7 +38,7 @@ export default {
name: 'ZoneList', name: 'ZoneList',
meta: { meta: {
title: 'zonesList', title: 'zonesList',
icon: 'vn:zone', icon: 'view_list',
}, },
component: () => import('src/pages/Zone/ZoneList.vue'), component: () => import('src/pages/Zone/ZoneList.vue'),
}, },

View File

@ -19,7 +19,7 @@ export const useInvoiceOutGlobalStore = defineStore({
maxShipped: null, maxShipped: null,
clientId: null, clientId: null,
printer: null, printer: null,
serialType: null, serialType: 'global',
}, },
addresses: [], addresses: [],
minInvoicingDate: null, minInvoicingDate: null,
@ -41,7 +41,6 @@ export const useInvoiceOutGlobalStore = defineStore({
async fetchAllData() { async fetchAllData() {
try { try {
const userInfo = await useUserConfig().fetch();
const date = Date.vnNew(); const date = Date.vnNew();
this.formInitialData.maxShipped = new Date( this.formInitialData.maxShipped = new Date(
date.getFullYear(), date.getFullYear(),
@ -53,7 +52,7 @@ export const useInvoiceOutGlobalStore = defineStore({
await Promise.all([ await Promise.all([
this.fetchParallelism(), this.fetchParallelism(),
this.fetchInvoiceOutConfig(userInfo.companyFk), this.fetchInvoiceOutConfig(),
]); ]);
this.initialDataLoading = false; this.initialDataLoading = false;
@ -62,21 +61,23 @@ export const useInvoiceOutGlobalStore = defineStore({
} }
}, },
async fetchInvoiceOutConfig(companyFk) { async fetchInvoiceOutConfig(formData = this.formInitialData) {
try { try {
this.formInitialData.companyFk = companyFk; const userInfo = await useUserConfig().fetch();
const params = { companyFk: companyFk }; const params = {
companyFk: userInfo.companyFk,
serialType: formData.serialType,
};
const { data } = await axios.get('InvoiceOuts/getInvoiceDate', { const { data } = await axios.get('InvoiceOuts/getInvoiceDate', {
params, params,
}); });
const stringDate = data.issued.substring(0, 10); this.minInvoicingDate = data?.issued
this.minInvoicingDate = stringDate; ? new Date(data.issued)
this.formInitialData.invoiceDate = stringDate; : Date.vnNew();
this.minInvoicingDate = new Date(data.issued);
this.formInitialData.invoiceDate = this.minInvoicingDate; this.formInitialData.invoiceDate = this.minInvoicingDate;
formData.invoiceDate = this.minInvoicingDate;
} catch (err) { } catch (err) {
console.error('Error fetching invoice out global initial data'); console.error('Error fetching invoice out global initial data');
throw new Error(); throw new Error();

View File

@ -17,6 +17,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
searchUrl: 'params', searchUrl: 'params',
navigate: null, navigate: null,
page: 1, page: 1,
mapKey: 'id',
}; };
function get(key) { function get(key) {
@ -46,6 +47,7 @@ export const useArrayDataStore = defineStore('arrayDataStore', () => {
function getDefaultState() { function getDefaultState() {
return Object.assign(JSON.parse(JSON.stringify(defaultOpts)), { return Object.assign(JSON.parse(JSON.stringify(defaultOpts)), {
data: ref(), data: ref(),
map: ref(new Map()),
}); });
} }

View File

@ -15,6 +15,10 @@ export const useStateStore = defineStore('stateStore', () => {
rightDrawer.value = !rightDrawer.value; rightDrawer.value = !rightDrawer.value;
} }
function rightDrawerChangeValue(value) {
rightDrawer.value = value;
}
function toggleSubToolbar() { function toggleSubToolbar() {
subToolbar.value = !subToolbar.value; subToolbar.value = !subToolbar.value;
} }
@ -50,5 +54,6 @@ export const useStateStore = defineStore('stateStore', () => {
isRightDrawerShown, isRightDrawerShown,
isSubToolbarShown, isSubToolbarShown,
toggleSubToolbar, toggleSubToolbar,
rightDrawerChangeValue,
}; };
}); });

View File

@ -3,6 +3,8 @@ describe('ClaimDevelopment', () => {
const claimId = 1; const claimId = 1;
const firstLineReason = 'tbody > :nth-child(1) > :nth-child(2)'; const firstLineReason = 'tbody > :nth-child(1) > :nth-child(2)';
const thirdRow = 'tbody > :nth-child(3)'; const thirdRow = 'tbody > :nth-child(3)';
const lastReason = 'Incompetencia';
const newReason = 'Calor';
beforeEach(() => { beforeEach(() => {
cy.viewport(1920, 1080); cy.viewport(1920, 1080);
@ -14,22 +16,22 @@ describe('ClaimDevelopment', () => {
}); });
it('should reset line', () => { it('should reset line', () => {
cy.selectOption(firstLineReason, 'Novato'); cy.selectOption(firstLineReason, newReason);
cy.resetCard(); cy.resetCard();
cy.getValue(firstLineReason).should('equal', 'Prisas'); cy.getValue(firstLineReason).should('equal', lastReason);
}); });
it('should edit line', () => { it('should edit line', () => {
cy.selectOption(firstLineReason, 'Novato'); cy.selectOption(firstLineReason, newReason);
cy.saveCard(); cy.saveCard();
cy.login('developer'); cy.login('developer');
cy.visit(`/#/claim/${claimId}/development`); cy.visit(`/#/claim/${claimId}/development`);
cy.getValue(firstLineReason).should('equal', 'Novato'); cy.getValue(firstLineReason).should('equal', newReason);
//Restart data //Restart data
cy.selectOption(firstLineReason, 'Prisas'); cy.selectOption(firstLineReason, lastReason);
cy.saveCard(); cy.saveCard();
}); });
@ -42,7 +44,7 @@ describe('ClaimDevelopment', () => {
const rowData = [ const rowData = [
false, false,
'Novato', newReason,
'Roces', 'Roces',
'Compradores', 'Compradores',
'administrativeNick', 'administrativeNick',

View File

@ -16,7 +16,7 @@ describe('Client list', () => {
}); });
it('Client list create new client', () => { it('Client list create new client', () => {
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); cy.addBtnClick();
const randomInt = Math.floor(Math.random() * 90) + 10; const randomInt = Math.floor(Math.random() * 90) + 10;
const data = { const data = {
@ -26,8 +26,8 @@ describe('Client list', () => {
'Web user': { val: `user_test_${randomInt}` }, 'Web user': { val: `user_test_${randomInt}` },
Street: { val: `C/ STREET ${randomInt}` }, Street: { val: `C/ STREET ${randomInt}` },
Email: { val: `user.test${randomInt}@cypress.com` }, Email: { val: `user.test${randomInt}@cypress.com` },
'Sales person': { val: 'employee', type: 'select' }, 'Sales person': { val: 'salesPerson', type: 'select' },
Location: { val: '46000, Valencia(Province one), España', type: 'select' }, Location: { val: '46000', type: 'select' },
'Business type': { val: 'Otros', type: 'select' }, 'Business type': { val: 'Otros', type: 'select' },
}; };
cy.fillInForm(data); cy.fillInForm(data);

View File

@ -11,7 +11,7 @@ describe('EntryStockBought', () => {
cy.get('.q-notification__message').should('have.text', 'Data saved'); cy.get('.q-notification__message').should('have.text', 'Data saved');
}); });
it('Should add a new reserved space for buyerBoss', () => { it('Should add a new reserved space for buyerBoss', () => {
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click(); cy.addBtnClick();
cy.get('input[aria-label="Reserve"]').type('1'); 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).clear();
cy.get('input[aria-label="Date"]').eq(1).type('01-01'); cy.get('input[aria-label="Date"]').eq(1).type('01-01');

View File

@ -2,7 +2,7 @@
describe('InvoiceInIntrastat', () => { describe('InvoiceInIntrastat', () => {
const firstRow = 'tbody > :nth-child(1)'; const firstRow = 'tbody > :nth-child(1)';
const thirdRow = 'tbody > :nth-child(3)'; const thirdRow = 'tbody > :nth-child(3)';
const firstRowCode = `${firstRow} > :nth-child(2)`; const codes = `[data-cy="intrastat-code"]`;
const firstRowAmount = `${firstRow} > :nth-child(3)`; const firstRowAmount = `${firstRow} > :nth-child(3)`;
beforeEach(() => { beforeEach(() => {
@ -11,13 +11,12 @@ describe('InvoiceInIntrastat', () => {
}); });
it('should edit the first line', () => { it('should edit the first line', () => {
cy.selectOption(firstRowCode, 'Plantas vivas: Esqueje/injerto, Vid'); cy.selectOption(`${firstRow} ${codes}`, 'Plantas vivas: Esqueje/injerto, Vid');
cy.get(firstRowAmount).clear(); cy.get(firstRowAmount).clear();
cy.saveCard(); cy.saveCard();
cy.get(`${firstRowCode} span`).should( cy.get(codes)
'have.text', .eq(0)
'6021010:Plantas vivas: Esqueje/injerto, Vid' .should('have.value', '6021010: Plantas vivas: Esqueje/injerto, Vid');
);
}); });
it('should add a new row', () => { it('should add a new row', () => {

View File

@ -1,7 +1,7 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
describe('InvoiceInList', () => { describe('InvoiceInList', () => {
const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)'; const firstRow = 'tbody.q-virtual-scroll__content tr:nth-child(1)';
const firstId = `${firstRow} > td:nth-child(1) span`; const firstId = `${firstRow} > td:nth-child(2) span`;
const firstDetailBtn = `${firstRow} .q-btn:nth-child(1)`; const firstDetailBtn = `${firstRow} .q-btn:nth-child(1)`;
const summaryHeaders = '.summaryBody .header-link'; const summaryHeaders = '.summaryBody .header-link';

Some files were not shown because too many files have changed in this diff Show More