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",
"version": "24.52.0",
"version": "25.02.0",
"description": "Salix frontend",
"productName": "Salix",
"author": "Verdnatura",

View File

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

View File

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

View File

@ -17,12 +17,10 @@ const stateQuery = useStateQueryStore();
const state = useState();
const user = state.getUser();
const appName = 'Lilium';
const pinnedModulesRef = ref();
onMounted(() => stateStore.setMounted());
const pinnedModulesRef = ref();
</script>
<template>
<QHeader color="white" elevated>
<QToolbar class="q-py-sm q-px-md">
@ -65,16 +63,6 @@ const pinnedModulesRef = ref();
<QSpace />
<div class="q-pl-sm q-gutter-sm row items-center no-wrap">
<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
:class="{ 'q-pa-none': quasar.platform.is.mobile }"
id="pinnedModules"
@ -106,7 +94,6 @@ const pinnedModulesRef = ref();
<VnBreadcrumbs v-if="$q.screen.lt.md" class="q-ml-md" />
</QHeader>
</template>
<style lang="scss" scoped>
.searchbar {
width: max-content;
@ -115,9 +102,3 @@ const pinnedModulesRef = ref();
background-color: var(--vn-section-color);
}
</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) {
const query = `/VnUsers/${user.value.id}`;
try {
await axios.patch(query, {
lang: value,
});
await axios.patch(query, { lang: value });
user.value.lang = value;
useState().setUser(user.value);
onDataSaved();
} catch (error) {
onDataError();

View File

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

View File

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

View File

@ -106,7 +106,7 @@ const manageDate = (date) => {
:class="{ required: isRequired }"
:rules="mixinRules"
:clearable="false"
@click="isPopupOpen = true"
@click="isPopupOpen = !isPopupOpen"
hide-bottom-space
>
<template #append>
@ -125,13 +125,6 @@ const manageDate = (date) => {
isPopupOpen = false;
"
/>
<QIcon
v-if="showEvent"
name="event"
class="cursor-pointer"
@click="isPopupOpen = !isPopupOpen"
:title="t('Open date')"
/>
</template>
<QMenu
v-if="$q.screen.gt.xs"
@ -151,15 +144,6 @@ const manageDate = (date) => {
</QInput>
</div>
</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>
es:
Open date: Abrir fecha

View File

@ -1,13 +1,28 @@
<script setup>
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 $attrs = useAttrs();
const step = ref($attrs.step || 0.01);
</script>
<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>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ import { useRoute } from 'vue-router';
import toDate from 'filters/toDate';
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
const { t } = useI18n();
const { t, te } = useI18n();
const $props = defineProps({
modelValue: {
type: Object,
@ -228,6 +228,14 @@ function sanitizer(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>
<template>
@ -277,7 +285,12 @@ function sanitizer(params) {
@remove="remove(chip.label)"
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">
<strong>{{ chip.label }}:</strong>
<span>"{{ formatValue(chip.value) }}"</span>
@ -290,6 +303,7 @@ function sanitizer(params) {
:params="userParams"
:tags="customTags"
:format-fn="formatValue"
:get-locale="getLocale"
:search-fn="search"
/>
</div>
@ -297,7 +311,12 @@ function sanitizer(params) {
<QSeparator />
</QList>
<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>
</QForm>
<QInnerLoading

View File

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

View File

@ -74,6 +74,10 @@ const props = defineProps({
type: Boolean,
default: false,
},
mapKey: {
type: String,
default: '',
},
});
const emit = defineEmits(['onFetch', 'onPaginate', 'onChange']);
@ -96,6 +100,7 @@ const arrayData = useArrayData(props.dataKey, {
exprBuilder: props.exprBuilder,
keepOpts: props.keepOpts,
searchUrl: props.searchUrl,
mapKey: props.mapKey,
});
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';
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);
return 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',
'searchUrl',
'navigate',
'mapKey',
];
if (typeof userOptions === 'object') {
for (const option in userOptions) {
@ -119,17 +120,12 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
const { limit } = filter;
store.hasMoreData = limit && response.data.length >= limit;
if (append) {
if (!store.data) store.data = [];
for (const row of response.data) store.data.push(row);
} else {
store.data = response.data;
if (!isDialogOpened()) updateRouter && updateStateParams();
}
processData(response.data, { map: !!store.mapKey, append });
if (!append && !isDialogOpened()) updateRouter && updateStateParams();
store.isLoading = false;
canceller = null;
return response;
}
@ -288,6 +284,31 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
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 isLoading = computed(() => store.isLoading || false);

View File

@ -11,6 +11,7 @@ body.body--light {
--vn-text-color: var(--font-color);
--vn-label-color: #5f5f5f;
--vn-accent-color: #e7e3e3;
--vn-empty-tag: #acacac;
background-color: var(--vn-page-color);
@ -26,6 +27,7 @@ body.body--dark {
--vn-text-color: white;
--vn-label-color: #a8a8a8;
--vn-accent-color: #424242;
--vn-empty-tag: #2d2d2d;
background-color: var(--vn-page-color);
}
@ -240,7 +242,7 @@ input::-webkit-inner-spin-button {
.q-table {
th,
td {
padding: 1px 10px 1px 10px;
padding: 1px 3px 1px 3px;
max-width: 130px;
div span {
overflow: hidden;
@ -296,3 +298,20 @@ input::-webkit-inner-spin-button {
.no-visible {
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
modes: Modes
zones: Zones
zonesList: Zones
zonesList: List
deliveryDays: Delivery days
upcomingDeliveries: Upcoming deliveries
role: Role
@ -333,11 +333,23 @@ globals:
packing: ITP
myTeam: My team
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
companyFk: Company
changePass: Change password
deleteConfirmTitle: Delete selected elements
changeState: Change state
raid: 'Raid {daysInForward} days'
isVies: Vies
errors:
statusUnauthorized: Access denied
statusInternalServerError: An internal server error has ocurred
@ -731,7 +743,6 @@ supplier:
sageTransactionTypeFk: Sage transaction type
supplierActivityFk: Supplier activity
isTrucker: Trucker
isVies: Vies
billingData:
payMethodFk: Billing data
payDemFk: Payment deadline

View File

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

View File

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

View File

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

View File

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

View File

@ -110,7 +110,7 @@ function handleLocation(data, location) {
<VnRow>
<QCheckbox :label="t('Has to invoice')" v-model="data.hasToInvoice" />
<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">
<QTooltip>
{{ t('whenActivatingIt') }}
@ -169,7 +169,6 @@ es:
Active: Activo
Frozen: Congelado
Has to invoice: Factura
Vies: Vies
Notify by email: Notificar vía e-mail
Invoice by address: Facturar por consignatario
Is equalizated: Recargo de equivalencia

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,6 +25,7 @@ const banks = ref([]);
const invoiceInFormRef = ref();
const invoiceId = +route.params.id;
const filter = { where: { invoiceInFk: invoiceId } };
const areRows = ref(false);
const columns = computed(() => [
{
@ -143,8 +144,6 @@ async function insert() {
}"
:disable="!isNotEuro(currency)"
v-model="row.foreignValue"
clearable
clear-icon="close"
/>
</QTd>
</template>
@ -230,7 +229,14 @@ async function insert() {
</template>
</CrudModel>
<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>
</template>
<style lang="scss" scoped>

View File

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

View File

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

View File

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

View File

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

View File

@ -1,41 +1,66 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnSelect from 'components/common/VnSelect.vue';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
import FetchData from 'components/FetchData.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 } });
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>
<template>
<FetchData
url="SupplierActivities"
auto-load
@on-fetch="(data) => (activities = data)"
/>
<VnFilterPanel :data-key="dataKey" :search-button="true">
<template #tags="{ tag, formatFn }">
<VnFilterPanel :data-key="dataKey" :search-button="true" :hidden-tags="['daysAgo']">
<template #tags="{ tag, formatFn, getLocale }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>
<strong>{{ getLocale(tag.label) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
<template #body="{ params, searchFn }">
<template #body="{ params, searchFn, getLocale }">
<QItem>
<QItemSection>
<VnInputDate :label="t('From')" v-model="params.from" is-outlined />
<VnInputDate
:label="$t('globals.from')"
v-model="params.from"
is-outlined
/>
</QItemSection>
</QItem>
<QItem>
<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>
</QItem>
<QItem>
@ -44,20 +69,18 @@ const activities = ref([]);
v-model="params.supplierFk"
url="Suppliers"
:fields="['id', 'nickname']"
:label="t('params.supplierFk')"
option-value="id"
:label="getLocale('supplierFk')"
option-label="nickname"
dense
outlined
rounded
:filter-options="['id', 'name']"
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<VnInput
:label="t('params.supplierRef')"
:label="getLocale('supplierRef')"
v-model="params.supplierRef"
is-outlined
lazy-rules
@ -67,7 +90,7 @@ const activities = ref([]);
<QItem>
<QItemSection>
<VnInput
:label="t('params.fi')"
:label="getLocale('fi')"
v-model="params.fi"
is-outlined
lazy-rules
@ -77,7 +100,7 @@ const activities = ref([]);
<QItem>
<QItemSection>
<VnInput
:label="t('params.serial')"
:label="getLocale('serial')"
v-model="params.serial"
is-outlined
lazy-rules
@ -87,7 +110,7 @@ const activities = ref([]);
<QItem>
<QItemSection>
<VnInput
:label="t('params.account')"
:label="getLocale('account')"
v-model="params.account"
is-outlined
lazy-rules
@ -97,7 +120,7 @@ const activities = ref([]);
<QItem>
<QItemSection>
<VnInput
:label="t('params.awb')"
:label="getLocale('globals.params.awbCode')"
v-model="params.awbCode"
is-outlined
lazy-rules
@ -107,24 +130,34 @@ const activities = ref([]);
<QItem>
<QItemSection>
<VnInputNumber
:label="t('Amount')"
:label="$t('globals.amount')"
v-model="params.amount"
is-outlined
/>
</QItemSection>
</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>
<QItemSection>
<QCheckbox
:label="t('invoiceIn.isBooked')"
:label="$t('InvoiceIn.isBooked')"
v-model="params.isBooked"
@update:model-value="searchFn()"
toggle-indeterminate
/>
</QItemSection>
<QItemSection>
<QCheckbox
:label="t('params.correctingFk')"
:label="getLocale('params.correctingFk')"
v-model="params.correctingFk"
@update:model-value="searchFn()"
toggle-indeterminate
@ -134,54 +167,3 @@ const activities = ref([]);
</template>
</VnFilterPanel>
</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>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { useState } from 'src/composables/useState';
import { downloadFile } from 'src/composables/downloadFile';
import { toDate, toCurrency } from 'src/filters/index';
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 VnInput from 'src/components/common/VnInput.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 { t } = useI18n();
onMounted(async () => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
const tableRef = ref();
const companies = ref([]);
const cols = computed(() => [
{
align: 'left',
name: 'isBooked',
label: t('InvoiceIn.isBooked'),
columnFilter: false,
},
{
align: 'left',
name: 'id',
label: 'Id',
isId: true,
chip: {
condition: () => true,
},
},
{
align: 'left',
name: 'supplierFk',
label: t('invoiceIn.list.supplier'),
label: t('InvoiceIn.list.supplier'),
columnFilter: {
component: 'select',
attrs: {
@ -41,20 +50,21 @@ const cols = computed(() => [
},
},
columnClass: 'expand',
cardVisible: true,
},
{
align: 'left',
name: 'supplierRef',
label: t('invoiceIn.list.supplierRef'),
label: t('InvoiceIn.list.supplierRef'),
},
{
align: 'left',
name: 'serial',
label: t('invoiceIn.serial'),
label: t('InvoiceIn.serial'),
},
{
align: 'left',
label: t('invoiceIn.list.issued'),
label: t('InvoiceIn.list.issued'),
name: 'issued',
component: null,
columnFilter: {
@ -64,20 +74,52 @@ const cols = computed(() => [
},
{
align: 'left',
name: 'isBooked',
label: t('invoiceIn.isBooked'),
columnFilter: false,
label: t('InvoiceIn.list.dueDated'),
name: 'dueDated',
component: null,
columnFilter: {
component: 'date',
},
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.dueDated)),
cardVisible: true,
},
{
align: 'left',
name: 'awbCode',
label: t('invoiceIn.list.awb'),
label: t('InvoiceIn.list.awb'),
},
{
align: 'left',
name: 'amount',
label: t('invoiceIn.list.amount'),
label: t('InvoiceIn.list.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',
@ -87,6 +129,7 @@ const cols = computed(() => [
title: t('components.smartCard.openSummary'),
icon: 'preview',
type: 'submit',
isPrimary: true,
action: (row) => viewSummary(row.id, InvoiceInSummary),
},
{
@ -101,6 +144,7 @@ const cols = computed(() => [
]);
</script>
<template>
<FetchData url="Companies" @on-fetch="(data) => (companies = data)" auto-load />
<InvoiceInSearchbar />
<RightMenu>
<template #right-panel>
@ -116,7 +160,7 @@ const cols = computed(() => [
urlCreate: 'InvoiceIns',
title: t('globals.createInvoiceIn'),
onDataSaved: ({ id }) => tableRef.redirect(id),
formInitialData: {},
formInitialData: { companyFk: user.companyFk, issued: Date.vnNew() },
}"
redirect="invoice-in"
:columns="cols"
@ -151,7 +195,7 @@ const cols = computed(() => [
</template>
</VnSelect>
<VnInput
:label="t('invoiceIn.list.supplierRef')"
:label="t('InvoiceIn.list.supplierRef')"
v-model="data.supplierRef"
/>
<VnSelect
@ -163,7 +207,7 @@ const cols = computed(() => [
option-label="code"
:required="true"
/>
<VnInputDate :label="t('invoiceIn.summary.issued')" v-model="data.issued" />
<VnInputDate :label="t('InvoiceIn.summary.issued')" v-model="data.issued" />
</template>
</VnTable>
</template>

View File

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

View File

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

View File

@ -1,4 +1,4 @@
invoiceIn:
InvoiceIn:
serial: Serial
isBooked: Is booked
list:
@ -7,8 +7,11 @@ invoiceIn:
supplierRef: Supplier ref.
file: File
issued: Issued
dueDated: Due dated
awb: AWB
amount: Amount
descriptor:
ticketList: Ticket list
card:
client: Client
company: Company
@ -39,3 +42,9 @@ invoiceIn:
net: Net
stems: Stems
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
isBooked: Contabilizada
list:
ref: Referencia
supplier: Proveedor
supplierRef: Ref. proveedor
shortIssued: F. emisión
issued: F. emisión
dueDated: F. vencimiento
file: Fichero
issued: Fecha emisión
awb: AWB
amount: Importe
descriptor:
ticketList: Listado de tickets
card:
client: Cliente
company: Empresa
@ -38,3 +40,8 @@ invoiceIn:
net: Neto
stems: Tallos
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
:label="t('invoiceOutSerialType')"
v-model="formData.serialType"
@update:model-value="
invoiceOutGlobalStore.fetchInvoiceOutConfig(formData)
"
:options="serialTypesOptions"
option-value="type"
option-label="type"

View File

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

View File

@ -361,7 +361,7 @@ function handleOnDataSave({ CrudModelRef }) {
@on-fetch="(data) => (warehousesOptions = data)"
auto-load
url="Warehouses"
:filter="{ fields: ['id', 'name'], order: 'name ASC', limit: 30 }"
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
/>
<RightMenu>
<template #right-panel>
@ -394,191 +394,186 @@ function handleOnDataSave({ CrudModelRef }) {
/>
</template>
</VnSubToolbar>
<QPage>
<VnTable
@on-fetch="
(data) =>
data.forEach((item) => {
item.hasMinPrice = `${item.hasMinPrice !== 0}`;
})
"
:default-remove="false"
:default-reset="false"
:default-save="false"
data-key="ItemFixedPrices"
url="FixedPrices/filter"
:order="['itemFk DESC', 'name DESC']"
save-url="FixedPrices/crud"
ref="tableRef"
dense
:filter="{
where: {
warehouseFk: user.warehouseFk,
},
}"
:columns="columns"
default-mode="table"
auto-load
:is-editable="true"
:right-search="false"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
:crud-model="{
disableInfiniteScroll: true,
}"
v-model:selected="rowsSelected"
:create-as-dialog="false"
:create="{
onDataSaved: handleOnDataSave,
}"
:use-model="true"
:disable-option="{ card: true }"
>
<template #header-selection="scope">
<QCheckbox v-model="scope.selected" />
</template>
<template #body-selection="scope">
{{ scope }}
<QCheckbox flat v-model="scope.selected" />
</template>
<VnTable
@on-fetch="
(data) =>
data.forEach((item) => {
item.hasMinPrice = `${item.hasMinPrice !== 0}`;
})
"
:default-remove="false"
:default-reset="false"
:default-save="false"
data-key="ItemFixedPrices"
url="FixedPrices/filter"
:order="['itemFk DESC', 'name DESC']"
save-url="FixedPrices/crud"
ref="tableRef"
dense
:filter="{
where: {
warehouseFk: user.warehouseFk,
},
}"
:columns="columns"
default-mode="table"
auto-load
:is-editable="true"
:right-search="false"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
:use-model="true"
v-model:selected="rowsSelected"
:create-as-dialog="false"
:create="{
onDataSaved: handleOnDataSave,
}"
:disable-option="{ card: true }"
>
<template #header-selection="scope">
<QCheckbox v-model="scope.selected" />
</template>
<template #body-selection="scope">
{{ scope }}
<QCheckbox flat v-model="scope.selected" />
</template>
<template #column-itemFk="props">
<VnSelect
style="max-width: 100px"
url="Items/withName"
hide-selected
option-label="id"
option-value="id"
v-model="props.row.itemFk"
v-on="getRowUpdateInputEvents(props, true, 'select')"
<template #column-itemFk="props">
<VnSelect
style="max-width: 100px"
url="Items/withName"
hide-selected
option-label="id"
option-value="id"
v-model="props.row.itemFk"
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">
<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" />
</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 #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')"
<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'"
/>
</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()"
<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))"
/>
</QDialog>
</QPage>
</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>
</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>
<style lang="scss">
.q-table th,

View File

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

View File

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

View File

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

View File

@ -1,20 +1,22 @@
<script setup>
import axios from 'axios';
import { useI18n } from 'vue-i18n';
import { computed, ref, onMounted } from 'vue';
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 { 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 VnInputDate from 'src/components/common/VnInputDate.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 { viewSummary } = useSummaryDialog();
@ -171,9 +173,9 @@ const getDateColor = (date) => {
today.setHours(0, 0, 0, 0);
const timeTicket = new Date(date);
timeTicket.setHours(0, 0, 0, 0);
const comparation = today - timeTicket;
if (comparation == 0) return 'bg-warning';
if (comparation < 0) return 'bg-success';
const difference = today - timeTicket;
if (difference == 0) return 'bg-warning';
if (difference < 0) return 'bg-success';
};
</script>
<template>
@ -201,8 +203,8 @@ const getDateColor = (date) => {
},
}"
:user-params="{ showEmpty: false }"
:right-search="false"
:columns="columns"
:right-search="false"
redirect="order"
>
<template #column-clientFk="{ row }">

View File

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

View File

@ -28,7 +28,7 @@ const filter = {
'id',
'workerFk',
'agencyModeFk',
'created',
'dated',
'm3',
'warehouseFk',
'description',
@ -78,7 +78,7 @@ const setData = (entity) => (data.value = useCardDescription(entity.code, entity
@on-fetch="setData"
>
<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('Zone')" :value="entity?.zone?.name" />
<VnLv

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,44 @@
<script setup>
import VnCard from 'components/common/VnCard.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>
<template>
<VnCard
data-key="Travel"
base-url="Travels"
:descriptor="TravelDescriptor"
:filter="filter"
search-data-key="TravelList"
:filter="filter"
:descriptor="TravelDescriptor"
:filter-panel="TravelFilter"
:searchbar-props="{
url: 'Travels/filter',
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 EntryDescriptorProxy from 'src/pages/Entry/Card/EntryDescriptorProxy.vue';
import FetchData from 'src/components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import { toDate, toCurrency } from 'src/filters';
import axios from 'axios';
@ -240,7 +240,7 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
data-key="TravelSummary"
>
<template #header>
<span>{{ travel.ref }} - {{ travel.id }}</span>
<span>{{ travel.id }} - {{ travel.ref }}</span>
</template>
<template #body>
@ -256,16 +256,20 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
:label="t('globals.warehouseOut')"
:value="travel.warehouseOut?.name"
/>
<QCheckbox
:label="t('travel.basicData.isRaid')"
v-model="travel.isRaid"
:disable="true"
/>
<QCheckbox
:label="t('travel.summary.delivered')"
v-model="travel.isDelivered"
:disable="true"
/>
<VnRow>
<QCheckbox
:label="t('travel.basicData.isRaid')"
v-model="travel.isRaid"
:disable="true"
/>
</VnRow>
<VnRow>
<QCheckbox
:label="t('travel.summary.delivered')"
v-model="travel.isDelivered"
:disable="true"
/>
</VnRow>
</QCard>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
@ -320,7 +324,6 @@ const getLink = (param) => `#/travel/${entityId.value}/${param}`;
<QTd>
<QCheckbox
v-if="col.name === 'isConfirmed'"
:label="t('travel.summary.received')"
:true-value="1"
:false-value="0"
v-model="row[col.name]"

View File

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

View File

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

View File

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

View File

@ -103,9 +103,12 @@ const formattedWeekTotalHours = computed(() =>
const onInputChange = async (date) => {
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);
setDate(_date);
if (outside) getMailStates(_date);
};
const setDate = async (date) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ describe('Client list', () => {
});
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 data = {
@ -26,8 +26,8 @@ describe('Client list', () => {
'Web user': { val: `user_test_${randomInt}` },
Street: { val: `C/ STREET ${randomInt}` },
Email: { val: `user.test${randomInt}@cypress.com` },
'Sales person': { val: 'employee', type: 'select' },
Location: { val: '46000, Valencia(Province one), España', type: 'select' },
'Sales person': { val: 'salesPerson', type: 'select' },
Location: { val: '46000', type: 'select' },
'Business type': { val: 'Otros', type: 'select' },
};
cy.fillInForm(data);

View File

@ -11,7 +11,7 @@ describe('EntryStockBought', () => {
cy.get('.q-notification__message').should('have.text', 'Data saved');
});
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="Date"]').eq(1).clear();
cy.get('input[aria-label="Date"]').eq(1).type('01-01');

View File

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

View File

@ -1,7 +1,7 @@
/// <reference types="cypress" />
describe('InvoiceInList', () => {
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 summaryHeaders = '.summaryBody .header-link';

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