Items summary #281
|
@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2418.01]
|
||||
|
||||
## [2416.01] - 2024-04-18
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "salix-front",
|
||||
"version": "24.16.0",
|
||||
"version": "24.18.0",
|
||||
"description": "Salix frontend",
|
||||
"productName": "Salix",
|
||||
"author": "Verdnatura",
|
||||
|
|
|
@ -93,13 +93,11 @@ module.exports = configure(function (/* ctx */) {
|
|||
[
|
||||
VueI18nPlugin({
|
||||
runtimeOnly: false,
|
||||
include: [
|
||||
path.resolve(__dirname, './src/i18n/locale/**'),
|
||||
path.resolve(__dirname, './src/pages/**/locale/**'),
|
||||
],
|
||||
}),
|
||||
{
|
||||
// if you want to use Vue I18n Legacy API, you need to set `compositionOnly: false`
|
||||
// compositionOnly: false,
|
||||
// you need to set i18n resource including paths !
|
||||
include: path.resolve(__dirname, './src/i18n/**'),
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import messages from 'src/i18n';
|
||||
import { locales } from 'src/i18n/handle';
|
||||
|
||||
const i18n = createI18n({
|
||||
locale: navigator.language || navigator.userLanguage,
|
||||
|
@ -12,8 +13,9 @@ const i18n = createI18n({
|
|||
legacy: false,
|
||||
});
|
||||
|
||||
export default boot(({ app }) => {
|
||||
export default boot(async ({ app }) => {
|
||||
// Set i18n instance on app
|
||||
await locales();
|
||||
app.use(i18n);
|
||||
});
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ defineExpose({
|
|||
<div class="q-mt-lg row justify-end">
|
||||
<QBtn
|
||||
:label="t('globals.save')"
|
||||
:title="t('globals.save')"
|
||||
type="submit"
|
||||
color="primary"
|
||||
:disabled="isLoading"
|
||||
|
@ -85,6 +86,7 @@ defineExpose({
|
|||
/>
|
||||
<QBtn
|
||||
:label="t('globals.cancel')"
|
||||
:title="t('globals.cancel')"
|
||||
type="reset"
|
||||
color="primary"
|
||||
flat
|
||||
|
|
|
@ -198,11 +198,13 @@ function addDefaultData(data) {
|
|||
en:
|
||||
contentTypesInfo: Allowed file types {allowedContentTypes}
|
||||
EntryDmsDescription: Reference {reference}
|
||||
WorkersDescription: Working of employee id {reference}
|
||||
SupplierDmsDescription: Reference {reference}
|
||||
es:
|
||||
Generate identifier for original file: Generar identificador para archivo original
|
||||
contentTypesInfo: Tipos de archivo permitidos {allowedContentTypes}
|
||||
EntryDmsDescription: Referencia {reference}
|
||||
WorkersDescription: Laboral del empleado {reference}
|
||||
SupplierDmsDescription: Referencia {reference}
|
||||
|
||||
</i18n>
|
||||
|
|
|
@ -5,9 +5,11 @@ import { useRoute } from 'vue-router';
|
|||
import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar';
|
||||
import axios from 'axios';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||
import VnDms from 'src/components/common/VnDms.vue';
|
||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
import VnUserLink from '../ui/VnUserLink.vue';
|
||||
import { downloadFile } from 'src/composables/downloadFile';
|
||||
|
||||
const route = useRoute();
|
||||
|
@ -26,6 +28,15 @@ const $props = defineProps({
|
|||
type: String,
|
||||
default: null,
|
||||
},
|
||||
deleteModel: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
downloadModel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
defaultDmsCode: {
|
||||
type: String,
|
||||
required: true,
|
||||
|
@ -74,7 +85,7 @@ const dmsFilter = {
|
|||
],
|
||||
},
|
||||
},
|
||||
order: ['dmsFk DESC'],
|
||||
where: { [$props.filter]: route.params.id },
|
||||
};
|
||||
|
||||
const columns = computed(() => [
|
||||
|
@ -94,12 +105,12 @@ const columns = computed(() => [
|
|||
props: (prop) => ({
|
||||
readonly: true,
|
||||
borderless: true,
|
||||
'model-value': prop.row.dmsType.name,
|
||||
'model-value': prop.row.dmsType?.name,
|
||||
}),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'order',
|
||||
field: 'hardCopyNumber',
|
||||
label: t('globals.order'),
|
||||
name: 'order',
|
||||
component: 'span',
|
||||
|
@ -117,6 +128,7 @@ const columns = computed(() => [
|
|||
label: t('globals.description'),
|
||||
name: 'description',
|
||||
component: 'span',
|
||||
props: (prop) => ({ value: prop.value?.toUpperCase() }),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
|
@ -136,21 +148,53 @@ const columns = computed(() => [
|
|||
name: 'file',
|
||||
component: 'span',
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'worker',
|
||||
label: t('globals.worker'),
|
||||
name: 'worker',
|
||||
component: VnUserLink,
|
||||
props: (prop) => ({
|
||||
name: prop.row.worker?.user?.name.toLowerCase(),
|
||||
workerId: prop.row.worker?.id,
|
||||
}),
|
||||
},
|
||||
{
|
||||
align: 'left',
|
||||
field: 'created',
|
||||
label: t('globals.created'),
|
||||
name: 'created',
|
||||
component: VnInputDate,
|
||||
props: (prop) => ({
|
||||
disable: true,
|
||||
'model-value': prop.row.created,
|
||||
}),
|
||||
},
|
||||
{
|
||||
field: 'options',
|
||||
name: 'options',
|
||||
components: [
|
||||
{
|
||||
component: QBtn,
|
||||
name: 'download',
|
||||
isDocuware: true,
|
||||
props: () => ({
|
||||
icon: 'cloud_download',
|
||||
flat: true,
|
||||
color: 'primary',
|
||||
}),
|
||||
click: (prop) => downloadFile(prop.row.id),
|
||||
click: (prop) =>
|
||||
downloadFile(
|
||||
prop.row.id,
|
||||
$props.downloadModel,
|
||||
null,
|
||||
prop.row.download
|
||||
),
|
||||
},
|
||||
{
|
||||
component: QBtn,
|
||||
name: 'edit',
|
||||
external: false,
|
||||
props: () => ({
|
||||
icon: 'edit',
|
||||
flat: true,
|
||||
|
@ -160,6 +204,8 @@ const columns = computed(() => [
|
|||
},
|
||||
{
|
||||
component: QBtn,
|
||||
name: 'delete',
|
||||
external: false,
|
||||
props: () => ({
|
||||
icon: 'delete',
|
||||
flat: true,
|
||||
|
@ -167,12 +213,24 @@ const columns = computed(() => [
|
|||
}),
|
||||
click: (prop) => deleteDms(prop.row.id),
|
||||
},
|
||||
{
|
||||
component: QBtn,
|
||||
name: 'open',
|
||||
external: true,
|
||||
props: () => ({
|
||||
icon: 'open_in_new',
|
||||
flat: true,
|
||||
color: 'primary',
|
||||
}),
|
||||
click: (prop) => open(prop.row.url),
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
function setData(data) {
|
||||
const newData = data.map((value) => value.dms);
|
||||
const newData = data.map((value) => value.dms || value);
|
||||
newData.sort((a, b) => new Date(b.created) - new Date(a.created));
|
||||
rows.value = newData;
|
||||
}
|
||||
|
||||
|
@ -186,7 +244,7 @@ function deleteDms(dmsFk) {
|
|||
},
|
||||
})
|
||||
.onOk(async () => {
|
||||
await axios.post(`${$props.model}/${dmsFk}/removeFile`);
|
||||
await axios.post(`${$props.deleteModel ?? $props.model}/${dmsFk}/removeFile`);
|
||||
const index = rows.value.findIndex((row) => row.id == dmsFk);
|
||||
rows.value.splice(index, 1);
|
||||
});
|
||||
|
@ -206,84 +264,106 @@ function parseDms(data) {
|
|||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
async function open(url) {
|
||||
window.open(url).focus();
|
||||
}
|
||||
|
||||
function shouldRenderButton(button, isExternal = false) {
|
||||
if (button.name == 'download') return true;
|
||||
return button.external === isExternal;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
<VnPaginate
|
||||
ref="dmsRef"
|
||||
:data-key="$props.model"
|
||||
:url="$props.model"
|
||||
:filter="dmsFilter"
|
||||
:where="{ [$props.filter]: route.params.id }"
|
||||
:order="['dmsFk DESC']"
|
||||
:auto-load="true"
|
||||
@on-fetch="setData"
|
||||
auto-load
|
||||
/>
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
class="full-width q-mt-md"
|
||||
hide-bottom
|
||||
row-key="clientFk"
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell="props">
|
||||
<QTd :props="props">
|
||||
<QTr :props="props">
|
||||
<component
|
||||
v-if="props.col.component"
|
||||
:is="props.col.component"
|
||||
v-bind="props.col.props && props.col.props(props)"
|
||||
>
|
||||
<span
|
||||
v-if="props.col.component == 'span'"
|
||||
style="white-space: wrap"
|
||||
>{{ props.value }}</span
|
||||
>
|
||||
</component>
|
||||
</QTr>
|
||||
|
||||
<div class="flex justify-center" v-if="props.col.name == 'options'">
|
||||
<div v-for="button of props.col.components" :key="button.id">
|
||||
<component
|
||||
:is="button.component"
|
||||
v-bind="button.props(props)"
|
||||
@click="button.click(props)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard
|
||||
bordered
|
||||
flat
|
||||
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
|
||||
>
|
||||
<QSeparator />
|
||||
<QList dense>
|
||||
<QItem v-for="col in props.cols" :key="col.name">
|
||||
<div v-if="col.name != 'options'" class="row">
|
||||
<span class="labelColor">{{ col.label }}:</span>
|
||||
<span>{{ col.value }}</span>
|
||||
</div>
|
||||
<div v-if="col.name == 'options'" class="row">
|
||||
<div
|
||||
v-for="button of col.components"
|
||||
:key="button.id"
|
||||
class="row"
|
||||
<template #body>
|
||||
<QTable
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
class="full-width q-mt-md"
|
||||
hide-bottom
|
||||
row-key="clientFk"
|
||||
:grid="$q.screen.lt.sm"
|
||||
>
|
||||
<template #body-cell="props">
|
||||
<QTd :props="props">
|
||||
<QTr :props="props">
|
||||
<component
|
||||
v-if="props.col.component"
|
||||
:is="props.col.component"
|
||||
v-bind="props.col.props && props.col.props(props)"
|
||||
>
|
||||
<span
|
||||
v-if="props.col.component == 'span'"
|
||||
style="white-space: wrap"
|
||||
>{{ props.value }}</span
|
||||
>
|
||||
<component
|
||||
:is="button.component"
|
||||
v-bind="button.props(col)"
|
||||
@click="button.click(col)"
|
||||
/>
|
||||
</div>
|
||||
</component>
|
||||
</QTr>
|
||||
|
||||
<div class="row no-wrap" v-if="props.col.name == 'options'">
|
||||
<div v-for="button of props.col.components" :key="button.id">
|
||||
<component
|
||||
v-if="
|
||||
shouldRenderButton(button, props.row.isDocuware)
|
||||
"
|
||||
:is="button.component"
|
||||
v-bind="button.props(props)"
|
||||
@click="button.click(props)"
|
||||
/>
|
||||
</div>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</div>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard
|
||||
bordered
|
||||
flat
|
||||
@keyup.ctrl.enter.stop="claimDevelopmentForm?.saveChanges()"
|
||||
>
|
||||
<QSeparator />
|
||||
<QList dense>
|
||||
<QItem v-for="col in props.cols" :key="col.name">
|
||||
<div v-if="col.name != 'options'" class="row">
|
||||
<span class="labelColor">{{ col.label }}:</span>
|
||||
<span>{{ col.value }}</span>
|
||||
</div>
|
||||
<div v-if="col.name == 'options'" class="row">
|
||||
<div
|
||||
v-for="button of col.components"
|
||||
:key="button.id"
|
||||
class="row"
|
||||
>
|
||||
<component
|
||||
v-if="
|
||||
shouldRenderButton(
|
||||
button.name,
|
||||
props.row.isDocuware
|
||||
)
|
||||
"
|
||||
:is="button.component"
|
||||
v-bind="button.props(col)"
|
||||
@click="button.click(col)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</QTable>
|
||||
</VnPaginate>
|
||||
<QDialog v-model="formDialog.show">
|
||||
<VnDms
|
||||
:model="updateModel ?? model"
|
||||
|
|
|
@ -77,6 +77,7 @@ const arrayData = useArrayData(props.dataKey, {
|
|||
userParams: props.userParams,
|
||||
exprBuilder: props.exprBuilder,
|
||||
});
|
||||
const hasMoreData = ref();
|
||||
const store = arrayData.store;
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -109,11 +110,10 @@ async function paginate() {
|
|||
|
||||
isLoading.value = true;
|
||||
await arrayData.loadMore();
|
||||
|
||||
if (!arrayData.hasMoreData.value) {
|
||||
if (store.userParamsChanged) arrayData.hasMoreData.value = true;
|
||||
store.userParamsChanged = false;
|
||||
isLoading.value = false;
|
||||
endPagination();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -123,12 +123,15 @@ async function paginate() {
|
|||
pagination.value.sortBy = sortBy;
|
||||
pagination.value.descending = descending;
|
||||
|
||||
isLoading.value = false;
|
||||
endPagination();
|
||||
}
|
||||
|
||||
function endPagination() {
|
||||
hasMoreData.value = arrayData.hasMoreData.value;
|
||||
isLoading.value = false;
|
||||
emit('onFetch', store.data);
|
||||
emit('onPaginate');
|
||||
}
|
||||
|
||||
async function onLoad(index, done) {
|
||||
if (!store.data) {
|
||||
return done();
|
||||
|
@ -193,6 +196,9 @@ defineExpose({ fetch, addFilter });
|
|||
<QSpinner color="orange" size="md" />
|
||||
</div>
|
||||
</QInfiniteScroll>
|
||||
<div v-if="!isLoading && hasMoreData" class="w-full flex justify-center q-mt-md">
|
||||
<QBtn color="primary" :label="t('Load more data')" @click="paginate()" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -209,4 +215,5 @@ defineExpose({ fetch, addFilter });
|
|||
es:
|
||||
No data to display: Sin datos que mostrar
|
||||
No results found: No se han encontrado resultados
|
||||
Load more data: Cargar más resultados
|
||||
</i18n>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<template>
|
||||
<div id="row" class="q-gutter-md q-mb-md">
|
||||
<div class="vn-row q-gutter-md q-mb-md">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scopped>
|
||||
#row {
|
||||
.vn-row {
|
||||
display: flex;
|
||||
> * {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 800px) {
|
||||
#row {
|
||||
.vn-row {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ const removeNode = (node) => {
|
|||
notify(t('department.departmentRemoved'), 'positive');
|
||||
await fetchNodeLeaves(parentFk);
|
||||
} catch (err) {
|
||||
console.log('Error removing department');
|
||||
console.error('Error removing department');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script setup>
|
||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const $props = defineProps({
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { useSession } from 'src/composables/useSession';
|
||||
import { getUrl } from './getUrl';
|
||||
|
||||
const {getTokenMultimedia} = useSession();
|
||||
const token = getTokenMultimedia();
|
||||
const { getTokenMultimedia } = useSession();
|
||||
const token = getTokenMultimedia();
|
||||
|
||||
export async function downloadFile(dmsId) {
|
||||
export async function downloadFile(id, model = 'dms', urlPath = '/downloadFile', url) {
|
||||
let appUrl = await getUrl('', 'lilium');
|
||||
appUrl = appUrl.replace('/#/', '');
|
||||
window.open(`${appUrl}/api/dms/${dmsId}/downloadFile?access_token=${token}`);
|
||||
window.open(url ?? `${appUrl}/api/${model}/${id}${urlPath}?access_token=${token}`);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ export function useArrayData(key, userOptions) {
|
|||
|
||||
const { limit } = filter;
|
||||
|
||||
hasMoreData.value = response.data.length === limit;
|
||||
hasMoreData.value = response.data.length >= limit;
|
||||
|
||||
if (append) {
|
||||
if (!store.data) store.data = [];
|
||||
|
|
1317
src/i18n/en/index.js
1317
src/i18n/en/index.js
File diff suppressed because it is too large
Load Diff
1316
src/i18n/es/index.js
1316
src/i18n/es/index.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
const modules = import.meta.glob(`../pages/**/locale/**.yml`);
|
||||
import translations from './index';
|
||||
const LOCALE_EXTENSION = '.yml';
|
||||
|
||||
export async function locales() {
|
||||
for await (const module of Object.keys(modules)) {
|
||||
const splittedFile = module.split('/');
|
||||
const lang = splittedFile.pop().split(LOCALE_EXTENSION)[0];
|
||||
const moduleFiles = splittedFile.join('/') + '/' + lang + LOCALE_EXTENSION;
|
||||
import(moduleFiles).then((t) => {
|
||||
Object.assign(translations[lang], t.default);
|
||||
});
|
||||
}
|
||||
return translations;
|
||||
}
|
||||
|
||||
export default translations;
|
|
@ -1,9 +1,15 @@
|
|||
import en from './en';
|
||||
import es from './es';
|
||||
export const localeEquivalence = {
|
||||
'en':'en-GB'
|
||||
const files = import.meta.glob(`./locale/*.yml`);
|
||||
const translations = {};
|
||||
|
||||
for (const file in files) {
|
||||
const lang = file.split('/').at(2).split('.')[0];
|
||||
import(file).then((t) => {
|
||||
translations[lang] = t.default;
|
||||
});
|
||||
}
|
||||
export default {
|
||||
en: en,
|
||||
es: es,
|
||||
|
||||
export const localeEquivalence = {
|
||||
en: 'en-GB',
|
||||
};
|
||||
|
||||
export default translations;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -12,6 +12,7 @@ import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue';
|
|||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
@ -177,7 +178,7 @@ function openDialog(dmsId) {
|
|||
@on-fetch="getClaimDms"
|
||||
>
|
||||
<template #header="{ entity: { claim } }">
|
||||
{{ claim.id }} - {{ claim.client.name }}
|
||||
{{ claim.id }} - {{ claim.client.name }} ({{ claim.client.id }})
|
||||
</template>
|
||||
<template #body="{ entity: { claim, salesClaimed, developments } }">
|
||||
<QCard class="vn-one">
|
||||
|
@ -214,10 +215,10 @@ function openDialog(dmsId) {
|
|||
</VnLv>
|
||||
<VnLv :label="t('claim.summary.customer')">
|
||||
<template #value>
|
||||
<VnUserLink
|
||||
:name="claim.client?.name"
|
||||
:worker-id="claim.client?.id"
|
||||
/>
|
||||
<span class="link cursor-pointer">
|
||||
{{ claim.client?.name }}
|
||||
<CustomerDescriptorProxy :id="claim.clientFk" />
|
||||
</span>
|
||||
</template>
|
||||
</VnLv>
|
||||
<VnLv
|
||||
|
|
|
@ -48,13 +48,17 @@ const zones = ref();
|
|||
</QItem>
|
||||
<QItem class="q-mb-sm">
|
||||
<QItemSection>
|
||||
<VnInput :label="t('Name')" v-model="params.name" is-outlined />
|
||||
<VnInput
|
||||
:label="t('customerFilter.filter.name')"
|
||||
v-model="params.name"
|
||||
is-outlined
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem class="q-mb-sm">
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
:label="t('Social Name')"
|
||||
:label="t('customerFilter.filter.socialName')"
|
||||
v-model="params.socialName"
|
||||
is-outlined
|
||||
/>
|
||||
|
@ -170,8 +174,6 @@ en:
|
|||
params:
|
||||
search: Contains
|
||||
fi: FI
|
||||
name: Name
|
||||
socialName: Social Name
|
||||
salesPersonFk: Salesperson
|
||||
provinceFk: Province
|
||||
city: City
|
||||
|
@ -183,8 +185,6 @@ es:
|
|||
params:
|
||||
search: Contiene
|
||||
fi: NIF
|
||||
name: Nombre
|
||||
socialName: Razón Social
|
||||
salesPersonFk: Comercial
|
||||
provinceFk: Provincia
|
||||
city: Ciudad
|
||||
|
@ -193,8 +193,6 @@ es:
|
|||
zoneFk: Zona
|
||||
postcode: CP
|
||||
FI: NIF
|
||||
Name: Nombre
|
||||
Social Name: Razón social
|
||||
Salesperson: Comercial
|
||||
Province: Provincia
|
||||
City: Ciudad
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
customerFilter:
|
||||
filter:
|
||||
name: Name
|
||||
socialName: Social name
|
|
@ -0,0 +1,4 @@
|
|||
customerFilter:
|
||||
filter:
|
||||
name: Nombre
|
||||
socialName: Razón Social
|
|
@ -63,7 +63,7 @@ const removeDepartment = () => {
|
|||
router.push({ name: 'WorkerDepartment' });
|
||||
notify('department.departmentRemoved', 'positive');
|
||||
} catch (err) {
|
||||
console.log('Error removing department');
|
||||
console.error('Error removing department');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
<script setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import CrudModel from 'components/CrudModel.vue';
|
||||
import VnRow from 'components/ui/VnRow.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
|
||||
const route = useRoute();
|
||||
const { params } = useRoute();
|
||||
const { t } = useI18n();
|
||||
|
||||
const entryObservationsRef = ref(null);
|
||||
const entryObservationsOptions = ref([]);
|
||||
const selected = ref([]);
|
||||
|
||||
const sortEntryObservationOptions = (data) => {
|
||||
entryObservationsOptions.value = [...data].sort((a, b) =>
|
||||
|
@ -24,6 +24,29 @@ const sortEntryObservationOptions = (data) => {
|
|||
onMounted(() => {
|
||||
if (entryObservationsRef.value) entryObservationsRef.value.reload();
|
||||
});
|
||||
|
||||
const columns = computed(() => [
|
||||
{
|
||||
name: 'observationType',
|
||||
label: t('entry.notes.observationType'),
|
||||
field: (row) => row.observationTypeFk,
|
||||
sortable: true,
|
||||
options: entryObservationsOptions.value,
|
||||
required: true,
|
||||
model: 'observationTypeFk',
|
||||
optionValue: 'id',
|
||||
optionLabel: 'description',
|
||||
tabIndex: 1,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
label: t('globals.description'),
|
||||
field: (row) => row.description,
|
||||
tabIndex: 2,
|
||||
align: 'left',
|
||||
},
|
||||
]);
|
||||
</script>
|
||||
<template>
|
||||
<FetchData
|
||||
|
@ -37,65 +60,90 @@ onMounted(() => {
|
|||
model="EntryAccount"
|
||||
:filter="{
|
||||
fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
|
||||
where: { entryFk: route.params.id },
|
||||
where: { entryFk: params.id },
|
||||
}"
|
||||
ref="entryObservationsRef"
|
||||
:default-remove="false"
|
||||
:data-required="{ entryFk: route.params.id }"
|
||||
:data-required="{ entryFk: params.id }"
|
||||
v-model:selected="selected"
|
||||
>
|
||||
<template #body="{ rows, validate }">
|
||||
<QCard class="q-pa-md">
|
||||
<VnRow
|
||||
v-for="(row, index) in rows"
|
||||
:key="index"
|
||||
class="row q-gutter-md q-mb-md"
|
||||
>
|
||||
<VnSelectFilter
|
||||
:label="t('entry.notes.observationType')"
|
||||
v-model="row.observationTypeFk"
|
||||
:options="entryObservationsOptions"
|
||||
:disable="!!row.id"
|
||||
option-label="description"
|
||||
option-value="id"
|
||||
hide-selected
|
||||
/>
|
||||
|
||||
<VnInput
|
||||
:label="t('globals.description')"
|
||||
v-model="row.description"
|
||||
:rules="validate('EntryObservation.description')"
|
||||
/>
|
||||
|
||||
<div class="row justify-center items-center">
|
||||
<QIcon
|
||||
name="delete"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="entryObservationsRef.remove([row])"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Remove note') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
<QTable
|
||||
v-model:selected="selected"
|
||||
:columns="columns"
|
||||
:rows="rows"
|
||||
:pagination="{ rowsPerPage: 0 }"
|
||||
row-key="$index"
|
||||
selection="multiple"
|
||||
hide-pagination
|
||||
:grid="$q.screen.lt.md"
|
||||
table-header-class="text-left"
|
||||
>
|
||||
<template #body-cell-observationType="{ row, col }">
|
||||
<QTd>
|
||||
<VnSelectFilter
|
||||
v-model="row[col.model]"
|
||||
:options="col.options"
|
||||
:option-value="col.optionValue"
|
||||
:option-label="col.optionLabel"
|
||||
:autofocus="col.tabIndex == 1"
|
||||
input-debounce="0"
|
||||
hide-selected
|
||||
:required="true"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #body-cell-description="{ row, col }">
|
||||
<QTd>
|
||||
<VnInput
|
||||
:label="t('globals.description')"
|
||||
v-model="row[col.name]"
|
||||
:rules="validate('EntryObservation.description')"
|
||||
/>
|
||||
</QTd>
|
||||
</template>
|
||||
<template #item="props">
|
||||
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
|
||||
<QCard bordered flat>
|
||||
<QCardSection>
|
||||
<QCheckbox v-model="props.selected" dense />
|
||||
</QCardSection>
|
||||
<QSeparator />
|
||||
<QList dense>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
v-model="props.row.observationTypeFk"
|
||||
:options="entryObservationsOptions"
|
||||
option-value="id"
|
||||
option-label="description"
|
||||
input-debounce="0"
|
||||
hide-selected
|
||||
:required="true"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
<QItem>
|
||||
<QItemSection>
|
||||
<VnInput
|
||||
:label="t('globals.description')"
|
||||
v-model="props.row.description"
|
||||
:rules="
|
||||
validate('EntryObservation.description')
|
||||
"
|
||||
/>
|
||||
</QItemSection>
|
||||
</QItem>
|
||||
</QList>
|
||||
</QCard>
|
||||
</div>
|
||||
</VnRow>
|
||||
<QIcon
|
||||
name="add"
|
||||
size="sm"
|
||||
class="cursor-pointer"
|
||||
color="primary"
|
||||
@click="entryObservationsRef.insert()"
|
||||
>
|
||||
<QTooltip>
|
||||
{{ t('Add note') }}
|
||||
</QTooltip>
|
||||
</QIcon>
|
||||
</QCard>
|
||||
</template>
|
||||
</QTable>
|
||||
</template>
|
||||
</CrudModel>
|
||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||
<QBtn fab color="primary" icon="add" @click="entryObservationsRef.insert()" />
|
||||
</QPageSticky>
|
||||
</template>
|
||||
|
||||
<i18n>
|
||||
es:
|
||||
Add note: Añadir nota
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<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 VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
|
@ -19,6 +21,11 @@ const props = defineProps({
|
|||
const currenciesOptions = ref([]);
|
||||
const companiesOptions = ref([]);
|
||||
const suppliersOptions = ref([]);
|
||||
|
||||
const stateStore = useStateStore();
|
||||
onMounted(async () => {
|
||||
stateStore.rightDrawer = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -58,7 +65,7 @@ const suppliersOptions = ref([]);
|
|||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.search"
|
||||
:label="t('params.search')"
|
||||
:label="t('entryFilter.filter.search')"
|
||||
is-outlined
|
||||
/>
|
||||
</QItemSection>
|
||||
|
@ -67,7 +74,7 @@ const suppliersOptions = ref([]);
|
|||
<QItemSection>
|
||||
<VnInput
|
||||
v-model="params.reference"
|
||||
:label="t('params.reference')"
|
||||
:label="t('entryFilter.filter.reference')"
|
||||
is-outlined
|
||||
/>
|
||||
</QItemSection>
|
||||
|
@ -210,8 +217,7 @@ const suppliersOptions = ref([]);
|
|||
<i18n>
|
||||
en:
|
||||
params:
|
||||
search: General search
|
||||
reference: Reference
|
||||
|
||||
invoiceNumber: Invoice number
|
||||
travelFk: Travel
|
||||
companyFk: Company
|
||||
|
@ -225,8 +231,7 @@ en:
|
|||
isOrdered: Ordered
|
||||
es:
|
||||
params:
|
||||
search: Búsqueda general
|
||||
reference: Referencia
|
||||
|
||||
invoiceNumber: Núm. factura
|
||||
travelFk: Envío
|
||||
companyFk: Empresa
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
entryList:
|
||||
list:
|
||||
inventoryEntry: 'Inventory entry'
|
||||
virtualEntry: 'Virtual entry'
|
||||
entryFilter:
|
||||
filter:
|
||||
search: 'General search'
|
||||
reference: 'Reference'
|
|
@ -0,0 +1,8 @@
|
|||
entryList:
|
||||
list:
|
||||
inventoryEntry: 'Es inventario'
|
||||
virtualEntry: 'Es una redada'
|
||||
entryFilter:
|
||||
filter:
|
||||
search: 'Búsqueda general'
|
||||
reference: 'Referencia'
|
|
@ -61,7 +61,7 @@ const data = ref(useCardDescription());
|
|||
const setData = (entity) => {
|
||||
if (!entity) return;
|
||||
data.value = useCardDescription(entity.client.name, entity.id);
|
||||
state.set('ClaimDescriptor', entity);
|
||||
state.set('OrderDescriptor', entity);
|
||||
};
|
||||
|
||||
const getConfirmationValue = (isConfirmed) => {
|
||||
|
|
|
@ -4,7 +4,6 @@ import { useI18n } from 'vue-i18n';
|
|||
|
||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
|
||||
import VnInput from 'src/components/common/VnInput.vue';
|
||||
import FetchData from 'components/FetchData.vue';
|
||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||
|
||||
|
@ -63,7 +62,7 @@ const decrement = (paramsObj, key) => {
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.agencyModeFk')"
|
||||
:label="t('travelFilter.filter.agencyModeFk')"
|
||||
v-model="params.agencyModeFk"
|
||||
@update:model-value="searchFn()"
|
||||
:options="agenciesOptions"
|
||||
|
@ -79,7 +78,7 @@ const decrement = (paramsObj, key) => {
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.warehouseOutFk')"
|
||||
:label="t('travelFilter.filter.warehouseOutFk')"
|
||||
v-model="params.warehouseOutFk"
|
||||
@update:model-value="searchFn()"
|
||||
:options="warehousesOptions"
|
||||
|
@ -95,7 +94,7 @@ const decrement = (paramsObj, key) => {
|
|||
<QItem>
|
||||
<QItemSection>
|
||||
<VnSelectFilter
|
||||
:label="t('params.warehouseInFk')"
|
||||
:label="t('travelFilter.filter.warehouseInFk')"
|
||||
v-model="params.warehouseInFk"
|
||||
@update:model-value="searchFn()"
|
||||
:options="warehousesOptions"
|
||||
|
@ -113,7 +112,7 @@ const decrement = (paramsObj, key) => {
|
|||
<QInput
|
||||
v-model="params.scopeDays"
|
||||
type="number"
|
||||
:label="t('params.scopeDays')"
|
||||
:label="t('travelFilter.filter.scopeDays')"
|
||||
dense
|
||||
outlined
|
||||
rounded
|
||||
|
@ -211,10 +210,6 @@ const decrement = (paramsObj, key) => {
|
|||
en:
|
||||
params:
|
||||
search: Id/Reference
|
||||
agencyModeFk: Agency
|
||||
warehouseInFk: Warehouse In
|
||||
warehouseOutFk: Warehouse Out
|
||||
scopeDays: Days onward
|
||||
landedFrom: Landed from
|
||||
landedTo: Landed to
|
||||
continent: Continent out
|
||||
|
@ -222,10 +217,6 @@ en:
|
|||
es:
|
||||
params:
|
||||
search: Id/Referencia
|
||||
agencyModeFk: Agencia
|
||||
warehouseInFk: Alm. entrada
|
||||
warehouseOutFk: Alm. salida
|
||||
scopeDays: Días adelante
|
||||
landedFrom: Llegada desde
|
||||
landedTo: Llegada hasta
|
||||
continent: Cont. Salida
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
travelFilter:
|
||||
filter:
|
||||
warehouseOutFk: 'Warehouse Out'
|
||||
warehouseInFk: 'Warehouse In'
|
||||
agencyModeFk: 'Agency'
|
||||
scopeDays: 'Days onward'
|
|
@ -0,0 +1,6 @@
|
|||
travelFilter:
|
||||
filter:
|
||||
warehouseInFk: 'Alm. entrada'
|
||||
warehouseOutFk: 'Alm. salida'
|
||||
agencyModeFk: 'Agencia'
|
||||
scopeDays: 'Días adelante'
|
|
@ -0,0 +1,15 @@
|
|||
<script setup>
|
||||
import VnDmsList from 'src/components/common/VnDmsList.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
const route = useRoute();
|
||||
</script>
|
||||
<template>
|
||||
<VnDmsList
|
||||
:model="`WorkerDms/${route.params.id}/filter`"
|
||||
update-model="Workers"
|
||||
delete-model="WorkerDms"
|
||||
download-model="WorkerDms"
|
||||
default-dms-code="hhrrData"
|
||||
filter="worker"
|
||||
/>
|
||||
</template>
|
|
@ -19,6 +19,7 @@ export default {
|
|||
'WorkerNotificationsManager',
|
||||
'WorkerPBX',
|
||||
'WorkerLog',
|
||||
'WorkerDms',
|
||||
],
|
||||
departmentCard: ['BasicData'],
|
||||
},
|
||||
|
@ -127,6 +128,15 @@ export default {
|
|||
},
|
||||
component: () => import('src/pages/Worker/Card/WorkerPBX.vue'),
|
||||
},
|
||||
{
|
||||
name: 'WorkerDms',
|
||||
path: 'dms',
|
||||
meta: {
|
||||
title: 'dms',
|
||||
icon: 'cloud_upload',
|
||||
},
|
||||
component: () => import('src/pages/Worker/Card/WorkerDms.vue'),
|
||||
},
|
||||
{
|
||||
name: 'WorkerLog',
|
||||
path: 'log',
|
||||
|
|
|
@ -5,37 +5,40 @@ describe('WagonTypeCreate', () => {
|
|||
cy.viewport(1920, 1080);
|
||||
cy.login('developer');
|
||||
cy.visit(`/#/entry/${entryId}/dms`);
|
||||
|
||||
});
|
||||
|
||||
it('should create edit and remove new dms', () => {
|
||||
cy.addRow();
|
||||
cy.get('.icon-attach').click()
|
||||
cy.get('.icon-attach').click();
|
||||
cy.get('.q-file').selectFile('test/cypress/fixtures/image.jpg', {
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get("tbody > tr").then((value) => {
|
||||
cy.get('tbody > tr').then((value) => {
|
||||
const u = undefined;
|
||||
|
||||
//Create and check if exist new row
|
||||
let newFileTd = Cypress.$(value).length;
|
||||
cy.get('.q-btn--standard > .q-btn__content > .block').click();
|
||||
expect(value).to.have.length(newFileTd++);
|
||||
const newRowSelector = `tbody > :nth-child(${newFileTd})`
|
||||
const newRowSelector = `tbody > :nth-child(${newFileTd})`;
|
||||
cy.waitForElement(newRowSelector);
|
||||
cy.validateRow(newRowSelector, [u, u, u, u, 'ENTRADA ID 1']);
|
||||
|
||||
//Edit new dms
|
||||
const u = undefined;
|
||||
cy.validateRow(newRowSelector, [u,u,u,u,'ENTRADA ID 1'])
|
||||
cy.get(`tbody :nth-child(${newFileTd}) > .text-right > .flex > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`).click();
|
||||
})
|
||||
// cy.log('newFileTd', newFileTd)
|
||||
const newDescription = 'entry id 1 modified';
|
||||
const textAreaSelector =
|
||||
'.q-textarea > .q-field__inner > .q-field__control > .q-field__control-container';
|
||||
cy.get(
|
||||
`tbody :nth-child(${newFileTd}) > .text-right > .no-wrap > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`
|
||||
).click();
|
||||
|
||||
// //Create and check if exist new row
|
||||
// cy.log('newFileTd:', newFileTd);
|
||||
// cy.get(`tbody :nth-child(${newFileTd}) > .text-right > .flex > :nth-child(2) > .q-btn > .q-btn__content > .q-icon`).click()
|
||||
cy.get(textAreaSelector).clear();
|
||||
cy.get(textAreaSelector).type(newDescription);
|
||||
cy.saveCard();
|
||||
cy.reload();
|
||||
|
||||
// cy.get(`tbody :nth-child(${newFileTd}) > :nth-child(5) > .q-tr > :nth-child(1) > span`).then((value) => {
|
||||
// cy.log(value)
|
||||
// });
|
||||
cy.validateRow(newRowSelector, [u, u, u, u, newDescription]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -37,6 +37,7 @@ describe('InvoiceInVat', () => {
|
|||
|
||||
it('should throw an error if there are fields undefined', () => {
|
||||
cy.get(inputBtns).eq(0).click();
|
||||
cy.get(':nth-child(1) > .q-td.q-table--col-auto-width > .q-field > .q-field__inner > .q-field__control > :nth-child(2) > .default-icon').click();
|
||||
cy.get(dialogBtns).eq(2).click();
|
||||
cy.get('.q-notification__message').should('have.text', "The code can't be empty");
|
||||
});
|
||||
|
@ -44,7 +45,7 @@ describe('InvoiceInVat', () => {
|
|||
it('should correctly handle expense addition', () => {
|
||||
cy.get(inputBtns).eq(0).click();
|
||||
|
||||
cy.get(dialogInputs).eq(0).click();
|
||||
cy.get(':nth-child(1) > .q-td.q-table--col-auto-width > .q-field > .q-field__inner > .q-field__control > :nth-child(2) > .default-icon').click();
|
||||
cy.get(dialogInputs).eq(0).type(randomInt);
|
||||
cy.get(dialogInputs).eq(1).click();
|
||||
cy.get(dialogInputs).eq(1).type('This is a dummy expense');
|
||||
|
|
|
@ -8,9 +8,9 @@ describe('WorkerList', () => {
|
|||
});
|
||||
|
||||
it('should load workers', () => {
|
||||
cy.get(workerFieldNames).eq(0).should('have.text', 'JessicaJones');
|
||||
cy.get(workerFieldNames).eq(1).should('have.text', 'BruceBanner');
|
||||
cy.get(workerFieldNames).eq(2).should('have.text', 'CharlesXavier');
|
||||
cy.get(workerFieldNames).eq(0).should('have.text', 'jessicajones');
|
||||
cy.get(workerFieldNames).eq(1).should('have.text', 'brucebanner');
|
||||
cy.get(workerFieldNames).eq(2).should('have.text', 'charlesxavier');
|
||||
});
|
||||
|
||||
it('should open the worker summary', () => {
|
||||
|
|
|
@ -60,7 +60,6 @@ describe('WorkerNotificationsManager', () => {
|
|||
it('should active a notification if you are their boss', () => {
|
||||
cy.login('salesBoss');
|
||||
cy.visit(`/#/worker/${salesPersonId}/notifications`);
|
||||
cy.waitForElement(activeList);
|
||||
cy.waitForElement(availableList);
|
||||
|
||||
cy.get(activeList)
|
||||
|
|
|
@ -6,7 +6,8 @@ describe('WorkerSummary', () => {
|
|||
});
|
||||
|
||||
it('should load worker summary', () => {
|
||||
cy.get('.summaryHeader > div').should('have.text', '19 - salesBoss salesBoss');
|
||||
cy.waitForElement('.summaryHeader');
|
||||
cy.get('.summaryHeader > div').should('have.text', '19 - salesboss salesboss');
|
||||
cy.get(':nth-child(1) > :nth-child(2) > .value > span').should(
|
||||
'have.text',
|
||||
'salesBossNick'
|
||||
|
|
|
@ -19,7 +19,7 @@ export default defineConfig({
|
|||
plugins: [
|
||||
vue({
|
||||
template: {
|
||||
transformAssetUrls
|
||||
transformAssetUrls,
|
||||
},
|
||||
}),
|
||||
quasar({
|
||||
|
|
Loading…
Reference in New Issue