Merge branch 'dev' of https: refs #8725//gitea.verdnatura.es/verdnatura/salix-front into 8725_submit_form_onClick
gitea/salix-front/pipeline/pr-dev This commit is unstable Details

This commit is contained in:
Javier Segarra 2025-03-24 03:31:04 +01:00
commit 6c4136fb58
178 changed files with 11504 additions and 14772 deletions

6
Jenkinsfile vendored
View File

@ -115,21 +115,25 @@ pipeline {
steps { steps {
script { script {
sh 'rm -f junit/e2e-*.xml' sh 'rm -f junit/e2e-*.xml'
sh 'rm -rf test/cypress/screenshots'
env.COMPOSE_TAG = PROTECTED_BRANCH.contains(env.CHANGE_TARGET) ? env.CHANGE_TARGET : 'dev' env.COMPOSE_TAG = PROTECTED_BRANCH.contains(env.CHANGE_TARGET) ? env.CHANGE_TARGET : 'dev'
def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs') def image = docker.build('lilium-dev', '-f docs/Dockerfile.dev docs')
sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY' sh 'docker login --username $CREDS_USR --password $CREDS_PSW $REGISTRY'
sh "docker-compose ${env.COMPOSE_PARAMS} pull back"
sh "docker-compose ${env.COMPOSE_PARAMS} pull db"
sh "docker-compose ${env.COMPOSE_PARAMS} up -d" sh "docker-compose ${env.COMPOSE_PARAMS} up -d"
image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") { image.inside("--network ${env.COMPOSE_PROJECT}_default -e CI -e TZ --init") {
sh 'sh test/cypress/cypressParallel.sh 2' sh 'sh test/cypress/cypressParallel.sh 1'
} }
} }
} }
post { post {
always { always {
sh "docker-compose ${env.COMPOSE_PARAMS} down -v" sh "docker-compose ${env.COMPOSE_PARAMS} down -v"
archiveArtifacts artifacts: 'test/cypress/screenshots/**/*', allowEmptyArchive: true
junit( junit(
testResults: 'junit/e2e-*.xml', testResults: 'junit/e2e-*.xml',
allowEmptyResults: true allowEmptyResults: true

View File

@ -32,6 +32,18 @@ pnpm run test:front
pnpm run test:e2e pnpm run test:e2e
``` ```
### Run e2e parallel
```bash
pnpm run test:e2e:parallel
```
### View e2e parallel report
```bash
pnpm run test:e2e:summary
```
### Build the app for production ### Build the app for production
```bash ```bash

View File

@ -1,6 +1,6 @@
{ {
"name": "salix-front", "name": "salix-front",
"version": "25.12.0", "version": "25.14.0",
"description": "Salix frontend", "description": "Salix frontend",
"productName": "Salix", "productName": "Salix",
"author": "Verdnatura", "author": "Verdnatura",
@ -13,7 +13,7 @@
"format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore", "format": "prettier --write \"**/*.{js,vue,scss,html,md,json}\" --ignore-path .gitignore",
"test:e2e": "cypress open", "test:e2e": "cypress open",
"test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run", "test:e2e:ci": "npm run resetDatabase && cd ../salix-front && cypress run",
"test:e2e:parallel": "bash ./test/cypress/cypressParallel.sh", "test:e2e:parallel": "bash ./test/cypress/run.sh",
"test:e2e:summary": "bash ./test/cypress/summary.sh", "test:e2e:summary": "bash ./test/cypress/summary.sh",
"test": "echo \"See package.json => scripts for available tests.\" && exit 0", "test": "echo \"See package.json => scripts for available tests.\" && exit 0",
"test:front": "vitest", "test:front": "vitest",
@ -56,6 +56,7 @@
"eslint-plugin-cypress": "^4.1.0", "eslint-plugin-cypress": "^4.1.0",
"eslint-plugin-vue": "^9.32.0", "eslint-plugin-vue": "^9.32.0",
"husky": "^8.0.0", "husky": "^8.0.0",
"junit-merge": "^2.0.0",
"mocha": "^11.1.0", "mocha": "^11.1.0",
"postcss": "^8.4.23", "postcss": "^8.4.23",
"prettier": "^3.4.2", "prettier": "^3.4.2",

File diff suppressed because it is too large Load Diff

View File

@ -181,9 +181,8 @@ async function saveChanges(data) {
return; return;
} }
let changes = data || getChanges(); let changes = data || getChanges();
if ($props.beforeSaveFn) { if ($props.beforeSaveFn) changes = await $props.beforeSaveFn(changes, getChanges);
changes = await $props.beforeSaveFn(changes, getChanges);
}
try { try {
if (changes?.creates?.length === 0 && changes?.updates?.length === 0) { if (changes?.creates?.length === 0 && changes?.updates?.length === 0) {
return; return;
@ -194,7 +193,7 @@ async function saveChanges(data) {
isLoading.value = false; isLoading.value = false;
} }
originalData.value = JSON.parse(JSON.stringify(formData.value)); originalData.value = JSON.parse(JSON.stringify(formData.value));
if (changes.creates?.length) await vnPaginateRef.value.fetch(); if (changes?.creates?.length) await vnPaginateRef.value.fetch();
hasChanges.value = false; hasChanges.value = false;
emit('saveChanges', data); emit('saveChanges', data);

View File

@ -140,7 +140,7 @@ const $props = defineProps({
}, },
dataCy: { dataCy: {
type: String, type: String,
default: 'vn-table', default: 'vnTable',
}, },
}); });
@ -595,18 +595,17 @@ function cardClick(_, row) {
function removeTextValue(data, getChanges) { function removeTextValue(data, getChanges) {
let changes = data.updates; let changes = data.updates;
if (!changes) return data; if (changes) {
for (const change of changes) {
for (const change of changes) { for (const key in change.data) {
for (const key in change.data) { if (key.endsWith('VnTableTextValue')) {
if (key.endsWith('VnTableTextValue')) { delete change.data[key];
delete change.data[key]; }
} }
} }
data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
} }
data.updates = changes.filter((change) => Object.keys(change.data).length > 0);
if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges); if ($attrs?.beforeSaveFn) data = $attrs.beforeSaveFn(data, getChanges);
return data; return data;
@ -685,7 +684,7 @@ const rowCtrlClickFunction = computed(() => {
@update:selected="emit('update:selected', $event)" @update:selected="emit('update:selected', $event)"
@selection="(details) => handleSelection(details, rows)" @selection="(details) => handleSelection(details, rows)"
:hide-selected-banner="true" :hide-selected-banner="true"
:data-cy="$props.dataCy ?? 'vnTable'" :data-cy
> >
<template #top-left v-if="!$props.withoutHeader"> <template #top-left v-if="!$props.withoutHeader">
<slot name="top-left"> </slot> <slot name="top-left"> </slot>
@ -776,12 +775,13 @@ const rowCtrlClickFunction = computed(() => {
:data-col-field="col?.name" :data-col-field="col?.name"
> >
<div <div
class="no-padding no-margin peter" class="no-padding no-margin"
style=" style="
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
" "
:data-cy="`vnTableCell_${col.name}`"
> >
<slot <slot
:name="`column-${col.name}`" :name="`column-${col.name}`"
@ -978,6 +978,8 @@ const rowCtrlClickFunction = computed(() => {
v-for="col of cols.filter((cols) => cols.visible ?? true)" v-for="col of cols.filter((cols) => cols.visible ?? true)"
:key="col?.id" :key="col?.id"
:class="getColAlign(col)" :class="getColAlign(col)"
:style="col?.width ? `max-width: ${col?.width}` : ''"
style="font-size: small"
> >
<slot <slot
:name="`column-footer-${col.name}`" :name="`column-footer-${col.name}`"
@ -1040,39 +1042,44 @@ const rowCtrlClickFunction = computed(() => {
@on-data-saved="(_, res) => createForm.onDataSaved(res)" @on-data-saved="(_, res) => createForm.onDataSaved(res)"
> >
<template #form-inputs="{ data, validations }"> <template #form-inputs="{ data, validations }">
<div :style="createComplement?.containerStyle"> <slot name="alter-create" :data="data">
<div <div :style="createComplement?.containerStyle">
:style="createComplement?.previousStyle" <div
v-if="!quasar.screen.xs" :style="createComplement?.previousStyle"
> v-if="!quasar.screen.xs"
<slot name="previous-create-dialog" :data="data" />
</div>
<div class="grid-create" :style="createComplement?.columnGridStyle">
<slot
v-for="column of splittedColumns.create"
:key="column.name"
:name="`column-create-${column.name}`"
:data="data"
:validations="validations"
:column-name="column.name"
:label="column.label"
> >
<VnColumn <slot name="previous-create-dialog" :data="data" />
:column="{ </div>
...column, <div
...{ disable: column?.createDisable ?? false }, class="grid-create"
}" :style="createComplement?.columnGridStyle"
:row="{}" >
default="input" <slot
v-model="data[column.name]" v-for="column of splittedColumns.create"
:show-label="true" :key="column.name"
component-prop="columnCreate" :name="`column-create-${column.name}`"
:data-cy="`${column.name}-create-popup`" :data="data"
/> :validations="validations"
</slot> :column-name="column.name"
<slot name="more-create-dialog" :data="data" /> :label="column.label"
>
<VnColumn
:column="{
...column,
...column?.createAttrs,
}"
:row="{}"
default="input"
v-model="data[column.name]"
:show-label="true"
component-prop="columnCreate"
:data-cy="`${column.name}-create-popup`"
/>
</slot>
<slot name="more-create-dialog" :data="data" />
</div>
</div> </div>
</div> </slot>
</template> </template>
</FormModelPopup> </FormModelPopup>
</QDialog> </QDialog>

View File

@ -47,14 +47,6 @@ vi.mock('src/router/modules', () => ({
], ],
}, },
}, },
{
path: 'create',
name: 'CustomerCreate',
meta: {
title: 'createCustomer',
icon: 'vn:addperson',
},
},
], ],
}, },
], ],

View File

@ -27,7 +27,11 @@ const checkboxModel = computed({
</script> </script>
<template> <template>
<div> <div>
<QCheckbox v-bind="$attrs" v-model="checkboxModel" /> <QCheckbox
v-bind="$attrs"
v-model="checkboxModel"
:data-cy="$attrs['data-cy'] ?? `vnCheckbox${$attrs['label'] ?? ''}`"
/>
<QIcon <QIcon
v-if="info" v-if="info"
v-bind="$attrs" v-bind="$attrs"

View File

@ -177,6 +177,7 @@ function addDefaultData(data) {
name="vn:attach" name="vn:attach"
class="cursor-pointer" class="cursor-pointer"
@click="inputFileRef.pickFiles()" @click="inputFileRef.pickFiles()"
data-cy="attachFile"
> >
<QTooltip>{{ t('globals.selectFile') }}</QTooltip> <QTooltip>{{ t('globals.selectFile') }}</QTooltip>
</QIcon> </QIcon>

View File

@ -389,10 +389,7 @@ defineExpose({
</div> </div>
</template> </template>
</QTable> </QTable>
<div <div v-else class="info-row q-pa-md text-center">
v-else
class="info-row q-pa-md text-center"
>
<h5> <h5>
{{ t('No data to display') }} {{ t('No data to display') }}
</h5> </h5>
@ -416,6 +413,7 @@ defineExpose({
v-shortcut v-shortcut
@click="showFormDialog()" @click="showFormDialog()"
class="fill-icon" class="fill-icon"
data-cy="addButton"
> >
<QTooltip> <QTooltip>
{{ t('Upload file') }} {{ t('Upload file') }}

View File

@ -107,7 +107,7 @@ const manageDate = (date) => {
@click="isPopupOpen = !isPopupOpen" @click="isPopupOpen = !isPopupOpen"
@keydown="isPopupOpen = false" @keydown="isPopupOpen = false"
hide-bottom-space hide-bottom-space
:data-cy="$attrs.dataCy ?? $attrs.label + '_inputDate'" :data-cy="($attrs['data-cy'] ?? $attrs.label) + '_inputDate'"
> >
<template #append> <template #append>
<QIcon <QIcon

View File

@ -10,7 +10,7 @@ import { useColor } from 'src/composables/useColor';
import { useCapitalize } from 'src/composables/useCapitalize'; import { useCapitalize } from 'src/composables/useCapitalize';
import { useValidator } from 'src/composables/useValidator'; import { useValidator } from 'src/composables/useValidator';
import VnAvatar from '../ui/VnAvatar.vue'; import VnAvatar from '../ui/VnAvatar.vue';
import VnJsonValue from '../common/VnJsonValue.vue'; import VnLogValue from './VnLogValue.vue';
import FetchData from '../FetchData.vue'; import FetchData from '../FetchData.vue';
import VnSelect from './VnSelect.vue'; import VnSelect from './VnSelect.vue';
import VnUserLink from '../ui/VnUserLink.vue'; import VnUserLink from '../ui/VnUserLink.vue';
@ -560,10 +560,11 @@ watch(
value.nameI18n value.nameI18n
}}: }}:
</span> </span>
<VnJsonValue <VnLogValue
:value=" :value="
value.val.val value.val.val
" "
:name="value.name"
/> />
</QItem> </QItem>
</QCardSection> </QCardSection>
@ -614,7 +615,11 @@ watch(
> >
{{ prop.nameI18n }}: {{ prop.nameI18n }}:
</span> </span>
<VnJsonValue :value="prop.val.val" /> <VnLogValue
:value="prop.val.val"
:name="prop.name"
/>
<VnIconLink />
<span <span
v-if=" v-if="
propIndex < propIndex <
@ -642,8 +647,9 @@ watch(
{{ prop.nameI18n }}: {{ prop.nameI18n }}:
</span> </span>
<span v-if="log.action == 'update'"> <span v-if="log.action == 'update'">
<VnJsonValue <VnLogValue
:value="prop.old.val" :value="prop.old.val"
:name="prop.name"
/> />
<span <span
v-if="prop.old.id" v-if="prop.old.id"
@ -652,8 +658,9 @@ watch(
#{{ prop.old.id }} #{{ prop.old.id }}
</span> </span>
<VnJsonValue <VnLogValue
:value="prop.val.val" :value="prop.val.val"
:name="prop.name"
/> />
<span <span
v-if="prop.val.id" v-if="prop.val.id"
@ -663,8 +670,9 @@ watch(
</span> </span>
</span> </span>
<span v-else="prop.old.val"> <span v-else="prop.old.val">
<VnJsonValue <VnLogValue
:value="prop.val.val" :value="prop.val.val"
:name="prop.name"
/> />
<span <span
v-if="prop.old.id" v-if="prop.old.id"

View File

@ -0,0 +1,22 @@
<script setup>
import { useDescriptorStore } from 'src/stores/useDescriptorStore';
import VnJsonValue from './VnJsonValue.vue';
import { computed } from 'vue';
const descriptorStore = useDescriptorStore();
const $props = defineProps({
name: { type: [String], default: undefined },
});
const descriptor = computed(() => descriptorStore.has($props.name));
</script>
<template>
<VnJsonValue v-bind="$attrs" />
<QIcon
name="launch"
class="link"
v-if="$attrs.value && descriptor"
:data-cy="'iconLaunch-' + $props.name"
/>
<component :is="descriptor" :id="$attrs.value" v-if="$attrs.value && descriptor" />
</template>

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue'; import { ref, toRefs, computed, watch, onMounted, useAttrs, nextTick } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import { useRequired } from 'src/composables/useRequired'; import { useRequired } from 'src/composables/useRequired';
@ -247,6 +247,7 @@ async function fetchFilter(val) {
} }
async function filterHandler(val, update) { async function filterHandler(val, update) {
if (isLoading.value) return update();
if (!val && lastVal.value === val) { if (!val && lastVal.value === val) {
lastVal.value = val; lastVal.value = val;
return update(); return update();
@ -294,6 +295,7 @@ async function onScroll({ to, direction, from, index }) {
await arrayData.loadMore(); await arrayData.loadMore();
setOptions(arrayData.store.data); setOptions(arrayData.store.data);
vnSelectRef.value.scrollTo(lastIndex); vnSelectRef.value.scrollTo(lastIndex);
await nextTick();
isLoading.value = false; isLoading.value = false;
} }
} }

View File

@ -0,0 +1,26 @@
import { describe, it, expect } from 'vitest';
import VnLogValue from 'src/components/common/VnLogValue.vue';
import { createWrapper } from 'app/test/vitest/helper';
const buildComponent = (props) => {
return createWrapper(VnLogValue, {
props,
global: {},
}).wrapper;
};
describe('VnLogValue', () => {
const id = 1;
it('renders without descriptor', async () => {
expect(getIcon('inventFk').exists()).toBe(false);
});
it('renders with descriptor', async () => {
expect(getIcon('claimFk').text()).toBe('launch');
});
function getIcon(name) {
const wrapper = buildComponent({ value: { val: id }, name });
return wrapper.find('.q-icon');
}
});

View File

@ -38,6 +38,10 @@ const $props = defineProps({
type: String, type: String,
default: 'md-width', default: 'md-width',
}, },
toModule: {
type: String,
default: null,
},
}); });
const state = useState(); const state = useState();
@ -129,6 +133,9 @@ const emit = defineEmits(['onFetch']);
const iconModule = computed(() => { const iconModule = computed(() => {
moduleName.value = getName(); moduleName.value = getName();
if ($props.toModule) {
return router.getRoutes().find((r) => r.name === $props.toModule.name).meta.icon;
}
if (isSameModuleName) { if (isSameModuleName) {
return router.options.routes[1].children.find((r) => r.name === moduleName.value) return router.options.routes[1].children.find((r) => r.name === moduleName.value)
?.meta?.icon; ?.meta?.icon;
@ -139,9 +146,10 @@ const iconModule = computed(() => {
const toModule = computed(() => { const toModule = computed(() => {
moduleName.value = getName(); moduleName.value = getName();
if ($props.toModule) return $props.toModule;
if (isSameModuleName) { if (isSameModuleName) {
return router.options.routes[1].children.find((r) => r.name === moduleName.value) return router.options.routes[1].children.find((r) => r.name === moduleName.value)
?.children[0]?.redirect; ?.redirect;
} else { } else {
return route.matched[1].path.split('/').length > 2 return route.matched[1].path.split('/').length > 2
? route.matched[1].redirect ? route.matched[1].redirect
@ -151,7 +159,7 @@ const toModule = computed(() => {
</script> </script>
<template> <template>
<div class="descriptor"> <div class="descriptor" data-cy="cardDescriptor">
<template v-if="entity && !isLoading"> <template v-if="entity && !isLoading">
<div class="header bg-primary q-pa-sm justify-between"> <div class="header bg-primary q-pa-sm justify-between">
<slot name="header-extra-action"> <slot name="header-extra-action">
@ -180,6 +188,7 @@ const toModule = computed(() => {
color="white" color="white"
class="link" class="link"
v-if="summary" v-if="summary"
data-cy="openSummaryBtn"
> >
<QTooltip> <QTooltip>
{{ t('components.smartCard.openSummary') }} {{ t('components.smartCard.openSummary') }}
@ -194,6 +203,7 @@ const toModule = computed(() => {
icon="launch" icon="launch"
round round
size="md" size="md"
data-cy="goToSummaryBtn"
> >
<QTooltip> <QTooltip>
{{ t('components.cardDescriptor.summary') }} {{ t('components.cardDescriptor.summary') }}
@ -211,18 +221,27 @@ const toModule = computed(() => {
<QList dense> <QList dense>
<QItemLabel header class="ellipsis text-h5" :lines="1"> <QItemLabel header class="ellipsis text-h5" :lines="1">
<div class="title"> <div class="title">
<span v-if="$props.title" :title="getValueFromPath(title)"> <span
v-if="$props.title"
:title="getValueFromPath(title)"
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_title`"
>
{{ getValueFromPath(title) ?? $props.title }} {{ getValueFromPath(title) ?? $props.title }}
</span> </span>
<slot v-else name="description" :entity="entity"> <slot v-else name="description" :entity="entity">
<span :title="entity.name"> <span
{{ entity.name }} :title="entity.name"
</span> :data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_description`"
v-text="entity.name"
/>
</slot> </slot>
</div> </div>
</QItemLabel> </QItemLabel>
<QItem> <QItem>
<QItemLabel class="subtitle"> <QItemLabel
class="subtitle"
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_subtitle`"
>
#{{ getValueFromPath(subtitle) ?? entity.id }} #{{ getValueFromPath(subtitle) ?? entity.id }}
</QItemLabel> </QItemLabel>
<QBtn <QBtn
@ -240,7 +259,10 @@ const toModule = computed(() => {
</QBtn> </QBtn>
</QItem> </QItem>
</QList> </QList>
<div class="list-box q-mt-xs"> <div
class="list-box q-mt-xs"
:data-cy="`${$attrs['data-cy'] ?? 'cardDescriptor'}_listbox`"
>
<slot name="body" :entity="entity" /> <slot name="body" :entity="entity" />
</div> </div>
</div> </div>

View File

@ -81,6 +81,7 @@ async function fetch() {
name: `${moduleName ?? route.meta.moduleName}Summary`, name: `${moduleName ?? route.meta.moduleName}Summary`,
params: { id: entityId || entity.id }, params: { id: entityId || entity.id },
}" }"
data-cy="goToSummaryBtn"
> >
<QIcon name="open_in_new" color="white" size="sm" /> <QIcon name="open_in_new" color="white" size="sm" />
</router-link> </router-link>

View File

@ -249,7 +249,7 @@ const getLocale = (label) => {
:key="chip.label" :key="chip.label"
:removable="!unremovableParams?.includes(chip.label)" :removable="!unremovableParams?.includes(chip.label)"
@remove="remove(chip.label)" @remove="remove(chip.label)"
data-cy="vnFilterPanelChip" :data-cy="`vnFilterPanelChip_${chip.label}`"
> >
<slot <slot
name="tags" name="tags"

View File

@ -28,7 +28,7 @@ function copyValueText() {
const val = computed(() => $props.value); const val = computed(() => $props.value);
</script> </script>
<template> <template>
<div class="vn-label-value"> <div class="vn-label-value" :data-cy="`${$attrs['data-cy'] ?? 'vnLv'}${label ?? ''}`">
<QCheckbox <QCheckbox
v-if="typeof value === 'boolean'" v-if="typeof value === 'boolean'"
v-model="val" v-model="val"

View File

@ -12,7 +12,7 @@
{{ $t('components.cardDescriptor.moreOptions') }} {{ $t('components.cardDescriptor.moreOptions') }}
</QTooltip> </QTooltip>
<QMenu ref="menuRef" data-cy="descriptor-more-opts-menu"> <QMenu ref="menuRef" data-cy="descriptor-more-opts-menu">
<QList> <QList data-cy="descriptor-more-opts_list">
<slot name="menu" :menu-ref="$refs.menuRef" /> <slot name="menu" :menu-ref="$refs.menuRef" />
</QList> </QList>
</QMenu> </QMenu>

View File

@ -99,7 +99,6 @@ globals:
file: File file: File
selectFile: Select a file selectFile: Select a file
copyClipboard: Copy on clipboard copyClipboard: Copy on clipboard
salesPerson: SalesPerson
send: Send send: Send
code: Code code: Code
since: Since since: Since
@ -158,6 +157,7 @@ globals:
changeState: Change state changeState: Change state
raid: 'Raid {daysInForward} days' raid: 'Raid {daysInForward} days'
isVies: Vies isVies: Vies
department: Department
noData: No data available noData: No data available
vehicle: Vehicle vehicle: Vehicle
pageTitles: pageTitles:
@ -347,7 +347,6 @@ globals:
params: params:
description: Description description: Description
clientFk: Client id clientFk: Client id
salesPersonFk: Sales person
warehouseFk: Warehouse warehouseFk: Warehouse
provinceFk: Province provinceFk: Province
stateFk: State stateFk: State
@ -605,7 +604,6 @@ worker:
balance: Balance balance: Balance
medical: Medical medical: Medical
list: list:
department: Department
schedule: Schedule schedule: Schedule
newWorker: New worker newWorker: New worker
summary: summary:
@ -864,7 +862,6 @@ components:
mine: For me mine: For me
hasMinPrice: Minimum price hasMinPrice: Minimum price
# LatestBuysFilter # LatestBuysFilter
salesPersonFk: Buyer
supplierFk: Supplier supplierFk: Supplier
from: From from: From
to: To to: To
@ -895,6 +892,8 @@ components:
VnLv: VnLv:
copyText: '{copyValue} has been copied to the clipboard' copyText: '{copyValue} has been copied to the clipboard'
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789' iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
VnNotes:
clientWithoutPhone: 'The following clients do not have a phone number and the message will not be sent to them: {clientWithoutPhone}'
weekdays: weekdays:
sun: Sunday sun: Sunday
mon: Monday mon: Monday

View File

@ -103,7 +103,6 @@ globals:
file: Fichero file: Fichero
selectFile: Seleccione un fichero selectFile: Seleccione un fichero
copyClipboard: Copiar en portapapeles copyClipboard: Copiar en portapapeles
salesPerson: Comercial
send: Enviar send: Enviar
code: Código code: Código
since: Desde since: Desde
@ -163,6 +162,7 @@ globals:
raid: 'Redada {daysInForward} días' raid: 'Redada {daysInForward} días'
isVies: Vies isVies: Vies
noData: Datos no disponibles noData: Datos no disponibles
department: Departamento
vehicle: Vehículo vehicle: Vehículo
pageTitles: pageTitles:
logIn: Inicio de sesión logIn: Inicio de sesión
@ -350,7 +350,6 @@ globals:
params: params:
description: Descripción description: Descripción
clientFk: Id cliente clientFk: Id cliente
salesPersonFk: Comercial
warehouseFk: Almacén warehouseFk: Almacén
provinceFk: Provincia provinceFk: Provincia
stateFk: Estado stateFk: Estado
@ -532,7 +531,6 @@ ticket:
state: Estado state: Estado
shipped: Enviado shipped: Enviado
landed: Entregado landed: Entregado
salesPerson: Comercial
total: Total total: Total
card: card:
customerId: ID cliente customerId: ID cliente
@ -624,8 +622,6 @@ invoiceOut:
errors: errors:
downloadCsvFailed: Error al descargar CSV downloadCsvFailed: Error al descargar CSV
order: order:
field:
salesPersonFk: Comercial
form: form:
clientFk: Cliente clientFk: Cliente
addressFk: Dirección addressFk: Dirección
@ -693,7 +689,6 @@ worker:
formation: Formación formation: Formación
medical: Mutua medical: Mutua
list: list:
department: Departamento
schedule: Horario schedule: Horario
newWorker: Nuevo trabajador newWorker: Nuevo trabajador
summary: summary:
@ -951,7 +946,6 @@ components:
hasMinPrice: Precio mínimo hasMinPrice: Precio mínimo
wareHouseFk: Almacén wareHouseFk: Almacén
# LatestBuysFilter # LatestBuysFilter
salesPersonFk: Comprador
supplierFk: Proveedor supplierFk: Proveedor
visible: Visible visible: Visible
active: Activo active: Activo
@ -982,6 +976,8 @@ components:
VnLv: VnLv:
copyText: '{copyValue} se ha copiado al portapepeles' copyText: '{copyValue} se ha copiado al portapepeles'
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789' iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789'
VnNotes:
clientWithoutPhone: 'Estos clientes no tienen asociado número de télefono y el sms no les será enviado: {clientWithoutPhone}'
weekdays: weekdays:
sun: Domingo sun: Domingo
mon: Lunes mon: Lunes

View File

@ -53,6 +53,7 @@ const removeAlias = () => {
:url="`MailAliases/${entityId}`" :url="`MailAliases/${entityId}`"
data-key="Alias" data-key="Alias"
title="alias" title="alias"
:to-module="{ name: 'AccountAlias' }"
> >
<template #menu> <template #menu>
<QItem v-ripple clickable @click="removeAlias()"> <QItem v-ripple clickable @click="removeAlias()">

View File

@ -0,0 +1,14 @@
<script setup>
import AccountDescriptor from './AccountDescriptor.vue';
import AccountSummary from './AccountSummary.vue';
</script>
<template>
<QPopupProxy style="max-width: 10px">
<AccountDescriptor
v-if="$attrs.id"
v-bind="$attrs.id"
:summary="AccountSummary"
:proxy-render="true"
/>
</QPopupProxy>
</template>

View File

@ -37,6 +37,7 @@ const removeRole = async () => {
:filter="{ where: { id: entityId } }" :filter="{ where: { id: entityId } }"
data-key="Role" data-key="Role"
:summary="$props.summary" :summary="$props.summary"
:to-module="{ name: 'AccountRoles' }"
> >
<template #menu> <template #menu>
<QItem v-ripple clickable @click="removeRole()"> <QItem v-ripple clickable @click="removeRole()">

View File

@ -5,6 +5,7 @@ import { useI18n } from 'vue-i18n';
import { toDateHourMinSec, toPercentage } from 'src/filters'; import { toDateHourMinSec, toPercentage } from 'src/filters';
import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'pages/Ticket/Card/TicketDescriptorProxy.vue';
import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue'; import ClaimDescriptorMenu from 'pages/Claim/Card/ClaimDescriptorMenu.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue';
@ -65,12 +66,12 @@ onMounted(async () => {
</template> </template>
</VnLv> </VnLv>
<VnLv :label="t('claim.created')" :value="toDateHourMinSec(entity.created)" /> <VnLv :label="t('claim.created')" :value="toDateHourMinSec(entity.created)" />
<VnLv :label="t('claim.commercial')"> <VnLv :label="t('globals.department')">
<template #value> <template #value>
<VnUserLink <span class="link">
:name="entity.client?.salesPersonUser?.name" {{ entity?.client?.department?.name || '-' }}
:worker-id="entity.client?.salesPersonFk" <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
/> </span>
</template> </template>
</VnLv> </VnLv>
<VnLv <VnLv

View File

@ -0,0 +1,14 @@
<script setup>
import ClaimDescriptor from './ClaimDescriptor.vue';
import ClaimSummary from './ClaimSummary.vue';
</script>
<template>
<QPopupProxy style="max-width: 10px">
<ClaimDescriptor
v-if="$attrs.id"
v-bind="$attrs.id"
:summary="ClaimSummary"
:proxy-render="true"
/>
</QPopupProxy>
</template>

View File

@ -14,7 +14,7 @@ export default {
relation: 'client', relation: 'client',
scope: { scope: {
include: [ include: [
{ relation: 'salesPersonUser' }, { relation: 'department' },
{ {
relation: 'claimsRatio', relation: 'claimsRatio',
scope: { scope: {

View File

@ -117,7 +117,7 @@ const selected = ref([]);
const mana = ref(0); const mana = ref(0);
async function fetchMana() { async function fetchMana() {
const ticketId = claim.value.ticketFk; const ticketId = claim.value.ticketFk;
const response = await axios.get(`Tickets/${ticketId}/getSalesPersonMana`); const response = await axios.get(`Tickets/${ticketId}/getDepartmentMana`);
mana.value = response.data; mana.value = response.data;
} }

View File

@ -19,6 +19,7 @@ import ClaimNotes from 'src/pages/Claim/Card/ClaimNotes.vue';
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue'; import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import ClaimDescriptorMenu from './ClaimDescriptorMenu.vue'; import ClaimDescriptorMenu from './ClaimDescriptorMenu.vue';
const route = useRoute(); const route = useRoute();
@ -252,13 +253,15 @@ function claimUrl(section) {
</VnLv> </VnLv>
<VnLv <VnLv
v-if="$route.name != 'ClaimSummary'" v-if="$route.name != 'ClaimSummary'"
:label="t('globals.salesPerson')" :label="t('customer.summary.team')"
> >
<template #value> <template #value>
<VnUserLink <span class="link">
:name="claim.client?.salesPersonUser?.name" {{ claim?.client?.department?.name || '-' }}
:worker-id="claim.client?.salesPersonFk" <DepartmentDescriptorProxy
/> :id="claim?.client?.departmentFk"
/>
</span>
</template> </template>
</VnLv> </VnLv>
<VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.attendedBy')"> <VnLv v-if="$route.name != 'ClaimSummary'" :label="t('claim.attendedBy')">

View File

@ -44,15 +44,14 @@ const props = defineProps({
is-outlined is-outlined
/> />
<VnSelect <VnSelect
:label="t('Salesperson')"
v-model="params.salesPersonFk"
url="Workers/activeWithInheritedRole"
:filter="{ where: { role: 'salesPerson' } }"
:use-like="false"
option-filter="firstName"
dense
outlined outlined
dense
rounded rounded
:label="t('globals.params.departmentFk')"
v-model="params.departmentFk"
option-value="id"
option-label="name"
url="Departments"
/> />
<VnSelect <VnSelect
:label="t('claim.attendedBy')" :label="t('claim.attendedBy')"
@ -126,7 +125,6 @@ en:
search: Contains search: Contains
clientFk: Customer clientFk: Customer
clientName: Customer clientName: Customer
salesPersonFk: Salesperson
attenderFk: Attender attenderFk: Attender
claimResponsibleFk: Responsible claimResponsibleFk: Responsible
claimStateFk: State claimStateFk: State
@ -139,7 +137,6 @@ es:
search: Contiene search: Contiene
clientFk: Cliente clientFk: Cliente
clientName: Cliente clientName: Cliente
salesPersonFk: Comercial
attenderFk: Asistente attenderFk: Asistente
claimResponsibleFk: Responsable claimResponsibleFk: Responsable
claimStateFk: Estado claimStateFk: Estado
@ -148,6 +145,5 @@ es:
itemFk: Artículo itemFk: Artículo
zoneFk: Zona zoneFk: Zona
Client Name: Nombre del cliente Client Name: Nombre del cliente
Salesperson: Comercial
Item: Artículo Item: Artículo
</i18n> </i18n>

View File

@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
import { toDate } from 'filters/index'; import { toDate } from 'filters/index';
import ClaimFilter from './ClaimFilter.vue'; import ClaimFilter from './ClaimFilter.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue'; import VnUserLink from 'src/components/ui/VnUserLink.vue';
import ClaimSummary from './Card/ClaimSummary.vue'; import ClaimSummary from './Card/ClaimSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
@ -48,6 +49,20 @@ const columns = computed(() => [
}, },
columnClass: 'expand', columnClass: 'expand',
}, },
{
align: 'left',
name: 'departmentFk',
label: t('customer.summary.team'),
component: 'select',
attrs: {
url: 'Departments',
},
create: true,
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
},
{ {
align: 'left', align: 'left',
label: t('claim.attendedBy'), label: t('claim.attendedBy'),
@ -152,6 +167,12 @@ const STATE_COLOR = {
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" />
</span> </span>
</template> </template>
<template #column-departmentFk="{ row }">
<span class="link" @click.stop>
{{ row.departmentName || '-' }}
<DepartmentDescriptorProxy :id="row?.departmentFk" />
</span>
</template>
<template #column-attendedBy="{ row }"> <template #column-attendedBy="{ row }">
<span @click.stop> <span @click.stop>
<VnUserLink :name="row.workerName" :worker-id="row.workerFk" /> <VnUserLink :name="row.workerName" :worker-id="row.workerFk" />

View File

@ -8,7 +8,6 @@ import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
import { getDifferences, getUpdatedValues } from 'src/filters'; import { getDifferences, getUpdatedValues } from 'src/filters';
const route = useRoute(); const route = useRoute();
@ -37,7 +36,7 @@ const exprBuilder = (param, value) => {
function onBeforeSave(formData, originalData) { function onBeforeSave(formData, originalData) {
return getUpdatedValues( return getUpdatedValues(
Object.keys(getDifferences(formData, originalData)), Object.keys(getDifferences(formData, originalData)),
formData formData,
); );
} }
</script> </script>
@ -119,16 +118,11 @@ function onBeforeSave(formData, originalData) {
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelectWorker <VnSelect
:label="t('customer.summary.salesPerson')" :label="t('globals.department')"
v-model="data.salesPersonFk" v-model="data.departmentFk"
:params="{ url="Departments"
departmentCodes: ['VT', 'shopping'], :fields="['id', 'name']"
}"
:has-avatar="true"
:rules="validate('client.salesPersonFk')"
:expr-builder="exprBuilder"
emit-value
/> />
<VnSelect <VnSelect
v-model="data.contactChannelFk" v-model="data.contactChannelFk"
@ -160,7 +154,7 @@ function onBeforeSave(formData, originalData) {
<QIcon name="info" class="cursor-pointer"> <QIcon name="info" class="cursor-pointer">
<QTooltip>{{ <QTooltip>{{
t( t(
'In case of a company succession, specify the grantor company' 'In case of a company succession, specify the grantor company',
) )
}}</QTooltip> }}</QTooltip>
</QIcon> </QIcon>

View File

@ -3,14 +3,14 @@ import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters'; import { toCurrency, toDate } from 'src/filters';
import useCardDescription from 'src/composables/useCardDescription'; import useCardDescription from 'src/composables/useCardDescription';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue'; import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
const state = useState(); const state = useState();
@ -84,14 +84,10 @@ const debtWarning = computed(() => {
:value="toCurrency(entity.debt)" :value="toCurrency(entity.debt)"
:info="t('customer.summary.riskInfo')" :info="t('customer.summary.riskInfo')"
/> />
<VnLv :label="t('customer.summary.salesPerson')"> <VnLv :label="t('globals.department')">
<template #value> <template #value>
<VnUserLink <span class="link" v-text="entity.department?.name" />
v-if="entity.salesPersonUser" <DepartmentDescriptorProxy :id="entity.department?.id" />
:name="entity.salesPersonUser.name"
:worker-id="entity.salesPersonFk"
/>
<span v-else>{{ dashIfEmpty(entity.salesPersonUser) }}</span>
</template> </template>
</VnLv> </VnLv>
<VnLv <VnLv

View File

@ -2,7 +2,6 @@
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { toCurrency, toPercentage, toDate, dashOrCurrency } from 'src/filters'; import { toCurrency, toPercentage, toDate, dashOrCurrency } from 'src/filters';
import CardSummary from 'components/ui/CardSummary.vue'; import CardSummary from 'components/ui/CardSummary.vue';
@ -13,6 +12,8 @@ import CustomerSummaryTable from 'src/pages/Customer/components/CustomerSummaryT
import VnTitle from 'src/components/common/VnTitle.vue'; import VnTitle from 'src/components/common/VnTitle.vue';
import VnRow from 'src/components/ui/VnRow.vue'; import VnRow from 'src/components/ui/VnRow.vue';
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue'; import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const grafanaUrl = 'https://grafana.verdnatura.es'; const grafanaUrl = 'https://grafana.verdnatura.es';
@ -106,16 +107,12 @@ const sumRisk = ({ clientRisks }) => {
{{ t('globals.params.email') }} {{ t('globals.params.email') }}
<VnLinkMail email="entity.email"></VnLinkMail> </template <VnLinkMail email="entity.email"></VnLinkMail> </template
></VnLv> ></VnLv>
<VnLv <VnLv :label="t('globals.department')">
:label="t('customer.summary.salesPerson')"
:value="entity?.salesPersonUser?.name"
>
<template #value> <template #value>
<VnUserLink <span class="link" v-text="entity.department?.name" />
:name="entity.salesPersonUser?.name" <DepartmentDescriptorProxy :id="entity?.department?.id" />
:worker-id="entity.salesPersonFk" </template>
/> </template </VnLv>
></VnLv>
<VnLv <VnLv
:label="t('customer.summary.contactChannel')" :label="t('customer.summary.contactChannel')"
:value="entity?.contactChannel?.name" :value="entity?.contactChannel?.name"

View File

@ -1,146 +0,0 @@
<script setup>
import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnLocation from 'src/components/common/VnLocation.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
const { t } = useI18n();
const initialData = reactive({
active: true,
isEqualizated: false,
});
const workersOptions = ref([]);
const businessTypesOptions = ref([]);
function handleLocation(data, location) {
const { town, code, provinceFk, countryFk } = location ?? {};
data.postcode = code;
data.city = town;
data.provinceFk = provinceFk;
data.countryFk = countryFk;
}
</script>
<template>
<FetchData
@on-fetch="(data) => (workersOptions = data)"
auto-load
url="Workers/search?departmentCodes"
/>
<FetchData
@on-fetch="(data) => (businessTypesOptions = data)"
auto-load
url="BusinessTypes"
/>
<QPage>
<VnSubToolbar />
<FormModel
:form-initial-data="initialData"
model="client"
url-create="Clients/createWithUser"
>
<template #form="{ data, validate }">
<VnRow>
<QInput :label="t('Comercial name')" v-model="data.name" />
<VnSelect
:label="t('Salesperson')"
:options="workersOptions"
hide-selected
option-label="name"
option-value="id"
v-model="data.salesPersonFk"
/>
</VnRow>
<VnRow>
<VnSelect
:label="t('Business type')"
:options="businessTypesOptions"
hide-selected
option-label="description"
option-value="code"
v-model="data.businessTypeFk"
/>
<QInput v-model="data.fi" :label="t('Tax number')" />
</VnRow>
<VnRow>
<QInput
:label="t('Business name')"
:rules="validate('client.socialName')"
v-model="data.socialName"
/>
</VnRow>
<VnRow>
<QInput
:label="t('Street')"
:rules="validate('client.street')"
v-model="data.street"
/>
</VnRow>
<VnRow>
<VnLocation
:rules="validate('Worker.postcode')"
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
v-model="data.location"
@update:model-value="(location) => handleLocation(data, location)"
>
</VnLocation>
</VnRow>
<VnRow>
<QInput v-model="data.userName" :label="t('Web user')" />
<QInput
:label="t('Email')"
:rules="validate('client.email')"
clearable
type="email"
v-model="data.email"
>
<template #append>
<QIcon name="info" class="cursor-info">
<QTooltip max-width="400px">{{
t('customer.basicData.youCanSaveMultipleEmails')
}}</QTooltip>
</QIcon>
</template>
</QInput>
</VnRow>
<QCheckbox
:label="t('Is equalizated')"
v-model="initialData.isEqualizated"
/>
</template>
</FormModel>
</QPage>
</template>
<style lang="scss" scoped>
.card {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
grid-gap: 20px;
}
</style>
<i18n>
es:
Comercial name: Nombre comercial
Salesperson: Comercial
Business type: Tipo de negocio
Tax number: NIF / CIF
Business name: Razón social
Street: Dirección fiscal
Postcode: Código postal
City: Población
Province: Provincia
Country: País
Web user: Usuario web
Email: Email
Is equalizated: Recargo de equivalencia
</i18n>

View File

@ -3,7 +3,6 @@ import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n(); const { t } = useI18n();
defineProps({ defineProps({
@ -65,22 +64,15 @@ const exprBuilder = (param, value) => {
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnSelectWorker <VnSelect
:label="t('Salesperson')"
v-model="params.salesPersonFk"
:params="{
departmentCodes: ['VT'],
}"
:expr-builder="exprBuilder"
@update:model-value="searchFn()"
emit-value
map-options
use-input
hide-selected
dense
outlined outlined
dense
rounded rounded
:input-debounce="0" :label="t('globals.params.departmentFk')"
v-model="params.departmentFk"
option-value="id"
option-label="name"
url="Departments"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -164,7 +156,6 @@ en:
params: params:
search: Contains search: Contains
fi: FI fi: FI
salesPersonFk: Salesperson
provinceFk: Province provinceFk: Province
isActive: Is active isActive: Is active
city: City city: City
@ -191,7 +182,6 @@ es:
sageTaxTypeFk: Tipo de impuesto Sage sageTaxTypeFk: Tipo de impuesto Sage
sageTransactionTypeFk: Tipo de impuesto Sage sageTransactionTypeFk: Tipo de impuesto Sage
payMethodFk: Forma de pago payMethodFk: Forma de pago
salesPersonFk: Comercial
provinceFk: Provincia provinceFk: Provincia
city: Ciudad city: Ciudad
phone: Teléfono phone: Teléfono
@ -201,7 +191,6 @@ es:
name: Nombre name: Nombre
postcode: CP postcode: CP
FI: NIF FI: NIF
Salesperson: Comercial
Province: Provincia Province: Provincia
City: Ciudad City: Ciudad
Phone: Teléfono Phone: Teléfono

View File

@ -10,7 +10,6 @@ import CustomerFilter from './CustomerFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import VnLocation from 'src/components/common/VnLocation.vue'; import VnLocation from 'src/components/common/VnLocation.vue';
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue'; import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -73,30 +72,17 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'salesPersonFk', name: 'departmentFk',
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'), label: t('customer.summary.team'),
component: 'select', component: 'select',
attrs: { attrs: {
url: 'Workers/activeWithInheritedRole', url: 'Departments',
fields: ['id', 'name', 'firstName'],
where: { role: 'salesPerson' },
optionFilter: 'firstName',
}, },
columnFilter: { create: true,
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name', 'firstName'],
where: { role: 'salesPerson' },
optionLabel: 'firstName',
optionValue: 'id',
},
},
create: false,
columnField: { columnField: {
component: null, component: null,
}, },
format: (row, dashIfEmpty) => dashIfEmpty(row.salesPerson), format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
{ {
align: 'left', align: 'left',
@ -155,6 +141,9 @@ const columns = computed(() => [
inWhere: true, inWhere: true,
}, },
columnClass: 'expand', columnClass: 'expand',
attrs: {
uppercase: true,
},
}, },
{ {
align: 'left', align: 'left',
@ -446,36 +435,6 @@ function handleLocation(data, location) {
redirect="customer" redirect="customer"
> >
<template #more-create-dialog="{ data }"> <template #more-create-dialog="{ data }">
<VnSelectWorker
:label="t('customer.summary.salesPerson')"
v-model="data.salesPersonFk"
:params="{
departmentCodes: ['VT', 'shopping'],
}"
:has-avatar="true"
: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 <VnLocation
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]" :acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
v-model="data.location" v-model="data.location"

View File

@ -32,28 +32,6 @@ const columns = computed(() => [
}, },
}, },
}, },
{
align: 'left',
name: 'isWorker',
label: t('Is worker'),
},
{
align: 'left',
name: 'salesPersonFk',
label: t('Salesperson'),
columnFilter: {
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
where: { role: 'salesPerson' },
useLike: false,
optionValue: 'id',
optionLabel: 'name',
optionFilter: 'firstName',
},
},
},
{ {
align: 'left', align: 'left',
name: 'departmentFk', name: 'departmentFk',
@ -153,6 +131,11 @@ const columns = computed(() => [
label: t('Has recovery'), label: t('Has recovery'),
name: 'hasRecovery', name: 'hasRecovery',
}, },
{
align: 'left',
name: 'isWorker',
label: t('customer.params.isWorker'),
},
]); ]);
const viewAddObservation = (rowsSelected) => { const viewAddObservation = (rowsSelected) => {
@ -167,7 +150,6 @@ const viewAddObservation = (rowsSelected) => {
function exprBuilder(param, value) { function exprBuilder(param, value) {
switch (param) { switch (param) {
case 'salesPersonFk':
case 'creditInsurance': case 'creditInsurance':
case 'countryFk': case 'countryFk':
return { [`c.${param}`]: value }; return { [`c.${param}`]: value };
@ -176,7 +158,7 @@ function exprBuilder(param, value) {
case 'workerFk': case 'workerFk':
return { [`co.${param}`]: value }; return { [`co.${param}`]: value };
case 'departmentFk': case 'departmentFk':
return { [`wd.${param}`]: value }; return { [`c.${param}`]: value };
case 'amount': case 'amount':
case 'clientFk': case 'clientFk':
return { [`d.${param}`]: value }; return { [`d.${param}`]: value };
@ -241,12 +223,6 @@ function exprBuilder(param, value) {
<template #column-observation="{ row }"> <template #column-observation="{ row }">
<VnInput type="textarea" v-model="row.observation" readonly dense rows="2" /> <VnInput type="textarea" v-model="row.observation" readonly dense rows="2" />
</template> </template>
<template #column-salesPersonFk="{ row }">
<span class="link" @click.stop>
{{ row.salesPersonName }}
<WorkerDescriptorProxy :id="row.salesPersonFk" />
</span>
</template>
<template #column-departmentFk="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.departmentName }} {{ row.departmentName }}
@ -265,8 +241,6 @@ function exprBuilder(param, value) {
es: es:
Add observation: Añadir observación Add observation: Añadir observación
Client: Cliente Client: Cliente
Is worker: Es trabajador
Salesperson: Comercial
Department: Departamento Department: Departamento
Country: País Country: País
P. Method: F. Pago P. Method: F. Pago
@ -281,5 +255,5 @@ es:
Credit I.: Crédito A. Credit I.: Crédito A.
Credit insurance: Crédito asegurado Credit insurance: Crédito asegurado
From: Desde From: Desde
Has recovery: Tiene recobro Has recovery: Recobro
</i18n> </i18n>

View File

@ -15,19 +15,12 @@ const props = defineProps({
}, },
}); });
const salespersons = ref();
const countries = ref(); const countries = ref();
const authors = ref(); const authors = ref();
const departments = ref(); const departments = ref();
</script> </script>
<template> <template>
<FetchData
:filter="{ where: { role: 'salesPerson' } }"
@on-fetch="(data) => (salespersons = data)"
auto-load
url="Workers/activeWithInheritedRole"
/>
<FetchData @on-fetch="(data) => (countries = data)" auto-load url="Countries" /> <FetchData @on-fetch="(data) => (countries = data)" auto-load url="Countries" />
<FetchData <FetchData
@on-fetch="(data) => (authors = data)" @on-fetch="(data) => (authors = data)"
@ -62,29 +55,6 @@ const departments = ref();
@update:model-value="searchFn()" @update:model-value="searchFn()"
/> />
</QItem> </QItem>
<QItem class="q-mb-sm">
<QItemSection v-if="salespersons">
<VnSelect
:input-debounce="0"
:label="t('Salesperson')"
:options="salespersons"
dense
emit-value
hide-selected
map-options
option-label="name"
option-value="id"
outlined
rounded
use-input
v-model="params.salesPersonFk"
@update:model-value="searchFn()"
/>
</QItemSection>
<QItemSection v-else>
<QSkeleton class="full-width" type="QInput" />
</QItemSection>
</QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection v-if="departments"> <QItemSection v-if="departments">
<VnSelect <VnSelect
@ -219,7 +189,6 @@ const departments = ref();
en: en:
params: params:
clientFk: Client clientFk: Client
salesPersonFk: Salesperson
countryFk: Country countryFk: Country
paymentMethod: P. Method paymentMethod: P. Method
balance: Balance D. balance: Balance D.
@ -230,7 +199,6 @@ en:
es: es:
params: params:
clientFk: Cliente clientFk: Cliente
salesPersonFk: Comercial
countryFk: País countryFk: País
paymentMethod: F. Pago paymentMethod: F. Pago
balance: Saldo V. balance: Saldo V.
@ -239,7 +207,6 @@ es:
credit: Crédito A. credit: Crédito A.
defaulterSinced: Desde defaulterSinced: Desde
Client: Cliente Client: Cliente
Salesperson: Comercial
Departments: Departamentos Departments: Departamentos
Country: País Country: País
P. Method: F. Pago P. Method: F. Pago

View File

@ -69,17 +69,16 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'), name: 'departmentFk',
name: 'salesPersonFk', label: t('customer.summary.team'),
component: 'select', component: 'select',
attrs: { attrs: {
url: 'Workers/activeWithInheritedRole', url: 'Departments',
fields: ['id', 'name'],
where: { role: 'salesPerson' },
optionFilter: 'firstName',
useLike: false,
}, },
visible: false, columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
]); ]);
</script> </script>
@ -96,7 +95,7 @@ const columns = computed(() => [
</VnSubToolbar> </VnSubToolbar>
<VnTable <VnTable
:data-key="dataKey" :data-key="dataKey"
url="Clients" url="Clients/filter"
:table="{ :table="{
'row-key': 'id', 'row-key': 'id',
selection: 'multiple', selection: 'multiple',
@ -127,7 +126,6 @@ const columns = computed(() => [
es: es:
Identifier: Identificador Identifier: Identificador
Social name: Razón social Social name: Razón social
Salesperson: Comercial
Phone: Teléfono Phone: Teléfono
City: Población City: Población
Email: Email Email: Email

View File

@ -20,7 +20,7 @@ customer:
name: Name name: Name
contact: Contact contact: Contact
mobile: Mobile mobile: Mobile
salesPerson: Sales person team: Team
contactChannel: Contact channel contactChannel: Contact channel
socialName: Social name socialName: Social name
fiscalId: Fiscal ID fiscalId: Fiscal ID
@ -78,7 +78,6 @@ customer:
id: Identifier id: Identifier
socialName: Social name socialName: Social name
fi: Tax number fi: Tax number
salesPersonFk: Salesperson
creditInsurance: Credit insurance creditInsurance: Credit insurance
phone: Phone phone: Phone
street: Street street: Street

View File

@ -20,7 +20,7 @@ customer:
name: Nombre name: Nombre
contact: Contacto contact: Contacto
mobile: Móvil mobile: Móvil
salesPerson: Comercial team: Equipo
contactChannel: Canal de contacto contactChannel: Canal de contacto
socialName: Razón social socialName: Razón social
fiscalId: NIF/CIF fiscalId: NIF/CIF
@ -78,7 +78,6 @@ customer:
id: Identificador id: Identificador
socialName: Razón social socialName: Razón social
fi: NIF / CIF fi: NIF / CIF
salesPersonFk: Comercial
creditInsurance: Crédito asegurado creditInsurance: Crédito asegurado
phone: Teléfono phone: Teléfono
street: Dirección fiscal street: Dirección fiscal

View File

@ -13,6 +13,7 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue'; import VnSelectTravelExtended from 'src/components/common/VnSelectTravelExtended.vue';
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue'; import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
const route = useRoute(); const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
@ -53,7 +54,7 @@ onMounted(() => {
:clear-store-on-unmount="false" :clear-store-on-unmount="false"
> >
<template #form="{ data }"> <template #form="{ data }">
<VnRow> <VnRow class="q-py-sm">
<VnSelectTravelExtended <VnSelectTravelExtended
:data="data" :data="data"
v-model="data.travelFk" v-model="data.travelFk"
@ -65,7 +66,7 @@ onMounted(() => {
:required="true" :required="true"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<VnInput v-model="data.reference" :label="t('globals.reference')" /> <VnInput v-model="data.reference" :label="t('globals.reference')" />
<VnInputNumber <VnInputNumber
v-model="data.invoiceAmount" v-model="data.invoiceAmount"
@ -73,7 +74,7 @@ onMounted(() => {
:positive="false" :positive="false"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<VnInput <VnInput
v-model="data.invoiceNumber" v-model="data.invoiceNumber"
:label="t('entry.summary.invoiceNumber')" :label="t('entry.summary.invoiceNumber')"
@ -84,12 +85,13 @@ onMounted(() => {
:options="companiesOptions" :options="companiesOptions"
option-value="id" option-value="id"
option-label="code" option-label="code"
sort-by="code"
map-options map-options
hide-selected hide-selected
:required="true" :required="true"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<VnInputNumber <VnInputNumber
:label="t('entry.summary.commission')" :label="t('entry.summary.commission')"
v-model="data.commission" v-model="data.commission"
@ -102,9 +104,10 @@ onMounted(() => {
:options="currenciesOptions" :options="currenciesOptions"
option-value="id" option-value="id"
option-label="code" option-label="code"
sort-by="code"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<VnInputNumber <VnInputNumber
v-model="data.initialTemperature" v-model="data.initialTemperature"
name="initialTemperature" name="initialTemperature"
@ -121,8 +124,16 @@ onMounted(() => {
:decimal-places="2" :decimal-places="2"
:positive="false" :positive="false"
/> />
<VnSelect
v-model="data.typeFk"
url="entryTypes"
:fields="['code', 'description']"
option-value="code"
optionLabel="description"
sortBy="description"
/>
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<QInput <QInput
:label="t('entry.basicData.observation')" :label="t('entry.basicData.observation')"
type="textarea" type="textarea"
@ -132,14 +143,20 @@ onMounted(() => {
fill-input fill-input
/> />
</VnRow> </VnRow>
<VnRow> <VnRow class="q-py-sm">
<QCheckbox v-model="data.isOrdered" :label="t('entry.summary.ordered')" /> <VnCheckbox
<QCheckbox v-model="data.isConfirmed" :label="t('globals.confirmed')" /> v-model="data.isOrdered"
<QCheckbox :label="t('entry.list.tableVisibleColumns.isOrdered')"
v-model="data.isExcludedFromAvailable"
:label="t('entry.summary.excludedFromAvailable')"
/> />
<QCheckbox <VnCheckbox
v-model="data.isConfirmed"
:label="t('entry.list.tableVisibleColumns.isConfirmed')"
/>
<VnCheckbox
v-model="data.isExcludedFromAvailable"
:label="t('entry.list.tableVisibleColumns.isExcludedFromAvailable')"
/>
<VnCheckbox
:disable="!isAdministrative()" :disable="!isAdministrative()"
v-model="data.isBooked" v-model="data.isBooked"
:label="t('entry.basicData.booked')" :label="t('entry.basicData.booked')"

View File

@ -2,7 +2,7 @@
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { onMounted, ref } from 'vue'; import { onMounted, ref, computed } from 'vue';
import { useState } from 'src/composables/useState'; import { useState } from 'src/composables/useState';
@ -16,6 +16,8 @@ import ItemDescriptor from 'src/pages/Item/Card/ItemDescriptor.vue';
import axios from 'axios'; import axios from 'axios';
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue'; import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
import { checkEntryLock } from 'src/composables/checkEntryLock'; import { checkEntryLock } from 'src/composables/checkEntryLock';
import VnRow from 'src/components/ui/VnRow.vue';
import VnInput from 'src/components/common/VnInput.vue';
const $props = defineProps({ const $props = defineProps({
id: { id: {
@ -57,31 +59,6 @@ const columns = [
createOrder: 12, createOrder: 12,
width: '25px', width: '25px',
}, },
{
label: t('Buyer'),
name: 'workerFk',
component: 'select',
attrs: {
url: 'TicketRequests/getItemTypeWorker',
fields: ['id', 'nickname'],
optionLabel: 'nickname',
sortBy: 'nickname ASC',
optionValue: 'id',
},
visible: false,
},
{
label: t('Family'),
name: 'itemTypeFk',
component: 'select',
attrs: {
url: 'itemTypes',
fields: ['id', 'name'],
optionLabel: 'name',
optionValue: 'id',
},
visible: false,
},
{ {
name: 'id', name: 'id',
isId: true, isId: true,
@ -111,16 +88,10 @@ const columns = [
}, },
}, },
{ {
align: 'center', align: 'left',
label: t('Article'), label: t('Article'),
component: 'input',
name: 'name', name: 'name',
component: 'select',
attrs: {
url: 'Items',
fields: ['id', 'name'],
optionLabel: 'name',
optionValue: 'id',
},
width: '85px', width: '85px',
isEditable: false, isEditable: false,
}, },
@ -212,7 +183,6 @@ const columns = [
}, },
}, },
{ {
align: 'center',
labelAbbreviation: 'GM', labelAbbreviation: 'GM',
label: t('Grouping selector'), label: t('Grouping selector'),
toolTip: t('Grouping selector'), toolTip: t('Grouping selector'),
@ -240,7 +210,6 @@ const columns = [
}, },
}, },
{ {
align: 'center',
labelAbbreviation: 'G', labelAbbreviation: 'G',
label: 'Grouping', label: 'Grouping',
toolTip: 'Grouping', toolTip: 'Grouping',
@ -294,7 +263,7 @@ const columns = [
align: 'center', align: 'center',
label: t('Amount'), label: t('Amount'),
name: 'amount', name: 'amount',
width: '45px', width: '75px',
component: 'number', component: 'number',
attrs: { attrs: {
positive: false, positive: false,
@ -310,7 +279,9 @@ const columns = [
toolTip: t('Package'), toolTip: t('Package'),
name: 'price2', name: 'price2',
component: 'number', component: 'number',
createDisable: true, createAttrs: {
disable: true,
},
width: '35px', width: '35px',
create: true, create: true,
format: (row) => parseFloat(row['price2']).toFixed(2), format: (row) => parseFloat(row['price2']).toFixed(2),
@ -320,7 +291,9 @@ const columns = [
label: t('Box'), label: t('Box'),
name: 'price3', name: 'price3',
component: 'number', component: 'number',
createDisable: true, createAttrs: {
disable: true,
},
cellEvent: { cellEvent: {
'update:modelValue': async (value, oldValue, row) => { 'update:modelValue': async (value, oldValue, row) => {
row['price2'] = row['price2'] * (value / oldValue); row['price2'] = row['price2'] * (value / oldValue);
@ -340,13 +313,6 @@ const columns = [
toggleIndeterminate: false, toggleIndeterminate: false,
}, },
component: 'checkbox', component: 'checkbox',
cellEvent: {
'update:modelValue': async (value, oldValue, row) => {
await axios.patch(`Items/${row['itemFk']}`, {
hasMinPrice: value,
});
},
},
width: '25px', width: '25px',
}, },
{ {
@ -356,13 +322,6 @@ const columns = [
toolTip: t('Minimum price'), toolTip: t('Minimum price'),
name: 'minPrice', name: 'minPrice',
component: 'number', component: 'number',
cellEvent: {
'update:modelValue': async (value, oldValue, row) => {
await axios.patch(`Items/${row['itemFk']}`, {
minPrice: value,
});
},
},
width: '35px', width: '35px',
style: (row) => { style: (row) => {
if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' }; if (!row?.hasMinPrice) return { color: 'var(--vn-label-color)' };
@ -425,6 +384,23 @@ const columns = [
}, },
}, },
]; ];
const buyerFk = ref(null);
const itemTypeFk = ref(null);
const inkFk = ref(null);
const tag1 = ref(null);
const tag2 = ref(null);
const tag1Filter = ref(null);
const tag2Filter = ref(null);
const filter = computed(() => {
const where = {};
where.workerFk = buyerFk.value;
where.itemTypeFk = itemTypeFk.value;
where.inkFk = inkFk.value;
where.tag1 = tag1.value;
where.tag2 = tag2.value;
return { where };
});
function getQuantityStyle(row) { function getQuantityStyle(row) {
if (row?.quantity !== row?.stickers * row?.packing) if (row?.quantity !== row?.stickers * row?.packing)
@ -610,6 +586,7 @@ onMounted(() => {
:url="`Entries/${entityId}/getBuyList`" :url="`Entries/${entityId}/getBuyList`"
search-url="EntryBuys" search-url="EntryBuys"
save-url="Buys/crud" save-url="Buys/crud"
:filter="filter"
:disable-option="{ card: true }" :disable-option="{ card: true }"
v-model:selected="selectedRows" v-model:selected="selectedRows"
@on-fetch="() => footerFetchDataRef.fetch()" @on-fetch="() => footerFetchDataRef.fetch()"
@ -655,7 +632,7 @@ onMounted(() => {
:is-editable="editableMode" :is-editable="editableMode"
:without-header="!editableMode" :without-header="!editableMode"
:with-filters="editableMode" :with-filters="editableMode"
:right-search="editableMode" :right-search="false"
:row-click="false" :row-click="false"
:columns="columns" :columns="columns"
:beforeSaveFn="beforeSave" :beforeSaveFn="beforeSave"
@ -666,6 +643,46 @@ onMounted(() => {
data-cy="entry-buys" data-cy="entry-buys"
overlay overlay
> >
<template #top-left>
<VnRow>
<VnSelect
:label="t('Buyer')"
v-model="buyerFk"
url="TicketRequests/getItemTypeWorker"
:fields="['id', 'nickname']"
option-label="nickname"
sort-by="nickname ASC"
/>
<VnSelect
:label="t('Family')"
v-model="itemTypeFk"
url="ItemTypes"
:fields="['id', 'name']"
option-label="name"
sort-by="name ASC"
/>
<VnSelect
:label="t('Color')"
v-model="inkFk"
url="Inks"
:fields="['id', 'name']"
option-label="name"
sort-by="name ASC"
/>
<VnInput
v-model="tag1Filter"
:label="t('Tag')"
@keyup.enter="tag1 = tag1Filter"
@remove="tag1 = null"
/>
<VnInput
v-model="tag2Filter"
:label="t('Tag')"
@keyup.enter="tag2 = tag2Filter"
@remove="tag2 = null"
/>
</VnRow>
</template>
<template #column-hex="{ row }"> <template #column-hex="{ row }">
<VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" /> <VnColor :colors="row?.hexJson" style="height: 100%; min-width: 2000px" />
</template> </template>
@ -696,7 +713,7 @@ onMounted(() => {
</div> </div>
</template> </template>
<template #column-footer-weight> <template #column-footer-weight>
{{ footer?.weight }} <span class="q-pr-xs">{{ footer?.weight }}</span>
</template> </template>
<template #column-footer-quantity> <template #column-footer-quantity>
<span :style="getQuantityStyle(footer)" data-cy="footer-quantity"> <span :style="getQuantityStyle(footer)" data-cy="footer-quantity">
@ -704,9 +721,8 @@ onMounted(() => {
</span> </span>
</template> </template>
<template #column-footer-amount> <template #column-footer-amount>
<span :style="getAmountStyle(footer)" data-cy="footer-amount"> <span data-cy="footer-amount">{{ footer?.amount }} / </span>
{{ footer?.amount }} <span style="color: var(--q-positive)">{{ footer?.checkedAmount }}</span>
</span>
</template> </template>
<template #column-create-itemFk="{ data, validations }"> <template #column-create-itemFk="{ data, validations }">
<VnSelect <VnSelect
@ -768,6 +784,8 @@ onMounted(() => {
</template> </template>
<i18n> <i18n>
es: es:
Buyer: Comprador
Family: Familia
Article: Artículo Article: Artículo
Siz.: Med. Siz.: Med.
Size: Medida Size: Medida

View File

@ -2,153 +2,82 @@
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnTable from 'src/components/VnTable/VnTable.vue';
import FetchData from 'components/FetchData.vue';
import CrudModel from 'components/CrudModel.vue';
import VnInput from 'src/components/common/VnInput.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
const { params } = useRoute(); const { params } = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const selectedRows = ref([]);
const entryObservationsRef = ref(null); const entryObservationsRef = ref(null);
const entryObservationsOptions = ref([]); const entityId = ref(params.id);
const selected = ref([]);
const sortEntryObservationOptions = (data) => {
entryObservationsOptions.value = [...data].sort((a, b) =>
a.description.localeCompare(b.description),
);
};
const columns = computed(() => [ const columns = computed(() => [
{ {
name: 'observationType', name: 'id',
label: t('entry.notes.observationType'), isId: true,
field: (row) => row.observationTypeFk, visible: false,
sortable: true, isEditable: false,
options: entryObservationsOptions.value, columnFilter: false,
required: true,
model: 'observationTypeFk',
optionValue: 'id',
optionLabel: 'description',
tabIndex: 1,
align: 'left',
}, },
{ {
name: 'observationTypeFk',
label: t('entry.notes.observationType'),
component: 'select',
columnFilter: { inWhere: true },
attrs: {
inWhere: true,
url: 'ObservationTypes',
fields: ['id', 'description'],
optionValue: 'id',
optionLabel: 'description',
sortBy: 'description',
},
width: '30px',
create: true,
},
{
align: 'left',
name: 'description', name: 'description',
label: t('globals.description'), label: t('globals.description'),
field: (row) => row.description, component: 'input',
tabIndex: 2, columnFilter: false,
align: 'left', attrs: { autogrow: true },
create: true,
}, },
]); ]);
const filter = computed(() => ({
fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
include: ['observationType'],
where: { entryFk: entityId },
}));
</script> </script>
<template> <template>
<FetchData <VnTable
url="ObservationTypes" ref="entryObservationsRef"
@on-fetch="(data) => sortEntryObservationOptions(data)" data-key="EntryObservations"
:columns="columns"
url="EntryObservations"
:user-filter="filter"
order="id ASC"
:disable-option="{ card: true }"
:is-editable="true"
:right-search="true"
v-model:selected="selectedRows"
:create="{
urlCreate: 'EntryObservations',
title: t('Create note'),
onDataSaved: () => {
entryObservationsRef.reload();
},
formInitialData: { entryFk: entityId },
}"
:table="{
'row-key': 'id',
selection: 'multiple',
}"
auto-load auto-load
/> />
<CrudModel
data-key="EntryAccount"
url="EntryObservations"
model="EntryAccount"
:filter="{
fields: ['id', 'entryFk', 'observationTypeFk', 'description'],
where: { entryFk: params.id },
}"
ref="entryObservationsRef"
:data-required="{ entryFk: params.id }"
v-model:selected="selected"
auto-load
>
<template #body="{ rows, validate }">
<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>
<VnSelect
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>
<VnSelect
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>
</template>
</QTable>
</template>
</CrudModel>
<QPageSticky position="bottom-right" :offset="[25, 25]">
<QBtn
fab
color="primary"
icon="add"
v-shortcut="'+'"
@click="entryObservationsRef.insert()"
/>
</QPageSticky>
</template> </template>
<i18n> <i18n>
es: es:
Add note: Añadir nota Create note: Crear nota
Remove note: Quitar nota
</i18n> </i18n>

View File

@ -92,13 +92,13 @@ onMounted(async () => {
</div> </div>
<div class="card-content"> <div class="card-content">
<VnCheckbox <VnCheckbox
:label="t('entry.summary.ordered')" :label="t('entry.list.tableVisibleColumns.isOrdered')"
v-model="entry.isOrdered" v-model="entry.isOrdered"
:disable="true" :disable="true"
size="xs" size="xs"
/> />
<VnCheckbox <VnCheckbox
:label="t('globals.confirmed')" :label="t('entry.list.tableVisibleColumns.isConfirmed')"
v-model="entry.isConfirmed" v-model="entry.isConfirmed"
:disable="true" :disable="true"
size="xs" size="xs"
@ -110,7 +110,11 @@ onMounted(async () => {
size="xs" size="xs"
/> />
<VnCheckbox <VnCheckbox
:label="t('entry.summary.excludedFromAvailable')" :label="
t(
'entry.list.tableVisibleColumns.isExcludedFromAvailable',
)
"
v-model="entry.isExcludedFromAvailable" v-model="entry.isExcludedFromAvailable"
:disable="true" :disable="true"
size="xs" size="xs"

View File

@ -85,7 +85,7 @@ const entryFilterPanel = ref();
</QItemSection> </QItemSection>
<QItemSection> <QItemSection>
<QCheckbox <QCheckbox
:label="t('entry.list.tableVisibleColumns.isConfirmed')" label="LE"
v-model="params.isConfirmed" v-model="params.isConfirmed"
toggle-indeterminate toggle-indeterminate
> >
@ -102,6 +102,7 @@ const entryFilterPanel = ref();
v-model="params.landed" v-model="params.landed"
@update:model-value="searchFn()" @update:model-value="searchFn()"
is-outlined is-outlined
data-cy="landed"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
@ -121,13 +122,6 @@ const entryFilterPanel = ref();
rounded rounded
/> />
</QItemSection> </QItemSection>
<QItemSection>
<VnInput
v-model="params.invoiceNumber"
:label="t('params.invoiceNumber')"
is-outlined
/>
</QItemSection>
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
@ -171,6 +165,7 @@ const entryFilterPanel = ref();
@update:model-value="searchFn()" @update:model-value="searchFn()"
url="Warehouses" url="Warehouses"
:fields="['id', 'name']" :fields="['id', 'name']"
sort-by="name ASC"
hide-selected hide-selected
dense dense
outlined outlined
@ -186,6 +181,7 @@ const entryFilterPanel = ref();
@update:model-value="searchFn()" @update:model-value="searchFn()"
url="Warehouses" url="Warehouses"
:fields="['id', 'name']" :fields="['id', 'name']"
sort-by="name ASC"
hide-selected hide-selected
dense dense
outlined outlined
@ -233,15 +229,6 @@ const entryFilterPanel = ref();
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnInput
v-model="params.evaNotes"
:label="t('params.evaNotes')"
is-outlined
/>
</QItemSection>
</QItem>
</template> </template>
</VnFilterPanel> </VnFilterPanel>
</template> </template>
@ -267,7 +254,7 @@ en:
hasToShowDeletedEntries: Show deleted entries hasToShowDeletedEntries: Show deleted entries
es: es:
params: params:
isExcludedFromAvailable: Inventario isExcludedFromAvailable: Excluida
isOrdered: Pedida isOrdered: Pedida
isConfirmed: Confirmado isConfirmed: Confirmado
isReceived: Recibida isReceived: Recibida

View File

@ -1,264 +0,0 @@
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useStateStore } from 'stores/useStateStore';
import { toDate } from 'src/filters';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import EntryLatestBuysFilter from './EntryLatestBuysFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue';
import VnImg from 'src/components/ui/VnImg.vue';
const stateStore = useStateStore();
const { t } = useI18n();
const tableRef = ref();
const columns = [
{
align: 'center',
label: t('entry.latestBuys.tableVisibleColumns.image'),
name: 'itemFk',
columnField: {
component: VnImg,
attrs: ({ row }) => {
return {
id: row.id,
size: '50x50',
};
},
},
columnFilter: false,
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.itemFk'),
name: 'itemFk',
isTitle: true,
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.summary.packing'),
name: 'packing',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.summary.grouping'),
name: 'grouping',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('globals.quantity'),
name: 'quantity',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('globals.description'),
name: 'description',
},
{
align: 'left',
label: t('globals.size'),
name: 'size',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('globals.tags'),
name: 'tags',
},
{
align: 'left',
label: t('globals.type'),
name: 'type',
},
{
align: 'left',
label: t('globals.intrastat'),
name: 'intrastat',
},
{
align: 'left',
label: t('globals.origin'),
name: 'origin',
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.weightByPiece'),
name: 'weightByPiece',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.isActive'),
name: 'isActive',
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.family'),
name: 'family',
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.entryFk'),
name: 'entryFk',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.summary.buyingValue'),
name: 'buyingValue',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.freightValue'),
name: 'freightValue',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.comissionValue'),
name: 'comissionValue',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.packageValue'),
name: 'packageValue',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.isIgnored'),
name: 'isIgnored',
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.price2'),
name: 'price2',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.price3'),
name: 'price3',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.minPrice'),
name: 'minPrice',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.ektFk'),
name: 'ektFk',
},
{
align: 'left',
label: t('globals.weight'),
name: 'weight',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.buys.packagingFk'),
name: 'packagingFk',
columnFilter: {
component: 'number',
inWhere: true,
},
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.packingOut'),
name: 'packingOut',
},
{
align: 'left',
label: t('entry.latestBuys.tableVisibleColumns.landing'),
name: 'landing',
component: 'date',
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landing)),
},
];
onMounted(async () => {
stateStore.rightDrawer = true;
});
onUnmounted(() => (stateStore.rightDrawer = false));
</script>
<template>
<RightMenu>
<template #right-panel>
<EntryLatestBuysFilter data-key="LatestBuys" />
</template>
</RightMenu>
<VnSubToolbar />
<VnTable
ref="tableRef"
data-key="LatestBuys"
url="Buys/latestBuysFilter"
order="id DESC"
:columns="columns"
redirect="entry"
:row-click="({ entryFk }) => tableRef.redirect(entryFk)"
auto-load
:right-search="false"
/>
</template>

View File

@ -1,161 +0,0 @@
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue';
import VnSelect from 'components/common/VnSelect.vue';
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
const { t } = useI18n();
defineProps({
dataKey: {
type: String,
required: true,
},
});
const tagValues = ref([]);
</script>
<template>
<ItemsFilterPanel :data-key="dataKey" :custom-tags="['tags']">
<template #body="{ params, searchFn }">
<QItem class="q-my-md">
<QItemSection>
<VnSelect
:label="t('components.itemsFilterPanel.salesPersonFk')"
v-model="params.salesPersonFk"
url="TicketRequests/getItemTypeWorker"
option-label="nickname"
:fields="['id', 'nickname']"
sort-by="nickname ASC"
dense
outlined
rounded
use-input
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
<QItem class="q-my-md">
<QItemSection>
<VnSelectSupplier
v-model="params.supplierFk"
url="Suppliers"
:fields="['id', 'name', 'nickname']"
sort-by="name ASC"
dense
outlined
rounded
/>
</QItemSection>
</QItem>
<QItem class="q-my-md">
<QItemSection>
<VnInputDate
:label="t('components.itemsFilterPanel.started')"
v-model="params.from"
is-outlined
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
<QItem class="q-my-md">
<QItemSection>
<VnInputDate
:label="t('components.itemsFilterPanel.ended')"
v-model="params.to"
is-outlined
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<QCheckbox
:label="t('components.itemsFilterPanel.active')"
v-model="params.active"
toggle-indeterminate
@update:model-value="searchFn()"
/>
</QItemSection>
<QItemSection>
<QCheckbox
:label="t('globals.visible')"
v-model="params.visible"
toggle-indeterminate
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
<QItem>
<QItemSection>
<QCheckbox
:label="t('components.itemsFilterPanel.floramondo')"
v-model="params.floramondo"
toggle-indeterminate
@update:model-value="searchFn()"
/>
</QItemSection>
</QItem>
<QItem
v-for="(value, index) in tagValues"
:key="value"
class="q-mt-md filter-value"
>
<QItemSection class="col">
<VnSelect
:label="t('params.tag')"
v-model="value.selectedTag"
:options="tagOptions"
option-label="name"
dense
outlined
rounded
:emit-value="false"
use-input
:is-clearable="false"
@update:model-value="getSelectedTagValues(value)"
/>
</QItemSection>
<QItemSection class="col">
<VnSelect
v-if="!value?.selectedTag?.isFree && value.valueOptions"
:label="t('params.value')"
v-model="value.value"
:options="value.valueOptions || []"
option-value="value"
option-label="value"
dense
outlined
rounded
emit-value
use-input
:disable="!value"
:is-clearable="false"
class="filter-input"
@update:model-value="applyTags(params, searchFn)"
/>
<VnInput
v-else
v-model="value.value"
:label="t('params.value')"
:disable="!value"
is-outlined
class="filter-input"
:is-clearable="false"
@keyup.enter="applyTags(params, searchFn)"
/>
</QItemSection>
<QIcon
name="delete"
class="filter-icon"
@click="removeTag(index, params, searchFn)"
/>
</QItem>
</template>
</ItemsFilterPanel>
</template>

View File

@ -107,9 +107,8 @@ const columns = computed(() => [
attrs: { attrs: {
url: 'suppliers', url: 'suppliers',
fields: ['id', 'name'], fields: ['id', 'name'],
where: { order: 'name DESC' }, sortBy: 'name ASC',
}, },
format: (row, dashIfEmpty) => dashIfEmpty(row.supplierName),
width: '110px', width: '110px',
}, },
{ {
@ -145,6 +144,7 @@ const columns = computed(() => [
attrs: { attrs: {
url: 'agencyModes', url: 'agencyModes',
fields: ['id', 'name'], fields: ['id', 'name'],
sortBy: 'name ASC',
}, },
columnField: { columnField: {
component: null, component: null,
@ -158,7 +158,6 @@ const columns = computed(() => [
component: 'input', component: 'input',
}, },
{ {
align: 'left',
label: t('entry.list.tableVisibleColumns.warehouseOutFk'), label: t('entry.list.tableVisibleColumns.warehouseOutFk'),
name: 'warehouseOutFk', name: 'warehouseOutFk',
cardVisible: true, cardVisible: true,
@ -166,6 +165,7 @@ const columns = computed(() => [
attrs: { attrs: {
url: 'warehouses', url: 'warehouses',
fields: ['id', 'name'], fields: ['id', 'name'],
sortBy: 'name ASC',
}, },
columnField: { columnField: {
component: null, component: null,
@ -174,7 +174,6 @@ const columns = computed(() => [
width: '65px', width: '65px',
}, },
{ {
align: 'left',
label: t('entry.list.tableVisibleColumns.warehouseInFk'), label: t('entry.list.tableVisibleColumns.warehouseInFk'),
name: 'warehouseInFk', name: 'warehouseInFk',
cardVisible: true, cardVisible: true,
@ -182,6 +181,7 @@ const columns = computed(() => [
attrs: { attrs: {
url: 'warehouses', url: 'warehouses',
fields: ['id', 'name'], fields: ['id', 'name'],
sortBy: 'name ASC',
}, },
columnField: { columnField: {
component: null, component: null,
@ -190,7 +190,6 @@ const columns = computed(() => [
width: '65px', width: '65px',
}, },
{ {
align: 'left',
labelAbbreviation: t('Type'), labelAbbreviation: t('Type'),
label: t('entry.list.tableVisibleColumns.entryTypeDescription'), label: t('entry.list.tableVisibleColumns.entryTypeDescription'),
toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'), toolTip: t('entry.list.tableVisibleColumns.entryTypeDescription'),
@ -201,6 +200,7 @@ const columns = computed(() => [
fields: ['code', 'description'], fields: ['code', 'description'],
optionValue: 'code', optionValue: 'code',
optionLabel: 'description', optionLabel: 'description',
sortBy: 'description',
}, },
width: '65px', width: '65px',
format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription), format: (row, dashIfEmpty) => dashIfEmpty(row.entryTypeDescription),

View File

@ -1,24 +1,23 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useState } from 'src/composables/useState'; import { useQuasar, date } from 'quasar';
import { useQuasar } from 'quasar';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue'; import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import FormModelPopup from 'components/FormModelPopup.vue'; import FormModelPopup from 'components/FormModelPopup.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import VnRow from 'components/ui/VnRow.vue'; import VnRow from 'components/ui/VnRow.vue';
import RightMenu from 'src/components/common/RightMenu.vue';
import EntryStockBoughtFilter from './EntryStockBoughtFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue'; import EntryStockBoughtDetail from 'src/pages/Entry/EntryStockBoughtDetail.vue';
import TravelDescriptorProxy from '../Travel/Card/TravelDescriptorProxy.vue';
import { useFilterParams } from 'src/composables/useFilterParams';
import axios from 'axios';
const { t } = useI18n(); const { t } = useI18n();
const quasar = useQuasar(); const quasar = useQuasar();
const state = useState(); const filterDate = ref(useFilterParams('StockBoughts').params);
const user = state.getUser();
const footer = ref({ bought: 0, reserve: 0 }); const footer = ref({ bought: 0, reserve: 0 });
const columns = computed(() => [ const columns = computed(() => [
{ {
@ -46,7 +45,7 @@ const columns = computed(() => [
optionValue: 'id', optionValue: 'id',
}, },
columnFilter: false, columnFilter: false,
width: '50px', width: '60%',
}, },
{ {
align: 'center', align: 'center',
@ -56,20 +55,20 @@ const columns = computed(() => [
create: true, create: true,
component: 'number', component: 'number',
summation: true, summation: true,
width: '50px',
format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)), format: ({ reserve }, dashIfEmpty) => dashIfEmpty(round(reserve)),
width: '20%',
}, },
{ {
align: 'center', align: 'right',
label: t('entryStockBought.bought'), label: t('entryStockBought.bought'),
name: 'bought', name: 'bought',
summation: true, summation: true,
cardVisible: true, cardVisible: true,
style: ({ reserve, bought }) => boughtStyle(bought, reserve), style: ({ reserve, bought }) => boughtStyle(bought, reserve),
columnFilter: false, columnFilter: false,
width: '20%',
}, },
{ {
align: 'left',
label: t('entryStockBought.date'), label: t('entryStockBought.date'),
name: 'dated', name: 'dated',
component: 'date', component: 'date',
@ -77,7 +76,7 @@ const columns = computed(() => [
create: true, create: true,
}, },
{ {
align: 'left', align: 'center',
name: 'tableActions', name: 'tableActions',
actions: [ actions: [
{ {
@ -90,7 +89,7 @@ const columns = computed(() => [
component: EntryStockBoughtDetail, component: EntryStockBoughtDetail,
componentProps: { componentProps: {
workerFk: row.workerFk, workerFk: row.workerFk,
dated: userParams.value.dated, dated: filterDate.value.dated,
}, },
}); });
}, },
@ -98,39 +97,29 @@ const columns = computed(() => [
], ],
}, },
]); ]);
const fetchDataRef = ref(); const fetchDataRef = ref();
const travelDialogRef = ref(false); const travelDialogRef = ref(false);
const tableRef = ref(); const tableRef = ref();
const travel = ref(null); const travel = ref(null);
const userParams = ref({ const filter = computed(() => ({
dated: Date.vnNew().toJSON(), fields: ['id', 'm3', 'ref', 'warehouseInFk'],
});
const filter = ref({
fields: ['id', 'm3', 'warehouseInFk'],
include: [ include: [
{ {
relation: 'warehouseIn', relation: 'warehouseIn',
scope: { scope: {
fields: ['code'], fields: ['code', 'name'],
}, },
}, },
], ],
where: { where: {
shipped: (userParams.value.dated shipped: date.adjustDate(filterDate.value.dated, {
? new Date(userParams.value.dated) hour: 0,
: Date.vnNew() minute: 0,
).setHours(0, 0, 0, 0), second: 0,
}),
m3: { neq: null }, m3: { neq: null },
}, },
}); }));
const setUserParams = async ({ dated }) => {
const shipped = (dated ? new Date(dated) : Date.vnNew()).setHours(0, 0, 0, 0);
filter.value.where.shipped = shipped;
fetchDataRef.value?.fetch();
};
function openDialog() { function openDialog() {
travelDialogRef.value = true; travelDialogRef.value = true;
@ -151,6 +140,31 @@ function round(value) {
function boughtStyle(bought, reserve) { function boughtStyle(bought, reserve) {
return reserve < bought ? { color: 'var(--q-negative)' } : ''; return reserve < bought ? { color: 'var(--q-negative)' } : '';
} }
async function beforeSave(data, getChanges) {
const changes = data.creates;
if (!changes) return data;
const patchPromises = [];
for (const change of changes) {
if (change?.isReal === false && change?.reserve > 0) {
const postData = {
workerFk: change.workerFk,
reserve: change.reserve,
dated: filterDate.value.dated,
};
const promise = axios.post('StockBoughts', postData).catch((error) => {
console.error('Error processing change: ', change, error);
});
patchPromises.push(promise);
}
}
await Promise.all(patchPromises);
const filteredChanges = changes.filter((change) => change?.isReal !== false);
data.creates = filteredChanges;
}
</script> </script>
<template> <template>
<VnSubToolbar> <VnSubToolbar>
@ -158,18 +172,17 @@ function boughtStyle(bought, reserve) {
<FetchData <FetchData
ref="fetchDataRef" ref="fetchDataRef"
url="Travels" url="Travels"
auto-load
:filter="filter" :filter="filter"
@on-fetch=" @on-fetch="
(data) => { (data) => {
travel = data.find( travel = data.find(
(data) => data.warehouseIn?.code.toLowerCase() === 'vnh', (data) => data.warehouseIn?.code?.toLowerCase() === 'vnh',
); );
} }
" "
/> />
<VnRow class="travel"> <VnRow class="travel">
<div v-if="travel"> <div v-show="travel">
<span style="color: var(--vn-label-color)"> <span style="color: var(--vn-label-color)">
{{ t('entryStockBought.purchaseSpaces') }}: {{ t('entryStockBought.purchaseSpaces') }}:
</span> </span>
@ -180,7 +193,7 @@ function boughtStyle(bought, reserve) {
v-if="travel?.m3" v-if="travel?.m3"
style="max-width: 20%" style="max-width: 20%"
flat flat
icon="edit" icon="search"
@click="openDialog()" @click="openDialog()"
:title="t('entryStockBought.editTravel')" :title="t('entryStockBought.editTravel')"
color="primary" color="primary"
@ -195,57 +208,42 @@ function boughtStyle(bought, reserve) {
:url-update="`Travels/${travel?.id}`" :url-update="`Travels/${travel?.id}`"
model="travel" model="travel"
:title="t('Travel m3')" :title="t('Travel m3')"
:form-initial-data="{ id: travel?.id, m3: travel?.m3 }" :form-initial-data="travel"
@on-data-saved="fetchDataRef.fetch()" @on-data-saved="fetchDataRef.fetch()"
> >
<template #form-inputs="{ data }"> <template #form-inputs="{ data }">
<VnInput <span class="link">
v-model="data.id" {{ data.ref }}
:label="t('id')" <TravelDescriptorProxy :id="data.id" />
type="number" </span>
disable
readonly
/>
<VnInput v-model="data.m3" :label="t('m3')" type="number" /> <VnInput v-model="data.m3" :label="t('m3')" type="number" />
</template> </template>
</FormModelPopup> </FormModelPopup>
</QDialog> </QDialog>
<RightMenu>
<template #right-panel>
<EntryStockBoughtFilter
data-key="StockBoughts"
@set-user-params="setUserParams"
/>
</template>
</RightMenu>
<div class="table-container"> <div class="table-container">
<div class="column items-center"> <div class="column items-center">
<VnTable <VnTable
ref="tableRef" ref="tableRef"
data-key="StockBoughts" data-key="StockBoughts"
url="StockBoughts/getStockBought" url="StockBoughts/getStockBought"
:beforeSaveFn="beforeSave"
save-url="StockBoughts/crud" save-url="StockBoughts/crud"
search-url="StockBoughts" search-url="StockBoughts"
order="reserve DESC" order="bought DESC"
:right-search="false"
:is-editable="true" :is-editable="true"
@on-fetch="(data) => setFooter(data)" @on-fetch="
:create="{ async (data) => {
urlCreate: 'StockBoughts', setFooter(data);
title: t('entryStockBought.reserveSomeSpace'), await fetchDataRef.fetch();
onDataSaved: () => tableRef.reload(), }
formInitialData: { "
workerFk: user.id,
dated: Date.vnNow(),
},
}"
:columns="columns" :columns="columns"
:user-params="userParams"
:footer="true" :footer="true"
table-height="80vh" table-height="80vh"
auto-load
:column-search="false" :column-search="false"
:without-header="true" :without-header="true"
:user-params="{ dated: Date.vnNew() }"
auto-load
> >
<template #column-workerFk="{ row }"> <template #column-workerFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
@ -278,9 +276,6 @@ function boughtStyle(bought, reserve) {
.column { .column {
min-width: 35%; min-width: 35%;
margin-top: 5%; margin-top: 5%;
display: flex;
flex-direction: column;
align-items: center;
} }
.text-negative { .text-negative {
color: $negative !important; color: $negative !important;

View File

@ -1,70 +0,0 @@
<script setup>
import { useI18n } from 'vue-i18n';
import { onMounted } from 'vue';
import { useStateStore } from 'stores/useStateStore';
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
const { t } = useI18n();
const props = defineProps({
dataKey: {
type: String,
required: true,
},
});
const stateStore = useStateStore();
const emit = defineEmits(['set-user-params']);
const setUserParams = (params) => {
emit('set-user-params', params);
};
onMounted(async () => {
stateStore.rightDrawer = true;
});
</script>
<template>
<VnFilterPanel
:data-key="props.dataKey"
:search-button="true"
search-url="StockBoughts"
@set-user-params="setUserParams"
>
<template #tags="{ tag, formatFn }">
<div class="q-gutter-x-xs">
<strong>{{ t(`params.${tag.label}`) }}: </strong>
<span>{{ formatFn(tag.value) }}</span>
</div>
</template>
<template #body="{ params, searchFn }">
<QItem class="q-my-sm">
<QItemSection>
<VnInputDate
id="date"
v-model="params.dated"
@update:model-value="
(value) => {
params.dated = value;
setUserParams(params);
searchFn();
}
"
:label="t('Date')"
is-outlined
/>
</QItemSection>
</QItem>
</template>
</VnFilterPanel>
</template>
<i18n>
en:
params:
dated: Date
workerFk: Worker
es:
Date: Fecha
params:
dated: Fecha
workerFk: Trabajador
</i18n>

View File

@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue'; import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { toDate } from 'src/filters/index'; import { toDate } from 'src/filters/index';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
import EntryBuysTableDialog from './EntryBuysTableDialog.vue'; import EntrySupplierlDetail from './EntrySupplierlDetail.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -18,18 +18,28 @@ const columns = computed(() => [
{ {
align: 'left', align: 'left',
name: 'id', name: 'id',
label: t('myEntries.id'), label: t('entrySupplier.id'),
columnFilter: false, columnFilter: false,
isId: true,
chip: {
condition: () => true,
},
},
{
align: 'left',
name: 'supplierName',
label: t('entrySupplier.supplierName'),
cardVisible: true,
isTitle: true, isTitle: true,
}, },
{ {
visible: false, visible: false,
align: 'right', align: 'right',
label: t('myEntries.shipped'), label: t('entrySupplier.shipped'),
name: 'shipped', name: 'shipped',
columnFilter: { columnFilter: {
name: 'fromShipped', name: 'fromShipped',
label: t('myEntries.fromShipped'), label: t('entrySupplier.fromShipped'),
component: 'date', component: 'date',
}, },
format: ({ shipped }) => toDate(shipped), format: ({ shipped }) => toDate(shipped),
@ -37,26 +47,26 @@ const columns = computed(() => [
{ {
visible: false, visible: false,
align: 'left', align: 'left',
label: t('myEntries.shipped'), label: t('entrySupplier.shipped'),
name: 'shipped', name: 'shipped',
columnFilter: { columnFilter: {
name: 'toShipped', name: 'toShipped',
label: t('myEntries.toShipped'), label: t('entrySupplier.toShipped'),
component: 'date', component: 'date',
}, },
format: ({ shipped }) => toDate(shipped), format: ({ shipped }) => toDate(shipped),
cardVisible: true, cardVisible: true,
}, },
{ {
align: 'right', align: 'left',
label: t('myEntries.shipped'), label: t('entrySupplier.shipped'),
name: 'shipped', name: 'shipped',
columnFilter: false, columnFilter: false,
format: ({ shipped }) => toDate(shipped), format: ({ shipped }) => toDate(shipped),
}, },
{ {
align: 'right', align: 'left',
label: t('myEntries.landed'), label: t('entrySupplier.landed'),
name: 'landed', name: 'landed',
columnFilter: false, columnFilter: false,
format: ({ landed }) => toDate(landed), format: ({ landed }) => toDate(landed),
@ -64,15 +74,13 @@ const columns = computed(() => [
{ {
align: 'right', align: 'right',
label: t('myEntries.wareHouseIn'), label: t('entrySupplier.wareHouseIn'),
name: 'warehouseInFk', name: 'warehouseInFk',
format: (row) => { format: ({ warehouseInName }) => warehouseInName,
row.warehouseInName;
},
cardVisible: true, cardVisible: true,
columnFilter: { columnFilter: {
name: 'warehouseInFk', name: 'warehouseInFk',
label: t('myEntries.warehouseInFk'), label: t('entrySupplier.warehouseInFk'),
component: 'select', component: 'select',
attrs: { attrs: {
url: 'warehouses', url: 'warehouses',
@ -86,13 +94,13 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
label: t('myEntries.daysOnward'), label: t('entrySupplier.daysOnward'),
name: 'daysOnward', name: 'daysOnward',
visible: false, visible: false,
}, },
{ {
align: 'left', align: 'left',
label: t('myEntries.daysAgo'), label: t('entrySupplier.daysAgo'),
name: 'daysAgo', name: 'daysAgo',
visible: false, visible: false,
}, },
@ -101,8 +109,8 @@ const columns = computed(() => [
name: 'tableActions', name: 'tableActions',
actions: [ actions: [
{ {
title: t('myEntries.printLabels'), title: t('entrySupplier.printLabels'),
icon: 'move_item', icon: 'search',
isPrimary: true, isPrimary: true,
action: (row) => printBuys(row.id), action: (row) => printBuys(row.id),
}, },
@ -112,7 +120,7 @@ const columns = computed(() => [
const printBuys = (rowId) => { const printBuys = (rowId) => {
quasar.dialog({ quasar.dialog({
component: EntryBuysTableDialog, component: EntrySupplierlDetail,
componentProps: { componentProps: {
id: rowId, id: rowId,
}, },
@ -121,19 +129,18 @@ const printBuys = (rowId) => {
</script> </script>
<template> <template>
<VnSearchbar <VnSearchbar
data-key="myEntriesList" data-key="entrySupplierList"
url="Entries/filter" url="Entries/filter"
:label="t('myEntries.search')" :label="t('entrySupplier.search')"
:info="t('myEntries.searchInfo')" :info="t('entrySupplier.searchInfo')"
/> />
<VnTable <VnTable
data-key="myEntriesList" data-key="entrySupplierList"
url="Entries/filter" url="Entries/filter"
:columns="columns" :columns="columns"
:user-params="params" :user-params="params"
default-mode="card" default-mode="card"
order="shipped DESC" order="shipped DESC"
auto-load auto-load
chip-locale="myEntries"
/> />
</template> </template>

View File

@ -30,7 +30,7 @@ const entriesTableColumns = computed(() => [
align: 'left', align: 'left',
name: 'itemFk', name: 'itemFk',
field: 'itemFk', field: 'itemFk',
label: t('entry.latestBuys.tableVisibleColumns.itemFk'), label: t('entrySupplier.itemId'),
}, },
{ {
align: 'left', align: 'left',
@ -65,7 +65,15 @@ const entriesTableColumns = computed(() => [
]); ]);
function downloadCSV(rows) { function downloadCSV(rows) {
const headers = ['id', 'itemFk', 'name', 'stickers', 'packing', 'grouping', 'comment']; const headers = [
'id',
'itemFk',
'name',
'stickers',
'packing',
'grouping',
'comment',
];
const csvRows = rows.map((row) => { const csvRows = rows.map((row) => {
const buy = row; const buy = row;
@ -119,17 +127,18 @@ function downloadCSV(rows) {
> >
<template #top-left> <template #top-left>
<QBtn <QBtn
:label="t('myEntries.downloadCsv')" :label="t('entrySupplier.downloadCsv')"
color="primary" color="primary"
icon="csv" icon="csv"
@click="downloadCSV(rows)" @click="downloadCSV(rows)"
unelevated unelevated
data-cy="downloadCsvBtn"
/> />
</template> </template>
<template #top-right> <template #top-right>
<QBtn <QBtn
class="q-mr-lg" class="q-mr-lg"
:label="t('myEntries.printLabels')" :label="t('entrySupplier.printLabels')"
color="primary" color="primary"
icon="print" icon="print"
@click=" @click="
@ -148,13 +157,18 @@ function downloadCSV(rows) {
v-if="props.row.stickers > 0" v-if="props.row.stickers > 0"
@click=" @click="
openReport( openReport(
`Entries/${props.row.id}/buy-label-supplier` `Entries/${props.row.id}/buy-label-supplier`,
{},
true,
) )
" "
unelevated unelevated
color="primary"
flat
data-cy="seeLabelBtn"
> >
<QTooltip>{{ <QTooltip>{{
t('myEntries.viewLabel') t('entrySupplier.viewLabel')
}}</QTooltip> }}</QTooltip>
</QBtn> </QBtn>
</QTr> </QTr>

View File

@ -38,7 +38,7 @@ const recalc = async () => {
<template> <template>
<div class="q-pa-lg row justify-center"> <div class="q-pa-lg row justify-center">
<QCard class="bg-light" style="width: 300px"> <QCard class="bg-light" style="width: 300px" data-cy="wasteRecalc">
<QCardSection> <QCardSection>
<VnInputDate <VnInputDate
class="q-mb-lg" class="q-mb-lg"
@ -46,6 +46,7 @@ const recalc = async () => {
:label="$t('globals.from')" :label="$t('globals.from')"
rounded rounded
dense dense
data-cy="dateFrom"
/> />
<VnInputDate <VnInputDate
class="q-mb-lg" class="q-mb-lg"
@ -55,6 +56,7 @@ const recalc = async () => {
:disable="!dateFrom" :disable="!dateFrom"
rounded rounded
dense dense
data-cy="dateTo"
/> />
<QBtn <QBtn
color="primary" color="primary"
@ -63,6 +65,7 @@ const recalc = async () => {
:loading="isLoading" :loading="isLoading"
:disable="isLoading || !(dateFrom && dateTo)" :disable="isLoading || !(dateFrom && dateTo)"
@click="recalc()" @click="recalc()"
data-cy="recalc"
/> />
</QCardSection> </QCardSection>
</QCard> </QCard>

View File

@ -6,7 +6,7 @@ entry:
list: list:
newEntry: New entry newEntry: New entry
tableVisibleColumns: tableVisibleColumns:
isExcludedFromAvailable: Exclude from inventory isExcludedFromAvailable: Excluded from available
isOrdered: Ordered isOrdered: Ordered
isConfirmed: Ready to label isConfirmed: Ready to label
isReceived: Received isReceived: Received
@ -33,7 +33,7 @@ entry:
invoiceAmount: Invoice amount invoiceAmount: Invoice amount
ordered: Ordered ordered: Ordered
booked: Booked booked: Booked
excludedFromAvailable: Inventory excludedFromAvailable: Excluded
travelReference: Reference travelReference: Reference
travelAgency: Agency travelAgency: Agency
travelShipped: Shipped travelShipped: Shipped
@ -55,7 +55,7 @@ entry:
commission: Commission commission: Commission
observation: Observation observation: Observation
booked: Booked booked: Booked
excludedFromAvailable: Inventory excludedFromAvailable: Excluded
initialTemperature: Ini °C initialTemperature: Ini °C
finalTemperature: Fin °C finalTemperature: Fin °C
buys: buys:
@ -65,27 +65,10 @@ entry:
printedStickers: Printed stickers printedStickers: Printed stickers
notes: notes:
observationType: Observation type observationType: Observation type
latestBuys:
tableVisibleColumns:
image: Picture
itemFk: Item ID
weightByPiece: Weight/Piece
isActive: Active
family: Family
entryFk: Entry
freightValue: Freight value
comissionValue: Commission value
packageValue: Package value
isIgnored: Is ignored
price2: Grouping
price3: Packing
minPrice: Min
ektFk: Ekt
packingOut: Package out
landing: Landing
isExcludedFromAvailable: Es inventory
params: params:
isExcludedFromAvailable: Exclude from inventory entryFk: Entry
observationTypeFk: Observation type
isExcludedFromAvailable: Excluded from available
isOrdered: Ordered isOrdered: Ordered
isConfirmed: Ready to label isConfirmed: Ready to label
isReceived: Received isReceived: Received
@ -127,13 +110,17 @@ entry:
company_name: Company name company_name: Company name
itemTypeFk: Item type itemTypeFk: Item type
workerFk: Worker id workerFk: Worker id
daysAgo: Days ago
toShipped: T. shipped
fromShipped: F. shipped
supplierName: Supplier
search: Search entries search: Search entries
searchInfo: You can search by entry reference searchInfo: You can search by entry reference
descriptorMenu: descriptorMenu:
showEntryReport: Show entry report showEntryReport: Show entry report
entryFilter: entryFilter:
params: params:
isExcludedFromAvailable: Exclude from inventory isExcludedFromAvailable: Excluded from available
invoiceNumber: Invoice number invoiceNumber: Invoice number
travelFk: Travel travelFk: Travel
companyFk: Company companyFk: Company
@ -155,7 +142,7 @@ entryFilter:
warehouseOutFk: Origin warehouseOutFk: Origin
warehouseInFk: Destiny warehouseInFk: Destiny
entryTypeCode: Entry type entryTypeCode: Entry type
myEntries: entrySupplier:
id: ID id: ID
landed: Landed landed: Landed
shipped: Shipped shipped: Shipped
@ -170,6 +157,8 @@ myEntries:
downloadCsv: Download CSV downloadCsv: Download CSV
search: Search entries search: Search entries
searchInfo: You can search by entry reference searchInfo: You can search by entry reference
supplierName: Supplier
itemId: Item id
entryStockBought: entryStockBought:
travel: Travel travel: Travel
editTravel: Edit travel editTravel: Edit travel

View File

@ -6,7 +6,7 @@ entry:
list: list:
newEntry: Nueva entrada newEntry: Nueva entrada
tableVisibleColumns: tableVisibleColumns:
isExcludedFromAvailable: Excluir del inventario isExcludedFromAvailable: Excluir del disponible
isOrdered: Pedida isOrdered: Pedida
isConfirmed: Lista para etiquetar isConfirmed: Lista para etiquetar
isReceived: Recibida isReceived: Recibida
@ -33,7 +33,7 @@ entry:
invoiceAmount: Importe invoiceAmount: Importe
ordered: Pedida ordered: Pedida
booked: Contabilizada booked: Contabilizada
excludedFromAvailable: Inventario excludedFromAvailable: Excluido
travelReference: Referencia travelReference: Referencia
travelAgency: Agencia travelAgency: Agencia
travelShipped: F. envio travelShipped: F. envio
@ -56,7 +56,7 @@ entry:
observation: Observación observation: Observación
commission: Comisión commission: Comisión
booked: Contabilizada booked: Contabilizada
excludedFromAvailable: Inventario excludedFromAvailable: Excluido
initialTemperature: Ini °C initialTemperature: Ini °C
finalTemperature: Fin °C finalTemperature: Fin °C
buys: buys:
@ -66,30 +66,12 @@ entry:
printedStickers: Etiquetas impresas printedStickers: Etiquetas impresas
notes: notes:
observationType: Tipo de observación observationType: Tipo de observación
latestBuys:
tableVisibleColumns:
image: Foto
itemFk: Id Artículo
weightByPiece: Peso (gramos)/tallo
isActive: Activo
family: Familia
entryFk: Entrada
freightValue: Porte
comissionValue: Comisión
packageValue: Embalaje
isIgnored: Ignorado
price2: Grouping
price3: Packing
minPrice: Min
ektFk: Ekt
packingOut: Embalaje envíos
landing: Llegada
isExcludedFromAvailable: Es inventario
search: Buscar entradas search: Buscar entradas
searchInfo: Puedes buscar por referencia de entrada searchInfo: Puedes buscar por referencia de entrada
params: params:
isExcludedFromAvailable: Excluir del inventario entryFk: Entrada
observationTypeFk: Tipo de observación
isExcludedFromAvailable: Excluir del disponible
isOrdered: Pedida isOrdered: Pedida
isConfirmed: Lista para etiquetar isConfirmed: Lista para etiquetar
isReceived: Recibida isReceived: Recibida
@ -131,9 +113,13 @@ entry:
company_name: Nombre empresa company_name: Nombre empresa
itemTypeFk: Familia itemTypeFk: Familia
workerFk: Comprador workerFk: Comprador
daysAgo: Días atras
toShipped: F. salida(hasta)
fromShipped: F. salida(desde)
supplierName: Proveedor
entryFilter: entryFilter:
params: params:
isExcludedFromAvailable: Inventario isExcludedFromAvailable: Excluido
isOrdered: Pedida isOrdered: Pedida
isConfirmed: Confirmado isConfirmed: Confirmado
isReceived: Recibida isReceived: Recibida
@ -149,7 +135,7 @@ entryFilter:
warehouseInFk: Destino warehouseInFk: Destino
entryTypeCode: Tipo de entrada entryTypeCode: Tipo de entrada
hasToShowDeletedEntries: Mostrar entradas eliminadas hasToShowDeletedEntries: Mostrar entradas eliminadas
myEntries: entrySupplier:
id: ID id: ID
landed: F. llegada landed: F. llegada
shipped: F. salida shipped: F. salida
@ -164,10 +150,12 @@ myEntries:
downloadCsv: Descargar CSV downloadCsv: Descargar CSV
search: Buscar entradas search: Buscar entradas
searchInfo: Puedes buscar por referencia de la entrada searchInfo: Puedes buscar por referencia de la entrada
supplierName: Proveedor
itemId: Id artículo
entryStockBought: entryStockBought:
travel: Envío travel: Envío
editTravel: Editar envío editTravel: Editar envío
purchaseSpaces: Espacios de compra purchaseSpaces: Camiones reservados
buyer: Comprador buyer: Comprador
reserve: Reservado reserve: Reservado
bought: Comprado bought: Comprado

View File

@ -121,25 +121,40 @@ function deleteFile(dmsFk) {
hide-selected hide-selected
:is-clearable="false" :is-clearable="false"
:required="true" :required="true"
data-cy="invoiceInBasicDataSupplier"
/> />
<VnInput <VnInput
clearable clearable
clear-icon="close" clear-icon="close"
:label="t('invoiceIn.supplierRef')" :label="t('invoiceIn.supplierRef')"
v-model="data.supplierRef" v-model="data.supplierRef"
data-cy="invoiceInBasicDataSupplierRef"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnInputDate :label="t('Expedition date')" v-model="data.issued" /> <VnInputDate
:label="t('Expedition date')"
v-model="data.issued"
data-cy="invoiceInBasicDataIssued"
/>
<VnInputDate <VnInputDate
:label="t('Operation date')" :label="t('Operation date')"
v-model="data.operated" v-model="data.operated"
autofocus autofocus
data-cy="invoiceInBasicDataOperated"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnInputDate :label="t('Entry date')" v-model="data.bookEntried" /> <VnInputDate
<VnInputDate :label="t('Accounted date')" v-model="data.booked" /> :label="t('Entry date')"
v-model="data.bookEntried"
data-cy="invoiceInBasicDatabookEntried"
/>
<VnInputDate
:label="t('Accounted date')"
v-model="data.booked"
data-cy="invoiceInBasicDataBooked"
/>
</VnRow> </VnRow>
<VnRow> <VnRow>
<VnSelect <VnSelect
@ -149,7 +164,7 @@ function deleteFile(dmsFk) {
option-value="id" option-value="id"
option-label="id" option-label="id"
:filter-options="['id', 'name']" :filter-options="['id', 'name']"
data-cy="UnDeductibleVatSelect" data-cy="invoiceInBasicDataDeductibleExpenseFk"
> >
<template #option="scope"> <template #option="scope">
<QItem v-bind="scope.itemProps"> <QItem v-bind="scope.itemProps">
@ -182,6 +197,7 @@ function deleteFile(dmsFk) {
padding="xs" padding="xs"
round round
@click="downloadFile(data.dmsFk)" @click="downloadFile(data.dmsFk)"
data-cy="invoiceInBasicDataDmsDownload"
/> />
<QBtn <QBtn
:class="{ :class="{
@ -197,6 +213,7 @@ function deleteFile(dmsFk) {
documentDialogRef.dms = data.dms; documentDialogRef.dms = data.dms;
} }
" "
data-cy="invoiceInBasicDataDmsEdit"
> >
<QTooltip>{{ t('Edit document') }}</QTooltip> <QTooltip>{{ t('Edit document') }}</QTooltip>
</QBtn> </QBtn>
@ -210,6 +227,7 @@ function deleteFile(dmsFk) {
padding="xs" padding="xs"
round round
@click="deleteFile(data.dmsFk)" @click="deleteFile(data.dmsFk)"
data-cy="invoiceInBasicDataDmsDelete"
/> />
</div> </div>
<QBtn <QBtn
@ -224,7 +242,7 @@ function deleteFile(dmsFk) {
delete documentDialogRef.dms; delete documentDialogRef.dms;
} }
" "
data-cy="dms-create" data-cy="invoiceInBasicDataDmsAdd"
> >
<QTooltip>{{ t('Create document') }}</QTooltip> <QTooltip>{{ t('Create document') }}</QTooltip>
</QBtn> </QBtn>
@ -237,9 +255,9 @@ function deleteFile(dmsFk) {
:label="t('Currency')" :label="t('Currency')"
v-model="data.currencyFk" v-model="data.currencyFk"
:options="currencies" :options="currencies"
option-value="id"
option-label="code" option-label="code"
sort-by="id" sort-by="id"
data-cy="invoiceInBasicDataCurrencyFk"
/> />
<VnSelect <VnSelect
@ -249,8 +267,8 @@ function deleteFile(dmsFk) {
:label="t('Company')" :label="t('Company')"
v-model="data.companyFk" v-model="data.companyFk"
:options="companies" :options="companies"
option-value="id"
option-label="code" option-label="code"
data-cy="invoiceInBasicDataCompanyFk"
/> />
</VnRow> </VnRow>
<VnRow> <VnRow>
@ -260,6 +278,7 @@ function deleteFile(dmsFk) {
:options="sageWithholdings" :options="sageWithholdings"
option-value="id" option-value="id"
option-label="withholding" option-label="withholding"
data-cy="invoiceInBasicDataWithholdingSageFk"
/> />
</VnRow> </VnRow>
</template> </template>

View File

@ -1,22 +1,16 @@
<script setup> <script setup>
import { ref, computed, capitalize } from 'vue'; import { ref, computed, capitalize } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import CrudModel from 'src/components/CrudModel.vue'; import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
const route = useRoute();
const { t } = useI18n(); const { t } = useI18n();
const arrayData = useArrayData(); const arrayData = useArrayData();
const invoiceIn = computed(() => arrayData.store.data); const invoiceIn = computed(() => arrayData.store.data);
const invoiceInCorrectionRef = ref(); const invoiceInCorrectionRef = ref();
const filter = {
include: { relation: 'invoiceIn' },
where: { correctingFk: route.params.id },
};
const columns = computed(() => [ const columns = computed(() => [
{ {
name: 'origin', name: 'origin',
@ -92,7 +86,8 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
v-if="invoiceIn" v-if="invoiceIn"
data-key="InvoiceInCorrection" data-key="InvoiceInCorrection"
url="InvoiceInCorrections" url="InvoiceInCorrections"
:filter="filter" :user-filter="{ include: { relation: 'invoiceIn' } }"
:filter="{ where: { correctingFk: $route.params.id } }"
auto-load auto-load
primary-key="correctingFk" primary-key="correctingFk"
:default-remove="false" :default-remove="false"
@ -115,6 +110,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
:option-label="col.optionLabel" :option-label="col.optionLabel"
:disable="row.invoiceIn.isBooked" :disable="row.invoiceIn.isBooked"
:filter-options="['description']" :filter-options="['description']"
data-cy="invoiceInCorrective_type"
> >
<template #option="{ opt, itemProps }"> <template #option="{ opt, itemProps }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
@ -137,6 +133,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
:rules="[requiredFieldRule]" :rules="[requiredFieldRule]"
:filter-options="['code', 'description']" :filter-options="['code', 'description']"
:disable="row.invoiceIn.isBooked" :disable="row.invoiceIn.isBooked"
data-cy="invoiceInCorrective_class"
> >
<template #option="{ opt, itemProps }"> <template #option="{ opt, itemProps }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
@ -161,6 +158,7 @@ const requiredFieldRule = (val) => val || t('globals.requiredField');
:option-label="col.optionLabel" :option-label="col.optionLabel"
:rules="[requiredFieldRule]" :rules="[requiredFieldRule]"
:disable="row.invoiceIn.isBooked" :disable="row.invoiceIn.isBooked"
data-cy="invoiceInCorrective_reason"
/> />
</QTd> </QTd>
</template> </template>

View File

@ -17,10 +17,6 @@ const { t } = useI18n();
const cardDescriptorRef = ref(); const cardDescriptorRef = ref();
const entityId = computed(() => $props.id || +currentRoute.value.params.id); const entityId = computed(() => $props.id || +currentRoute.value.params.id);
const totalAmount = ref(); const totalAmount = ref();
const config = ref();
const cplusRectificationTypes = ref([]);
const siiTypeInvoiceIns = ref([]);
const invoiceCorrectionTypes = ref([]);
const invoiceInCorrection = reactive({ correcting: [], corrected: null }); const invoiceInCorrection = reactive({ correcting: [], corrected: null });
const routes = reactive({ const routes = reactive({
getSupplier: (id) => { getSupplier: (id) => {
@ -30,7 +26,7 @@ const routes = reactive({
return { return {
name: 'InvoiceInList', name: 'InvoiceInList',
query: { query: {
params: JSON.stringify({ supplierFk: id }), table: JSON.stringify({ supplierFk: id }),
}, },
}; };
}, },
@ -39,7 +35,7 @@ const routes = reactive({
return { return {
name: 'InvoiceInList', name: 'InvoiceInList',
query: { query: {
params: JSON.stringify({ correctedFk: entityId.value }), table: JSON.stringify({ correctedFk: entityId.value }),
}, },
}; };
} }
@ -108,7 +104,7 @@ async function setInvoiceCorrection(id) {
<VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" /> <VnLv :label="t('invoiceIn.list.amount')" :value="toCurrency(totalAmount)" />
<VnLv :label="t('invoiceIn.list.supplier')"> <VnLv :label="t('invoiceIn.list.supplier')">
<template #value> <template #value>
<span class="link"> <span class="link" data-cy="invoiceInDescriptor_supplier">
{{ entity?.supplier?.nickname }} {{ entity?.supplier?.nickname }}
<SupplierDescriptorProxy :id="entity?.supplierFk" /> <SupplierDescriptorProxy :id="entity?.supplierFk" />
</span> </span>

View File

@ -1,5 +1,5 @@
<script setup> <script setup>
import { ref, computed, toRefs, reactive } from 'vue'; import { ref, computed, toRefs, reactive, onBeforeMount } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar'; import { useQuasar } from 'quasar';
@ -111,10 +111,9 @@ async function cloneInvoice() {
} }
const isAgricultural = () => { const isAgricultural = () => {
if (!config.value) return false;
return ( return (
invoiceIn.value?.supplier?.sageFarmerWithholdingFk === invoiceIn.value?.supplier?.sageWithholdingFk ==
config?.value[0]?.sageWithholdingFk config.value?.sageFarmerWithholdingFk
); );
}; };
function showPdfInvoice() { function showPdfInvoice() {
@ -153,162 +152,183 @@ const createInvoiceInCorrection = async () => {
); );
push({ path: `/invoice-in/${correctingId}/summary` }); push({ path: `/invoice-in/${correctingId}/summary` });
}; };
onBeforeMount(async () => {
config.value = (
await axios.get('invoiceinConfigs/findOne', {
params: { fields: ['sageFarmerWithholdingFk'] },
})
).data;
});
</script> </script>
<template> <template>
<FetchData <template v-if="config">
url="InvoiceCorrectionTypes" <FetchData
@on-fetch="(data) => (invoiceCorrectionTypes = data)" url="InvoiceCorrectionTypes"
auto-load @on-fetch="(data) => (invoiceCorrectionTypes = data)"
/> auto-load
<FetchData />
url="CplusRectificationTypes" <FetchData
@on-fetch="(data) => (cplusRectificationTypes = data)" url="CplusRectificationTypes"
auto-load @on-fetch="(data) => (cplusRectificationTypes = data)"
/> auto-load
<FetchData />
url="SiiTypeInvoiceIns" <FetchData
:where="{ code: { like: 'R%' } }" url="SiiTypeInvoiceIns"
@on-fetch="(data) => (siiTypeInvoiceIns = data)" :where="{ code: { like: 'R%' } }"
auto-load @on-fetch="(data) => (siiTypeInvoiceIns = data)"
/> auto-load
<FetchData />
url="InvoiceInConfigs" <InvoiceInToBook>
:where="{ fields: ['sageWithholdingFk'] }" <template #content="{ book }">
auto-load <QItem
@on-fetch="(data) => (config = data)" v-if="!invoice?.isBooked && canEditProp('toBook')"
/> v-ripple
<InvoiceInToBook> clickable
<template #content="{ book }"> @click="book(entityId)"
<QItem >
v-if="!invoice?.isBooked && canEditProp('toBook')" <QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection>
v-ripple </QItem>
clickable </template>
@click="book(entityId)" </InvoiceInToBook>
<QItem
v-if="invoice?.isBooked && canEditProp('toUnbook')"
v-ripple
clickable
@click="triggerMenu('unbook')"
>
<QItemSection>
{{ t('invoiceIn.descriptorMenu.unbook') }}
</QItemSection>
</QItem>
<QItem
v-if="canEditProp('deleteById')"
v-ripple
clickable
@click="triggerMenu('delete')"
>
<QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
</QItem>
<QItem
v-if="canEditProp('clone')"
v-ripple
clickable
@click="triggerMenu('clone')"
>
<QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
</QItem>
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
<QItemSection>{{
t('invoiceIn.descriptorMenu.showAgriculturalPdf')
}}</QItemSection>
</QItem>
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
<QItemSection
>{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
> >
<QItemSection>{{ t('invoiceIn.descriptorMenu.book') }}</QItemSection> </QItem>
</QItem> <QItem
</template> v-if="!invoiceInCorrection.corrected"
</InvoiceInToBook> v-ripple
<QItem clickable
v-if="invoice?.isBooked && canEditProp('toUnbook')" @click="triggerMenu('correct')"
v-ripple data-cy="createCorrectiveItem"
clickable
@click="triggerMenu('unbook')"
>
<QItemSection>
{{ t('invoiceIn.descriptorMenu.unbook') }}
</QItemSection>
</QItem>
<QItem
v-if="canEditProp('deleteById')"
v-ripple
clickable
@click="triggerMenu('delete')"
>
<QItemSection>{{ t('invoiceIn.descriptorMenu.deleteInvoice') }}</QItemSection>
</QItem>
<QItem v-if="canEditProp('clone')" v-ripple clickable @click="triggerMenu('clone')">
<QItemSection>{{ t('invoiceIn.descriptorMenu.cloneInvoice') }}</QItemSection>
</QItem>
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('showPdf')">
<QItemSection>{{
t('invoiceIn.descriptorMenu.showAgriculturalPdf')
}}</QItemSection>
</QItem>
<QItem v-if="isAgricultural()" v-ripple clickable @click="triggerMenu('sendPdf')">
<QItemSection
>{{ t('invoiceIn.descriptorMenu.sendAgriculturalPdf') }}...</QItemSection
> >
</QItem> <QItemSection
<QItem >{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
v-if="!invoiceInCorrection.corrected" >
v-ripple </QItem>
clickable <QItem
@click="triggerMenu('correct')" v-if="invoice.dmsFk"
data-cy="createCorrectiveItem" v-ripple
> clickable
<QItemSection @click="downloadFile(invoice.dmsFk)"
>{{ t('invoiceIn.descriptorMenu.createCorrective') }}...</QItemSection
> >
</QItem> <QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection>
<QItem v-if="invoice.dmsFk" v-ripple clickable @click="downloadFile(invoice.dmsFk)"> </QItem>
<QItemSection>{{ t('components.smartCard.downloadFile') }}</QItemSection> <QDialog ref="correctionDialogRef">
</QItem> <QCard data-cy="correctiveInvoiceDialog">
<QDialog ref="correctionDialogRef"> <QCardSection>
<QCard> <QItem class="q-px-none">
<QCardSection> <span class="text-primary text-h6 full-width">
<QItem class="q-px-none"> {{ t('Create rectificative invoice') }}
<span class="text-primary text-h6 full-width"> </span>
{{ t('Create rectificative invoice') }} <QBtn icon="close" flat round dense v-close-popup />
</span> </QItem>
<QBtn icon="close" flat round dense v-close-popup /> </QCardSection>
</QItem> <QCardSection>
</QCardSection> <QItem>
<QCardSection> <QItemSection>
<QItem> <QInput
<QItemSection> :label="t('Original invoice')"
<QInput v-model="entityId"
:label="t('Original invoice')" readonly
v-model="entityId" />
readonly <VnSelect
/> :label="`${useCapitalize(t('globals.class'))}`"
<VnSelect v-model="correctionFormData.invoiceClass"
:label="`${useCapitalize(t('globals.class'))}`" :options="siiTypeInvoiceIns"
v-model="correctionFormData.invoiceClass" option-value="id"
:options="siiTypeInvoiceIns" option-label="code"
option-value="id" :required="true"
option-label="code" data-cy="invoiceInDescriptorMenu_class"
:required="true" />
/> </QItemSection>
</QItemSection> <QItemSection>
<QItemSection> <VnSelect
<VnSelect :label="`${useCapitalize(t('globals.type'))}`"
:label="`${useCapitalize(t('globals.type'))}`" v-model="correctionFormData.invoiceType"
v-model="correctionFormData.invoiceType" :options="cplusRectificationTypes"
:options="cplusRectificationTypes" option-value="id"
option-value="id" option-label="description"
option-label="description" :required="true"
:required="true" data-cy="invoiceInDescriptorMenu_type"
> >
<template #option="{ itemProps, opt }"> <template #option="{ itemProps, opt }">
<QItem v-bind="itemProps"> <QItem v-bind="itemProps">
<QItemSection> <QItemSection>
<QItemLabel <QItemLabel
>{{ opt.id }} - >{{ opt.id }} -
{{ opt.description }}</QItemLabel {{ opt.description }}</QItemLabel
> >
</QItemSection> </QItemSection>
</QItem> </QItem>
<div></div> <div></div>
</template> </template>
</VnSelect> </VnSelect>
<VnSelect <VnSelect
:label="`${useCapitalize(t('globals.reason'))}`" :label="`${useCapitalize(t('globals.reason'))}`"
v-model="correctionFormData.invoiceReason" v-model="correctionFormData.invoiceReason"
:options="invoiceCorrectionTypes" :options="invoiceCorrectionTypes"
option-value="id" option-value="id"
option-label="description" option-label="description"
:required="true" :required="true"
/> data-cy="invoiceInDescriptorMenu_reason"
</QItemSection> />
</QItem> </QItemSection>
</QCardSection> </QItem>
<QCardActions class="justify-end q-mr-sm"> </QCardSection>
<QBtn flat :label="t('globals.close')" color="primary" v-close-popup /> <QCardActions class="justify-end q-mr-sm">
<QBtn <QBtn
:label="t('globals.save')" flat
color="primary" :label="t('globals.close')"
v-close-popup color="primary"
@click="createInvoiceInCorrection" v-close-popup
:disable="isNotFilled" />
/> <QBtn
</QCardActions> :label="t('globals.save')"
</QCard> color="primary"
</QDialog> v-close-popup
@click="createInvoiceInCorrection"
:disable="isNotFilled"
data-cy="saveCorrectiveInvoice"
/>
</QCardActions>
</QCard>
</QDialog>
</template>
</template> </template>
<i18n> <i18n>
en: en:
isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries

View File

@ -198,6 +198,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
color="orange-11" color="orange-11"
text-color="black" text-color="black"
@click="book(entityId)" @click="book(entityId)"
data-cy="invoiceInSummary_book"
/> />
</template> </template>
</InvoiceIntoBook> </InvoiceIntoBook>
@ -219,7 +220,7 @@ const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
:value="entity.supplier?.name" :value="entity.supplier?.name"
> >
<template #value> <template #value>
<span class="link"> <span class="link" data-cy="invoiceInSummary_supplier">
{{ entity.supplier?.name }} {{ entity.supplier?.name }}
<SupplierDescriptorProxy :id="entity.supplierFk" /> <SupplierDescriptorProxy :id="entity.supplierFk" />
</span> </span>

View File

@ -202,6 +202,9 @@ function setCursor(ref) {
:option-label="col.optionLabel" :option-label="col.optionLabel"
:filter-options="['id', 'name']" :filter-options="['id', 'name']"
:tooltip="t('Create a new expense')" :tooltip="t('Create a new expense')"
:acls="[
{ model: 'Expense', props: '*', accessType: 'WRITE' },
]"
@keydown.tab.prevent=" @keydown.tab.prevent="
autocompleteExpense( autocompleteExpense(
$event, $event,

View File

@ -7,6 +7,7 @@ import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import { dateRange } from 'src/filters'; import { dateRange } from 'src/filters';
import { date } from 'quasar'; import { date } from 'quasar';
import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue'; import VnSelectSupplier from 'src/components/common/VnSelectSupplier.vue';
import VnCheckbox from 'src/components/common/VnCheckbox.vue';
defineProps({ dataKey: { type: String, required: true } }); defineProps({ dataKey: { type: String, required: true } });
const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ'; const dateFormat = 'YYYY-MM-DDTHH:mm:ss.SSSZ';
@ -147,13 +148,13 @@ function handleDaysAgo(params, daysAgo) {
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<QCheckbox <VnCheckbox
:label="$t('invoiceIn.isBooked')" :label="$t('invoiceIn.isBooked')"
v-model="params.isBooked" v-model="params.isBooked"
@update:model-value="searchFn()" @update:model-value="searchFn()"
toggle-indeterminate toggle-indeterminate
/> />
<QCheckbox <VnCheckbox
:label="getLocale('params.correctingFk')" :label="getLocale('params.correctingFk')"
v-model="params.correctingFk" v-model="params.correctingFk"
@update:model-value="searchFn()" @update:model-value="searchFn()"

View File

@ -4,7 +4,7 @@ import { useQuasar } from 'quasar';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnConfirm from 'src/components/ui/VnConfirm.vue'; import VnConfirm from 'src/components/ui/VnConfirm.vue';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import qs from 'qs';
const { notify, dialog } = useQuasar(); const { notify, dialog } = useQuasar();
const { t } = useI18n(); const { t } = useI18n();
@ -61,17 +61,15 @@ async function checkToBook(id) {
} }
async function toBook(id) { async function toBook(id) {
let type = 'positive'; let err = false;
let message = t('globals.dataSaved');
try { try {
await axios.post(`InvoiceIns/${id}/toBook`); await axios.post(`InvoiceIns/${id}/toBook`);
store.data.isBooked = true; store.data.isBooked = true;
} catch (e) { } catch (e) {
type = 'negative'; err = true;
message = t('It was not able to book the invoice'); throw e;
} finally { } finally {
notify({ type, message }); if (!err) notify({ type: 'positive', message: t('globals.dataSaved') });
} }
} }
</script> </script>

View File

@ -46,6 +46,11 @@ function ticketFilter(invoice) {
<InvoiceOutDescriptorMenu :invoice-out-data="entity" :menu-ref="menuRef" /> <InvoiceOutDescriptorMenu :invoice-out-data="entity" :menu-ref="menuRef" />
</template> </template>
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv
v-if="entity.externalRef"
:label="t('invoiceOut.externalRef')"
:value="entity.externalRef"
/>
<VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" /> <VnLv :label="t('invoiceOut.card.issued')" :value="toDate(entity.issued)" />
<VnLv :label="t('globals.amount')" :value="toCurrency(entity.amount)" /> <VnLv :label="t('globals.amount')" :value="toCurrency(entity.amount)" />
<VnLv v-if="entity.client" :label="t('globals.client')"> <VnLv v-if="entity.client" :label="t('globals.client')">

View File

@ -8,7 +8,7 @@ import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { usePrintService } from 'src/composables/usePrintService'; import { usePrintService } from 'src/composables/usePrintService';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import InvoiceOutSummary from './Card/InvoiceOutSummary.vue'; import InvoiceOutSummary from './Card/InvoiceOutSummary.vue';
import { toCurrency, toDate } from 'src/filters/index'; import { toCurrency, toDate, dashIfEmpty } from 'src/filters/index';
import { QBtn } from 'quasar'; import { QBtn } from 'quasar';
import axios from 'axios'; import axios from 'axios';
import InvoiceOutFilter from './InvoiceOutFilter.vue'; import InvoiceOutFilter from './InvoiceOutFilter.vue';
@ -16,7 +16,7 @@ import VnRow from 'src/components/ui/VnRow.vue';
import VnRadio from 'src/components/common/VnRadio.vue'; import VnRadio from 'src/components/common/VnRadio.vue';
import VnInput from 'src/components/common/VnInput.vue'; import VnInput from 'src/components/common/VnInput.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue'; import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
const { t } = useI18n(); const { t } = useI18n();
@ -55,6 +55,14 @@ const columns = computed(() => [
name: 'id', name: 'id',
}, },
}, },
{
align: 'left',
name: 'issued',
label: t('invoiceOut.summary.issued'),
component: 'date',
format: (row) => toDate(row.issued),
columnField: { component: null },
},
{ {
align: 'left', align: 'left',
name: 'ref', name: 'ref',
@ -90,12 +98,12 @@ const columns = computed(() => [
{ {
align: 'left', align: 'left',
name: 'departmentFk', name: 'departmentFk',
label: t('globals.params.departmentFk'), label: t('customer.summary.team'),
cardVisible: true,
component: 'select', component: 'select',
attrs: { attrs: {
url: 'Departments', url: 'Departments',
}, },
create: true,
columnField: { columnField: {
component: null, component: null,
}, },
@ -246,7 +254,7 @@ watchEffect(selectedRows);
</template> </template>
<template #column-departmentFk="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.departmentName || '-' }} {{ dashIfEmpty(row.departmentName) }}
<DepartmentDescriptorProxy :id="row?.departmentFk" /> <DepartmentDescriptorProxy :id="row?.departmentFk" />
</span> </span>
</template> </template>

View File

@ -8,7 +8,7 @@ import { useInvoiceOutGlobalStore } from 'src/stores/invoiceOutGlobal.js';
import { useArrayData } from 'src/composables/useArrayData'; import { useArrayData } from 'src/composables/useArrayData';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from '../Ticket/Card/TicketDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue'; import DepartmentDescriptorProxy from '../Worker/Department/Card/DepartmentDescriptorProxy.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import InvoiceOutNegativeBasesFilter from './InvoiceOutNegativeBasesFilter.vue'; import InvoiceOutNegativeBasesFilter from './InvoiceOutNegativeBasesFilter.vue';
import RightMenu from 'src/components/common/RightMenu.vue'; import RightMenu from 'src/components/common/RightMenu.vue';
@ -115,18 +115,16 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
label: t('customer.extendedList.tableVisibleColumns.salesPersonFk'), name: 'departmentFk',
name: 'workerName', label: t('customer.summary.team'),
component: 'select', component: 'select',
attrs: { attrs: {
url: 'Workers/activeWithInheritedRole', url: 'Departments',
fields: ['id', 'name'],
where: { role: 'salesPerson' },
}, },
columnField: { columnField: {
component: null, component: null,
}, },
format: (row, dashIfEmpty) => dashIfEmpty(row.workerName), format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
]); ]);
@ -198,10 +196,10 @@ const downloadCSV = async () => {
<TicketDescriptorProxy :id="row.ticketFk" /> <TicketDescriptorProxy :id="row.ticketFk" />
</span> </span>
</template> </template>
<template #column-workerName="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row.workerName }} {{ row.departmentName }}
<WorkerDescriptorProxy :id="row.comercialId" /> <DepartmentDescriptorProxy :id="row.departmentFk" />
</span> </span>
</template> </template>
<template #moreFilterPanel="{ params }"> <template #moreFilterPanel="{ params }">

View File

@ -129,12 +129,15 @@ const props = defineProps({
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelectWorker <VnSelect
:label="t('invoiceOut.negativeBases.comercial')" outlined
v-model="params.workerName" dense
option-value="name" rounded
is-outlined :label="t('globals.params.departmentFk')"
@update:model-value="searchFn()" v-model="params.departmentFk"
option-value="id"
option-label="name"
url="Departments"
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>

View File

@ -1,6 +1,7 @@
invoiceOut: invoiceOut:
search: Search invoice search: Search invoice
searchInfo: You can search by invoice reference searchInfo: You can search by invoice reference
externalRef: External Ref.
params: params:
id: ID id: ID
company: Company company: Company
@ -12,7 +13,6 @@ invoiceOut:
isActive: Active isActive: Active
hasToInvoice: Has to invoice hasToInvoice: Has to invoice
hasVerifiedData: Verified data hasVerifiedData: Verified data
workerName: Worker
isTaxDataChecked: Verified data isTaxDataChecked: Verified data
amount: Amount amount: Amount
clientFk: Client clientFk: Client
@ -26,6 +26,7 @@ invoiceOut:
max: Max max: Max
hasPdf: Has PDF hasPdf: Has PDF
search: Contains search: Contains
departmentFk: Department
card: card:
issued: Issued issued: Issued
customerCard: Customer card customerCard: Customer card

View File

@ -1,6 +1,7 @@
invoiceOut: invoiceOut:
search: Buscar factura emitida search: Buscar factura emitida
searchInfo: Puedes buscar por referencia de la factura searchInfo: Puedes buscar por referencia de la factura
externalRef: Ref. externa
params: params:
id: ID id: ID
company: Empresa company: Empresa
@ -12,7 +13,6 @@ invoiceOut:
isActive: Activo isActive: Activo
hasToInvoice: Debe facturar hasToInvoice: Debe facturar
hasVerifiedData: Datos verificados hasVerifiedData: Datos verificados
workerName: Comercial
isTaxDataChecked: Datos comprobados isTaxDataChecked: Datos comprobados
amount: Importe amount: Importe
clientFk: Cliente clientFk: Cliente
@ -26,6 +26,7 @@ invoiceOut:
max: Max max: Max
hasPdf: Tiene PDF hasPdf: Tiene PDF
search: Contiene search: Contiene
departmentFk: Departamento
card: card:
issued: Fecha emisión issued: Fecha emisión
customerCard: Ficha del cliente customerCard: Ficha del cliente

View File

@ -3,6 +3,7 @@ import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import { useStateStore } from 'stores/useStateStore'; import { useStateStore } from 'stores/useStateStore';
import { toCurrency } from 'filters/index'; import { toCurrency } from 'filters/index';
import useNotify from 'src/composables/useNotify.js'; import useNotify from 'src/composables/useNotify.js';
@ -61,6 +62,7 @@ const columns = computed(() => [
columnClass: 'expand', columnClass: 'expand',
}, },
{ {
align: 'left',
label: t('item.buyRequest.requester'), label: t('item.buyRequest.requester'),
name: 'requesterName', name: 'requesterName',
component: 'select', component: 'select',
@ -77,6 +79,19 @@ const columns = computed(() => [
}, },
columnClass: 'shrink', columnClass: 'shrink',
}, },
{
align: 'left',
name: 'departmentFk',
label: t('customer.summary.team'),
component: 'select',
attrs: {
url: 'Departments',
},
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
},
{ {
label: t('item.buyRequest.requested'), label: t('item.buyRequest.requested'),
name: 'quantity', name: 'quantity',
@ -107,6 +122,7 @@ const columns = computed(() => [
}, },
columnClass: 'shrink', columnClass: 'shrink',
}, },
{ {
label: t('globals.item'), label: t('globals.item'),
name: 'item', name: 'item',
@ -262,6 +278,12 @@ const onDenyAccept = (_, responseData) => {
<WorkerDescriptorProxy :id="row.requesterFk" /> <WorkerDescriptorProxy :id="row.requesterFk" />
</span> </span>
</template> </template>
<template #column-departmentFk="{ row }">
<span class="link" @click.stop>
{{ row.departmentName }}
<DepartmentDescriptorProxy :id="row.departmentFk" />
</span>
</template>
<template #column-item="{ row }"> <template #column-item="{ row }">
<span> <span>

View File

@ -30,6 +30,7 @@ const entityId = computed(() => {
:filter="filter" :filter="filter"
title="code" title="code"
data-key="ItemType" data-key="ItemType"
:to-module="{ name: 'ItemTypeList' }"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="$t('itemType.shared.code')" :value="entity.code" /> <VnLv :label="$t('itemType.shared.code')" :value="entity.code" />

View File

@ -31,7 +31,7 @@ function exprBuilder(param, value) {
switch (param) { switch (param) {
case 'clientFk': case 'clientFk':
return { [`c.id`]: value }; return { [`c.id`]: value };
case 'salesPersonFk': case 'departmentFk':
return { [`c.${param}`]: value }; return { [`c.${param}`]: value };
} }
} }
@ -62,25 +62,17 @@ const columns = computed(() => [
columnFilter: false, columnFilter: false,
}, },
{ {
label: t('salesClientsTable.salesPerson'),
name: 'salesPersonFk',
field: 'salesPerson',
align: 'left', align: 'left',
name: 'departmentFk',
label: t('customer.summary.team'),
component: 'select',
attrs: {
url: 'Departments',
},
columnField: { columnField: {
component: null, component: null,
}, },
optionFilter: 'firstName', format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
columnFilter: {
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
sortBy: 'nickname ASC',
where: { role: 'salesPerson' },
useLike: false,
},
},
columnClass: 'no-padding',
}, },
{ {
label: t('salesClientsTable.client'), label: t('salesClientsTable.client'),
@ -128,9 +120,9 @@ const columns = computed(() => [
<VnInputDate v-model="to" :label="$t('globals.to')" dense /> <VnInputDate v-model="to" :label="$t('globals.to')" dense />
</VnRow> </VnRow>
</template> </template>
<template #column-salesPersonFk="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" :title="row.salesPerson" v-text="row.salesPerson" /> <span class="link" :title="row.department" v-text="row.department" />
<WorkerDescriptorProxy :id="row.salesPersonFk" dense /> <WorkerDescriptorProxy :id="row.departmentFk" dense />
</template> </template>
<template #column-clientFk="{ row }"> <template #column-clientFk="{ row }">
<span class="link" :title="row.clientName" v-text="row.clientName" /> <span class="link" :title="row.clientName" v-text="row.clientName" />

View File

@ -1,9 +1,9 @@
<script setup> <script setup>
import { ref, computed } from 'vue'; import { ref, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js'; import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
import { toCurrency } from 'src/filters'; import { toCurrency } from 'src/filters';
@ -20,8 +20,8 @@ function exprBuilder(param, value) {
switch (param) { switch (param) {
case 'clientFk': case 'clientFk':
return { [`c.id`]: value }; return { [`c.id`]: value };
case 'salesPersonFk': case 'departmentFk':
return { [`c.salesPersonFk`]: value }; return { [`c.departmentFk`]: value };
} }
} }
@ -63,20 +63,18 @@ const columns = computed(() => [
columnFilter: false, columnFilter: false,
}, },
{ {
label: t('salesClientsTable.salesPerson'),
name: 'salesPersonFk',
align: 'left', align: 'left',
optionFilter: 'firstName', name: 'departmentFk',
columnFilter: { label: t('customer.summary.team'),
component: 'select', component: 'select',
attrs: { attrs: {
url: 'Workers/activeWithInheritedRole', url: 'Departments',
fields: ['id', 'name'],
sortBy: 'nickname ASC',
where: { role: 'salesPerson' },
useLike: false,
},
}, },
create: true,
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
{ {
label: t('salesOrdersTable.import'), label: t('salesOrdersTable.import'),
@ -184,11 +182,10 @@ const openTab = (id) =>
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" />
</QTd> </QTd>
</template> </template>
<template #column-departmentFk="{ row }">
<template #column-salesPersonFk="{ row }">
<QTd @click.stop> <QTd @click.stop>
<span class="link" v-text="row.salesPerson" /> <span class="link" v-text="row.departmentName" />
<WorkerDescriptorProxy :id="row.salesPersonFk" dense /> <DepartmentDescriptorProxy :id="row.departmentFk" dense />
</QTd> </QTd>
</template> </template>
</VnTable> </VnTable>

View File

@ -9,7 +9,6 @@ import VnInput from 'src/components/common/VnInput.vue';
import VnInputNumber from 'src/components/common/VnInputNumber.vue'; import VnInputNumber from 'src/components/common/VnInputNumber.vue';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
import { dateRange } from 'src/filters'; import { dateRange } from 'src/filters';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
defineProps({ dataKey: { type: String, required: true } }); defineProps({ dataKey: { type: String, required: true } });
const { t, te } = useI18n(); const { t, te } = useI18n();
@ -113,16 +112,14 @@ const getLocale = (label) => {
</QItem> </QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelectWorker <VnSelect
outlined outlined
dense dense
rounded rounded
:label="t('globals.params.salesPersonFk')" :label="t('globals.params.departmentFk')"
v-model="params.salesPersonFk" v-model="params.departmentFk"
:params="{ departmentCodes: ['VT'] }" url="Departments"
:no-one="true" />
>
</VnSelectWorker>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem> <QItem>
@ -210,20 +207,6 @@ const getLocale = (label) => {
/> />
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem>
<QItemSection>
<VnSelect
outlined
dense
rounded
:label="t('globals.params.departmentFk')"
v-model="params.department"
option-label="name"
option-value="name"
url="Departments"
/>
</QItemSection>
</QItem>
<QItem> <QItem>
<QItemSection> <QItemSection>
<VnSelect <VnSelect

View File

@ -2,7 +2,7 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue'; import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue'; import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
@ -49,8 +49,8 @@ function exprBuilder(param, value) {
switch (param) { switch (param) {
case 'stateFk': case 'stateFk':
return { 'ts.stateFk': value }; return { 'ts.stateFk': value };
case 'salesPersonFk': case 'departmentFk':
return { 'c.salesPersonFk': !value ? null : value }; return { 'c.departmentFk': !value ? null : value };
case 'provinceFk': case 'provinceFk':
return { 'a.provinceFk': value }; return { 'a.provinceFk': value };
case 'theoreticalHour': case 'theoreticalHour':
@ -108,19 +108,18 @@ const columns = computed(() => [
}, },
}, },
{ {
label: t('salesClientsTable.salesPerson'),
name: 'salesPersonFk',
field: 'userName',
align: 'left', align: 'left',
columnFilter: { name: 'departmentFk',
component: 'select', label: t('customer.summary.team'),
attrs: { component: 'select',
url: 'Workers/search?departmentCodes=["VT"]', attrs: {
fields: ['id', 'name', 'nickname', 'code'], url: 'Departments',
sortBy: 'nickname ASC',
optionLabel: 'nickname',
},
}, },
create: true,
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
{ {
label: t('salesClientsTable.date'), label: t('salesClientsTable.date'),
@ -437,10 +436,10 @@ const openTab = (id) => useOpenURL(`#/ticket/${id}/sale`);
<CustomerDescriptorProxy :id="row.clientFk" /> <CustomerDescriptorProxy :id="row.clientFk" />
</div> </div>
</template> </template>
<template #column-salesPersonFk="{ row }"> <template #column-departmentFk="{ row }">
<div @click.stop :title="row.userName"> <div @click.stop :title="row.departmentName">
<span class="link" v-text="dashIfEmpty(row.userName)" /> <span class="link" v-text="dashIfEmpty(row.departmentName)" />
<WorkerDescriptorProxy :id="row.salesPersonFk" /> <DepartmentDescriptorProxy :id="row.departmentFk" />
</div> </div>
</template> </template>
<template #column-shippedDate="{ row }"> <template #column-shippedDate="{ row }">

View File

@ -7,7 +7,6 @@ salesClientsTable:
to: To to: To
date: Date date: Date
hour: Hour hour: Hour
salesPerson: Salesperson
client: Client client: Client
salesOrdersTable: salesOrdersTable:
delete: Delete delete: Delete

View File

@ -7,7 +7,6 @@ salesClientsTable:
to: Hasta to: Hasta
date: Fecha date: Fecha
hour: Hora hour: Hora
salesPerson: Comercial
client: Cliente client: Cliente
salesOrdersTable: salesOrdersTable:
delete: Eliminar delete: Eliminar

View File

@ -64,17 +64,7 @@ const orderFilter = {
{ {
relation: 'client', relation: 'client',
scope: { scope: {
fields: [ fields: ['name', 'isActive', 'isFreezed', 'isTaxDataChecked'],
'salesPersonFk',
'name',
'isActive',
'isFreezed',
'isTaxDataChecked',
],
include: {
relation: 'salesPersonUser',
scope: { fields: ['id', 'name'] },
},
}, },
}, },
], ],
@ -167,7 +157,7 @@ const onClientChange = async (clientId) => {
!data.isConfirmed && !data.isConfirmed &&
agencyList?.length && agencyList?.length &&
agencyList.some( agencyList.some(
(agency) => agency.agencyModeFk === data.agency_id (agency) => agency.agencyModeFk === data.agency_id,
) )
? data.agencyModeFk ? data.agencyModeFk
: null : null

View File

@ -8,7 +8,7 @@ import filter from './OrderFilter.js';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import FetchData from 'components/FetchData.vue'; import FetchData from 'components/FetchData.vue';
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue'; import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
const DEFAULT_ITEMS = 0; const DEFAULT_ITEMS = 0;
@ -66,11 +66,11 @@ const total = ref(0);
:label="t('globals.state')" :label="t('globals.state')"
:value="getConfirmationValue(entity.isConfirmed)" :value="getConfirmationValue(entity.isConfirmed)"
/> />
<VnLv :label="t('order.field.salesPersonFk')"> <VnLv :label="t('customer.summary.team')">
<template #value> <template #value>
<span class="link"> <span class="link">
{{ entity?.client?.salesPersonUser?.name || '-' }} {{ entity?.client?.department?.name || '-' }}
<WorkerDescriptorProxy :id="entity?.client?.salesPersonFk" /> <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
</span> </span>
</template> </template>
</VnLv> </VnLv>

View File

@ -10,14 +10,14 @@ export default {
relation: 'client', relation: 'client',
scope: { scope: {
fields: [ fields: [
'salesPersonFk', 'departmentFk',
'name', 'name',
'isActive', 'isActive',
'isFreezed', 'isFreezed',
'isTaxDataChecked', 'isTaxDataChecked',
], ],
include: { include: {
relation: 'salesPersonUser', relation: 'department',
scope: { fields: ['id', 'name'] }, scope: { fields: ['id', 'name'] },
}, },
}, },

View File

@ -6,7 +6,6 @@ import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
import VnSelect from 'components/common/VnSelect.vue'; import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue'; import VnInputDate from 'components/common/VnInputDate.vue';
import VnInput from 'components/common/VnInput.vue'; import VnInput from 'components/common/VnInput.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ const props = defineProps({
@ -62,15 +61,15 @@ const sourceList = ref([]);
outlined outlined
rounded rounded
/> />
<VnSelectWorker <VnSelect
:label="t('globals.salesPerson')"
v-model="params.workerFk"
:params="{
departmentCodes: ['VT'],
}"
dense
outlined outlined
dense
rounded rounded
:label="t('globals.params.departmentFk')"
v-model="params.departmentFk"
option-value="id"
option-label="name"
url="Departments"
/> />
<VnInputDate <VnInputDate
v-model="params.from" v-model="params.from"
@ -125,7 +124,6 @@ en:
search: Includes search: Includes
clientFk: Client clientFk: Client
agencyModeFk: Agency agencyModeFk: Agency
salesPersonFk: Sales Person
from: From from: From
to: To to: To
orderFk: Order orderFk: Order
@ -136,7 +134,6 @@ en:
showEmpty: Show Empty showEmpty: Show Empty
customerId: Customer ID customerId: Customer ID
agency: Agency agency: Agency
salesPerson: Sales Person
fromLanded: From Landed fromLanded: From Landed
toLanded: To Landed toLanded: To Landed
orderId: Order ID orderId: Order ID
@ -149,7 +146,6 @@ es:
search: Búsqueda search: Búsqueda
clientFk: Cliente clientFk: Cliente
agencyModeFk: Agencia agencyModeFk: Agencia
salesPersonFk: Comercial
from: Desde from: Desde
to: Hasta to: Hasta
orderFk: Cesta orderFk: Cesta
@ -160,7 +156,6 @@ es:
showEmpty: Mostrar vacías showEmpty: Mostrar vacías
customerId: ID Cliente customerId: ID Cliente
agency: Agencia agency: Agencia
salesPerson: Comercial
fromLanded: Desde F. entrega fromLanded: Desde F. entrega
toLanded: Hasta F. entrega toLanded: Hasta F. entrega
orderId: ID Cesta orderId: ID Cesta

View File

@ -10,12 +10,12 @@ import axios from 'axios';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue'; import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import OrderFilter from './Card/OrderFilter.vue'; import OrderFilter from './Card/OrderFilter.vue';
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
import WorkerDescriptorProxy from '../Worker/Card/WorkerDescriptorProxy.vue';
import VnTable from 'src/components/VnTable/VnTable.vue'; import VnTable from 'src/components/VnTable/VnTable.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue'; import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
import DepartmentDescriptorProxy from 'src/pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import { getAddresses } from '../Customer/composables/getAddresses'; import { getAddresses } from '../Customer/composables/getAddresses';
const { t } = useI18n(); const { t } = useI18n();
@ -59,22 +59,17 @@ const columns = computed(() => [
}, },
{ {
align: 'left', align: 'left',
name: 'salesPersonFk', name: 'departmentFk',
label: t('module.salesPerson'), label: t('customer.summary.team'),
columnFilter: { component: 'select',
component: 'select', attrs: {
inWhere: true, url: 'Departments',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
where: { role: 'salesPerson' },
useLike: false,
optionValue: 'id',
optionLabel: 'name',
optionFilter: 'firstName',
},
}, },
format: (row) => row?.name, create: true,
columnField: {
component: null,
},
format: (row, dashIfEmpty) => dashIfEmpty(row.departmentName),
}, },
{ {
align: 'center', align: 'center',
@ -264,10 +259,10 @@ const isDefaultAddress = (opt, data) => {
<CustomerDescriptorProxy :id="row?.clientFk" /> <CustomerDescriptorProxy :id="row?.clientFk" />
</span> </span>
</template> </template>
<template #column-salesPersonFk="{ row }"> <template #column-departmentFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row?.name }} {{ row?.departmentName }}
<WorkerDescriptorProxy :id="row?.salesPersonFk" /> <DepartmentDescriptorProxy :id="row?.departmentFk" />
</span> </span>
</template> </template>
<template #column-landed="{ row }"> <template #column-landed="{ row }">

View File

@ -8,7 +8,6 @@ module:
hour: Hour hour: Hour
agency: Agency agency: Agency
total: Total total: Total
salesPerson: Sales Person
address: Address address: Address
cerateOrder: Create order cerateOrder: Create order
lines: lines:
@ -22,8 +21,6 @@ lines:
params: params:
tagGroups: Tags tagGroups: Tags
order: order:
field:
salesPersonFk: Sales Person
form: form:
clientFk: Client clientFk: Client
addressFk: Address addressFk: Address

View File

@ -8,7 +8,6 @@ module:
hour: Hora hour: Hora
agency: Agencia agency: Agencia
total: Total total: Total
salesPerson: Comercial
address: Dirección address: Dirección
cerateOrder: Crear cesta cerateOrder: Crear cesta
lines: lines:
@ -22,8 +21,6 @@ lines:
params: params:
tagGroups: Tags tagGroups: Tags
order: order:
field:
salesPersonFk: Comercial
form: form:
clientFk: Cliente clientFk: Cliente
addressFk: Dirección addressFk: Dirección

View File

@ -17,7 +17,7 @@ const props = defineProps({
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const entityId = computed(() => props.id || route.params.id); const entityId = computed(() => props.id || route.params.id);
const { store } = useArrayData('Parking'); const { store } = useArrayData();
const card = computed(() => store.data); const card = computed(() => store.data);
</script> </script>
<template> <template>
@ -26,6 +26,7 @@ const card = computed(() => store.data);
:url="`Agencies/${entityId}`" :url="`Agencies/${entityId}`"
:title="card?.name" :title="card?.name"
:subtitle="props.id" :subtitle="props.id"
:to-module="{ name: 'RouteAgency' }"
> >
<template #body="{ entity: agency }"> <template #body="{ entity: agency }">
<VnLv :label="t('globals.name')" :value="agency.name" /> <VnLv :label="t('globals.name')" :value="agency.name" />

View File

@ -2,11 +2,11 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import useCardDescription from 'composables/useCardDescription';
import VnLv from 'components/ui/VnLv.vue'; import VnLv from 'components/ui/VnLv.vue';
import { dashIfEmpty, toDate } from 'src/filters'; import { dashIfEmpty, toDate } from 'src/filters';
import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue'; import RouteDescriptorMenu from 'pages/Route/Card/RouteDescriptorMenu.vue';
import filter from './RouteFilter.js'; import filter from './RouteFilter.js';
import useCardDescription from 'src/composables/useCardDescription';
import axios from 'axios'; import axios from 'axios';
const $props = defineProps({ const $props = defineProps({

View File

@ -35,6 +35,7 @@ const entityId = computed(() => {
:filter="filter" :filter="filter"
data-key="Roadmap" data-key="Roadmap"
:summary="summary" :summary="summary"
:to-module="{ name: 'RouteRoadmap' }"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="t('Roadmap')" :value="entity?.name" /> <VnLv :label="t('Roadmap')" :value="entity?.name" />

View File

@ -332,6 +332,7 @@ const openTicketsDialog = (id) => {
<QBtn <QBtn
icon="vn:clone" icon="vn:clone"
color="primary" color="primary"
flat
class="q-mr-sm" class="q-mr-sm"
:disable="!selectedRows?.length" :disable="!selectedRows?.length"
@click="confirmationDialog = true" @click="confirmationDialog = true"
@ -341,6 +342,7 @@ const openTicketsDialog = (id) => {
<QBtn <QBtn
icon="cloud_download" icon="cloud_download"
color="primary" color="primary"
flat
class="q-mr-sm" class="q-mr-sm"
:disable="!selectedRows?.length" :disable="!selectedRows?.length"
@click="showRouteReport" @click="showRouteReport"
@ -352,6 +354,7 @@ const openTicketsDialog = (id) => {
<QBtn <QBtn
icon="check" icon="check"
color="primary" color="primary"
flat
class="q-mr-sm" class="q-mr-sm"
:disable="!selectedRows?.length" :disable="!selectedRows?.length"
@click="markAsServed()" @click="markAsServed()"

View File

@ -3,6 +3,7 @@ import { computed, ref, markRaw } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { useSummaryDialog } from 'src/composables/useSummaryDialog'; import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { toHour } from 'src/filters'; import { toHour } from 'src/filters';
import { useRouter } from 'vue-router';
import RouteSummary from 'pages/Route/Card/RouteSummary.vue'; import RouteSummary from 'pages/Route/Card/RouteSummary.vue';
import RouteFilter from 'pages/Route/Card/RouteFilter.vue'; import RouteFilter from 'pages/Route/Card/RouteFilter.vue';
import VnTable from 'components/VnTable/VnTable.vue'; import VnTable from 'components/VnTable/VnTable.vue';
@ -11,9 +12,9 @@ import AgencyDescriptorProxy from 'src/pages/Route/Agency/Card/AgencyDescriptorP
import VehicleDescriptorProxy from 'src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue'; import VehicleDescriptorProxy from 'src/pages/Route/Vehicle/Card/VehicleDescriptorProxy.vue';
import VnSection from 'src/components/common/VnSection.vue'; import VnSection from 'src/components/common/VnSection.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue'; import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
import RouteTickets from './RouteTickets.vue';
const { t } = useI18n(); const { t } = useI18n();
const router = useRouter();
const { viewSummary } = useSummaryDialog(); const { viewSummary } = useSummaryDialog();
const tableRef = ref([]); const tableRef = ref([]);
const dataKey = 'RouteList'; const dataKey = 'RouteList';
@ -29,8 +30,10 @@ const routeFilter = {
}; };
function redirectToTickets(id) { function redirectToTickets(id) {
const url = `#/route/${id}/tickets`; router.push({
window.open(url, '_blank'); name: 'RouteTickets',
params: { id },
});
} }
const columns = computed(() => [ const columns = computed(() => [
@ -46,26 +49,18 @@ const columns = computed(() => [
width: '25px', width: '25px',
}, },
{ {
align: 'left',
name: 'workerFk', name: 'workerFk',
label: t('gloabls.worker'), label: t('globals.worker'),
component: markRaw(VnSelectWorker), component: markRaw(VnSelectWorker),
create: true, create: true,
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef), format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
columnFilter: false, columnFilter: false,
cardVisible: true,
width: '100px', width: '100px',
}, },
{ {
name: 'workerFk',
label: t('globals.worker'),
visible: false,
cardVisible: true,
},
{
name: 'agencyName',
label: t('globals.agency'), label: t('globals.agency'),
},
{
label: t('globals.Agency'),
name: 'agencyModeFk', name: 'agencyModeFk',
component: 'select', component: 'select',
attrs: { attrs: {
@ -77,23 +72,13 @@ const columns = computed(() => [
}, },
}, },
create: true, create: true,
columnFilter: false, columnFilter: true,
visible: false,
},
{
name: 'agencyName',
label: t('globals.agency'),
visible: false,
cardVisible: true, cardVisible: true,
}, visible: true,
{
name: 'vehiclePlateNumber',
label: t('globals.vehicle'),
}, },
{ {
name: 'vehicleFk', name: 'vehicleFk',
label: t('globals.Vehicle'), label: t('globals.vehicle'),
cardVisible: true,
component: 'select', component: 'select',
attrs: { attrs: {
url: 'vehicles', url: 'vehicles',
@ -106,8 +91,9 @@ const columns = computed(() => [
}, },
}, },
create: true, create: true,
columnFilter: false, columnFilter: true,
visible: false, cardVisible: true,
visible: true,
}, },
{ {
align: 'center', align: 'center',
@ -181,8 +167,8 @@ const columns = computed(() => [
<VnTable <VnTable
:with-filters="false" :with-filters="false"
:data-key :data-key
:columns="columns"
ref="tableRef" ref="tableRef"
:columns="columns"
:right-search="false" :right-search="false"
redirect="route" redirect="route"
:create="{ :create="{
@ -199,7 +185,7 @@ const columns = computed(() => [
<WorkerDescriptorProxy :id="row?.workerFk" v-if="row?.workerFk" /> <WorkerDescriptorProxy :id="row?.workerFk" v-if="row?.workerFk" />
</span> </span>
</template> </template>
<template #column-agencyName="{ row }"> <template #column-agencyModeFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row?.agencyName }} {{ row?.agencyName }}
<AgencyDescriptorProxy <AgencyDescriptorProxy
@ -208,7 +194,7 @@ const columns = computed(() => [
/> />
</span> </span>
</template> </template>
<template #column-vehiclePlateNumber="{ row }"> <template #column-vehicleFk="{ row }">
<span class="link" @click.stop> <span class="link" @click.stop>
{{ row?.vehiclePlateNumber }} {{ row?.vehiclePlateNumber }}
<VehicleDescriptorProxy <VehicleDescriptorProxy

View File

@ -30,16 +30,16 @@ const columns = computed(() => [
align: 'center', align: 'center',
}, },
{ {
name: 'street', name: 'client',
label: t('Street'), label: t('Client'),
field: (row) => row?.street, field: (row) => row?.nickname,
sortable: false, sortable: false,
align: 'left', align: 'left',
}, },
{ {
name: 'client', name: 'street',
label: t('Client'), label: t('Street'),
field: (row) => row?.nickname, field: (row) => row?.street,
sortable: false, sortable: false,
align: 'left', align: 'left',
}, },
@ -199,12 +199,22 @@ const confirmRemove = (ticket) => {
const openSmsDialog = async () => { const openSmsDialog = async () => {
const clientsId = []; const clientsId = [];
const clientsPhone = []; const clientsPhone = [];
const clientWithoutPhone = [];
for (let ticket of selectedRows.value) { for (let ticket of selectedRows.value) {
clientsId.push(ticket?.clientFk); clientsId.push(ticket?.clientFk);
const { data: client } = await axios.get(`Clients/${ticket?.clientFk}`); const { data: client } = await axios.get(`Clients/${ticket?.clientFk}`);
if (!client.phone) {
clientWithoutPhone.push(ticket?.clientFk);
continue;
}
clientsPhone.push(client.phone); clientsPhone.push(client.phone);
} }
if (clientWithoutPhone.length) {
quasar.notify({
type: 'warning',
message: t('components.VnNotes.clientWithoutPhone', { clientWithoutPhone }),
});
}
quasar.dialog({ quasar.dialog({
component: SendSmsDialog, component: SendSmsDialog,
@ -319,7 +329,7 @@ const openSmsDialog = async () => {
selection="multiple" selection="multiple"
> >
<template #body-cell-order="{ row }"> <template #body-cell-order="{ row }">
<QTd class="order-field"> <QTd class="order-field" auto-width>
<div class="flex no-wrap items-center"> <div class="flex no-wrap items-center">
<QIcon <QIcon
name="low_priority" name="low_priority"
@ -341,7 +351,7 @@ const openSmsDialog = async () => {
</QTd> </QTd>
</template> </template>
<template #body-cell-city="{ value, row }"> <template #body-cell-city="{ value, row }">
<QTd auto-width> <QTd>
<span class="link" @click="goToBuscaman(row)"> <span class="link" @click="goToBuscaman(row)">
{{ value }} {{ value }}
<QTooltip>{{ t('Open buscaman') }}</QTooltip> <QTooltip>{{ t('Open buscaman') }}</QTooltip>
@ -349,7 +359,7 @@ const openSmsDialog = async () => {
</QTd> </QTd>
</template> </template>
<template #body-cell-client="{ value, row }"> <template #body-cell-client="{ value, row }">
<QTd auto-width> <QTd>
<span class="link"> <span class="link">
{{ value }} {{ value }}
<CustomerDescriptorProxy :id="row?.clientFk" /> <CustomerDescriptorProxy :id="row?.clientFk" />

View File

@ -24,6 +24,7 @@ const entityId = computed(() => props.id || route.params.id);
:url="`Vehicles/${entityId}`" :url="`Vehicles/${entityId}`"
data-key="Vehicle" data-key="Vehicle"
title="numberPlate" title="numberPlate"
:to-module="{ name: 'RouteVehicle' }"
> >
<template #menu="{ entity }"> <template #menu="{ entity }">
<QItem <QItem

View File

@ -2,6 +2,7 @@
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import VnFilterPanel from 'components/ui/VnFilterPanel.vue'; import VnFilterPanel from 'components/ui/VnFilterPanel.vue';
import VnSelect from 'src/components/common/VnSelect.vue'; import VnSelect from 'src/components/common/VnSelect.vue';
import VnSelectWorker from 'src/components/common/VnSelectWorker.vue';
const { t } = useI18n(); const { t } = useI18n();
const props = defineProps({ const props = defineProps({
@ -46,19 +47,7 @@ const emit = defineEmits(['search']);
</QItem> </QItem>
<QItem class="q-mb-sm"> <QItem class="q-mb-sm">
<QItemSection> <QItemSection>
<VnSelect <VnSelectWorker v-model="params.userFk" outlined rounded />
dense
outlined
rounded
:label="t('params.userFk')"
v-model="params.userFk"
url="Workers/activeWithInheritedRole"
option-value="id"
option-label="firstName"
:where="{ role: 'salesPerson' }"
sort-by="firstName ASC"
:use-like="false"
/>
</QItemSection> </QItemSection>
</QItem> </QItem>
<QItem class="q-mb-md"> <QItem class="q-mb-md">

View File

@ -21,7 +21,7 @@ const entityId = computed(() => props.id || route.params.id);
:url="`Parkings/${entityId}`" :url="`Parkings/${entityId}`"
title="code" title="code"
:filter="filter" :filter="filter"
:to-module="{ name: 'ParkingList' }" :to-module="{ name: 'ParkingMain' }"
> >
<template #body="{ entity }"> <template #body="{ entity }">
<VnLv :label="$t('globals.code')" :value="entity.code" /> <VnLv :label="$t('globals.code')" :value="entity.code" />

View File

@ -44,8 +44,8 @@ const getPriceDifference = async () => {
shipped: ticket.value.shipped, shipped: ticket.value.shipped,
}; };
const { data } = await axios.post( const { data } = await axios.post(
`tickets/${ticket.value.id}/priceDifference`, `tickets/${formData.value.id}/priceDifference`,
params params,
); );
ticket.value.sale = data; ticket.value.sale = data;
}; };
@ -71,8 +71,8 @@ const submit = async () => {
}; };
const { data } = await axios.post( const { data } = await axios.post(
`tickets/${ticket.value.id}/componentUpdate`, `tickets/${formData.value.id}/componentUpdate`,
params params,
); );
if (!data) return; if (!data) return;
@ -99,7 +99,7 @@ const onNextStep = async () => {
openConfirmationModal( openConfirmationModal(
t('basicData.negativesConfirmTitle'), t('basicData.negativesConfirmTitle'),
t('basicData.negativesConfirmMessage'), t('basicData.negativesConfirmMessage'),
submitWithNegatives submitWithNegatives,
); );
else submit(); else submit();
} }

View File

@ -3,10 +3,10 @@ import { ref, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue'; import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import DepartmentDescriptorProxy from 'pages/Worker/Department/Card/DepartmentDescriptorProxy.vue';
import CardDescriptor from 'components/ui/CardDescriptor.vue'; import CardDescriptor from 'components/ui/CardDescriptor.vue';
import TicketDescriptorMenu from './TicketDescriptorMenu.vue'; import TicketDescriptorMenu from './TicketDescriptorMenu.vue';
import VnLv from 'src/components/ui/VnLv.vue'; import VnLv from 'src/components/ui/VnLv.vue';
import VnUserLink from 'src/components/ui/VnUserLink.vue';
import { toDateTimeFormat } from 'src/filters/date'; import { toDateTimeFormat } from 'src/filters/date';
import filter from './TicketFilter.js'; import filter from './TicketFilter.js';
import FetchData from 'src/components/FetchData.vue'; import FetchData from 'src/components/FetchData.vue';
@ -88,12 +88,12 @@ function getInfo() {
</QBadge> </QBadge>
</template> </template>
</VnLv> </VnLv>
<VnLv :label="t('globals.salesPerson')"> <VnLv :label="t('customer.summary.team')">
<template #value> <template #value>
<VnUserLink <span class="link">
:name="entity.client?.salesPersonUser?.name" {{ entity?.client?.department?.name || '-' }}
:worker-id="entity.client?.salesPersonFk" <DepartmentDescriptorProxy :id="entity?.client?.departmentFk" />
/> </span>
</template> </template>
</VnLv> </VnLv>
<VnLv <VnLv

View File

@ -32,7 +32,7 @@ onMounted(() => {
watch( watch(
() => props.ticket, () => props.ticket,
() => restoreTicket () => restoreTicket,
); );
const { push, currentRoute } = useRouter(); const { push, currentRoute } = useRouter();
@ -58,7 +58,7 @@ const hasDocuwareFile = ref();
const quasar = useQuasar(); const quasar = useQuasar();
const canRestoreTicket = ref(false); const canRestoreTicket = ref(false);
const onClientSelected = async(clientId) =>{ const onClientSelected = async (clientId) => {
client.value = clientId; client.value = clientId;
await fetchClient(); await fetchClient();
await fetchAddresses(); await fetchAddresses();
@ -66,10 +66,10 @@ const onClientSelected = async(clientId) =>{
const onAddressSelected = (addressId) => { const onAddressSelected = (addressId) => {
address.value = addressId; address.value = addressId;
} };
const fetchClient = async () => { const fetchClient = async () => {
const response = await getClient(client.value) const response = await getClient(client.value);
if (!response) return; if (!response) return;
const [retrievedClient] = response.data; const [retrievedClient] = response.data;
selectedClient.value = retrievedClient; selectedClient.value = retrievedClient;
@ -151,7 +151,7 @@ function openDeliveryNote(type = 'deliveryNote', documentType = 'pdf') {
recipientId: ticket.value.clientFk, recipientId: ticket.value.clientFk,
type: type, type: type,
}, },
'_blank' '_blank',
); );
} }
@ -297,8 +297,8 @@ async function transferClient() {
clientFk: client.value, clientFk: client.value,
addressFk: address.value, addressFk: address.value,
}; };
await axios.patch( `Tickets/${ticketId.value}/transferClient`, params ); await axios.patch(`Tickets/${ticketId.value}/transferClient`, params);
window.location.reload(); window.location.reload();
} }
@ -339,7 +339,7 @@ async function changeShippedHour(time) {
const { data } = await axios.post( const { data } = await axios.post(
`Tickets/${ticketId.value}/updateEditableTicket`, `Tickets/${ticketId.value}/updateEditableTicket`,
params params,
); );
if (data) window.location.reload(); if (data) window.location.reload();
@ -405,8 +405,7 @@ async function uploadDocuware(force) {
uploadDocuware(true); uploadDocuware(true);
}); });
const { data } = await axios.post(`Docuwares/upload`, { const { data } = await axios.post(`Docuwares/upload-delivery-note`, {
fileCabinet: 'deliveryNote',
ticketIds: [parseInt(ticketId.value)], ticketIds: [parseInt(ticketId.value)],
}); });
@ -500,7 +499,7 @@ async function ticketToRestore() {
</QItem> </QItem>
</template> </template>
</VnSelect> </VnSelect>
<VnSelect <VnSelect
:disable="!client" :disable="!client"
:options="addressesOptions" :options="addressesOptions"
:fields="['id', 'nickname']" :fields="['id', 'nickname']"
@ -815,7 +814,7 @@ async function ticketToRestore() {
en: en:
addTurn: Add turn addTurn: Add turn
invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}" invoiceIds: "Invoices have been generated with the following ids: {invoiceIds}"
es: es:
Show Delivery Note...: Ver albarán... Show Delivery Note...: Ver albarán...
Send Delivery Note...: Enviar albarán... Send Delivery Note...: Enviar albarán...

View File

@ -33,7 +33,7 @@ const save = (sale = $props.sale) => {
}; };
const getMana = async () => { const getMana = async () => {
const { data } = await axios.get(`Tickets/${route.params.id}/getSalesPersonMana`); const { data } = await axios.get(`Tickets/${route.params.id}/getDepartmentMana`);
mana.value = data; mana.value = data;
await getUsesMana(); await getUsesMana();
}; };

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