HOTFIX: #6943 CustomerList form salesPersons options #790
180
CHANGELOG.md
180
CHANGELOG.md
|
@ -1,3 +1,183 @@
|
||||||
|
# Version 24.40 - 2024-10-02
|
||||||
|
|
||||||
|
### Added 🆕
|
||||||
|
|
||||||
|
- chore: refs #4074 admit several acls by:jorgep
|
||||||
|
- chore: refs #4074 drop workerCreate by:jorgep
|
||||||
|
- chore: refs #4074 fix tests by:jorgep
|
||||||
|
- chore: refs #4074 wip replace useRole for useAcl by:jorgep
|
||||||
|
- chore: refs #7155 remove console.log by:alexm
|
||||||
|
- chore: refs #7155 typo by:alexm
|
||||||
|
- chore: refs #7663 add test by:jorgep
|
||||||
|
- chore: refs #7663 create test wip by:jorgep
|
||||||
|
- chore: refs #7663 drop useless code (origin/7663-setWeight) by:jorgep
|
||||||
|
- chore: refs #7828 fix e2e by:jorgep
|
||||||
|
- feat(AccountBasicData): add twoFactorFk by:alexm
|
||||||
|
- feat: add max rule by:Javier Segarra
|
||||||
|
- feat: add shortcut add event in some subSections by:Javier Segarra
|
||||||
|
- feat: add shortcut more buttons (origin/add_shortcut_add_subSections) by:Javier Segarra
|
||||||
|
- feat: add tooltip CustomerNewCustomAgent by:Javier Segarra
|
||||||
|
- feat: apply color when today by:Javier Segarra
|
||||||
|
- feat: change label because its more natural by:Javier Segarra
|
||||||
|
- feat: change order by:Javier Segarra
|
||||||
|
- feat: change QBadge color by:Javier Segarra
|
||||||
|
- feat: change url CustomerList by:Javier Segarra
|
||||||
|
- feat: copy customer countryFk by:Javier Segarra
|
||||||
|
- feat: create VnSelectEnum and add in AccountBasicData and ClaimBasicData by:alexm
|
||||||
|
- feat: CustomerBalance by:Javier Segarra
|
||||||
|
- feat: CustomerConsumptionFilter by:Javier Segarra
|
||||||
|
- feat: customer consumption (origin/7830-customerDesplegables, 7830-customerDesplegables) by:alexm
|
||||||
|
- feat: CustomerCreateTicket by:Javier Segarra
|
||||||
|
- feat: CustomerCredit section by:Javier Segarra
|
||||||
|
- feat: CustomerGreuges by:Javier Segarra
|
||||||
|
- feat: CustomerSample to VnTable by:Javier Segarra
|
||||||
|
- feat: global handler (origin/fix_global_handler, fix_global_handler) by:alexm
|
||||||
|
- feat: goToSupplier by:Javier Segarra
|
||||||
|
- feat: handle newValue by:Javier Segarra
|
||||||
|
- feat: handle same multiple CP by:Javier Segarra
|
||||||
|
- feat: hide menus on small view (origin/hideMenu) by:jorgep
|
||||||
|
- feat: minor changes by:Javier Segarra
|
||||||
|
- feat: orderCreateDialog by:Javier Segarra
|
||||||
|
- feat: refs #4074 drop useless code by:jorgep
|
||||||
|
- feat: refs #4074 useAcl in vnSelectDialog by:jorgep
|
||||||
|
- feat: refs #6346 new wagon type section by:Jon
|
||||||
|
- feat: refs #7404 add m3 and fix detail by:pablone
|
||||||
|
- feat: refs #7404 add some style to the form and reorganize fields by:pablone
|
||||||
|
- feat: refs #7404 add travel m3 to reserves form by:pablone
|
||||||
|
- feat: refs #7404 style dynamic text color by:pablone
|
||||||
|
- feat: refs #7404 travel m3 form by:pablone
|
||||||
|
- feat: refs #7500 added VnImg to show files by:Jon
|
||||||
|
- feat: refs #7663 add setWeight menu opt (wip) by:jorgep
|
||||||
|
- feat: refs #7663 fine tunning by:jorgep
|
||||||
|
- feat: refs #7828 create axios instance which no manage errors (origin/7828-makeCorrectCalls) by:jorgep
|
||||||
|
- feat: refs #7828 useAcl & cherry pick mail data worker by:jorgep
|
||||||
|
- feat: remove cli warnings by:Javier Segarra
|
||||||
|
- feat: show preparation field by:Javier Segarra
|
||||||
|
- feat: stateGroupedFilter by:Javier Segarra
|
||||||
|
- feat: translations fixed by:jgallego
|
||||||
|
- feat(TravelList): add daysOnward by:alexm
|
||||||
|
- feat: travel m3 by:pablone
|
||||||
|
- feat: use disableInifiniteScroll property by:Javier Segarra
|
||||||
|
- feat: VnImg draggable by:Javier Segarra
|
||||||
|
- feat: vnLocation changes by:Javier Segarra
|
||||||
|
- feat: vnSelect exprBuilder by:Javier Segarra
|
||||||
|
- fix: refs #7404 remove some style by:pablone
|
||||||
|
- fix: refs #7404 style non center pop up (origin/7404-fixFront) by:pablone
|
||||||
|
- fix: refs #7404 translates and some minor style fixes by:pablone
|
||||||
|
- fix: styles by:Javier Segarra
|
||||||
|
- perf: improve style by:Javier Segarra
|
||||||
|
|
||||||
|
### Changed 📦
|
||||||
|
|
||||||
|
- perf: CustomerBalance by:Javier Segarra
|
||||||
|
- perf: CustomerBasicData by:Javier Segarra
|
||||||
|
- perf: CustomerBasicData.salesPersonFk by:Javier Segarra
|
||||||
|
- perf: CustomerSummary by:Javier Segarra
|
||||||
|
- perf: customerSummaryTable by:Javier Segarra
|
||||||
|
- perf: disable card option by:Javier Segarra
|
||||||
|
- perf: i18n by:Javier Segarra
|
||||||
|
- perf: improve by:Javier Segarra
|
||||||
|
- perf: improve style by:Javier Segarra
|
||||||
|
- perf: imrpove exprBuilder by:Javier Segarra
|
||||||
|
- perf: minor comments by:Javier Segarra
|
||||||
|
- perf: refs #6346 previous changes by:Jon
|
||||||
|
- perf: sendEmail customerConsumption by:Javier Segarra
|
||||||
|
- perf: solve reload CardSummary component by:Javier Segarra
|
||||||
|
- perf: update CustommerDescriptor by:Javier Segarra
|
||||||
|
- refactor: refs #4074 accept array by:jorgep
|
||||||
|
- refactor: refs #4074 rollback by:jorgep
|
||||||
|
- refactor: refs #4074 use acl & drop useless roles by:jorgep
|
||||||
|
- refactor: refs #4074 useAcl in navigationStore & router by:jorgep
|
||||||
|
- refactor: refs #4074 use fn (origin/4074-useAcls) by:jorgep
|
||||||
|
- refactor: refs #4074 use VnTitle by:jorgep
|
||||||
|
- refactor: refs #6346 deleted front error checking by:Jon
|
||||||
|
- refactor: refs #6346 requested changes by:Jon
|
||||||
|
- refactor: refs #6346 wagons to VnTable by:Jon
|
||||||
|
- refactor: refs #7500 deleted useless code by:Jon
|
||||||
|
- refactor: refs #7500 refactor vnimg when storage is dms by:Jon
|
||||||
|
- refactor: refs #7828 wip by:jorgep
|
||||||
|
|
||||||
|
### Fixed 🛠️
|
||||||
|
|
||||||
|
- chore: refs #4074 fix tests by:jorgep
|
||||||
|
- chore: refs #7828 fix e2e by:jorgep
|
||||||
|
- feat: refs #7404 add m3 and fix detail by:pablone
|
||||||
|
- feat: translations fixed by:jgallego
|
||||||
|
- fix: #5938 grouped filter by:Javier Segarra
|
||||||
|
- fix: #6943 fix customerSummaryTable by:Javier Segarra
|
||||||
|
- fix: #6943 show nickname salesPerson by:Javier Segarra
|
||||||
|
- fix: address-create i18n by:Javier Segarra
|
||||||
|
- fix: comments (origin/6943_fix_customer_module, 6943_fix_customer_module) by:Javier Segarra
|
||||||
|
- fix: CusomerSummary to Address by:Javier Segarra
|
||||||
|
- fix: CustomerAddress mobile by:Javier Segarra
|
||||||
|
- fix: CustomerBillingData by:Javier Segarra
|
||||||
|
- fix: Customerconsumption by:Javier Segarra
|
||||||
|
- fix: customer credit opinion by:alexm
|
||||||
|
- fix: CustomerCreditOpinion workerDescriptor by:Javier Segarra
|
||||||
|
- fix: CustomerDescriptorAccount by:Javier Segarra
|
||||||
|
- fix: CustomerDescriptor.bussinessTypeFk by:Javier Segarra
|
||||||
|
- fix: CustomerFilter by:Javier Segarra
|
||||||
|
- fix: CustomerGreuges by:Javier Segarra
|
||||||
|
- fix: CustomerMandates by:Javier Segarra
|
||||||
|
- fix: Customer module find salesPersons out of first get by:Javier Segarra
|
||||||
|
- fix: CustomerRecovery transalate label by:Javier Segarra
|
||||||
|
- fix: CustomerSamples by:Javier Segarra
|
||||||
|
- fix: customerSummaryToTicketList button by:Javier Segarra
|
||||||
|
- fix: CustomerWebPayment by:Javier Segarra
|
||||||
|
- fix: CustommerSummaryTable Proxy by:Javier Segarra
|
||||||
|
- fix: deleted code by:Jon
|
||||||
|
- fix: duplicate code by:alexm
|
||||||
|
- fix: emit:updateModelValue by:Javier Segarra
|
||||||
|
- fix: fixed wagon tests by:Jon
|
||||||
|
- fix: fix wagon list reload by:Jon
|
||||||
|
- fix: i18n en preparation label by:Javier Segarra
|
||||||
|
- fix: infiniteScroll by:Javier Segarra
|
||||||
|
- fix: isFullMovable checkbox by:Javier Segarra
|
||||||
|
- fix: merge conflicts by:Javier Segarra
|
||||||
|
- fix: merge in dev by:alexm
|
||||||
|
- fix: missing code by:Jon
|
||||||
|
- fix: Options VnSelect properties by:Javier Segarra
|
||||||
|
- fix: refs #4074 await to watch by:jorgep
|
||||||
|
- fix: refs #4074 drop wrong acl by:jorgep
|
||||||
|
- fix: refs #4074 workerCard data-key by:jorgep
|
||||||
|
- fix: refs #6346 fix list and create by:pablone
|
||||||
|
- fix: refs #6943 prevent null (origin/6943-warmfix-preventNull) by:jorgep
|
||||||
|
- fix: refs #7155 remove userParams in watcher (7155-travel_daysOnward) by:alexm
|
||||||
|
- fix: refs #7155 use chip-locale (origin/7155-travel_daysOnward_2, 7155-travel_daysOnward_2) by:alexm
|
||||||
|
- fix: refs #7404 remove console.log by:pablone
|
||||||
|
- fix: refs #7404 remove from test by:pablone
|
||||||
|
- fix: refs #7404 remove some style by:pablone
|
||||||
|
- fix: refs #7404 revert commit prevent production access by:pablone
|
||||||
|
- fix: refs #7404 style non center pop up (origin/7404-fixFront) by:pablone
|
||||||
|
- fix: refs #7404 translates and some minor style fixes by:pablone
|
||||||
|
- fix: refs #7500 fixed e2e test by:Jon
|
||||||
|
- fix: refs #7500 fixed showing images wrongly by:Jon
|
||||||
|
- fix: refs #7830 customer credit by:pablone
|
||||||
|
- fix: refs #7830 remove console.log by:pablone
|
||||||
|
- fix: remove console.log by:pablone
|
||||||
|
- fix: remove FetchData by:Javier Segarra
|
||||||
|
- fix: remove FIXME (origin/6943_fix_customerSummaryTable) by:Javier Segarra
|
||||||
|
- fix: remove print variable by:Javier Segarra
|
||||||
|
- fix: remove promise execution by:Javier Segarra
|
||||||
|
- fix: reset VnTable scroll properties by:Javier Segarra
|
||||||
|
- fix: rule by:Javier Segarra
|
||||||
|
- fix: solve conflicts from master to test by:Javier Segarra
|
||||||
|
- fix: split params (origin/warmfix-addSearchUrl) by:jorgep
|
||||||
|
- fix: state cell by:Javier Segarra
|
||||||
|
- fix: stop call back event hasMoreData by:Javier Segarra
|
||||||
|
- fix: styles by:Javier Segarra
|
||||||
|
- fix: SupplierFiscalData VnLocation (origin/fix_supplierFD_location) by:Javier Segarra
|
||||||
|
- fix: VnLocation test by:Javier Segarra
|
||||||
|
- fix(VnTable): header background-color by:alexm
|
||||||
|
- fix(VnTable): sanitizer value is defined by:carlossa
|
||||||
|
- fix: wagon reload (origin/FixWagonRedirect) by:Jon
|
||||||
|
- fix: workerDms filter workerFk by:alexm
|
||||||
|
- fix(WorkerList): add type email by:alexm
|
||||||
|
- Merge remote-tracking branch 'origin/7830-customerDesplegables' into 6943_fix_customerSummaryTable by:Javier Segarra
|
||||||
|
- refs #7155 scopeDays fix (origin/7155-scopeDays) by:carlossa
|
||||||
|
- revert: vnUSerLink change by:Javier Segarra
|
||||||
|
- test: fix test (7677_vnLocation_perf) by:Javier Segarra
|
||||||
|
|
||||||
# Version 24.38 - 2024-09-17
|
# Version 24.38 - 2024-09-17
|
||||||
|
|
||||||
### Added 🆕
|
### Added 🆕
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "24.38.0",
|
"version": "24.40.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
|
|
@ -5,8 +5,10 @@ import useNotify from 'src/composables/useNotify.js';
|
||||||
|
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
|
const baseUrl = '/api/';
|
||||||
|
|
||||||
axios.defaults.baseURL = '/api/';
|
axios.defaults.baseURL = baseUrl;
|
||||||
|
const axiosNoError = axios.create({ baseURL: baseUrl });
|
||||||
|
|
||||||
const onRequest = (config) => {
|
const onRequest = (config) => {
|
||||||
const token = session.getToken();
|
const token = session.getToken();
|
||||||
|
@ -79,5 +81,7 @@ const onResponseError = (error) => {
|
||||||
|
|
||||||
axios.interceptors.request.use(onRequest, onRequestError);
|
axios.interceptors.request.use(onRequest, onRequestError);
|
||||||
axios.interceptors.response.use(onResponse, onResponseError);
|
axios.interceptors.response.use(onResponse, onResponseError);
|
||||||
|
axiosNoError.interceptors.request.use(onRequest);
|
||||||
|
axiosNoError.interceptors.response.use(onResponse);
|
||||||
|
|
||||||
export { onRequest, onResponseError };
|
export { onRequest, onResponseError, axiosNoError };
|
||||||
|
|
|
@ -2,9 +2,15 @@ import { boot } from 'quasar/wrappers';
|
||||||
import qFormMixin from './qformMixin';
|
import qFormMixin from './qformMixin';
|
||||||
import mainShortcutMixin from './mainShortcutMixin';
|
import mainShortcutMixin from './mainShortcutMixin';
|
||||||
import keyShortcut from './keyShortcut';
|
import keyShortcut from './keyShortcut';
|
||||||
|
import useNotify from 'src/composables/useNotify.js';
|
||||||
|
const { notify } = useNotify();
|
||||||
|
|
||||||
export default boot(({ app }) => {
|
export default boot(({ app }) => {
|
||||||
app.mixin(qFormMixin);
|
app.mixin(qFormMixin);
|
||||||
app.mixin(mainShortcutMixin);
|
app.mixin(mainShortcutMixin);
|
||||||
app.directive('shortcut', keyShortcut);
|
app.directive('shortcut', keyShortcut);
|
||||||
|
app.config.errorHandler = function (err) {
|
||||||
|
console.error(err);
|
||||||
|
notify('globals.error', 'negative', 'error');
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, onMounted, nextTick } from 'vue';
|
import { reactive, ref, onMounted, nextTick, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
@ -7,16 +7,21 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import FormModelPopup from './FormModelPopup.vue';
|
import FormModelPopup from './FormModelPopup.vue';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
|
||||||
defineProps({ showEntityField: { type: Boolean, default: true } });
|
defineProps({ showEntityField: { type: Boolean, default: true } });
|
||||||
|
|
||||||
const emit = defineEmits(['onDataSaved']);
|
const emit = defineEmits(['onDataSaved']);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const bicInputRef = ref(null);
|
const bicInputRef = ref(null);
|
||||||
|
const state = useState();
|
||||||
|
|
||||||
|
const customer = computed(() => state.get('customer'));
|
||||||
|
|
||||||
const bankEntityFormData = reactive({
|
const bankEntityFormData = reactive({
|
||||||
name: null,
|
name: null,
|
||||||
bic: null,
|
bic: null,
|
||||||
countryFk: null,
|
countryFk: customer.value?.countryFk,
|
||||||
id: null,
|
id: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ async function setProvince(id, data) {
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
:rules="validate('postcode.city')"
|
:rules="validate('postcode.city')"
|
||||||
:roles-allowed-to-create="['deliveryAssistant', 'administrative']"
|
:acls="[{ model: 'Town', props: '*', accessType: 'WRITE' }]"
|
||||||
:emit-value="false"
|
:emit-value="false"
|
||||||
clearable
|
clearable
|
||||||
>
|
>
|
||||||
|
|
|
@ -44,7 +44,7 @@ onMounted(async () => {
|
||||||
|
|
||||||
async function fetch(fetchFilter = {}) {
|
async function fetch(fetchFilter = {}) {
|
||||||
try {
|
try {
|
||||||
const filter = Object.assign(fetchFilter, $props.filter); // eslint-disable-line vue/no-dupe-keys
|
const filter = { ...fetchFilter, ...$props.filter }; // eslint-disable-line vue/no-dupe-keys
|
||||||
if ($props.where && !fetchFilter.where) filter.where = $props.where;
|
if ($props.where && !fetchFilter.where) filter.where = $props.where;
|
||||||
if ($props.sortBy) filter.order = $props.sortBy;
|
if ($props.sortBy) filter.order = $props.sortBy;
|
||||||
if ($props.limit) filter.limit = $props.limit;
|
if ($props.limit) filter.limit = $props.limit;
|
||||||
|
|
|
@ -297,11 +297,12 @@ const removeTag = (index, params, search) => {
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem class="q-mt-lg">
|
<QItem class="q-mt-lg">
|
||||||
<QIcon
|
<QBtn
|
||||||
name="add_circle"
|
icon="add_circle"
|
||||||
|
shortcut="+"
|
||||||
|
flat
|
||||||
class="fill-icon-on-hover q-px-xs"
|
class="fill-icon-on-hover q-px-xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="sm"
|
|
||||||
@click="tagValues.push({})"
|
@click="tagValues.push({})"
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -24,9 +24,9 @@ const { notify } = useNotify();
|
||||||
|
|
||||||
const rectificativeTypeOptions = ref([]);
|
const rectificativeTypeOptions = ref([]);
|
||||||
const siiTypeInvoiceOutsOptions = ref([]);
|
const siiTypeInvoiceOutsOptions = ref([]);
|
||||||
const inheritWarehouse = ref(true);
|
|
||||||
const invoiceParams = reactive({
|
const invoiceParams = reactive({
|
||||||
id: $props.invoiceOutData?.id,
|
id: $props.invoiceOutData?.id,
|
||||||
|
inheritWarehouse: true,
|
||||||
});
|
});
|
||||||
const invoiceCorrectionTypesOptions = ref([]);
|
const invoiceCorrectionTypesOptions = ref([]);
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ const refund = async () => {
|
||||||
<div>
|
<div>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('Inherit warehouse')"
|
:label="t('Inherit warehouse')"
|
||||||
v-model="inheritWarehouse"
|
v-model="invoiceParams.inheritWarehouse"
|
||||||
/>
|
/>
|
||||||
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
|
<QIcon name="info" class="cursor-info q-ml-sm" size="sm">
|
||||||
<QTooltip>{{ t('Inherit warehouse tooltip') }}</QTooltip>
|
<QTooltip>{{ t('Inherit warehouse tooltip') }}</QTooltip>
|
||||||
|
|
|
@ -38,7 +38,7 @@ async function onProvinceCreated(_, data) {
|
||||||
hide-selected
|
hide-selected
|
||||||
v-model="provinceFk"
|
v-model="provinceFk"
|
||||||
:rules="validate && validate('postcode.provinceFk')"
|
:rules="validate && validate('postcode.provinceFk')"
|
||||||
:roles-allowed-to-create="['deliveryAssistant', 'administrative']"
|
:acls="[{ model: 'Province', props: '*', accessType: 'WRITE' }]"
|
||||||
>
|
>
|
||||||
<template #option="{ itemProps, opt }">
|
<template #option="{ itemProps, opt }">
|
||||||
<QItem v-bind="itemProps">
|
<QItem v-bind="itemProps">
|
||||||
|
|
|
@ -10,8 +10,6 @@ import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnInputTime from 'components/common/VnInputTime.vue';
|
import VnInputTime from 'components/common/VnInputTime.vue';
|
||||||
import VnTableColumn from 'components/VnTable/VnColumn.vue';
|
import VnTableColumn from 'components/VnTable/VnColumn.vue';
|
||||||
|
|
||||||
defineExpose({ addFilter });
|
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
column: {
|
column: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -30,6 +28,9 @@ const $props = defineProps({
|
||||||
default: 'params',
|
default: 'params',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
defineExpose({ addFilter, props: $props });
|
||||||
|
|
||||||
const model = defineModel(undefined, { required: true });
|
const model = defineModel(undefined, { required: true });
|
||||||
const arrayData = useArrayData($props.dataKey, { searchUrl: $props.searchUrl });
|
const arrayData = useArrayData($props.dataKey, { searchUrl: $props.searchUrl });
|
||||||
const columnFilter = computed(() => $props.column?.columnFilter);
|
const columnFilter = computed(() => $props.column?.columnFilter);
|
||||||
|
@ -115,11 +116,11 @@ const components = {
|
||||||
rawSelect: selectComponent,
|
rawSelect: selectComponent,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function addFilter(value) {
|
async function addFilter(value, name) {
|
||||||
value ??= undefined;
|
value ??= undefined;
|
||||||
if (value && typeof value === 'object') value = model.value;
|
if (value && typeof value === 'object') value = model.value;
|
||||||
value = value === '' ? undefined : value;
|
value = value === '' ? undefined : value;
|
||||||
let field = columnFilter.value?.name ?? $props.column.name;
|
let field = columnFilter.value?.name ?? $props.column.name ?? name;
|
||||||
|
|
||||||
if (columnFilter.value?.inWhere) {
|
if (columnFilter.value?.inWhere) {
|
||||||
if (columnFilter.value.alias) field = columnFilter.value.alias + '.' + field;
|
if (columnFilter.value.alias) field = columnFilter.value.alias + '.' + field;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { useArrayData } from 'composables/useArrayData';
|
||||||
const model = defineModel({ type: Object });
|
const model = defineModel({ type: Object });
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
name: {
|
name: {
|
||||||
type: String,
|
type: [String, Boolean],
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
|
|
|
@ -69,9 +69,10 @@ const $props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
hasSubToolbar: {
|
hasSubToolbar: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: null,
|
||||||
},
|
},
|
||||||
disableOption: {
|
disableOption: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -97,6 +98,14 @@ const $props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
default: '90vh',
|
default: '90vh',
|
||||||
},
|
},
|
||||||
|
chipLocale: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
|
@ -117,6 +126,7 @@ const showForm = ref(false);
|
||||||
const splittedColumns = ref({ columns: [] });
|
const splittedColumns = ref({ columns: [] });
|
||||||
const columnsVisibilitySkipped = ref();
|
const columnsVisibilitySkipped = ref();
|
||||||
const createForm = ref();
|
const createForm = ref();
|
||||||
|
const tableFilterRef = ref([]);
|
||||||
|
|
||||||
const tableModes = [
|
const tableModes = [
|
||||||
{
|
{
|
||||||
|
@ -142,7 +152,7 @@ onMounted(() => {
|
||||||
quasar.platform.is.mobile && !$props.disableOption?.card
|
quasar.platform.is.mobile && !$props.disableOption?.card
|
||||||
? CARD_MODE
|
? CARD_MODE
|
||||||
: $props.defaultMode;
|
: $props.defaultMode;
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = quasar.screen.gt.xs;
|
||||||
columnsVisibilitySkipped.value = [
|
columnsVisibilitySkipped.value = [
|
||||||
...splittedColumns.value.columns
|
...splittedColumns.value.columns
|
||||||
.filter((c) => c.visible == false)
|
.filter((c) => c.visible == false)
|
||||||
|
@ -219,7 +229,7 @@ function splitColumns(columns) {
|
||||||
if (col.cardVisible) splittedColumns.value.cardVisible.push(col);
|
if (col.cardVisible) splittedColumns.value.cardVisible.push(col);
|
||||||
if ($props.isEditable && col.disable == null) col.disable = false;
|
if ($props.isEditable && col.disable == null) col.disable = false;
|
||||||
if ($props.useModel && col.columnFilter != false)
|
if ($props.useModel && col.columnFilter != false)
|
||||||
col.columnFilter = { ...col.columnFilter, inWhere: true };
|
col.columnFilter = { inWhere: true, ...col.columnFilter };
|
||||||
splittedColumns.value.columns.push(col);
|
splittedColumns.value.columns.push(col);
|
||||||
}
|
}
|
||||||
// Status column
|
// Status column
|
||||||
|
@ -297,6 +307,7 @@ defineExpose({
|
||||||
redirect: redirectFn,
|
redirect: redirectFn,
|
||||||
selected,
|
selected,
|
||||||
CrudModelRef,
|
CrudModelRef,
|
||||||
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleOnDataSaved(_, res) {
|
function handleOnDataSaved(_, res) {
|
||||||
|
@ -320,6 +331,13 @@ function handleOnDataSaved(_, res) {
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
:redirect="!!redirect"
|
:redirect="!!redirect"
|
||||||
@set-user-params="setUserParams"
|
@set-user-params="setUserParams"
|
||||||
|
:disable-submit-event="true"
|
||||||
|
@remove="
|
||||||
|
(key) =>
|
||||||
|
tableFilterRef
|
||||||
|
.find((f) => f.props?.column.name == key)
|
||||||
|
?.addFilter()
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<template #body>
|
<template #body>
|
||||||
<div
|
<div
|
||||||
|
@ -330,6 +348,7 @@ function handleOnDataSaved(_, res) {
|
||||||
:key="col.id"
|
:key="col.id"
|
||||||
>
|
>
|
||||||
<VnTableFilter
|
<VnTableFilter
|
||||||
|
ref="tableFilterRef"
|
||||||
:column="col"
|
:column="col"
|
||||||
:data-key="$attrs['data-key']"
|
:data-key="$attrs['data-key']"
|
||||||
v-model="params[columnName(col)]"
|
v-model="params[columnName(col)]"
|
||||||
|
@ -353,21 +372,25 @@ function handleOnDataSaved(_, res) {
|
||||||
:columns="splittedColumns.columns"
|
:columns="splittedColumns.columns"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
<template #tags="{ tag, formatFn }" v-if="chipLocale">
|
||||||
|
<div class="q-gutter-x-xs">
|
||||||
|
<strong>{{ t(`${chipLocale}.${tag.label}`) }}: </strong>
|
||||||
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</VnFilterPanel>
|
</VnFilterPanel>
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
<!-- class in div to fix warn-->
|
|
||||||
|
|
||||||
<CrudModel
|
<CrudModel
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:class="$attrs['class'] ?? 'q-px-md'"
|
:class="$attrs['class'] ?? 'q-px-md'"
|
||||||
:limit="20"
|
:limit="$attrs['limit'] ?? 20"
|
||||||
ref="CrudModelRef"
|
ref="CrudModelRef"
|
||||||
@on-fetch="(...args) => emit('onFetch', ...args)"
|
@on-fetch="(...args) => emit('onFetch', ...args)"
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
:disable-infinite-scroll="isTableMode"
|
:disable-infinite-scroll="isTableMode"
|
||||||
@save-changes="reload"
|
@save-changes="reload"
|
||||||
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
:has-sub-toolbar="$props.hasSubToolbar ?? isEditable"
|
||||||
:auto-load="hasParams || $attrs['auto-load']"
|
:auto-load="hasParams || $attrs['auto-load']"
|
||||||
>
|
>
|
||||||
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
||||||
|
@ -385,7 +408,7 @@ function handleOnDataSaved(_, res) {
|
||||||
card-container-class="grid-three"
|
card-container-class="grid-three"
|
||||||
flat
|
flat
|
||||||
:style="isTableMode && `max-height: ${tableHeight}`"
|
:style="isTableMode && `max-height: ${tableHeight}`"
|
||||||
virtual-scroll
|
:virtual-scroll="isTableMode"
|
||||||
@virtual-scroll="
|
@virtual-scroll="
|
||||||
(event) =>
|
(event) =>
|
||||||
event.index > rows.length - 2 &&
|
event.index > rows.length - 2 &&
|
||||||
|
@ -631,6 +654,20 @@ function handleOnDataSaved(_, res) {
|
||||||
</QCard>
|
</QCard>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
|
<template #bottom-row="{ cols }" v-if="footer">
|
||||||
|
<QTr v-if="rows.length" class="bg-header" style="height: 30px">
|
||||||
|
<QTh
|
||||||
|
v-for="col of cols.filter((cols) => cols.visible ?? true)"
|
||||||
|
:key="col?.id"
|
||||||
|
class="text-center"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
:name="`column-footer-${col.name}`"
|
||||||
|
:class="getColAlign(col)"
|
||||||
|
/>
|
||||||
|
</QTh>
|
||||||
|
</QTr>
|
||||||
|
</template>
|
||||||
</QTable>
|
</QTable>
|
||||||
</template>
|
</template>
|
||||||
</CrudModel>
|
</CrudModel>
|
||||||
|
@ -698,7 +735,7 @@ es:
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-header {
|
.bg-header {
|
||||||
background-color: var(--vn-header-color);
|
background-color: var(--vn-accent-color);
|
||||||
color: var(--vn-text-color);
|
color: var(--vn-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,9 +745,7 @@ es:
|
||||||
|
|
||||||
.q-table--dark .q-table__bottom,
|
.q-table--dark .q-table__bottom,
|
||||||
.q-table--dark thead,
|
.q-table--dark thead,
|
||||||
.q-table--dark tr,
|
.q-table--dark tr {
|
||||||
.q-table--dark th,
|
|
||||||
.q-table--dark td {
|
|
||||||
border-color: var(--vn-section-color);
|
border-color: var(--vn-section-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,6 +799,10 @@ es:
|
||||||
thead tr:first-child th {
|
thead tr:first-child th {
|
||||||
top: 0;
|
top: 0;
|
||||||
}
|
}
|
||||||
|
.q-table__top {
|
||||||
|
top: 0;
|
||||||
|
padding: 12px 0;
|
||||||
|
}
|
||||||
tbody {
|
tbody {
|
||||||
.q-checkbox {
|
.q-checkbox {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -17,17 +17,15 @@ const $props = defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let mixed;
|
|
||||||
const componentArray = computed(() => {
|
const componentArray = computed(() => {
|
||||||
if (typeof $props.prop === 'object') return [$props.prop];
|
if (typeof $props.prop === 'object') return [$props.prop];
|
||||||
return $props.prop;
|
return $props.prop;
|
||||||
});
|
});
|
||||||
|
|
||||||
function mix(toComponent) {
|
function mix(toComponent) {
|
||||||
if (mixed) return mixed;
|
|
||||||
const { component, attrs, event } = toComponent;
|
const { component, attrs, event } = toComponent;
|
||||||
const customComponent = $props.components[component];
|
const customComponent = $props.components[component];
|
||||||
mixed = {
|
return {
|
||||||
component: customComponent?.component ?? component,
|
component: customComponent?.component ?? component,
|
||||||
attrs: {
|
attrs: {
|
||||||
...toValueAttrs(attrs),
|
...toValueAttrs(attrs),
|
||||||
|
@ -37,7 +35,6 @@ function mix(toComponent) {
|
||||||
},
|
},
|
||||||
event: { ...customComponent?.event, ...event },
|
event: { ...customComponent?.event, ...event },
|
||||||
};
|
};
|
||||||
return mixed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toValueAttrs(attrs) {
|
function toValueAttrs(attrs) {
|
||||||
|
|
|
@ -5,12 +5,14 @@ import { useRoute } from 'vue-router';
|
||||||
import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar';
|
import { useQuasar, QCheckbox, QBtn, QInput } from 'quasar';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import VnUserLink from '../ui/VnUserLink.vue';
|
||||||
|
import { downloadFile } from 'src/composables/downloadFile';
|
||||||
|
import VnImg from 'components/ui/VnImg.vue';
|
||||||
import VnPaginate from 'components/ui/VnPaginate.vue';
|
import VnPaginate from 'components/ui/VnPaginate.vue';
|
||||||
import VnDms from 'src/components/common/VnDms.vue';
|
import VnDms from 'src/components/common/VnDms.vue';
|
||||||
import VnConfirm from 'components/ui/VnConfirm.vue';
|
import VnConfirm from 'components/ui/VnConfirm.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
import VnUserLink from '../ui/VnUserLink.vue';
|
import { useSession } from 'src/composables/useSession';
|
||||||
import { downloadFile } from 'src/composables/downloadFile';
|
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
@ -18,6 +20,7 @@ const { t } = useI18n();
|
||||||
const rows = ref();
|
const rows = ref();
|
||||||
const dmsRef = ref();
|
const dmsRef = ref();
|
||||||
const formDialog = ref({});
|
const formDialog = ref({});
|
||||||
|
const token = useSession().getTokenMultimedia();
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
model: {
|
model: {
|
||||||
|
@ -89,6 +92,23 @@ const dmsFilter = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: '',
|
||||||
|
name: 'file',
|
||||||
|
align: 'left',
|
||||||
|
component: VnImg,
|
||||||
|
props: (prop) => {
|
||||||
|
return {
|
||||||
|
storage: 'dms',
|
||||||
|
collection: null,
|
||||||
|
resolution: null,
|
||||||
|
id: prop.row.file.split('.')[0],
|
||||||
|
token: token,
|
||||||
|
class: 'rounded',
|
||||||
|
ratio: 1,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'id',
|
field: 'id',
|
||||||
|
@ -142,13 +162,6 @@ const columns = computed(() => [
|
||||||
'model-value': Boolean(prop.value),
|
'model-value': Boolean(prop.value),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
{
|
|
||||||
align: 'left',
|
|
||||||
field: 'file',
|
|
||||||
label: t('globals.file'),
|
|
||||||
name: 'file',
|
|
||||||
component: 'span',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'worker',
|
field: 'worker',
|
||||||
|
@ -387,7 +400,14 @@ defineExpose({
|
||||||
/>
|
/>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<QBtn fab color="primary" icon="add" @click="showFormDialog()" class="fill-icon">
|
<QBtn
|
||||||
|
fab
|
||||||
|
color="primary"
|
||||||
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
|
@click="showFormDialog()"
|
||||||
|
class="fill-icon"
|
||||||
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Upload file') }}
|
{{ t('Upload file') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
|
@ -395,10 +415,6 @@ defineExpose({
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.q-gutter-y-ms {
|
|
||||||
display: grid;
|
|
||||||
row-gap: 20px;
|
|
||||||
}
|
|
||||||
.labelColor {
|
.labelColor {
|
||||||
color: var(--vn-label-color);
|
color: var(--vn-label-color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,9 +67,13 @@ const mixinRules = [
|
||||||
requiredFieldRule,
|
requiredFieldRule,
|
||||||
...($attrs.rules ?? []),
|
...($attrs.rules ?? []),
|
||||||
(val) => {
|
(val) => {
|
||||||
const { min } = vnInputRef.value.$attrs;
|
const { min, max } = vnInputRef.value.$attrs;
|
||||||
if (!min) return null;
|
if (!min) return null;
|
||||||
if (min >= 0) if (Math.floor(val) < min) return t('inputMin', { value: min });
|
if (min >= 0) if (Math.floor(val) < min) return t('inputMin', { value: min });
|
||||||
|
if (!max) return null;
|
||||||
|
if (max > 0) {
|
||||||
|
if (Math.floor(val) > max) return t('inputMax', { value: max });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
@ -116,8 +120,10 @@ const mixinRules = [
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
inputMin: Must be more than {value}
|
inputMin: Must be more than {value}
|
||||||
|
inputMax: Must be less than {value}
|
||||||
es:
|
es:
|
||||||
inputMin: Debe ser mayor a {value}
|
inputMin: Debe ser mayor a {value}
|
||||||
|
inputMax: Debe ser menor a {value}
|
||||||
</i18n>
|
</i18n>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.q-field__append {
|
.q-field__append {
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { onMounted, watch, computed, ref } from 'vue';
|
import { onMounted, watch, computed, ref } from 'vue';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { useAttrs } from 'vue';
|
||||||
|
|
||||||
const model = defineModel({ type: [String, Date] });
|
const model = defineModel({ type: [String, Date] });
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -14,29 +15,19 @@ const $props = defineProps({
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
const { validations } = useValidator();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
|
const requiredFieldRule = (val) => validations().required($attrs.required, val);
|
||||||
|
|
||||||
const dateFormat = 'DD/MM/YYYY';
|
const dateFormat = 'DD/MM/YYYY';
|
||||||
const isPopupOpen = ref();
|
const isPopupOpen = ref();
|
||||||
const hover = ref();
|
const hover = ref();
|
||||||
const mask = ref();
|
const mask = ref();
|
||||||
|
const $attrs = useAttrs();
|
||||||
|
|
||||||
onMounted(() => {
|
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
|
||||||
// fix quasar bug
|
|
||||||
mask.value = '##/##/####';
|
|
||||||
});
|
|
||||||
|
|
||||||
const styleAttrs = computed(() => {
|
|
||||||
return $props.isOutlined
|
|
||||||
? {
|
|
||||||
dense: true,
|
|
||||||
outlined: true,
|
|
||||||
rounded: true,
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
});
|
|
||||||
|
|
||||||
const formattedDate = computed({
|
const formattedDate = computed({
|
||||||
get() {
|
get() {
|
||||||
|
@ -48,15 +39,12 @@ const formattedDate = computed({
|
||||||
let newDate;
|
let newDate;
|
||||||
if (value) {
|
if (value) {
|
||||||
// parse input
|
// parse input
|
||||||
if (value.includes('/')) {
|
if (value.includes('/') && value.length >= 10) {
|
||||||
if (value.length == 6) value = value + new Date().getFullYear();
|
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
|
||||||
if (value.length >= 10) {
|
value = date.formatDate(
|
||||||
if (value.at(2) == '/') value = value.split('/').reverse().join('/');
|
new Date(value).toISOString(),
|
||||||
value = date.formatDate(
|
'YYYY-MM-DDTHH:mm:ss.SSSZ'
|
||||||
new Date(value).toISOString(),
|
);
|
||||||
'YYYY-MM-DDTHH:mm:ss.SSSZ'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const [year, month, day] = value.split('-').map((e) => parseInt(e));
|
const [year, month, day] = value.split('-').map((e) => parseInt(e));
|
||||||
newDate = new Date(year, month - 1, day);
|
newDate = new Date(year, month - 1, day);
|
||||||
|
@ -79,12 +67,25 @@ const formattedDate = computed({
|
||||||
const popupDate = computed(() =>
|
const popupDate = computed(() =>
|
||||||
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value
|
model.value ? date.formatDate(new Date(model.value), 'YYYY/MM/DD') : model.value
|
||||||
);
|
);
|
||||||
|
onMounted(() => {
|
||||||
|
// fix quasar bug
|
||||||
|
mask.value = '##/##/####';
|
||||||
|
});
|
||||||
watch(
|
watch(
|
||||||
() => model.value,
|
() => model.value,
|
||||||
(val) => (formattedDate.value = val),
|
(val) => (formattedDate.value = val),
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const styleAttrs = computed(() => {
|
||||||
|
return $props.isOutlined
|
||||||
|
? {
|
||||||
|
dense: true,
|
||||||
|
outlined: true,
|
||||||
|
rounded: true,
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -96,9 +97,10 @@ watch(
|
||||||
placeholder="dd/mm/aaaa"
|
placeholder="dd/mm/aaaa"
|
||||||
v-bind="{ ...$attrs, ...styleAttrs }"
|
v-bind="{ ...$attrs, ...styleAttrs }"
|
||||||
:class="{ required: $attrs.required }"
|
:class="{ required: $attrs.required }"
|
||||||
:rules="$attrs.required ? [requiredFieldRule] : null"
|
:rules="mixinRules"
|
||||||
:clearable="false"
|
:clearable="false"
|
||||||
@click="isPopupOpen = true"
|
@click="isPopupOpen = true"
|
||||||
|
hide-bottom-space
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref, useAttrs } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
const { validations } = useValidator();
|
||||||
|
const $attrs = useAttrs();
|
||||||
const model = defineModel({ type: String });
|
const model = defineModel({ type: String });
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
timeOnly: {
|
timeOnly: {
|
||||||
|
@ -16,8 +18,8 @@ const props = defineProps({
|
||||||
});
|
});
|
||||||
const initialDate = ref(model.value ?? Date.vnNew());
|
const initialDate = ref(model.value ?? Date.vnNew());
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
|
const requiredFieldRule = (val) => validations().required($attrs.required, val);
|
||||||
|
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
|
||||||
const dateFormat = 'HH:mm';
|
const dateFormat = 'HH:mm';
|
||||||
const isPopupOpen = ref();
|
const isPopupOpen = ref();
|
||||||
const hover = ref();
|
const hover = ref();
|
||||||
|
@ -74,9 +76,10 @@ function dateToTime(newDate) {
|
||||||
v-bind="{ ...$attrs, ...styleAttrs }"
|
v-bind="{ ...$attrs, ...styleAttrs }"
|
||||||
:class="{ required: $attrs.required }"
|
:class="{ required: $attrs.required }"
|
||||||
style="min-width: 100px"
|
style="min-width: 100px"
|
||||||
:rules="$attrs.required ? [requiredFieldRule] : null"
|
:rules="mixinRules"
|
||||||
@click="isPopupOpen = false"
|
@click="isPopupOpen = false"
|
||||||
type="time"
|
type="time"
|
||||||
|
hide-bottom-space
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import LeftMenu from 'components/LeftMenu.vue';
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -10,7 +11,9 @@ const $props = defineProps({
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
onMounted(() => (stateStore.leftDrawer = $props.leftDrawer));
|
onMounted(
|
||||||
|
() => (stateStore.leftDrawer = useQuasar().screen.gt.xs ? $props.leftDrawer : false)
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, toRefs, computed, watch, onMounted } from 'vue';
|
import { ref, toRefs, computed, watch, onMounted, useAttrs } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
|
const emit = defineEmits(['update:modelValue', 'update:options', 'remove']);
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
|
@ -37,6 +38,10 @@ const $props = defineProps({
|
||||||
type: [Array],
|
type: [Array],
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
exprBuilder: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
isClearable: {
|
isClearable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
@ -82,10 +87,11 @@ const $props = defineProps({
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const { validations } = useValidator();
|
||||||
|
const requiredFieldRule = (val) => validations().required($attrs.required, val);
|
||||||
|
const $attrs = useAttrs();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const requiredFieldRule = (val) => val ?? t('globals.fieldRequired');
|
const mixinRules = [requiredFieldRule, ...($attrs.rules ?? [])];
|
||||||
|
|
||||||
const { optionLabel, optionValue, optionFilter, optionFilterValue, options, modelValue } =
|
const { optionLabel, optionValue, optionFilter, optionFilterValue, options, modelValue } =
|
||||||
toRefs($props);
|
toRefs($props);
|
||||||
const myOptions = ref([]);
|
const myOptions = ref([]);
|
||||||
|
@ -177,6 +183,7 @@ async function fetchFilter(val) {
|
||||||
}, {});
|
}, {});
|
||||||
} else defaultWhere = { [key]: getVal(val) };
|
} else defaultWhere = { [key]: getVal(val) };
|
||||||
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
||||||
|
$props.exprBuilder && Object.assign(where, $props.exprBuilder(key, val));
|
||||||
const fetchOptions = { where, include, limit };
|
const fetchOptions = { where, include, limit };
|
||||||
if (fields) fetchOptions.fields = fields;
|
if (fields) fetchOptions.fields = fields;
|
||||||
if (sortBy) fetchOptions.order = sortBy;
|
if (sortBy) fetchOptions.order = sortBy;
|
||||||
|
@ -248,8 +255,9 @@ const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
|
||||||
ref="vnSelectRef"
|
ref="vnSelectRef"
|
||||||
lazy-rules
|
lazy-rules
|
||||||
:class="{ required: $attrs.required }"
|
:class="{ required: $attrs.required }"
|
||||||
:rules="$attrs.required ? [requiredFieldRule] : null"
|
:rules="mixinRules"
|
||||||
virtual-scroll-slice-size="options.length"
|
virtual-scroll-slice-size="options.length"
|
||||||
|
hide-bottom-space
|
||||||
>
|
>
|
||||||
<template v-if="isClearable" #append>
|
<template v-if="isClearable" #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useRole } from 'src/composables/useRole';
|
import { useRole } from 'src/composables/useRole';
|
||||||
|
import { useAcl } from 'src/composables/useAcl';
|
||||||
|
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
const emit = defineEmits(['update:modelValue']);
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
@ -11,6 +12,10 @@ const $props = defineProps({
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => ['developer'],
|
default: () => ['developer'],
|
||||||
},
|
},
|
||||||
|
acls: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
actionIcon: {
|
actionIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'add',
|
default: 'add',
|
||||||
|
@ -22,15 +27,12 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
const role = useRole();
|
const role = useRole();
|
||||||
const showForm = ref(false);
|
const acl = useAcl();
|
||||||
|
|
||||||
const isAllowedToCreate = computed(() => {
|
const isAllowedToCreate = computed(() => {
|
||||||
|
if ($props.acls.length) return acl.hasAny($props.acls);
|
||||||
return role.hasAny($props.rolesAllowedToCreate);
|
return role.hasAny($props.rolesAllowedToCreate);
|
||||||
});
|
});
|
||||||
|
|
||||||
const toggleForm = () => {
|
|
||||||
showForm.value = !showForm.value;
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -41,7 +43,7 @@ const toggleForm = () => {
|
||||||
>
|
>
|
||||||
<template v-if="isAllowedToCreate" #append>
|
<template v-if="isAllowedToCreate" #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
@click.stop.prevent="toggleForm()"
|
@click.stop.prevent="$refs.dialog.show()"
|
||||||
:name="actionIcon"
|
:name="actionIcon"
|
||||||
:size="actionIcon === 'add' ? 'xs' : 'sm'"
|
:size="actionIcon === 'add' ? 'xs' : 'sm'"
|
||||||
:class="['default-icon', { '--add-icon': actionIcon === 'add' }]"
|
:class="['default-icon', { '--add-icon': actionIcon === 'add' }]"
|
||||||
|
@ -51,7 +53,7 @@ const toggleForm = () => {
|
||||||
>
|
>
|
||||||
<QTooltip v-if="tooltip">{{ tooltip }}</QTooltip>
|
<QTooltip v-if="tooltip">{{ tooltip }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QDialog v-model="showForm" transition-show="scale" transition-hide="scale">
|
<QDialog ref="dialog" transition-show="scale" transition-hide="scale">
|
||||||
<slot name="form" />
|
<slot name="form" />
|
||||||
</QDialog>
|
</QDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
<script setup>
|
||||||
|
import { onBeforeMount, ref, useAttrs } from 'vue';
|
||||||
|
import axios from 'axios';
|
||||||
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
|
||||||
|
const { schema, table, column, translation, defaultOptions } = defineProps({
|
||||||
|
schema: {
|
||||||
|
type: String,
|
||||||
|
default: 'vn',
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
translation: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
defaultOptions: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const $attrs = useAttrs();
|
||||||
|
const options = ref([]);
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
options.value = [].concat(defaultOptions);
|
||||||
|
const { data } = await axios.get(`Applications/get-enum-values`, {
|
||||||
|
params: { schema, table, column },
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const value of data)
|
||||||
|
options.value.push({
|
||||||
|
[$attrs['option-value'] ?? 'id']: value,
|
||||||
|
[$attrs['option-label'] ?? 'name']: translation ? translation(value) : value,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VnSelect
|
||||||
|
v-bind="$attrs"
|
||||||
|
:options="options"
|
||||||
|
:key="options.length"
|
||||||
|
:input-debounce="0"
|
||||||
|
/>
|
||||||
|
</template>
|
|
@ -127,11 +127,6 @@ const dialog = ref(null);
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
|
|
||||||
.subName {
|
|
||||||
color: var(--vn-label-color);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ const props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||||
|
defineExpose({ show: () => dialogRef.value.show(), hide: () => dialogRef.value.hide() });
|
||||||
|
|
||||||
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
||||||
|
|
||||||
|
@ -68,8 +69,10 @@ async function confirm() {
|
||||||
<QSpace />
|
<QSpace />
|
||||||
<QBtn icon="close" :disable="isLoading" flat round dense v-close-popup />
|
<QBtn icon="close" :disable="isLoading" flat round dense v-close-popup />
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection class="row items-center">
|
<QCardSection class="q-pb-none">
|
||||||
<span v-if="message !== false" v-html="message" />
|
<span v-if="message !== false" v-html="message" />
|
||||||
|
</QCardSection>
|
||||||
|
<QCardSection class="row items-center q-pt-none">
|
||||||
<slot name="customHTML"></slot>
|
<slot name="customHTML"></slot>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardActions align="right">
|
<QCardActions align="right">
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { onMounted, ref, computed, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useArrayData } from 'composables/useArrayData';
|
import { useArrayData } from 'composables/useArrayData';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
import { date } from 'quasar';
|
||||||
import toDate from 'filters/toDate';
|
import toDate from 'filters/toDate';
|
||||||
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
import VnFilterPanelChip from 'components/ui/VnFilterPanelChip.vue';
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ const $props = defineProps({
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({ search, sanitizer });
|
defineExpose({ search, sanitizer });
|
||||||
|
|
||||||
const emit = defineEmits([
|
const emit = defineEmits([
|
||||||
'update:modelValue',
|
'update:modelValue',
|
||||||
'refresh',
|
'refresh',
|
||||||
|
@ -112,9 +114,9 @@ watch(
|
||||||
);
|
);
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
async function search(evt) {
|
async function search() {
|
||||||
try {
|
try {
|
||||||
if (evt && $props.disableSubmitEvent) return;
|
if ($props.disableSubmitEvent) return;
|
||||||
|
|
||||||
store.filter.where = {};
|
store.filter.where = {};
|
||||||
isLoading.value = true;
|
isLoading.value = true;
|
||||||
|
@ -165,7 +167,7 @@ const tagsList = computed(() => {
|
||||||
for (const key of Object.keys(userParams.value)) {
|
for (const key of Object.keys(userParams.value)) {
|
||||||
const value = userParams.value[key];
|
const value = userParams.value[key];
|
||||||
if (value == null || ($props.hiddenTags || []).includes(key)) continue;
|
if (value == null || ($props.hiddenTags || []).includes(key)) continue;
|
||||||
tagList.push({ label: key, value });
|
tagList.push({ label: aliasField(key), value });
|
||||||
}
|
}
|
||||||
return tagList;
|
return tagList;
|
||||||
});
|
});
|
||||||
|
@ -185,6 +187,7 @@ async function remove(key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatValue(value) {
|
function formatValue(value) {
|
||||||
|
if (value instanceof Date) return date.formatDate(value, 'DD/MM/YYYY');
|
||||||
if (typeof value === 'boolean') return value ? t('Yes') : t('No');
|
if (typeof value === 'boolean') return value ? t('Yes') : t('No');
|
||||||
if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);
|
if (isNaN(value) && !isNaN(Date.parse(value))) return toDate(value);
|
||||||
|
|
||||||
|
@ -200,6 +203,11 @@ function sanitizer(params) {
|
||||||
}
|
}
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function aliasField(field) {
|
||||||
|
const split = field.split('.');
|
||||||
|
return split[1] ?? split[0];
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -39,6 +39,8 @@ const getUrl = (zoom = false) => {
|
||||||
const curResolution = zoom
|
const curResolution = zoom
|
||||||
? $props.zoomResolution || $props.resolution
|
? $props.zoomResolution || $props.resolution
|
||||||
: $props.resolution;
|
: $props.resolution;
|
||||||
|
if ($props.storage === 'dms')
|
||||||
|
return `/api/${$props.storage}/${$props.id}/downloadFile?access_token=${token}`;
|
||||||
return isEmployee
|
return isEmployee
|
||||||
? `/api/${$props.storage}/${$props.collection}/${curResolution}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
|
? `/api/${$props.storage}/${$props.collection}/${curResolution}/${$props.id}/download?access_token=${token}&${timeStamp.value}`
|
||||||
: noImage;
|
: noImage;
|
||||||
|
@ -52,6 +54,7 @@ defineExpose({
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<QImg
|
<QImg
|
||||||
|
:draggable="true"
|
||||||
:class="{ zoomIn: zoom }"
|
:class="{ zoomIn: zoom }"
|
||||||
:src="getUrl()"
|
:src="getUrl()"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
|
@ -60,10 +63,12 @@ defineExpose({
|
||||||
/>
|
/>
|
||||||
<QDialog v-if="$props.zoom" v-model="show">
|
<QDialog v-if="$props.zoom" v-model="show">
|
||||||
<QImg
|
<QImg
|
||||||
|
:draggable="true"
|
||||||
:src="getUrl(true)"
|
:src="getUrl(true)"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
spinner-color="primary"
|
spinner-color="primary"
|
||||||
class="img_zoom"
|
class="img_zoom"
|
||||||
|
:ratio="0"
|
||||||
/>
|
/>
|
||||||
</QDialog>
|
</QDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -122,7 +122,6 @@ watch(
|
||||||
() => [props.url, props.filter],
|
() => [props.url, props.filter],
|
||||||
([url, filter]) => mounted.value && fetch({ url, filter })
|
([url, filter]) => mounted.value && fetch({ url, filter })
|
||||||
);
|
);
|
||||||
|
|
||||||
const addFilter = async (filter, params) => {
|
const addFilter = async (filter, params) => {
|
||||||
await arrayData.addFilter({ filter, params });
|
await arrayData.addFilter({ filter, params });
|
||||||
};
|
};
|
||||||
|
@ -131,9 +130,8 @@ async function fetch(params) {
|
||||||
useArrayData(props.dataKey, params);
|
useArrayData(props.dataKey, params);
|
||||||
arrayData.reset(['filter.skip', 'skip']);
|
arrayData.reset(['filter.skip', 'skip']);
|
||||||
await arrayData.fetch({ append: false });
|
await arrayData.fetch({ append: false });
|
||||||
if (!store.hasMoreData) {
|
if (!store.hasMoreData) isLoading.value = false;
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
emit('onFetch', store.data);
|
emit('onFetch', store.data);
|
||||||
return store.data;
|
return store.data;
|
||||||
}
|
}
|
||||||
|
@ -224,13 +222,20 @@ defineExpose({ fetch, addFilter, paginate });
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
<slot name="body" :rows="store.data"></slot>
|
<slot name="body" :rows="store.data"></slot>
|
||||||
<div v-if="isLoading" class="info-row q-pa-md text-center">
|
<div v-if="isLoading" class="spinner info-row q-pa-md text-center">
|
||||||
<QSpinner color="primary" size="md" />
|
<QSpinner color="primary" size="md" />
|
||||||
</div>
|
</div>
|
||||||
</QInfiniteScroll>
|
</QInfiniteScroll>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.spinner {
|
||||||
|
z-index: 1;
|
||||||
|
align-content: end;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
.info-row {
|
.info-row {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
const $props = defineProps({
|
defineProps({
|
||||||
name: { type: String, default: null },
|
name: { type: String, default: null },
|
||||||
|
tag: { type: String, default: null },
|
||||||
workerId: { type: Number, default: null },
|
workerId: { type: Number, default: null },
|
||||||
defaultName: { type: Boolean, default: false },
|
defaultName: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<slot name="link">
|
<slot name="link">
|
||||||
<span :class="{ link: $props.workerId }">
|
<span :class="{ link: workerId }">
|
||||||
{{ $props.defaultName ? $props.name ?? t('globals.system') : $props.name }}
|
{{ defaultName ? name ?? $t('globals.system') : name }}
|
||||||
</span>
|
</span>
|
||||||
</slot>
|
</slot>
|
||||||
<WorkerDescriptorProxy v-if="$props.workerId" :id="$props.workerId" />
|
<WorkerDescriptorProxy v-if="workerId" :id="workerId" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -16,13 +16,18 @@ export function useAcl() {
|
||||||
state.setAcls(acls);
|
state.setAcls(acls);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasAny(model, prop, accessType) {
|
function hasAny(acls) {
|
||||||
const acls = state.getAcls().value[model];
|
for (const acl of acls) {
|
||||||
if (acls)
|
let { model, props, accessType } = acl;
|
||||||
return ['*', prop].some((key) => {
|
const modelAcls = state.getAcls().value[model];
|
||||||
const acl = acls[key];
|
Array.isArray(props) || (props = [props]);
|
||||||
return acl && (acl['*'] || acl[accessType]);
|
if (modelAcls)
|
||||||
});
|
return ['*', ...props].some((key) => {
|
||||||
|
const acl = modelAcls[key];
|
||||||
|
return acl && (acl['*'] || acl[accessType]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -26,7 +26,8 @@ export function useArrayData(key = useRoute().meta.moduleName, userOptions) {
|
||||||
const params = JSON.parse(query[searchUrl]);
|
const params = JSON.parse(query[searchUrl]);
|
||||||
const filter = params?.filter && JSON.parse(params?.filter ?? '{}');
|
const filter = params?.filter && JSON.parse(params?.filter ?? '{}');
|
||||||
delete params.filter;
|
delete params.filter;
|
||||||
store.userParams = { ...params, ...store.userParams };
|
|
||||||
|
store.userParams = { ...store.userParams, ...params };
|
||||||
store.userFilter = { ...filter, ...store.userFilter };
|
store.userFilter = { ...filter, ...store.userFilter };
|
||||||
if (filter?.order) store.order = filter.order;
|
if (filter?.order) store.order = filter.order;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
import { useSession } from './useSession';
|
import { useSession } from './useSession';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
export function usePrintService() {
|
export function usePrintService() {
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const { getTokenMultimedia } = useSession();
|
const { getTokenMultimedia } = useSession();
|
||||||
|
|
||||||
function sendEmail(path, params) {
|
function sendEmail(path, params) {
|
||||||
return axios.post(path, params).then(() =>
|
return axios.post(path, params).then(() =>
|
||||||
quasar.notify({
|
quasar.notify({
|
||||||
message: 'Notification sent',
|
message: t('globals.notificationSent'),
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
icon: 'check',
|
icon: 'check',
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openReport(path, params) {
|
function openReport(path, params, isNewTab = '_self') {
|
||||||
|
if (typeof params === 'string') params = JSON.parse(params);
|
||||||
params = Object.assign(
|
params = Object.assign(
|
||||||
{
|
{
|
||||||
access_token: getTokenMultimedia(),
|
access_token: getTokenMultimedia(),
|
||||||
|
@ -25,8 +29,7 @@ export function usePrintService() {
|
||||||
);
|
);
|
||||||
|
|
||||||
const query = new URLSearchParams(params).toString();
|
const query = new URLSearchParams(params).toString();
|
||||||
|
window.open(`api/${path}?${query}`, isNewTab);
|
||||||
window.open(`api/${path}?${query}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -37,6 +37,10 @@ a {
|
||||||
.link {
|
.link {
|
||||||
color: $color-link;
|
color: $color-link;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
&--white {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tx-color-link {
|
.tx-color-link {
|
||||||
|
@ -264,6 +268,7 @@ input::-webkit-inner-spin-button {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-photo-btn {
|
.edit-photo-btn {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 12px;
|
right: 12px;
|
||||||
|
@ -271,3 +276,15 @@ input::-webkit-inner-spin-button {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.subName {
|
||||||
|
color: var(--vn-label-color);
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.q-date {
|
||||||
|
&__today {
|
||||||
|
border: 2px solid $info;
|
||||||
|
color: $info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ $color-font-secondary: #777;
|
||||||
.bg-success {
|
.bg-success {
|
||||||
background-color: $positive;
|
background-color: $positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bg-notice {
|
.bg-notice {
|
||||||
background-color: $info;
|
background-color: $info;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ globals:
|
||||||
lang:
|
lang:
|
||||||
es: Spanish
|
es: Spanish
|
||||||
en: English
|
en: English
|
||||||
|
quantity: Quantity
|
||||||
language: Language
|
language: Language
|
||||||
entity: Entity
|
entity: Entity
|
||||||
user: User
|
user: User
|
||||||
|
@ -98,8 +99,14 @@ globals:
|
||||||
to: To
|
to: To
|
||||||
notes: Notes
|
notes: Notes
|
||||||
refresh: Refresh
|
refresh: Refresh
|
||||||
|
item: Item
|
||||||
|
ticket: Ticket
|
||||||
|
campaign: Campaign
|
||||||
|
weight: Weight
|
||||||
|
error: Ups! Something went wrong
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Login
|
logIn: Login
|
||||||
|
addressEdit: Update address
|
||||||
summary: Summary
|
summary: Summary
|
||||||
basicData: Basic data
|
basicData: Basic data
|
||||||
log: Logs
|
log: Logs
|
||||||
|
@ -124,9 +131,11 @@ globals:
|
||||||
notifications: Notifications
|
notifications: Notifications
|
||||||
defaulter: Defaulter
|
defaulter: Defaulter
|
||||||
customerCreate: New customer
|
customerCreate: New customer
|
||||||
|
createOrder: New order
|
||||||
fiscalData: Fiscal data
|
fiscalData: Fiscal data
|
||||||
billingData: Billing data
|
billingData: Billing data
|
||||||
consignees: Consignees
|
consignees: Consignees
|
||||||
|
'address-create': New address
|
||||||
notes: Notes
|
notes: Notes
|
||||||
credits: Credits
|
credits: Credits
|
||||||
greuges: Greuges
|
greuges: Greuges
|
||||||
|
@ -150,6 +159,7 @@ globals:
|
||||||
dms: File management
|
dms: File management
|
||||||
entryCreate: New entry
|
entryCreate: New entry
|
||||||
latestBuys: Latest buys
|
latestBuys: Latest buys
|
||||||
|
reserves: Reserves
|
||||||
tickets: Tickets
|
tickets: Tickets
|
||||||
ticketCreate: New Tickets
|
ticketCreate: New Tickets
|
||||||
boxing: Boxing
|
boxing: Boxing
|
||||||
|
@ -322,135 +332,6 @@ resetPassword:
|
||||||
repeatPassword: Repeat password
|
repeatPassword: Repeat password
|
||||||
passwordNotMatch: Passwords don't match
|
passwordNotMatch: Passwords don't match
|
||||||
passwordChanged: Password changed
|
passwordChanged: Password changed
|
||||||
customer:
|
|
||||||
list:
|
|
||||||
phone: Phone
|
|
||||||
email: Email
|
|
||||||
customerOrders: Display customer orders
|
|
||||||
moreOptions: More options
|
|
||||||
card:
|
|
||||||
customerList: Customer list
|
|
||||||
customerId: Claim ID
|
|
||||||
salesPerson: Sales person
|
|
||||||
credit: Credit
|
|
||||||
risk: Risk
|
|
||||||
securedCredit: Secured credit
|
|
||||||
payMethod: Pay method
|
|
||||||
debt: Debt
|
|
||||||
isFrozen: Customer frozen
|
|
||||||
hasDebt: Customer has debt
|
|
||||||
isDisabled: Customer inactive
|
|
||||||
notChecked: Customer no checked
|
|
||||||
webAccountInactive: Web account inactive
|
|
||||||
noWebAccess: Web access is disabled
|
|
||||||
businessType: Business type
|
|
||||||
passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
|
|
||||||
businessTypeFk: Business type
|
|
||||||
summary:
|
|
||||||
basicData: Basic data
|
|
||||||
fiscalAddress: Fiscal address
|
|
||||||
fiscalData: Fiscal data
|
|
||||||
billingData: Billing data
|
|
||||||
consignee: Default consignee
|
|
||||||
businessData: Business data
|
|
||||||
financialData: Financial data
|
|
||||||
customerId: Customer ID
|
|
||||||
name: Name
|
|
||||||
contact: Contact
|
|
||||||
phone: Phone
|
|
||||||
mobile: Mobile
|
|
||||||
email: Email
|
|
||||||
salesPerson: Sales person
|
|
||||||
contactChannel: Contact channel
|
|
||||||
socialName: Social name
|
|
||||||
fiscalId: Fiscal ID
|
|
||||||
postcode: Postcode
|
|
||||||
province: Province
|
|
||||||
country: Country
|
|
||||||
street: Address
|
|
||||||
isEqualizated: Is equalizated
|
|
||||||
isActive: Is active
|
|
||||||
invoiceByAddress: Invoice by address
|
|
||||||
verifiedData: Verified data
|
|
||||||
hasToInvoice: Has to invoice
|
|
||||||
notifyByEmail: Notify by email
|
|
||||||
vies: VIES
|
|
||||||
payMethod: Pay method
|
|
||||||
bankAccount: Bank account
|
|
||||||
dueDay: Due day
|
|
||||||
hasLcr: Has LCR
|
|
||||||
hasCoreVnl: Has core VNL
|
|
||||||
hasB2BVnl: Has B2B VNL
|
|
||||||
addressName: Address name
|
|
||||||
addressCity: City
|
|
||||||
addressStreet: Street
|
|
||||||
username: Username
|
|
||||||
webAccess: Web access
|
|
||||||
totalGreuge: Total greuge
|
|
||||||
mana: Mana
|
|
||||||
priceIncreasingRate: Price increasing rate
|
|
||||||
averageInvoiced: Average invoiced
|
|
||||||
claimRate: Claming rate
|
|
||||||
risk: Risk
|
|
||||||
riskInfo: Invoices minus payments plus orders not yet invoiced
|
|
||||||
credit: Credit
|
|
||||||
creditInfo: Company's maximum risk
|
|
||||||
securedCredit: Secured credit
|
|
||||||
securedCreditInfo: Solunion's maximum risk
|
|
||||||
balance: Balance
|
|
||||||
balanceInfo: Invoices minus payments
|
|
||||||
balanceDue: Balance due
|
|
||||||
balanceDueInfo: Deviated invoices minus payments
|
|
||||||
recoverySince: Recovery since
|
|
||||||
businessType: Business Type
|
|
||||||
city: City
|
|
||||||
descriptorInfo: Invoices minus payments plus orders not yet
|
|
||||||
rating: Rating
|
|
||||||
recommendCredit: Recommended credit
|
|
||||||
basicData:
|
|
||||||
socialName: Fiscal name
|
|
||||||
businessType: Business type
|
|
||||||
contact: Contact
|
|
||||||
youCanSaveMultipleEmails: You can save multiple emails
|
|
||||||
email: Email
|
|
||||||
phone: Phone
|
|
||||||
mobile: Mobile
|
|
||||||
salesPerson: Sales person
|
|
||||||
contactChannel: Contact channel
|
|
||||||
previousClient: Previous client
|
|
||||||
extendedList:
|
|
||||||
tableVisibleColumns:
|
|
||||||
id: Identifier
|
|
||||||
name: Name
|
|
||||||
socialName: Social name
|
|
||||||
fi: Tax number
|
|
||||||
salesPersonFk: Salesperson
|
|
||||||
credit: Credit
|
|
||||||
creditInsurance: Credit insurance
|
|
||||||
phone: Phone
|
|
||||||
mobile: Mobile
|
|
||||||
street: Street
|
|
||||||
countryFk: Country
|
|
||||||
provinceFk: Province
|
|
||||||
city: City
|
|
||||||
postcode: Postcode
|
|
||||||
email: Email
|
|
||||||
created: Created
|
|
||||||
businessTypeFk: Business type
|
|
||||||
payMethodFk: Billing data
|
|
||||||
sageTaxTypeFk: Sage tax type
|
|
||||||
sageTransactionTypeFk: Sage tr. type
|
|
||||||
isActive: Active
|
|
||||||
isVies: Vies
|
|
||||||
isTaxDataChecked: Verified data
|
|
||||||
isEqualizated: Is equalizated
|
|
||||||
isFreezed: Freezed
|
|
||||||
hasToInvoice: Invoice
|
|
||||||
hasToInvoiceByAddress: Invoice by address
|
|
||||||
isToBeMailed: Mailing
|
|
||||||
hasLcr: Received LCR
|
|
||||||
hasCoreVnl: VNL core received
|
|
||||||
hasSepaVnl: VNL B2B received
|
|
||||||
entry:
|
entry:
|
||||||
list:
|
list:
|
||||||
newEntry: New entry
|
newEntry: New entry
|
||||||
|
@ -939,6 +820,16 @@ worker:
|
||||||
credit: Have
|
credit: Have
|
||||||
concept: Concept
|
concept: Concept
|
||||||
wagon:
|
wagon:
|
||||||
|
pageTitles:
|
||||||
|
wagons: Wagons
|
||||||
|
wagonsList: Wagons List
|
||||||
|
wagonCreate: Create wagon
|
||||||
|
wagonEdit: Edit wagon
|
||||||
|
typesList: Types List
|
||||||
|
typeCreate: Create type
|
||||||
|
typeEdit: Edit type
|
||||||
|
wagonCounter: Trolley counter
|
||||||
|
wagonTray: Tray List
|
||||||
type:
|
type:
|
||||||
name: Name
|
name: Name
|
||||||
submit: Submit
|
submit: Submit
|
||||||
|
@ -1109,6 +1000,7 @@ travel:
|
||||||
warehouseOut: Warehouse out
|
warehouseOut: Warehouse out
|
||||||
totalEntries: Total entries
|
totalEntries: Total entries
|
||||||
totalEntriesTooltip: Total entries
|
totalEntriesTooltip: Total entries
|
||||||
|
daysOnward: Landed days onwards
|
||||||
summary:
|
summary:
|
||||||
confirmed: Confirmed
|
confirmed: Confirmed
|
||||||
entryId: Entry Id
|
entryId: Entry Id
|
||||||
|
|
|
@ -3,6 +3,7 @@ globals:
|
||||||
es: Español
|
es: Español
|
||||||
en: Inglés
|
en: Inglés
|
||||||
language: Idioma
|
language: Idioma
|
||||||
|
quantity: Cantidad
|
||||||
entity: Entidad
|
entity: Entidad
|
||||||
user: Usuario
|
user: Usuario
|
||||||
details: Detalles
|
details: Detalles
|
||||||
|
@ -100,8 +101,14 @@ globals:
|
||||||
to: Hasta
|
to: Hasta
|
||||||
notes: Notas
|
notes: Notas
|
||||||
refresh: Actualizar
|
refresh: Actualizar
|
||||||
|
item: Artículo
|
||||||
|
ticket: Ticket
|
||||||
|
campaign: Campaña
|
||||||
|
weight: Peso
|
||||||
|
error: ¡Ups! Algo salió mal
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Inicio de sesión
|
logIn: Inicio de sesión
|
||||||
|
addressEdit: Modificar consignatario
|
||||||
summary: Resumen
|
summary: Resumen
|
||||||
basicData: Datos básicos
|
basicData: Datos básicos
|
||||||
log: Historial
|
log: Historial
|
||||||
|
@ -121,6 +128,7 @@ globals:
|
||||||
inheritedRoles: Roles heredados
|
inheritedRoles: Roles heredados
|
||||||
customers: Clientes
|
customers: Clientes
|
||||||
customerCreate: Nuevo cliente
|
customerCreate: Nuevo cliente
|
||||||
|
createOrder: Nuevo pedido
|
||||||
list: Listado
|
list: Listado
|
||||||
webPayments: Pagos Web
|
webPayments: Pagos Web
|
||||||
extendedList: Listado extendido
|
extendedList: Listado extendido
|
||||||
|
@ -130,6 +138,7 @@ globals:
|
||||||
fiscalData: Datos fiscales
|
fiscalData: Datos fiscales
|
||||||
billingData: Forma de pago
|
billingData: Forma de pago
|
||||||
consignees: Consignatarios
|
consignees: Consignatarios
|
||||||
|
'address-create': Nuevo consignatario
|
||||||
notes: Notas
|
notes: Notas
|
||||||
credits: Créditos
|
credits: Créditos
|
||||||
greuges: Greuges
|
greuges: Greuges
|
||||||
|
@ -153,6 +162,7 @@ globals:
|
||||||
dms: Gestión documental
|
dms: Gestión documental
|
||||||
entryCreate: Nueva entrada
|
entryCreate: Nueva entrada
|
||||||
latestBuys: Últimas compras
|
latestBuys: Últimas compras
|
||||||
|
reserves: Reservas
|
||||||
tickets: Tickets
|
tickets: Tickets
|
||||||
ticketCreate: Nuevo ticket
|
ticketCreate: Nuevo ticket
|
||||||
boxing: Encajado
|
boxing: Encajado
|
||||||
|
@ -324,134 +334,6 @@ resetPassword:
|
||||||
repeatPassword: Repetir contraseña
|
repeatPassword: Repetir contraseña
|
||||||
passwordNotMatch: Las contraseñas no coinciden
|
passwordNotMatch: Las contraseñas no coinciden
|
||||||
passwordChanged: Contraseña cambiada
|
passwordChanged: Contraseña cambiada
|
||||||
customer:
|
|
||||||
list:
|
|
||||||
phone: Teléfono
|
|
||||||
email: Email
|
|
||||||
customerOrders: Mostrar órdenes del cliente
|
|
||||||
moreOptions: Más opciones
|
|
||||||
card:
|
|
||||||
customerId: ID cliente
|
|
||||||
salesPerson: Comercial
|
|
||||||
credit: Crédito
|
|
||||||
risk: Riesgo
|
|
||||||
securedCredit: Crédito asegurado
|
|
||||||
payMethod: Método de pago
|
|
||||||
debt: Riesgo
|
|
||||||
isFrozen: Cliente congelado
|
|
||||||
hasDebt: Cliente con riesgo
|
|
||||||
isDisabled: Cliente inactivo
|
|
||||||
notChecked: Cliente no comprobado
|
|
||||||
webAccountInactive: Sin acceso web
|
|
||||||
noWebAccess: El acceso web está desactivado
|
|
||||||
businessType: Tipo de negocio
|
|
||||||
passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
|
|
||||||
businessTypeFk: Tipo de negocio
|
|
||||||
summary:
|
|
||||||
basicData: Datos básicos
|
|
||||||
fiscalAddress: Dirección fiscal
|
|
||||||
fiscalData: Datos fiscales
|
|
||||||
billingData: Datos de facturación
|
|
||||||
consignee: Consignatario pred.
|
|
||||||
businessData: Datos comerciales
|
|
||||||
financialData: Datos financieros
|
|
||||||
customerId: ID cliente
|
|
||||||
name: Nombre
|
|
||||||
contact: Contacto
|
|
||||||
phone: Teléfono
|
|
||||||
mobile: Móvil
|
|
||||||
email: Email
|
|
||||||
salesPerson: Comercial
|
|
||||||
contactChannel: Canal de contacto
|
|
||||||
socialName: Razón social
|
|
||||||
fiscalId: NIF/CIF
|
|
||||||
postcode: Código postal
|
|
||||||
province: Provincia
|
|
||||||
country: País
|
|
||||||
street: Calle
|
|
||||||
isEqualizated: Recargo de equivalencia
|
|
||||||
isActive: Activo
|
|
||||||
invoiceByAddress: Facturar por consignatario
|
|
||||||
verifiedData: Datos verificados
|
|
||||||
hasToInvoice: Facturar
|
|
||||||
notifyByEmail: Notificar por email
|
|
||||||
vies: VIES
|
|
||||||
payMethod: Método de pago
|
|
||||||
bankAccount: Cuenta bancaria
|
|
||||||
dueDay: Día de pago
|
|
||||||
hasLcr: Recibido LCR
|
|
||||||
hasCoreVnl: Recibido core VNL
|
|
||||||
hasB2BVnl: Recibido B2B VNL
|
|
||||||
addressName: Nombre de la dirección
|
|
||||||
addressCity: Ciudad
|
|
||||||
addressStreet: Calle
|
|
||||||
username: Usuario
|
|
||||||
webAccess: Acceso web
|
|
||||||
totalGreuge: Greuge total
|
|
||||||
mana: Maná
|
|
||||||
priceIncreasingRate: Ratio de incremento de precio
|
|
||||||
averageInvoiced: Facturación media
|
|
||||||
claimRate: Ratio de reclamaciones
|
|
||||||
risk: Riesgo
|
|
||||||
riskInfo: Facturas menos recibos mas pedidos sin facturar
|
|
||||||
credit: Crédito
|
|
||||||
creditInfo: Riesgo máximo asumido por la empresa
|
|
||||||
securedCredit: Crédito asegurado
|
|
||||||
securedCreditInfo: Riesgo máximo asumido por Solunion
|
|
||||||
balance: Balance
|
|
||||||
balanceInfo: Facturas menos recibos
|
|
||||||
balanceDue: Saldo vencido
|
|
||||||
balanceDueInfo: Facturas fuera de plazo menos recibos
|
|
||||||
recoverySince: Recobro desde
|
|
||||||
businessType: Tipo de negocio
|
|
||||||
city: Población
|
|
||||||
descriptorInfo: Facturas menos recibos mas pedidos sin facturar
|
|
||||||
rating: Clasificación
|
|
||||||
recommendCredit: Crédito recomendado
|
|
||||||
basicData:
|
|
||||||
socialName: Nombre fiscal
|
|
||||||
businessType: Tipo de negocio
|
|
||||||
contact: Contacto
|
|
||||||
youCanSaveMultipleEmails: Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios{','} ejemplo{':'} user{'@'}dominio{'.'}com, user2{'@'}dominio{'.'}com siendo el primer correo electrónico el principal
|
|
||||||
email: Email
|
|
||||||
phone: Teléfono
|
|
||||||
mobile: Móvil
|
|
||||||
salesPerson: Comercial
|
|
||||||
contactChannel: Canal de contacto
|
|
||||||
previousClient: Cliente anterior
|
|
||||||
extendedList:
|
|
||||||
tableVisibleColumns:
|
|
||||||
id: Identificador
|
|
||||||
name: Nombre
|
|
||||||
socialName: Razón social
|
|
||||||
fi: NIF / CIF
|
|
||||||
salesPersonFk: Comercial
|
|
||||||
credit: Crédito
|
|
||||||
creditInsurance: Crédito asegurado
|
|
||||||
phone: Teléfono
|
|
||||||
mobile: Móvil
|
|
||||||
street: Dirección fiscal
|
|
||||||
countryFk: País
|
|
||||||
provinceFk: Provincia
|
|
||||||
city: Población
|
|
||||||
postcode: Código postal
|
|
||||||
email: Email
|
|
||||||
created: Fecha creación
|
|
||||||
businessTypeFk: Tipo de negocio
|
|
||||||
payMethodFk: Forma de pago
|
|
||||||
sageTaxTypeFk: Tipo de impuesto Sage
|
|
||||||
sageTransactionTypeFk: Tipo tr. sage
|
|
||||||
isActive: Activo
|
|
||||||
isVies: Vies
|
|
||||||
isTaxDataChecked: Datos comprobados
|
|
||||||
isEqualizated: Recargo de equivalencias
|
|
||||||
isFreezed: Congelado
|
|
||||||
hasToInvoice: Factura
|
|
||||||
hasToInvoiceByAddress: Factura por consigna
|
|
||||||
isToBeMailed: Env. emails
|
|
||||||
hasLcr: Recibido LCR
|
|
||||||
hasCoreVnl: Recibido core VNL
|
|
||||||
hasSepaVnl: Recibido B2B VNL
|
|
||||||
entry:
|
entry:
|
||||||
list:
|
list:
|
||||||
newEntry: Nueva entrada
|
newEntry: Nueva entrada
|
||||||
|
@ -936,6 +818,16 @@ worker:
|
||||||
credit: Haber
|
credit: Haber
|
||||||
concept: Concepto
|
concept: Concepto
|
||||||
wagon:
|
wagon:
|
||||||
|
pageTitles:
|
||||||
|
wagons: Vagones
|
||||||
|
wagonsList: Listado vagones
|
||||||
|
wagonCreate: Crear tipo
|
||||||
|
wagonEdit: Editar tipo
|
||||||
|
typesList: Listado tipos
|
||||||
|
typeCreate: Crear tipo
|
||||||
|
typeEdit: Editar tipo
|
||||||
|
wagonCounter: Contador de carros
|
||||||
|
wagonTray: Listado bandejas
|
||||||
type:
|
type:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
submit: Guardar
|
submit: Guardar
|
||||||
|
@ -1093,6 +985,7 @@ travel:
|
||||||
warehouseOut: Alm.entrada
|
warehouseOut: Alm.entrada
|
||||||
totalEntries: ∑
|
totalEntries: ∑
|
||||||
totalEntriesTooltip: Entradas totales
|
totalEntriesTooltip: Entradas totales
|
||||||
|
daysOnward: Días de llegada en adelante
|
||||||
summary:
|
summary:
|
||||||
confirmed: Confirmado
|
confirmed: Confirmado
|
||||||
entryId: Id entrada
|
entryId: Id entrada
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
|
@ -24,7 +25,7 @@ watch(
|
||||||
<template>
|
<template>
|
||||||
<FormModel
|
<FormModel
|
||||||
ref="formModelRef"
|
ref="formModelRef"
|
||||||
:url="`VnUsers/preview`"
|
url="VnUsers/preview"
|
||||||
:url-update="`VnUsers/${route.params.id}/update-user`"
|
:url-update="`VnUsers/${route.params.id}/update-user`"
|
||||||
:filter="accountFilter"
|
:filter="accountFilter"
|
||||||
model="Accounts"
|
model="Accounts"
|
||||||
|
@ -43,6 +44,15 @@ watch(
|
||||||
option-value="code"
|
option-value="code"
|
||||||
option-label="code"
|
option-label="code"
|
||||||
/>
|
/>
|
||||||
|
<VnSelectEnum
|
||||||
|
schema="account"
|
||||||
|
table="user"
|
||||||
|
column="twoFactor"
|
||||||
|
v-model="data.twoFactor"
|
||||||
|
:label="t('account.card.twoFactor')"
|
||||||
|
option-value="code"
|
||||||
|
option-label="code"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
|
|
|
@ -142,7 +142,13 @@ const redirectToRoleSummary = (id) =>
|
||||||
<SubRoleCreateForm @on-submit-create-subrole="createSubRole" />
|
<SubRoleCreateForm @on-submit-create-subrole="createSubRole" />
|
||||||
</QDialog>
|
</QDialog>
|
||||||
<QPageSticky position="bottom-right" :offset="[18, 18]">
|
<QPageSticky position="bottom-right" :offset="[18, 18]">
|
||||||
<QBtn fab icon="add" color="primary" @click="openCreateSubRoleForm()">
|
<QBtn
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
|
color="primary"
|
||||||
|
@click="openCreateSubRoleForm()"
|
||||||
|
>
|
||||||
<QTooltip>{{ t('warehouses.add') }}</QTooltip>
|
<QTooltip>{{ t('warehouses.add') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
|
|
|
@ -35,6 +35,7 @@ account:
|
||||||
willDeactivated: User will be deactivated
|
willDeactivated: User will be deactivated
|
||||||
activated: User activated!
|
activated: User activated!
|
||||||
deactivated: User deactivated!
|
deactivated: User deactivated!
|
||||||
|
twoFactor: Two factor
|
||||||
actions:
|
actions:
|
||||||
setPassword: Set password
|
setPassword: Set password
|
||||||
disableAccount:
|
disableAccount:
|
||||||
|
|
|
@ -32,6 +32,7 @@ account:
|
||||||
activated: ¡Usuario activado!
|
activated: ¡Usuario activado!
|
||||||
deactivated: ¡Usuario desactivado!
|
deactivated: ¡Usuario desactivado!
|
||||||
newUser: Nuevo usuario
|
newUser: Nuevo usuario
|
||||||
|
twoFactor: Doble factor
|
||||||
privileges:
|
privileges:
|
||||||
delegate: Puede delegar privilegios
|
delegate: Puede delegar privilegios
|
||||||
actions:
|
actions:
|
||||||
|
|
|
@ -3,58 +3,18 @@ import { ref } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnSelectEnum from 'src/components/common/VnSelectEnum.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
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 VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
|
||||||
import axios from 'axios';
|
|
||||||
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
import VnAvatar from 'src/components/ui/VnAvatar.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
const claimStates = ref([]);
|
|
||||||
const claimStatesCopy = ref([]);
|
|
||||||
const optionsList = ref([]);
|
|
||||||
|
|
||||||
const workersOptions = ref([]);
|
const workersOptions = ref([]);
|
||||||
|
|
||||||
function setClaimStates(data) {
|
|
||||||
claimStates.value = data;
|
|
||||||
claimStatesCopy.value = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getEnumValues() {
|
|
||||||
optionsList.value = [{ id: null, description: t('claim.null') }];
|
|
||||||
const { data } = await axios.get(`Applications/get-enum-values`, {
|
|
||||||
params: {
|
|
||||||
schema: 'vn',
|
|
||||||
table: 'claim',
|
|
||||||
column: 'pickup',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
for (let value of data)
|
|
||||||
optionsList.value.push({ id: value, description: t(`claim.${value}`) });
|
|
||||||
}
|
|
||||||
|
|
||||||
getEnumValues();
|
|
||||||
|
|
||||||
const statesFilter = {
|
|
||||||
options: claimStates,
|
|
||||||
filterFn: (options, value) => {
|
|
||||||
const search = value.toLowerCase();
|
|
||||||
|
|
||||||
if (value === '') return claimStatesCopy.value;
|
|
||||||
|
|
||||||
return options.value.filter((row) => {
|
|
||||||
const description = row.description.toLowerCase();
|
|
||||||
|
|
||||||
return description.indexOf(search) > -1;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -70,7 +30,7 @@ const statesFilter = {
|
||||||
auto-load
|
auto-load
|
||||||
:reload="true"
|
:reload="true"
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate, filter }">
|
<template #form="{ data, validate }">
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.client.name"
|
v-model="data.client.name"
|
||||||
|
@ -101,20 +61,14 @@ const statesFilter = {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VnSelect>
|
</VnSelect>
|
||||||
<QSelect
|
<VnSelect
|
||||||
v-model="data.claimStateFk"
|
v-model="data.claimStateFk"
|
||||||
:options="claimStates"
|
url="ClaimStates"
|
||||||
option-value="id"
|
|
||||||
option-label="description"
|
|
||||||
emit-value
|
|
||||||
:label="t('claim.state')"
|
:label="t('claim.state')"
|
||||||
map-options
|
option-label="description"
|
||||||
use-input
|
|
||||||
@filter="(value, update) => filter(value, update, statesFilter)"
|
|
||||||
:rules="validate('claim.claimStateFk')"
|
:rules="validate('claim.claimStateFk')"
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
>
|
/>
|
||||||
</QSelect>
|
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<QInput
|
<QInput
|
||||||
|
@ -123,16 +77,14 @@ const statesFilter = {
|
||||||
:rules="validate('claim.packages')"
|
:rules="validate('claim.packages')"
|
||||||
type="number"
|
type="number"
|
||||||
/>
|
/>
|
||||||
<QSelect
|
<VnSelectEnum
|
||||||
v-model="data.pickup"
|
v-model="data.pickup"
|
||||||
:options="optionsList"
|
|
||||||
option-value="id"
|
|
||||||
option-label="description"
|
|
||||||
emit-value
|
|
||||||
:label="t('claim.pickup')"
|
:label="t('claim.pickup')"
|
||||||
map-options
|
table="claim"
|
||||||
use-input
|
column="pickup"
|
||||||
:input-debounce="0"
|
option-label="description"
|
||||||
|
:translation="(value) => t(`claim.${value}`)"
|
||||||
|
:default-options="[{ id: null, description: t('claim.null') }]"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -317,7 +317,7 @@ async function saveWhenHasChanges() {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<QBtn fab color="primary" icon="add" @click="showImportDialog()" />
|
<QBtn fab color="primary" shortcut="+" icon="add" @click="showImportDialog()" />
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,13 @@ function onDrag() {
|
||||||
</QDialog>
|
</QDialog>
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<label for="fileInput">
|
<label for="fileInput">
|
||||||
<QBtn fab @click="inputFile.nativeEl.click()" icon="add" color="primary">
|
<QBtn
|
||||||
|
fab
|
||||||
|
@click="inputFile.nativeEl.click()"
|
||||||
|
shortcut="+"
|
||||||
|
icon="add"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
<QInput
|
<QInput
|
||||||
ref="inputFile"
|
ref="inputFile"
|
||||||
type="file"
|
type="file"
|
||||||
|
|
|
@ -5,15 +5,12 @@ import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const addresses = ref([]);
|
const addresses = ref([]);
|
||||||
const client = ref(null);
|
const client = ref(null);
|
||||||
const provincesLocation = ref([]);
|
|
||||||
|
|
||||||
const addressFilter = {
|
const addressFilter = {
|
||||||
fields: [
|
fields: [
|
||||||
|
@ -41,7 +38,13 @@ const addressFilter = {
|
||||||
{
|
{
|
||||||
relation: 'province',
|
relation: 'province',
|
||||||
scope: {
|
scope: {
|
||||||
fields: ['id', 'name'],
|
fields: ['id', 'name', 'countryFk'],
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
relation: 'country',
|
||||||
|
scope: { fields: ['id', 'name'] },
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -83,13 +86,6 @@ const getClientData = async (id) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const setProvince = (provinceFk) => {
|
|
||||||
const result = provincesLocation.value.filter(
|
|
||||||
(province) => province.id === provinceFk
|
|
||||||
);
|
|
||||||
return result[0]?.name || '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const isDefaultAddress = (address) => {
|
const isDefaultAddress = (address) => {
|
||||||
return client?.value?.defaultAddressFk === address.id ? 1 : 0;
|
return client?.value?.defaultAddressFk === address.id ? 1 : 0;
|
||||||
};
|
};
|
||||||
|
@ -128,12 +124,6 @@ const toCustomerAddressEdit = (addressId) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
@on-fetch="(data) => (provincesLocation = data)"
|
|
||||||
auto-load
|
|
||||||
url="Provinces/location"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="full-width flex justify-center">
|
<div class="full-width flex justify-center">
|
||||||
<QCard class="card-width q-pa-lg" v-if="addresses.length">
|
<QCard class="card-width q-pa-lg" v-if="addresses.length">
|
||||||
<QCardSection>
|
<QCardSection>
|
||||||
|
@ -177,7 +167,14 @@ const toCustomerAddressEdit = (addressId) => {
|
||||||
<div>{{ item.street }}</div>
|
<div>{{ item.street }}</div>
|
||||||
<div>
|
<div>
|
||||||
{{ item.postalCode }} - {{ item.city }},
|
{{ item.postalCode }} - {{ item.city }},
|
||||||
{{ setProvince(item.provinceFk) }}
|
{{ item.province.name }}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ item.phone }}
|
||||||
|
<span v-if="item.mobile"
|
||||||
|
>,
|
||||||
|
{{ item.mobile }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
|
|
|
@ -2,32 +2,30 @@
|
||||||
import { computed, onBeforeMount, ref } from 'vue';
|
import { computed, onBeforeMount, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useRole } from 'src/composables/useRole';
|
import { useAcl } from 'src/composables/useAcl';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
import { toCurrency, toDate, toDateHourMin } from 'src/filters';
|
import { toCurrency, toDate, toDateHourMin } from 'src/filters';
|
||||||
import { useState } from 'composables/useState';
|
import { useState } from 'composables/useState';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import { useStateStore } from 'stores/useStateStore';
|
||||||
import { usePrintService } from 'composables/usePrintService';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
import { useSession } from 'composables/useSession';
|
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import VnInput from 'components/common/VnInput.vue';
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import VnSubToolbar from 'components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'components/ui/VnSubToolbar.vue';
|
||||||
import VnFilter from 'components/VnTable/VnFilter.vue';
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
|
||||||
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
|
import CustomerNewPayment from 'src/pages/Customer/components/CustomerNewPayment.vue';
|
||||||
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
||||||
|
|
||||||
const { openConfirmationModal } = useVnConfirm();
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
const { sendEmail } = usePrintService();
|
const { sendEmail, openReport } = usePrintService();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { hasAny } = useRole();
|
const { hasAny } = useAcl();
|
||||||
|
const currentBalance = ref({});
|
||||||
const session = useSession();
|
|
||||||
const tokenMultimedia = session.getTokenMultimedia();
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const state = useState();
|
const state = useState();
|
||||||
|
@ -35,9 +33,9 @@ const stateStore = useStateStore();
|
||||||
const user = state.getUser();
|
const user = state.getUser();
|
||||||
|
|
||||||
const clientRisk = ref([]);
|
const clientRisk = ref([]);
|
||||||
|
const companies = ref([]);
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const companyId = ref();
|
const companyId = ref(user.value.companyFk);
|
||||||
const companyLastId = ref(user.value.companyFk);
|
|
||||||
const balances = ref([]);
|
const balances = ref([]);
|
||||||
const vnFilterRef = ref({});
|
const vnFilterRef = ref({});
|
||||||
const filter = computed(() => {
|
const filter = computed(() => {
|
||||||
|
@ -47,43 +45,16 @@ const filter = computed(() => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const companyFilterColumn = {
|
|
||||||
align: 'left',
|
|
||||||
name: 'companyId',
|
|
||||||
label: t('Company'),
|
|
||||||
component: 'select',
|
|
||||||
attrs: {
|
|
||||||
url: 'Companies',
|
|
||||||
optionLabel: 'code',
|
|
||||||
sortBy: 'code',
|
|
||||||
limit: 0,
|
|
||||||
},
|
|
||||||
columnFilter: {
|
|
||||||
event: {
|
|
||||||
remove: () => (companyId.value = null),
|
|
||||||
'update:modelValue': (newCompanyFk) => {
|
|
||||||
if (!newCompanyFk) return;
|
|
||||||
vnFilterRef.value.addFilter(newCompanyFk);
|
|
||||||
companyLastId.value = newCompanyFk;
|
|
||||||
},
|
|
||||||
blur: () =>
|
|
||||||
!companyId.value &&
|
|
||||||
(companyId.value = companyLastId.value ?? user.value.companyFk),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
visible: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
name: 'payed',
|
name: 'payed',
|
||||||
label: t('Date'),
|
label: t('Date'),
|
||||||
format: ({ payed }) => toDate(payed),
|
format: ({ payed }) => toDate(payed),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
name: 'created',
|
name: 'created',
|
||||||
label: t('Creation date'),
|
label: t('Creation date'),
|
||||||
format: ({ created }) => toDateHourMin(created),
|
format: ({ created }) => toDateHourMin(created),
|
||||||
|
@ -91,16 +62,10 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'workerFk',
|
|
||||||
label: t('Employee'),
|
label: t('Employee'),
|
||||||
columnField: {
|
columnField: {
|
||||||
component: 'userLink',
|
component: 'userLink',
|
||||||
attrs: ({ row }) => {
|
attrs: ({ row }) => ({ workerId: row.workerFk, name: row.userName }),
|
||||||
return {
|
|
||||||
workerId: row.workerFk,
|
|
||||||
name: row.userName,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
|
@ -125,14 +90,14 @@ const columns = computed(() => [
|
||||||
isId: true,
|
isId: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'left',
|
||||||
name: 'credit',
|
name: 'credit',
|
||||||
label: t('Havings'),
|
label: t('Havings'),
|
||||||
format: ({ credit }) => credit && toCurrency(credit),
|
format: ({ credit }) => credit && toCurrency(credit),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'left',
|
||||||
name: 'balance',
|
name: 'balance',
|
||||||
label: t('Balance'),
|
label: t('Balance'),
|
||||||
format: ({ balance }) => toCurrency(balance),
|
format: ({ balance }) => toCurrency(balance),
|
||||||
|
@ -171,41 +136,20 @@ const columns = computed(() => [
|
||||||
|
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
companyId.value = user.value.companyFk;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
async function getClientRisk() {
|
async function getCurrentBalance(data) {
|
||||||
const { data } = await axios.get(`clientRisks`, {
|
currentBalance.value[companyId.value] = {
|
||||||
params: {
|
amount: 0,
|
||||||
filter: JSON.stringify({
|
code: companies.value.find((c) => c.id === companyId.value)?.code,
|
||||||
include: { relation: 'company', scope: { fields: ['code'] } },
|
};
|
||||||
where: { clientFk: route.params.id, companyFk: user.value.companyFk },
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
clientRisk.value = data;
|
|
||||||
return clientRisk.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getCurrentBalance() {
|
for (const balance of data) {
|
||||||
const currentBalance = (await getClientRisk()).find((balance) => {
|
currentBalance.value[balance.companyFk] = {
|
||||||
return balance.companyFk === companyId.value;
|
code: balance.company.code,
|
||||||
});
|
amount: balance.amount,
|
||||||
return currentBalance && currentBalance.amount;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
async function onFetch(data) {
|
|
||||||
balances.value = [];
|
|
||||||
for (const [index, balance] of data.entries()) {
|
|
||||||
if (index === 0) {
|
|
||||||
balance.balance = await getCurrentBalance();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const previousBalance = data[index - 1];
|
|
||||||
balance.balance =
|
|
||||||
previousBalance?.balance - (previousBalance?.debit - previousBalance?.credit);
|
|
||||||
}
|
}
|
||||||
balances.value = data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const showNewPaymentDialog = () => {
|
const showNewPaymentDialog = () => {
|
||||||
|
@ -220,31 +164,48 @@ const showNewPaymentDialog = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const showBalancePdf = ({ id }) => {
|
const showBalancePdf = ({ id }) => {
|
||||||
const url = `api/InvoiceOuts/${id}/download?access_token=${tokenMultimedia}`;
|
openReport(`InvoiceOuts/${id}/download`, {}, '_blank');
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
alexm
commented
Revisar bien la funcionalidad de este archivo, se usa en otro sitio Revisar bien la funcionalidad de este archivo, se usa en otro sitio
jsegarra
commented
he creado un composable he creado un composable
|
|||||||
|
<FetchData
|
||||||
|
url="Companies"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="(data) => (companies = data)"
|
||||||
|
></FetchData>
|
||||||
|
<FetchData
|
||||||
|
v-if="companies.length > 0"
|
||||||
|
url="clientRisks"
|
||||||
|
:filter="{
|
||||||
|
include: { relation: 'company', scope: { fields: ['code'] } },
|
||||||
|
where: { clientFk: route.params.id },
|
||||||
|
}"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="getCurrentBalance"
|
||||||
|
></FetchData>
|
||||||
|
|
||||||
<VnSubToolbar class="q-mb-md">
|
<VnSubToolbar class="q-mb-md">
|
||||||
<template #st-data>
|
<template #st-data>
|
||||||
<div class="column justify-center q-px-md q-py-sm">
|
<div class="column justify-center q-px-md q-py-sm">
|
||||||
<span class="text-bold">{{ t('Total by company') }}</span>
|
<span class="text-bold">{{ t('Total by company') }}</span>
|
||||||
<div class="row justify-center" v-if="clientRisk?.length">
|
<div class="row justify-center">
|
||||||
{{ clientRisk[0].company.code }}:
|
{{ currentBalance[companyId]?.code }}:
|
||||||
{{ toCurrency(clientRisk[0].amount) }}
|
{{ toCurrency(currentBalance[companyId]?.amount) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #st-actions>
|
<template #st-actions>
|
||||||
<div>
|
<div>
|
||||||
<VnFilter
|
<VnSelect
|
||||||
|
:label="t('Company')"
|
||||||
ref="vnFilterRef"
|
ref="vnFilterRef"
|
||||||
v-model="companyId"
|
v-model="companyId"
|
||||||
data-key="CustomerBalance"
|
data-key="CustomerBalance"
|
||||||
:column="companyFilterColumn"
|
:options="companies"
|
||||||
search-url="balance"
|
option-label="code"
|
||||||
/>
|
option-value="id"
|
||||||
|
></VnSelect>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VnSubToolbar>
|
</VnSubToolbar>
|
||||||
|
@ -258,7 +219,7 @@ const showBalancePdf = ({ id }) => {
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
:column-search="false"
|
:column-search="false"
|
||||||
@on-fetch="onFetch"
|
:disable-option="{ card: true }"
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #column-balance="{ rowIndex }">
|
<template #column-balance="{ rowIndex }">
|
||||||
|
@ -266,7 +227,7 @@ const showBalancePdf = ({ id }) => {
|
||||||
</template>
|
</template>
|
||||||
<template #column-description="{ row }">
|
<template #column-description="{ row }">
|
||||||
<div class="link" v-if="row.isInvoice">
|
<div class="link" v-if="row.isInvoice">
|
||||||
{{ row.description }}
|
{{ t('bill', { ref: row.description }) }}
|
||||||
<InvoiceOutDescriptorProxy :id="row.description" />
|
<InvoiceOutDescriptorProxy :id="row.description" />
|
||||||
</div>
|
</div>
|
||||||
<span v-else class="q-pa-xs dotted rounded-borders" :title="row.description">
|
<span v-else class="q-pa-xs dotted rounded-borders" :title="row.description">
|
||||||
|
@ -284,7 +245,9 @@ const showBalancePdf = ({ id }) => {
|
||||||
>
|
>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="scope.value"
|
v-model="scope.value"
|
||||||
:disable="!hasAny(['administrative'])"
|
:disable="
|
||||||
|
!hasAny([{ model: 'Receipt', props: '*', accessType: 'WRITE' }])
|
||||||
|
"
|
||||||
@keypress.enter="scope.set"
|
@keypress.enter="scope.set"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -16,6 +16,20 @@ const { t } = useI18n();
|
||||||
const businessTypes = ref([]);
|
const businessTypes = ref([]);
|
||||||
const contactChannels = ref([]);
|
const contactChannels = ref([]);
|
||||||
const title = ref();
|
const title = ref();
|
||||||
|
const handleSalesModelValue = (val) => ({
|
||||||
|
or: [
|
||||||
|
{ id: val },
|
||||||
|
{ name: val },
|
||||||
|
{ nickname: { like: '%' + val + '%' } },
|
||||||
|
{ code: { like: `${val}%` } },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const exprBuilder = (param, value) => {
|
||||||
|
return {
|
||||||
|
and: [{ active: { neq: false } }, handleSalesModelValue(value)],
|
||||||
|
};
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -25,6 +39,7 @@ const title = ref();
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="BusinessTypes"
|
url="BusinessTypes"
|
||||||
|
:filter="{ fields: ['code', 'description'], order: 'description ASC ' }"
|
||||||
@on-fetch="(data) => (businessTypes = data)"
|
@on-fetch="(data) => (businessTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
|
@ -33,12 +48,12 @@ const title = ref();
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnInput
|
<VnInput
|
||||||
:label="t('globals.name')"
|
:label="t('globals.name')"
|
||||||
:rules="validate('client.socialName')"
|
:rules="validate('client.name')"
|
||||||
autofocus
|
autofocus
|
||||||
clearable
|
clearable
|
||||||
v-model="data.name"
|
v-model="data.name"
|
||||||
/>
|
/>
|
||||||
<QSelect
|
<VnSelect
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
:label="t('customer.basicData.businessType')"
|
:label="t('customer.basicData.businessType')"
|
||||||
:options="businessTypes"
|
:options="businessTypes"
|
||||||
|
@ -89,20 +104,20 @@ const title = ref();
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
url="Workers/activeWithInheritedRole"
|
url="Workers/search"
|
||||||
:filter="{ where: { role: 'salesPerson' } }"
|
|
||||||
option-filter="firstName"
|
|
||||||
v-model="data.salesPersonFk"
|
v-model="data.salesPersonFk"
|
||||||
:label="t('customer.basicData.salesPerson')"
|
:label="t('customer.basicData.salesPerson')"
|
||||||
|
:params="{
|
||||||
|
departmentCodes: ['VT', 'shopping'],
|
||||||
|
}"
|
||||||
|
:fields="['id', 'nickname']"
|
||||||
|
sort-by="nickname ASC"
|
||||||
|
option-label="nickname"
|
||||||
|
option-value="id"
|
||||||
:rules="validate('client.salesPersonFk')"
|
:rules="validate('client.salesPersonFk')"
|
||||||
:use-like="false"
|
:expr-builder="exprBuilder"
|
||||||
:emit-value="false"
|
emit-value
|
||||||
@update:model-value="
|
auto-load
|
||||||
(val) => {
|
|
||||||
title = val?.nickname;
|
|
||||||
data.salesPersonFk = val?.id;
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VnAvatar
|
<VnAvatar
|
||||||
|
@ -111,8 +126,19 @@ const title = ref();
|
||||||
:title="title"
|
:title="title"
|
||||||
/>
|
/>
|
||||||
</template>
|
</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>
|
||||||
</VnSelect>
|
</VnSelect>
|
||||||
<QSelect
|
<VnSelect
|
||||||
v-model="data.contactChannelFk"
|
v-model="data.contactChannelFk"
|
||||||
:options="contactChannels"
|
:options="contactChannels"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
@ -125,7 +151,8 @@ const title = ref();
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<QSelect
|
<VnSelect
|
||||||
|
url="Clients"
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
:label="t('customer.basicData.previousClient')"
|
:label="t('customer.basicData.previousClient')"
|
||||||
:options="clients"
|
:options="clients"
|
||||||
|
@ -134,7 +161,9 @@ const title = ref();
|
||||||
map-options
|
map-options
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
sort-by="name ASC"
|
||||||
v-model="data.transferorFk"
|
v-model="data.transferorFk"
|
||||||
|
:fields="['id', 'name']"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-pointer">
|
<QIcon name="info" class="cursor-pointer">
|
||||||
|
@ -145,7 +174,7 @@ const title = ref();
|
||||||
}}</QTooltip>
|
}}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</template>
|
</template>
|
||||||
</QSelect>
|
</VnSelect>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
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';
|
||||||
|
@ -14,8 +13,6 @@ import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const payMethods = ref([]);
|
|
||||||
const bankEntitiesOptions = ref([]);
|
|
||||||
const bankEntitiesRef = ref(null);
|
const bankEntitiesRef = ref(null);
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
|
@ -31,15 +28,6 @@ const getBankEntities = (data, formData) => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<fetch-data @on-fetch="(data) => (payMethods = data)" auto-load url="PayMethods" />
|
|
||||||
<fetch-data
|
|
||||||
ref="bankEntitiesRef"
|
|
||||||
@on-fetch="(data) => (bankEntitiesOptions = data)"
|
|
||||||
:filter="filter"
|
|
||||||
auto-load
|
|
||||||
url="BankEntities"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormModel
|
<FormModel
|
||||||
:url-update="`Clients/${route.params.id}`"
|
:url-update="`Clients/${route.params.id}`"
|
||||||
:url="`Clients/${route.params.id}/getCard`"
|
:url="`Clients/${route.params.id}/getCard`"
|
||||||
|
@ -49,8 +37,9 @@ const getBankEntities = (data, formData) => {
|
||||||
<template #form="{ data, validate }">
|
<template #form="{ data, validate }">
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
auto-load
|
||||||
|
url="PayMethods"
|
||||||
:label="t('Billing data')"
|
:label="t('Billing data')"
|
||||||
:options="payMethods"
|
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
option-label="name"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
@ -69,8 +58,11 @@ const getBankEntities = (data, formData) => {
|
||||||
</VnInput>
|
</VnInput>
|
||||||
<VnSelectDialog
|
<VnSelectDialog
|
||||||
:label="t('Swift / BIC')"
|
:label="t('Swift / BIC')"
|
||||||
:options="bankEntitiesOptions"
|
ref="bankEntitiesRef"
|
||||||
:roles-allowed-to-create="['salesAssistant', 'hr']"
|
:filter="filter"
|
||||||
|
auto-load
|
||||||
|
url="BankEntities"
|
||||||
|
:acls="[{ model: 'BankEntity', props: '*', accessType: 'WRITE' }]"
|
||||||
:rules="validate('Worker.bankEntity')"
|
:rules="validate('Worker.bankEntity')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="name"
|
option-label="name"
|
||||||
|
@ -85,9 +77,8 @@ const getBankEntities = (data, formData) => {
|
||||||
<template #option="scope">
|
<template #option="scope">
|
||||||
<QItem v-bind="scope.itemProps">
|
<QItem v-bind="scope.itemProps">
|
||||||
<QItemSection v-if="scope.opt">
|
<QItemSection v-if="scope.opt">
|
||||||
<QItemLabel
|
<QItemLabel>{{ scope.opt.bic }} </QItemLabel>
|
||||||
>{{ scope.opt.bic }} {{ scope.opt.name }}</QItemLabel
|
<QItemLabel caption> {{ scope.opt.name }}</QItemLabel>
|
||||||
>
|
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,17 +1,23 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import VnCard from 'components/common/VnCard.vue';
|
import VnCard from 'components/common/VnCard.vue';
|
||||||
import CustomerDescriptor from './CustomerDescriptor.vue';
|
import CustomerDescriptor from './CustomerDescriptor.vue';
|
||||||
import CustomerFilter from '../CustomerFilter.vue';
|
import CustomerFilter from '../CustomerFilter.vue';
|
||||||
|
const route = useRoute();
|
||||||
|
|
||||||
|
const routeName = computed(() => route.name);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnCard
|
<VnCard
|
||||||
data-key="Client"
|
data-key="Client"
|
||||||
base-url="Clients"
|
base-url="Clients"
|
||||||
:descriptor="CustomerDescriptor"
|
:descriptor="CustomerDescriptor"
|
||||||
:filter-panel="CustomerFilter"
|
:filter-panel="routeName != 'CustomerConsumption' && CustomerFilter"
|
||||||
search-data-key="CustomerList"
|
search-data-key="CustomerList"
|
||||||
:searchbar-props="{
|
:searchbar-props="{
|
||||||
url: 'Clients/extendedListFilter',
|
url: 'Clients/filter',
|
||||||
label: 'Search customer',
|
label: 'Search customer',
|
||||||
info: 'You can search by customer id or name',
|
info: 'You can search by customer id or name',
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,15 +1,241 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import CustomerConsumptionFilter from './CustomerConsumptionFilter.vue';
|
import { ref, computed, onBeforeMount } from 'vue';
|
||||||
import { useStateStore } from 'src/stores/useStateStore';
|
import axios from 'axios';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { toDate } from 'src/filters/index';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
import FetchedTags from 'components/ui/FetchedTags.vue';
|
||||||
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
|
import { usePrintService } from 'src/composables/usePrintService';
|
||||||
|
import { useVnConfirm } from 'src/composables/useVnConfirm';
|
||||||
|
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
const { openReport, sendEmail } = usePrintService();
|
||||||
|
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
|
import ItemDescriptorProxy from 'src/pages/Item/Card/ItemDescriptorProxy.vue';
|
||||||
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
|
||||||
|
const arrayData = useArrayData('Client');
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const campaignList = ref();
|
||||||
|
const showActionBtns = computed(() => handleQueryParams());
|
||||||
|
function handleQueryParams() {
|
||||||
|
const query = getQueryParams();
|
||||||
|
return query.from && query.to;
|
||||||
|
}
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
name: 'search',
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.search'),
|
||||||
|
visible: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'itemFk',
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.item'),
|
||||||
|
columnClass: 'shrink',
|
||||||
|
cardVisible: true,
|
||||||
|
columnFilter: {
|
||||||
|
name: 'itemId',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ticketFk',
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.ticket'),
|
||||||
|
cardVisible: true,
|
||||||
|
columnFilter: {
|
||||||
|
inWhere: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'shipped',
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.shipped'),
|
||||||
|
format: ({ shipped }) => toDate(shipped),
|
||||||
|
columnFilter: false,
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'description',
|
||||||
|
align: 'left',
|
||||||
|
label: t('globals.description'),
|
||||||
|
columnClass: 'expand',
|
||||||
|
columnFilter: {
|
||||||
|
inWhere: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'quantity',
|
||||||
|
label: t('globals.quantity'),
|
||||||
|
cardVisible: true,
|
||||||
|
columnFilter: {
|
||||||
|
inWhere: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'grouped',
|
||||||
|
label: t('Group by items'),
|
||||||
|
component: 'checkbox',
|
||||||
|
visible: false,
|
||||||
|
orderBy: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
campaignList.value = (await axios('Campaigns/latest')).data;
|
||||||
|
});
|
||||||
|
|
||||||
|
function getQueryParams() {
|
||||||
|
return JSON.parse(route.query.consumption ?? '{}');
|
||||||
|
}
|
||||||
|
function getParams() {
|
||||||
|
const query = getQueryParams();
|
||||||
|
return {
|
||||||
|
from: query.from,
|
||||||
|
to: query.to,
|
||||||
|
recipient: arrayData.store.data.email,
|
||||||
|
recipientId: arrayData.store.data.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const userParams = computed(() => {
|
||||||
|
const minDate = Date.vnNew();
|
||||||
|
minDate.setHours(0, 0, 0, 0);
|
||||||
|
minDate.setMonth(minDate.getMonth() - 2);
|
||||||
|
|
||||||
|
const maxDate = Date.vnNew();
|
||||||
|
maxDate.setHours(23, 59, 59, 59);
|
||||||
|
|
||||||
|
return {
|
||||||
|
campaign: campaignList.value[0]?.id,
|
||||||
|
from: minDate,
|
||||||
|
to: maxDate,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const openReportPdf = () => {
|
||||||
|
openReport(`Clients/${route.params.id}/campaign-metrics-pdf`, getParams());
|
||||||
|
};
|
||||||
|
|
||||||
|
const openSendEmailDialog = async () => {
|
||||||
|
openConfirmationModal(
|
||||||
|
t('The consumption report will be sent'),
|
||||||
|
t('Please, confirm'),
|
||||||
|
() => sendCampaignMetricsEmail({ address: arrayData.store.data.email })
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const sendCampaignMetricsEmail = ({ address }) => {
|
||||||
|
sendEmail(`Clients/${route.params.id}/campaign-metrics-email`, {
|
||||||
|
recipient: address,
|
||||||
|
...getParams(),
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Teleport to="#right-panel" v-if="useStateStore().isHeaderMounted()">
|
<VnTable
|
||||||
<CustomerConsumptionFilter data-key="CustomerConsumption" />
|
v-if="campaignList"
|
||||||
</Teleport>
|
data-key="CustomerConsumption"
|
||||||
|
url="Clients/consumption"
|
||||||
|
:order="['itemTypeFk', 'itemName', 'itemSize', 'description']"
|
||||||
|
:columns="columns"
|
||||||
|
search-url="consumption"
|
||||||
|
:filter="filter"
|
||||||
|
:user-params="userParams"
|
||||||
|
:default-remove="false"
|
||||||
|
:default-reset="false"
|
||||||
|
:default-save="false"
|
||||||
|
:has-sub-toolbar="true"
|
||||||
|
auto-load
|
||||||
|
>
|
||||||
|
<template #moreBeforeActions>
|
||||||
|
<QBtn
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon-right="picture_as_pdf"
|
||||||
|
@click="openReportPdf()"
|
||||||
|
:disabled="!showActionBtns"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('globals.downloadPdf') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
color="primary"
|
||||||
|
flat
|
||||||
|
icon-right="email"
|
||||||
|
@click="openSendEmailDialog()"
|
||||||
|
:disabled="!showActionBtns"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('Send to email') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
<template #column-itemFk="{ row }">
|
||||||
|
<span class="link">
|
||||||
|
{{ row.itemFk }}
|
||||||
|
<ItemDescriptorProxy :id="row.itemFk" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #column-ticketFk="{ row }">
|
||||||
|
<span class="link">
|
||||||
|
{{ row.ticketFk }}
|
||||||
|
<TicketDescriptorProxy :id="row.ticketFk" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #column-description="{ row }">
|
||||||
|
<div>{{ row.concept }}</div>
|
||||||
|
<div v-if="row.subName" class="subName">
|
||||||
|
{{ row.subName }}
|
||||||
|
</div>
|
||||||
|
<FetchedTags :item="row" :max-length="3" />
|
||||||
|
</template>
|
||||||
|
<template #moreFilterPanel="{ params }">
|
||||||
|
<div class="column no-wrap flex-center q-gutter-y-md q-mt-xs q-pr-xl">
|
||||||
|
<VnSelect
|
||||||
|
v-model="params.campaign"
|
||||||
|
:options="campaignList"
|
||||||
|
:label="t('globals.campaign')"
|
||||||
|
:filled="true"
|
||||||
|
class="q-px-sm q-pt-none fit"
|
||||||
|
dense
|
||||||
|
option-label="code"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ scope.opt?.code }}
|
||||||
|
{{
|
||||||
|
new Date(scope.opt?.dated).getFullYear()
|
||||||
|
}}</QItemLabel
|
||||||
|
>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.from"
|
||||||
|
:label="t('globals.from')"
|
||||||
|
:filled="true"
|
||||||
|
class="q-px-xs q-pt-none fit"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.to"
|
||||||
|
:label="t('globals.to')"
|
||||||
|
:filled="true"
|
||||||
|
class="q-px-xs q-pt-none fit"
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Enter a new search: Introduce una nueva búsqueda
|
Enter a new search: Introduce una nueva búsqueda
|
||||||
|
Group by items: Agrupar por artículos
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -1,91 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
|
||||||
import { QItem } from 'quasar';
|
|
||||||
import VnSelect from 'src/components/common/VnSelect.vue';
|
|
||||||
import { QItemSection } from 'quasar';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
defineProps({ dataKey: { type: String, required: true } });
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<VnFilterPanel :data-key="dataKey" :search-button="true">
|
|
||||||
<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 }">
|
|
||||||
<QItem>
|
|
||||||
<QItemSection>
|
|
||||||
<VnInput
|
|
||||||
:label="t('params.item')"
|
|
||||||
v-model="params.itemId"
|
|
||||||
is-outlined
|
|
||||||
lazy-rules
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
|
||||||
<QItemSection>
|
|
||||||
<VnSelect
|
|
||||||
v-model="params.buyerId"
|
|
||||||
url="TicketRequests/getItemTypeWorker"
|
|
||||||
:label="t('params.buyer')"
|
|
||||||
option-value="id"
|
|
||||||
option-label="nickname"
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
rounded
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
|
||||||
<!--It's required to include the relation category !! There's 413 records in production-->
|
|
||||||
<QItemSection>
|
|
||||||
<VnSelect
|
|
||||||
v-model="params.typeId"
|
|
||||||
url="ItemTypes"
|
|
||||||
:label="t('params.type')"
|
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
rounded
|
|
||||||
>
|
|
||||||
</VnSelect>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
<QItem>
|
|
||||||
<QItemSection>
|
|
||||||
<VnSelect
|
|
||||||
url="ItemCategories"
|
|
||||||
:label="t('params.category')"
|
|
||||||
option-label="name"
|
|
||||||
option-value="id"
|
|
||||||
v-model="params.categoryId"
|
|
||||||
dense
|
|
||||||
outlined
|
|
||||||
rounded
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
|
||||||
</template>
|
|
||||||
</VnFilterPanel>
|
|
||||||
</template>
|
|
||||||
<i18n>
|
|
||||||
en:
|
|
||||||
params:
|
|
||||||
item: Item id
|
|
||||||
buyer: Buyer
|
|
||||||
type: Type
|
|
||||||
category: Category
|
|
||||||
es:
|
|
||||||
params:
|
|
||||||
item: Id artículo
|
|
||||||
buyer: Comprador
|
|
||||||
type: Tipo
|
|
||||||
category: Categoría
|
|
||||||
</i18n>
|
|
|
@ -56,17 +56,18 @@ const customerContactsRef = ref(null);
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<QIcon
|
<QBtn
|
||||||
@click="customerContactsRef.insert()"
|
@click="customerContactsRef.insert()"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
color="primary"
|
color="primary"
|
||||||
name="add"
|
flat
|
||||||
size="sm"
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Add contact') }}
|
{{ t('Add contact') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QBtn>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -53,6 +53,8 @@ const openDialog = (item) => {
|
||||||
promise: updateData,
|
promise: updateData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
updateData();
|
||||||
|
showQPageSticky.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const openViewCredit = (credit) => {
|
const openViewCredit = (credit) => {
|
||||||
|
|
|
@ -1,23 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { QBtn } from 'quasar';
|
|
||||||
|
|
||||||
import { toCurrency, toDateHourMin } from 'src/filters';
|
import { toCurrency, toDateHourMin } from 'src/filters';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import FormModel from 'components/FormModel.vue';
|
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const clientInformasRef = ref(null);
|
const tableRef = ref();
|
||||||
const rows = ref([]);
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -37,10 +31,9 @@ const filter = {
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'created',
|
format: ({ created }) => toDateHourMin(created),
|
||||||
format: (value) => toDateHourMin(value),
|
|
||||||
label: t('Since'),
|
label: t('Since'),
|
||||||
name: 'since',
|
name: 'created',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -51,66 +44,56 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'right',
|
||||||
field: 'rating',
|
field: 'rating',
|
||||||
label: t('Rating'),
|
label: t('customer.summary.rating'),
|
||||||
name: 'rating',
|
name: 'rating',
|
||||||
|
create: true,
|
||||||
|
columnCreate: {
|
||||||
|
component: 'number',
|
||||||
|
autofocus: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'right',
|
align: 'right',
|
||||||
field: 'recommendedCredit',
|
field: 'recommendedCredit',
|
||||||
format: (value) => toCurrency(value),
|
format: ({ recommendedCredit }) => toCurrency(recommendedCredit),
|
||||||
label: t('Recommended credit'),
|
label: t('customer.summary.recommendCredit'),
|
||||||
name: 'recommendedCredit',
|
name: 'recommendedCredit',
|
||||||
|
create: true,
|
||||||
|
columnCreate: {
|
||||||
|
component: 'number',
|
||||||
|
autofocus: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
watch(
|
|
||||||
() => route.params.id,
|
|
||||||
(newValue) => {
|
|
||||||
if (!newValue) return;
|
|
||||||
filter.where.clientFk = newValue;
|
|
||||||
clientInformasRef.value?.fetch();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<VnTable
|
||||||
:filter="filter"
|
ref="tableRef"
|
||||||
@on-fetch="(data) => (rows = data)"
|
data-key="ClientInformas"
|
||||||
auto-load
|
|
||||||
ref="clientInformasRef"
|
|
||||||
url="ClientInformas"
|
url="ClientInformas"
|
||||||
/>
|
:filter="filter"
|
||||||
|
:order="['created DESC']"
|
||||||
<FormModel
|
:columns="columns"
|
||||||
:form-initial-data="{}"
|
:right-search="false"
|
||||||
:observe-form-changes="false"
|
:is-editable="false"
|
||||||
:url-create="`Clients/${route.params.id}/setRating`"
|
:use-model="true"
|
||||||
|
:column-search="false"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
|
auto-load
|
||||||
|
:create="{
|
||||||
|
urlCreate: `Clients/${route.params.id}/setRating`,
|
||||||
|
title: 'Create rating',
|
||||||
|
onDataSaved: () => tableRef.reload(),
|
||||||
|
formInitialData: {},
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<template #form="{ data }">
|
<template #column-employee="{ row }">
|
||||||
<VnRow>
|
<span class="link">{{ row.worker.user.nickname }}</span>
|
||||||
<div class="col">
|
<WorkerDescriptorProxy :id="row.worker.id" />
|
||||||
<VnInput
|
|
||||||
:label="t('Rating')"
|
|
||||||
clearable
|
|
||||||
type="number"
|
|
||||||
v-model.number="data.rating"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
<VnInput
|
|
||||||
:label="t('Recommended credit')"
|
|
||||||
clearable
|
|
||||||
type="number"
|
|
||||||
v-model.number="data.recommendedCredit"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</VnRow>
|
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</VnTable>
|
||||||
|
<!-- <QTable
|
||||||
<div class="full-width flex justify-center" v-if="rows.length">
|
|
||||||
<QTable
|
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:pagination="{ rowsPerPage: 0 }"
|
:pagination="{ rowsPerPage: 0 }"
|
||||||
:rows="rows"
|
:rows="rows"
|
||||||
|
@ -120,22 +103,16 @@ watch(
|
||||||
class="card-width q-px-lg"
|
class="card-width q-px-lg"
|
||||||
>
|
>
|
||||||
<template #body-cell-employee="{ row }">
|
<template #body-cell-employee="{ row }">
|
||||||
<QTd auto-width @click.stop>
|
<QTd @click.stop>
|
||||||
<QBtn color="blue" flat no-caps>{{ row.worker.user.nickname }}</QBtn>
|
<span class="link">{{ row.worker.user.nickname }}</span>
|
||||||
<WorkerDescriptorProxy :id="row.clientFk" />
|
<WorkerDescriptorProxy :id="row.clientFk" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
</QTable>
|
</QTable> -->
|
||||||
</div>
|
|
||||||
|
|
||||||
<h5 class="flex justify-center color-vn-label" v-else>
|
|
||||||
{{ t('globals.noResults') }}
|
|
||||||
</h5>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Rating: Clasificación
|
|
||||||
Recommended credit: Crédito recomendado
|
Recommended credit: Crédito recomendado
|
||||||
Since: Desde
|
Since: Desde
|
||||||
Employee: Empleado
|
Employee: Empleado
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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 { toCurrency, toDate } from 'src/filters';
|
import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
|
||||||
|
|
||||||
import useCardDescription from 'src/composables/useCardDescription';
|
import useCardDescription from 'src/composables/useCardDescription';
|
||||||
|
|
||||||
|
@ -11,6 +11,10 @@ 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';
|
||||||
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
import CustomerDescriptorMenu from './CustomerDescriptorMenu.vue';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
const state = useState();
|
||||||
|
|
||||||
|
const customer = computed(() => state.get('customer'));
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -43,7 +47,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
:subtitle="data.subtitle"
|
:subtitle="data.subtitle"
|
||||||
@on-fetch="setData"
|
@on-fetch="setData"
|
||||||
:summary="$props.summary"
|
:summary="$props.summary"
|
||||||
data-key="customerData"
|
data-key="customer"
|
||||||
>
|
>
|
||||||
<template #menu="{ entity }">
|
<template #menu="{ entity }">
|
||||||
<CustomerDescriptorMenu :customer="entity" />
|
<CustomerDescriptorMenu :customer="entity" />
|
||||||
|
@ -57,35 +61,46 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
:value="toCurrency(entity.creditInsurance)"
|
:value="toCurrency(entity.creditInsurance)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VnLv :label="t('customer.card.debt')" :value="toCurrency(entity.debt)" />
|
<VnLv
|
||||||
<VnLv v-if="entity.salesPersonUser" :label="t('customer.card.salesPerson')">
|
:label="t('customer.card.debt')"
|
||||||
|
:value="toCurrency(entity.debt)"
|
||||||
|
:info="t('customer.summary.riskInfo')"
|
||||||
|
/>
|
||||||
|
<VnLv :label="t('customer.card.salesPerson')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<VnUserLink
|
||||||
:name="entity.salesPersonUser?.name"
|
v-if="entity.salesPersonUser"
|
||||||
|
:name="entity.salesPersonUser.name"
|
||||||
:worker-id="entity.salesPersonFk"
|
:worker-id="entity.salesPersonFk"
|
||||||
/>
|
/>
|
||||||
|
<span v-else>{{ dashIfEmpty(entity.salesPersonUser) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.card.businessTypeFk')"
|
:label="t('customer.card.businessTypeFk')"
|
||||||
:value="entity.businessTypeFk"
|
:value="entity.businessType.description"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #icons="{ entity }">
|
<template #icons>
|
||||||
<QCardActions class="q-gutter-x-md">
|
<QCardActions v-if="customer" class="q-gutter-x-md">
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="!entity.isActive"
|
v-if="!customer.isActive"
|
||||||
name="vn:disabled"
|
name="vn:disabled"
|
||||||
size="xs"
|
size="xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.isDisabled') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon v-if="entity.isFreezed" name="vn:frozen" size="xs" color="primary">
|
<QIcon
|
||||||
|
v-if="customer.isFreezed"
|
||||||
|
name="vn:frozen"
|
||||||
|
size="xs"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.isFrozen') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="!entity.account.active"
|
v-if="!customer.account?.active"
|
||||||
color="primary"
|
color="primary"
|
||||||
name="vn:noweb"
|
name="vn:noweb"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
@ -93,7 +108,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
<QTooltip>{{ t('customer.card.webAccountInactive') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.webAccountInactive') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="entity.debt > entity.credit"
|
v-if="customer.debt > customer.credit"
|
||||||
name="vn:risk"
|
name="vn:risk"
|
||||||
size="xs"
|
size="xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -101,7 +116,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.hasDebt') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="!entity.isTaxDataChecked"
|
v-if="!customer.isTaxDataChecked"
|
||||||
name="vn:no036"
|
name="vn:no036"
|
||||||
size="xs"
|
size="xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
|
@ -109,7 +124,7 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
<QTooltip>{{ t('customer.card.notChecked') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QBtn
|
<QBtn
|
||||||
v-if="entity.unpaid"
|
v-if="customer.unpaid"
|
||||||
flat
|
flat
|
||||||
size="sm"
|
size="sm"
|
||||||
icon="vn:Client_unpaid"
|
icon="vn:Client_unpaid"
|
||||||
|
@ -121,13 +136,13 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
<br />
|
<br />
|
||||||
{{
|
{{
|
||||||
t('unpaidDated', {
|
t('unpaidDated', {
|
||||||
dated: toDate(entity.unpaid.dated),
|
dated: toDate(customer.unpaid.dated),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
<br />
|
<br />
|
||||||
{{
|
{{
|
||||||
t('unpaidAmount', {
|
t('unpaidAmount', {
|
||||||
amount: toCurrency(entity.unpaid.amount),
|
amount: toCurrency(customer.unpaid.amount),
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
|
@ -139,7 +154,13 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
<QBtn
|
<QBtn
|
||||||
:to="{
|
:to="{
|
||||||
name: 'TicketList',
|
name: 'TicketList',
|
||||||
query: { table: JSON.stringify({ clientFk: entity.id }) },
|
query: {
|
||||||
|
from: undefined,
|
||||||
|
to: undefined,
|
||||||
|
table: JSON.stringify({
|
||||||
|
clientFk: entity.id,
|
||||||
|
}),
|
||||||
|
},
|
||||||
}"
|
}"
|
||||||
size="md"
|
size="md"
|
||||||
icon="vn:ticket"
|
icon="vn:ticket"
|
||||||
|
@ -160,23 +181,8 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
</QBtn>
|
</QBtn>
|
||||||
<QBtn
|
<QBtn
|
||||||
:to="{
|
:to="{
|
||||||
name: 'OrderCreate',
|
name: 'AccountSummary',
|
||||||
query: { clientId: entity.id },
|
params: { id: entity.id },
|
||||||
}"
|
|
||||||
size="md"
|
|
||||||
icon="vn:basketadd"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('New order') }}</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
<QBtn
|
|
||||||
:to="{
|
|
||||||
name: 'AccountList',
|
|
||||||
query: {
|
|
||||||
table: JSON.stringify({
|
|
||||||
filter: { where: { id: entity.id } },
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}"
|
}"
|
||||||
size="md"
|
size="md"
|
||||||
icon="face"
|
icon="face"
|
||||||
|
@ -184,6 +190,18 @@ const setData = (entity) => (data.value = useCardDescription(entity?.name, entit
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('Go to user') }}</QTooltip>
|
<QTooltip>{{ t('Go to user') }}</QTooltip>
|
||||||
</QBtn>
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
v-if="entity.supplier"
|
||||||
|
:to="{
|
||||||
|
name: 'SupplierSummary',
|
||||||
|
params: { id: entity.supplier.id },
|
||||||
|
}"
|
||||||
|
size="md"
|
||||||
|
icon="vn:supplier"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('Go to supplier') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
</QCardActions>
|
</QCardActions>
|
||||||
</template>
|
</template>
|
||||||
</CardDescriptor>
|
</CardDescriptor>
|
||||||
jsegarra marked this conversation as resolved
Outdated
alexm
commented
Comentado? Comentado?
|
|||||||
|
@ -197,8 +215,8 @@ es:
|
||||||
Go to module index: Ir al índice del módulo
|
Go to module index: Ir al índice del módulo
|
||||||
Customer ticket list: Listado de tickets del cliente
|
Customer ticket list: Listado de tickets del cliente
|
||||||
Customer invoice out list: Listado de facturas del cliente
|
Customer invoice out list: Listado de facturas del cliente
|
||||||
New order: Nuevo pedido
|
|
||||||
Go to user: Ir al usuario
|
Go to user: Ir al usuario
|
||||||
|
Go to supplier: Ir al proveedor
|
||||||
Customer unpaid: Cliente impago
|
Customer unpaid: Cliente impago
|
||||||
Unpaid: Impagado
|
Unpaid: Impagado
|
||||||
unpaidDated: 'Fecha {dated}'
|
unpaidDated: 'Fecha {dated}'
|
||||||
|
|
|
@ -8,6 +8,9 @@ import { useQuasar } from 'quasar';
|
||||||
import useNotify from 'src/composables/useNotify';
|
import useNotify from 'src/composables/useNotify';
|
||||||
|
|
||||||
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
|
import VnSmsDialog from 'src/components/common/VnSmsDialog.vue';
|
||||||
|
import TicketCreateDialog from 'src/pages/Ticket/TicketCreateDialog.vue';
|
||||||
|
import OrderCreateDialog from 'src/pages/Order/Card/OrderCreateDialog.vue';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
customer: {
|
customer: {
|
||||||
|
@ -40,20 +43,32 @@ const sendSms = async (payload) => {
|
||||||
notify(error.message, 'positive');
|
notify(error.message, 'positive');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ticketCreateFormDialog = ref(null);
|
||||||
|
const openTicketCreateForm = () => {
|
||||||
|
ticketCreateFormDialog.value.show();
|
||||||
|
};
|
||||||
|
const orderCreateFormDialog = ref(null);
|
||||||
|
const openOrderCreateForm = () => {
|
||||||
|
orderCreateFormDialog.value.show();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<QItem v-ripple clickable>
|
<QItem v-ripple clickable @click="openTicketCreateForm()">
|
||||||
jsegarra marked this conversation as resolved
Outdated
jgallego
commented
los comentarios no suben los comentarios no suben
|
|||||||
<QItemSection>
|
<QItemSection>
|
||||||
<RouterLink
|
{{ t('globals.pageTitles.createTicket') }}
|
||||||
:to="{
|
<QDialog ref="ticketCreateFormDialog">
|
||||||
name: 'TicketCreate',
|
<TicketCreateDialog />
|
||||||
query: { clientFk: customer.id },
|
</QDialog>
|
||||||
}"
|
</QItemSection>
|
||||||
class="color-vn-text"
|
</QItem>
|
||||||
>
|
<QItem v-ripple clickable @click="openOrderCreateForm()">
|
||||||
{{ t('Simple ticket') }}
|
<QItemSection>
|
||||||
</RouterLink>
|
{{ t('globals.pageTitles.createOrder') }}
|
||||||
|
<QDialog ref="orderCreateFormDialog">
|
||||||
|
<OrderCreateDialog :client-fk="customer.id" />
|
||||||
|
</QDialog>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
alexm
commented
Se quitan? Se quitan?
jsegarra
commented
Se mueve la funcionalidad del DescriptorMenu a botón en Descriptor actions Se mueve la funcionalidad del DescriptorMenu a botón en Descriptor actions
|
|||||||
<QItem v-ripple clickable>
|
<QItem v-ripple clickable>
|
||||||
|
|
|
@ -236,6 +236,7 @@ const toCustomerFileManagementCreate = () => {
|
||||||
@click.stop="toCustomerFileManagementCreate()"
|
@click.stop="toCustomerFileManagementCreate()"
|
||||||
color="primary"
|
color="primary"
|
||||||
fab
|
fab
|
||||||
|
shortcut="+"
|
||||||
icon="add"
|
icon="add"
|
||||||
/>
|
/>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
|
|
|
@ -135,15 +135,17 @@ function handleLocation(data, location) {
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
<QCheckbox :label="t('Verified data')" v-model="data.isTaxDataChecked" />
|
<QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('Electronic invoice')"
|
:label="t('Electronic invoice')"
|
||||||
v-model="data.hasElectronicInvoice"
|
v-model="data.hasElectronicInvoice"
|
||||||
|
/><QCheckbox
|
||||||
|
:label="t('Verified data')"
|
||||||
|
v-model="data.isTaxDataChecked"
|
||||||
/>
|
/>
|
||||||
<QCheckbox :label="t('Daily invoice')" v-model="data.hasDailyInvoice" />
|
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</template>
|
</template>
|
||||||
</FormModel>
|
</FormModel>
|
||||||
|
|
|
@ -5,10 +5,10 @@ import { useRoute } from 'vue-router';
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency } from 'src/filters';
|
||||||
import { toDateTimeFormat } from 'src/filters/date';
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
const entityId = computed(() => route.params.id);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const rows = ref([]);
|
|
||||||
const totalAmount = ref();
|
const totalAmount = ref();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const filter = computed(() => {
|
const filter = computed(() => {
|
||||||
|
@ -28,7 +28,7 @@ const filter = computed(() => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
where: {
|
where: {
|
||||||
clientFk: route.params.id,
|
clientFk: entityId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -47,7 +47,6 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'userFk',
|
|
||||||
label: t('Created by'),
|
label: t('Created by'),
|
||||||
component: 'userLink',
|
component: 'userLink',
|
||||||
attrs: ({ row }) => {
|
attrs: ({ row }) => {
|
||||||
|
@ -73,6 +72,7 @@ const columns = computed(() => [
|
||||||
columnCreate: {
|
columnCreate: {
|
||||||
component: 'select',
|
component: 'select',
|
||||||
url: 'greugeTypes',
|
url: 'greugeTypes',
|
||||||
|
sortBy: 'name ASC ',
|
||||||
limit: 0,
|
limit: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -84,14 +84,14 @@ const columns = computed(() => [
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const setRows = (data) => {
|
|
||||||
rows.value = data;
|
|
||||||
totalAmount.value = data.reduce((acc, { amount = 0 }) => acc + amount, 0);
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<FetchData
|
||||||
|
:url="`Greuges/${entityId}/sumAmount`"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="({ sumAmount }) => (totalAmount = sumAmount)"
|
||||||
|
></FetchData>
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="Greuges"
|
data-key="Greuges"
|
||||||
|
@ -104,10 +104,10 @@ const setRows = (data) => {
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
:column-search="false"
|
:column-search="false"
|
||||||
@on-fetch="(data) => setRows(data)"
|
:disable-option="{ card: true }"
|
||||||
:create="{
|
:create="{
|
||||||
urlCreate: `Greuges`,
|
urlCreate: `Greuges`,
|
||||||
title: t('New credit'),
|
title: t('New greuge'),
|
||||||
onDataSaved: () => tableRef.reload(),
|
onDataSaved: () => tableRef.reload(),
|
||||||
formInitialData: { shipped: new Date(), clientFk: route.params.id },
|
formInitialData: { shipped: new Date(), clientFk: route.params.id },
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,20 +1,19 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { toDateTimeFormat } from 'src/filters/date';
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const rows = ref([]);
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: [
|
include: [
|
||||||
{ relation: 'mandateType', scope: { fields: ['id', 'name'] } },
|
{ relation: 'mandateType', scope: { fields: ['id', 'code'] } },
|
||||||
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
{ relation: 'company', scope: { fields: ['id', 'code'] } },
|
||||||
],
|
],
|
||||||
where: { clientFk: route.params.id },
|
where: { clientFk: route.params.id },
|
||||||
|
@ -22,114 +21,61 @@ const filter = {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableColumnComponents = {
|
|
||||||
id: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
company: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
registerDate: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
endDate: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'id',
|
|
||||||
label: t('Id'),
|
|
||||||
name: 'id',
|
name: 'id',
|
||||||
|
label: t('globals.id'),
|
||||||
|
field: 'id',
|
||||||
|
isId: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (row) => row.company.code,
|
cardVisible: true,
|
||||||
label: t('Company'),
|
format: ({ company }) => company.code,
|
||||||
|
label: t('globals.company'),
|
||||||
name: 'company',
|
name: 'company',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (row) => row.mandateType.name,
|
cardVisible: true,
|
||||||
label: t('Type'),
|
format: ({ mandateType }) => mandateType.code,
|
||||||
|
label: t('globals.type'),
|
||||||
name: 'type',
|
name: 'type',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'created',
|
cardVisible: true,
|
||||||
label: t('Register date'),
|
label: t('Register date'),
|
||||||
name: 'registerDate',
|
name: 'created',
|
||||||
format: (value) => toDateTimeFormat(value),
|
format: ({ created }) => toDateTimeFormat(created),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
field: 'finished',
|
cardVisible: true,
|
||||||
|
name: 'finished',
|
||||||
label: t('End date'),
|
label: t('End date'),
|
||||||
name: 'endDate',
|
format: ({ finished }) => dashIfEmpty(toDateTimeFormat(finished)),
|
||||||
format: (value) => (value ? toDateTimeFormat(value) : '-'),
|
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
:filter="filter"
|
|
||||||
@on-fetch="(data) => (rows = data)"
|
|
||||||
auto-load
|
|
||||||
url="Mandates"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<QPage class="column items-center q-pa-md">
|
<QPage class="column items-center q-pa-md">
|
||||||
<QTable
|
<VnTable
|
||||||
|
:filter="filter"
|
||||||
|
auto-load
|
||||||
|
url="Mandates"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:pagination="{ rowsPerPage: 12 }"
|
|
||||||
:rows="rows"
|
|
||||||
class="full-width q-mt-md"
|
class="full-width q-mt-md"
|
||||||
row-key="id"
|
:right-search="false"
|
||||||
v-if="rows?.length"
|
:row-click="false"
|
||||||
>
|
/>
|
||||||
<template #body-cell="props">
|
|
||||||
<QTd :props="props">
|
|
||||||
<QTr :props="props" class="cursor-pointer">
|
|
||||||
<component
|
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
|
||||||
class="rounded-borders q-pa-sm"
|
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
|
||||||
>
|
|
||||||
{{ props.value }}
|
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
|
|
||||||
<h5 class="flex justify-center color-vn-label" v-else>
|
|
||||||
{{ t('globals.noResults') }}
|
|
||||||
</h5>
|
|
||||||
</QPage>
|
</QPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Id: Id
|
|
||||||
Company: Empresa
|
|
||||||
Type: Tipo
|
|
||||||
Register date: Fecha alta
|
Register date: Fecha alta
|
||||||
End date: Fecha baja
|
End date: Fecha baja
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -89,9 +89,10 @@ function setFinished(id) {
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
:create="{
|
:create="{
|
||||||
urlCreate: 'Recoveries',
|
urlCreate: 'Recoveries',
|
||||||
title: 'New recovery',
|
title: t('New recovery'),
|
||||||
onDataSaved: () => tableRef.reload(),
|
onDataSaved: () => tableRef.reload(),
|
||||||
formInitialData: { clientFk: route.params.id, started: Date.vnNew() },
|
formInitialData: { clientFk: route.params.id, started: Date.vnNew() },
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -1,19 +1,18 @@
|
||||||
<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 { useRoute, useRouter } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { QBtn } from 'quasar';
|
import { QBtn, useQuasar } from 'quasar';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import { toDateTimeFormat } from 'src/filters/date';
|
import { toDateTimeFormat } from 'src/filters/date';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
import { dashIfEmpty } from 'src/filters';
|
||||||
|
import CustomerSamplesCreate from '../components/CustomerSamplesCreate.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
const rows = ref([]);
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -26,108 +25,87 @@ const filter = {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableColumnComponents = {
|
|
||||||
sent: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
worker: {
|
|
||||||
component: QBtn,
|
|
||||||
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
company: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'created',
|
name: 'created',
|
||||||
label: t('Sent'),
|
label: t('Sent'),
|
||||||
name: 'sent',
|
format: ({ created }) => toDateTimeFormat(created),
|
||||||
format: (value) => toDateTimeFormat(value),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (value) => value.type.description,
|
format: (row) => row.type.description,
|
||||||
label: t('Description'),
|
label: t('Description'),
|
||||||
name: 'description',
|
name: 'description',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (value) => value.user.name,
|
|
||||||
label: t('Worker'),
|
label: t('Worker'),
|
||||||
name: 'worker',
|
columnField: {
|
||||||
|
component: 'userLink',
|
||||||
|
attrs: ({ row }) => {
|
||||||
|
return {
|
||||||
|
defaultName: true,
|
||||||
|
workerId: row?.user?.id,
|
||||||
|
name: row?.user?.name,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (value) => value.company?.code,
|
format: ({ company }) => company?.code ?? dashIfEmpty(company),
|
||||||
label: t('Company'),
|
label: t('Company'),
|
||||||
name: 'company',
|
name: 'company',
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
const quasar = useQuasar();
|
||||||
|
|
||||||
const toCustomerSamplesCreate = () => {
|
const toCustomerSamplesCreate = () => {
|
||||||
router.push({ name: 'CustomerSamplesCreate' });
|
quasar
|
||||||
|
.dialog({
|
||||||
|
component: CustomerSamplesCreate,
|
||||||
|
})
|
||||||
|
.onOk(() => tableRef.value.reload());
|
||||||
};
|
};
|
||||||
|
const tableRef = ref();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<VnTable
|
||||||
:filter="filter"
|
ref="tableRef"
|
||||||
@on-fetch="(data) => (rows = data)"
|
data-key="ClientSamples"
|
||||||
auto-load
|
auto-load
|
||||||
|
:filter="filter"
|
||||||
url="ClientSamples"
|
url="ClientSamples"
|
||||||
/>
|
:columns="columns"
|
||||||
|
:pagination="{ rowsPerPage: 12 }"
|
||||||
<div class="full-width flex justify-center">
|
:disable-option="{ card: true }"
|
||||||
<QPage class="card-width q-pa-lg">
|
:right-search="false"
|
||||||
<QTable
|
:rows="rows"
|
||||||
:columns="columns"
|
:order="['created DESC']"
|
||||||
:pagination="{ rowsPerPage: 12 }"
|
class="full-width q-mt-md"
|
||||||
:rows="rows"
|
row-key="id"
|
||||||
class="full-width q-mt-md"
|
:create="false"
|
||||||
row-key="id"
|
:no-data-label="t('globals.noResults')"
|
||||||
:no-data-label="t('globals.noResults')"
|
>
|
||||||
>
|
<template #column-worker="{ row }">
|
||||||
<template #body-cell="props">
|
<div v-if="row.user">
|
||||||
<QTd :props="props">
|
<span class="link">{{ row.user?.name }}</span
|
||||||
<QTr :props="props" class="cursor-pointer">
|
><WorkerDescriptorProxy :id="row.userFk" />
|
||||||
<component
|
</div>
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
<span v-else>{{ dashIfEmpty(row.user) }}</span>
|
||||||
class="col-content"
|
</template>
|
||||||
v-bind="
|
</VnTable>
|
||||||
tableColumnComponents[props.col.name].props(props)
|
|
||||||
"
|
|
||||||
@click="
|
|
||||||
tableColumnComponents[props.col.name].event(props)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
{{ props.value }}
|
|
||||||
<WorkerDescriptorProxy
|
|
||||||
:id="props.row.userFk"
|
|
||||||
v-if="props.col.name === 'worker'"
|
|
||||||
/>
|
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
</QPage>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="toCustomerSamplesCreate()" color="primary" fab icon="add" />
|
<QBtn
|
||||||
|
@click.stop="toCustomerSamplesCreate()"
|
||||||
|
color="primary"
|
||||||
|
fab
|
||||||
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
|
/>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Send sample') }}
|
{{ t('Send sample') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref, onMounted } 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 } from 'src/filters';
|
import { toCurrency, toPercentage, toDate } from 'src/filters';
|
||||||
import CardSummary from 'components/ui/CardSummary.vue';
|
import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import { getUrl } from 'src/composables/getUrl';
|
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
||||||
import CustomerSummaryTable from 'src/pages/Customer/components/CustomerSummaryTable.vue';
|
import CustomerSummaryTable from 'src/pages/Customer/components/CustomerSummaryTable.vue';
|
||||||
|
@ -24,11 +25,6 @@ const $props = defineProps({
|
||||||
const entityId = computed(() => $props.id || route.params.id);
|
const entityId = computed(() => $props.id || route.params.id);
|
||||||
const customer = computed(() => summary.value.entity);
|
const customer = computed(() => summary.value.entity);
|
||||||
const summary = ref();
|
const summary = ref();
|
||||||
const clientUrl = ref();
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
clientUrl.value = (await getUrl('client/')) + entityId.value + '/';
|
|
||||||
});
|
|
||||||
|
|
||||||
jsegarra marked this conversation as resolved
Outdated
alexm
commented
No se usa no? No se usa no?
jsegarra
commented
En quasar build no sale el warning. En quasar build no sale el warning.
Se usa en el onMounted
|
|||||||
const balanceDue = computed(() => {
|
const balanceDue = computed(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -41,11 +37,11 @@ const balanceDue = computed(() => {
|
||||||
const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : ''));
|
const balanceDueWarning = computed(() => (balanceDue.value ? 'negative' : ''));
|
||||||
|
|
||||||
const claimRate = computed(() => {
|
const claimRate = computed(() => {
|
||||||
return customer.value.claimsRatio.claimingRate;
|
return customer.value.claimsRatio?.claimingRate ?? 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
const priceIncreasingRate = computed(() => {
|
const priceIncreasingRate = computed(() => {
|
||||||
return customer.value.claimsRatio.priceIncreasing / 100;
|
return customer.value.claimsRatio?.priceIncreasing ?? 0 / 100;
|
||||||
});
|
});
|
||||||
|
|
||||||
const debtWarning = computed(() => {
|
const debtWarning = computed(() => {
|
||||||
|
@ -59,6 +55,11 @@ const creditWarning = computed(() => {
|
||||||
|
|
||||||
return tooMuchInsurance || noCreditInsurance ? 'negative' : '';
|
return tooMuchInsurance || noCreditInsurance ? 'negative' : '';
|
||||||
});
|
});
|
||||||
|
const sumRisk = ({ clientRisks }) => {
|
||||||
|
let total = clientRisks.reduce((acc, { amount }) => acc + amount, 0);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -92,7 +93,13 @@ const creditWarning = computed(() => {
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.salesPerson')"
|
:label="t('customer.summary.salesPerson')"
|
||||||
:value="entity?.salesPersonUser?.name"
|
:value="entity?.salesPersonUser?.name"
|
||||||
/>
|
>
|
||||||
|
<template #value>
|
||||||
|
<VnUserLink
|
||||||
|
:name="entity.salesPersonUser?.name"
|
||||||
|
:worker-id="entity.salesPersonFk"
|
||||||
|
/> </template
|
||||||
|
></VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.contactChannel')"
|
:label="t('customer.summary.contactChannel')"
|
||||||
:value="entity?.contactChannel?.name"
|
:value="entity?.contactChannel?.name"
|
||||||
|
@ -132,7 +139,7 @@ const creditWarning = computed(() => {
|
||||||
:url="`#/customer/${entityId}/fiscal-data`"
|
:url="`#/customer/${entityId}/fiscal-data`"
|
||||||
:text="t('customer.summary.fiscalData')"
|
:text="t('customer.summary.fiscalData')"
|
||||||
/>
|
/>
|
||||||
<VnRow>
|
<VnRow class="block">
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.isEqualizated')"
|
:label="t('customer.summary.isEqualizated')"
|
||||||
:value="entity.isEqualizated"
|
:value="entity.isEqualizated"
|
||||||
|
@ -141,8 +148,6 @@ const creditWarning = computed(() => {
|
||||||
:label="t('customer.summary.isActive')"
|
:label="t('customer.summary.isActive')"
|
||||||
:value="entity.isActive"
|
:value="entity.isActive"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
|
||||||
<VnRow>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.verifiedData')"
|
:label="t('customer.summary.verifiedData')"
|
||||||
:value="entity.isTaxDataChecked"
|
:value="entity.isTaxDataChecked"
|
||||||
|
@ -151,8 +156,6 @@ const creditWarning = computed(() => {
|
||||||
:label="t('customer.summary.hasToInvoice')"
|
:label="t('customer.summary.hasToInvoice')"
|
||||||
:value="entity.hasToInvoice"
|
:value="entity.hasToInvoice"
|
||||||
/>
|
/>
|
||||||
</VnRow>
|
|
||||||
<VnRow>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.notifyByEmail')"
|
:label="t('customer.summary.notifyByEmail')"
|
||||||
:value="entity.isToBeMailed"
|
:value="entity.isToBeMailed"
|
||||||
|
@ -163,7 +166,7 @@ const creditWarning = computed(() => {
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<VnTitle
|
<VnTitle
|
||||||
:url="`#/customer/${entityId}/billing-data`"
|
:url="`#/customer/${entityId}/billing-data`"
|
||||||
:text="t('customer.summary.billingData')"
|
:text="t('customer.summary.payMethodFk')"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.payMethod')"
|
:label="t('customer.summary.payMethod')"
|
||||||
|
@ -171,7 +174,7 @@ const creditWarning = computed(() => {
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('customer.summary.bankAccount')" :value="entity.iban" />
|
<VnLv :label="t('customer.summary.bankAccount')" :value="entity.iban" />
|
||||||
<VnLv :label="t('customer.summary.dueDay')" :value="entity.dueDay" />
|
<VnLv :label="t('customer.summary.dueDay')" :value="entity.dueDay" />
|
||||||
<VnRow class="q-mt-sm" wrap>
|
<VnRow class="q-mt-sm block">
|
||||||
<VnLv :label="t('customer.summary.hasLcr')" :value="entity.hasLcr" />
|
<VnLv :label="t('customer.summary.hasLcr')" :value="entity.hasLcr" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.hasCoreVnl')"
|
:label="t('customer.summary.hasCoreVnl')"
|
||||||
|
@ -186,7 +189,7 @@ const creditWarning = computed(() => {
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one" v-if="entity.defaultAddress">
|
<QCard class="vn-one" v-if="entity.defaultAddress">
|
||||||
<VnTitle
|
<VnTitle
|
||||||
:url="`#/customer/${entityId}/consignees`"
|
:url="`#/customer/${entityId}/address`"
|
||||||
:text="t('customer.summary.consignee')"
|
:text="t('customer.summary.consignee')"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
|
@ -219,7 +222,7 @@ const creditWarning = computed(() => {
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one" v-if="entity.account">
|
<QCard class="vn-one" v-if="entity.account">
|
||||||
<VnTitle
|
<VnTitle
|
||||||
:url="`https://grafana.verdnatura.es/d/adjlxzv5yjt34d/analisis-de-clientes-7c-crm?orgId=1&var-clientFk=${entityId}`"
|
:url="`${grafanaUrl}/d/adjlxzv5yjt34d/analisis-de-clientes-7c-crm?orgId=1&var-clientFk=${entityId}`"
|
||||||
:text="t('customer.summary.businessData')"
|
:text="t('customer.summary.businessData')"
|
||||||
icon="vn:grafana"
|
icon="vn:grafana"
|
||||||
/>
|
/>
|
||||||
|
@ -232,7 +235,6 @@ const creditWarning = computed(() => {
|
||||||
:value="toCurrency(entity?.mana?.mana)"
|
:value="toCurrency(entity?.mana?.mana)"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
v-if="entity.claimsRatio"
|
|
||||||
:label="t('customer.summary.priceIncreasingRate')"
|
:label="t('customer.summary.priceIncreasingRate')"
|
||||||
:value="toPercentage(priceIncreasingRate)"
|
:value="toPercentage(priceIncreasingRate)"
|
||||||
/>
|
/>
|
||||||
|
@ -241,15 +243,14 @@ const creditWarning = computed(() => {
|
||||||
:value="toCurrency(entity?.averageInvoiced?.invoiced)"
|
:value="toCurrency(entity?.averageInvoiced?.invoiced)"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
v-if="entity.claimsRatio"
|
|
||||||
:label="t('customer.summary.claimRate')"
|
:label="t('customer.summary.claimRate')"
|
||||||
:value="toPercentage(claimRate)"
|
:value="toPercentage(claimRate)"
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one" v-if="entity.account">
|
<QCard class="vn-one" v-if="entity.account">
|
||||||
<VnTitle
|
<VnTitle
|
||||||
:url="`https://grafana.verdnatura.es/d/40buzE4Vk/comportamiento-pagos-clientes?orgId=1&var-clientFk=${entityId}`"
|
:url="`${grafanaUrl}/d/40buzE4Vk/comportamiento-pagos-clientes?orgId=1&var-clientFk=${entityId}`"
|
||||||
:text="t('customer.summary.financialData')"
|
:text="t('customer.summary.payMethodFk')"
|
||||||
icon="vn:grafana"
|
icon="vn:grafana"
|
||||||
/>
|
/>
|
||||||
<VnLv
|
<VnLv
|
||||||
|
@ -267,15 +268,13 @@ const creditWarning = computed(() => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VnLv
|
<VnLv
|
||||||
v-if="entity.creditInsurance"
|
|
||||||
:label="t('customer.summary.securedCredit')"
|
:label="t('customer.summary.securedCredit')"
|
||||||
:value="toCurrency(entity.creditInsurance)"
|
:value="toCurrency(entity.creditInsurance)"
|
||||||
:info="t('customer.summary.securedCreditInfo')"
|
:info="t('customer.summary.securedCreditInfo')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('customer.summary.balance')"
|
:label="t('customer.summary.balance')"
|
||||||
:value="toCurrency(entity.sumRisk) || toCurrency(0)"
|
:value="toCurrency(sumRisk(entity)) || toCurrency(0)"
|
||||||
:info="t('customer.summary.balanceInfo')"
|
:info="t('customer.summary.balanceInfo')"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -302,7 +301,7 @@ const creditWarning = computed(() => {
|
||||||
:value="entity.recommendedCredit"
|
:value="entity.recommendedCredit"
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard>
|
||||||
<VnTitle :text="t('Latest tickets')" />
|
<VnTitle :text="t('Latest tickets')" />
|
||||||
<CustomerSummaryTable />
|
<CustomerSummaryTable />
|
||||||
</QCard>
|
</QCard>
|
||||||
|
|
|
@ -151,7 +151,10 @@ watch(
|
||||||
clearable
|
clearable
|
||||||
type="number"
|
type="number"
|
||||||
v-model="amount"
|
v-model="amount"
|
||||||
/>
|
autofocus
|
||||||
|
>
|
||||||
|
<template #append>€</template></VnInput
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</QForm>
|
</QForm>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import { toCurrency, toDateHourMinSec } from 'src/filters';
|
import { toCurrency, toDateHourMin } from 'src/filters';
|
||||||
|
|
||||||
import CustomerCloseIconTooltip from '../components/CustomerCloseIconTooltip.vue';
|
import CustomerCloseIconTooltip from '../components/CustomerCloseIconTooltip.vue';
|
||||||
import CustomerCheckIconTooltip from '../components/CustomerCheckIconTooltip.vue';
|
import CustomerCheckIconTooltip from '../components/CustomerCheckIconTooltip.vue';
|
||||||
|
@ -74,7 +74,7 @@ const columns = computed(() => [
|
||||||
field: 'created',
|
field: 'created',
|
||||||
label: t('Date'),
|
label: t('Date'),
|
||||||
name: 'date',
|
name: 'date',
|
||||||
format: (value) => toDateHourMinSec(value),
|
format: (value) => toDateHourMin(value),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
|
|
@ -1,35 +1,20 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
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';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
defineProps({
|
||||||
dataKey: {
|
dataKey: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const provinces = ref();
|
|
||||||
const workers = ref();
|
|
||||||
const zones = ref();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData url="Provinces" @on-fetch="(data) => (provinces = data)" auto-load />
|
<VnFilterPanel :data-key="dataKey" :search-button="true" search-url="table">
|
||||||
<FetchData url="Zones" @on-fetch="(data) => (zones = data)" auto-load />
|
|
||||||
<FetchData
|
|
||||||
url="Workers/activeWithInheritedRole"
|
|
||||||
:filter="{ where: { role: 'salesPerson' } }"
|
|
||||||
@on-fetch="(data) => (workers = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<VnFilterPanel :data-key="props.dataKey" :search-button="true" search-url="table">
|
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
@ -65,15 +50,14 @@ const zones = ref();
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection v-if="!workers">
|
<QItemSection>
|
||||||
<QSkeleton type="QInput" class="full-width" />
|
|
||||||
</QItemSection>
|
|
||||||
<QItemSection v-if="workers">
|
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
url="Workers/activeWithInheritedRole"
|
||||||
|
:filter="{ where: { role: 'salesPerson' } }"
|
||||||
|
auto-load
|
||||||
:label="t('Salesperson')"
|
:label="t('Salesperson')"
|
||||||
v-model="params.salesPersonFk"
|
v-model="params.salesPersonFk"
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
:options="workers"
|
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
emit-value
|
emit-value
|
||||||
|
@ -88,15 +72,12 @@ const zones = ref();
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem class="q-mb-sm">
|
<QItem class="q-mb-sm">
|
||||||
<QItemSection v-if="!provinces">
|
<QItemSection
|
||||||
<QSkeleton type="QInput" class="full-width" />
|
><VnSelect
|
||||||
</QItemSection>
|
url="Provinces"
|
||||||
<QItemSection v-if="provinces">
|
|
||||||
<VnSelect
|
|
||||||
:label="t('Province')"
|
:label="t('Province')"
|
||||||
v-model="params.provinceFk"
|
v-model="params.provinceFk"
|
||||||
@update:model-value="searchFn()"
|
@update:model-value="searchFn()"
|
||||||
:options="provinces"
|
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
emit-value
|
emit-value
|
||||||
|
@ -105,6 +86,7 @@ const zones = ref();
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
auto-load
|
||||||
:input-debounce="0"
|
:input-debounce="0"
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
|
@ -135,25 +117,21 @@ const zones = ref();
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection v-if="!zones">
|
<VnSelect
|
||||||
<QSkeleton type="QInput" class="full-width" />
|
url="Zones"
|
||||||
</QItemSection>
|
:label="t('Zone')"
|
||||||
<QItemSection v-if="zones">
|
v-model="params.zoneFk"
|
||||||
<VnSelect
|
@update:model-value="searchFn()"
|
||||||
:label="t('Zone')"
|
option-value="id"
|
||||||
v-model="params.zoneFk"
|
option-label="name"
|
||||||
@update:model-value="searchFn()"
|
emit-value
|
||||||
:options="zones"
|
map-options
|
||||||
option-value="id"
|
hide-selected
|
||||||
option-label="name"
|
dense
|
||||||
emit-value
|
outlined
|
||||||
map-options
|
rounded
|
||||||
hide-selected
|
auto-load
|
||||||
dense
|
/>
|
||||||
outlined
|
|
||||||
rounded
|
|
||||||
/>
|
|
||||||
</QItemSection>
|
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem>
|
<QItem>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
|
|
|
@ -8,10 +8,10 @@ import VnLocation from 'src/components/common/VnLocation.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
import CustomerSummary from './Card/CustomerSummary.vue';
|
import CustomerSummary from './Card/CustomerSummary.vue';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
import VnLinkPhone from 'src/components/ui/VnLinkPhone.vue';
|
||||||
|
|
||||||
import { toDate } from 'src/filters';
|
import { toDate } from 'src/filters';
|
||||||
|
import CustomerFilter from './CustomerFilter.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -396,6 +396,11 @@ function handleLocation(data, location) {
|
||||||
:label="t('Search customer')"
|
:label="t('Search customer')"
|
||||||
data-key="Customer"
|
data-key="Customer"
|
||||||
/>
|
/>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<CustomerFilter data-key="Customer" />
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="Customer"
|
data-key="Customer"
|
||||||
|
@ -412,6 +417,7 @@ function handleLocation(data, location) {
|
||||||
order="id DESC"
|
order="id DESC"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
redirect="customer"
|
redirect="customer"
|
||||||
|
:right-search="false"
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
|
|
|
@ -134,6 +134,7 @@ function handleLocation(data, location) {
|
||||||
option-label="fiscalName"
|
option-label="fiscalName"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.customsAgentFk"
|
v-model="data.customsAgentFk"
|
||||||
|
:tooltip="t('Create a new expense')"
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
|
<CustomerNewCustomsAgent @on-data-saved="refreshData()" />
|
||||||
|
|
|
@ -11,7 +11,7 @@ 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 VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
import VnSelectDialog from 'src/components/common/VnSelectDialog.vue';
|
||||||
import CustomsNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
|
import CustomerNewCustomsAgent from 'src/pages/Customer/components/CustomerNewCustomsAgent.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -226,9 +226,10 @@ function handleLocation(data, location) {
|
||||||
option-label="fiscalName"
|
option-label="fiscalName"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
v-model="data.customsAgentFk"
|
v-model="data.customsAgentFk"
|
||||||
|
:tooltip="t('New customs agent')"
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CustomsNewCustomsAgent />
|
<CustomerNewCustomsAgent />
|
||||||
</template>
|
</template>
|
||||||
</VnSelectDialog>
|
</VnSelectDialog>
|
||||||
</div>
|
</div>
|
||||||
|
@ -309,6 +310,7 @@ es:
|
||||||
Mobile: Movíl
|
Mobile: Movíl
|
||||||
Incoterms: Incoterms
|
Incoterms: Incoterms
|
||||||
Customs agent: Agente de aduanas
|
Customs agent: Agente de aduanas
|
||||||
|
New customs agent: Nuevo agente de aduanas
|
||||||
Notes: Notas
|
Notes: Notas
|
||||||
Observation type: Tipo de observación
|
Observation type: Tipo de observación
|
||||||
Description: Descripción
|
Description: Descripción
|
||||||
|
|
|
@ -46,7 +46,6 @@ const onSubmit = async () => {
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
await axios.patch(`Clients/${$props.id}/setPassword`, payload);
|
await axios.patch(`Clients/${$props.id}/setPassword`, payload);
|
||||||
await $props.promise();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notify('errors.create', 'negative');
|
notify('errors.create', 'negative');
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive } from 'vue';
|
import { reactive, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
@ -10,10 +10,12 @@ import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
const routeId = computed(() => route.params.id);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const initialData = reactive({
|
const initialData = reactive({
|
||||||
clientFK: Number(route.params.id),
|
started: Date.vnNew(),
|
||||||
|
clientFk: routeId.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
const toCustomerCreditContracts = () => {
|
const toCustomerCreditContracts = () => {
|
||||||
|
|
|
@ -1,47 +1,26 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
import { toCurrency, toDateHourMinSec } from 'src/filters';
|
import { toCurrency, toDate } from 'src/filters';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const rows = ref([]);
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
where: {
|
where: {
|
||||||
creditClassificationFk: `${route.params.creditId}`,
|
creditClassificationFk: `${route.params.creditId}`,
|
||||||
},
|
},
|
||||||
limit: 20,
|
limit: 20,
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableColumnComponents = {
|
|
||||||
created: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
grade: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
credit: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'created',
|
field: 'created',
|
||||||
format: (value) => toDateHourMinSec(value),
|
format: ({ created }) => toDate(created),
|
||||||
label: t('Created'),
|
label: t('Created'),
|
||||||
name: 'created',
|
name: 'created',
|
||||||
},
|
},
|
||||||
|
@ -53,8 +32,7 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'credit',
|
format: ({ credit }) => toCurrency(credit),
|
||||||
format: (value) => toCurrency(value),
|
|
||||||
label: t('Credit'),
|
label: t('Credit'),
|
||||||
name: 'credit',
|
name: 'credit',
|
||||||
},
|
},
|
||||||
|
@ -62,41 +40,19 @@ const columns = computed(() => [
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<VnTable
|
||||||
:filter="filter"
|
|
||||||
@on-fetch="(data) => (rows = data)"
|
|
||||||
auto-load
|
|
||||||
url="CreditInsurances"
|
url="CreditInsurances"
|
||||||
/>
|
ref="tableRef"
|
||||||
|
data-key="creditInsurances"
|
||||||
<QPage class="column items-center q-pa-md" v-if="rows.length">
|
:filter="filter"
|
||||||
<QTable
|
:columns="columns"
|
||||||
:columns="columns"
|
:right-search="false"
|
||||||
:pagination="{ rowsPerPage: 12 }"
|
:is-editable="false"
|
||||||
:rows="rows"
|
:use-model="true"
|
||||||
class="full-width q-mt-md"
|
:column-search="false"
|
||||||
row-key="id"
|
:disable-option="{ card: true }"
|
||||||
>
|
auto-load
|
||||||
<template #body-cell="props">
|
></VnTable>
|
||||||
<QTd :props="props">
|
|
||||||
<QTr :props="props" class="cursor-pointer">
|
|
||||||
<component
|
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
|
||||||
class="col-content"
|
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
|
||||||
>
|
|
||||||
{{ props.value }}
|
|
||||||
</component>
|
|
||||||
</QTr>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</QTable>
|
|
||||||
</QPage>
|
|
||||||
|
|
||||||
<h5 class="flex justify-center color-vn-label" v-else>
|
|
||||||
{{ t('globals.noResults') }}
|
|
||||||
</h5>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -83,35 +83,35 @@ const toCustomerFileManagement = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<fetch-data
|
<FetchData
|
||||||
@on-fetch="(data) => (client = data)"
|
@on-fetch="(data) => (client = data)"
|
||||||
auto-load
|
auto-load
|
||||||
:url="`Clients/${route.params.id}/getCard`"
|
:url="`Clients/${route.params.id}/getCard`"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterFindOne"
|
:filter="filterFindOne"
|
||||||
@on-fetch="(data) => (findOne = data)"
|
@on-fetch="(data) => (findOne = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="DmsTypes/findOne"
|
url="DmsTypes/findOne"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
@on-fetch="(data) => (allowedContentTypes = data)"
|
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="DmsContainers/allowedContentTypes"
|
url="DmsContainers/allowedContentTypes"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterCompanies"
|
:filter="filterCompanies"
|
||||||
@on-fetch="(data) => (optionsCompanies = data)"
|
@on-fetch="(data) => (optionsCompanies = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Companies"
|
url="Companies"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterWarehouses"
|
:filter="filterWarehouses"
|
||||||
@on-fetch="(data) => (optionsWarehouses = data)"
|
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterWarehouses"
|
:filter="filterWarehouses"
|
||||||
@on-fetch="(data) => (optionsDmsTypes = data)"
|
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
|
|
|
@ -69,25 +69,25 @@ const toCustomerFileManagement = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<fetch-data :url="`Dms/${route.params.dmsId}`" @on-fetch="setCurrentDms" auto-load />
|
<FetchData :url="`Dms/${route.params.dmsId}`" @on-fetch="setCurrentDms" auto-load />
|
||||||
<fetch-data
|
<FetchData
|
||||||
@on-fetch="(data) => (allowedContentTypes = data)"
|
@on-fetch="(data) => (allowedContentTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="DmsContainers/allowedContentTypes"
|
url="DmsContainers/allowedContentTypes"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterCompanies"
|
:filter="filterCompanies"
|
||||||
@on-fetch="(data) => (optionsCompanies = data)"
|
@on-fetch="(data) => (optionsCompanies = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Companies"
|
url="Companies"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterWarehouses"
|
:filter="filterWarehouses"
|
||||||
@on-fetch="(data) => (optionsWarehouses = data)"
|
@on-fetch="(data) => (optionsWarehouses = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Warehouses"
|
url="Warehouses"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterWarehouses"
|
:filter="filterWarehouses"
|
||||||
@on-fetch="(data) => (optionsDmsTypes = data)"
|
@on-fetch="(data) => (optionsDmsTypes = data)"
|
||||||
auto-load
|
auto-load
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onBeforeMount, reactive, ref } from 'vue';
|
import { computed, onBeforeMount, reactive, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { usePrintService } from 'composables/usePrintService';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
import { useQuasar } from 'quasar';
|
import { useDialogPluginComponent, useQuasar } from 'quasar';
|
||||||
|
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import { useValidator } from 'src/composables/useValidator';
|
import { useValidator } from 'src/composables/useValidator';
|
||||||
|
@ -17,7 +17,9 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import VnInput from 'src/components/common/VnInput.vue';
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
import CustomerSamplesPreview from 'src/pages/Customer/components/CustomerSamplesPreview.vue';
|
import CustomerSamplesPreview from 'src/pages/Customer/components/CustomerSamplesPreview.vue';
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
import FormPopup from 'src/components/FormPopup.vue';
|
||||||
|
|
||||||
|
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
||||||
|
|
||||||
const { notify } = useNotify();
|
const { notify } = useNotify();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -27,17 +29,17 @@ const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const state = useState();
|
const state = useState();
|
||||||
const user = state.getUser();
|
const user = state.getUser();
|
||||||
const stateStore = useStateStore();
|
|
||||||
const { sendEmail } = usePrintService();
|
const { sendEmail } = usePrintService();
|
||||||
const client = ref({});
|
|
||||||
const hasChanged = ref(false);
|
const hasChanged = ref(false);
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const optionsClientsAddressess = ref([]);
|
const addressess = ref([]);
|
||||||
const optionsCompanies = ref([]);
|
const companies = ref([]);
|
||||||
const optionsEmailUsers = ref([]);
|
const optionsEmailUsers = ref([]);
|
||||||
const optionsSamplesVisible = ref([]);
|
const optionsSamplesVisible = ref([]);
|
||||||
const sampleType = ref({ hasPreview: false });
|
const sampleType = ref({ hasPreview: false });
|
||||||
|
const initialData = reactive({});
|
||||||
|
const entityId = computed(() => route.params.id);
|
||||||
|
const customer = computed(() => state.get('customer'));
|
||||||
const filterEmailUsers = { where: { userFk: user.value.id } };
|
const filterEmailUsers = { where: { userFk: user.value.id } };
|
||||||
const filterClientsAddresses = {
|
const filterClientsAddresses = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -59,14 +61,13 @@ const filterSamplesVisible = {
|
||||||
],
|
],
|
||||||
order: ['description'],
|
order: ['description'],
|
||||||
};
|
};
|
||||||
const initialData = reactive({});
|
|
||||||
|
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
const { data } = await axios.get(`Clients/1/getCard`);
|
initialData.clientFk = customer.value.id;
|
||||||
client.value = data;
|
initialData.recipient = customer.value.email;
|
||||||
initialData.clientFk = route.params?.id;
|
initialData.recipientId = customer.value.id;
|
||||||
initialData.recipient = data.email;
|
|
||||||
initialData.recipientId = data.id;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const setEmailUser = (data) => {
|
const setEmailUser = (data) => {
|
||||||
|
@ -76,7 +77,7 @@ const setEmailUser = (data) => {
|
||||||
|
|
||||||
const setClientsAddresses = (data) => {
|
const setClientsAddresses = (data) => {
|
||||||
initialData.addressId = data[0].id;
|
initialData.addressId = data[0].id;
|
||||||
optionsClientsAddressess.value = data;
|
addressess.value = data;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setSampleType = (sampleId) => {
|
const setSampleType = (sampleId) => {
|
||||||
|
@ -89,20 +90,6 @@ const setSampleType = (sampleId) => {
|
||||||
initialData.companyId = companyFk;
|
initialData.companyId = companyFk;
|
||||||
};
|
};
|
||||||
|
|
||||||
const setInitialData = () => {
|
|
||||||
hasChanged.value = false;
|
|
||||||
|
|
||||||
initialData.addressId = optionsClientsAddressess.value[0].id;
|
|
||||||
initialData.companyFk = null;
|
|
||||||
initialData.from = null;
|
|
||||||
initialData.recipient = client.value.email;
|
|
||||||
initialData.recipientId = client.value.id;
|
|
||||||
initialData.replyTo = optionsEmailUsers.value[0]?.email;
|
|
||||||
initialData.typeFk = '';
|
|
||||||
|
|
||||||
sampleType.value = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateMessage = () => {
|
const validateMessage = () => {
|
||||||
if (!initialData.recipient) return 'Email cannot be blank';
|
if (!initialData.recipient) return 'Email cannot be blank';
|
||||||
if (!sampleType.value) return 'Choose a sample';
|
if (!sampleType.value) return 'Choose a sample';
|
||||||
|
@ -121,14 +108,14 @@ const setParams = (params) => {
|
||||||
const getPreview = async () => {
|
const getPreview = async () => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
recipientId: route.params.id,
|
recipientId: entityId,
|
||||||
};
|
};
|
||||||
const validationMessage = validateMessage();
|
const validationMessage = validateMessage();
|
||||||
if (validationMessage) return notify(t(validationMessage), 'negative');
|
if (validationMessage) return notify(t(validationMessage), 'negative');
|
||||||
|
|
||||||
setParams(params);
|
setParams(params);
|
||||||
|
|
||||||
const path = `${sampleType.value.model}/${route.params.id}/${sampleType.value.code}-html`;
|
const path = `${sampleType.value.model}/${entityId.value}/${sampleType.value.code}-html`;
|
||||||
const { data } = await axios.get(path, { params });
|
const { data } = await axios.get(path, { params });
|
||||||
|
|
||||||
if (!data) return;
|
if (!data) return;
|
||||||
|
@ -169,7 +156,6 @@ const getSamples = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
getSamples();
|
|
||||||
const onDataSaved = async () => {
|
const onDataSaved = async () => {
|
||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
|
@ -179,8 +165,9 @@ const onDataSaved = async () => {
|
||||||
};
|
};
|
||||||
setParams(params);
|
setParams(params);
|
||||||
const samplesData = await getSamples();
|
const samplesData = await getSamples();
|
||||||
const path = `${samplesData.model}/${route.params.id}/${samplesData.code}-email`;
|
const path = `${samplesData.model}/${entityId.value}/${samplesData.code}-email`;
|
||||||
await sendEmail(path, params);
|
await sendEmail(path, params);
|
||||||
|
onDialogOK(params);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notify('errors.create', 'negative');
|
notify('errors.create', 'negative');
|
||||||
}
|
}
|
||||||
|
@ -197,73 +184,54 @@ const toCustomerSamples = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterEmailUsers"
|
:filter="filterEmailUsers"
|
||||||
@on-fetch="setEmailUser"
|
@on-fetch="setEmailUser"
|
||||||
auto-load
|
auto-load
|
||||||
url="EmailUsers"
|
url="EmailUsers"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterClientsAddresses"
|
:filter="filterClientsAddresses"
|
||||||
:url="`Clients/${route.params.id}/addresses`"
|
:url="`Clients/${entityId}/addresses`"
|
||||||
@on-fetch="setClientsAddresses"
|
@on-fetch="setClientsAddresses"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterCompanies"
|
:filter="filterCompanies"
|
||||||
@on-fetch="(data) => (optionsCompanies = data)"
|
@on-fetch="(data) => (companies = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Companies"
|
url="Companies"
|
||||||
/>
|
/>
|
||||||
<fetch-data
|
<FetchData
|
||||||
:filter="filterSamplesVisible"
|
:filter="filterSamplesVisible"
|
||||||
@on-fetch="(data) => (optionsSamplesVisible = data)"
|
@on-fetch="(data) => (optionsSamplesVisible = data)"
|
||||||
auto-load
|
auto-load
|
||||||
url="Samples/visible"
|
url="Samples/visible"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Teleport v-if="stateStore?.isSubToolbarShown()" to="#st-actions">
|
<QDialog ref="dialogRef">
|
||||||
<QBtnGroup push class="q-gutter-x-sm">
|
<FormPopup
|
||||||
<QBtn
|
:default-cancel-button="false"
|
||||||
:label="t('globals.cancel')"
|
:default-submit-button="false"
|
||||||
@click="toCustomerSamples"
|
@on-submit="onSubmit()"
|
||||||
color="primary"
|
>
|
||||||
flat
|
<template #custom-buttons>
|
||||||
icon="close"
|
<QBtn
|
||||||
/>
|
:disabled="isLoading || !sampleType?.hasPreview"
|
||||||
<QBtn
|
:label="t('Preview')"
|
||||||
:disabled="isLoading || !sampleType?.hasPreview"
|
:loading="isLoading"
|
||||||
:label="t('Preview')"
|
@click.stop="getPreview()"
|
||||||
:loading="isLoading"
|
color="primary"
|
||||||
@click.stop="getPreview()"
|
flat
|
||||||
color="primary"
|
icon="preview" /><QBtn
|
||||||
flat
|
:disabled="!hasChanged"
|
||||||
icon="preview"
|
:label="t('globals.save')"
|
||||||
/>
|
:loading="isLoading"
|
||||||
<QBtn
|
@click="onSubmit"
|
||||||
:disabled="!hasChanged"
|
color="primary"
|
||||||
:label="t('globals.reset')"
|
icon="save"
|
||||||
:loading="isLoading"
|
/></template>
|
||||||
@click="setInitialData"
|
<template #form-inputs>
|
||||||
color="primary"
|
|
||||||
flat
|
|
||||||
icon="restart_alt"
|
|
||||||
type="reset"
|
|
||||||
/>
|
|
||||||
<QBtn
|
|
||||||
:disabled="!hasChanged"
|
|
||||||
:label="t('globals.save')"
|
|
||||||
:loading="isLoading"
|
|
||||||
@click="onSubmit"
|
|
||||||
color="primary"
|
|
||||||
icon="save"
|
|
||||||
/>
|
|
||||||
</QBtnGroup>
|
|
||||||
</Teleport>
|
|
||||||
|
|
||||||
<div class="full-width flex justify-center">
|
|
||||||
<QCard class="card-width q-pa-lg">
|
|
||||||
<QForm>
|
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Sample')"
|
:label="t('Sample')"
|
||||||
|
@ -320,7 +288,7 @@ const toCustomerSamples = () => {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Company')"
|
:label="t('Company')"
|
||||||
:options="optionsCompanies"
|
:options="companies"
|
||||||
:rules="validate('entry.companyFk')"
|
:rules="validate('entry.companyFk')"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="code"
|
option-label="code"
|
||||||
|
@ -333,7 +301,7 @@ const toCustomerSamples = () => {
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('Address')"
|
:label="t('Address')"
|
||||||
:options="optionsClientsAddressess"
|
:options="addressess"
|
||||||
hide-selected
|
hide-selected
|
||||||
option-label="nickname"
|
option-label="nickname"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
|
@ -371,15 +339,15 @@ const toCustomerSamples = () => {
|
||||||
required="true"
|
required="true"
|
||||||
v-model="initialData.from"
|
v-model="initialData.from"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div> </VnRow
|
||||||
</VnRow>
|
></template>
|
||||||
</QForm>
|
</FormPopup>
|
||||||
</QCard>
|
</QDialog>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
|
New sample: Crear plantilla
|
||||||
Sample: Plantilla
|
Sample: Plantilla
|
||||||
Recipient: Destinatario
|
Recipient: Destinatario
|
||||||
Reply to: Responder a
|
Reply to: Responder a
|
||||||
|
|
|
@ -1,22 +1,25 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
|
||||||
import { QBtn, date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
|
import { toDateFormat } from 'src/filters/date.js';
|
||||||
|
|
||||||
import { toCurrency } from 'src/filters';
|
import { toCurrency } from 'src/filters';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import CustomerSummaryTableActions from './CustomerSummaryTableActions.vue';
|
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
|
||||||
|
import InvoiceOutDescriptorProxy from 'pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
||||||
import RouteDescriptorProxy from 'src/pages/Route/Card/RouteDescriptorProxy.vue';
|
import RouteDescriptorProxy from 'src/pages/Route/Card/RouteDescriptorProxy.vue';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
import CustomerDescriptorProxy from '../Card/CustomerDescriptorProxy.vue';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { viewSummary } = useSummaryDialog();
|
||||||
const rows = ref([]);
|
|
||||||
|
|
||||||
const filter = {
|
const filter = {
|
||||||
include: [
|
include: [
|
||||||
|
@ -32,57 +35,7 @@ const filter = {
|
||||||
],
|
],
|
||||||
where: { clientFk: route.params.id },
|
where: { clientFk: route.params.id },
|
||||||
order: ['shipped DESC', 'id'],
|
order: ['shipped DESC', 'id'],
|
||||||
limit: 10,
|
limit: 30,
|
||||||
};
|
|
||||||
|
|
||||||
const tableColumnComponents = {
|
|
||||||
id: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
nickname: {
|
|
||||||
component: QBtn,
|
|
||||||
props: () => ({ flat: true, color: 'blue', noCaps: true }),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
agency: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
route: {
|
|
||||||
component: QBtn,
|
|
||||||
props: () => ({ flat: true, color: 'blue' }),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
packages: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
date: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
total: {
|
|
||||||
component: 'span',
|
|
||||||
props: () => {},
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
component: CustomerSummaryTableActions,
|
|
||||||
props: (prop) => ({
|
|
||||||
id: prop.row.id,
|
|
||||||
}),
|
|
||||||
event: () => {},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
|
@ -94,37 +47,37 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'nickname',
|
|
||||||
label: t('Nickname'),
|
label: t('Nickname'),
|
||||||
name: 'nickname',
|
name: 'nickname',
|
||||||
|
columnClass: 'expand',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (row) => row?.agencyMode?.name,
|
format: (row) => row.agencyMode.name,
|
||||||
|
columnClass: 'expand',
|
||||||
label: t('Agency'),
|
label: t('Agency'),
|
||||||
name: 'agency',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'routeFk',
|
name: 'routeFk',
|
||||||
|
columnClass: 'shrink',
|
||||||
label: t('Route'),
|
label: t('Route'),
|
||||||
name: 'route',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'packages',
|
field: 'packages',
|
||||||
label: t('Packages'),
|
label: t('Packages'),
|
||||||
name: 'packages',
|
name: 'packages',
|
||||||
|
columnClass: 'shrink',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (row) => date.formatDate(row?.shipped, 'DD/MM/YYYY'),
|
format: ({ shipped }) => date.formatDate(shipped, 'DD/MM/YYYY'),
|
||||||
label: t('Date'),
|
label: t('Date'),
|
||||||
name: 'date',
|
name: 'shipped',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: (row) => row?.ticketState?.state?.name,
|
|
||||||
label: t('State'),
|
label: t('State'),
|
||||||
name: 'state',
|
name: 'state',
|
||||||
},
|
},
|
||||||
|
@ -134,11 +87,25 @@ const columns = computed(() => [
|
||||||
label: t('Total'),
|
label: t('Total'),
|
||||||
name: 'total',
|
name: 'total',
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'right',
|
||||||
field: 'totalWithVat',
|
|
||||||
label: '',
|
label: '',
|
||||||
name: 'actions',
|
name: 'tableActions',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
title: t('customer.summary.goToLines'),
|
||||||
|
icon: 'vn:lines',
|
||||||
|
action: ({ id }) => router.push({ params: { id }, name: 'TicketSale' }),
|
||||||
|
isPrimary: true,
|
||||||
jgallego marked this conversation as resolved
Outdated
jgallego
commented
El otro día comenté contigo con Alex que el Windows open mejor no usarlo. aplica aqui? El otro día comenté contigo con Alex que el Windows open mejor no usarlo. aplica aqui?
jsegarra
commented
El viernes pasado comentamos que habia un composable openReport que hacia esto. El viernes pasado comentamos que habia un composable openReport que hacia esto.
Para este caso concreto lo ideal seria usar la etiqueta a de HTML y la propiedad hRef, pero en este caso no aplica
|
|||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('components.smartCard.viewSummary'),
|
||||||
|
icon: 'preview',
|
||||||
|
isPrimary: true,
|
||||||
|
action: (row) => viewSummary(row.id, TicketSummary),
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -156,84 +123,89 @@ const setTotalPriceColor = (ticket) => {
|
||||||
if (total > 0 && total < 50) return 'warning';
|
if (total > 0 && total < 50) return 'warning';
|
||||||
};
|
};
|
||||||
|
|
||||||
const navigateToticketSummary = (id) => {
|
const setShippedColor = (date) => {
|
||||||
router.push({
|
const today = Date.vnNew();
|
||||||
name: 'TicketSummary',
|
today.setHours(0, 0, 0, 0);
|
||||||
params: { id },
|
|
||||||
});
|
const ticketShipped = new Date(date);
|
||||||
|
ticketShipped.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const difference = today - ticketShipped;
|
||||||
|
|
||||||
|
if (difference == 0) return 'warning';
|
||||||
|
if (difference < 0) return 'success';
|
||||||
};
|
};
|
||||||
const commonColumns = (col) => ['date', 'state', 'total'].includes(col);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<VnTable
|
||||||
|
data-key="CustomerTickets"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
@on-fetch="(data) => (rows = data)"
|
:right-search="false"
|
||||||
auto-load
|
:column-search="false"
|
||||||
url="Tickets"
|
url="Tickets"
|
||||||
/>
|
:columns="columns"
|
||||||
<QCard class="vn-one q-py-sm flex justify-between">
|
search-url="tickets"
|
||||||
<QTable
|
:without-header="true"
|
||||||
:columns="columns"
|
auto-load
|
||||||
:pagination="{ rowsPerPage: 12 }"
|
order="shipped DESC, id"
|
||||||
:rows="rows"
|
:disable-option="{ card: true, table: true }"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
row-key="id"
|
:disable-infinite-scroll="true"
|
||||||
>
|
>
|
||||||
<template #body-cell="props">
|
<template #column-nickname="{ row }">
|
||||||
<QTd :props="props" @click="navigateToticketSummary(props.row.id)">
|
<span class="link">
|
||||||
<QTr :props="props" class="cursor-pointer">
|
{{ row.nickname }}
|
||||||
<component
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||||
:is="tableColumnComponents[props.col.name].component"
|
</span>
|
||||||
@click="tableColumnComponents[props.col.name].event(props)"
|
</template>
|
||||||
class="rounded-borders"
|
|
||||||
v-bind="tableColumnComponents[props.col.name].props(props)"
|
<template #column-routeFk="{ row }">
|
||||||
>
|
<span class="link">
|
||||||
<template v-if="!commonColumns(props.col.name)">
|
{{ row.routeFk }}
|
||||||
<span
|
<RouteDescriptorProxy :id="row.routeFk" />
|
||||||
:class="{
|
</span>
|
||||||
link:
|
</template>
|
||||||
props.col.name === 'route' ||
|
<template #column-total="{ row }">
|
||||||
props.col.name === 'nickname',
|
<QBadge
|
||||||
}"
|
class="q-pa-sm"
|
||||||
>
|
v-if="setTotalPriceColor(row)"
|
||||||
{{ props.value }}
|
:color="setTotalPriceColor(row)"
|
||||||
</span>
|
text-color="black"
|
||||||
</template>
|
>
|
||||||
<template v-if="props.col.name === 'date'">
|
{{ toCurrency(row.totalWithVat) }}
|
||||||
<QBadge class="q-pa-sm" color="warning">
|
</QBadge>
|
||||||
{{ props.value }}
|
<span v-else> {{ toCurrency(row.totalWithVat) }}</span>
|
||||||
</QBadge>
|
</template>
|
||||||
</template>
|
<template #column-state="{ row }">
|
||||||
<template v-if="props.col.name === 'state'">
|
<span v-if="row.invoiceOut">
|
||||||
<QBadge :color="setStateColor(props.row)" class="q-pa-sm">
|
<span :class="{ link: row.invoiceOut.ref }">
|
||||||
{{ props.value }}
|
{{ row.invoiceOut.ref }}
|
||||||
</QBadge>
|
<InvoiceOutDescriptorProxy :id="row.invoiceOut.id" />
|
||||||
</template>
|
</span>
|
||||||
<template v-if="props.col.name === 'total'">
|
</span>
|
||||||
<QBadge
|
<QBadge
|
||||||
:color="setTotalPriceColor(props.row)"
|
class="q-pa-sm"
|
||||||
class="q-pa-sm"
|
:color="setStateColor(row)"
|
||||||
alexm
commented
Creo que poniendo redirect ya lo hace no? Creo que poniendo redirect ya lo hace no?
jsegarra
commented
espectacular espectacular
|
|||||||
v-if="setTotalPriceColor(props.row)"
|
text-color="black"
|
||||||
>
|
v-else-if="setStateColor(row)"
|
||||||
{{ toCurrency(props.value) }}
|
>
|
||||||
</QBadge>
|
{{ row?.ticketState?.state.name }}
|
||||||
<div v-else>{{ toCurrency(props.value) }}</div>
|
</QBadge>
|
||||||
</template>
|
<span v-else> {{ row?.ticketState?.state.name }}</span>
|
||||||
<CustomerDescriptorProxy
|
</template>
|
||||||
:id="props.row.clientFk"
|
<template #column-shipped="{ row }">
|
||||||
v-if="props.col.name === 'nickname'"
|
<QBadge
|
||||||
/>
|
class="q-pa-sm"
|
||||||
<RouteDescriptorProxy
|
:color="setShippedColor(row.shipped)"
|
||||||
:id="props.row.routeFk"
|
text-color="black"
|
||||||
v-if="props.col.name === 'route'"
|
v-if="setShippedColor(row.shipped)"
|
||||||
/>
|
>
|
||||||
</component>
|
{{ toDateFormat(row.shipped) }}
|
||||||
</QTr>
|
</QBadge>
|
||||||
</QTd>
|
<span v-else> {{ toDateFormat(row.shipped) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</QTable>
|
</VnTable>
|
||||||
</QCard>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
|
||||||
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
id: {
|
|
||||||
type: Number,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { viewSummary } = useSummaryDialog();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div>
|
|
||||||
<QIcon color="primary" name="vn:lines" size="sm">
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('Go to lines') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
<QIcon
|
|
||||||
@click.stop="viewSummary(id, TicketSummary)"
|
|
||||||
class="q-ml-md"
|
|
||||||
color="primary"
|
|
||||||
name="preview"
|
|
||||||
size="sm"
|
|
||||||
>
|
|
||||||
<QTooltip>
|
|
||||||
{{ t('Preview') }}
|
|
||||||
</QTooltip>
|
|
||||||
</QIcon>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<i18n>
|
|
||||||
es:
|
|
||||||
Go to lines: Ir a lineas
|
|
||||||
Preview: Vista previa
|
|
||||||
</i18n>
|
|
|
@ -2,3 +2,135 @@ customerFilter:
|
||||||
filter:
|
filter:
|
||||||
name: Name
|
name: Name
|
||||||
socialName: Social name
|
socialName: Social name
|
||||||
|
customer:
|
||||||
|
list:
|
||||||
|
phone: Phone
|
||||||
|
email: Email
|
||||||
|
customerOrders: Display customer orders
|
||||||
|
moreOptions: More options
|
||||||
|
card:
|
||||||
|
customerList: Customer list
|
||||||
|
customerId: Claim ID
|
||||||
|
salesPerson: Sales person
|
||||||
|
credit: Credit
|
||||||
|
risk: Risk
|
||||||
|
securedCredit: Secured credit
|
||||||
|
payMethod: Pay method
|
||||||
|
debt: Debt
|
||||||
|
isFrozen: Customer frozen
|
||||||
|
hasDebt: Customer has debt
|
||||||
|
isDisabled: Customer inactive
|
||||||
|
notChecked: Customer no checked
|
||||||
|
webAccountInactive: Web account inactive
|
||||||
|
noWebAccess: Web access is disabled
|
||||||
|
businessType: Business type
|
||||||
|
passwordRequirements: 'The password must have at least { length } length characters, {nAlpha} alphabetic characters, {nUpper} capital letters, {nDigits} digits and {nPunct} symbols (Ex: $%&.)\n'
|
||||||
|
businessTypeFk: Business type
|
||||||
|
summary:
|
||||||
|
basicData: Basic data
|
||||||
|
fiscalAddress: Fiscal address
|
||||||
|
fiscalData: Fiscal data
|
||||||
|
billingData: Billing data
|
||||||
|
consignee: Default consignee
|
||||||
|
businessData: Business data
|
||||||
|
financialData: Financial data
|
||||||
|
customerId: Customer ID
|
||||||
|
name: Name
|
||||||
|
contact: Contact
|
||||||
|
phone: Phone
|
||||||
|
mobile: Mobile
|
||||||
|
email: Email
|
||||||
|
salesPerson: Sales person
|
||||||
|
contactChannel: Contact channel
|
||||||
|
socialName: Social name
|
||||||
|
fiscalId: Fiscal ID
|
||||||
|
postcode: Postcode
|
||||||
|
province: Province
|
||||||
|
country: Country
|
||||||
|
street: Address
|
||||||
|
isEqualizated: Is equalizated
|
||||||
|
isActive: Is active
|
||||||
|
invoiceByAddress: Invoice by address
|
||||||
|
verifiedData: Verified data
|
||||||
|
hasToInvoice: Has to invoice
|
||||||
|
notifyByEmail: Notify by email
|
||||||
|
vies: VIES
|
||||||
|
payMethod: Pay method
|
||||||
|
bankAccount: Bank account
|
||||||
|
dueDay: Due day
|
||||||
|
hasLcr: Has LCR
|
||||||
|
hasCoreVnl: Has core VNL
|
||||||
|
hasB2BVnl: Has B2B VNL
|
||||||
|
addressName: Address name
|
||||||
|
addressCity: City
|
||||||
|
addressStreet: Street
|
||||||
|
username: Username
|
||||||
|
webAccess: Web access
|
||||||
|
totalGreuge: Total greuge
|
||||||
|
mana: Mana
|
||||||
|
priceIncreasingRate: Price increasing rate
|
||||||
|
averageInvoiced: Average invoiced
|
||||||
|
claimRate: Claming rate
|
||||||
|
payMethodFk: Billing data
|
||||||
|
risk: Risk
|
||||||
|
maximumRisk: Solunion's maximum risk
|
||||||
|
riskInfo: Invoices minus payments plus orders not yet invoiced
|
||||||
|
credit: Credit
|
||||||
|
creditInfo: Company's maximum risk
|
||||||
|
securedCredit: Secured credit
|
||||||
|
securedCreditInfo: Solunion's maximum risk
|
||||||
|
balance: Balance
|
||||||
|
balanceInfo: Invoices minus payments
|
||||||
|
balanceDue: Balance due
|
||||||
|
balanceDueInfo: Deviated invoices minus payments
|
||||||
|
recoverySince: Recovery since
|
||||||
|
businessType: Business Type
|
||||||
|
city: City
|
||||||
|
descriptorInfo: Invoices minus payments plus orders not yet
|
||||||
|
rating: Rating
|
||||||
|
recommendCredit: Recommended credit
|
||||||
|
goToLines: Go to lines
|
||||||
|
basicData:
|
||||||
|
socialName: Fiscal name
|
||||||
|
businessType: Business type
|
||||||
|
contact: Contact
|
||||||
|
youCanSaveMultipleEmails: You can save multiple emails
|
||||||
|
email: Email
|
||||||
|
phone: Phone
|
||||||
|
mobile: Mobile
|
||||||
|
salesPerson: Sales person
|
||||||
|
contactChannel: Contact channel
|
||||||
|
previousClient: Previous client
|
||||||
|
extendedList:
|
||||||
|
tableVisibleColumns:
|
||||||
|
id: Identifier
|
||||||
|
name: Name
|
||||||
|
socialName: Social name
|
||||||
|
fi: Tax number
|
||||||
|
salesPersonFk: Salesperson
|
||||||
|
credit: Credit
|
||||||
|
creditInsurance: Credit insurance
|
||||||
|
phone: Phone
|
||||||
|
mobile: Mobile
|
||||||
|
street: Street
|
||||||
|
countryFk: Country
|
||||||
|
provinceFk: Province
|
||||||
|
city: City
|
||||||
|
postcode: Postcode
|
||||||
|
email: Email
|
||||||
|
created: Created
|
||||||
|
businessTypeFk: Business type
|
||||||
|
payMethodFk: Billing data
|
||||||
|
sageTaxTypeFk: Sage tax type
|
||||||
|
sageTransactionTypeFk: Sage tr. type
|
||||||
|
isActive: Active
|
||||||
|
isVies: Vies
|
||||||
|
isTaxDataChecked: Verified data
|
||||||
|
isEqualizated: Is equalizated
|
||||||
|
isFreezed: Freezed
|
||||||
|
hasToInvoice: Invoice
|
||||||
|
hasToInvoiceByAddress: Invoice by address
|
||||||
|
isToBeMailed: Mailing
|
||||||
|
hasLcr: Received LCR
|
||||||
|
hasCoreVnl: VNL core received
|
||||||
|
hasSepaVnl: VNL B2B received
|
||||||
|
|
|
@ -4,3 +4,134 @@ customerFilter:
|
||||||
filter:
|
filter:
|
||||||
name: Nombre
|
name: Nombre
|
||||||
socialName: Razón Social
|
socialName: Razón Social
|
||||||
|
customer:
|
||||||
|
list:
|
||||||
|
phone: Teléfono
|
||||||
|
email: Email
|
||||||
|
customerOrders: Mostrar órdenes del cliente
|
||||||
|
moreOptions: Más opciones
|
||||||
|
card:
|
||||||
|
customerId: ID cliente
|
||||||
|
salesPerson: Comercial
|
||||||
|
credit: Crédito
|
||||||
|
risk: Riesgo
|
||||||
|
securedCredit: Crédito asegurado
|
||||||
|
payMethod: Método de pago
|
||||||
|
debt: Riesgo
|
||||||
|
isFrozen: Cliente congelado
|
||||||
|
hasDebt: Cliente con riesgo
|
||||||
|
isDisabled: Cliente inactivo
|
||||||
|
notChecked: Cliente no comprobado
|
||||||
|
webAccountInactive: Sin acceso web
|
||||||
|
noWebAccess: El acceso web está desactivado
|
||||||
|
businessType: Tipo de negocio
|
||||||
|
passwordRequirements: 'La contraseña debe tener al menos { length } caracteres de longitud, {nAlpha} caracteres alfabéticos, {nUpper} letras mayúsculas, {nDigits} dígitos y {nPunct} símbolos (Ej: $%&.)'
|
||||||
|
businessTypeFk: Tipo de negocio
|
||||||
|
summary:
|
||||||
|
basicData: Datos básicos
|
||||||
|
fiscalAddress: Dirección fiscal
|
||||||
|
fiscalData: Datos fiscales
|
||||||
|
billingData: Datos de facturación
|
||||||
|
consignee: Consignatario pred.
|
||||||
|
businessData: Datos comerciales
|
||||||
|
financialData: Datos financieros
|
||||||
|
customerId: ID cliente
|
||||||
|
name: Nombre
|
||||||
|
contact: Contacto
|
||||||
|
phone: Teléfono
|
||||||
|
mobile: Móvil
|
||||||
|
email: Email
|
||||||
|
salesPerson: Comercial
|
||||||
|
contactChannel: Canal de contacto
|
||||||
|
socialName: Razón social
|
||||||
|
fiscalId: NIF/CIF
|
||||||
|
postcode: Código postal
|
||||||
|
province: Provincia
|
||||||
|
country: País
|
||||||
|
street: Calle
|
||||||
|
isEqualizated: Recargo de equivalencia
|
||||||
|
isActive: Activo
|
||||||
|
invoiceByAddress: Facturar por consignatario
|
||||||
|
verifiedData: Datos verificados
|
||||||
|
hasToInvoice: Facturar
|
||||||
|
notifyByEmail: Notificar por email
|
||||||
|
vies: VIES
|
||||||
|
payMethod: Método de pago
|
||||||
|
bankAccount: Cuenta bancaria
|
||||||
|
dueDay: Vencimiento
|
||||||
|
hasLcr: Recibido LCR
|
||||||
|
hasCoreVnl: Recibido core VNL
|
||||||
|
hasB2BVnl: Recibido B2B VNL
|
||||||
|
addressName: Nombre de la dirección
|
||||||
|
addressCity: Ciudad
|
||||||
|
addressStreet: Calle
|
||||||
|
username: Usuario
|
||||||
|
webAccess: Acceso web
|
||||||
|
totalGreuge: Greuge total
|
||||||
|
mana: Maná
|
||||||
|
priceIncreasingRate: Ratio de incremento de precio
|
||||||
|
averageInvoiced: Facturación media
|
||||||
|
claimRate: Ratio de reclamaciones
|
||||||
|
maximumRisk: Riesgo máximo asumido por Solunion
|
||||||
|
payMethodFk: Forma de pago
|
||||||
|
risk: Riesgo
|
||||||
|
riskInfo: Facturas menos recibos mas pedidos sin facturar
|
||||||
|
credit: Crédito
|
||||||
|
creditInfo: Riesgo máximo asumido por la empresa
|
||||||
|
securedCredit: Crédito asegurado
|
||||||
|
securedCreditInfo: Riesgo máximo asumido por Solunion
|
||||||
|
balance: Balance
|
||||||
|
balanceInfo: Facturas menos recibos
|
||||||
|
balanceDue: Saldo vencido
|
||||||
|
balanceDueInfo: Facturas fuera de plazo menos recibos
|
||||||
|
recoverySince: Recobro desde
|
||||||
|
businessType: Tipo de negocio
|
||||||
|
city: Población
|
||||||
|
descriptorInfo: Facturas menos recibos mas pedidos sin facturar
|
||||||
|
rating: Clasificación
|
||||||
|
recommendCredit: Crédito recomendado
|
||||||
|
goToLines: Ir a líneas
|
||||||
|
basicData:
|
||||||
|
socialName: Nombre fiscal
|
||||||
|
businessType: Tipo de negocio
|
||||||
|
contact: Contacto
|
||||||
|
youCanSaveMultipleEmails: Puede guardar varios correos electrónicos encadenándolos mediante comas sin espacios{','} ejemplo{':'} user{'@'}dominio{'.'}com, user2{'@'}dominio{'.'}com siendo el primer correo electrónico el principal
|
||||||
|
email: Email
|
||||||
|
phone: Teléfono
|
||||||
|
mobile: Móvil
|
||||||
|
salesPerson: Comercial
|
||||||
|
contactChannel: Canal de contacto
|
||||||
|
previousClient: Cliente anterior
|
||||||
|
extendedList:
|
||||||
|
tableVisibleColumns:
|
||||||
|
id: Identificador
|
||||||
|
name: Nombre
|
||||||
|
socialName: Razón social
|
||||||
|
fi: NIF / CIF
|
||||||
|
salesPersonFk: Comercial
|
||||||
|
credit: Crédito
|
||||||
|
creditInsurance: Crédito asegurado
|
||||||
|
phone: Teléfono
|
||||||
|
mobile: Móvil
|
||||||
|
street: Dirección fiscal
|
||||||
|
countryFk: País
|
||||||
|
provinceFk: Provincia
|
||||||
|
city: Población
|
||||||
|
postcode: Código postal
|
||||||
|
email: Email
|
||||||
|
created: Fecha creación
|
||||||
|
businessTypeFk: Tipo de negocio
|
||||||
|
payMethodFk: Forma de pago
|
||||||
|
sageTaxTypeFk: Tipo de impuesto Sage
|
||||||
|
sageTransactionTypeFk: Tipo tr. sage
|
||||||
|
isActive: Activo
|
||||||
|
isVies: Vies
|
||||||
|
isTaxDataChecked: Datos comprobados
|
||||||
|
isEqualizated: Recargo de equivalencias
|
||||||
|
isFreezed: Congelado
|
||||||
|
hasToInvoice: Factura
|
||||||
|
hasToInvoiceByAddress: Factura por consigna
|
||||||
|
isToBeMailed: Env. emails
|
||||||
|
hasLcr: Recibido LCR
|
||||||
|
hasCoreVnl: Recibido core VNL
|
||||||
|
hasSepaVnl: Recibido B2B VNL
|
||||||
|
|
|
@ -60,7 +60,7 @@ const pinnedModules = computed(() => navigation.getPinnedModules());
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{
|
{{
|
||||||
'Ctrl + Alt + ' +
|
'Ctrl + Alt + ' +
|
||||||
item.keyBinding.toUpperCase()
|
item?.keyBinding?.toUpperCase()
|
||||||
}}
|
}}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,12 +16,12 @@ const workersOptions = ref([]);
|
||||||
const clientsOptions = ref([]);
|
const clientsOptions = ref([]);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<fetch-data
|
<FetchData
|
||||||
url="Workers/search"
|
url="Workers/search"
|
||||||
@on-fetch="(data) => (workersOptions = data)"
|
@on-fetch="(data) => (workersOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<fetch-data url="Clients" @on-fetch="(data) => (clientsOptions = data)" auto-load />
|
<FetchData url="Clients" @on-fetch="(data) => (clientsOptions = data)" auto-load />
|
||||||
<FormModel
|
<FormModel
|
||||||
:url="`Departments/${route.params.id}`"
|
:url="`Departments/${route.params.id}`"
|
||||||
model="department"
|
model="department"
|
||||||
|
|
|
@ -138,7 +138,13 @@ const columns = computed(() => [
|
||||||
</template>
|
</template>
|
||||||
</CrudModel>
|
</CrudModel>
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<QBtn fab color="primary" icon="add" @click="entryObservationsRef.insert()" />
|
<QBtn
|
||||||
|
fab
|
||||||
|
color="primary"
|
||||||
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
|
@click="entryObservationsRef.insert()"
|
||||||
|
/>
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.v
|
||||||
import { toDate, toCurrency } from 'src/filters';
|
import { toDate, toCurrency } from 'src/filters';
|
||||||
import { getUrl } from 'src/composables/getUrl';
|
import { getUrl } from 'src/composables/getUrl';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import FetchedTags from 'src/components/ui/FetchedTags.vue';
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -163,7 +164,7 @@ const fetchEntryBuys = async () => {
|
||||||
>
|
>
|
||||||
<template #header-left>
|
<template #header-left>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="route.name !== 'EntrySummary'"
|
v-if="route?.name !== 'EntrySummary'"
|
||||||
:to="{ name: 'EntrySummary', params: { id: entityId } }"
|
:to="{ name: 'EntrySummary', params: { id: entityId } }"
|
||||||
class="header link"
|
class="header link"
|
||||||
:href="entryUrl"
|
:href="entryUrl"
|
||||||
|
@ -184,7 +185,10 @@ const fetchEntryBuys = async () => {
|
||||||
<QIcon name="open_in_new" />
|
<QIcon name="open_in_new" />
|
||||||
</router-link>
|
</router-link>
|
||||||
<VnLv :label="t('entry.summary.commission')" :value="entry.commission" />
|
<VnLv :label="t('entry.summary.commission')" :value="entry.commission" />
|
||||||
<VnLv :label="t('entry.summary.currency')" :value="entry.currency.name" />
|
<VnLv
|
||||||
|
:label="t('entry.summary.currency')"
|
||||||
|
:value="entry.currency?.name"
|
||||||
|
/>
|
||||||
<VnLv :label="t('entry.summary.company')" :value="entry.company.code" />
|
<VnLv :label="t('entry.summary.company')" :value="entry.company.code" />
|
||||||
<VnLv :label="t('entry.summary.reference')" :value="entry.reference" />
|
<VnLv :label="t('entry.summary.reference')" :value="entry.reference" />
|
||||||
<VnLv
|
<VnLv
|
||||||
|
@ -210,12 +214,12 @@ const fetchEntryBuys = async () => {
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('entry.summary.travelAgency')"
|
:label="t('entry.summary.travelAgency')"
|
||||||
:value="entry.travel.agency.name"
|
:value="entry.travel.agency?.name"
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('shipped')" :value="toDate(entry.travel.shipped)" />
|
<VnLv :label="t('shipped')" :value="toDate(entry.travel.shipped)" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('entry.summary.travelWarehouseOut')"
|
:label="t('entry.summary.travelWarehouseOut')"
|
||||||
:value="entry.travel.warehouseOut.name"
|
:value="entry.travel.warehouseOut?.name"
|
||||||
/>
|
/>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('entry.summary.travelDelivered')"
|
:label="t('entry.summary.travelDelivered')"
|
||||||
|
@ -225,7 +229,7 @@ const fetchEntryBuys = async () => {
|
||||||
<VnLv :label="t('landed')" :value="toDate(entry.travel.landed)" />
|
<VnLv :label="t('landed')" :value="toDate(entry.travel.landed)" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('entry.summary.travelWarehouseIn')"
|
:label="t('entry.summary.travelWarehouseIn')"
|
||||||
:value="entry.travel.warehouseIn.name"
|
:value="entry.travel.warehouseIn?.name"
|
||||||
/>
|
/>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
:label="t('entry.summary.travelReceived')"
|
:label="t('entry.summary.travelReceived')"
|
||||||
|
@ -281,17 +285,17 @@ const fetchEntryBuys = async () => {
|
||||||
>
|
>
|
||||||
<template #body="{ cols, row, rowIndex }">
|
<template #body="{ cols, row, rowIndex }">
|
||||||
<QTr no-hover>
|
<QTr no-hover>
|
||||||
<QTd v-for="col in cols" :key="col.name">
|
<QTd v-for="col in cols" :key="col?.name">
|
||||||
<component
|
<component
|
||||||
:is="tableColumnComponents[col.name].component(props)"
|
:is="tableColumnComponents[col?.name].component()"
|
||||||
v-bind="tableColumnComponents[col.name].props(props)"
|
v-bind="tableColumnComponents[col?.name].props()"
|
||||||
@click="tableColumnComponents[col.name].event(props)"
|
@click="tableColumnComponents[col?.name].event()"
|
||||||
class="col-content"
|
class="col-content"
|
||||||
>
|
>
|
||||||
<template
|
<template
|
||||||
v-if="
|
v-if="
|
||||||
col.name !== 'observation' &&
|
col?.name !== 'observation' &&
|
||||||
col.name !== 'isConfirmed'
|
col?.name !== 'isConfirmed'
|
||||||
"
|
"
|
||||||
>{{ col.value }}</template
|
>{{ col.value }}</template
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
import { onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
|
||||||
import EntryLatestBuysFilter from './EntryLatestBuysFilter.vue';
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
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 stateStore = useStateStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
import { toDate } from 'src/filters';
|
|
||||||
import VnImg from 'src/components/ui/VnImg.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
import VnInput from 'components/common/VnInput.vue';
|
||||||
import VnSelect from 'components/common/VnSelect.vue';
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
|
import ItemsFilterPanel from 'src/components/ItemsFilterPanel.vue';
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ defineProps({
|
||||||
|
|
||||||
const itemTypeWorkersOptions = ref([]);
|
const itemTypeWorkersOptions = ref([]);
|
||||||
const suppliersOptions = ref([]);
|
const suppliersOptions = ref([]);
|
||||||
|
const tagValues = ref([]);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -281,6 +281,7 @@ async function onSubmit() {
|
||||||
v-else
|
v-else
|
||||||
icon="add_circle"
|
icon="add_circle"
|
||||||
round
|
round
|
||||||
|
shortcut="+"
|
||||||
padding="xs"
|
padding="xs"
|
||||||
@click="setCreateDms()"
|
@click="setCreateDms()"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useI18n } from 'vue-i18n';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { toCurrency, toDate } from 'src/filters';
|
import { toCurrency, toDate } from 'src/filters';
|
||||||
import { useRole } from 'src/composables/useRole';
|
import { useAcl } from 'src/composables/useAcl';
|
||||||
import { downloadFile } from 'src/composables/downloadFile';
|
import { downloadFile } from 'src/composables/downloadFile';
|
||||||
import { useArrayData } from 'src/composables/useArrayData';
|
import { useArrayData } from 'src/composables/useArrayData';
|
||||||
import { usePrintService } from 'composables/usePrintService';
|
import { usePrintService } from 'composables/usePrintService';
|
||||||
|
@ -24,7 +24,7 @@ const $props = defineProps({ id: { type: Number, default: null } });
|
||||||
const { push, currentRoute } = useRouter();
|
const { push, currentRoute } = useRouter();
|
||||||
|
|
||||||
const quasar = useQuasar();
|
const quasar = useQuasar();
|
||||||
const { hasAny } = useRole();
|
const { hasAny } = useAcl();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openReport, sendEmail } = usePrintService();
|
const { openReport, sendEmail } = usePrintService();
|
||||||
const arrayData = useArrayData();
|
const arrayData = useArrayData();
|
||||||
|
@ -195,7 +195,8 @@ async function cloneInvoice() {
|
||||||
push({ path: `/invoice-in/${data.id}/summary` });
|
push({ path: `/invoice-in/${data.id}/summary` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const isAdministrative = () => hasAny(['administrative']);
|
const canEditProp = (props) =>
|
||||||
|
hasAny([{ model: 'InvoiceIn', props, accessType: 'WRITE' }]);
|
||||||
|
|
||||||
const isAgricultural = () => {
|
const isAgricultural = () => {
|
||||||
if (!config.value) return false;
|
if (!config.value) return false;
|
||||||
|
@ -283,7 +284,7 @@ const createInvoiceInCorrection = async () => {
|
||||||
<InvoiceInToBook>
|
<InvoiceInToBook>
|
||||||
<template #content="{ book }">
|
<template #content="{ book }">
|
||||||
<QItem
|
<QItem
|
||||||
v-if="!entity?.isBooked && isAdministrative()"
|
v-if="!entity?.isBooked && canEditProp('toBook')"
|
||||||
v-ripple
|
v-ripple
|
||||||
clickable
|
clickable
|
||||||
@click="book(entityId)"
|
@click="book(entityId)"
|
||||||
|
@ -293,7 +294,7 @@ const createInvoiceInCorrection = async () => {
|
||||||
</template>
|
</template>
|
||||||
</InvoiceInToBook>
|
</InvoiceInToBook>
|
||||||
<QItem
|
<QItem
|
||||||
v-if="entity?.isBooked && isAdministrative()"
|
v-if="entity?.isBooked && canEditProp('toUnbook')"
|
||||||
v-ripple
|
v-ripple
|
||||||
clickable
|
clickable
|
||||||
@click="triggerMenu('unbook')"
|
@click="triggerMenu('unbook')"
|
||||||
|
@ -303,7 +304,7 @@ const createInvoiceInCorrection = async () => {
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem
|
<QItem
|
||||||
v-if="isAdministrative()"
|
v-if="canEditProp('deleteById')"
|
||||||
v-ripple
|
v-ripple
|
||||||
clickable
|
clickable
|
||||||
@click="triggerMenu('delete')"
|
@click="triggerMenu('delete')"
|
||||||
|
@ -311,7 +312,7 @@ const createInvoiceInCorrection = async () => {
|
||||||
<QItemSection>{{ t('Delete invoice') }}</QItemSection>
|
<QItemSection>{{ t('Delete invoice') }}</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem
|
<QItem
|
||||||
v-if="isAdministrative()"
|
v-if="canEditProp('clone')"
|
||||||
v-ripple
|
v-ripple
|
||||||
clickable
|
clickable
|
||||||
@click="triggerMenu('clone')"
|
@click="triggerMenu('clone')"
|
||||||
|
|
|
@ -230,7 +230,7 @@ async function insert() {
|
||||||
</template>
|
</template>
|
||||||
</CrudModel>
|
</CrudModel>
|
||||||
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
<QPageSticky position="bottom-right" :offset="[25, 25]">
|
||||||
<QBtn color="primary" icon="add" size="lg" round @click="insert" />
|
<QBtn color="primary" icon="add" shortcut="+" size="lg" round @click="insert" />
|
||||||
</QPageSticky>
|
</QPageSticky>
|
||||||
</template>
|
</template>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -224,6 +224,7 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
<QBtn
|
<QBtn
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="add"
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
size="lg"
|
size="lg"
|
||||||
round
|
round
|
||||||
@click="invoiceInFormRef.insert()"
|
@click="invoiceInFormRef.insert()"
|
||||||
|
|
|
@ -405,6 +405,7 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="add"
|
icon="add"
|
||||||
size="lg"
|
size="lg"
|
||||||
|
shortcut="+"
|
||||||
round
|
round
|
||||||
@click="invoiceInFormRef.insert()"
|
@click="invoiceInFormRef.insert()"
|
||||||
>
|
>
|
||||||
|
|
|
@ -41,8 +41,7 @@ const invoiceFormType = ref('pdf');
|
||||||
const defaultEmailAddress = ref($props.invoiceOutData.client?.email);
|
const defaultEmailAddress = ref($props.invoiceOutData.client?.email);
|
||||||
|
|
||||||
const showInvoicePdf = () => {
|
const showInvoicePdf = () => {
|
||||||
const url = `api/InvoiceOuts/${$props.invoiceOutData.id}/download?access_token=${token}`;
|
openReport(`InvoiceOuts/${$props.invoiceOutData.id}/download`, {}, '_blank');
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const showInvoiceCsv = () => {
|
const showInvoiceCsv = () => {
|
||||||
|
|
|
@ -65,17 +65,18 @@ const focusLastInput = () => {
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</div>
|
</div>
|
||||||
<QIcon
|
<QBtn
|
||||||
@click="insertRow()"
|
@click="insertRow()"
|
||||||
class="cursor-pointer fill-icon-on-hover"
|
class="cursor-pointer fill-icon-on-hover"
|
||||||
color="primary"
|
color="primary"
|
||||||
name="add_circle"
|
icon="add_circle"
|
||||||
size="sm"
|
shortcut="+"
|
||||||
|
flat
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Add barcode') }}
|
{{ t('Add barcode') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QBtn>
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
</CrudModel>
|
</CrudModel>
|
||||||
|
|
|
@ -7,8 +7,7 @@ import CardSummary from 'components/ui/CardSummary.vue';
|
||||||
import VnLv from 'src/components/ui/VnLv.vue';
|
import VnLv from 'src/components/ui/VnLv.vue';
|
||||||
import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
|
import ItemDescriptorImage from 'src/pages/Item/Card/ItemDescriptorImage.vue';
|
||||||
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
import VnUserLink from 'src/components/ui/VnUserLink.vue';
|
||||||
|
import VnTitle from 'src/components/common/VnTitle.vue';
|
||||||
import { useRole } from 'src/composables/useRole';
|
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -19,23 +18,10 @@ const $props = defineProps({
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const roleState = useRole();
|
|
||||||
|
|
||||||
const entityId = computed(() => $props.id || route.params.id);
|
const entityId = computed(() => $props.id || route.params.id);
|
||||||
|
const getUrl = (id, param) => `#/Item/${id}/${param}`;
|
||||||
const isBuyer = computed(() => {
|
|
||||||
return roleState.hasAny(['buyer']);
|
|
||||||
});
|
|
||||||
|
|
||||||
const isReplenisher = computed(() => {
|
|
||||||
return roleState.hasAny(['replenisher']);
|
|
||||||
});
|
|
||||||
|
|
||||||
const isAdministrative = computed(() => {
|
|
||||||
return roleState.hasAny(['administrative']);
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<CardSummary
|
<CardSummary
|
||||||
ref="summary"
|
ref="summary"
|
||||||
|
@ -44,13 +30,15 @@ const isAdministrative = computed(() => {
|
||||||
data-key="ItemSummary"
|
data-key="ItemSummary"
|
||||||
>
|
>
|
||||||
<template #header-left>
|
<template #header-left>
|
||||||
<router-link
|
<QBtn
|
||||||
v-if="route.name !== 'ItemSummary'"
|
v-if="$route.name !== 'ItemSummary'"
|
||||||
:to="{ name: 'ItemSummary', params: { id: entityId } }"
|
:to="{ name: 'ItemSummary', params: { id: entityId } }"
|
||||||
class="header link"
|
class="header link--white"
|
||||||
>
|
icon="open_in_new"
|
||||||
<QIcon name="open_in_new" color="white" size="sm" />
|
flat
|
||||||
</router-link>
|
dense
|
||||||
|
round
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #header="{ entity: { item } }">
|
<template #header="{ entity: { item } }">
|
||||||
{{ item.id }} - {{ item.name }}
|
{{ item.id }} - {{ item.name }}
|
||||||
|
@ -65,15 +53,10 @@ const isAdministrative = computed(() => {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle
|
||||||
:is="isBuyer ? 'router-link' : 'span'"
|
:url="getUrl(entityId, 'basic-data')"
|
||||||
:to="{ name: 'ItemBasicData', params: { id: entityId } }"
|
:text="t('item.summary.basicData')"
|
||||||
class="header"
|
/>
|
||||||
:class="{ 'header-link': isBuyer }"
|
|
||||||
>
|
|
||||||
{{ t('item.summary.basicData') }}
|
|
||||||
<QIcon v-if="isBuyer" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<VnLv :label="t('item.summary.name')" :value="item.name" />
|
<VnLv :label="t('item.summary.name')" :value="item.name" />
|
||||||
<VnLv :label="t('item.summary.completeName')" :value="item.longName" />
|
<VnLv :label="t('item.summary.completeName')" :value="item.longName" />
|
||||||
<VnLv :label="t('item.summary.family')" :value="item.itemType.name" />
|
<VnLv :label="t('item.summary.family')" :value="item.itemType.name" />
|
||||||
|
@ -104,15 +87,10 @@ const isAdministrative = computed(() => {
|
||||||
</VnLv>
|
</VnLv>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle
|
||||||
:is="isBuyer ? 'router-link' : 'span'"
|
:url="getUrl(entityId, 'basic-data')"
|
||||||
:to="{ name: 'ItemBasicData', params: { id: entityId } }"
|
:text="t('item.summary.otherData')"
|
||||||
class="header"
|
/>
|
||||||
:class="{ 'header-link': isBuyer }"
|
|
||||||
>
|
|
||||||
{{ t('item.summary.otherData') }}
|
|
||||||
<QIcon v-if="isBuyer" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('item.summary.intrastatCode')"
|
:label="t('item.summary.intrastatCode')"
|
||||||
:value="item.intrastat.id"
|
:value="item.intrastat.id"
|
||||||
|
@ -137,15 +115,7 @@ const isAdministrative = computed(() => {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle :url="getUrl(entityId, 'tags')" :text="t('item.summary.tags')" />
|
||||||
:is="isBuyer || isReplenisher ? 'router-link' : 'span'"
|
|
||||||
:to="{ name: 'ItemTags', params: { id: entityId } }"
|
|
||||||
class="header"
|
|
||||||
:class="{ 'header-link': isBuyer || isReplenisher }"
|
|
||||||
>
|
|
||||||
{{ t('item.summary.tags') }}
|
|
||||||
<QIcon v-if="isBuyer || isReplenisher" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
v-for="(tag, index) in tags"
|
v-for="(tag, index) in tags"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
@ -154,29 +124,14 @@ const isAdministrative = computed(() => {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one" v-if="item.description">
|
<QCard class="vn-one" v-if="item.description">
|
||||||
<component
|
<VnTitle
|
||||||
:is="isBuyer ? 'router-link' : 'span'"
|
:url="getUrl(entityId, 'basic-data')"
|
||||||
:to="{ name: 'ItemBasicData', params: { id: entityId } }"
|
:text="t('item.summary.description')"
|
||||||
class="header"
|
/>
|
||||||
:class="{ 'header-link': isBuyer }"
|
<p v-text="item.description" />
|
||||||
>
|
|
||||||
{{ t('item.summary.description') }}
|
|
||||||
<QIcon v-if="isBuyer" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<p>
|
|
||||||
{{ item.description }}
|
|
||||||
</p>
|
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle :url="getUrl(entityId, 'tax')" :text="t('item.summary.tax')" />
|
||||||
:is="isBuyer || isAdministrative ? 'router-link' : 'span'"
|
|
||||||
:to="{ name: 'ItemTax', params: { id: entityId } }"
|
|
||||||
class="header"
|
|
||||||
:class="{ 'header-link': isBuyer || isAdministrative }"
|
|
||||||
>
|
|
||||||
{{ t('item.summary.tax') }}
|
|
||||||
<QIcon v-if="isBuyer || isAdministrative" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<VnLv
|
<VnLv
|
||||||
v-for="(tax, index) in item.taxes"
|
v-for="(tax, index) in item.taxes"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
@ -185,15 +140,10 @@ const isAdministrative = computed(() => {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle
|
||||||
:is="isBuyer ? 'router-link' : 'span'"
|
:url="getUrl(entityId, 'botanical')"
|
||||||
:to="{ name: 'ItemBotanical', params: { id: entityId } }"
|
:text="t('item.summary.botanical')"
|
||||||
class="header"
|
/>
|
||||||
:class="{ 'header-link': isBuyer }"
|
|
||||||
>
|
|
||||||
{{ t('item.summary.botanical') }}
|
|
||||||
<QIcon v-if="isBuyer" name="open_in_new" />
|
|
||||||
</component>
|
|
||||||
<VnLv :label="t('item.summary.genus')" :value="botanical?.genus?.name" />
|
<VnLv :label="t('item.summary.genus')" :value="botanical?.genus?.name" />
|
||||||
<VnLv
|
<VnLv
|
||||||
:label="t('item.summary.specie')"
|
:label="t('item.summary.specie')"
|
||||||
|
@ -201,23 +151,19 @@ const isAdministrative = computed(() => {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<component
|
<VnTitle
|
||||||
:is="isBuyer || isReplenisher ? 'router-link' : 'span'"
|
:url="getUrl(entityId, 'barcode')"
|
||||||
:to="{ name: 'ItemBarcode', params: { id: entityId } }"
|
:text="t('item.summary.barcode')"
|
||||||
class="header"
|
/>
|
||||||
:class="{ 'header-link': isBuyer || isReplenisher }"
|
<p
|
||||||
>
|
v-for="(barcode, index) in item.itemBarcode"
|
||||||
{{ t('item.summary.barcode') }}
|
:key="index"
|
||||||
<QIcon v-if="isBuyer || isReplenisher" name="open_in_new" />
|
v-text="barcode.code"
|
||||||
</component>
|
/>
|
||||||
<p v-for="(barcode, index) in item.itemBarcode" :key="index">
|
|
||||||
{{ barcode.code }}
|
|
||||||
</p>
|
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
</CardSummary>
|
</CardSummary>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
Este artículo necesita una foto: Este artículo necesita una foto
|
Este artículo necesita una foto: Este artículo necesita una foto
|
||||||
|
|
|
@ -168,19 +168,20 @@ const insertTag = (rows) => {
|
||||||
</div>
|
</div>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
<VnRow class="justify-center items-center">
|
<VnRow class="justify-center items-center">
|
||||||
<QIcon
|
<QBtn
|
||||||
@click="insertTag(rows)"
|
@click="insertTag(rows)"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
:disable="!validRow"
|
:disable="!validRow"
|
||||||
color="primary"
|
color="primary"
|
||||||
name="add"
|
flat
|
||||||
size="sm"
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
style="flex: 0"
|
style="flex: 0"
|
||||||
>
|
>
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('itemTags.addTag') }}
|
{{ t('itemTags.addTag') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QBtn>
|
||||||
</VnRow>
|
</VnRow>
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -212,6 +212,7 @@ const decrement = (paramsObj, key) => {
|
||||||
flat
|
flat
|
||||||
dense
|
dense
|
||||||
size="12px"
|
size="12px"
|
||||||
|
shortcut="+"
|
||||||
@click="add(params, 'scopeDays')"
|
@click="add(params, 'scopeDays')"
|
||||||
/>
|
/>
|
||||||
<QBtn
|
<QBtn
|
||||||
|
|
|
@ -374,8 +374,10 @@ function addOrder(value, field, params) {
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem class="q-mt-lg">
|
<QItem class="q-mt-lg">
|
||||||
<QIcon
|
<QBtn
|
||||||
name="add_circle"
|
icon="add_circle"
|
||||||
|
shortcut="+"
|
||||||
|
flat
|
||||||
class="filter-icon"
|
class="filter-icon"
|
||||||
@click="tagValues.push({})"
|
@click="tagValues.push({})"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
<script setup>
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { useState } from 'composables/useState';
|
||||||
|
import FormModelPopup from 'components/FormModelPopup.vue';
|
||||||
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
import { useDialogPluginComponent } from 'quasar';
|
||||||
|
import { reactive } from 'vue';
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const route = useRoute();
|
||||||
|
const state = useState();
|
||||||
|
const ORDER_MODEL = 'order';
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const clientList = ref([]);
|
||||||
|
const agencyList = ref([]);
|
||||||
|
const addressList = ref([]);
|
||||||
|
defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||||
|
|
||||||
|
const fetchAddressList = async (addressId) => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get('addresses', {
|
||||||
|
params: {
|
||||||
|
filter: JSON.stringify({
|
||||||
|
fields: ['id', 'nickname', 'street', 'city'],
|
||||||
|
where: { id: addressId },
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addressList.value = data;
|
||||||
|
if (addressList.value?.length === 1) {
|
||||||
|
state.get(ORDER_MODEL).addressId = addressList.value[0].id;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error fetching addresses`, err);
|
||||||
|
return err.response;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchAgencyList = async (landed, addressFk) => {
|
||||||
|
if (!landed || !addressFk) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get('Agencies/landsThatDay', {
|
||||||
|
params: {
|
||||||
|
addressFk,
|
||||||
|
landed: new Date(landed).toISOString(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
agencyList.value = data;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`Error fetching agencies`, err);
|
||||||
|
return err.response;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// const fetchOrderDetails = (order) => {
|
||||||
|
// fetchAddressList(order?.addressFk);
|
||||||
|
// fetchAgencyList(order?.landed, order?.addressFk);
|
||||||
|
// };
|
||||||
|
const $props = defineProps({
|
||||||
|
clientFk: {
|
||||||
|
type: Number,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const initialFormState = reactive({
|
||||||
|
active: true,
|
||||||
|
addressId: null,
|
||||||
|
clientFk: $props.clientFk,
|
||||||
|
});
|
||||||
|
// const orderMapper = (order) => {
|
||||||
|
// return {
|
||||||
|
// addressId: order.addressFk,
|
||||||
|
// agencyModeId: order.agencyModeFk,
|
||||||
|
// landed: new Date(order.landed).toISOString(),
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
// const orderFilter = {
|
||||||
|
// include: [
|
||||||
|
// { relation: 'agencyMode', scope: { fields: ['name'] } },
|
||||||
|
// {
|
||||||
|
// relation: 'address',
|
||||||
|
// scope: { fields: ['nickname'] },
|
||||||
|
// },
|
||||||
|
// { relation: 'rows', scope: { fields: ['id'] } },
|
||||||
|
// {
|
||||||
|
// relation: 'client',
|
||||||
|
// scope: {
|
||||||
|
// fields: [
|
||||||
|
// 'salesPersonFk',
|
||||||
|
// 'name',
|
||||||
|
// 'isActive',
|
||||||
|
// 'isFreezed',
|
||||||
|
// 'isTaxDataChecked',
|
||||||
|
// ],
|
||||||
|
// include: {
|
||||||
|
// relation: 'salesPersonUser',
|
||||||
|
// scope: { fields: ['id', 'name'] },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// };
|
||||||
|
|
||||||
|
const onClientChange = async (clientId = $props.clientFk) => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get(`Clients/${clientId}`);
|
||||||
|
await fetchAddressList(data.defaultAddressFk);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error al cambiar el cliente:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
async function onDataSaved(_, id) {
|
||||||
|
await router.push({ path: `/order/${id}/catalog` });
|
||||||
|
}
|
||||||
|
onMounted(async () => {
|
||||||
|
await onClientChange();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="addresses"
|
||||||
|
@on-fetch="(data) => (clientOptions = data)"
|
||||||
|
:filter="{ fields: ['id', 'name', 'defaultAddressFk'], order: 'id' }"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<FormModelPopup
|
||||||
|
url-create="Orders/new"
|
||||||
|
:title="t('Create Order')"
|
||||||
|
@on-data-saved="onDataSaved"
|
||||||
|
:model="ORDER_MODEL"
|
||||||
|
:filter="orderFilter"
|
||||||
|
:form-initial-data="initialFormState"
|
||||||
|
>
|
||||||
|
<template #form-inputs="{ data }">
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnSelect
|
||||||
|
url="Clients"
|
||||||
|
:label="t('order.form.clientFk')"
|
||||||
|
v-model="data.clientFk"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
:filter="{
|
||||||
|
fields: ['id', 'name', 'defaultAddressFk'],
|
||||||
|
}"
|
||||||
|
hide-selected
|
||||||
|
@update:model-value="onClientChange"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{ `${scope.opt.id}: ${scope.opt.name}` }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('order.form.addressFk')"
|
||||||
|
v-model="data.addressId"
|
||||||
|
:options="addressList"
|
||||||
|
option-value="id"
|
||||||
|
option-label="street"
|
||||||
|
hide-selected
|
||||||
|
:disable="!addressList?.length"
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
{{
|
||||||
|
`${scope.opt.nickname}: ${scope.opt.street},${scope.opt.city}`
|
||||||
|
}}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnInputDate
|
||||||
|
placeholder="dd-mm-aaa"
|
||||||
|
:label="t('order.form.landed')"
|
||||||
|
v-model="data.landed"
|
||||||
|
@update:model-value="
|
||||||
|
() => fetchAgencyList(data.landed, data.addressId)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</VnRow>
|
||||||
|
<VnRow class="row q-gutter-md q-mb-md">
|
||||||
|
<VnSelect
|
||||||
|
:label="t('order.form.agencyModeFk')"
|
||||||
|
v-model="data.agencyModeId"
|
||||||
|
:options="agencyList"
|
||||||
|
option-value="agencyModeFk"
|
||||||
|
option-label="agencyMode"
|
||||||
|
hide-selected
|
||||||
|
:disable="!agencyList?.length"
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
</FormModelPopup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
No default address found for the client: No hay ninguna dirección asociada a este cliente.
|
||||||
|
</i18n>
|
|
@ -88,7 +88,7 @@ async function deleteWorCenter(id) {
|
||||||
</VnPaginate>
|
</VnPaginate>
|
||||||
</div>
|
</div>
|
||||||
<QPageSticky :offset="[18, 18]">
|
<QPageSticky :offset="[18, 18]">
|
||||||
<QBtn @click.stop="dialog.show()" color="primary" fab icon="add">
|
<QBtn @click.stop="dialog.show()" color="primary" fab shortcut="+" icon="add">
|
||||||
<QDialog ref="dialog">
|
<QDialog ref="dialog">
|
||||||
<FormModelPopup
|
<FormModelPopup
|
||||||
:title="t('Add work center')"
|
:title="t('Add work center')"
|
||||||
|
|
|
@ -3,7 +3,6 @@ import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<VnSearchbar
|
<VnSearchbar
|
||||||
data-key="RouteList"
|
data-key="RouteList"
|
||||||
|
|
|
@ -103,8 +103,8 @@ es:
|
||||||
Roadmap: Troncal
|
Roadmap: Troncal
|
||||||
ETD date: Fecha ETD
|
ETD date: Fecha ETD
|
||||||
ETD hour: Hora ETD
|
ETD hour: Hora ETD
|
||||||
Tractor plate: Matrícula tractor
|
Tractor plate: Matrícula tractora
|
||||||
Trailer plate: Matrícula trailer
|
Trailer plate: Matrícula remolque
|
||||||
Carrier: Transportista
|
Carrier: Transportista
|
||||||
Price: Precio
|
Price: Precio
|
||||||
Driver name: Nombre del conductor
|
Driver name: Nombre del conductor
|
||||||
|
|
|
@ -164,8 +164,8 @@ en:
|
||||||
to: To
|
to: To
|
||||||
es:
|
es:
|
||||||
params:
|
params:
|
||||||
tractorPlate: Matrícula del tractor
|
tractorPlate: Matrícula tractora
|
||||||
trailerPlate: Matrícula del trailer
|
trailerPlate: Matrícula remolque
|
||||||
supplierFk: Transportista
|
supplierFk: Transportista
|
||||||
price: Precio
|
price: Precio
|
||||||
driverName: Nombre del conductor
|
driverName: Nombre del conductor
|
||||||
|
@ -174,8 +174,8 @@ es:
|
||||||
to: Hasta
|
to: Hasta
|
||||||
From: Desde
|
From: Desde
|
||||||
To: Hasta
|
To: Hasta
|
||||||
Tractor Plate: Matrícula del tractor
|
Tractor Plate: Matrícula tractora
|
||||||
Trailer Plate: Matrícula del trailer
|
Trailer Plate: Matrícula remolque
|
||||||
Carrier: Transportista
|
Carrier: Transportista
|
||||||
Price: Precio
|
Price: Precio
|
||||||
Driver name: Nombre del conductor
|
Driver name: Nombre del conductor
|
||||||
|
|
|
@ -65,9 +65,10 @@ const updateDefaultStop = (data) => {
|
||||||
</div>
|
</div>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardSection>
|
<QCardSection>
|
||||||
<QIcon
|
<QBtn
|
||||||
name="add"
|
flat
|
||||||
size="sm"
|
icon="add"
|
||||||
|
shortcut="+"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
color="primary"
|
color="primary"
|
||||||
@click="roadmapStopsCrudRef.insert()"
|
@click="roadmapStopsCrudRef.insert()"
|
||||||
|
@ -75,7 +76,7 @@ const updateDefaultStop = (data) => {
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
{{ t('Add stop') }}
|
{{ t('Add stop') }}
|
||||||
</QTooltip>
|
</QTooltip>
|
||||||
</QIcon>
|
</QBtn>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Usar la propiedad searchUrl a false para esto
searchUrl es una propiedad de tipo String que tiene por defecto table.
Aunque no la declares, te pone table
Si la declaras no puedes decirle que valga false, null o undefined
Ni poniendo q el type sea [string, boolean]??
Si esta solución la había planteado y probado, pero no me gustaba porque mezcla 2 tipos. Aunque veo que hay 2 resultados mas para esta combinación
Uf es q lo veo mas facil de usar que añadir un parametro mas.
Creo que poniendo el if y pasando comillas vacias haria la funcion de booleano jajja