Merge branch 'dev' of https://gitea.verdnatura.es/verdnatura/salix-front into 6336-claim_changes_v3
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Alex Moreno 2024-04-19 09:36:10 +02:00
commit 6db5c56f5a
30 changed files with 462 additions and 171 deletions

View File

@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- (Tickets) => Se añade la opción de clonar ticket. #6951 - (Tickets) => Se añade la opción de clonar ticket. #6951
- (Parking) => Se añade la sección Parking. #5186 - (Parking) => Se añade la sección Parking. #5186
- (Rutas) => Se añade el campo "servida" a la tabla y se añade también a los filtros. #7130
### Changed ### Changed
### Fixed ### Fixed

View File

@ -26,7 +26,7 @@ const value = computed({
emit('update:modelValue', value); emit('update:modelValue', value);
}, },
}); });
const hover = ref(false);
const styleAttrs = computed(() => { const styleAttrs = computed(() => {
return $props.isOutlined return $props.isOutlined
? { ? {
@ -41,6 +41,10 @@ const onEnterPress = () => {
emit('keyup.enter'); emit('keyup.enter');
}; };
const handleValue = (val = null) => {
value.value = val;
};
const focus = () => { const focus = () => {
vnInputRef.value.focus(); vnInputRef.value.focus();
}; };
@ -51,20 +55,33 @@ defineExpose({
</script> </script>
<template> <template>
<div
@mouseover="hover = true"
@mouseleave="hover = false"
:rules="$attrs.required ? [requiredFieldRule] : null"
>
<QInput <QInput
ref="vnInputRef" ref="vnInputRef"
v-model="value" v-model="value"
v-bind="{ ...$attrs, ...styleAttrs }" v-bind="{ ...$attrs, ...styleAttrs }"
type="text" :type="$attrs.type"
:class="{ required: $attrs.required }" :class="{ required: $attrs.required }"
@keyup.enter="onEnterPress()" @keyup.enter="onEnterPress()"
:rules="$attrs.required ? [requiredFieldRule] : null" :clearable="false"
> >
<template v-if="$slots.prepend" #prepend> <template v-if="$slots.prepend" #prepend>
<slot name="prepend" /> <slot name="prepend" />
</template> </template>
<template v-if="$slots.append" #append>
<slot name="append" /> <template #append>
<slot name="append" v-if="$slots.append" />
<QIcon
name="close"
size="xs"
v-if="hover && value"
@click="handleValue(null)"
></QIcon>
</template> </template>
</QInput> </QInput>
</div>
</template> </template>

View File

@ -1,7 +1,6 @@
<script setup> <script setup>
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import VnInput from 'components/common/VnInput.vue'; import isValidDate from 'filters/isValidDate';
import isValidDate from "filters/isValidDate";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -17,6 +16,8 @@ const props = defineProps({
default: false, default: false,
}, },
}); });
const hover = ref(false);
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const joinDateAndTime = (date, time) => { const joinDateAndTime = (date, time) => {
@ -77,14 +78,21 @@ const styleAttrs = computed(() => {
</script> </script>
<template> <template>
<VnInput <div @mouseover="hover = true" @mouseleave="hover = false">
<QInput
class="vn-input-date" class="vn-input-date"
readonly
:model-value="displayDate(value)" :model-value="displayDate(value)"
v-bind="{ ...$attrs, ...styleAttrs }" v-bind="{ ...$attrs, ...styleAttrs }"
readonly
@click="isPopupOpen = true" @click="isPopupOpen = true"
> >
<template #append> <template #append>
<QIcon
name="close"
size="xs"
v-if="hover && value"
@click="onDateUpdate(null)"
></QIcon>
<QIcon name="event" class="cursor-pointer"> <QIcon name="event" class="cursor-pointer">
<QPopupProxy <QPopupProxy
v-model="isPopupOpen" v-model="isPopupOpen"
@ -94,13 +102,15 @@ const styleAttrs = computed(() => {
:no-parent-event="props.readonly" :no-parent-event="props.readonly"
> >
<QDate <QDate
:today-btn="true"
:model-value="formatDate(value)" :model-value="formatDate(value)"
@update:model-value="onDateUpdate" @update:model-value="onDateUpdate"
/> />
</QPopupProxy> </QPopupProxy>
</QIcon> </QIcon>
</template> </template>
</VnInput> </QInput>
</div>
</template> </template>
<style lang="scss"> <style lang="scss">

View File

@ -2,7 +2,6 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import isValidDate from 'filters/isValidDate'; import isValidDate from 'filters/isValidDate';
import VnInput from "components/common/VnInput.vue";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -20,6 +19,7 @@ const props = defineProps({
}); });
const { t } = useI18n(); const { t } = useI18n();
const emit = defineEmits(['update:modelValue']); const emit = defineEmits(['update:modelValue']);
const value = computed({ const value = computed({
get() { get() {
return props.modelValue; return props.modelValue;
@ -27,12 +27,7 @@ const value = computed({
set(value) { set(value) {
const [hours, minutes] = value.split(':'); const [hours, minutes] = value.split(':');
const date = new Date(props.modelValue); const date = new Date(props.modelValue);
date.setHours( date.setHours(Number.parseInt(hours) || 0, Number.parseInt(minutes) || 0, 0, 0);
Number.parseInt(hours) || 0,
Number.parseInt(minutes) || 0,
0,
0
);
emit('update:modelValue', value ? date.toISOString() : null); emit('update:modelValue', value ? date.toISOString() : null);
}, },
}); });
@ -71,7 +66,7 @@ const styleAttrs = computed(() => {
</script> </script>
<template> <template>
<VnInput <QInput
class="vn-input-time" class="vn-input-time"
readonly readonly
:model-value="formatTime(value)" :model-value="formatTime(value)"
@ -79,7 +74,7 @@ const styleAttrs = computed(() => {
@click="isPopupOpen = true" @click="isPopupOpen = true"
> >
<template #append> <template #append>
<QIcon name="event" class="cursor-pointer"> <QIcon name="schedule" class="cursor-pointer">
<QPopupProxy <QPopupProxy
v-model="isPopupOpen" v-model="isPopupOpen"
cover cover
@ -111,7 +106,7 @@ const styleAttrs = computed(() => {
</QPopupProxy> </QPopupProxy>
</QIcon> </QIcon>
</template> </template>
</VnInput> </QInput>
</template> </template>
<style lang="scss"> <style lang="scss">

View File

@ -127,7 +127,6 @@ async function paginate() {
} }
function endPagination() { function endPagination() {
hasMoreData.value = arrayData.hasMoreData.value;
isLoading.value = false; isLoading.value = false;
emit('onFetch', store.data); emit('onFetch', store.data);
emit('onPaginate'); emit('onPaginate');
@ -183,11 +182,12 @@ defineExpose({ fetch, addFilter });
</QCard> </QCard>
</div> </div>
</div> </div>
<QInfiniteScroll <QInfiniteScroll
v-if="store.data" v-if="store.data"
@load="onLoad" @load="onLoad"
:offset="offset" :offset="offset"
:disable="disableInfiniteScroll || !arrayData.hasMoreData.value" :disable="disableInfiniteScroll || !arrayData.hasMoreData"
class="full-width" class="full-width"
v-bind="$attrs" v-bind="$attrs"
> >

View File

@ -97,6 +97,7 @@ export function useArrayData(key, userOptions) {
const { limit } = filter; const { limit } = filter;
hasMoreData.value = limit && response.data.length >= limit; hasMoreData.value = limit && response.data.length >= limit;
store.hasMoreData = hasMoreData.value;
if (append) { if (append) {
if (!store.data) store.data = []; if (!store.data) store.data = [];
@ -168,7 +169,7 @@ export function useArrayData(key, userOptions) {
} }
async function loadMore() { async function loadMore() {
if (!hasMoreData.value) return; if (!hasMoreData.value && !store.hasMoreData) return;
store.skip = store.limit * page.value; store.skip = store.limit * page.value;
page.value += 1; page.value += 1;

View File

@ -3,31 +3,29 @@ import { useRole } from './useRole';
import { useUserConfig } from './useUserConfig'; import { useUserConfig } from './useUserConfig';
import axios from 'axios'; import axios from 'axios';
import useNotify from './useNotify'; import useNotify from './useNotify';
const TOKEN_MULTIMEDIA = 'tokenMultimedia';
const TOKEN = 'token';
export function useSession() { export function useSession() {
const { notify } = useNotify(); const { notify } = useNotify();
function getToken() { function getToken() {
const localToken = localStorage.getItem('token'); const localToken = localStorage.getItem(TOKEN);
const sessionToken = sessionStorage.getItem('token'); const sessionToken = sessionStorage.getItem(TOKEN);
return localToken || sessionToken || ''; return localToken || sessionToken || '';
} }
function getTokenMultimedia() { function getTokenMultimedia() {
const localTokenMultimedia = localStorage.getItem('token'); // Temporal const localTokenMultimedia = localStorage.getItem(TOKEN_MULTIMEDIA);
const sessionTokenMultimedia = sessionStorage.getItem('token'); // Temporal const sessionTokenMultimedia = sessionStorage.getItem(TOKEN_MULTIMEDIA);
return localTokenMultimedia || sessionTokenMultimedia || ''; return localTokenMultimedia || sessionTokenMultimedia || '';
} }
function setToken(data) { function setToken(data) {
if (data.keepLogin) { const storage = data.keepLogin ? localStorage : sessionStorage;
localStorage.setItem('token', data.token); storage.setItem(TOKEN, data.token);
localStorage.setItem('tokenMultimedia', data.tokenMultimedia); storage.setItem(TOKEN_MULTIMEDIA, data.tokenMultimedia);
} else {
sessionStorage.setItem('token', data.token);
sessionStorage.setItem('tokenMultimedia', data.tokenMultimedia);
}
} }
async function destroyToken(url, storage, key) { async function destroyToken(url, storage, key) {
if (storage.getItem(key)) { if (storage.getItem(key)) {
@ -71,8 +69,8 @@ export function useSession() {
} }
function isLoggedIn() { function isLoggedIn() {
const localToken = localStorage.getItem('token'); const localToken = localStorage.getItem(TOKEN);
const sessionToken = sessionStorage.getItem('token'); const sessionToken = sessionStorage.getItem(TOKEN);
return !!(localToken || sessionToken); return !!(localToken || sessionToken);
} }

View File

@ -1096,6 +1096,7 @@ item:
list: List list: List
diary: Diary diary: Diary
tags: Tags tags: Tags
wasteBreakdown: Waste breakdown
itemCreate: New item itemCreate: New item
descriptor: descriptor:
item: Item item: Item
@ -1124,6 +1125,13 @@ item:
stemMultiplier: Multiplier stemMultiplier: Multiplier
producer: Producer producer: Producer
landed: Landed landed: Landed
create:
name: Name
tag: Tag
priority: Priority
type: Type
intrastat: Intrastat
origin: Origin
components: components:
topbar: {} topbar: {}
userPanel: userPanel:

View File

@ -1095,6 +1095,7 @@ item:
list: Listado list: Listado
diary: Histórico diary: Histórico
tags: Etiquetas tags: Etiquetas
wasteBreakdown: Deglose de mermas
itemCreate: Nuevo artículo itemCreate: Nuevo artículo
descriptor: descriptor:
item: Artículo item: Artículo
@ -1123,6 +1124,13 @@ item:
stemMultiplier: Multiplicador stemMultiplier: Multiplicador
producer: Productor producer: Productor
landed: F. entrega landed: F. entrega
create:
name: Nombre
tag: Etiqueta
priority: Prioridad
type: Tipo
intrastat: Intrastat
origin: Origen
components: components:
topbar: {} topbar: {}
userPanel: userPanel:

View File

@ -1,4 +1,4 @@
customerFilter: customerFilter:
filter: filter:
name: 'Name' name: Name
socialName: 'Social name' socialName: Social name

View File

@ -1,4 +1,4 @@
customerFilter: customerFilter:
filter: filter:
name: 'Nombre' name: Nombre
socialName: 'Razón Social' socialName: Razón Social

View File

@ -2,6 +2,7 @@
import { ref } from 'vue'; import { ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useRole } from 'src/composables/useRole';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue'; import FormModel from 'components/FormModel.vue';
@ -15,6 +16,8 @@ import { toDate } from 'src/filters';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const { hasAny } = useRole();
const isAdministrative = () => hasAny(['administrative']);
const suppliersOptions = ref([]); const suppliersOptions = ref([]);
const travelsOptions = ref([]); const travelsOptions = ref([]);
@ -206,6 +209,7 @@ const onFilterTravelSelected = (formData, id) => {
</div> </div>
<div class="col"> <div class="col">
<QCheckbox <QCheckbox
v-if="isAdministrative()"
v-model="data.isBooked" v-model="data.isBooked"
:label="t('entry.basicData.booked')" :label="t('entry.basicData.booked')"
/> />

View File

@ -1,8 +1,8 @@
entryList: entryList:
list: list:
inventoryEntry: 'Inventory entry' inventoryEntry: Inventory entry
virtualEntry: 'Virtual entry' virtualEntry: Virtual entry
entryFilter: entryFilter:
filter: filter:
search: 'General search' search: General search
reference: 'Reference' reference: Reference

View File

@ -1,8 +1,8 @@
entryList: entryList:
list: list:
inventoryEntry: 'Es inventario' inventoryEntry: Es inventario
virtualEntry: 'Es una redada' virtualEntry: Es una redada
entryFilter: entryFilter:
filter: filter:
search: 'Búsqueda general' search: Búsqueda general
reference: 'Referencia' reference: Referencia

View File

@ -257,7 +257,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
const isAdministrative = () => hasAny(['administrative']); const isAdministrative = () => hasAny(['administrative']);
const isAgricultural = () => const isAgricultural = () =>
invoiceIn.value.supplier.sageWithholdingFk == config.value[0].sageWithholdingFk; invoiceIn.value?.supplier?.sageWithholdingFk === config.value[0]?.sageWithholdingFk;
function showPdfInvoice() { function showPdfInvoice() {
if (isAgricultural()) openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`); if (isAgricultural()) openReport(`InvoiceIns/${entityId.value}/invoice-in-pdf`);

View File

@ -0,0 +1 @@
<template>Item basic data</template>

View File

@ -1 +1,170 @@
<template>Item create view</template> <script setup>
import { reactive, ref, onBeforeMount } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import FetchData from 'components/FetchData.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import axios from 'axios';
const { t } = useI18n();
const router = useRouter();
const newItemForm = reactive({});
const originsOptions = ref([]);
const tagsOptions = ref([]);
const validPriorities = ref([]);
const itemTypesOptions = ref([]);
const intrastatsOptions = ref([]);
const fetchDefaultPriorityTag = async () => {
const filter = {
fields: ['defaultPriority', 'defaultTag', 'validPriorities'],
limit: 1,
};
const { data } = await axios.get(`ItemConfigs`, { filter });
if (!data) return;
const dataRow = data[0];
validPriorities.value = [...dataRow.validPriorities];
newItemForm.priority = dataRow.defaultPriority;
newItemForm.tag = dataRow.defaultTag;
};
const redirectToItemBasicData = (_, { id }) => {
router.push({ name: 'ItemBasicData', params: { id } });
};
onBeforeMount(async () => {
await fetchDefaultPriorityTag();
});
</script>
<template>
<FetchData
url="Origins"
@on-fetch="(data) => (originsOptions = data)"
:filter="{ order: 'name' }"
auto-load
/>
<FetchData
url="Tags"
:filter="{ fields: ['id', 'name'], order: 'name ASC' }"
@on-fetch="(data) => (tagsOptions = data)"
auto-load
/>
<FetchData
url="ItemTypes"
:filter="{
fields: ['id', 'code', 'categoryFk', 'name'],
include: 'category',
order: 'name ASC',
}"
@on-fetch="(data) => (itemTypesOptions = data)"
auto-load
/>
<FetchData
url="Intrastats"
:filter="{ fields: ['id', 'description'], order: 'description ASC' }"
@on-fetch="(data) => (intrastatsOptions = data)"
auto-load
/>
<QPage>
<VnSubToolbar />
<FormModel
url-create="Items/new"
model="item"
:form-initial-data="newItemForm"
observe-form-changes
@on-data-saved="redirectToItemBasicData"
>
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnInput
v-model="data.provisionalName"
:label="t('item.create.name')"
/>
<VnSelectFilter
:label="t('item.create.tag')"
v-model="data.tag"
:options="tagsOptions"
option-value="id"
option-label="name"
hide-selected
/>
<VnSelectFilter
:label="t('item.create.priority')"
v-model="data.priority"
:options="validPriorities"
option-value="priority"
option-label="priority"
hide-selected
/>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelectFilter
:label="t('item.create.type')"
v-model="data.typeFk"
:options="itemTypesOptions"
option-label="name"
option-value="id"
hide-selected
>
<template #option="scope">
<QItem class="column" v-bind="scope.itemProps">
<QItemLabel class="row">
<span style="width: 3em">
{{ scope.opt?.code }}
</span>
<span>
{{ scope.opt?.name }}
</span>
</QItemLabel>
<QItemLabel v-if="scope.opt?.category" caption>
{{ scope.opt?.category?.name }}
</QItemLabel>
</QItem>
</template>
</VnSelectFilter>
<VnSelectFilter
:label="t('item.create.intrastat')"
v-model="data.intrastatFk"
:options="intrastatsOptions"
option-label="description"
option-value="id"
hide-selected
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>
{{ scope.opt?.description }}
</QItemLabel>
<QItemLabel caption>
#{{ scope.opt?.id }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
</VnRow>
<VnRow class="row q-gutter-md q-mb-md">
<VnSelectFilter
:label="t('item.create.origin')"
v-model="data.originFk"
:options="originsOptions"
option-value="id"
option-label="name"
hide-selected
/>
</VnRow>
</template>
</FormModel>
</QPage>
</template>

View File

@ -197,6 +197,15 @@ const warehouseList = ref([]);
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<QCheckbox
v-model="params.isOk"
:label="t('Served')"
toggle-indeterminate
/>
</QItemSection>
</QItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -212,6 +221,7 @@ en:
workerFk: Worker workerFk: Worker
from: From from: From
to: To to: To
Served: Served
es: es:
params: params:
warehouseFk: Almacén warehouseFk: Almacén
@ -229,4 +239,5 @@ es:
Worker: Trabajador Worker: Trabajador
From: Desde From: Desde
To: Hasta To: Hasta
Served: Servida
</i18n> </i18n>

View File

@ -11,8 +11,8 @@ import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import axios from 'axios'; import axios from 'axios';
import VnInputTime from 'components/common/VnInputTime.vue'; import VnInputTime from 'components/common/VnInputTime.vue';
import RouteSearchbar from "pages/Route/Card/RouteSearchbar.vue"; import RouteSearchbar from 'pages/Route/Card/RouteSearchbar.vue';
import {useStateStore} from "stores/useStateStore"; import { useStateStore } from 'stores/useStateStore';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
@ -26,6 +26,7 @@ const defaultInitialData = {
description: '', description: '',
vehicleFk: null, vehicleFk: null,
workerFk: null, workerFk: null,
isOk: false,
}; };
const workerList = ref([]); const workerList = ref([]);
@ -211,6 +212,7 @@ const onSave = (data, response) => {
size="sm" size="sm"
v-model="data.isOk" v-model="data.isOk"
:label="t('Is served')" :label="t('Is served')"
clearable
/> />
</div> </div>
</VnRow> </VnRow>

View File

@ -73,9 +73,9 @@ const ticketColumns = ref([
align: 'left', align: 'left',
}, },
{ {
name: 'warehouse', name: 'state',
label: t('route.summary.warehouse'), label: t('route.summary.state'),
field: (row) => row?.warehouseName, field: (row) => row?.ticketStateName,
sortable: false, sortable: false,
align: 'left', align: 'left',
}, },
@ -187,6 +187,15 @@ const ticketColumns = ref([
:label="t('route.summary.packages')" :label="t('route.summary.packages')"
:value="getTotalPackages(entity.tickets)" :value="getTotalPackages(entity.tickets)"
/> />
<QCheckbox
:label="
entity.route.isOk
? t('route.summary.closed')
: t('route.summary.open')
"
v-model="entity.route.isOk"
:disable="true"
/>
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<div class="header"> <div class="header">
@ -274,10 +283,14 @@ en:
city: City city: City
pc: PC pc: PC
client: Client client: Client
warehouse: Warehouse state: State
m3: m3:
packaging: Packaging packaging: Packaging
ticket: Ticket ticket: Ticket
closed: Closed
open: Open
yes: Yes
no: No
es: es:
route: route:
summary: summary:
@ -299,6 +312,10 @@ es:
city: Población city: Población
pc: CP pc: CP
client: Cliente client: Cliente
warehouse: Almacén state: Estado
packaging: Encajado packaging: Encajado
closed: Cerrada
open: Abierta
yes:
no: No
</i18n> </i18n>

View File

@ -95,6 +95,13 @@ const columns = computed(() => [
sortable: true, sortable: true,
align: 'left', align: 'left',
}, },
{
name: 'isServed',
label: t('Served'),
field: (row) => Boolean(row.isOk),
sortable: true,
align: 'left',
},
{ {
name: 'actions', name: 'actions',
label: '', label: '',
@ -265,7 +272,7 @@ const openTicketsDialog = (id) => {
auto-load auto-load
> >
<template #body="{ rows }"> <template #body="{ rows }">
<div class="q-pa-md"> <div class="q-pa-md route-table">
<QTable <QTable
v-model:selected="selectedRows" v-model:selected="selectedRows"
:columns="columns" :columns="columns"
@ -279,7 +286,7 @@ const openTicketsDialog = (id) => {
:no-data-label="t('globals.noResults')" :no-data-label="t('globals.noResults')"
> >
<template #body-cell-worker="{ row }"> <template #body-cell-worker="{ row }">
<QTd> <QTd class="table-input-cell">
<VnSelectFilter <VnSelectFilter
:label="t('Worker')" :label="t('Worker')"
v-model="row.workerFk" v-model="row.workerFk"
@ -312,7 +319,7 @@ const openTicketsDialog = (id) => {
</QTd> </QTd>
</template> </template>
<template #body-cell-agency="{ row }"> <template #body-cell-agency="{ row }">
<QTd> <QTd class="table-input-cell">
<VnSelectFilter <VnSelectFilter
:label="t('Agency')" :label="t('Agency')"
v-model="row.agencyModeFk" v-model="row.agencyModeFk"
@ -329,7 +336,7 @@ const openTicketsDialog = (id) => {
</QTd> </QTd>
</template> </template>
<template #body-cell-vehicle="{ row }"> <template #body-cell-vehicle="{ row }">
<QTd> <QTd class="table-input-cell">
<VnSelectFilter <VnSelectFilter
:label="t('Vehicle')" :label="t('Vehicle')"
v-model="row.vehicleFk" v-model="row.vehicleFk"
@ -397,6 +404,19 @@ const openTicketsDialog = (id) => {
/> />
</QTd> </QTd>
</template> </template>
<template #body-cell-isServed="props">
<QTd>
<QCheckbox v-model="props.value" disable>
<QTooltip>
{{
props.value
? t('Route is closed')
: t('Route is not served')
}}
</QTooltip>
</QCheckbox>
</QTd>
</template>
<template #body-cell-actions="props"> <template #body-cell-actions="props">
<QTd :props="props"> <QTd :props="props">
<div class="flex items-center no-wrap table-actions"> <div class="flex items-center no-wrap table-actions">
@ -455,7 +475,7 @@ const openTicketsDialog = (id) => {
<style lang="scss" scoped> <style lang="scss" scoped>
.table-input-cell { .table-input-cell {
min-width: 150px; max-width: 143px;
} }
.route-list { .route-list {
@ -466,6 +486,11 @@ const openTicketsDialog = (id) => {
.table-actions { .table-actions {
gap: 12px; gap: 12px;
} }
.lock-icon-cell {
text-align: center;
margin-left: -20%;
}
</style> </style>
<i18n> <i18n>
en: en:
@ -479,6 +504,7 @@ es:
Description: Descripción Description: Descripción
Hour started: Hora inicio Hour started: Hora inicio
Hour finished: Hora fin Hour finished: Hora fin
Served: Servida
newRoute: Nueva Ruta newRoute: Nueva Ruta
Clone Selected Routes: Clonar rutas seleccionadas Clone Selected Routes: Clonar rutas seleccionadas
Select the starting date: Seleccione la fecha de inicio Select the starting date: Seleccione la fecha de inicio
@ -490,4 +516,6 @@ es:
Add ticket: Añadir tickets Add ticket: Añadir tickets
Preview: Vista previa Preview: Vista previa
Summary: Resumen Summary: Resumen
Route is closed: La ruta está cerrada
Route is not served: La ruta no está servida
</i18n> </i18n>

View File

@ -1,10 +1,9 @@
<script setup> <script setup>
import { onMounted, ref, computed, onUpdated } from 'vue'; import { ref, computed, onUpdated } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CardSummary from 'components/ui/CardSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import { getUrl } from 'src/composables/getUrl';
import { useRole } from 'src/composables/useRole'; import { useRole } from 'src/composables/useRole';
import { dashIfEmpty } from 'src/filters'; import { dashIfEmpty } from 'src/filters';
import VnUserLink from 'src/components/ui/VnUserLink.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue';
@ -28,12 +27,6 @@ const entityId = computed(() => $props.id || route.params.id);
const summaryRef = ref(); const summaryRef = ref();
const supplier = ref(); const supplier = ref();
const supplierUrl = ref();
onMounted(async () => {
await roleState.fetch();
supplierUrl.value = (await getUrl('supplier/')) + entityId.value;
});
async function setData(data) { async function setData(data) {
if (data) { if (data) {
@ -44,6 +37,10 @@ async function setData(data) {
const isAdministrative = computed(() => { const isAdministrative = computed(() => {
return roleState.hasAny(['administrative']); return roleState.hasAny(['administrative']);
}); });
function getUrl(section) {
return isAdministrative.value && `#/supplier/${entityId.value}/${section}`;
}
</script> </script>
<template> <template>
@ -58,15 +55,10 @@ const isAdministrative = computed(() => {
<template #body> <template #body>
<QCard class="vn-one"> <QCard class="vn-one">
<router-link <VnTitle
v-if="isAdministrative" :url="getUrl('basic-data')"
class="header link" :text="t('globals.summary.basicData')"
:to="{ name: 'SupplierBasicData', params: { id: entityId } }" />
>
{{ t('globals.summary.basicData') }}
<QIcon name="open_in_new" />
</router-link>
<span v-else> {{ t('globals.summary.basicData') }}</span>
<VnLv label="Id" :value="supplier.id" /> <VnLv label="Id" :value="supplier.id" />
<VnLv label="Alias" :value="supplier.nickname" /> <VnLv label="Alias" :value="supplier.nickname" />
<VnLv :label="t('supplier.summary.responsible')"> <VnLv :label="t('supplier.summary.responsible')">
@ -94,15 +86,10 @@ const isAdministrative = computed(() => {
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<router-link <VnTitle
v-if="isAdministrative" :url="getUrl('billing-data')"
class="header link" :text="t('supplier.summary.billingData')"
:to="{ name: 'SupplierBillingData', params: { id: entityId } }" />
>
{{ t('supplier.summary.billingData') }}
<QIcon name="open_in_new" />
</router-link>
<span v-else> {{ t('supplier.summary.billingData') }}</span>
<VnLv <VnLv
:label="t('supplier.summary.payMethod')" :label="t('supplier.summary.payMethod')"
:value="supplier.payMethod?.name" :value="supplier.payMethod?.name"
@ -117,15 +104,10 @@ const isAdministrative = computed(() => {
<VnLv :label="t('supplier.summary.account')" :value="supplier.account" /> <VnLv :label="t('supplier.summary.account')" :value="supplier.account" />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<router-link <VnTitle
v-if="isAdministrative" :url="getUrl('fiscal-data')"
class="header link" :text="t('supplier.summary.fiscalData')"
:to="{ name: 'SupplierFiscalData', params: { id: entityId } }" />
>
{{ t('supplier.summary.fiscalData') }}
<QIcon name="open_in_new" />
</router-link>
<span v-else> {{ t('supplier.summary.fiscalData') }}</span>
<VnLv <VnLv
:label="t('supplier.summary.sageTaxType')" :label="t('supplier.summary.sageTaxType')"
:value="supplier.sageTaxType?.vat" :value="supplier.sageTaxType?.vat"
@ -152,15 +134,10 @@ const isAdministrative = computed(() => {
/> />
</QCard> </QCard>
<QCard class="vn-one"> <QCard class="vn-one">
<router-link <VnTitle
v-if="isAdministrative" :url="getUrl('fiscal-data')"
class="header link" :text="t('supplier.summary.fiscalAddress')"
:to="{ name: 'SupplierFiscalData', params: { id: entityId } }" />
>
{{ t('supplier.summary.fiscalAddress') }}
<QIcon name="open_in_new" />
</router-link>
<span v-else> {{ t('supplier.summary.fiscalAddress') }}</span>
<VnLv :label="t('supplier.summary.socialName')" :value="supplier.name" /> <VnLv :label="t('supplier.summary.socialName')" :value="supplier.name" />
<VnLv :label="t('supplier.summary.taxNumber')" :value="supplier.nif" /> <VnLv :label="t('supplier.summary.taxNumber')" :value="supplier.nif" />
<VnLv :label="t('supplier.summary.street')" :value="supplier.street" /> <VnLv :label="t('supplier.summary.street')" :value="supplier.street" />

View File

@ -1,6 +1,6 @@
travelFilter: travelFilter:
filter: filter:
warehouseOutFk: 'Warehouse Out' warehouseOutFk: Warehouse Out
warehouseInFk: 'Warehouse In' warehouseInFk: Warehouse In
agencyModeFk: 'Agency' agencyModeFk: Agency
scopeDays: 'Days onward' scopeDays: Days onward

View File

@ -1,6 +1,6 @@
travelFilter: travelFilter:
filter: filter:
warehouseInFk: 'Alm. entrada' warehouseInFk: Alm. entrada
warehouseOutFk: 'Alm. salida' warehouseOutFk: Alm. salida
agencyModeFk: 'Agencia' agencyModeFk: Agencia
scopeDays: 'Días adelante' scopeDays: Días adelante

View File

@ -10,8 +10,8 @@ export default {
component: RouterView, component: RouterView,
redirect: { name: 'ItemMain' }, redirect: { name: 'ItemMain' },
menus: { menus: {
main: ['ItemList'], main: ['ItemList', 'WasteBreakdown'],
card: [], card: ['ItemBasicData'],
}, },
children: [ children: [
{ {
@ -37,6 +37,19 @@ export default {
}, },
component: () => import('src/pages/Item/ItemCreate.vue'), component: () => import('src/pages/Item/ItemCreate.vue'),
}, },
{
path: 'waste-breakdown',
name: 'WasteBreakdown',
meta: {
title: 'wasteBreakdown',
icon: 'vn:claims',
},
beforeEnter: (to, from, next) => {
next({ name: 'ItemList' });
window.location.href =
'https://grafana.verdnatura.es/d/TTNXQAxVk';
},
},
], ],
}, },
{ {
@ -72,6 +85,15 @@ export default {
}, },
component: () => import('src/pages/Item/Card/ItemTags.vue'), component: () => import('src/pages/Item/Card/ItemTags.vue'),
}, },
{
path: 'basic-data',
name: 'ItemBasicData',
meta: {
title: 'basicData',
icon: 'vn:settings',
},
component: () => import('src/pages/Item/Card/ItemBasicData.vue'),
},
], ],
}, },
], ],

View File

@ -1,48 +1,64 @@
const locationOptions ='[role="listbox"] > div.q-virtual-scroll__content > .q-item' const locationOptions = '[role="listbox"] > div.q-virtual-scroll__content > .q-item';
describe('VnLocation', () => { describe('VnLocation', () => {
describe('Create',()=>{ describe('Create', () => {
const inputLocation = ':nth-child(3) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control'; const inputLocation =
'.q-form .q-card> :nth-child(3) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control';
beforeEach(() => { beforeEach(() => {
cy.viewport(1280, 720); cy.viewport(1280, 720);
cy.login('developer'); cy.login('developer');
cy.visit('/#/worker/create'); cy.visit('/#/worker/create');
cy.waitForElement('.q-card'); cy.waitForElement('.q-card');
}); });
it('Show all options', function() { it('Show all options', function () {
cy.get(inputLocation).click(); cy.get(inputLocation).click();
cy.get(locationOptions).should('have.length.at.least',5); cy.get(locationOptions).should('have.length.at.least', 5);
}); });
it('input filter location as "al"', function() { it('input filter location as "al"', function () {
cy.get(inputLocation).click(); cy.get(inputLocation).click();
cy.get(inputLocation).clear(); cy.get(inputLocation).clear();
cy.get(inputLocation).type('al'); cy.get(inputLocation).type('al');
cy.get(locationOptions).should('have.length.at.least',3); cy.get(locationOptions).should('have.length.at.least', 3);
}); });
it('input filter location as "ecuador"', function() { it('input filter location as "ecuador"', function () {
cy.get(inputLocation).click(); cy.get(inputLocation).click();
cy.get(inputLocation).clear(); cy.get(inputLocation).clear();
cy.get(inputLocation).type('ecuador'); cy.get(inputLocation).type('ecuador');
cy.get(locationOptions).should('have.length.at.least',1); cy.get(locationOptions).should('have.length.at.least', 1);
cy.get(`${locationOptions}:nth-child(1)`).click(); cy.get(`${locationOptions}:nth-child(1)`).click();
cy.get(':nth-child(3) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(2) > .q-icon').click(); cy.get(inputLocation + '> :nth-child(2) > .q-icon').click();
}); });
}); });
describe('Fiscal-data',()=>{ describe('Fiscal-data', () => {
beforeEach(() => { beforeEach(() => {
cy.viewport(1280, 720); cy.viewport(1280, 720);
cy.login('developer'); cy.login('developer');
cy.visit('/#/supplier/567/fiscal-data', {timeout: 2000}); cy.visit('/#/supplier/567/fiscal-data', { timeout: 2000 });
cy.waitForElement('.q-card'); cy.waitForElement('.q-card');
}); });
it('Create postCode', function() { it('Create postCode', function () {
cy.get(':nth-child(6) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(3) > .q-icon').click(); cy.get(
':nth-child(6) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(3) > .q-icon'
).click();
cy.get(' .q-card > h1').should('have.text', 'New postcode'); cy.get(' .q-card > h1').should('have.text', 'New postcode');
cy.get('.q-card > :nth-child(4) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(1) > input').clear('12'); cy.get(
cy.get('.q-card > :nth-child(4) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(1) > input').type('1234453'); '.q-card > :nth-child(4) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(1) > input'
cy.selectOption('.q-dialog__inner > .column > #formModel > .q-card > :nth-child(4) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control ', 'Valencia'); ).clear('12');
cy.selectOption('.q-dialog__inner > .column > #formModel > .q-card > :nth-child(5) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control ', 'Province one'); cy.get(
cy.selectOption('.q-dialog__inner > .column > #formModel > .q-card > :nth-child(5) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control ', 'España'); '.q-card > :nth-child(4) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control > :nth-child(1) > input'
).type('1234453');
cy.selectOption(
'.q-dialog__inner > .column > #formModel > .q-card > :nth-child(4) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control ',
'Valencia'
);
cy.selectOption(
'.q-dialog__inner > .column > #formModel > .q-card > :nth-child(5) > :nth-child(1) > .q-field > .q-field__inner > .q-field__control ',
'Province one'
);
cy.selectOption(
'.q-dialog__inner > .column > #formModel > .q-card > :nth-child(5) > :nth-child(2) > .q-field > .q-field__inner > .q-field__control ',
'España'
);
cy.get('.q-mt-lg > .q-btn--standard').click(); cy.get('.q-mt-lg > .q-btn--standard').click();
}); });
}); });
}) });

View File

@ -8,6 +8,7 @@ describe('ClaimDevelopment', () => {
cy.viewport(1920, 1080); cy.viewport(1920, 1080);
cy.login('developer'); cy.login('developer');
cy.visit(`/#/claim/${claimId}/development`); cy.visit(`/#/claim/${claimId}/development`);
cy.waitForElement('tbody');
}); });
it('should reset line', () => { it('should reset line', () => {

View File

@ -1,6 +1,6 @@
/// <reference types="cypress" /> /// <reference types="cypress" />
describe('InvoiceInBasicData', () => { describe('InvoiceInBasicData', () => {
const selects = ':nth-child(1) > :nth-child(1) > .q-field'; const selects = '.q-form .q-card>:nth-child(1) > :nth-child(1) > .q-field';
const appendBtns = 'label button'; const appendBtns = 'label button';
const dialogAppendBtns = '.q-dialog label button'; const dialogAppendBtns = '.q-dialog label button';
const dialogInputs = '.q-dialog input'; const dialogInputs = '.q-dialog input';

View File

@ -72,6 +72,7 @@ Cypress.Commands.add('getValue', (selector) => {
// Fill Inputs // Fill Inputs
Cypress.Commands.add('selectOption', (selector, option) => { Cypress.Commands.add('selectOption', (selector, option) => {
cy.waitForElement(selector);
cy.get(selector).find('.q-select__dropdown-icon').click(); cy.get(selector).find('.q-select__dropdown-icon').click();
cy.get('.q-menu .q-item').contains(option).click(); cy.get('.q-menu .q-item').contains(option).click();
}); });
@ -183,11 +184,11 @@ Cypress.Commands.add('closeSideMenu', (element) => {
Cypress.Commands.add('clearSearchbar', (element) => { Cypress.Commands.add('clearSearchbar', (element) => {
if (element) cy.waitForElement(element); if (element) cy.waitForElement(element);
cy.get('#searchbar > form > label > div:nth-child(1) input').clear(); cy.get('#searchbar > form > div:nth-child(1) > label > div:nth-child(1) input').clear();
}); });
Cypress.Commands.add('writeSearchbar', (value) => { Cypress.Commands.add('writeSearchbar', (value) => {
cy.get('#searchbar > form > label > div:nth-child(1) input').type(value); cy.get('#searchbar > form > div:nth-child(1) > label > div:nth-child(1) input').type(value);
}); });
Cypress.Commands.add('validateContent', (selector, expectedValue) => { Cypress.Commands.add('validateContent', (selector, expectedValue) => {
cy.get(selector).should('have.text', expectedValue); cy.get(selector).should('have.text', expectedValue);

View File

@ -27,7 +27,10 @@ export default defineConfig({
sassVariables: 'src/quasar-variables.scss', sassVariables: 'src/quasar-variables.scss',
}), }),
VueI18nPlugin({ VueI18nPlugin({
include: path.resolve(__dirname, 'src/i18n/**'), include: [
path.resolve(__dirname, 'src/i18n/**'),
path.resolve(__dirname, 'src/pages/**/locale/**'),
],
}), }),
jsconfigPaths(), jsconfigPaths(),
], ],