Merge branch 'dev' into 7354_ZoneMigration_End
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
gitea/salix-front/pipeline/pr-dev This commit looks good
Details
This commit is contained in:
commit
1af4a559fc
138
CHANGELOG.md
138
CHANGELOG.md
|
@ -1,3 +1,141 @@
|
||||||
|
# Version 24.36 - 2024-08-27
|
||||||
|
|
||||||
|
### Added 🆕
|
||||||
|
|
||||||
|
- feat(FormModel): trim data by default by:alexm
|
||||||
|
- feat(orderBasicData): add notes by:alexm
|
||||||
|
- feat(orderList): correct create order by:alexm
|
||||||
|
- feat(orderList): use orderFilter and fixed this by:alexm
|
||||||
|
- feat: #7323 handle workerPhoto (origin/7323_workerPhoto, 7323_workerPhoto) by:Javier Segarra
|
||||||
|
- feat: add recover password and reset password by:alexm
|
||||||
|
- feat: refs #7346 add seriaType option by:jgallego
|
||||||
|
- feat: refs #7346 elimino === by:jgallego
|
||||||
|
- feat: refs #7346 formdata uses serialType by:jgallego
|
||||||
|
- feat: refs #7346 refactor by:jgallego
|
||||||
|
- feat: refs #7346 sonarLint warnings (origin/7346-invoiceOutMultilple, 7346-invoiceOutMultilple) by:jgallego
|
||||||
|
- feat: refs #7710 uses cloneAll by:jgallego
|
||||||
|
- fix: refs #7717 fix OrderList table filters' and summary table style by:Jon
|
||||||
|
|
||||||
|
### Changed 📦
|
||||||
|
|
||||||
|
- feat: refs #7346 refactor by:jgallego
|
||||||
|
- perf: date fields (mindshore/feature/TicketFutureFilter, feature/TicketFutureFilter) by:Javier Segarra
|
||||||
|
- perf: refs #7717 right menu filter by:Jon
|
||||||
|
- perf: use ref at component start by:Javier Segarra
|
||||||
|
- refactor: refs #7717 delete useless function and import by:Jon
|
||||||
|
- refactor: refs #7717 deleted useless code by:Jon
|
||||||
|
|
||||||
|
### Fixed 🛠️
|
||||||
|
|
||||||
|
- feat(orderList): use orderFilter and fixed this by:alexm
|
||||||
|
- fix(VnTable): orderBy v-model by:alexm
|
||||||
|
- fix(account_card): redirection by:carlossa
|
||||||
|
- fix(orderLines): reload when delete and redirect when confirm by:alexm
|
||||||
|
- fix: #6336 ClaimListStates by:Javier Segarra
|
||||||
|
- fix: account subsections cards by:carlossa
|
||||||
|
- fix: duplicate key by:Jon
|
||||||
|
- fix: order description to vnTable by:alexm
|
||||||
|
- fix: orderCatalogFilter order by:alexm
|
||||||
|
- fix: quasar build warnings (6336_claim_fix_states) by:Javier Segarra
|
||||||
|
- fix: refs #7717 fix OrderList table filters' and summary table style by:Jon
|
||||||
|
- fix: refs #7717 fix basic data form & minor errors by:Jon
|
||||||
|
- fix: refs #7717 fix catalog filter, searchbar redirect and search by:Jon
|
||||||
|
- fix: refs #7717 fix catalog searchbar and worker tests(refs #7323) by:Jon
|
||||||
|
- fix: refs #7717 fix order sections by:Jon
|
||||||
|
- fix: refs #7717 fix volume and lines redirect by:Jon
|
||||||
|
- fix: refs #7717 fixed searchbar filter with rightmenu filters' applied by:Jon
|
||||||
|
- fix: test by:alexm
|
||||||
|
- fix: ticketDescriptorMenu by:Javier Segarra
|
||||||
|
- refs #7355 account fixes by:carlossa
|
||||||
|
|
||||||
|
# Version 24.34 - 2024-08-20
|
||||||
|
|
||||||
|
### Added 🆕
|
||||||
|
|
||||||
|
- chore: #6900 order params by:jorgep
|
||||||
|
- chore: refs #6900 drop console log by:jorgep
|
||||||
|
- chore: refs #6900 drop vnCurrency by:jorgep
|
||||||
|
- chore: refs #6900 fix e2e tests by:jorgep
|
||||||
|
- chore: refs #6900 mv rectificative logic by:jorgep
|
||||||
|
- chore: refs #6900 responsive code by:jorgep
|
||||||
|
- chore: refs #7283 drop array types by:jorgep
|
||||||
|
- chore: refs #7283 drop import by:jorgep
|
||||||
|
- chore: refs #7283 fix e2e logout by:jorgep
|
||||||
|
- chore: refs #7283 update VnAvatar title handling by:jorgep
|
||||||
|
- chore: refs #7323 fix test by:jorgep
|
||||||
|
- chore: refs #7323 remove unused import by:jorgep
|
||||||
|
- chore: refs #7323drop commented code by:jorgep
|
||||||
|
- feat(VnCard): use props searchbar by:alexm
|
||||||
|
- feat(customer): improve basicData to balance by:alexm
|
||||||
|
- feat(customer_balance): refs #6943 add functionality from salix by:alexm
|
||||||
|
- feat(customer_balance): refs #6943 translations by:alexm
|
||||||
|
- feat: refs #6130 husky commitLint config by:pablone
|
||||||
|
- feat: refs #6130 husky hooks by:pablone
|
||||||
|
- feat: refs #6900 add InvoiceInSerial by:jorgep
|
||||||
|
- feat: refs #6900 add locale by:jorgep
|
||||||
|
- feat: refs #6900 use VnTable & sort filter fields by:jorgep
|
||||||
|
- feat: refs #7323 add flex-wrap by:jorgep
|
||||||
|
- feat: refs #7323 add my account" btn & fix models log selectable by:jorgep
|
||||||
|
- feat: refs #7323 improve test by:jorgep
|
||||||
|
|
||||||
|
### Changed 📦
|
||||||
|
|
||||||
|
- refactor(customer_log: use VnLog by:alexm
|
||||||
|
- refactor(customer_recovery): to vnTable by:alexm
|
||||||
|
- refactor(customer_webAccess): FormModel by:alexm
|
||||||
|
- refactor: refs #7283 update avatar size and color by:jorgep
|
||||||
|
|
||||||
|
### Fixed 🛠️
|
||||||
|
|
||||||
|
- chore: refs #6900 fix e2e tests by:jorgep
|
||||||
|
- chore: refs #7283 fix e2e logout by:jorgep
|
||||||
|
- chore: refs #7323 fix test by:jorgep
|
||||||
|
- feat: refs #7323 add my account" btn & fix models log selectable by:jorgep
|
||||||
|
- fix #7355 fix acls list by:carlossa
|
||||||
|
- fix(VnFilterPanel): emit userParams better by:alexm
|
||||||
|
- fix(claim_summary): url links (HEAD -> 7864_testToMaster_2434, origin/test, origin/7864_testToMaster_2434, test) by:alexm
|
||||||
|
- fix(customer_sms: fix reload by:alexm
|
||||||
|
- fix(twoFactor): unify code login and twoFactor by:alexm
|
||||||
|
- fix: VnCard VnSearchbar props by:alexm
|
||||||
|
- fix: accountMailAlias by:alexm
|
||||||
|
- fix: refs #6130 add commit lint modules by:pablone
|
||||||
|
- fix: refs #6130 pnpm-lock.yml by:pablone
|
||||||
|
- fix: refs #6900 improve loading by:jorgep
|
||||||
|
- fix: refs #6900 improve logic (origin/6900-addSerial) by:jorgep
|
||||||
|
- fix: refs #6900 improve logic by:jorgep
|
||||||
|
- fix: refs #6900 rectificative btn reactivity by:jorgep
|
||||||
|
- fix: refs #6900 use type number by:jorgep
|
||||||
|
- fix: refs #6900 vat & dueday by:jorgep
|
||||||
|
- fix: refs #6900 vat, dueday & intrastat by:jorgep
|
||||||
|
- fix: refs #6989 show entity name & default time from config table by:jorgep
|
||||||
|
- fix: refs #7283 basicData locale by:jorgep
|
||||||
|
- fix: refs #7283 itemLastEntries filter by:jorgep
|
||||||
|
- fix: refs #7283 itemTags & VnImg by:jorgep
|
||||||
|
- fix: refs #7283 locale by:jorgep
|
||||||
|
- fix: refs #7283 min-width vnImg by:jorgep
|
||||||
|
- fix: refs #7283 use vnAvatar & add optional zoom by:jorgep
|
||||||
|
- fix: refs #7283 userPanel pic by:jorgep
|
||||||
|
- fix: refs #7323 add department popup by:jorgep
|
||||||
|
- fix: refs #7323 add locale by:jorgep
|
||||||
|
- fix: refs #7323 css righ menu by:jorgep
|
||||||
|
- fix: refs #7323 data-key & add select by:jorgep
|
||||||
|
- fix: refs #7323 load all opts by:jorgep
|
||||||
|
- fix: refs #7323 righ menu bug by:jorgep
|
||||||
|
- fix: refs #7323 use global locale by:jorgep
|
||||||
|
- fix: refs #7323 use workerFilter (origin/7323-warmfix-fixErrors) by:jorgep
|
||||||
|
- fix: refs #7323 vnsubtoolbar css by:jorgep
|
||||||
|
- fix: refs #7323 wrong css by:jorgep
|
||||||
|
- refs #7355 fix Rol, alias by:carlossa
|
||||||
|
- refs #7355 fix accountAlias by:carlossa
|
||||||
|
- refs #7355 fix alias summary by:carlossa
|
||||||
|
- refs #7355 fix conflicts by:carlossa
|
||||||
|
- refs #7355 fix create Rol by:carlossa
|
||||||
|
- refs #7355 fix list by:carlossa
|
||||||
|
- refs #7355 fix lists redirects summary by:carlossa
|
||||||
|
- refs #7355 fix roles by:carlossa
|
||||||
|
- refs #7355 fix search exprBuilder by:carlossa
|
||||||
|
- refs #7355 fix vnTable by:carlossa
|
||||||
|
|
||||||
# Version 24.32 - 2024-08-06
|
# Version 24.32 - 2024-08-06
|
||||||
|
|
||||||
### Added 🆕
|
### Added 🆕
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "salix-front",
|
"name": "salix-front",
|
||||||
"version": "24.34.0",
|
"version": "24.36.0",
|
||||||
"description": "Salix frontend",
|
"description": "Salix frontend",
|
||||||
"productName": "Salix",
|
"productName": "Salix",
|
||||||
"author": "Verdnatura",
|
"author": "Verdnatura",
|
||||||
|
|
|
@ -107,7 +107,7 @@ const orders = ref(parseOrder(routeQuery.filter?.order));
|
||||||
const CrudModelRef = ref({});
|
const CrudModelRef = ref({});
|
||||||
const showForm = ref(false);
|
const showForm = ref(false);
|
||||||
const splittedColumns = ref({ columns: [] });
|
const splittedColumns = ref({ columns: [] });
|
||||||
const columnsVisibilitySkiped = ref();
|
const columnsVisibilitySkipped = ref();
|
||||||
const createForm = ref();
|
const createForm = ref();
|
||||||
|
|
||||||
const tableModes = [
|
const tableModes = [
|
||||||
|
@ -135,7 +135,7 @@ onMounted(() => {
|
||||||
? CARD_MODE
|
? CARD_MODE
|
||||||
: $props.defaultMode;
|
: $props.defaultMode;
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
columnsVisibilitySkiped.value = [
|
columnsVisibilitySkipped.value = [
|
||||||
...splittedColumns.value.columns
|
...splittedColumns.value.columns
|
||||||
.filter((c) => c.visible == false)
|
.filter((c) => c.visible == false)
|
||||||
.map((c) => c.name),
|
.map((c) => c.name),
|
||||||
|
@ -342,296 +342,280 @@ defineExpose({
|
||||||
</QScrollArea>
|
</QScrollArea>
|
||||||
</QDrawer>
|
</QDrawer>
|
||||||
<!-- class in div to fix warn-->
|
<!-- class in div to fix warn-->
|
||||||
<div class="q-px-md">
|
|
||||||
<CrudModel
|
<CrudModel
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:limit="20"
|
:class="$attrs['class'] ?? 'q-px-md'"
|
||||||
ref="CrudModelRef"
|
:limit="20"
|
||||||
@on-fetch="(...args) => emit('onFetch', ...args)"
|
ref="CrudModelRef"
|
||||||
:search-url="searchUrl"
|
@on-fetch="(...args) => emit('onFetch', ...args)"
|
||||||
:disable-infinite-scroll="isTableMode"
|
:search-url="searchUrl"
|
||||||
@save-changes="reload"
|
:disable-infinite-scroll="isTableMode"
|
||||||
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
@save-changes="reload"
|
||||||
:auto-load="hasParams || $attrs['auto-load']"
|
:has-sub-toolbar="$attrs['hasSubToolbar'] ?? isEditable"
|
||||||
>
|
:auto-load="hasParams || $attrs['auto-load']"
|
||||||
<template
|
>
|
||||||
v-for="(_, slotName) in $slots"
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotData" :key="slotName">
|
||||||
#[slotName]="slotData"
|
<slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
|
||||||
:key="slotName"
|
</template>
|
||||||
|
<template #body="{ rows }">
|
||||||
|
<QTable
|
||||||
|
v-bind="table"
|
||||||
|
class="vnTable"
|
||||||
|
:columns="splittedColumns.columns"
|
||||||
|
:rows="rows"
|
||||||
|
v-model:selected="selected"
|
||||||
|
:grid="!isTableMode"
|
||||||
|
table-header-class="bg-header"
|
||||||
|
card-container-class="grid-three"
|
||||||
|
flat
|
||||||
|
:style="isTableMode && `max-height: ${tableHeight}`"
|
||||||
|
virtual-scroll
|
||||||
|
@virtual-scroll="
|
||||||
|
(event) =>
|
||||||
|
event.index > rows.length - 2 &&
|
||||||
|
CrudModelRef.vnPaginateRef.paginate()
|
||||||
|
"
|
||||||
|
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
||||||
|
@update:selected="emit('update:selected', $event)"
|
||||||
>
|
>
|
||||||
<slot :name="slotName" v-bind="slotData ?? {}" :key="slotName" />
|
<template #top-left v-if="!$props.withoutHeader">
|
||||||
</template>
|
<slot name="top-left"></slot>
|
||||||
<template #body="{ rows }">
|
</template>
|
||||||
<QTable
|
<template #top-right v-if="!$props.withoutHeader">
|
||||||
v-bind="table"
|
<VnVisibleColumn
|
||||||
class="vnTable"
|
v-if="isTableMode"
|
||||||
:columns="splittedColumns.columns"
|
v-model="splittedColumns.columns"
|
||||||
:rows="rows"
|
:table-code="tableCode ?? route.name"
|
||||||
v-model:selected="selected"
|
:skip="columnsVisibilitySkipped"
|
||||||
:grid="!isTableMode"
|
/>
|
||||||
table-header-class="bg-header"
|
<QBtnToggle
|
||||||
card-container-class="grid-three"
|
v-model="mode"
|
||||||
flat
|
toggle-color="primary"
|
||||||
:style="isTableMode && `max-height: ${tableHeight}`"
|
class="bg-vn-section-color"
|
||||||
virtual-scroll
|
dense
|
||||||
@virtual-scroll="
|
:options="tableModes.filter((mode) => !mode.disable)"
|
||||||
(event) =>
|
/>
|
||||||
event.index > rows.length - 2 &&
|
<QBtn
|
||||||
CrudModelRef.vnPaginateRef.paginate()
|
v-if="$props.rightSearch"
|
||||||
"
|
icon="filter_alt"
|
||||||
@row-click="(_, row) => rowClickFunction && rowClickFunction(row)"
|
class="bg-vn-section-color q-ml-md"
|
||||||
@update:selected="emit('update:selected', $event)"
|
dense
|
||||||
>
|
@click="stateStore.toggleRightDrawer()"
|
||||||
<template #top-left v-if="!$props.withoutHeader">
|
/>
|
||||||
<slot name="top-left"></slot>
|
</template>
|
||||||
</template>
|
<template #header-cell="{ col }">
|
||||||
<template #top-right v-if="!$props.withoutHeader">
|
<QTh v-if="col.visible ?? true">
|
||||||
<VnVisibleColumn
|
<div
|
||||||
v-if="isTableMode"
|
class="column self-start q-ml-xs ellipsis"
|
||||||
v-model="splittedColumns.columns"
|
:class="`text-${col?.align ?? 'left'}`"
|
||||||
:table-code="tableCode ?? route.name"
|
:style="$props.columnSearch ? 'height: 75px' : ''"
|
||||||
:skip="columnsVisibilitySkiped"
|
>
|
||||||
/>
|
<div class="row items-center no-wrap" style="height: 30px">
|
||||||
<QBtnToggle
|
<QTooltip v-if="col.toolTip">{{ col.toolTip }}</QTooltip>
|
||||||
v-model="mode"
|
<VnTableOrder
|
||||||
toggle-color="primary"
|
v-model="orders[col.orderBy ?? col.name]"
|
||||||
class="bg-vn-section-color"
|
:name="col.orderBy ?? col.name"
|
||||||
dense
|
:label="col?.label"
|
||||||
:options="tableModes"
|
|
||||||
/>
|
|
||||||
<QBtn
|
|
||||||
v-if="$props.rightSearch"
|
|
||||||
icon="filter_alt"
|
|
||||||
class="bg-vn-section-color q-ml-md"
|
|
||||||
dense
|
|
||||||
@click="stateStore.toggleRightDrawer()"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
<template #header-cell="{ col }">
|
|
||||||
<QTh v-if="col.visible ?? true">
|
|
||||||
<div
|
|
||||||
class="column self-start q-ml-xs ellipsis"
|
|
||||||
:class="`text-${col?.align ?? 'left'}`"
|
|
||||||
:style="$props.columnSearch ? 'height: 75px' : ''"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class="row items-center no-wrap"
|
|
||||||
style="height: 30px"
|
|
||||||
>
|
|
||||||
<VnTableOrder
|
|
||||||
v-model="orders[col.orderBy ?? col.name]"
|
|
||||||
:name="col.orderBy ?? col.name"
|
|
||||||
:label="col?.label"
|
|
||||||
:data-key="$attrs['data-key']"
|
|
||||||
:search-url="searchUrl"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<VnTableFilter
|
|
||||||
v-if="$props.columnSearch"
|
|
||||||
:column="col"
|
|
||||||
:show-title="true"
|
|
||||||
:data-key="$attrs['data-key']"
|
:data-key="$attrs['data-key']"
|
||||||
v-model="params[columnName(col)]"
|
|
||||||
:search-url="searchUrl"
|
:search-url="searchUrl"
|
||||||
class="full-width"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</QTh>
|
<VnTableFilter
|
||||||
</template>
|
v-if="$props.columnSearch"
|
||||||
<template #header-cell-tableActions>
|
:column="col"
|
||||||
<QTh auto-width class="sticky" />
|
:show-title="true"
|
||||||
</template>
|
:data-key="$attrs['data-key']"
|
||||||
<template #body-cell-tableStatus="{ col, row }">
|
v-model="params[columnName(col)]"
|
||||||
<QTd auto-width :class="getColAlign(col)">
|
:search-url="searchUrl"
|
||||||
<VnTableChip
|
class="full-width"
|
||||||
:columns="splittedColumns.columnChips"
|
/>
|
||||||
|
</div>
|
||||||
|
</QTh>
|
||||||
|
</template>
|
||||||
|
<template #header-cell-tableActions>
|
||||||
|
<QTh auto-width class="sticky" />
|
||||||
|
</template>
|
||||||
|
<template #body-cell-tableStatus="{ col, row }">
|
||||||
|
<QTd auto-width :class="getColAlign(col)">
|
||||||
|
<VnTableChip :columns="splittedColumns.columnChips" :row="row">
|
||||||
|
<template #afterChip>
|
||||||
|
<slot name="afterChip" :row="row"></slot>
|
||||||
|
</template>
|
||||||
|
</VnTableChip>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #body-cell="{ col, row, rowIndex }">
|
||||||
|
<!-- Columns -->
|
||||||
|
<QTd
|
||||||
|
auto-width
|
||||||
|
class="no-margin q-px-xs"
|
||||||
|
:class="[getColAlign(col), col.columnClass]"
|
||||||
|
v-if="col.visible ?? true"
|
||||||
|
@click.ctrl="
|
||||||
|
($event) =>
|
||||||
|
rowCtrlClickFunction && rowCtrlClickFunction($event, row)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<slot
|
||||||
|
:name="`column-${col.name}`"
|
||||||
|
:col="col"
|
||||||
|
:row="row"
|
||||||
|
:row-index="rowIndex"
|
||||||
|
>
|
||||||
|
<VnTableColumn
|
||||||
|
:column="col"
|
||||||
:row="row"
|
:row="row"
|
||||||
>
|
:is-editable="col.isEditable ?? isEditable"
|
||||||
<template #afterChip>
|
v-model="row[col.name]"
|
||||||
<slot name="afterChip" :row="row"></slot>
|
component-prop="columnField"
|
||||||
</template>
|
/>
|
||||||
</VnTableChip>
|
</slot>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell="{ col, row, rowIndex }">
|
<template #body-cell-tableActions="{ col, row }">
|
||||||
<!-- Columns -->
|
<QTd
|
||||||
<QTd
|
auto-width
|
||||||
auto-width
|
:class="getColAlign(col)"
|
||||||
class="no-margin q-px-xs"
|
class="sticky no-padding"
|
||||||
:class="[getColAlign(col), col.columnClass]"
|
@click="stopEventPropagation($event)"
|
||||||
v-if="col.visible ?? true"
|
>
|
||||||
@click.ctrl="
|
<QBtn
|
||||||
($event) =>
|
v-for="(btn, index) of col.actions"
|
||||||
rowCtrlClickFunction &&
|
:key="index"
|
||||||
rowCtrlClickFunction($event, row)
|
:title="btn.title"
|
||||||
|
:icon="btn.icon"
|
||||||
|
class="q-px-sm"
|
||||||
|
flat
|
||||||
|
:class="
|
||||||
|
btn.isPrimary ? 'text-primary-light' : 'color-vn-text '
|
||||||
|
"
|
||||||
|
:style="`visibility: ${
|
||||||
|
(btn.show && btn.show(row)) ?? true ? 'visible' : 'hidden'
|
||||||
|
}`"
|
||||||
|
@click="btn.action(row)"
|
||||||
|
/>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
<template #item="{ row, colsMap }">
|
||||||
|
<component
|
||||||
|
:is="$props.redirect ? 'router-link' : 'span'"
|
||||||
|
:to="`/${$props.redirect}/` + row.id"
|
||||||
|
>
|
||||||
|
<QCard
|
||||||
|
bordered
|
||||||
|
flat
|
||||||
|
class="row no-wrap justify-between cursor-pointer"
|
||||||
|
@click="
|
||||||
|
(_, row) => {
|
||||||
|
$props.rowClick && $props.rowClick(row);
|
||||||
|
}
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<slot
|
<QCardSection
|
||||||
:name="`column-${col.name}`"
|
vertical
|
||||||
:col="col"
|
class="no-margin no-padding"
|
||||||
:row="row"
|
:class="colsMap.tableActions ? 'w-80' : 'fit'"
|
||||||
:row-index="rowIndex"
|
|
||||||
>
|
|
||||||
<VnTableColumn
|
|
||||||
:column="col"
|
|
||||||
:row="row"
|
|
||||||
:is-editable="col.isEditable ?? isEditable"
|
|
||||||
v-model="row[col.name]"
|
|
||||||
component-prop="columnField"
|
|
||||||
/>
|
|
||||||
</slot>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #body-cell-tableActions="{ col, row }">
|
|
||||||
<QTd
|
|
||||||
auto-width
|
|
||||||
:class="getColAlign(col)"
|
|
||||||
class="sticky no-padding"
|
|
||||||
@click="stopEventPropagation($event)"
|
|
||||||
>
|
|
||||||
<QBtn
|
|
||||||
v-for="(btn, index) of col.actions"
|
|
||||||
:key="index"
|
|
||||||
:title="btn.title"
|
|
||||||
:icon="btn.icon"
|
|
||||||
class="q-px-sm"
|
|
||||||
flat
|
|
||||||
:class="
|
|
||||||
btn.isPrimary
|
|
||||||
? 'text-primary-light'
|
|
||||||
: 'color-vn-text '
|
|
||||||
"
|
|
||||||
:style="`visibility: ${
|
|
||||||
(btn.show && btn.show(row)) ?? true
|
|
||||||
? 'visible'
|
|
||||||
: 'hidden'
|
|
||||||
}`"
|
|
||||||
@click="btn.action(row)"
|
|
||||||
/>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #item="{ row, colsMap }">
|
|
||||||
<component
|
|
||||||
:is="$props.redirect ? 'router-link' : 'span'"
|
|
||||||
:to="`/${$props.redirect}/` + row.id"
|
|
||||||
>
|
|
||||||
<QCard
|
|
||||||
bordered
|
|
||||||
flat
|
|
||||||
class="row no-wrap justify-between cursor-pointer"
|
|
||||||
@click="
|
|
||||||
(_, row) => {
|
|
||||||
$props.rowClick && $props.rowClick(row);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
|
<!-- Chips -->
|
||||||
<QCardSection
|
<QCardSection
|
||||||
vertical
|
v-if="splittedColumns.chips.length"
|
||||||
class="no-margin no-padding"
|
class="no-margin q-px-xs q-py-none"
|
||||||
:class="colsMap.tableActions ? 'w-80' : 'fit'"
|
|
||||||
>
|
>
|
||||||
<!-- Chips -->
|
<VnTableChip
|
||||||
<QCardSection
|
:columns="splittedColumns.chips"
|
||||||
v-if="splittedColumns.chips.length"
|
:row="row"
|
||||||
class="no-margin q-px-xs q-py-none"
|
|
||||||
>
|
>
|
||||||
<VnTableChip
|
<template #afterChip>
|
||||||
:columns="splittedColumns.chips"
|
<slot name="afterChip" :row="row"></slot>
|
||||||
:row="row"
|
</template>
|
||||||
>
|
</VnTableChip>
|
||||||
<template #afterChip>
|
</QCardSection>
|
||||||
<slot name="afterChip" :row="row"></slot>
|
<!-- Title -->
|
||||||
</template>
|
<QCardSection
|
||||||
</VnTableChip>
|
v-if="splittedColumns.title"
|
||||||
</QCardSection>
|
class="q-pl-sm q-py-none text-primary-light text-bold text-h6 cardEllipsis"
|
||||||
<!-- Title -->
|
>
|
||||||
<QCardSection
|
<span
|
||||||
v-if="splittedColumns.title"
|
:title="row[splittedColumns.title.name]"
|
||||||
class="q-pl-sm q-py-none text-primary-light text-bold text-h6 cardEllipsis"
|
@click="stopEventPropagation($event)"
|
||||||
|
class="cursor-text"
|
||||||
>
|
>
|
||||||
<span
|
{{ row[splittedColumns.title.name] }}
|
||||||
:title="row[splittedColumns.title.name]"
|
</span>
|
||||||
@click="stopEventPropagation($event)"
|
</QCardSection>
|
||||||
class="cursor-text"
|
<!-- Fields -->
|
||||||
>
|
<QCardSection
|
||||||
{{ row[splittedColumns.title.name] }}
|
class="q-pl-sm q-pr-lg q-py-xs"
|
||||||
</span>
|
:class="$props.cardClass"
|
||||||
</QCardSection>
|
>
|
||||||
<!-- Fields -->
|
<div
|
||||||
<QCardSection
|
v-for="(
|
||||||
class="q-pl-sm q-pr-lg q-py-xs"
|
col, index
|
||||||
:class="$props.cardClass"
|
) of splittedColumns.cardVisible"
|
||||||
|
:key="col.name"
|
||||||
|
class="fields"
|
||||||
>
|
>
|
||||||
<div
|
<VnLv
|
||||||
v-for="(
|
:label="
|
||||||
col, index
|
!col.component && col.label
|
||||||
) of splittedColumns.cardVisible"
|
? `${col.label}:`
|
||||||
:key="col.name"
|
: ''
|
||||||
class="fields"
|
"
|
||||||
>
|
>
|
||||||
<VnLv
|
<template #value>
|
||||||
:label="
|
<span
|
||||||
!col.component && col.label
|
@click="stopEventPropagation($event)"
|
||||||
? `${col.label}:`
|
>
|
||||||
: ''
|
<slot
|
||||||
"
|
:name="`column-${col.name}`"
|
||||||
>
|
:col="col"
|
||||||
<template #value>
|
:row="row"
|
||||||
<span
|
:row-index="index"
|
||||||
@click="
|
|
||||||
stopEventPropagation($event)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<slot
|
<VnTableColumn
|
||||||
:name="`column-${col.name}`"
|
:column="col"
|
||||||
:col="col"
|
|
||||||
:row="row"
|
:row="row"
|
||||||
:row-index="index"
|
:is-editable="false"
|
||||||
>
|
v-model="row[col.name]"
|
||||||
<VnTableColumn
|
component-prop="columnField"
|
||||||
:column="col"
|
:show-label="true"
|
||||||
:row="row"
|
/>
|
||||||
:is-editable="false"
|
</slot>
|
||||||
v-model="row[col.name]"
|
</span>
|
||||||
component-prop="columnField"
|
</template>
|
||||||
:show-label="true"
|
</VnLv>
|
||||||
/>
|
</div>
|
||||||
</slot>
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
</VnLv>
|
|
||||||
</div>
|
|
||||||
</QCardSection>
|
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<!-- Actions -->
|
</QCardSection>
|
||||||
<QCardSection
|
<!-- Actions -->
|
||||||
v-if="colsMap.tableActions"
|
<QCardSection
|
||||||
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
|
v-if="colsMap.tableActions"
|
||||||
@click="stopEventPropagation($event)"
|
class="column flex-center w-10 no-margin q-pa-xs q-gutter-y-xs"
|
||||||
>
|
@click="stopEventPropagation($event)"
|
||||||
<QBtn
|
>
|
||||||
v-for="(btn, index) of splittedColumns.actions
|
<QBtn
|
||||||
.actions"
|
v-for="(btn, index) of splittedColumns.actions
|
||||||
:key="index"
|
.actions"
|
||||||
:title="btn.title"
|
:key="index"
|
||||||
:icon="btn.icon"
|
:title="btn.title"
|
||||||
class="q-pa-xs"
|
:icon="btn.icon"
|
||||||
flat
|
class="q-pa-xs"
|
||||||
:class="
|
flat
|
||||||
btn.isPrimary
|
:class="
|
||||||
? 'text-primary-light'
|
btn.isPrimary
|
||||||
: 'color-vn-text '
|
? 'text-primary-light'
|
||||||
"
|
: 'color-vn-text '
|
||||||
@click="btn.action(row)"
|
"
|
||||||
/>
|
@click="btn.action(row)"
|
||||||
</QCardSection>
|
/>
|
||||||
</QCard>
|
</QCardSection>
|
||||||
</component>
|
</QCard>
|
||||||
</template>
|
</component>
|
||||||
</QTable>
|
</template>
|
||||||
</template>
|
</QTable>
|
||||||
</CrudModel>
|
</template>
|
||||||
</div>
|
</CrudModel>
|
||||||
<QPageSticky v-if="create" :offset="[20, 20]" style="z-index: 2">
|
<QPageSticky v-if="create" :offset="[20, 20]" style="z-index: 2">
|
||||||
<QBtn @click="showForm = !showForm" color="primary" fab icon="add" />
|
<QBtn @click="showForm = !showForm" color="primary" fab icon="add" />
|
||||||
<QTooltip>
|
<QTooltip>
|
||||||
|
|
|
@ -8,7 +8,6 @@ import VnSubToolbar from '../ui/VnSubToolbar.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
import LeftMenu from 'components/LeftMenu.vue';
|
import LeftMenu from 'components/LeftMenu.vue';
|
||||||
import RightMenu from 'components/common/RightMenu.vue';
|
import RightMenu from 'components/common/RightMenu.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dataKey: { type: String, required: true },
|
dataKey: { type: String, required: true },
|
||||||
baseUrl: { type: String, default: undefined },
|
baseUrl: { type: String, default: undefined },
|
||||||
|
@ -74,7 +73,7 @@ if (props.baseUrl) {
|
||||||
<QPage>
|
<QPage>
|
||||||
<VnSubToolbar />
|
<VnSubToolbar />
|
||||||
<div :class="[useCardSize(), $attrs.class]">
|
<div :class="[useCardSize(), $attrs.class]">
|
||||||
<RouterView />
|
<RouterView :key="route.fullPath" />
|
||||||
</div>
|
</div>
|
||||||
</QPage>
|
</QPage>
|
||||||
</QPageContainer>
|
</QPageContainer>
|
||||||
|
|
|
@ -3,7 +3,7 @@ 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';
|
||||||
|
|
||||||
const model = defineModel({ type: String });
|
const model = defineModel({ type: [String, Date] });
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
isOutlined: {
|
isOutlined: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { watch, computed, ref, nextTick } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date } from 'quasar';
|
import { date } from 'quasar';
|
||||||
|
|
||||||
|
@ -14,13 +14,13 @@ const props = defineProps({
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const initialDate = ref(model.value);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
|
const requiredFieldRule = (val) => !!val || t('globals.fieldRequired');
|
||||||
|
|
||||||
const dateFormat = 'HH:mm';
|
const dateFormat = 'HH:mm';
|
||||||
const isPopupOpen = ref();
|
const isPopupOpen = ref();
|
||||||
const hover = ref();
|
const hover = ref();
|
||||||
const inputRef = ref();
|
|
||||||
|
|
||||||
const styleAttrs = computed(() => {
|
const styleAttrs = computed(() => {
|
||||||
return props.isOutlined
|
return props.isOutlined
|
||||||
|
@ -50,7 +50,8 @@ const formattedTime = computed({
|
||||||
}
|
}
|
||||||
if (!props.timeOnly) {
|
if (!props.timeOnly) {
|
||||||
const [hh, mm] = time.split(':');
|
const [hh, mm] = time.split(':');
|
||||||
const date = new Date(model.value ? model.value : null);
|
|
||||||
|
const date = new Date(model.value ? model.value : initialDate.value);
|
||||||
date.setHours(hh, mm, 0);
|
date.setHours(hh, mm, 0);
|
||||||
time = date?.toISOString();
|
time = date?.toISOString();
|
||||||
}
|
}
|
||||||
|
@ -62,37 +63,10 @@ const formattedTime = computed({
|
||||||
function dateToTime(newDate) {
|
function dateToTime(newDate) {
|
||||||
return date.formatDate(new Date(newDate), dateFormat);
|
return date.formatDate(new Date(newDate), dateFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
|
||||||
() => model.value,
|
|
||||||
(val) => (formattedTime.value = val),
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => formattedTime.value,
|
|
||||||
async (val) => {
|
|
||||||
let position = 3;
|
|
||||||
const input = inputRef.value?.getNativeElement();
|
|
||||||
if (!val || !input) return;
|
|
||||||
|
|
||||||
let [hh, mm] = val.split(':');
|
|
||||||
hh = parseInt(hh);
|
|
||||||
if (hh >= 10 || mm != '00') return;
|
|
||||||
|
|
||||||
await nextTick();
|
|
||||||
await nextTick();
|
|
||||||
if (!hh) position = 0;
|
|
||||||
input.setSelectionRange(position, position);
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div @mouseover="hover = true" @mouseleave="hover = false">
|
<div @mouseover="hover = true" @mouseleave="hover = false">
|
||||||
<QInput
|
<QInput
|
||||||
ref="inputRef"
|
|
||||||
class="vn-input-time"
|
class="vn-input-time"
|
||||||
mask="##:##"
|
mask="##:##"
|
||||||
placeholder="--:--"
|
placeholder="--:--"
|
||||||
|
@ -102,7 +76,7 @@ watch(
|
||||||
style="min-width: 100px"
|
style="min-width: 100px"
|
||||||
:rules="$attrs.required ? [requiredFieldRule] : null"
|
:rules="$attrs.required ? [requiredFieldRule] : null"
|
||||||
@click="isPopupOpen = false"
|
@click="isPopupOpen = false"
|
||||||
@focus="inputRef.getNativeElement().setSelectionRange(0, 0)"
|
type="time"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon
|
<QIcon
|
||||||
|
@ -149,6 +123,11 @@ watch(
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(input[type='time']::-webkit-calendar-picker-indicator) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Open time: Abrir tiempo
|
Open time: Abrir tiempo
|
||||||
|
|
|
@ -73,6 +73,14 @@ const $props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
params: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
noOne: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -85,6 +93,11 @@ const myOptionsOriginal = ref([]);
|
||||||
const vnSelectRef = ref();
|
const vnSelectRef = ref();
|
||||||
const dataRef = ref();
|
const dataRef = ref();
|
||||||
const lastVal = ref();
|
const lastVal = ref();
|
||||||
|
const noOneText = t('globals.noOne');
|
||||||
|
const noOneOpt = ref({
|
||||||
|
[optionValue.value]: false,
|
||||||
|
[optionLabel.value]: noOneText,
|
||||||
|
});
|
||||||
|
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get() {
|
get() {
|
||||||
|
@ -100,9 +113,11 @@ watch(options, (newValue) => {
|
||||||
setOptions(newValue);
|
setOptions(newValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(modelValue, (newValue) => {
|
watch(modelValue, async (newValue) => {
|
||||||
if (!myOptions.value.some((option) => option[optionValue.value] == newValue))
|
if (!myOptions.value.some((option) => option[optionValue.value] == newValue))
|
||||||
fetchFilter(newValue);
|
await fetchFilter(newValue);
|
||||||
|
|
||||||
|
if ($props.noOne) myOptions.value.unshift(noOneOpt.value);
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -153,13 +168,19 @@ async function fetchFilter(val) {
|
||||||
? optionValue.value
|
? optionValue.value
|
||||||
: optionFilter.value ?? optionLabel.value);
|
: optionFilter.value ?? optionLabel.value);
|
||||||
|
|
||||||
const defaultWhere = $props.useLike
|
let defaultWhere = {};
|
||||||
? { [key]: { like: `%${val}%` } }
|
if ($props.filterOptions.length) {
|
||||||
: { [key]: val };
|
defaultWhere = $props.filterOptions.reduce((obj, prop) => {
|
||||||
|
if (!obj.or) obj.or = [];
|
||||||
|
obj.or.push({ [prop]: getVal(val) });
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
} else defaultWhere = { [key]: getVal(val) };
|
||||||
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
const where = { ...(val ? defaultWhere : {}), ...$props.where };
|
||||||
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;
|
||||||
|
|
||||||
return dataRef.value.fetch(fetchOptions);
|
return dataRef.value.fetch(fetchOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +201,9 @@ async function filterHandler(val, update) {
|
||||||
} else newOptions = filter(val, myOptionsOriginal.value);
|
} else newOptions = filter(val, myOptionsOriginal.value);
|
||||||
update(
|
update(
|
||||||
() => {
|
() => {
|
||||||
|
if ($props.noOne && noOneText.toLowerCase().includes(val.toLowerCase()))
|
||||||
|
newOptions.unshift(noOneOpt.value);
|
||||||
|
|
||||||
myOptions.value = newOptions;
|
myOptions.value = newOptions;
|
||||||
},
|
},
|
||||||
(ref) => {
|
(ref) => {
|
||||||
|
@ -194,6 +218,8 @@ async function filterHandler(val, update) {
|
||||||
function nullishToTrue(value) {
|
function nullishToTrue(value) {
|
||||||
return value ?? true;
|
return value ?? true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getVal = (val) => ($props.useLike ? { like: `%${val}%` } : val);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -205,6 +231,7 @@ function nullishToTrue(value) {
|
||||||
:limit="limit"
|
:limit="limit"
|
||||||
:sort-by="sortBy"
|
:sort-by="sortBy"
|
||||||
:fields="fields"
|
:fields="fields"
|
||||||
|
:params="params"
|
||||||
/>
|
/>
|
||||||
<QSelect
|
<QSelect
|
||||||
v-model="value"
|
v-model="value"
|
||||||
|
|
|
@ -15,7 +15,7 @@ const props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
type: String,
|
type: [String, Boolean],
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
|
@ -35,7 +35,10 @@ defineEmits(['confirm', ...useDialogPluginComponent.emits]);
|
||||||
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
||||||
|
|
||||||
const title = props.title || t('Confirm');
|
const title = props.title || t('Confirm');
|
||||||
const message = props.message || t('Are you sure you want to continue?');
|
const message =
|
||||||
|
props.message ||
|
||||||
|
(props.message !== false ? t('Are you sure you want to continue?') : false);
|
||||||
|
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
|
|
||||||
async function confirm() {
|
async function confirm() {
|
||||||
|
@ -61,12 +64,12 @@ async function confirm() {
|
||||||
size="xl"
|
size="xl"
|
||||||
v-if="icon"
|
v-if="icon"
|
||||||
/>
|
/>
|
||||||
<span class="text-h6 text-grey">{{ title }}</span>
|
<span class="text-h6">{{ title }}</span>
|
||||||
<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="row items-center">
|
||||||
<span v-html="message"></span>
|
<span v-if="message !== false" v-html="message" />
|
||||||
<slot name="customHTML"></slot>
|
<slot name="customHTML"></slot>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<QCardActions align="right">
|
<QCardActions align="right">
|
||||||
|
|
|
@ -24,7 +24,7 @@ const $props = defineProps({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
unRemovableParams: {
|
unremovableParams: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
|
@ -150,7 +150,7 @@ async function clearFilters() {
|
||||||
arrayData.reset(['skip', 'filter.skip', 'page']);
|
arrayData.reset(['skip', 'filter.skip', 'page']);
|
||||||
// Filtrar los params no removibles
|
// Filtrar los params no removibles
|
||||||
const removableFilters = Object.keys(userParams.value).filter((param) =>
|
const removableFilters = Object.keys(userParams.value).filter((param) =>
|
||||||
$props.unRemovableParams.includes(param)
|
$props.unremovableParams.includes(param)
|
||||||
);
|
);
|
||||||
const newParams = {};
|
const newParams = {};
|
||||||
// Conservar solo los params que no son removibles
|
// Conservar solo los params que no son removibles
|
||||||
|
@ -182,10 +182,10 @@ const tagsList = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const tags = computed(() => {
|
const tags = computed(() => {
|
||||||
return tagsList.value.filter((tag) => !($props.customTags || []).includes(tag.key));
|
return tagsList.value.filter((tag) => !($props.customTags || []).includes(tag.label));
|
||||||
});
|
});
|
||||||
const customTags = computed(() =>
|
const customTags = computed(() =>
|
||||||
tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.key))
|
tagsList.value.filter((tag) => ($props.customTags || []).includes(tag.label))
|
||||||
);
|
);
|
||||||
|
|
||||||
async function remove(key) {
|
async function remove(key) {
|
||||||
|
@ -204,7 +204,7 @@ function formatValue(value) {
|
||||||
|
|
||||||
function sanitizer(params) {
|
function sanitizer(params) {
|
||||||
for (const [key, value] of Object.entries(params)) {
|
for (const [key, value] of Object.entries(params)) {
|
||||||
if (typeof value == 'object') {
|
if (value && typeof value === 'object') {
|
||||||
const param = Object.values(value)[0];
|
const param = Object.values(value)[0];
|
||||||
if (typeof param == 'string') params[key] = param.replaceAll('%', '');
|
if (typeof param == 'string') params[key] = param.replaceAll('%', '');
|
||||||
}
|
}
|
||||||
|
@ -270,7 +270,7 @@ function sanitizer(params) {
|
||||||
<VnFilterPanelChip
|
<VnFilterPanelChip
|
||||||
v-for="chip of tags"
|
v-for="chip of tags"
|
||||||
:key="chip.label"
|
:key="chip.label"
|
||||||
:removable="!unRemovableParams.includes(chip.label)"
|
:removable="!unremovableParams?.includes(chip.label)"
|
||||||
@remove="remove(chip.label)"
|
@remove="remove(chip.label)"
|
||||||
>
|
>
|
||||||
<slot name="tags" :tag="chip" :format-fn="formatValue">
|
<slot name="tags" :tag="chip" :format-fn="formatValue">
|
||||||
|
|
|
@ -10,6 +10,10 @@ const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
autoLoad: {
|
autoLoad: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -215,7 +219,7 @@ defineExpose({ fetch, addFilter, paginate });
|
||||||
v-if="store.data"
|
v-if="store.data"
|
||||||
@load="onLoad"
|
@load="onLoad"
|
||||||
:offset="offset"
|
:offset="offset"
|
||||||
class="full-width"
|
:class="['full-width', props.class]"
|
||||||
:disable="disableInfiniteScroll || !store.hasMoreData"
|
:disable="disableInfiniteScroll || !store.hasMoreData"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
>
|
>
|
||||||
|
|
|
@ -124,7 +124,7 @@ async function search() {
|
||||||
<QForm @submit="search" id="searchbarForm">
|
<QForm @submit="search" id="searchbarForm">
|
||||||
<VnInput
|
<VnInput
|
||||||
id="searchbar"
|
id="searchbar"
|
||||||
v-model="searchText"
|
v-model.trim="searchText"
|
||||||
:placeholder="t(props.label)"
|
:placeholder="t(props.label)"
|
||||||
dense
|
dense
|
||||||
standout
|
standout
|
||||||
|
|
|
@ -7,5 +7,5 @@ export function getDateQBadgeColor(date) {
|
||||||
let comparation = today - timeTicket;
|
let comparation = today - timeTicket;
|
||||||
|
|
||||||
if (comparation == 0) return 'warning';
|
if (comparation == 0) return 'warning';
|
||||||
if (comparation < 0) return 'negative';
|
if (comparation < 0) return 'success';
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,10 +103,6 @@ select:-webkit-autofill {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-width {
|
|
||||||
width: 770px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vn-card-list {
|
.vn-card-list {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 60em;
|
max-width: 60em;
|
||||||
|
@ -257,7 +253,6 @@ input::-webkit-inner-spin-button {
|
||||||
}
|
}
|
||||||
td {
|
td {
|
||||||
font-size: 11pt;
|
font-size: 11pt;
|
||||||
border-top: 1px solid var(--vn-page-color);
|
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,3 +263,10 @@ input::-webkit-inner-spin-button {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.edit-photo-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
bottom: 12px;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
|
@ -20,21 +20,21 @@ export function isValidDate(date) {
|
||||||
* Converts a given date to a specific format.
|
* Converts a given date to a specific format.
|
||||||
*
|
*
|
||||||
* @param {number|string|Date} date - The date to be formatted.
|
* @param {number|string|Date} date - The date to be formatted.
|
||||||
|
* @param {Object} opts - Optional parameters to customize the output format.
|
||||||
* @returns {string} The formatted date as a string in 'dd/mm/yyyy' format. If the provided date is not valid, an empty string is returned.
|
* @returns {string} The formatted date as a string in 'dd/mm/yyyy' format. If the provided date is not valid, an empty string is returned.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
* // returns "02/12/2022"
|
* // returns "02/12/2022"
|
||||||
* toDateFormat(new Date(2022, 11, 2));
|
* toDateFormat(new Date(2022, 11, 2));
|
||||||
*/
|
*/
|
||||||
export function toDateFormat(date, locale = 'es-ES') {
|
export function toDateFormat(date, locale = 'es-ES', opts = {}) {
|
||||||
if (!isValidDate(date)) {
|
if (!isValidDate(date)) return '';
|
||||||
return '';
|
|
||||||
}
|
const format = Object.assign(
|
||||||
return new Date(date).toLocaleDateString(locale, {
|
{ year: 'numeric', month: '2-digit', day: '2-digit' },
|
||||||
year: 'numeric',
|
opts
|
||||||
month: '2-digit',
|
);
|
||||||
day: '2-digit',
|
return new Date(date).toLocaleDateString(locale, format);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export default function dateRange(value) {
|
export default function dateRange(value) {
|
||||||
const minHour = new Date(value);
|
const minHour = new Date(value);
|
||||||
minHour.setHours(0, 0, 0, 0);
|
minHour.setHours(0, 0, 0, 0);
|
||||||
const maxHour = new Date();
|
const maxHour = new Date(value);
|
||||||
maxHour.setHours(23, 59, 59, 59);
|
maxHour.setHours(23, 59, 59, 59);
|
||||||
|
|
||||||
return [minHour, maxHour];
|
return [minHour, maxHour];
|
||||||
|
|
|
@ -95,6 +95,7 @@ globals:
|
||||||
from: From
|
from: From
|
||||||
to: To
|
to: To
|
||||||
notes: Notes
|
notes: Notes
|
||||||
|
refresh: Refresh
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Login
|
logIn: Login
|
||||||
summary: Summary
|
summary: Summary
|
||||||
|
@ -256,6 +257,9 @@ globals:
|
||||||
twoFactor: Two factor
|
twoFactor: Two factor
|
||||||
recoverPassword: Recover password
|
recoverPassword: Recover password
|
||||||
resetPassword: Reset password
|
resetPassword: Reset password
|
||||||
|
ticketsMonitor: Tickets monitor
|
||||||
|
clientsActionsMonitor: Clients and actions
|
||||||
|
serial: Serial
|
||||||
created: Created
|
created: Created
|
||||||
worker: Worker
|
worker: Worker
|
||||||
now: Now
|
now: Now
|
||||||
|
@ -269,6 +273,7 @@ globals:
|
||||||
subtitle: Are you sure exit without saving?
|
subtitle: Are you sure exit without saving?
|
||||||
createInvoiceIn: Create invoice in
|
createInvoiceIn: Create invoice in
|
||||||
myAccount: My account
|
myAccount: My account
|
||||||
|
noOne: No one
|
||||||
errors:
|
errors:
|
||||||
statusUnauthorized: Access denied
|
statusUnauthorized: Access denied
|
||||||
statusInternalServerError: An internal server error has ocurred
|
statusInternalServerError: An internal server error has ocurred
|
||||||
|
@ -455,6 +460,7 @@ entry:
|
||||||
travelFk: Travel
|
travelFk: Travel
|
||||||
isExcludedFromAvailable: Inventory
|
isExcludedFromAvailable: Inventory
|
||||||
isRaid: Raid
|
isRaid: Raid
|
||||||
|
invoiceAmount: Import
|
||||||
summary:
|
summary:
|
||||||
commission: Commission
|
commission: Commission
|
||||||
currency: Currency
|
currency: Currency
|
||||||
|
@ -691,6 +697,7 @@ invoiceOut:
|
||||||
chooseValidClient: Choose a valid client
|
chooseValidClient: Choose a valid client
|
||||||
chooseValidCompany: Choose a valid company
|
chooseValidCompany: Choose a valid company
|
||||||
chooseValidPrinter: Choose a valid printer
|
chooseValidPrinter: Choose a valid printer
|
||||||
|
chooseValidSerialType: Choose a serial type
|
||||||
fillDates: Invoice date and the max date should be filled
|
fillDates: Invoice date and the max date should be filled
|
||||||
invoiceDateLessThanMaxDate: Invoice date can not be less than max date
|
invoiceDateLessThanMaxDate: Invoice date can not be less than max date
|
||||||
invoiceWithFutureDate: Exists an invoice with a future date
|
invoiceWithFutureDate: Exists an invoice with a future date
|
||||||
|
@ -1122,9 +1129,12 @@ travel:
|
||||||
agency: Agency
|
agency: Agency
|
||||||
shipped: Shipped
|
shipped: Shipped
|
||||||
landed: Landed
|
landed: Landed
|
||||||
|
shipHour: Shipment Hour
|
||||||
|
landHour: Landing Hour
|
||||||
warehouseIn: Warehouse in
|
warehouseIn: Warehouse in
|
||||||
warehouseOut: Warehouse out
|
warehouseOut: Warehouse out
|
||||||
totalEntries: Total entries
|
totalEntries: Total entries
|
||||||
|
totalEntriesTooltip: Total entries
|
||||||
summary:
|
summary:
|
||||||
confirmed: Confirmed
|
confirmed: Confirmed
|
||||||
entryId: Entry Id
|
entryId: Entry Id
|
||||||
|
|
|
@ -97,6 +97,7 @@ globals:
|
||||||
from: Desde
|
from: Desde
|
||||||
to: Hasta
|
to: Hasta
|
||||||
notes: Notas
|
notes: Notas
|
||||||
|
refresh: Actualizar
|
||||||
pageTitles:
|
pageTitles:
|
||||||
logIn: Inicio de sesión
|
logIn: Inicio de sesión
|
||||||
summary: Resumen
|
summary: Resumen
|
||||||
|
@ -260,6 +261,9 @@ globals:
|
||||||
twoFactor: Doble factor
|
twoFactor: Doble factor
|
||||||
recoverPassword: Recuperar contraseña
|
recoverPassword: Recuperar contraseña
|
||||||
resetPassword: Restablecer contraseña
|
resetPassword: Restablecer contraseña
|
||||||
|
ticketsMonitor: Monitor de tickets
|
||||||
|
clientsActionsMonitor: Clientes y acciones
|
||||||
|
serial: Facturas por serie
|
||||||
created: Fecha creación
|
created: Fecha creación
|
||||||
worker: Trabajador
|
worker: Trabajador
|
||||||
now: Ahora
|
now: Ahora
|
||||||
|
@ -273,6 +277,7 @@ globals:
|
||||||
subtitle: ¿Seguro que quiere salir sin guardar?
|
subtitle: ¿Seguro que quiere salir sin guardar?
|
||||||
createInvoiceIn: Crear factura recibida
|
createInvoiceIn: Crear factura recibida
|
||||||
myAccount: Mi cuenta
|
myAccount: Mi cuenta
|
||||||
|
noOne: Nadie
|
||||||
errors:
|
errors:
|
||||||
statusUnauthorized: Acceso denegado
|
statusUnauthorized: Acceso denegado
|
||||||
statusInternalServerError: Ha ocurrido un error interno del servidor
|
statusInternalServerError: Ha ocurrido un error interno del servidor
|
||||||
|
@ -456,6 +461,7 @@ entry:
|
||||||
travelFk: Envio
|
travelFk: Envio
|
||||||
isExcludedFromAvailable: Inventario
|
isExcludedFromAvailable: Inventario
|
||||||
isRaid: Redada
|
isRaid: Redada
|
||||||
|
invoiceAmount: Importe
|
||||||
summary:
|
summary:
|
||||||
commission: Comisión
|
commission: Comisión
|
||||||
currency: Moneda
|
currency: Moneda
|
||||||
|
@ -699,6 +705,7 @@ invoiceOut:
|
||||||
chooseValidClient: Selecciona un cliente válido
|
chooseValidClient: Selecciona un cliente válido
|
||||||
chooseValidCompany: Selecciona una empresa válida
|
chooseValidCompany: Selecciona una empresa válida
|
||||||
chooseValidPrinter: Selecciona una impresora válida
|
chooseValidPrinter: Selecciona una impresora válida
|
||||||
|
chooseValidSerialType: Selecciona una tipo de serie válida
|
||||||
fillDates: La fecha de la factura y la fecha máxima deben estar completas
|
fillDates: La fecha de la factura y la fecha máxima deben estar completas
|
||||||
invoiceDateLessThanMaxDate: La fecha de la factura no puede ser menor que la fecha máxima
|
invoiceDateLessThanMaxDate: La fecha de la factura no puede ser menor que la fecha máxima
|
||||||
invoiceWithFutureDate: Existe una factura con una fecha futura
|
invoiceWithFutureDate: Existe una factura con una fecha futura
|
||||||
|
@ -1101,11 +1108,14 @@ travel:
|
||||||
id: Id
|
id: Id
|
||||||
ref: Referencia
|
ref: Referencia
|
||||||
agency: Agencia
|
agency: Agencia
|
||||||
shipped: Enviado
|
shipped: F.envío
|
||||||
landed: Llegada
|
shipHour: Hora de envío
|
||||||
warehouseIn: Almacén de salida
|
landHour: Hora de llegada
|
||||||
warehouseOut: Almacén de entrada
|
landed: F.entrega
|
||||||
totalEntries: Total de entradas
|
warehouseIn: Alm.salida
|
||||||
|
warehouseOut: Alm.entrada
|
||||||
|
totalEntries: ∑
|
||||||
|
totalEntriesTooltip: Entradas totales
|
||||||
summary:
|
summary:
|
||||||
confirmed: Confirmado
|
confirmed: Confirmado
|
||||||
entryId: Id entrada
|
entryId: Id entrada
|
||||||
|
@ -1270,6 +1280,7 @@ components:
|
||||||
clone: Clonar
|
clone: Clonar
|
||||||
openCard: Ficha
|
openCard: Ficha
|
||||||
openSummary: Detalles
|
openSummary: Detalles
|
||||||
|
viewSummary: Vista previa
|
||||||
cardDescriptor:
|
cardDescriptor:
|
||||||
mainList: Listado principal
|
mainList: Listado principal
|
||||||
summary: Resumen
|
summary: Resumen
|
||||||
|
|
|
@ -141,6 +141,7 @@ const deleteAcl = async ({ id }) => {
|
||||||
formInitialData: {},
|
formInitialData: {},
|
||||||
}"
|
}"
|
||||||
order="id DESC"
|
order="id DESC"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
:right-search="true"
|
:right-search="true"
|
||||||
|
|
|
@ -21,24 +21,21 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: t('id'),
|
label: t('Id'),
|
||||||
isId: true,
|
isId: true,
|
||||||
field: 'id',
|
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'alias',
|
name: 'alias',
|
||||||
label: t('alias'),
|
label: t('Alias'),
|
||||||
field: 'alias',
|
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'description',
|
name: 'description',
|
||||||
label: t('description'),
|
label: t('Description'),
|
||||||
field: 'description',
|
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
|
@ -69,9 +66,17 @@ const columns = computed(() => [
|
||||||
}"
|
}"
|
||||||
order="id DESC"
|
order="id DESC"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
redirect="account/alias"
|
redirect="account/alias"
|
||||||
:is-editable="true"
|
:is-editable="true"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Alias: Alias
|
||||||
|
Description: Descripción
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -14,15 +14,23 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: t('id'),
|
label: t('Id'),
|
||||||
isId: true,
|
isId: true,
|
||||||
field: 'id',
|
field: 'id',
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
name: 'search',
|
||||||
|
attrs: {
|
||||||
|
url: 'VnUsers/preview',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'username',
|
name: 'username',
|
||||||
label: t('nickname'),
|
label: t('Nickname'),
|
||||||
isTitle: true,
|
isTitle: true,
|
||||||
component: 'input',
|
component: 'input',
|
||||||
columnField: {
|
columnField: {
|
||||||
|
@ -37,7 +45,7 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: t('name'),
|
label: t('Name'),
|
||||||
component: 'input',
|
component: 'input',
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
|
@ -65,6 +73,7 @@ const columns = computed(() => [
|
||||||
title: t('View Summary'),
|
title: t('View Summary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, AccountSummary),
|
action: (row) => viewSummary(row.id, AccountSummary),
|
||||||
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -108,3 +117,10 @@ const exprBuilder = (param, value) => {
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Nickname: Nickname
|
||||||
|
Name: Nombre
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -15,7 +15,6 @@ const { t } = useI18n();
|
||||||
url: 'VnUsers/preview',
|
url: 'VnUsers/preview',
|
||||||
label: t('account.search'),
|
label: t('account.search'),
|
||||||
info: t('account.searchInfo'),
|
info: t('account.searchInfo'),
|
||||||
searchUrl: 'table',
|
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -72,7 +72,7 @@ const hasAccount = ref(false);
|
||||||
</VnImg>
|
</VnImg>
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="t('account.card.nickname')" :value="entity.nickname" />
|
<VnLv :label="t('account.card.nickname')" :value="entity.name" />
|
||||||
<VnLv :label="t('account.card.role')" :value="entity.role.name" />
|
<VnLv :label="t('account.card.role')" :value="entity.role.name" />
|
||||||
</template>
|
</template>
|
||||||
<template #actions="{ entity }">
|
<template #actions="{ entity }">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
|
@ -12,17 +12,14 @@ const route = useRoute();
|
||||||
|
|
||||||
const rolesOptions = ref([]);
|
const rolesOptions = ref([]);
|
||||||
const formModelRef = ref();
|
const formModelRef = ref();
|
||||||
|
watch(
|
||||||
|
() => route.params.id,
|
||||||
|
() => formModelRef.value.reset()
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData url="VnRoles" auto-load @on-fetch="(data) => (rolesOptions = data)" />
|
<FetchData url="VnRoles" auto-load @on-fetch="(data) => (rolesOptions = data)" />
|
||||||
<FormModel
|
<FormModel ref="formModelRef" model="AccountPrivileges" url="VnUsers" auto-load>
|
||||||
ref="formModelRef"
|
|
||||||
model="AccountPrivileges"
|
|
||||||
:url="`VnUsers/${route.params.id}/privileges`"
|
|
||||||
:url-create="`VnUsers/${route.params.id}/privileges`"
|
|
||||||
auto-load
|
|
||||||
@on-data-saved="formModelRef.fetch()"
|
|
||||||
>
|
|
||||||
<template #form="{ data }">
|
<template #form="{ data }">
|
||||||
<div class="q-gutter-y-sm">
|
<div class="q-gutter-y-sm">
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
|
|
|
@ -48,7 +48,7 @@ const filter = {
|
||||||
<QIcon name="open_in_new" />
|
<QIcon name="open_in_new" />
|
||||||
</router-link>
|
</router-link>
|
||||||
</QCardSection>
|
</QCardSection>
|
||||||
<VnLv :label="t('account.card.nickname')" :value="account.nickname" />
|
<VnLv :label="t('account.card.nickname')" :value="account.name" />
|
||||||
<VnLv :label="t('account.card.role')" :value="account.role.name" />
|
<VnLv :label="t('account.card.role')" :value="account.role.name" />
|
||||||
</QCard>
|
</QCard>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -21,24 +21,30 @@ const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: t('id'),
|
label: t('Id'),
|
||||||
isId: true,
|
isId: true,
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
inWhere: true,
|
inWhere: true,
|
||||||
|
component: 'select',
|
||||||
|
name: 'search',
|
||||||
|
attrs: {
|
||||||
|
url: 'VnRoles',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'name',
|
name: 'name',
|
||||||
label: t('name'),
|
label: t('Name'),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'description',
|
name: 'description',
|
||||||
label: t('description'),
|
label: t('Description'),
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
|
@ -51,6 +57,7 @@ const columns = computed(() => [
|
||||||
title: t('View Summary'),
|
title: t('View Summary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, RoleSummary),
|
action: (row) => viewSummary(row.id, RoleSummary),
|
||||||
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -93,8 +100,16 @@ const exprBuilder = (param, value) => {
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
order="id ASC"
|
order="id ASC"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
redirect="account/role"
|
redirect="account/role"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Id: Id
|
||||||
|
Description: Descripción
|
||||||
|
Name: Nombre
|
||||||
|
</i18n>
|
||||||
|
|
|
@ -36,8 +36,6 @@ const $props = defineProps({
|
||||||
|
|
||||||
const entityId = computed(() => $props.id || route.params.id);
|
const entityId = computed(() => $props.id || route.params.id);
|
||||||
const ClaimStates = ref([]);
|
const ClaimStates = ref([]);
|
||||||
const claimUrl = ref();
|
|
||||||
const salixUrl = ref();
|
|
||||||
const claimDmsRef = ref();
|
const claimDmsRef = ref();
|
||||||
const claimDms = ref([]);
|
const claimDms = ref([]);
|
||||||
const multimediaDialog = ref();
|
const multimediaDialog = ref();
|
||||||
|
@ -152,11 +150,6 @@ const developmentColumns = ref([
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
salixUrl.value = await getUrl('');
|
|
||||||
claimUrl.value = salixUrl.value + `claim/${entityId.value}/`;
|
|
||||||
});
|
|
||||||
|
|
||||||
async function getClaimDms() {
|
async function getClaimDms() {
|
||||||
claimDmsFilter.value.where = { claimFk: entityId.value };
|
claimDmsFilter.value.where = { claimFk: entityId.value };
|
||||||
await claimDmsRef.value.fetch();
|
await claimDmsRef.value.fetch();
|
||||||
|
@ -177,10 +170,15 @@ function openDialog(dmsId) {
|
||||||
multimediaSlide.value = dmsId;
|
multimediaSlide.value = dmsId;
|
||||||
multimediaDialog.value = true;
|
multimediaDialog.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeState(value) {
|
async function changeState(value) {
|
||||||
await axios.patch(`Claims/updateClaim/${entityId.value}`, { claimStateFk: value });
|
await axios.patch(`Claims/updateClaim/${entityId.value}`, { claimStateFk: value });
|
||||||
router.go(route.fullPath);
|
router.go(route.fullPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function claimUrl(section) {
|
||||||
|
return '#/claim/' + entityId.value + '/' + section;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -234,7 +232,7 @@ async function changeState(value) {
|
||||||
<template #body="{ entity: { claim, salesClaimed, developments } }">
|
<template #body="{ entity: { claim, salesClaimed, developments } }">
|
||||||
<QCard class="vn-one" v-if="$route.name != 'ClaimSummary'">
|
<QCard class="vn-one" v-if="$route.name != 'ClaimSummary'">
|
||||||
<VnTitle
|
<VnTitle
|
||||||
:url="`#/claim/${entityId}/basic-data`"
|
:url="claimUrl('basic-data')"
|
||||||
:text="t('globals.pageTitles.basicData')"
|
:text="t('globals.pageTitles.basicData')"
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('claim.created')" :value="toDate(claim.created)" />
|
<VnLv :label="t('claim.created')" :value="toDate(claim.created)" />
|
||||||
|
@ -275,7 +273,7 @@ async function changeState(value) {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-two">
|
<QCard class="vn-two">
|
||||||
<VnTitle :url="`#/claim/${entityId}/notes`" :text="t('claim.notes')" />
|
<VnTitle :url="claimUrl('notes')" :text="t('claim.notes')" />
|
||||||
<ClaimNotes
|
<ClaimNotes
|
||||||
:id="entityId"
|
:id="entityId"
|
||||||
:add-note="false"
|
:add-note="false"
|
||||||
|
@ -284,7 +282,7 @@ async function changeState(value) {
|
||||||
/>
|
/>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-two" v-if="claimDms?.length">
|
<QCard class="vn-two" v-if="claimDms?.length">
|
||||||
<VnTitle :url="`#/claim/${entityId}/photos`" :text="t('claim.photos')" />
|
<VnTitle :url="claimUrl('photos')" :text="t('claim.photos')" />
|
||||||
<div class="container max-container-height" style="overflow: auto">
|
<div class="container max-container-height" style="overflow: auto">
|
||||||
<div
|
<div
|
||||||
class="multimedia-container"
|
class="multimedia-container"
|
||||||
|
@ -326,7 +324,7 @@ async function changeState(value) {
|
||||||
</div>
|
</div>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-max" v-if="salesClaimed.length > 0">
|
<QCard class="vn-max" v-if="salesClaimed.length > 0">
|
||||||
<VnTitle :url="`#/claim/${entityId}/lines`" :text="t('claim.details')" />
|
<VnTitle :url="claimUrl('lines')" :text="t('claim.details')" />
|
||||||
<QTable
|
<QTable
|
||||||
:columns="detailsColumns"
|
:columns="detailsColumns"
|
||||||
:rows="salesClaimed"
|
:rows="salesClaimed"
|
||||||
|
@ -365,7 +363,7 @@ async function changeState(value) {
|
||||||
</QTable>
|
</QTable>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-max" v-if="developments.length > 0">
|
<QCard class="vn-max" v-if="developments.length > 0">
|
||||||
<VnTitle :url="claimUrl + 'development'" :text="t('claim.development')" />
|
<VnTitle :url="claimUrl('development')" :text="t('claim.development')" />
|
||||||
<QTable
|
<QTable
|
||||||
:columns="developmentColumns"
|
:columns="developmentColumns"
|
||||||
:rows="developments"
|
:rows="developments"
|
||||||
|
@ -390,7 +388,7 @@ async function changeState(value) {
|
||||||
</QTable>
|
</QTable>
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-max">
|
<QCard class="vn-max">
|
||||||
<VnTitle :url="claimUrl + 'action'" :text="t('claim.actions')" />
|
<VnTitle :url="claimUrl('action')" :text="t('claim.actions')" />
|
||||||
<div id="slider-container" class="q-px-xl q-py-md">
|
<div id="slider-container" class="q-px-xl q-py-md">
|
||||||
<QSlider
|
<QSlider
|
||||||
v-model="claim.responsibility"
|
v-model="claim.responsibility"
|
||||||
|
|
|
@ -79,7 +79,7 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('claim.state'),
|
label: t('claim.state'),
|
||||||
format: ({ stateCode }) =>
|
format: ({ stateCode }) =>
|
||||||
claimFilterRef.value?.states.find(({code}) => code === stateCode)
|
claimFilterRef.value?.states.find(({ code }) => code === stateCode)
|
||||||
?.description,
|
?.description,
|
||||||
name: 'stateCode',
|
name: 'stateCode',
|
||||||
chip: {
|
chip: {
|
||||||
|
@ -100,7 +100,7 @@ const columns = computed(() => [
|
||||||
name: 'tableActions',
|
name: 'tableActions',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: t('Client ticket list'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, ClaimSummary),
|
action: (row) => viewSummary(row.id, ClaimSummary),
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,7 +42,7 @@ claim:
|
||||||
pickup: Recoger
|
pickup: Recoger
|
||||||
null: No
|
null: No
|
||||||
agency: Agencia
|
agency: Agencia
|
||||||
delivery: Entrega
|
delivery: Reparto
|
||||||
fileDescription: 'ID de reclamación {claimId} del cliente {clientName} con ID {clientId}'
|
fileDescription: 'ID de reclamación {claimId} del cliente {clientName} con ID {clientId}'
|
||||||
noData: 'No hay imágenes/videos, haz clic aquí o arrastra y suelta el archivo'
|
noData: 'No hay imágenes/videos, haz clic aquí o arrastra y suelta el archivo'
|
||||||
dragDrop: Arrastra y suelta aquí
|
dragDrop: Arrastra y suelta aquí
|
||||||
|
|
|
@ -357,7 +357,7 @@ const columns = computed(() => [
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Client ticket list'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, CustomerSummary),
|
action: (row) => viewSummary(row.id, CustomerSummary),
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,11 +7,19 @@ import { useStateStore } from 'stores/useStateStore';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
import { toDate } from 'src/filters';
|
import { toDate } from 'src/filters';
|
||||||
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
|
import EntrySummary from './Card/EntrySummary.vue';
|
||||||
|
import VnUserLink from 'components/ui/VnUserLink.vue';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import CustomerDescriptorProxy from '../Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
|
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
|
||||||
|
import TravelDescriptorProxy from 'src/pages/Travel/Card/TravelDescriptorProxy.vue';
|
||||||
|
|
||||||
const stateStore = useStateStore();
|
const stateStore = useStateStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
|
|
||||||
|
const { viewSummary } = useSummaryDialog();
|
||||||
const entryFilter = {
|
const entryFilter = {
|
||||||
include: [
|
include: [
|
||||||
{
|
{
|
||||||
|
@ -142,6 +150,12 @@ const columns = computed(() => [
|
||||||
create: true,
|
create: true,
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
|
format: (row, dashIfEmpty) => dashIfEmpty(row.travelRef),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
label: t('entry.list.tableVisibleColumns.invoiceAmount'),
|
||||||
|
name: 'invoiceAmount',
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
label: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
label: t('entry.list.tableVisibleColumns.isExcludedFromAvailable'),
|
||||||
|
@ -168,6 +182,18 @@ const columns = computed(() => [
|
||||||
inWhere: true,
|
inWhere: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'right',
|
||||||
|
name: 'tableActions',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
title: t('components.smartCard.viewSummary'),
|
||||||
|
icon: 'preview',
|
||||||
|
action: (row) => viewSummary(row.id, EntrySummary),
|
||||||
|
isPrimary: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
|
@ -201,7 +227,20 @@ onMounted(async () => {
|
||||||
redirect="entry"
|
redirect="entry"
|
||||||
auto-load
|
auto-load
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
/>
|
>
|
||||||
|
<template #column-supplierFk="{ row }">
|
||||||
|
<span class="link" @click.stop>
|
||||||
|
{{ row.supplierName }}
|
||||||
|
<SupplierDescriptorProxy :id="row.supplierFk" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template #column-travelFk="{ row }">
|
||||||
|
<span class="link" @click.stop>
|
||||||
|
{{ row.travelRef }}
|
||||||
|
<TravelDescriptorProxy :id="row.travelFk" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
|
|
|
@ -18,6 +18,7 @@ const { notify } = useNotify();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const arrayData = useArrayData();
|
const arrayData = useArrayData();
|
||||||
const invoiceIn = computed(() => arrayData.store.data);
|
const invoiceIn = computed(() => arrayData.store.data);
|
||||||
|
const currency = computed(() => invoiceIn.value?.currency?.code);
|
||||||
|
|
||||||
const rowsSelected = ref([]);
|
const rowsSelected = ref([]);
|
||||||
const banks = ref([]);
|
const banks = ref([]);
|
||||||
|
@ -139,9 +140,9 @@ const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount,
|
||||||
<QTd>
|
<QTd>
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': !isNotEuro(invoiceIn.currency.code),
|
'no-pointer-events': !isNotEuro(currency),
|
||||||
}"
|
}"
|
||||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
:disable="!isNotEuro(currency)"
|
||||||
v-model="row.foreignValue"
|
v-model="row.foreignValue"
|
||||||
clearable
|
clearable
|
||||||
clear-icon="close"
|
clear-icon="close"
|
||||||
|
@ -154,9 +155,7 @@ const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount,
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd />
|
<QTd />
|
||||||
<QTd>
|
<QTd>
|
||||||
{{
|
{{ toCurrency(getTotalAmount(rows), currency) }}
|
||||||
toCurrency(getTotalAmount(rows), invoiceIn.currency.code)
|
|
||||||
}}
|
|
||||||
</QTd>
|
</QTd>
|
||||||
<QTd />
|
<QTd />
|
||||||
</QTr>
|
</QTr>
|
||||||
|
@ -208,11 +207,9 @@ const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount,
|
||||||
:label="t('Foreign value')"
|
:label="t('Foreign value')"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': !isNotEuro(
|
'no-pointer-events': !isNotEuro(currency),
|
||||||
invoiceIn.currency.code
|
|
||||||
),
|
|
||||||
}"
|
}"
|
||||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
:disable="!isNotEuro(currency)"
|
||||||
v-model="props.row.foreignValue"
|
v-model="props.row.foreignValue"
|
||||||
clearable
|
clearable
|
||||||
clear-icon="close"
|
clear-icon="close"
|
||||||
|
|
|
@ -242,11 +242,12 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
</template>
|
</template>
|
||||||
<template #body-cell-taxablebase="{ row }">
|
<template #body-cell-taxablebase="{ row }">
|
||||||
<QTd>
|
<QTd>
|
||||||
|
{{ currency }}
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': isNotEuro(invoiceIn.currency.code),
|
'no-pointer-events': isNotEuro(currency),
|
||||||
}"
|
}"
|
||||||
:disable="isNotEuro(invoiceIn.currency.code)"
|
:disable="isNotEuro(currency)"
|
||||||
label=""
|
label=""
|
||||||
clear-icon="close"
|
clear-icon="close"
|
||||||
v-model="row.taxableBase"
|
v-model="row.taxableBase"
|
||||||
|
@ -312,9 +313,9 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
<QTd>
|
<QTd>
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': !isNotEuro(invoiceIn.currency.code),
|
'no-pointer-events': !isNotEuro(currency),
|
||||||
}"
|
}"
|
||||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
:disable="!isNotEuro(currency)"
|
||||||
v-model="row.foreignValue"
|
v-model="row.foreignValue"
|
||||||
/>
|
/>
|
||||||
</QTd>
|
</QTd>
|
||||||
|
@ -361,12 +362,10 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
<VnInputNumber
|
<VnInputNumber
|
||||||
:label="t('Taxable base')"
|
:label="t('Taxable base')"
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': isNotEuro(
|
'no-pointer-events': isNotEuro(currency),
|
||||||
invoiceIn.currency.code
|
|
||||||
),
|
|
||||||
}"
|
}"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
:disable="isNotEuro(invoiceIn.currency.code)"
|
:disable="isNotEuro(currency)"
|
||||||
clear-icon="close"
|
clear-icon="close"
|
||||||
v-model="props.row.taxableBase"
|
v-model="props.row.taxableBase"
|
||||||
clearable
|
clearable
|
||||||
|
@ -427,11 +426,9 @@ const formatOpt = (row, { model, options }, prop) => {
|
||||||
:label="t('Foreign value')"
|
:label="t('Foreign value')"
|
||||||
class="full-width"
|
class="full-width"
|
||||||
:class="{
|
:class="{
|
||||||
'no-pointer-events': !isNotEuro(
|
'no-pointer-events': !isNotEuro(currency),
|
||||||
invoiceIn.currency.code
|
|
||||||
),
|
|
||||||
}"
|
}"
|
||||||
:disable="!isNotEuro(invoiceIn.currency.code)"
|
:disable="!isNotEuro(currency)"
|
||||||
v-model="props.row.foreignValue"
|
v-model="props.row.foreignValue"
|
||||||
/>
|
/>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onBeforeMount } from 'vue';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import axios from 'axios';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import InvoiceInSerialFilter from './InvoiceInSerialFilter.vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const cols = computed(() => [
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'serial',
|
||||||
|
label: t('Serial'),
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'pending',
|
||||||
|
label: t('Pending'),
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'total',
|
||||||
|
label: 'Total',
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const daysAgo = ref();
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
const tableParam = useRoute().query.table;
|
||||||
|
|
||||||
|
if (tableParam) daysAgo.value = JSON.parse(tableParam).daysAgo;
|
||||||
|
else
|
||||||
|
daysAgo.value = (
|
||||||
|
await axios.get('InvoiceInConfigs/findOne', {
|
||||||
|
params: { filter: { fields: ['daysAgo'] } },
|
||||||
|
})
|
||||||
|
).data?.daysAgo;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<InvoiceInSerialFilter data-key="InvoiceInSerial" />
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
|
<VnTable
|
||||||
|
v-if="!isNaN(daysAgo)"
|
||||||
|
data-key="InvoiceInSerial"
|
||||||
|
url="InvoiceIns/getSerial"
|
||||||
|
:columns="cols"
|
||||||
|
:right-search="false"
|
||||||
|
:user-params="{ daysAgo }"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<i18n>
|
||||||
|
es:
|
||||||
|
Serial: Serie
|
||||||
|
Pending: Pendiente
|
||||||
|
</i18n>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<script setup>
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
|
defineProps({ dataKey: { type: String, required: true } });
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
</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>
|
||||||
|
<VnInputNumber
|
||||||
|
v-model="params.daysAgo"
|
||||||
|
:label="t('params.daysAgo')"
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
v-model="params.serial"
|
||||||
|
:label="t('params.serial')"
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnFilterPanel>
|
||||||
|
</template>
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
params:
|
||||||
|
daysAgo: Last days
|
||||||
|
serial: serial
|
||||||
|
es:
|
||||||
|
params:
|
||||||
|
daysAgo: Últimos días
|
||||||
|
serial: serie
|
||||||
|
</i18n>
|
|
@ -222,7 +222,7 @@ const showTransferInvoiceForm = async () => {
|
||||||
<QItemSection>{{ t('Generate PDF invoice') }}</QItemSection>
|
<QItemSection>{{ t('Generate PDF invoice') }}</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem v-ripple clickable>
|
<QItem v-ripple clickable>
|
||||||
<QItemSection>{{ t('Refund...') }}</QItemSection>
|
<QItemSection>{{ t('Refund') }}</QItemSection>
|
||||||
<QItemSection side>
|
<QItemSection side>
|
||||||
<QIcon name="keyboard_arrow_right" />
|
<QIcon name="keyboard_arrow_right" />
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
|
@ -250,7 +250,7 @@ es:
|
||||||
Delete invoice: Eliminar factura
|
Delete invoice: Eliminar factura
|
||||||
Book invoice: Asentar factura
|
Book invoice: Asentar factura
|
||||||
Generate PDF invoice: Generar PDF factura
|
Generate PDF invoice: Generar PDF factura
|
||||||
Refund...: Abono
|
Refund: Abono
|
||||||
As PDF: como PDF
|
As PDF: como PDF
|
||||||
As CSV: como CSV
|
As CSV: como CSV
|
||||||
Send PDF: Enviar PDF
|
Send PDF: Enviar PDF
|
||||||
|
|
|
@ -94,11 +94,13 @@ const selectCustomerId = (id) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const statusText = computed(() => {
|
const statusText = computed(() => {
|
||||||
return status.value === 'invoicing'
|
const baseStatus = t(`status.${status.value}`);
|
||||||
? `${t(`status.${status.value}`)} ${
|
const clientId =
|
||||||
addresses.value[getAddressNumber.value]?.clientId
|
status.value === 'invoicing'
|
||||||
}`
|
? addresses.value[getAddressNumber.value]?.clientId || ''
|
||||||
: t(`status.${status.value}`);
|
: '';
|
||||||
|
|
||||||
|
return clientId ? `${baseStatus} ${clientId}`.trim() : baseStatus;
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => (stateStore.rightDrawer = true));
|
onMounted(() => (stateStore.rightDrawer = true));
|
||||||
|
|
|
@ -20,21 +20,25 @@ const { initialDataLoading, formInitialData, invoicing, status } =
|
||||||
const { makeInvoice, setStatusValue } = invoiceOutGlobalStore;
|
const { makeInvoice, setStatusValue } = invoiceOutGlobalStore;
|
||||||
|
|
||||||
const clientsToInvoice = ref('all');
|
const clientsToInvoice = ref('all');
|
||||||
|
|
||||||
const companiesOptions = ref([]);
|
const companiesOptions = ref([]);
|
||||||
|
|
||||||
const printersOptions = ref([]);
|
const printersOptions = ref([]);
|
||||||
|
const serialTypesOptions = ref([]);
|
||||||
|
|
||||||
const clientsOptions = ref([]);
|
const handleInvoiceOutSerialsFetch = (data) => {
|
||||||
|
serialTypesOptions.value = Array.from(
|
||||||
|
new Set(data.map((item) => item.type).filter((type) => type))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const formData = ref({});
|
const formData = ref({});
|
||||||
|
|
||||||
const optionsInitialData = computed(() => {
|
const optionsInitialData = computed(() => {
|
||||||
return (
|
const optionsArrays = [
|
||||||
companiesOptions.value.length > 0 &&
|
companiesOptions.value,
|
||||||
printersOptions.value.length > 0 &&
|
printersOptions.value,
|
||||||
clientsOptions.value.length > 0
|
serialTypesOptions.value,
|
||||||
);
|
];
|
||||||
|
return optionsArrays.every((arr) => arr.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
const getStatus = computed({
|
const getStatus = computed({
|
||||||
|
@ -48,7 +52,7 @@ const getStatus = computed({
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await invoiceOutGlobalStore.init();
|
await invoiceOutGlobalStore.init();
|
||||||
formData.value = formInitialData.value.invoiceDate;
|
formData.value = { invoiceDate: formInitialData.value.invoiceDate };
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -59,8 +63,11 @@ onMounted(async () => {
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData url="Printers" @on-fetch="(data) => (printersOptions = data)" auto-load />
|
<FetchData url="Printers" @on-fetch="(data) => (printersOptions = data)" auto-load />
|
||||||
<FetchData url="Clients" @on-fetch="(data) => (clientsOptions = data)" auto-load />
|
<FetchData
|
||||||
|
url="invoiceOutSerials"
|
||||||
|
@on-fetch="handleInvoiceOutSerialsFetch"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
<QForm
|
<QForm
|
||||||
v-if="!initialDataLoading && optionsInitialData"
|
v-if="!initialDataLoading && optionsInitialData"
|
||||||
@submit="makeInvoice(formData, clientsToInvoice)"
|
@submit="makeInvoice(formData, clientsToInvoice)"
|
||||||
|
@ -87,13 +94,34 @@ onMounted(async () => {
|
||||||
v-if="clientsToInvoice === 'one'"
|
v-if="clientsToInvoice === 'one'"
|
||||||
:label="t('client')"
|
:label="t('client')"
|
||||||
v-model="formData.clientId"
|
v-model="formData.clientId"
|
||||||
:options="clientsOptions"
|
url="Clients"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
hide-selected
|
hide-selected
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>
|
||||||
|
#{{ scope.opt?.id }} {{ scope.opt?.name }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('invoiceOutSerialType')"
|
||||||
|
v-model="formData.serialType"
|
||||||
|
:options="serialTypesOptions"
|
||||||
|
option-value="type"
|
||||||
|
option-label="type"
|
||||||
|
hide-selected
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
/>
|
/>
|
||||||
<VnInputDate
|
<VnInputDate
|
||||||
v-model="formData.invoiceDate"
|
v-model="formData.invoiceDate"
|
||||||
|
@ -109,9 +137,7 @@ onMounted(async () => {
|
||||||
:label="t('company')"
|
:label="t('company')"
|
||||||
v-model="formData.companyFk"
|
v-model="formData.companyFk"
|
||||||
:options="companiesOptions"
|
:options="companiesOptions"
|
||||||
option-value="id"
|
|
||||||
option-label="code"
|
option-label="code"
|
||||||
hide-selected
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
@ -120,9 +146,6 @@ onMounted(async () => {
|
||||||
:label="t('printer')"
|
:label="t('printer')"
|
||||||
v-model="formData.printer"
|
v-model="formData.printer"
|
||||||
:options="printersOptions"
|
:options="printersOptions"
|
||||||
option-value="id"
|
|
||||||
option-label="name"
|
|
||||||
hide-selected
|
|
||||||
dense
|
dense
|
||||||
outlined
|
outlined
|
||||||
rounded
|
rounded
|
||||||
|
@ -168,6 +191,7 @@ en:
|
||||||
printer: Printer
|
printer: Printer
|
||||||
invoiceOut: Invoice out
|
invoiceOut: Invoice out
|
||||||
client: Client
|
client: Client
|
||||||
|
invoiceOutSerialType: Serial Type
|
||||||
stop: Stop
|
stop: Stop
|
||||||
|
|
||||||
es:
|
es:
|
||||||
|
@ -179,5 +203,6 @@ es:
|
||||||
printer: Impresora
|
printer: Impresora
|
||||||
invoiceOut: Facturar
|
invoiceOut: Facturar
|
||||||
client: Cliente
|
client: Cliente
|
||||||
|
invoiceOutSerialType: Tipo de Serie
|
||||||
stop: Parar
|
stop: Parar
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -122,7 +122,7 @@ const columns = computed(() => [
|
||||||
name: 'tableActions',
|
name: 'tableActions',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: t('InvoiceOutSummary'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, InvoiceOutSummary),
|
action: (row) => viewSummary(row.id, InvoiceOutSummary),
|
||||||
},
|
},
|
||||||
|
@ -198,7 +198,7 @@ watchEffect(selectedRows);
|
||||||
:url="`${MODEL}/filter`"
|
:url="`${MODEL}/filter`"
|
||||||
:create="{
|
:create="{
|
||||||
urlCreate: 'InvoiceOuts/createManualInvoice',
|
urlCreate: 'InvoiceOuts/createManualInvoice',
|
||||||
title: t('Create Manual Invoice'),
|
title: t('Create manual invoice'),
|
||||||
onDataSaved: ({ id }) => tableRef.redirect(id),
|
onDataSaved: ({ id }) => tableRef.redirect(id),
|
||||||
formInitialData: {
|
formInitialData: {
|
||||||
active: true,
|
active: true,
|
||||||
|
@ -226,10 +226,18 @@ watchEffect(selectedRows);
|
||||||
url="Tickets"
|
url="Tickets"
|
||||||
v-model="data.ticketFk"
|
v-model="data.ticketFk"
|
||||||
:label="t('invoiceOutList.tableVisibleColumns.ticket')"
|
:label="t('invoiceOutList.tableVisibleColumns.ticket')"
|
||||||
:options="ticketsOptions"
|
option-label="id"
|
||||||
option-label="nickname"
|
|
||||||
option-value="id"
|
option-value="id"
|
||||||
/>
|
>
|
||||||
|
<template #option="scope">
|
||||||
|
<QItem v-bind="scope.itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel> #{{ scope.opt?.id }} </QItemLabel>
|
||||||
|
<QItemLabel caption>{{ scope.opt?.nickname }}</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
<span class="q-ml-md">O</span>
|
<span class="q-ml-md">O</span>
|
||||||
</div>
|
</div>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
|
@ -242,7 +250,7 @@ watchEffect(selectedRows);
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
url="InvoiceOutSerials"
|
url="InvoiceOutSerials"
|
||||||
v-model="data.invoiceOutSerial"
|
v-model="data.serial"
|
||||||
:label="t('invoiceOutList.tableVisibleColumns.invoiceOutSerial')"
|
:label="t('invoiceOutList.tableVisibleColumns.invoiceOutSerial')"
|
||||||
:options="invoiceOutSerialsOptions"
|
:options="invoiceOutSerialsOptions"
|
||||||
option-label="description"
|
option-label="description"
|
||||||
|
@ -254,7 +262,7 @@ watchEffect(selectedRows);
|
||||||
/>
|
/>
|
||||||
<VnSelect
|
<VnSelect
|
||||||
url="TaxAreas"
|
url="TaxAreas"
|
||||||
v-model="data.area"
|
v-model="data.taxArea"
|
||||||
:label="t('invoiceOutList.tableVisibleColumns.taxArea')"
|
:label="t('invoiceOutList.tableVisibleColumns.taxArea')"
|
||||||
:options="taxAreasOptions"
|
:options="taxAreasOptions"
|
||||||
option-label="code"
|
option-label="code"
|
||||||
|
@ -275,10 +283,12 @@ en:
|
||||||
fileAllowed: Successful download of CSV file
|
fileAllowed: Successful download of CSV file
|
||||||
youCanSearchByInvoiceReference: You can search by invoice reference
|
youCanSearchByInvoiceReference: You can search by invoice reference
|
||||||
createInvoice: Make invoice
|
createInvoice: Make invoice
|
||||||
|
Create manual invoice: Create manual invoice
|
||||||
es:
|
es:
|
||||||
searchInvoice: Buscar factura emitida
|
searchInvoice: Buscar factura emitida
|
||||||
fileDenied: El navegador denegó la descarga de archivos...
|
fileDenied: El navegador denegó la descarga de archivos...
|
||||||
fileAllowed: Descarga exitosa de archivo CSV
|
fileAllowed: Descarga exitosa de archivo CSV
|
||||||
youCanSearchByInvoiceReference: Puedes buscar por referencia de la factura
|
youCanSearchByInvoiceReference: Puedes buscar por referencia de la factura
|
||||||
createInvoice: Crear factura
|
createInvoice: Crear factura
|
||||||
|
Create manual invoice: Crear factura manual
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -138,14 +138,6 @@ en:
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.edit-photo-btn {
|
|
||||||
position: absolute;
|
|
||||||
right: 12px;
|
|
||||||
bottom: 12px;
|
|
||||||
z-index: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separation-borders {
|
.separation-borders {
|
||||||
border-left: 1px solid $white;
|
border-left: 1px solid $white;
|
||||||
border-right: 1px solid $white;
|
border-right: 1px solid $white;
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
|
import { toDateFormat } from 'src/filters/date.js';
|
||||||
|
import VnTable from 'src/components/VnTable/VnTable.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
import VnRow from 'src/components/ui/VnRow.vue';
|
||||||
|
import { dateRange } from 'src/filters';
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const dates = dateRange(Date.vnNew());
|
||||||
|
const from = ref(dates[0]);
|
||||||
|
const to = ref(dates[1]);
|
||||||
|
|
||||||
|
const filter = computed(() => {
|
||||||
|
const obj = {};
|
||||||
|
const formatFrom = setHours(from.value, 'from');
|
||||||
|
const formatTo = setHours(to.value, 'to');
|
||||||
|
let stamp;
|
||||||
|
|
||||||
|
if (!formatFrom && formatTo) stamp = { lte: formatTo };
|
||||||
|
else if (formatFrom && !formatTo) stamp = { gte: formatFrom };
|
||||||
|
else if (formatFrom && formatTo) stamp = { between: [formatFrom, formatTo] };
|
||||||
|
|
||||||
|
return Object.assign(obj, { where: { 'v.stamp': stamp } });
|
||||||
|
});
|
||||||
|
|
||||||
|
function exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'clientFk':
|
||||||
|
return { [`c.id`]: value };
|
||||||
|
case 'salesPersonFk':
|
||||||
|
return { [`c.${param}`]: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setHours(date, type) {
|
||||||
|
if (!date) return null;
|
||||||
|
|
||||||
|
const d = new Date(date);
|
||||||
|
if (type == 'from') d.setHours(0, 0, 0, 0);
|
||||||
|
else d.setHours(23, 59, 59, 59);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('salesClientsTable.date'),
|
||||||
|
name: 'dated',
|
||||||
|
field: 'dated',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: false,
|
||||||
|
format: (row) => toDateFormat(row.dated, 'es-ES', { year: '2-digit' }),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesClientsTable.hour'),
|
||||||
|
name: 'hour',
|
||||||
|
field: 'hour',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesClientsTable.salesPerson'),
|
||||||
|
name: 'salesPersonFk',
|
||||||
|
field: 'salesPerson',
|
||||||
|
align: 'left',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
optionFilter: 'firstName',
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'nickname ASC',
|
||||||
|
where: { role: 'salesPerson' },
|
||||||
|
useLike: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columnClass: 'no-padding',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesClientsTable.client'),
|
||||||
|
field: 'clientName',
|
||||||
|
name: 'clientFk',
|
||||||
|
align: 'left',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
orderBy: 'c.name',
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Clients',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
columnClass: 'no-padding',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VnTable
|
||||||
|
ref="table"
|
||||||
|
data-key="SalesMonitorClients"
|
||||||
|
url="SalesMonitors/clientsFilter"
|
||||||
|
search-url="SalesMonitorClients"
|
||||||
|
:order="['dated DESC', 'hour DESC']"
|
||||||
|
:expr-builder="exprBuilder"
|
||||||
|
:filter="filter"
|
||||||
|
:offset="50"
|
||||||
|
auto-load
|
||||||
|
:columns="columns"
|
||||||
|
:right-search="false"
|
||||||
|
default-mode="table"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
|
dense
|
||||||
|
class="q-px-none"
|
||||||
|
>
|
||||||
|
<template #top-left>
|
||||||
|
<VnRow>
|
||||||
|
<VnInputDate v-model="from" :label="$t('globals.from')" dense />
|
||||||
|
<VnInputDate v-model="to" :label="$t('globals.to')" dense />
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
||||||
|
<template #column-salesPersonFk="{ row }">
|
||||||
|
<span class="link" :title="row.salesPerson" v-text="row.salesPerson" />
|
||||||
|
<WorkerDescriptorProxy :id="row.salesPersonFk" dense />
|
||||||
|
</template>
|
||||||
|
<template #column-clientFk="{ row }">
|
||||||
|
<span class="link" :title="row.clientName" v-text="row.clientName" />
|
||||||
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||||
|
</template>
|
||||||
|
</VnTable>
|
||||||
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.full-width .vn-row > * {
|
||||||
|
flex: 0.4;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,26 @@
|
||||||
|
<script setup>
|
||||||
|
import SalesClientTable from './MonitorClients.vue';
|
||||||
|
import SalesOrdersTable from './MonitorOrders.vue';
|
||||||
|
import VnRow from 'src/components/ui/VnRow.vue';
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VnRow
|
||||||
|
class="q-pa-md"
|
||||||
|
:style="{ 'flex-direction': $q.screen.lt.lg ? 'column' : 'row', gap: '0px' }"
|
||||||
|
>
|
||||||
|
<div style="flex: 0.3">
|
||||||
|
<span
|
||||||
|
class="q-ml-md text-body1"
|
||||||
|
v-text="$t('salesMonitor.clientsOnWebsite')"
|
||||||
|
/>
|
||||||
|
<SalesClientTable />
|
||||||
|
</div>
|
||||||
|
<div style="flex: 0.7">
|
||||||
|
<span
|
||||||
|
class="q-ml-md text-body1"
|
||||||
|
v-text="$t('salesMonitor.recentOrderActions')"
|
||||||
|
/>
|
||||||
|
<SalesOrdersTable />
|
||||||
|
</div>
|
||||||
|
</VnRow>
|
||||||
|
</template>
|
|
@ -1,90 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { onMounted, onUnmounted, ref } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import { useStateStore } from 'stores/useStateStore';
|
|
||||||
import SalesClientTable from './SalesClientsTable.vue';
|
|
||||||
import SalesOrdersTable from './SalesOrdersTable.vue';
|
|
||||||
import SalesTicketsTable from './SalesTicketsTable.vue';
|
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const stateStore = useStateStore();
|
|
||||||
|
|
||||||
const expanded = ref(true);
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
stateStore.leftDrawer = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => (stateStore.leftDrawer = true));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<template v-if="stateStore.isHeaderMounted()">
|
|
||||||
<Teleport to="#searchbar">
|
|
||||||
<VnSearchbar
|
|
||||||
data-key="SalesMonitorTickets"
|
|
||||||
url="SalesMonitors/salesFilter"
|
|
||||||
:redirect="false"
|
|
||||||
:label="t('searchBar.label')"
|
|
||||||
:info="t('searchBar.info')"
|
|
||||||
/>
|
|
||||||
</Teleport>
|
|
||||||
</template>
|
|
||||||
<QPage class="column items-center q-pa-md">
|
|
||||||
<QCard class="full-width q-mb-lg">
|
|
||||||
<QExpansionItem v-model="expanded" dense :duration="150">
|
|
||||||
<template v-if="!expanded" #header>
|
|
||||||
<div class="row full-width">
|
|
||||||
<span class="flex col text-body1">
|
|
||||||
{{ t('salesMonitor.clientsOnWebsite') }}
|
|
||||||
</span>
|
|
||||||
<span class="flex col q-ml-xl text-body1">
|
|
||||||
{{ t('salesMonitor.recentOrderActions') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template #default>
|
|
||||||
<div class="expansion-tables-container">
|
|
||||||
<QCardSection class="col">
|
|
||||||
<span class="flex col q-mb-sm text-body1">
|
|
||||||
{{ t('salesMonitor.clientsOnWebsite') }}
|
|
||||||
</span>
|
|
||||||
<SalesClientTable />
|
|
||||||
</QCardSection>
|
|
||||||
<QCardSection class="col">
|
|
||||||
<span class="flex col q-mb-sm text-body1">
|
|
||||||
{{ t('salesMonitor.recentOrderActions') }}
|
|
||||||
</span>
|
|
||||||
<SalesOrdersTable />
|
|
||||||
</QCardSection>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</QExpansionItem>
|
|
||||||
</QCard>
|
|
||||||
<QCard class="full-width">
|
|
||||||
<QItem class="justify-between">
|
|
||||||
<QItemLabel class="col slider-container">
|
|
||||||
<span class="text-body1"
|
|
||||||
>{{ t('salesMonitor.ticketsMonitor') }}
|
|
||||||
</span>
|
|
||||||
<QCardSection class="col" style="padding-inline: 0"
|
|
||||||
><SalesTicketsTable />
|
|
||||||
</QCardSection>
|
|
||||||
</QItemLabel>
|
|
||||||
</QItem>
|
|
||||||
</QCard>
|
|
||||||
</QPage>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.expansion-tables-container {
|
|
||||||
display: flex;
|
|
||||||
border-top: 1px solid $color-spacer;
|
|
||||||
|
|
||||||
@media (max-width: $breakpoint-md-max) {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
|
|
||||||
|
import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
|
||||||
|
import { toCurrency } from 'src/filters';
|
||||||
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
|
|
||||||
|
const table = ref();
|
||||||
|
const selectedRows = ref([]);
|
||||||
|
|
||||||
|
function exprBuilder(param, value) {
|
||||||
|
switch (param) {
|
||||||
|
case 'clientFk':
|
||||||
|
return { [`c.id`]: value };
|
||||||
|
case 'salesPersonFk':
|
||||||
|
return { [`c.salesPersonFk`]: value };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const columns = computed(() => [
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.dateSend'),
|
||||||
|
name: 'dateSend',
|
||||||
|
field: 'dateSend',
|
||||||
|
align: 'left',
|
||||||
|
orderBy: 'date_send',
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.dateMake'),
|
||||||
|
name: 'dateMake',
|
||||||
|
field: 'dateMake',
|
||||||
|
align: 'left',
|
||||||
|
orderBy: 'date_make',
|
||||||
|
columnFilter: false,
|
||||||
|
format: (row) => toDateTimeFormat(row.date_make),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.client'),
|
||||||
|
name: 'clientFk',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Clients',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.agency'),
|
||||||
|
name: 'agencyName',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.salesPerson'),
|
||||||
|
name: 'salesPersonFk',
|
||||||
|
align: 'left',
|
||||||
|
optionFilter: 'firstName',
|
||||||
|
columnFilter: {
|
||||||
|
component: 'select',
|
||||||
|
attrs: {
|
||||||
|
url: 'Workers/activeWithInheritedRole',
|
||||||
|
fields: ['id', 'name'],
|
||||||
|
sortBy: 'nickname ASC',
|
||||||
|
where: { role: 'salesPerson' },
|
||||||
|
useLike: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('salesOrdersTable.import'),
|
||||||
|
name: 'import',
|
||||||
|
field: 'import',
|
||||||
|
align: 'left',
|
||||||
|
columnFilter: false,
|
||||||
|
format: (row) => toCurrency(row.import),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getBadgeColor = (date) => {
|
||||||
|
const today = Date.vnNew();
|
||||||
|
today.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const orderLanded = new Date(date);
|
||||||
|
orderLanded.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
const difference = today - orderLanded;
|
||||||
|
|
||||||
|
if (difference == 0) return 'warning';
|
||||||
|
if (difference < 0) return 'success';
|
||||||
|
if (difference > 0) return 'alert';
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeOrders = async () => {
|
||||||
|
try {
|
||||||
|
const selectedIds = selectedRows.value.map((row) => row.id);
|
||||||
|
const params = { deletes: selectedIds };
|
||||||
|
await axios.post('SalesMonitors/deleteOrders', params);
|
||||||
|
selectedRows.value = [];
|
||||||
|
await table.value.reload();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error deleting orders', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openTab = (id) =>
|
||||||
|
window.open(`#/order/${id}/summary`, '_blank', 'noopener, noreferrer');
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VnTable
|
||||||
|
ref="table"
|
||||||
|
class="q-px-none"
|
||||||
|
data-key="SalesMonitorOrders"
|
||||||
|
url="SalesMonitors/ordersFilter"
|
||||||
|
search-url="SalesMonitorOrders"
|
||||||
|
order="date_send DESC"
|
||||||
|
:right-search="false"
|
||||||
|
:expr-builder="exprBuilder"
|
||||||
|
auto-load
|
||||||
|
:columns="columns"
|
||||||
|
:table="{
|
||||||
|
'row-key': 'id',
|
||||||
|
selection: 'multiple',
|
||||||
|
'hide-bottom': true,
|
||||||
|
}"
|
||||||
|
default-mode="table"
|
||||||
|
:row-click="({ id }) => openTab(id)"
|
||||||
|
v-model:selected="selectedRows"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
|
>
|
||||||
|
<template #top-left>
|
||||||
|
<QBtn
|
||||||
|
icon="refresh"
|
||||||
|
size="md"
|
||||||
|
color="primary"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
@click="$refs.table.reload()"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('globals.refresh') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
<QBtn
|
||||||
|
v-if="selectedRows.length"
|
||||||
|
icon="delete"
|
||||||
|
size="md"
|
||||||
|
dense
|
||||||
|
flat
|
||||||
|
color="primary"
|
||||||
|
@click="
|
||||||
|
openConfirmationModal(
|
||||||
|
$t('salesOrdersTable.deleteConfirmTitle'),
|
||||||
|
$t('salesOrdersTable.deleteConfirmMessage'),
|
||||||
|
removeOrders
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ t('salesOrdersTable.delete') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
|
</template>
|
||||||
|
<template #column-dateSend="{ row }">
|
||||||
|
<QTd>
|
||||||
|
<QBadge
|
||||||
|
:color="getBadgeColor(row.date_send)"
|
||||||
|
text-color="black"
|
||||||
|
class="q-pa-sm"
|
||||||
|
style="font-size: 14px"
|
||||||
|
>
|
||||||
|
{{ toDateFormat(row.date_send) }}
|
||||||
|
</QBadge>
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #column-clientFk="{ row }">
|
||||||
|
<QTd @click.stop>
|
||||||
|
<span class="link" v-text="row.clientName" :title="row.clientName" />
|
||||||
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #column-salesPersonFk="{ row }">
|
||||||
|
<QTd @click.stop>
|
||||||
|
<span class="link" v-text="row.salesPerson" />
|
||||||
|
<WorkerDescriptorProxy :id="row.salesPersonFk" dense />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
|
</VnTable>
|
||||||
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.q-td {
|
||||||
|
max-width: 140px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,147 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref, computed, reactive, watch } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
|
||||||
|
|
||||||
import { toDateFormat } from 'src/filters/date.js';
|
|
||||||
import VnTable from 'src/components/VnTable/VnTable.vue';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
|
|
||||||
const paginateRef = ref(null);
|
|
||||||
const workersActiveOptions = ref([]);
|
|
||||||
const clientsOptions = ref([]);
|
|
||||||
|
|
||||||
const from = ref(Date.vnNew());
|
|
||||||
const to = ref(Date.vnNew());
|
|
||||||
|
|
||||||
const dateRange = computed(() => {
|
|
||||||
const minHour = new Date(from.value);
|
|
||||||
minHour.setHours(0, 0, 0, 0);
|
|
||||||
const maxHour = new Date(to.value);
|
|
||||||
maxHour.setHours(23, 59, 59, 59);
|
|
||||||
return [minHour, maxHour];
|
|
||||||
});
|
|
||||||
|
|
||||||
const filter = reactive({
|
|
||||||
where: {
|
|
||||||
'v.stamp': {
|
|
||||||
between: dateRange.value,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const refetch = async () => await paginateRef.value.fetch();
|
|
||||||
|
|
||||||
watch(dateRange, (val) => {
|
|
||||||
filter.where['v.stamp'].between = val;
|
|
||||||
refetch();
|
|
||||||
});
|
|
||||||
|
|
||||||
function exprBuilder(param, value) {
|
|
||||||
switch (param) {
|
|
||||||
case 'clientFk':
|
|
||||||
return { [`c.id`]: value };
|
|
||||||
case 'salesPersonFk':
|
|
||||||
return { [`c.${param}`]: value };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const params = reactive({});
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
|
||||||
{
|
|
||||||
label: t('salesClientsTable.date'),
|
|
||||||
name: 'dated',
|
|
||||||
field: 'dated',
|
|
||||||
align: 'left',
|
|
||||||
columnFilter: null,
|
|
||||||
sortable: true,
|
|
||||||
format: (row) => toDateFormat(row.dated),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('salesClientsTable.hour'),
|
|
||||||
name: 'hour',
|
|
||||||
field: 'hour',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('salesClientsTable.salesPerson'),
|
|
||||||
name: 'salesPerson',
|
|
||||||
field: 'salesPerson',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
columnField: {
|
|
||||||
component: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('salesClientsTable.client'),
|
|
||||||
field: 'clientName',
|
|
||||||
name: 'client',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
columnField: {
|
|
||||||
component: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<FetchData
|
|
||||||
url="Workers/activeWithInheritedRole"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'nickname'],
|
|
||||||
order: 'nickname ASC',
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
}"
|
|
||||||
auto-load
|
|
||||||
@on-fetch="(data) => (workersActiveOptions = data)"
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="Clients"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'name'],
|
|
||||||
order: 'name ASC',
|
|
||||||
}"
|
|
||||||
auto-load
|
|
||||||
@on-fetch="(data) => (clientsOptions = data)"
|
|
||||||
/>
|
|
||||||
<QCard style="max-height: 380px; overflow-y: scroll">
|
|
||||||
<VnTable
|
|
||||||
ref="paginateRef"
|
|
||||||
data-key="SalesMonitorClients"
|
|
||||||
url="SalesMonitors/clientsFilter"
|
|
||||||
:order="['dated DESC', 'hour DESC']"
|
|
||||||
:limit="6"
|
|
||||||
:expr-builder="exprBuilder"
|
|
||||||
:user-params="params"
|
|
||||||
:filter="filter"
|
|
||||||
:offset="50"
|
|
||||||
auto-load
|
|
||||||
:columns="columns"
|
|
||||||
:right-search="false"
|
|
||||||
default-mode="table"
|
|
||||||
dense
|
|
||||||
:without-header="true"
|
|
||||||
>
|
|
||||||
<template #column-salesPerson="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<span class="link">{{ row.salesPerson }}</span>
|
|
||||||
<WorkerDescriptorProxy :id="row.salesPersonFk" dense />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #column-client="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<span class="link">{{ row.clientName }}</span>
|
|
||||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</VnTable>
|
|
||||||
</QCard>
|
|
||||||
</template>
|
|
|
@ -1,204 +0,0 @@
|
||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue';
|
|
||||||
import { useI18n } from 'vue-i18n';
|
|
||||||
|
|
||||||
import FetchData from 'components/FetchData.vue';
|
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
|
||||||
|
|
||||||
import { toDateFormat, toDateTimeFormat } from 'src/filters/date.js';
|
|
||||||
import { toCurrency } from 'src/filters';
|
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
|
||||||
const { openConfirmationModal } = useVnConfirm();
|
|
||||||
|
|
||||||
const paginateRef = ref(null);
|
|
||||||
const workersActiveOptions = ref([]);
|
|
||||||
const clientsOptions = ref([]);
|
|
||||||
const selectedRows = ref([]);
|
|
||||||
|
|
||||||
const dateRange = (value) => {
|
|
||||||
const minHour = new Date(value);
|
|
||||||
minHour.setHours(0, 0, 0, 0);
|
|
||||||
const maxHour = new Date(value);
|
|
||||||
maxHour.setHours(23, 59, 59, 59);
|
|
||||||
|
|
||||||
return [minHour, maxHour];
|
|
||||||
};
|
|
||||||
|
|
||||||
function exprBuilder(param, value) {
|
|
||||||
switch (param) {
|
|
||||||
case 'date_send':
|
|
||||||
return {
|
|
||||||
[`o.date_send`]: {
|
|
||||||
between: dateRange(value),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
case 'clientFk':
|
|
||||||
return { [`c.id`]: value };
|
|
||||||
case 'salesPersonFk':
|
|
||||||
return { [`c.${param}`]: value };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
|
||||||
{
|
|
||||||
label: t('salesOrdersTable.date'),
|
|
||||||
name: 'date',
|
|
||||||
field: 'dated',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
cardVisible: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('salesOrdersTable.client'),
|
|
||||||
name: 'client',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
cardVisible: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: t('salesOrdersTable.salesPerson'),
|
|
||||||
name: 'salesPerson',
|
|
||||||
align: 'left',
|
|
||||||
sortable: true,
|
|
||||||
cardVisible: true,
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const getBadgeColor = (date) => {
|
|
||||||
const today = Date.vnNew();
|
|
||||||
today.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
const orderLanded = new Date(date);
|
|
||||||
orderLanded.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
const difference = today - orderLanded;
|
|
||||||
|
|
||||||
if (difference == 0) return 'warning';
|
|
||||||
if (difference < 0) return 'success';
|
|
||||||
if (difference > 0) return 'alert';
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeOrders = async () => {
|
|
||||||
try {
|
|
||||||
const selectedIds = selectedRows.value.map((row) => row.id);
|
|
||||||
const params = { deletes: selectedIds };
|
|
||||||
await axios.post('SalesMonitors/deleteOrders', params);
|
|
||||||
selectedRows.value = [];
|
|
||||||
await paginateRef.value.fetch();
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error deleting orders', err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const redirectToOrderSummary = (orderId) => {
|
|
||||||
const url = `#/order/${orderId}/summary`;
|
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<FetchData
|
|
||||||
url="Workers/activeWithInheritedRole"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'nickname'],
|
|
||||||
order: 'nickname ASC',
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
}"
|
|
||||||
auto-load
|
|
||||||
@on-fetch="(data) => (workersActiveOptions = data)"
|
|
||||||
/>
|
|
||||||
<FetchData
|
|
||||||
url="Clients"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'name'],
|
|
||||||
order: 'name ASC',
|
|
||||||
}"
|
|
||||||
auto-load
|
|
||||||
@on-fetch="(data) => (clientsOptions = data)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<VnSubToolbar />
|
|
||||||
<QCard style="max-height: 380px; overflow-y: scroll">
|
|
||||||
<VnTable
|
|
||||||
ref="paginateRef"
|
|
||||||
data-key="SalesMonitorOrders"
|
|
||||||
url="SalesMonitors/ordersFilter"
|
|
||||||
order="date_make DESC"
|
|
||||||
:limit="6"
|
|
||||||
:right-search="false"
|
|
||||||
:expr-builder="exprBuilder"
|
|
||||||
auto-load
|
|
||||||
:columns="columns"
|
|
||||||
:table="{
|
|
||||||
'row-key': 'id',
|
|
||||||
selection: 'multiple',
|
|
||||||
'hide-bottom': true,
|
|
||||||
}"
|
|
||||||
default-mode="table"
|
|
||||||
:without-header="false"
|
|
||||||
@row-click="(_, row) => redirectToOrderSummary(row.id)"
|
|
||||||
v-model:selected="selectedRows"
|
|
||||||
>
|
|
||||||
<template #top-left>
|
|
||||||
<QBtn
|
|
||||||
v-if="selectedRows.length > 0"
|
|
||||||
icon="delete"
|
|
||||||
size="md"
|
|
||||||
color="primary"
|
|
||||||
@click="
|
|
||||||
openConfirmationModal(
|
|
||||||
t('salesOrdersTable.deleteConfirmTitle'),
|
|
||||||
t('salesOrdersTable.deleteConfirmMessage'),
|
|
||||||
removeOrders
|
|
||||||
)
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<QTooltip>{{ t('salesOrdersTable.delete') }}</QTooltip>
|
|
||||||
</QBtn>
|
|
||||||
</template>
|
|
||||||
<template #column-date="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<QBadge
|
|
||||||
:color="getBadgeColor(row.date_send)"
|
|
||||||
text-color="black"
|
|
||||||
class="q-pa-sm q-mb-md"
|
|
||||||
style="font-size: 14px"
|
|
||||||
>
|
|
||||||
{{ toDateFormat(row.date_send) }}
|
|
||||||
</QBadge>
|
|
||||||
<div>{{ toDateTimeFormat(row.date_make) }}</div>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
<template #column-client="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<div class="q-mb-md">
|
|
||||||
<span class="link">{{ row.clientName }}</span>
|
|
||||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
|
||||||
</div>
|
|
||||||
<span> {{ row.agencyName }}</span>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #column-salesPerson="{ row }">
|
|
||||||
<QTd>
|
|
||||||
<div class="q-mb-md">
|
|
||||||
<span class="link">{{ row.salesPerson }}</span>
|
|
||||||
<WorkerDescriptorProxy :id="row.salesPersonFk" dense />
|
|
||||||
</div>
|
|
||||||
<span>{{ toCurrency(row.import) }}</span>
|
|
||||||
</QTd>
|
|
||||||
</template>
|
|
||||||
</VnTable>
|
|
||||||
</QCard>
|
|
||||||
</template>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.q-td {
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -0,0 +1,286 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
import VnFilterPanelChip from 'src/components/ui/VnFilterPanelChip.vue';
|
||||||
|
import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
import VnInputNumber from 'src/components/common/VnInputNumber.vue';
|
||||||
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
|
import { dateRange } from 'src/filters';
|
||||||
|
|
||||||
|
defineProps({ dataKey: { type: String, required: true } });
|
||||||
|
const { t } = useI18n();
|
||||||
|
const warehouses = ref();
|
||||||
|
const groupedStates = ref();
|
||||||
|
|
||||||
|
const handleScopeDays = (params, days, callback) => {
|
||||||
|
const [from, to] = dateRange(Date.vnNew());
|
||||||
|
if (!days) {
|
||||||
|
Object.assign(params, { from, to, scopeDays: 1 });
|
||||||
|
} else {
|
||||||
|
params.from = from;
|
||||||
|
to.setDate(to.getDate() + days);
|
||||||
|
params.to = to;
|
||||||
|
}
|
||||||
|
if (callback) callback();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<FetchData url="Warehouses" auto-load @on-fetch="(data) => (warehouses = data)" />
|
||||||
|
<FetchData
|
||||||
|
url="AlertLevels"
|
||||||
|
auto-load
|
||||||
|
@on-fetch="
|
||||||
|
(data) =>
|
||||||
|
(groupedStates = data.map((x) => Object.assign(x, { code: t(x.code) })))
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<VnFilterPanel
|
||||||
|
:data-key="dataKey"
|
||||||
|
:search-button="true"
|
||||||
|
:hidden-tags="['from', 'to']"
|
||||||
|
:custom-tags="['scopeDays']"
|
||||||
|
:unremovable-params="['from', 'to', 'scopeDays']"
|
||||||
|
>
|
||||||
|
<template #tags="{ tag, formatFn }">
|
||||||
|
<div class="q-gutter-x-xs">
|
||||||
|
<strong v-text="`${t(`params.${tag.label}`)}:`" />
|
||||||
|
<span v-text="formatFn(tag.value)" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #customTags="{ params, searchFn, formatFn }">
|
||||||
|
<VnFilterPanelChip
|
||||||
|
v-if="params.scopeDays"
|
||||||
|
removable
|
||||||
|
@remove="handleScopeDays(params, null, searchFn)"
|
||||||
|
>
|
||||||
|
<strong v-text="`${t(`params.scopeDays`)}:`" />
|
||||||
|
<span v-text="formatFn(params.scopeDays)" />
|
||||||
|
</VnFilterPanelChip>
|
||||||
|
</template>
|
||||||
|
<template #body="{ params }">
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.clientFk')"
|
||||||
|
v-model="params.clientFk"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.orderFk')"
|
||||||
|
v-model="params.orderFk"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInputNumber
|
||||||
|
:label="t('params.scopeDays')"
|
||||||
|
v-model="params.scopeDays"
|
||||||
|
is-outlined
|
||||||
|
@update:model-value="(val) => handleScopeDays(params, val)"
|
||||||
|
@remove="(val) => handleScopeDays(params, val)"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.nickname')"
|
||||||
|
v-model="params.nickname"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.salesPersonFk')"
|
||||||
|
v-model="params.salesPersonFk"
|
||||||
|
url="Workers/search"
|
||||||
|
:params="{ departmentCodes: ['VT'] }"
|
||||||
|
is-outlined
|
||||||
|
option-value="code"
|
||||||
|
option-label="name"
|
||||||
|
:no-one="true"
|
||||||
|
>
|
||||||
|
<template #option="{ opt, itemProps }">
|
||||||
|
<QItem v-bind="itemProps">
|
||||||
|
<QItemSection>
|
||||||
|
<QItemLabel>{{ opt.name }}</QItemLabel>
|
||||||
|
<QItemLabel
|
||||||
|
v-if="opt.code"
|
||||||
|
class="text-grey text-caption"
|
||||||
|
>
|
||||||
|
{{ `${opt.nickname}, ${opt.code}` }}
|
||||||
|
</QItemLabel>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.refFk')"
|
||||||
|
v-model="params.refFk"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.agencyModeFk')"
|
||||||
|
v-model="params.agencyModeFk"
|
||||||
|
url="AgencyModes/isActive"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.stateFk')"
|
||||||
|
v-model="params.stateFk"
|
||||||
|
url="States"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.groupedStates')"
|
||||||
|
v-model="params.alertLevel"
|
||||||
|
:options="groupedStates"
|
||||||
|
option-label="code"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.warehouseFk')"
|
||||||
|
v-model="params.warehouseFk"
|
||||||
|
:options="warehouses"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
rounded
|
||||||
|
:label="t('params.provinceFk')"
|
||||||
|
v-model="params.provinceFk"
|
||||||
|
url="Provinces"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('params.myTeam')"
|
||||||
|
v-model="params.myTeam"
|
||||||
|
toggle-indeterminate
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('params.problems')"
|
||||||
|
v-model="params.problems"
|
||||||
|
toggle-indeterminate
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('params.pending')"
|
||||||
|
v-model="params.pending"
|
||||||
|
toggle-indeterminate
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnFilterPanel>
|
||||||
|
</template>
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
params:
|
||||||
|
clientFk: Client id
|
||||||
|
orderFk: Order id
|
||||||
|
scopeDays: Days onward
|
||||||
|
nickname: Nickname
|
||||||
|
salesPersonFk: Sales person
|
||||||
|
refFk: Invoice
|
||||||
|
agencyModeFk: Agency
|
||||||
|
stateFk: State
|
||||||
|
groupedStates: Grouped State
|
||||||
|
warehouseFk: Warehouse
|
||||||
|
provinceFk: Province
|
||||||
|
myTeam: My team
|
||||||
|
problems: With problems
|
||||||
|
pending: Pending
|
||||||
|
from: From
|
||||||
|
to: To
|
||||||
|
alertLevel: Grouped State
|
||||||
|
FREE: Free
|
||||||
|
DELIVERED: Delivered
|
||||||
|
ON_PREPARATION: On preparation
|
||||||
|
ON_PREVIOUS: On previous
|
||||||
|
PACKED: Packed
|
||||||
|
No one: No one
|
||||||
|
|
||||||
|
es:
|
||||||
|
params:
|
||||||
|
clientFk: Id cliente
|
||||||
|
orderFk: Id cesta
|
||||||
|
scopeDays: Días en adelante
|
||||||
|
nickname: Nombre mostrado
|
||||||
|
salesPersonFk: Comercial
|
||||||
|
refFk: Factura
|
||||||
|
agencyModeFk: Agencia
|
||||||
|
stateFk: Estado
|
||||||
|
groupedStates: Estado agrupado
|
||||||
|
warehouseFk: Almacén
|
||||||
|
provinceFk: Provincia
|
||||||
|
myTeam: Mi equipo
|
||||||
|
problems: Con problemas
|
||||||
|
pending: Pendiente
|
||||||
|
from: Desde
|
||||||
|
To: Hasta
|
||||||
|
alertLevel: Estado agrupado
|
||||||
|
FREE: Libre
|
||||||
|
DELIVERED: Servido
|
||||||
|
ON_PREPARATION: En preparación
|
||||||
|
ON_PREVIOUS: En previa
|
||||||
|
PACKED: Encajado
|
||||||
|
</i18n>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<script setup>
|
||||||
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VnSearchbar
|
||||||
|
data-key="SalesMonitorTickets"
|
||||||
|
url="SalesMonitors/salesFilter"
|
||||||
|
:redirect="false"
|
||||||
|
:label="$t('searchBar.label')"
|
||||||
|
:info="$t('searchBar.info')"
|
||||||
|
/>
|
||||||
|
</template>
|
|
@ -1,37 +1,38 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, reactive } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
import WorkerDescriptorProxy from 'src/pages/Worker/Card/WorkerDescriptorProxy.vue';
|
||||||
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
import CustomerDescriptorProxy from 'src/pages/Customer/Card/CustomerDescriptorProxy.vue';
|
||||||
import TableVisibleColumns from 'src/components/common/TableVisibleColumns.vue';
|
|
||||||
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
import InvoiceOutDescriptorProxy from 'src/pages/InvoiceOut/Card/InvoiceOutDescriptorProxy.vue';
|
||||||
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
import ZoneDescriptorProxy from 'src/pages/Zone/Card/ZoneDescriptorProxy.vue';
|
||||||
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
|
import TicketSummary from 'src/pages/Ticket/Card/TicketSummary.vue';
|
||||||
import VnTable from 'components/VnTable/VnTable.vue';
|
import VnTable from 'components/VnTable/VnTable.vue';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import { toDateFormat, toTimeFormat } from 'src/filters/date.js';
|
import { toDateFormat } from 'src/filters/date.js';
|
||||||
import { toCurrency, dateRange } from 'src/filters';
|
import { toCurrency, dateRange, dashIfEmpty } from 'src/filters';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import MonitorTicketSearchbar from './MonitorTicketSearchbar.vue';
|
||||||
|
import MonitorTicketFilter from './MonitorTicketFilter.vue';
|
||||||
|
|
||||||
const DEFAULT_AUTO_REFRESH = 1000;
|
const DEFAULT_AUTO_REFRESH = 2 * 60 * 1000; // 2min in ms
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const autoRefresh = ref(false);
|
const autoRefresh = ref(false);
|
||||||
const paginateRef = ref(null);
|
const tableRef = ref(null);
|
||||||
const workersActiveOptions = ref([]);
|
const provinceOpts = ref([]);
|
||||||
const provincesOptions = ref([]);
|
const stateOpts = ref([]);
|
||||||
const statesOptions = ref([]);
|
const zoneOpts = ref([]);
|
||||||
const zonesOptions = ref([]);
|
|
||||||
const visibleColumns = ref([]);
|
const visibleColumns = ref([]);
|
||||||
const allColumnNames = ref([]);
|
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
|
const [from, to] = dateRange(Date.vnNew());
|
||||||
|
|
||||||
function exprBuilder(param, value) {
|
function exprBuilder(param, value) {
|
||||||
switch (param) {
|
switch (param) {
|
||||||
case 'stateFk':
|
case 'stateFk':
|
||||||
return { 'ts.stateFk': value };
|
return { 'ts.stateFk': value };
|
||||||
case 'salesPersonFk':
|
case 'salesPersonFk':
|
||||||
return { 'c.salesPersonFk': value };
|
return { 'c.salesPersonFk': !value ? null : value };
|
||||||
case 'provinceFk':
|
case 'provinceFk':
|
||||||
return { 'a.provinceFk': value };
|
return { 'a.provinceFk': value };
|
||||||
case 'theoreticalHour':
|
case 'theoreticalHour':
|
||||||
|
@ -48,15 +49,12 @@ function exprBuilder(param, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = { order: ['totalProblems DESC'] };
|
|
||||||
let params = reactive({});
|
|
||||||
|
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.problems'),
|
label: t('salesTicketsTable.problems'),
|
||||||
name: 'problems',
|
name: 'totalProblems',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
|
||||||
columnFilter: false,
|
columnFilter: false,
|
||||||
attrs: {
|
attrs: {
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -64,13 +62,12 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.identifier'),
|
label: t('salesTicketsTable.identifier'),
|
||||||
name: 'identifier',
|
name: 'id',
|
||||||
field: 'id',
|
field: 'id',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
|
||||||
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'input',
|
component: 'number',
|
||||||
name: 'id',
|
name: 'id',
|
||||||
attrs: {
|
attrs: {
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -79,41 +76,41 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.client'),
|
label: t('salesTicketsTable.client'),
|
||||||
name: 'client',
|
name: 'clientFk',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'input',
|
component: 'select',
|
||||||
name: 'nickname',
|
|
||||||
attrs: {
|
attrs: {
|
||||||
dense: true,
|
url: 'Clients',
|
||||||
|
fields: ['id', 'name', 'nickname'],
|
||||||
|
sortBy: 'name ASC',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.salesPerson'),
|
label: t('salesTicketsTable.salesPerson'),
|
||||||
name: 'salesPerson',
|
name: 'salesPersonFk',
|
||||||
field: 'userName',
|
field: 'userName',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
optionFilter: 'firstName',
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'select',
|
component: 'select',
|
||||||
name: 'salesPersonFk',
|
|
||||||
attrs: {
|
attrs: {
|
||||||
options: workersActiveOptions.value,
|
url: 'Workers/activeWithInheritedRole',
|
||||||
'option-value': 'id',
|
fields: ['id', 'name'],
|
||||||
'option-label': 'name',
|
sortBy: 'nickname ASC',
|
||||||
dense: true,
|
where: { role: 'salesPerson' },
|
||||||
|
useLike: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.date'),
|
label: t('salesTicketsTable.date'),
|
||||||
name: 'date',
|
name: 'shippedDate',
|
||||||
style: { 'max-width': '100px' },
|
style: { 'max-width': '100px' },
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'date',
|
component: 'date',
|
||||||
name: 'shippedDate',
|
name: 'shippedDate',
|
||||||
|
@ -124,61 +121,39 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.theoretical'),
|
label: t('salesTicketsTable.theoretical'),
|
||||||
name: 'theoretical',
|
name: 'theoreticalhour',
|
||||||
field: 'zoneLanding',
|
field: 'zoneLanding',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
format: (row) => row.theoreticalhour,
|
||||||
format: (val) => toTimeFormat(val),
|
columnFilter: false,
|
||||||
columnFilter: {
|
|
||||||
component: 'input',
|
|
||||||
name: 'theoreticalHour',
|
|
||||||
attrs: {
|
|
||||||
dense: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.practical'),
|
label: t('salesTicketsTable.practical'),
|
||||||
name: 'practical',
|
name: 'practicalHour',
|
||||||
field: 'practicalHour',
|
field: 'practicalHour',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
format: (row) => row.practicalHour,
|
||||||
columnFilter: {
|
columnFilter: false,
|
||||||
component: 'input',
|
|
||||||
name: 'practicalHour',
|
|
||||||
attrs: {
|
|
||||||
dense: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.preparation'),
|
label: t('salesTicketsTable.preparation'),
|
||||||
name: 'preparation',
|
name: 'preparationHour',
|
||||||
field: 'shipped',
|
field: 'shipped',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
format: (row) => row.preparationHour,
|
||||||
format: (val) => toTimeFormat(val),
|
columnFilter: false,
|
||||||
columnFilter: {
|
|
||||||
component: 'input',
|
|
||||||
name: 'shippedDate',
|
|
||||||
attrs: {
|
|
||||||
dense: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.province'),
|
label: t('salesTicketsTable.province'),
|
||||||
name: 'province',
|
name: 'provinceFk',
|
||||||
field: 'province',
|
field: 'province',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
style: { 'max-width': '100px' },
|
format: (row) => row.province,
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'select',
|
component: 'select',
|
||||||
name: 'provinceFk',
|
name: 'provinceFk',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: provincesOptions.value,
|
options: provinceOpts.value,
|
||||||
'option-value': 'id',
|
'option-value': 'id',
|
||||||
'option-label': 'name',
|
'option-label': 'name',
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -190,12 +165,11 @@ const columns = computed(() => [
|
||||||
name: 'state',
|
name: 'state',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
style: { 'max-width': '100px' },
|
style: { 'max-width': '100px' },
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'select',
|
component: 'select',
|
||||||
name: 'stateFk',
|
name: 'stateFk',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: statesOptions.value,
|
options: stateOpts.value,
|
||||||
'option-value': 'id',
|
'option-value': 'id',
|
||||||
'option-label': 'name',
|
'option-label': 'name',
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -207,10 +181,7 @@ const columns = computed(() => [
|
||||||
name: 'isFragile',
|
name: 'isFragile',
|
||||||
field: 'isFragile',
|
field: 'isFragile',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
columnFilter: false,
|
||||||
columnFilter: {
|
|
||||||
inWhere: true,
|
|
||||||
},
|
|
||||||
attrs: {
|
attrs: {
|
||||||
'checked-icon': 'local_bar',
|
'checked-icon': 'local_bar',
|
||||||
'unchecked-icon': 'local_bar',
|
'unchecked-icon': 'local_bar',
|
||||||
|
@ -220,14 +191,14 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.zone'),
|
label: t('salesTicketsTable.zone'),
|
||||||
name: 'zone',
|
name: 'zoneFk',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'select',
|
component: 'select',
|
||||||
name: 'zoneFk',
|
name: 'zoneFk',
|
||||||
attrs: {
|
attrs: {
|
||||||
options: zonesOptions.value,
|
options: zoneOpts.value,
|
||||||
'option-value': 'id',
|
'option-value': 'id',
|
||||||
'option-label': 'name',
|
'option-label': 'name',
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -236,13 +207,13 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: t('salesTicketsTable.total'),
|
label: t('salesTicketsTable.total'),
|
||||||
name: 'total',
|
name: 'totalWithVat',
|
||||||
field: 'totalWithVat',
|
field: 'totalWithVat',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
style: { 'max-width': '75px' },
|
style: { 'max-width': '75px' },
|
||||||
sortable: true,
|
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: 'input',
|
component: 'number',
|
||||||
name: 'totalWithVat',
|
name: 'totalWithVat',
|
||||||
attrs: {
|
attrs: {
|
||||||
dense: true,
|
dense: true,
|
||||||
|
@ -258,7 +229,7 @@ const columns = computed(() => [
|
||||||
title: t('salesTicketsTable.goToLines'),
|
title: t('salesTicketsTable.goToLines'),
|
||||||
icon: 'vn:lines',
|
icon: 'vn:lines',
|
||||||
color: 'priamry',
|
color: 'priamry',
|
||||||
action: (row) => redirectToSales(row.id),
|
action: (row) => openTab(row.id),
|
||||||
isPrimary: true,
|
isPrimary: true,
|
||||||
attrs: {
|
attrs: {
|
||||||
flat: true,
|
flat: true,
|
||||||
|
@ -297,18 +268,13 @@ let refreshTimer = null;
|
||||||
|
|
||||||
const autoRefreshHandler = (value) => {
|
const autoRefreshHandler = (value) => {
|
||||||
if (value)
|
if (value)
|
||||||
refreshTimer = setInterval(() => paginateRef.value.fetch(), DEFAULT_AUTO_REFRESH);
|
refreshTimer = setInterval(() => tableRef.value.reload(), DEFAULT_AUTO_REFRESH);
|
||||||
else {
|
else {
|
||||||
clearInterval(refreshTimer);
|
clearInterval(refreshTimer);
|
||||||
refreshTimer = null;
|
refreshTimer = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectToTicketSummary = (id) => {
|
|
||||||
const url = `#/ticket/${id}/summary`;
|
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
|
||||||
|
|
||||||
const stateColors = {
|
const stateColors = {
|
||||||
notice: 'info',
|
notice: 'info',
|
||||||
success: 'positive',
|
success: 'positive',
|
||||||
|
@ -329,23 +295,10 @@ const formatShippedDate = (date) => {
|
||||||
return toDateFormat(_date);
|
return toDateFormat(_date);
|
||||||
};
|
};
|
||||||
|
|
||||||
const redirectToSales = (id) => {
|
const openTab = (id) =>
|
||||||
const url = `#/ticket/${id}/sale`;
|
window.open(`#/ticket/${id}/sale`, '_blank', 'noopener, noreferrer');
|
||||||
window.open(url, '_blank');
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
|
||||||
url="Workers/activeWithInheritedRole"
|
|
||||||
:filter="{
|
|
||||||
fields: ['id', 'nickname'],
|
|
||||||
order: 'nickname ASC',
|
|
||||||
where: { role: 'salesPerson' },
|
|
||||||
}"
|
|
||||||
auto-load
|
|
||||||
@on-fetch="(data) => (workersActiveOptions = data)"
|
|
||||||
/>
|
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Provinces"
|
url="Provinces"
|
||||||
:filter="{
|
:filter="{
|
||||||
|
@ -353,7 +306,7 @@ const redirectToSales = (id) => {
|
||||||
order: 'name ASC',
|
order: 'name ASC',
|
||||||
}"
|
}"
|
||||||
auto-load
|
auto-load
|
||||||
@on-fetch="(data) => (provincesOptions = data)"
|
@on-fetch="(data) => (provinceOpts = data)"
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="States"
|
url="States"
|
||||||
|
@ -362,7 +315,7 @@ const redirectToSales = (id) => {
|
||||||
order: 'name ASC',
|
order: 'name ASC',
|
||||||
}"
|
}"
|
||||||
auto-load
|
auto-load
|
||||||
@on-fetch="(data) => (statesOptions = data)"
|
@on-fetch="(data) => (stateOpts = data)"
|
||||||
/>
|
/>
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Zones"
|
url="Zones"
|
||||||
|
@ -371,46 +324,60 @@ const redirectToSales = (id) => {
|
||||||
order: 'name ASC',
|
order: 'name ASC',
|
||||||
}"
|
}"
|
||||||
auto-load
|
auto-load
|
||||||
@on-fetch="(data) => (zonesOptions = data)"
|
@on-fetch="(data) => (zoneOpts = data)"
|
||||||
/>
|
/>
|
||||||
|
<MonitorTicketSearchbar />
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<MonitorTicketFilter data-key="saleMonitorTickets" />
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
<VnTable
|
<VnTable
|
||||||
ref="paginateRef"
|
ref="tableRef"
|
||||||
data-key="SalesMonitorTickets"
|
data-key="saleMonitorTickets"
|
||||||
url="SalesMonitors/salesFilter"
|
url="SalesMonitors/salesFilter"
|
||||||
:filter="filter"
|
search-url="saleMonitorTickets"
|
||||||
:limit="20"
|
|
||||||
:expr-builder="exprBuilder"
|
:expr-builder="exprBuilder"
|
||||||
:user-params="params"
|
|
||||||
:offset="50"
|
:offset="50"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:visible-columns="visibleColumns"
|
:visible-columns="visibleColumns"
|
||||||
:right-search="false"
|
:right-search="false"
|
||||||
default-mode="table"
|
default-mode="table"
|
||||||
auto-load
|
auto-load
|
||||||
@row-click="(_, row) => redirectToTicketSummary(row.id)"
|
:row-click="({ id }) => openTab(id)"
|
||||||
|
:disable-option="{ card: true }"
|
||||||
|
:user-params="{ from, to, scopeDays: 1 }"
|
||||||
>
|
>
|
||||||
<template #top-left>
|
<template #top-left>
|
||||||
<TableVisibleColumns
|
<QBtn
|
||||||
:all-columns="allColumnNames"
|
icon="refresh"
|
||||||
table-code="ticketsMonitor"
|
size="md"
|
||||||
labels-traductions-path="salesTicketsTable"
|
color="primary"
|
||||||
@on-config-saved="visibleColumns = [...$event, 'rowActions']"
|
class="q-mr-sm"
|
||||||
/>
|
dense
|
||||||
|
flat
|
||||||
|
@click="$refs.tableRef.reload()"
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('globals.refresh') }}</QTooltip>
|
||||||
|
</QBtn>
|
||||||
<QCheckbox
|
<QCheckbox
|
||||||
v-model="autoRefresh"
|
v-model="autoRefresh"
|
||||||
:label="t('salesTicketsTable.autoRefresh')"
|
:label="$t('salesTicketsTable.autoRefresh')"
|
||||||
@update:model-value="autoRefreshHandler"
|
@update:model-value="autoRefreshHandler"
|
||||||
/>
|
dense
|
||||||
|
>
|
||||||
|
<QTooltip>{{ $t('refreshInfo') }}</QTooltip>
|
||||||
|
</QCheckbox>
|
||||||
</template>
|
</template>
|
||||||
<template #column-problems="{ row }">
|
<template #column-totalProblems="{ row }">
|
||||||
<QTd class="no-padding" style="max-width: 50px">
|
<QTd class="no-padding" style="max-width: 60px">
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.isTaxDataChecked === 0"
|
v-if="row.isTaxDataChecked === 0"
|
||||||
name="vn:no036"
|
name="vn:no036"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.noVerifiedData') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.hasTicketRequest"
|
v-if="row.hasTicketRequest"
|
||||||
|
@ -418,7 +385,7 @@ const redirectToSales = (id) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.purchaseRequest') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.itemShortage"
|
v-if="row.itemShortage"
|
||||||
|
@ -426,10 +393,10 @@ const redirectToSales = (id) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.notVisible') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.notVisible') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon v-if="row.isFreezed" name="vn:frozen" color="primary" size="xs">
|
<QIcon v-if="row.isFreezed" name="vn:frozen" color="primary" size="xs">
|
||||||
<QTooltip>{{ t('salesTicketsTable.clientFrozen') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.clientFrozen') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.risk"
|
v-if="row.risk"
|
||||||
|
@ -437,7 +404,9 @@ const redirectToSales = (id) => {
|
||||||
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
:color="row.hasHighRisk ? 'negative' : 'primary'"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.risk') }}: {{ row.risk }}</QTooltip>
|
<QTooltip
|
||||||
|
>{{ $t('salesTicketsTable.risk') }}: {{ row.risk }}</QTooltip
|
||||||
|
>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.hasComponentLack"
|
v-if="row.hasComponentLack"
|
||||||
|
@ -445,7 +414,7 @@ const redirectToSales = (id) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.componentLack') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.componentLack') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
<QIcon
|
<QIcon
|
||||||
v-if="row.isTooLittle"
|
v-if="row.isTooLittle"
|
||||||
|
@ -453,11 +422,11 @@ const redirectToSales = (id) => {
|
||||||
color="primary"
|
color="primary"
|
||||||
size="xs"
|
size="xs"
|
||||||
>
|
>
|
||||||
<QTooltip>{{ t('salesTicketsTable.tooLittle') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.tooLittle') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-identifier="{ row }">
|
<template #column-id="{ row }">
|
||||||
<QTd class="no-padding">
|
<QTd class="no-padding">
|
||||||
<span class="link" @click.stop.prevent>
|
<span class="link" @click.stop.prevent>
|
||||||
{{ row.id }}
|
{{ row.id }}
|
||||||
|
@ -465,19 +434,19 @@ const redirectToSales = (id) => {
|
||||||
</span>
|
</span>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-client="{ row }">
|
<template #column-clientFk="{ row }">
|
||||||
<QTd class="no-padding" @click.stop.prevent>
|
<QTd class="no-padding" @click.stop :title="row.nickname">
|
||||||
<span class="link">{{ row.nickname }}</span>
|
<span class="link">{{ row.nickname }}</span>
|
||||||
<CustomerDescriptorProxy :id="row.clientFk" />
|
<CustomerDescriptorProxy :id="row.clientFk" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-salesPerson="{ row }">
|
<template #column-salesPersonFk="{ row }">
|
||||||
<QTd class="no-padding" @click.stop.prevent>
|
<QTd class="no-padding" @click.stop :title="row.userName">
|
||||||
<span class="link">{{ row.userName }}</span>
|
<span class="link" v-text="dashIfEmpty(row.userName)" />
|
||||||
<WorkerDescriptorProxy :id="row.salesPersonFk" />
|
<WorkerDescriptorProxy :id="row.salesPersonFk" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-date="{ row }">
|
<template #column-shippedDate="{ row }">
|
||||||
<QTd class="no-padding">
|
<QTd class="no-padding">
|
||||||
<QBadge
|
<QBadge
|
||||||
v-bind="getBadgeAttrs(row.shippedDate)"
|
v-bind="getBadgeAttrs(row.shippedDate)"
|
||||||
|
@ -488,6 +457,11 @@ const redirectToSales = (id) => {
|
||||||
</QBadge>
|
</QBadge>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
|
<template #column-provinceFk="{ row }">
|
||||||
|
<QTd class="no-padding">
|
||||||
|
<span :title="row.province" v-text="row.province" />
|
||||||
|
</QTd>
|
||||||
|
</template>
|
||||||
<template #column-state="{ row }">
|
<template #column-state="{ row }">
|
||||||
<QTd class="no-padding" @click.stop.prevent>
|
<QTd class="no-padding" @click.stop.prevent>
|
||||||
<div v-if="row.refFk">
|
<div v-if="row.refFk">
|
||||||
|
@ -508,17 +482,17 @@ const redirectToSales = (id) => {
|
||||||
<template #column-isFragile="{ row }">
|
<template #column-isFragile="{ row }">
|
||||||
<QTd class="no-padding">
|
<QTd class="no-padding">
|
||||||
<QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm">
|
<QIcon v-if="row.isFragile" name="local_bar" color="primary" size="sm">
|
||||||
<QTooltip>{{ t('salesTicketsTable.isFragile') }}</QTooltip>
|
<QTooltip>{{ $t('salesTicketsTable.isFragile') }}</QTooltip>
|
||||||
</QIcon>
|
</QIcon>
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-zone="{ row }">
|
<template #column-zoneFk="{ row }">
|
||||||
<QTd class="no-padding" @click.stop.prevent>
|
<QTd class="no-padding" @click.stop.prevent :title="row.zoneName">
|
||||||
<span class="link">{{ row.zoneName }}</span>
|
<span class="link">{{ row.zoneName }}</span>
|
||||||
<ZoneDescriptorProxy :id="row.zoneFk" />
|
<ZoneDescriptorProxy :id="row.zoneFk" />
|
||||||
</QTd>
|
</QTd>
|
||||||
</template>
|
</template>
|
||||||
<template #column-total="{ row }">
|
<template #column-totalWithVat="{ row }">
|
||||||
<QTd class="no-padding">
|
<QTd class="no-padding">
|
||||||
<QBadge
|
<QBadge
|
||||||
:color="totalPriceColor(row) || 'transparent'"
|
:color="totalPriceColor(row) || 'transparent'"
|
|
@ -11,11 +11,14 @@ salesClientsTable:
|
||||||
client: Client
|
client: Client
|
||||||
salesOrdersTable:
|
salesOrdersTable:
|
||||||
delete: Delete
|
delete: Delete
|
||||||
date: Date
|
dateSend: Send date
|
||||||
|
dateMake: Make date
|
||||||
client: Client
|
client: Client
|
||||||
salesPerson: Salesperson
|
salesPerson: Salesperson
|
||||||
deleteConfirmTitle: Delete selected elements
|
deleteConfirmTitle: Delete selected elements
|
||||||
deleteConfirmMessage: All the selected elements will be deleted. Are you sure you want to continue?
|
deleteConfirmMessage: All the selected elements will be deleted. Are you sure you want to continue?
|
||||||
|
agency: Agency
|
||||||
|
import: Import
|
||||||
salesTicketsTable:
|
salesTicketsTable:
|
||||||
autoRefresh: Auto-refresh
|
autoRefresh: Auto-refresh
|
||||||
problems: Problems
|
problems: Problems
|
||||||
|
@ -43,3 +46,4 @@ salesTicketsTable:
|
||||||
searchBar:
|
searchBar:
|
||||||
label: Search tickets
|
label: Search tickets
|
||||||
info: Search tickets by id or alias
|
info: Search tickets by id or alias
|
||||||
|
refreshInfo: Toggle auto-refresh every 2 minutes
|
||||||
|
|
|
@ -11,11 +11,14 @@ salesClientsTable:
|
||||||
client: Cliente
|
client: Cliente
|
||||||
salesOrdersTable:
|
salesOrdersTable:
|
||||||
delete: Eliminar
|
delete: Eliminar
|
||||||
date: Fecha
|
dateSend: Fecha de envío
|
||||||
|
dateMake: Fecha de realización
|
||||||
client: Cliente
|
client: Cliente
|
||||||
salesPerson: Comercial
|
salesPerson: Comercial
|
||||||
deleteConfirmTitle: Eliminar los elementos seleccionados
|
deleteConfirmTitle: Eliminar los elementos seleccionados
|
||||||
deleteConfirmMessage: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
|
deleteConfirmMessage: Todos los elementos seleccionados serán eliminados. ¿Seguro que quieres continuar?
|
||||||
|
agency: Agencia
|
||||||
|
import: Importe
|
||||||
salesTicketsTable:
|
salesTicketsTable:
|
||||||
autoRefresh: Auto-refresco
|
autoRefresh: Auto-refresco
|
||||||
problems: Problemas
|
problems: Problemas
|
||||||
|
@ -43,3 +46,4 @@ salesTicketsTable:
|
||||||
searchBar:
|
searchBar:
|
||||||
label: Buscar tickets
|
label: Buscar tickets
|
||||||
info: Buscar tickets por identificador o alias
|
info: Buscar tickets por identificador o alias
|
||||||
|
refreshInfo: Conmuta el refresco automático cada 2 minutos
|
||||||
|
|
|
@ -10,7 +10,7 @@ const { t } = useI18n();
|
||||||
data-key="OrderList"
|
data-key="OrderList"
|
||||||
url="Orders/filter"
|
url="Orders/filter"
|
||||||
:label="t('Search order')"
|
:label="t('Search order')"
|
||||||
:info="t('You can search orders by reference')"
|
:info="t('Search orders by ticket id')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -18,5 +18,5 @@ const { t } = useI18n();
|
||||||
<i18n>
|
<i18n>
|
||||||
es:
|
es:
|
||||||
Search order: Buscar orden
|
Search order: Buscar orden
|
||||||
You can search orders by reference: Puedes buscar por referencia de la orden
|
Search orders by ticket id: Buscar pedido por id ticket
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
|
@ -185,7 +185,7 @@ const columns = computed(() => [
|
||||||
action: (row) => openTicketsDialog(row?.id),
|
action: (row) => openTicketsDialog(row?.id),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Preview'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row?.id, RouteSummary),
|
action: (row) => viewSummary(row?.id, RouteSummary),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import FetchData from 'components/FetchData.vue';
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
@ -11,8 +11,8 @@ import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const shelvingId = route.params?.id || null;
|
const entityId = computed(() => route.params.id ?? null);
|
||||||
const isNew = Boolean(!shelvingId);
|
const isNew = Boolean(!entityId.value);
|
||||||
const defaultInitialData = {
|
const defaultInitialData = {
|
||||||
parkingFk: null,
|
parkingFk: null,
|
||||||
priority: null,
|
priority: null,
|
||||||
|
@ -67,7 +67,7 @@ const onSave = (shelving, newShelving) => {
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnSubToolbar />
|
<VnSubToolbar v-if="isNew" />
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Parkings"
|
url="Parkings"
|
||||||
:filter="parkingFilter"
|
:filter="parkingFilter"
|
||||||
|
@ -75,13 +75,13 @@ const onSave = (shelving, newShelving) => {
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FormModel
|
<FormModel
|
||||||
:url="isNew ? null : `Shelvings/${shelvingId}`"
|
:url="isNew ? null : `Shelvings/${entityId}`"
|
||||||
:url-create="isNew ? 'Shelvings' : null"
|
:url-create="isNew ? 'Shelvings' : null"
|
||||||
:observe-form-changes="!isNew"
|
:observe-form-changes="!isNew"
|
||||||
:filter="shelvingFilter"
|
:filter="shelvingFilter"
|
||||||
model="shelving"
|
model="shelving"
|
||||||
:auto-load="!isNew"
|
:auto-load="!isNew"
|
||||||
:form-initial-data="defaultInitialData"
|
:form-initial-data="isNew ? defaultInitialData : null"
|
||||||
@on-data-saved="onSave"
|
@on-data-saved="onSave"
|
||||||
>
|
>
|
||||||
<template #form="{ data, validate, filter }">
|
<template #form="{ data, validate, filter }">
|
||||||
|
|
|
@ -30,10 +30,12 @@ const actions = {
|
||||||
let clonedTicketId;
|
let clonedTicketId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data } = await axios.post(`Tickets/${ticketId}/clone`, {
|
const { data } = await axios.post(`Tickets/cloneAll`, {
|
||||||
shipped: ticket.value.shipped,
|
ticketsIds: [ticket.value.id],
|
||||||
|
withWarehouse: true,
|
||||||
|
negative: false,
|
||||||
});
|
});
|
||||||
clonedTicketId = data;
|
clonedTicketId = data[0].id;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
opts.message = t('It was not able to clone the ticket');
|
opts.message = t('It was not able to clone the ticket');
|
||||||
opts.type = 'negative';
|
opts.type = 'negative';
|
||||||
|
|
|
@ -268,7 +268,6 @@ onMounted(async () => {
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
const filteredColumns = columns.value.filter((col) => col.name !== 'history');
|
||||||
allColumnNames.value = filteredColumns.map((col) => col.name);
|
allColumnNames.value = filteredColumns.map((col) => col.name);
|
||||||
// await expeditionsArrayData.fetch({ append: false });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => (stateStore.rightDrawer = false));
|
onUnmounted(() => (stateStore.rightDrawer = false));
|
||||||
|
|
|
@ -131,7 +131,11 @@ const createClaim = () => {
|
||||||
onCreateClaimAccepted
|
onCreateClaimAccepted
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
openConfirmationModal(t('Do you want to create a claim?'), onCreateClaimAccepted);
|
openConfirmationModal(
|
||||||
|
t('Do you want to create a claim?'),
|
||||||
|
false,
|
||||||
|
onCreateClaimAccepted
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCreateClaimAccepted = async () => {
|
const onCreateClaimAccepted = async () => {
|
||||||
|
@ -153,14 +157,22 @@ const setReserved = async (reserved) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const createRefund = async (withWarehouse) => {
|
const createRefund = async (withWarehouse) => {
|
||||||
if (!props.sales) return;
|
if (!props.ticket) return;
|
||||||
|
|
||||||
const salesIds = props.sales.map((sale) => sale.id);
|
const params = {
|
||||||
const params = { salesIds: salesIds, withWarehouse: withWarehouse, negative: true };
|
ticketsIds: [props.ticket.id],
|
||||||
const { data } = await axios.post('Sales/clone', params);
|
withWarehouse: withWarehouse,
|
||||||
const [refundTicket] = data;
|
negative: true,
|
||||||
notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
|
};
|
||||||
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
|
||||||
|
try {
|
||||||
|
const { data } = await axios.post('Tickets/cloneAll', params);
|
||||||
|
const [refundTicket] = data;
|
||||||
|
notify(t('refundTicketCreated', { ticketId: refundTicket.id }), 'positive');
|
||||||
|
router.push({ name: 'TicketSale', params: { id: refundTicket.id } });
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -244,7 +256,7 @@ const createRefund = async (withWarehouse) => {
|
||||||
</QItem>
|
</QItem>
|
||||||
<QItem clickable v-ripple>
|
<QItem clickable v-ripple>
|
||||||
<QItemSection>
|
<QItemSection>
|
||||||
<QItemLabel>{{ t('Refund...') }}</QItemLabel>
|
<QItemLabel>{{ t('Refund') }}</QItemLabel>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
<QItemSection side>
|
<QItemSection side>
|
||||||
<QIcon name="keyboard_arrow_right" />
|
<QIcon name="keyboard_arrow_right" />
|
||||||
|
@ -279,7 +291,7 @@ es:
|
||||||
Add claim: Crear reclamación
|
Add claim: Crear reclamación
|
||||||
Mark as reserved: Marcar como reservado
|
Mark as reserved: Marcar como reservado
|
||||||
Unmark as reserved: Desmarcar como reservado
|
Unmark as reserved: Desmarcar como reservado
|
||||||
Refund...: Abono...
|
Refund: Abono
|
||||||
with warehouse: con almacén
|
with warehouse: con almacén
|
||||||
without warehouse: sin almacén
|
without warehouse: sin almacén
|
||||||
Claim out of time: Reclamación fuera de plazo
|
Claim out of time: Reclamación fuera de plazo
|
||||||
|
|
|
@ -82,7 +82,9 @@ const openCreateModal = () => createTrackingDialogRef.value.show();
|
||||||
data-key="TicketTracking"
|
data-key="TicketTracking"
|
||||||
:filter="paginateFilter"
|
:filter="paginateFilter"
|
||||||
url="TicketTrackings"
|
url="TicketTrackings"
|
||||||
auto-load
|
auto-load
|
||||||
|
order="created DESC"
|
||||||
|
:limit="0"
|
||||||
>
|
>
|
||||||
<template #body="{ rows }">
|
<template #body="{ rows }">
|
||||||
<QTable
|
<QTable
|
||||||
|
|
|
@ -448,7 +448,7 @@ const handleCloseProgressDialog = () => {
|
||||||
const handleCancelProgress = () => (cancelProgress.value = true);
|
const handleCancelProgress = () => (cancelProgress.value = true);
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
let today = Date.vnNew();
|
let today = Date.vnNew().toISOString();
|
||||||
const tomorrow = new Date(today);
|
const tomorrow = new Date(today);
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
||||||
userParams.dateFuture = tomorrow;
|
userParams.dateFuture = tomorrow;
|
||||||
|
|
|
@ -55,7 +55,7 @@ onMounted(async () => await getItemPackingTypes());
|
||||||
:data-key="props.dataKey"
|
:data-key="props.dataKey"
|
||||||
:search-button="true"
|
:search-button="true"
|
||||||
:hidden-tags="['search']"
|
:hidden-tags="['search']"
|
||||||
:unremovable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
|
:un-removable-params="['warehouseFk', 'dateFuture', 'dateToAdvance']"
|
||||||
>
|
>
|
||||||
<template #tags="{ tag, formatFn }">
|
<template #tags="{ tag, formatFn }">
|
||||||
<div class="q-gutter-x-xs">
|
<div class="q-gutter-x-xs">
|
||||||
|
@ -70,7 +70,6 @@ onMounted(async () => await getItemPackingTypes());
|
||||||
v-model="params.dateFuture"
|
v-model="params.dateFuture"
|
||||||
:label="t('params.dateFuture')"
|
:label="t('params.dateFuture')"
|
||||||
is-outlined
|
is-outlined
|
||||||
@update:model-value="searchFn()"
|
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
@ -80,7 +79,6 @@ onMounted(async () => await getItemPackingTypes());
|
||||||
v-model="params.dateToAdvance"
|
v-model="params.dateToAdvance"
|
||||||
:label="t('params.dateToAdvance')"
|
:label="t('params.dateToAdvance')"
|
||||||
is-outlined
|
is-outlined
|
||||||
@update:model-value="searchFn()"
|
|
||||||
/>
|
/>
|
||||||
</QItemSection>
|
</QItemSection>
|
||||||
</QItem>
|
</QItem>
|
||||||
|
|
|
@ -8,6 +8,8 @@ import VnSelect from 'src/components/common/VnSelect.vue';
|
||||||
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
import TicketDescriptorProxy from 'src/pages/Ticket/Card/TicketDescriptorProxy.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
|
import TicketFutureFilter from './TicketFutureFilter.vue';
|
||||||
|
|
||||||
import { dashIfEmpty, toCurrency } from 'src/filters';
|
import { dashIfEmpty, toCurrency } from 'src/filters';
|
||||||
import { useVnConfirm } from 'composables/useVnConfirm';
|
import { useVnConfirm } from 'composables/useVnConfirm';
|
||||||
|
@ -37,9 +39,9 @@ const exprBuilder = (param, value) => {
|
||||||
return { liters: value };
|
return { liters: value };
|
||||||
case 'lines':
|
case 'lines':
|
||||||
return { lines: value };
|
return { lines: value };
|
||||||
case 'ipt':
|
case 'iptColFilter':
|
||||||
return { ipt: { like: `%${value}%` } };
|
return { ipt: { like: `%${value}%` } };
|
||||||
case 'futureIpt':
|
case 'futureIptColFilter':
|
||||||
return { futureIpt: { like: `%${value}%` } };
|
return { futureIpt: { like: `%${value}%` } };
|
||||||
case 'totalWithVat':
|
case 'totalWithVat':
|
||||||
return { totalWithVat: value };
|
return { totalWithVat: value };
|
||||||
|
@ -47,8 +49,8 @@ const exprBuilder = (param, value) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const userParams = reactive({
|
const userParams = reactive({
|
||||||
futureDated: Date.vnNew(),
|
futureDated: Date.vnNew().toISOString(),
|
||||||
originDated: Date.vnNew(),
|
originDated: Date.vnNew().toISOString(),
|
||||||
warehouseFk: user.value.warehouseFk,
|
warehouseFk: user.value.warehouseFk,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -83,6 +85,8 @@ const getInputEvents = (col) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const tickets = computed(() => store.data);
|
||||||
|
|
||||||
const ticketColumns = computed(() => [
|
const ticketColumns = computed(() => [
|
||||||
{
|
{
|
||||||
label: t('futureTickets.problems'),
|
label: t('futureTickets.problems'),
|
||||||
|
@ -121,7 +125,7 @@ const ticketColumns = computed(() => [
|
||||||
sortable: true,
|
sortable: true,
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: VnSelect,
|
component: VnSelect,
|
||||||
filterParamKey: 'ipt',
|
filterParamKey: 'iptColFilter',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
filterValue: null,
|
filterValue: null,
|
||||||
event: getInputEvents,
|
event: getInputEvents,
|
||||||
|
@ -214,7 +218,7 @@ const ticketColumns = computed(() => [
|
||||||
sortable: true,
|
sortable: true,
|
||||||
columnFilter: {
|
columnFilter: {
|
||||||
component: VnSelect,
|
component: VnSelect,
|
||||||
filterParamKey: 'futureIpt',
|
filterParamKey: 'futureIptColFilter',
|
||||||
type: 'select',
|
type: 'select',
|
||||||
filterValue: null,
|
filterValue: null,
|
||||||
event: getInputEvents,
|
event: getInputEvents,
|
||||||
|
@ -305,9 +309,14 @@ onMounted(async () => {
|
||||||
</QBtn>
|
</QBtn>
|
||||||
</template>
|
</template>
|
||||||
</VnSubToolbar>
|
</VnSubToolbar>
|
||||||
|
<RightMenu>
|
||||||
|
<template #right-panel>
|
||||||
|
<TicketFutureFilter data-key="FutureTickets" />
|
||||||
|
</template>
|
||||||
|
</RightMenu>
|
||||||
<QPage class="column items-center q-pa-md">
|
<QPage class="column items-center q-pa-md">
|
||||||
<QTable
|
<QTable
|
||||||
:rows="store.data"
|
:rows="tickets"
|
||||||
:columns="ticketColumns"
|
:columns="ticketColumns"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
selection="multiple"
|
selection="multiple"
|
||||||
|
|
|
@ -0,0 +1,242 @@
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
import FetchData from 'components/FetchData.vue';
|
||||||
|
import VnFilterPanel from 'src/components/ui/VnFilterPanel.vue';
|
||||||
|
import VnSelect from 'components/common/VnSelect.vue';
|
||||||
|
import VnInputDate from 'src/components/common/VnInputDate.vue';
|
||||||
|
import VnInput from 'src/components/common/VnInput.vue';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { onMounted } from 'vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const props = defineProps({
|
||||||
|
dataKey: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const warehousesOptions = ref([]);
|
||||||
|
const itemPackingTypes = ref([]);
|
||||||
|
const stateOptions = ref([]);
|
||||||
|
|
||||||
|
const getItemPackingTypes = async () => {
|
||||||
|
try {
|
||||||
|
const filter = {
|
||||||
|
where: { isActive: true },
|
||||||
|
};
|
||||||
|
const { data } = await axios.get('ItemPackingTypes', {
|
||||||
|
params: { filter: JSON.stringify(filter) },
|
||||||
|
});
|
||||||
|
itemPackingTypes.value = data.map((ipt) => ({
|
||||||
|
description: t(ipt.description),
|
||||||
|
code: ipt.code,
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getGroupedStates = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await axios.get('AlertLevels');
|
||||||
|
stateOptions.value = data.map((state) => ({
|
||||||
|
id: state.id,
|
||||||
|
name: t(`futureTickets.${state.code}`),
|
||||||
|
code: state.code,
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
getItemPackingTypes();
|
||||||
|
getGroupedStates();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<FetchData
|
||||||
|
url="Warehouses"
|
||||||
|
@on-fetch="(data) => (warehousesOptions = data)"
|
||||||
|
auto-load
|
||||||
|
/>
|
||||||
|
<VnFilterPanel
|
||||||
|
:data-key="props.dataKey"
|
||||||
|
:hidden-tags="['search']"
|
||||||
|
:un-removable-params="['warehouseFk', 'originDated', 'futureDated']"
|
||||||
|
>
|
||||||
|
<template #tags="{ tag, formatFn }">
|
||||||
|
<div class="q-gutter-x-xs">
|
||||||
|
<strong>{{ t(`params.${tag.label}`) }}: </strong>
|
||||||
|
<span>{{ formatFn(tag.value) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #body="{ params, searchFn }">
|
||||||
|
<QItem class="q-my-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.originDated"
|
||||||
|
:label="t('params.originDated')"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-my-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnInputDate
|
||||||
|
v-model="params.futureDated"
|
||||||
|
:label="t('params.futureDated')"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-my-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.litersMax')"
|
||||||
|
v-model="params.litersMax"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem class="q-my-sm">
|
||||||
|
<QItemSection>
|
||||||
|
<VnInput
|
||||||
|
:label="t('params.linesMax')"
|
||||||
|
v-model="params.linesMax"
|
||||||
|
is-outlined
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('params.ipt')"
|
||||||
|
v-model="params.ipt"
|
||||||
|
:options="itemPackingTypes"
|
||||||
|
option-value="code"
|
||||||
|
option-label="description"
|
||||||
|
:info="t('iptInfo')"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('params.futureIpt')"
|
||||||
|
v-model="params.futureIpt"
|
||||||
|
:options="itemPackingTypes"
|
||||||
|
option-value="code"
|
||||||
|
option-label="description"
|
||||||
|
:info="t('iptInfo')"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('params.state')"
|
||||||
|
v-model="params.state"
|
||||||
|
:options="stateOptions"
|
||||||
|
option-value="code"
|
||||||
|
option-label="name"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('params.futureState')"
|
||||||
|
v-model="params.futureState"
|
||||||
|
:options="stateOptions"
|
||||||
|
option-value="code"
|
||||||
|
option-label="name"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<QCheckbox
|
||||||
|
:label="t('params.problems')"
|
||||||
|
v-model="params.problems"
|
||||||
|
:toggle-indeterminate="false"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
/>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
<QItem>
|
||||||
|
<QItemSection>
|
||||||
|
<VnSelect
|
||||||
|
:label="t('params.warehouseFk')"
|
||||||
|
v-model="params.warehouseFk"
|
||||||
|
:options="warehousesOptions"
|
||||||
|
option-value="id"
|
||||||
|
option-label="name"
|
||||||
|
@update:model-value="searchFn()"
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
rounded
|
||||||
|
>
|
||||||
|
</VnSelect>
|
||||||
|
</QItemSection>
|
||||||
|
</QItem>
|
||||||
|
</template>
|
||||||
|
</VnFilterPanel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<i18n>
|
||||||
|
en:
|
||||||
|
iptInfo: IPT
|
||||||
|
params:
|
||||||
|
originDated: Origin date
|
||||||
|
futureDated: Destination date
|
||||||
|
futureIpt: Destination IPT
|
||||||
|
ipt: Origin IPT
|
||||||
|
warehouseFk: Warehouse
|
||||||
|
litersMax: Max liters
|
||||||
|
linesMax: Max lines
|
||||||
|
state: Origin grouped state
|
||||||
|
futureState: Destination grouped state
|
||||||
|
problems: With problems
|
||||||
|
es:
|
||||||
|
Horizontal: Horizontal
|
||||||
|
Vertical: Vertical
|
||||||
|
iptInfo: Encajado
|
||||||
|
params:
|
||||||
|
originDated: Fecha origen
|
||||||
|
futureDated: Fecha destino
|
||||||
|
futureIpt: IPT destino
|
||||||
|
ipt: IPT Origen
|
||||||
|
warehouseFk: Almacén
|
||||||
|
litersMax: Litros máx.
|
||||||
|
linesMax: Líneas máx.
|
||||||
|
state: Estado agrupado origen
|
||||||
|
futureState: Estado agrupado destino
|
||||||
|
problems: Con problemas
|
||||||
|
</i18n>
|
|
@ -93,6 +93,11 @@ futureTickets:
|
||||||
moveTicketSuccess: Tickets moved successfully!
|
moveTicketSuccess: Tickets moved successfully!
|
||||||
searchInfo: Search future tickets by date
|
searchInfo: Search future tickets by date
|
||||||
futureTicket: Future tickets
|
futureTicket: Future tickets
|
||||||
|
FREE: Free
|
||||||
|
ON_PREVIOUS: ON_PREVIOUS
|
||||||
|
ON_PREPARATION: On preparation
|
||||||
|
PACKED: Packed
|
||||||
|
DELIVERED: Delivered
|
||||||
expedition:
|
expedition:
|
||||||
id: Expedition
|
id: Expedition
|
||||||
item: Item
|
item: Item
|
||||||
|
|
|
@ -140,6 +140,11 @@ futureTickets:
|
||||||
moveTicketSuccess: Tickets movidos correctamente
|
moveTicketSuccess: Tickets movidos correctamente
|
||||||
searchInfo: Buscar tickets por fecha
|
searchInfo: Buscar tickets por fecha
|
||||||
futureTicket: Tickets a futuro
|
futureTicket: Tickets a futuro
|
||||||
|
FREE: Libre
|
||||||
|
ON_PREVIOUS: ON_PREVIOUS
|
||||||
|
ON_PREPARATION: En preparación
|
||||||
|
PACKED: Encajado
|
||||||
|
DELIVERED: Servido
|
||||||
ticketSale:
|
ticketSale:
|
||||||
id: Id
|
id: Id
|
||||||
visible: Visible
|
visible: Visible
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { computed } from 'vue';
|
||||||
import TravelSummary from './Card/TravelSummary.vue';
|
import TravelSummary from './Card/TravelSummary.vue';
|
||||||
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'components/ui/VnSearchbar.vue';
|
||||||
import { toDate } from 'src/filters';
|
import { toDate } from 'src/filters';
|
||||||
|
import { getDateQBadgeColor } from 'src/composables/getDateQBadgeColor.js';
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -46,14 +47,12 @@ const columns = computed(() => [
|
||||||
name: 'id',
|
name: 'id',
|
||||||
label: t('travel.travelList.tableVisibleColumns.id'),
|
label: t('travel.travelList.tableVisibleColumns.id'),
|
||||||
isId: true,
|
isId: true,
|
||||||
field: 'id',
|
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'ref',
|
name: 'ref',
|
||||||
label: t('travel.travelList.tableVisibleColumns.ref'),
|
label: t('travel.travelList.tableVisibleColumns.ref'),
|
||||||
field: 'ref',
|
|
||||||
component: 'input',
|
component: 'input',
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
|
@ -65,7 +64,6 @@ const columns = computed(() => [
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'agencyModeFk',
|
name: 'agencyModeFk',
|
||||||
label: t('travel.travelList.tableVisibleColumns.agency'),
|
label: t('travel.travelList.tableVisibleColumns.agency'),
|
||||||
field: 'agencyModeFk',
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'agencyModes',
|
url: 'agencyModes',
|
||||||
|
@ -78,37 +76,10 @@ const columns = computed(() => [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
align: 'left',
|
|
||||||
name: 'shipped',
|
|
||||||
label: t('travel.travelList.tableVisibleColumns.shipped'),
|
|
||||||
field: 'shipped',
|
|
||||||
component: 'date',
|
|
||||||
columnField: {
|
|
||||||
component: null,
|
|
||||||
},
|
|
||||||
cardVisible: true,
|
|
||||||
create: true,
|
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
align: 'left',
|
|
||||||
name: 'landed',
|
|
||||||
label: t('travel.travelList.tableVisibleColumns.landed'),
|
|
||||||
field: 'landed',
|
|
||||||
component: 'date',
|
|
||||||
columnField: {
|
|
||||||
component: null,
|
|
||||||
},
|
|
||||||
cardVisible: true,
|
|
||||||
create: true,
|
|
||||||
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'warehouseInFk',
|
name: 'warehouseInFk',
|
||||||
label: t('travel.travelList.tableVisibleColumns.warehouseIn'),
|
label: t('travel.travelList.tableVisibleColumns.warehouseIn'),
|
||||||
field: 'warehouseInFk',
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'warehouses',
|
url: 'warehouses',
|
||||||
|
@ -123,11 +94,28 @@ const columns = computed(() => [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'shipped',
|
||||||
|
label: t('travel.travelList.tableVisibleColumns.shipped'),
|
||||||
|
component: 'date',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
cardVisible: true,
|
||||||
|
create: true,
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.shipped)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'shipmentHour',
|
||||||
|
label: t('travel.travelList.tableVisibleColumns.shipHour'),
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'warehouseOutFk',
|
name: 'warehouseOutFk',
|
||||||
label: t('travel.travelList.tableVisibleColumns.warehouseOut'),
|
label: t('travel.travelList.tableVisibleColumns.warehouseOut'),
|
||||||
field: 'warehouseOutFk',
|
|
||||||
component: 'select',
|
component: 'select',
|
||||||
attrs: {
|
attrs: {
|
||||||
url: 'warehouses',
|
url: 'warehouses',
|
||||||
|
@ -140,12 +128,30 @@ const columns = computed(() => [
|
||||||
cardVisible: true,
|
cardVisible: true,
|
||||||
create: true,
|
create: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'landed',
|
||||||
|
label: t('travel.travelList.tableVisibleColumns.landed'),
|
||||||
|
component: 'date',
|
||||||
|
columnField: {
|
||||||
|
component: null,
|
||||||
|
},
|
||||||
|
cardVisible: true,
|
||||||
|
create: true,
|
||||||
|
format: (row, dashIfEmpty) => dashIfEmpty(toDate(row.landed)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
align: 'left',
|
||||||
|
name: 'landingHour',
|
||||||
|
label: t('travel.travelList.tableVisibleColumns.landHour'),
|
||||||
|
cardVisible: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
name: 'totalEntries',
|
name: 'totalEntries',
|
||||||
label: t('travel.travelList.tableVisibleColumns.totalEntries'),
|
label: t('travel.travelList.tableVisibleColumns.totalEntries'),
|
||||||
field: 'totalEntries',
|
|
||||||
component: 'input',
|
component: 'input',
|
||||||
|
toolTip: t('travel.travelList.tableVisibleColumns.totalEntriesTooltip'),
|
||||||
columnField: {
|
columnField: {
|
||||||
component: null,
|
component: null,
|
||||||
},
|
},
|
||||||
|
@ -165,13 +171,15 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('Add entry'),
|
title: t('Add entry'),
|
||||||
icon: 'contact_support',
|
icon: 'vn:ticket',
|
||||||
action: redirectCreateEntryView,
|
action: redirectCreateEntryView,
|
||||||
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('View Summary'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, TravelSummary),
|
action: (row) => viewSummary(row.id, TravelSummary),
|
||||||
|
isPrimary: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -202,12 +210,43 @@ const columns = computed(() => [
|
||||||
redirect="travel"
|
redirect="travel"
|
||||||
:is-editable="false"
|
:is-editable="false"
|
||||||
:use-model="true"
|
:use-model="true"
|
||||||
/>
|
>
|
||||||
|
<template #column-shipped="{ row }">
|
||||||
|
<QBadge
|
||||||
|
text-color="black"
|
||||||
|
v-if="getDateQBadgeColor(row.shipped)"
|
||||||
|
:color="getDateQBadgeColor(row.shipped)"
|
||||||
|
>
|
||||||
|
{{ toDate(row.shipped) }}
|
||||||
|
</QBadge>
|
||||||
|
<span v-else>{{ toDate(row.shipped) }}</span>
|
||||||
|
<QIcon
|
||||||
|
name="flight_takeoff"
|
||||||
|
size="sm"
|
||||||
|
:class="{ 'is-active': row.isDelivered }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #column-landed="{ row }">
|
||||||
|
<QBadge
|
||||||
|
text-color="black"
|
||||||
|
v-if="getDateQBadgeColor(row.landed)"
|
||||||
|
:color="getDateQBadgeColor(row.landed)"
|
||||||
|
>
|
||||||
|
{{ toDate(row.landed) }}
|
||||||
|
</QBadge>
|
||||||
|
<span v-else>{{ toDate(row.landed) }}</span>
|
||||||
|
<QIcon
|
||||||
|
name="flight_land"
|
||||||
|
size="sm"
|
||||||
|
:class="{ 'is-active': row.isReceived }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</VnTable>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<i18n>
|
<i18n>
|
||||||
en:
|
en:
|
||||||
addEntry: Add entry
|
Add entry: Add entry
|
||||||
searchByIdOrReference: Search by ID or reference
|
searchByIdOrReference: Search by ID or reference
|
||||||
|
|
||||||
es:
|
es:
|
||||||
|
@ -215,4 +254,12 @@ es:
|
||||||
searchByIdOrReference: Buscar por ID o por referencia
|
searchByIdOrReference: Buscar por ID o por referencia
|
||||||
You can search by travel id or name: Buscar por envio por id o nombre
|
You can search by travel id or name: Buscar por envio por id o nombre
|
||||||
Search travel: Buscar envio
|
Search travel: Buscar envio
|
||||||
|
Clone: Clonar
|
||||||
|
Add entry: Añadir Entrada
|
||||||
</i18n>
|
</i18n>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.is-active {
|
||||||
|
color: #c8e484;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -152,7 +152,7 @@ const getEventAttrs = (timestamp) => {
|
||||||
|
|
||||||
if (isFestive) {
|
if (isFestive) {
|
||||||
attrs.class = '--festive';
|
attrs.class = '--festive';
|
||||||
attrs.label = event.absenceId ?? timestamp.day;
|
attrs.label = timestamp.day;
|
||||||
} else attrs.class = `--${type}`;
|
} else attrs.class = `--${type}`;
|
||||||
|
|
||||||
return attrs;
|
return attrs;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import useCardDescription from 'src/composables/useCardDescription';
|
||||||
import { useState } from 'src/composables/useState';
|
import { useState } from 'src/composables/useState';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import VnImg from 'src/components/ui/VnImg.vue';
|
import VnImg from 'src/components/ui/VnImg.vue';
|
||||||
|
import EditPictureForm from 'components/EditPictureForm.vue';
|
||||||
|
|
||||||
const $props = defineProps({
|
const $props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
@ -18,6 +19,7 @@ const $props = defineProps({
|
||||||
default: null,
|
default: null,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const image = ref(null);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -25,6 +27,10 @@ const state = useState();
|
||||||
const user = state.getUser();
|
const user = state.getUser();
|
||||||
const changePasswordFormDialog = ref(null);
|
const changePasswordFormDialog = ref(null);
|
||||||
const cardDescriptorRef = ref(null);
|
const cardDescriptorRef = ref(null);
|
||||||
|
const showEditPhotoForm = ref(false);
|
||||||
|
const toggleEditPictureForm = () => {
|
||||||
|
showEditPhotoForm.value = !showEditPhotoForm.value;
|
||||||
|
};
|
||||||
|
|
||||||
const entityId = computed(() => {
|
const entityId = computed(() => {
|
||||||
return $props.id || route.params.id;
|
return $props.id || route.params.id;
|
||||||
|
@ -99,7 +105,9 @@ const handleExcluded = async () => {
|
||||||
|
|
||||||
workerExcluded.value = !workerExcluded.value;
|
workerExcluded.value = !workerExcluded.value;
|
||||||
};
|
};
|
||||||
|
const handlePhotoUpdated = (evt = false) => {
|
||||||
|
image.value.reload(evt);
|
||||||
|
};
|
||||||
const refetch = async () => await cardDescriptorRef.value.getData();
|
const refetch = async () => await cardDescriptorRef.value.getData();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
@ -144,27 +152,49 @@ const refetch = async () => await cardDescriptorRef.value.getData();
|
||||||
</QItem>
|
</QItem>
|
||||||
</template>
|
</template>
|
||||||
<template #before>
|
<template #before>
|
||||||
<VnImg
|
<div class="relative-position">
|
||||||
:id="parseInt(entityId)"
|
<VnImg
|
||||||
collection="user"
|
ref="image"
|
||||||
resolution="520x520"
|
:id="parseInt(entityId)"
|
||||||
class="photo"
|
collection="user"
|
||||||
>
|
resolution="520x520"
|
||||||
<template #error>
|
class="photo"
|
||||||
<div
|
>
|
||||||
class="absolute-full picture text-center q-pa-md flex flex-center"
|
<template #error>
|
||||||
>
|
<div
|
||||||
<div>
|
class="absolute-full picture text-center q-pa-md flex flex-center"
|
||||||
<div class="text-grey-5" style="opacity: 0.4; font-size: 5vh">
|
>
|
||||||
<QIcon name="vn:claims" />
|
<div>
|
||||||
</div>
|
<div
|
||||||
<div class="text-grey-5" style="opacity: 0.4">
|
class="text-grey-5"
|
||||||
{{ t('worker.imageNotFound') }}
|
style="opacity: 0.4; font-size: 5vh"
|
||||||
|
>
|
||||||
|
<QIcon name="vn:claims" />
|
||||||
|
</div>
|
||||||
|
<div class="text-grey-5" style="opacity: 0.4">
|
||||||
|
{{ t('worker.imageNotFound') }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template> </VnImg
|
||||||
</template>
|
><QBtn
|
||||||
</VnImg>
|
color="primary"
|
||||||
|
size="lg"
|
||||||
|
round
|
||||||
|
class="edit-photo-btn"
|
||||||
|
@click="toggleEditPictureForm()"
|
||||||
|
>
|
||||||
|
<QIcon name="edit" size="sm" />
|
||||||
|
<QDialog ref="editPhotoFormDialog" v-model="showEditPhotoForm">
|
||||||
|
<EditPictureForm
|
||||||
|
collection="user"
|
||||||
|
:id="entityId"
|
||||||
|
@close-form="toggleEditPictureForm()"
|
||||||
|
@on-photo-uploaded="handlePhotoUpdated"
|
||||||
|
/>
|
||||||
|
</QDialog>
|
||||||
|
</QBtn>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #body="{ entity }">
|
<template #body="{ entity }">
|
||||||
<VnLv :label="t('worker.card.name')" :value="entity.user?.nickname" />
|
<VnLv :label="t('worker.card.name')" :value="entity.user?.nickname" />
|
||||||
|
|
|
@ -93,7 +93,6 @@ const filter = {
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</VnLv>
|
</VnLv>
|
||||||
<VnLv :label="t('worker.list.email')" :value="worker.user.email" copy />
|
|
||||||
<VnLv :label="t('worker.summary.boss')" link>
|
<VnLv :label="t('worker.summary.boss')" link>
|
||||||
<template #value>
|
<template #value>
|
||||||
<VnUserLink
|
<VnUserLink
|
||||||
|
@ -139,29 +138,25 @@ const filter = {
|
||||||
/>
|
/>
|
||||||
<VnLv :label="t('worker.summary.fi')" :value="worker.fi" />
|
<VnLv :label="t('worker.summary.fi')" :value="worker.fi" />
|
||||||
<VnLv :label="t('worker.summary.birth')" :value="toDate(worker.birth)" />
|
<VnLv :label="t('worker.summary.birth')" :value="toDate(worker.birth)" />
|
||||||
<VnRow class="q-mt-sm" wrap>
|
<VnLv
|
||||||
<VnLv
|
:label="t('worker.summary.isFreelance')"
|
||||||
:label="t('worker.summary.isFreelance')"
|
:value="worker.isFreelance"
|
||||||
:value="worker.isFreelance"
|
/>
|
||||||
/>
|
<VnLv
|
||||||
<VnLv
|
:label="t('worker.summary.isSsDiscounted')"
|
||||||
:label="t('worker.summary.isSsDiscounted')"
|
:value="worker.isSsDiscounted"
|
||||||
:value="worker.isSsDiscounted"
|
/>
|
||||||
/>
|
<VnLv
|
||||||
<VnLv
|
:label="t('worker.summary.hasMachineryAuthorized')"
|
||||||
:label="t('worker.summary.hasMachineryAuthorized')"
|
:value="worker.hasMachineryAuthorized"
|
||||||
:value="worker.hasMachineryAuthorized"
|
/>
|
||||||
/>
|
<VnLv :label="t('worker.summary.isDisable')" :value="worker.isDisable" />
|
||||||
<VnLv
|
|
||||||
:label="t('worker.summary.isDisable')"
|
|
||||||
:value="worker.isDisable"
|
|
||||||
/>
|
|
||||||
</VnRow>
|
|
||||||
</QCard>
|
</QCard>
|
||||||
<QCard class="vn-one">
|
<QCard class="vn-one">
|
||||||
<VnTitle :text="t('worker.summary.userData')" />
|
<VnTitle :text="t('worker.summary.userData')" />
|
||||||
<VnLv :label="t('worker.summary.userId')" :value="worker.user.id" />
|
<VnLv :label="t('worker.summary.userId')" :value="worker.user.id" />
|
||||||
<VnLv :label="t('worker.card.name')" :value="worker.user.nickname" />
|
<VnLv :label="t('worker.card.name')" :value="worker.user.nickname" />
|
||||||
|
<VnLv :label="t('worker.list.email')" :value="worker.user.email" copy />
|
||||||
<VnLv :label="t('worker.summary.role')">
|
<VnLv :label="t('worker.summary.role')">
|
||||||
<template #value>
|
<template #value>
|
||||||
<span class="link">
|
<span class="link">
|
||||||
|
|
|
@ -34,6 +34,10 @@ const weekdayStore = useWeekdayStore();
|
||||||
const weekDays = ref([]);
|
const weekDays = ref([]);
|
||||||
const { openConfirmationModal } = useVnConfirm();
|
const { openConfirmationModal } = useVnConfirm();
|
||||||
const { getWeekOfYear } = date;
|
const { getWeekOfYear } = date;
|
||||||
|
const defaultDate = computed(() => {
|
||||||
|
const timestamp = route.query.timestamp;
|
||||||
|
return timestamp ? new Date(timestamp * 1000) : Date.vnNew();
|
||||||
|
});
|
||||||
|
|
||||||
const workerTimeFormDialogRef = ref(null);
|
const workerTimeFormDialogRef = ref(null);
|
||||||
const workerTimeReasonFormDialogRef = ref(null);
|
const workerTimeReasonFormDialogRef = ref(null);
|
||||||
|
@ -56,7 +60,7 @@ const workerTimeFormProps = reactive({
|
||||||
// Array utilizado por QCalendar para seleccionar un rango de fechas
|
// Array utilizado por QCalendar para seleccionar un rango de fechas
|
||||||
const selectedCalendarDates = ref([]);
|
const selectedCalendarDates = ref([]);
|
||||||
// Date formateada para bindear al componente QDate
|
// Date formateada para bindear al componente QDate
|
||||||
const selectedDateFormatted = ref(toDateString(Date.vnNew()));
|
const selectedDateFormatted = ref(toDateString(defaultDate.value));
|
||||||
|
|
||||||
const arrayData = useArrayData('workerData');
|
const arrayData = useArrayData('workerData');
|
||||||
|
|
||||||
|
@ -423,7 +427,7 @@ onBeforeMount(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await setDate(Date.vnNew());
|
await setDate(defaultDate.value);
|
||||||
await getMailStates(selectedDate.value);
|
await getMailStates(selectedDate.value);
|
||||||
stateStore.rightDrawer = true;
|
stateStore.rightDrawer = true;
|
||||||
});
|
});
|
||||||
|
@ -547,9 +551,12 @@ onMounted(async () => {
|
||||||
<QTd
|
<QTd
|
||||||
v-for="(day, index) in props.cols"
|
v-for="(day, index) in props.cols"
|
||||||
:key="index"
|
:key="index"
|
||||||
style="padding: 20px 16px !important"
|
:style="{
|
||||||
|
padding: '20px 16px !important',
|
||||||
|
'vertical-align': 'baseline',
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<div class="full-height full-width column items-center">
|
<div class="full-width column items-center">
|
||||||
<WorkerTimeHourChip
|
<WorkerTimeHourChip
|
||||||
v-for="(hour, ind) in day.dayData?.hours"
|
v-for="(hour, ind) in day.dayData?.hours"
|
||||||
:key="ind"
|
:key="ind"
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
import { onBeforeMount, ref } from 'vue';
|
import { onBeforeMount, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { useUserConfig } from 'src/composables/useUserConfig';
|
|
||||||
import VnRow from 'components/ui/VnRow.vue';
|
import VnRow from 'components/ui/VnRow.vue';
|
||||||
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
|
||||||
import VnInputDate from 'components/common/VnInputDate.vue';
|
import VnInputDate from 'components/common/VnInputDate.vue';
|
||||||
|
@ -14,15 +13,25 @@ import FetchData from 'components/FetchData.vue';
|
||||||
import FormModel from 'components/FormModel.vue';
|
import FormModel from 'components/FormModel.vue';
|
||||||
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
||||||
import VnRadio from 'src/components/common/VnRadio.vue';
|
import VnRadio from 'src/components/common/VnRadio.vue';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const user = useState().getUser();
|
||||||
|
|
||||||
const companiesOptions = ref([]);
|
const companiesOptions = ref([]);
|
||||||
const workersOptions = ref([]);
|
|
||||||
const payMethodsOptions = ref([]);
|
const payMethodsOptions = ref([]);
|
||||||
const bankEntitiesOptions = ref([]);
|
const bankEntitiesOptions = ref([]);
|
||||||
const formData = ref({ isFreelance: false });
|
const formData = ref({ companyFk: user.value.companyFk, isFreelance: false });
|
||||||
const defaultPayMethod = ref(0);
|
const defaultPayMethod = ref();
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
defaultPayMethod.value = (
|
||||||
|
await axios.get('WorkerConfigs/findOne', {
|
||||||
|
params: { field: ['payMethodFk'] },
|
||||||
|
})
|
||||||
|
).data.payMethodFk;
|
||||||
|
formData.value.payMethodFk = defaultPayMethod.value;
|
||||||
|
});
|
||||||
|
|
||||||
function handleLocation(data, location) {
|
function handleLocation(data, location) {
|
||||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||||
|
@ -32,16 +41,32 @@ function handleLocation(data, location) {
|
||||||
data.countryFk = countryFk;
|
data.countryFk = countryFk;
|
||||||
}
|
}
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
function generateCodeUser(worker) {
|
||||||
const userInfo = await useUserConfig().fetch();
|
if (!worker.firstName || !worker.lastNames) return;
|
||||||
formData.value.companyFk = userInfo.companyFk;
|
|
||||||
|
|
||||||
const { data } = await axios.get('WorkerConfigs/findOne', {
|
const totalName = worker.firstName.concat(' ' + worker.lastNames).toLowerCase();
|
||||||
params: { field: ['payMethodFk'] },
|
const totalNameArray = totalName.split(' ');
|
||||||
});
|
let newCode = '';
|
||||||
defaultPayMethod.value = data.payMethodFk;
|
|
||||||
formData.value.payMethodFk = defaultPayMethod.value;
|
for (let part of totalNameArray) newCode += part.charAt(0);
|
||||||
});
|
|
||||||
|
worker.code = newCode.toUpperCase().slice(0, 3);
|
||||||
|
worker.name = totalNameArray[0] + newCode.slice(1);
|
||||||
|
|
||||||
|
if (!worker.companyFk) worker.companyFk = user.companyFk;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function autofillBic(worker) {
|
||||||
|
if (!worker || !worker.iban) return;
|
||||||
|
|
||||||
|
let bankEntityId = parseInt(worker.iban.substr(4, 4));
|
||||||
|
let filter = { where: { id: bankEntityId } };
|
||||||
|
|
||||||
|
const { data } = await axios.get(`BankEntities`, { params: { filter } });
|
||||||
|
const hasData = data && data[0];
|
||||||
|
if (hasData) worker.bankEntityFk = data[0].id;
|
||||||
|
else if (!hasData) worker.bankEntityFk = undefined;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<FetchData
|
<FetchData
|
||||||
|
@ -49,11 +74,6 @@ onBeforeMount(async () => {
|
||||||
@on-fetch="(data) => (companiesOptions = data)"
|
@on-fetch="(data) => (companiesOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
|
||||||
url="Workers/search"
|
|
||||||
@on-fetch="(data) => (workersOptions = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Paymethods"
|
url="Paymethods"
|
||||||
@on-fetch="(data) => (payMethodsOptions = data)"
|
@on-fetch="(data) => (payMethodsOptions = data)"
|
||||||
|
@ -93,11 +113,13 @@ onBeforeMount(async () => {
|
||||||
v-model="data.firstName"
|
v-model="data.firstName"
|
||||||
:label="t('worker.create.name')"
|
:label="t('worker.create.name')"
|
||||||
:rules="validate('Worker.firstName')"
|
:rules="validate('Worker.firstName')"
|
||||||
|
@update:model-value="generateCodeUser(data)"
|
||||||
/>
|
/>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.lastNames"
|
v-model="data.lastNames"
|
||||||
:label="t('worker.create.lastName')"
|
:label="t('worker.create.lastName')"
|
||||||
:rules="validate('Worker.lastNames')"
|
:rules="validate('Worker.lastNames')"
|
||||||
|
@update:model-value="generateCodeUser(data)"
|
||||||
/>
|
/>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.code"
|
v-model="data.code"
|
||||||
|
@ -130,7 +152,7 @@ onBeforeMount(async () => {
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('worker.create.boss')"
|
:label="t('worker.create.boss')"
|
||||||
v-model="data.bossFk"
|
v-model="data.bossFk"
|
||||||
:options="workersOptions"
|
url="Workers/search"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
hide-selected
|
hide-selected
|
||||||
|
@ -204,6 +226,7 @@ onBeforeMount(async () => {
|
||||||
:label="t('worker.create.iban')"
|
:label="t('worker.create.iban')"
|
||||||
:rules="validate('Worker.iban')"
|
:rules="validate('Worker.iban')"
|
||||||
:disable="formData.isFreelance"
|
:disable="formData.isFreelance"
|
||||||
|
@update:model-value="autofillBic(data)"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-info">
|
<QIcon name="info" class="cursor-info">
|
||||||
|
@ -221,6 +244,8 @@ onBeforeMount(async () => {
|
||||||
:roles-allowed-to-create="['salesAssistant', 'hr']"
|
:roles-allowed-to-create="['salesAssistant', 'hr']"
|
||||||
:rules="validate('Worker.bankEntity')"
|
:rules="validate('Worker.bankEntity')"
|
||||||
:disable="formData.isFreelance"
|
:disable="formData.isFreelance"
|
||||||
|
@update:model-value="autofillBic(data)"
|
||||||
|
:filter-options="['bic', 'name']"
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CreateBankEntityForm
|
<CreateBankEntityForm
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue';
|
import { onBeforeMount, computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
|
||||||
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
|
||||||
|
@ -16,16 +16,19 @@ import CreateBankEntityForm from 'src/components/CreateBankEntityForm.vue';
|
||||||
import FetchData from 'src/components/FetchData.vue';
|
import FetchData from 'src/components/FetchData.vue';
|
||||||
import RightMenu from 'src/components/common/RightMenu.vue';
|
import RightMenu from 'src/components/common/RightMenu.vue';
|
||||||
import WorkerFilter from './WorkerFilter.vue';
|
import WorkerFilter from './WorkerFilter.vue';
|
||||||
|
import { useState } from 'src/composables/useState';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tableRef = ref();
|
const tableRef = ref();
|
||||||
const { viewSummary } = useSummaryDialog();
|
const { viewSummary } = useSummaryDialog();
|
||||||
const companiesOptions = ref([]);
|
const companiesOptions = ref([]);
|
||||||
const workersOptions = ref([]);
|
|
||||||
const payMethodsOptions = ref([]);
|
const payMethodsOptions = ref([]);
|
||||||
const bankEntitiesOptions = ref([]);
|
const bankEntitiesOptions = ref([]);
|
||||||
const postcodesOptions = ref([]);
|
const postcodesOptions = ref([]);
|
||||||
|
|
||||||
|
const user = useState().getUser();
|
||||||
|
const defaultPayMethod = ref();
|
||||||
const columns = computed(() => [
|
const columns = computed(() => [
|
||||||
{
|
{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
|
@ -74,7 +77,7 @@ const columns = computed(() => [
|
||||||
name: 'tableActions',
|
name: 'tableActions',
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
title: t('InvoiceOutSummary'),
|
title: t('components.smartCard.viewSummary'),
|
||||||
icon: 'preview',
|
icon: 'preview',
|
||||||
action: (row) => viewSummary(row.id, WorkerSummary),
|
action: (row) => viewSummary(row.id, WorkerSummary),
|
||||||
},
|
},
|
||||||
|
@ -82,6 +85,14 @@ const columns = computed(() => [
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
onBeforeMount(async () => {
|
||||||
|
defaultPayMethod.value = (
|
||||||
|
await axios.get('WorkerConfigs/findOne', {
|
||||||
|
params: { field: ['payMethodFk'] },
|
||||||
|
})
|
||||||
|
).data?.payMethodFk;
|
||||||
|
});
|
||||||
|
|
||||||
function handleLocation(data, location) {
|
function handleLocation(data, location) {
|
||||||
const { town, code, provinceFk, countryFk } = location ?? {};
|
const { town, code, provinceFk, countryFk } = location ?? {};
|
||||||
data.postcode = code;
|
data.postcode = code;
|
||||||
|
@ -98,6 +109,31 @@ function uppercaseStreetModel(data) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateCodeUser(worker) {
|
||||||
|
if (!worker.firstName || !worker.lastNames) return;
|
||||||
|
|
||||||
|
const totalName = worker.firstName.concat(' ' + worker.lastNames).toLowerCase();
|
||||||
|
const totalNameArray = totalName.split(' ');
|
||||||
|
let newCode = '';
|
||||||
|
|
||||||
|
for (let part of totalNameArray) newCode += part.charAt(0);
|
||||||
|
|
||||||
|
worker.code = newCode.toUpperCase().slice(0, 3);
|
||||||
|
worker.name = totalNameArray[0] + newCode.slice(1);
|
||||||
|
|
||||||
|
if (!worker.companyFk) worker.companyFk = user.companyFk;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function autofillBic(worker) {
|
||||||
|
if (!worker || !worker.iban) return;
|
||||||
|
|
||||||
|
let bankEntityId = parseInt(worker.iban.substr(4, 4));
|
||||||
|
let filter = { where: { id: bankEntityId } };
|
||||||
|
|
||||||
|
const { data } = await axios.get(`BankEntities`, { params: { filter } });
|
||||||
|
worker.bankEntityFk = data?.[0]?.id ?? undefined;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VnSearchbar
|
<VnSearchbar
|
||||||
|
@ -110,11 +146,6 @@ function uppercaseStreetModel(data) {
|
||||||
@on-fetch="(data) => (companiesOptions = data)"
|
@on-fetch="(data) => (companiesOptions = data)"
|
||||||
auto-load
|
auto-load
|
||||||
/>
|
/>
|
||||||
<FetchData
|
|
||||||
url="Workers/search"
|
|
||||||
@on-fetch="(data) => (workersOptions = data)"
|
|
||||||
auto-load
|
|
||||||
/>
|
|
||||||
<FetchData
|
<FetchData
|
||||||
url="Paymethods"
|
url="Paymethods"
|
||||||
@on-fetch="(data) => (payMethodsOptions = data)"
|
@on-fetch="(data) => (payMethodsOptions = data)"
|
||||||
|
@ -131,6 +162,7 @@ function uppercaseStreetModel(data) {
|
||||||
</template>
|
</template>
|
||||||
</RightMenu>
|
</RightMenu>
|
||||||
<VnTable
|
<VnTable
|
||||||
|
v-if="defaultPayMethod"
|
||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
data-key="Worker"
|
data-key="Worker"
|
||||||
url="Workers/filter"
|
url="Workers/filter"
|
||||||
|
@ -139,6 +171,8 @@ function uppercaseStreetModel(data) {
|
||||||
title: t('Create worker'),
|
title: t('Create worker'),
|
||||||
onDataSaved: ({ id }) => tableRef.redirect(id),
|
onDataSaved: ({ id }) => tableRef.redirect(id),
|
||||||
formInitialData: {
|
formInitialData: {
|
||||||
|
payMethodFk: defaultPayMethod,
|
||||||
|
companyFk: user.companyFk,
|
||||||
isFreelance: false,
|
isFreelance: false,
|
||||||
},
|
},
|
||||||
}"
|
}"
|
||||||
|
@ -149,7 +183,7 @@ function uppercaseStreetModel(data) {
|
||||||
auto-load
|
auto-load
|
||||||
>
|
>
|
||||||
<template #more-create-dialog="{ data }">
|
<template #more-create-dialog="{ data }">
|
||||||
<div class="q-pa-lg full-width" style="max-width: 1200px">
|
<div class="q-pa-lg full-width">
|
||||||
<VnRadio
|
<VnRadio
|
||||||
v-model="data.isFreelance"
|
v-model="data.isFreelance"
|
||||||
:val="false"
|
:val="false"
|
||||||
|
@ -163,10 +197,16 @@ function uppercaseStreetModel(data) {
|
||||||
@update:model-value="delete data.payMethodFk"
|
@update:model-value="delete data.payMethodFk"
|
||||||
/>
|
/>
|
||||||
<VnRow>
|
<VnRow>
|
||||||
<VnInput v-model="data.firstName" :label="t('worker.create.name')" />
|
<VnInput
|
||||||
|
next
|
||||||
|
v-model="data.firstName"
|
||||||
|
:label="t('worker.create.name')"
|
||||||
|
@update:model-value="generateCodeUser(data)"
|
||||||
|
/>
|
||||||
<VnInput
|
<VnInput
|
||||||
v-model="data.lastNames"
|
v-model="data.lastNames"
|
||||||
:label="t('worker.create.lastName')"
|
:label="t('worker.create.lastName')"
|
||||||
|
@update:model-value="generateCodeUser(data)"
|
||||||
/>
|
/>
|
||||||
<VnInput v-model="data.code" :label="t('worker.create.code')" />
|
<VnInput v-model="data.code" :label="t('worker.create.code')" />
|
||||||
</VnRow>
|
</VnRow>
|
||||||
|
@ -189,7 +229,7 @@ function uppercaseStreetModel(data) {
|
||||||
<VnSelect
|
<VnSelect
|
||||||
:label="t('worker.create.boss')"
|
:label="t('worker.create.boss')"
|
||||||
v-model="data.bossFk"
|
v-model="data.bossFk"
|
||||||
:options="workersOptions"
|
url="Workers/search"
|
||||||
option-value="id"
|
option-value="id"
|
||||||
option-label="name"
|
option-label="name"
|
||||||
hide-selected
|
hide-selected
|
||||||
|
@ -254,6 +294,7 @@ function uppercaseStreetModel(data) {
|
||||||
v-model="data.iban"
|
v-model="data.iban"
|
||||||
:label="t('worker.create.iban')"
|
:label="t('worker.create.iban')"
|
||||||
:disable="data.isFreelance"
|
:disable="data.isFreelance"
|
||||||
|
@update:model-value="autofillBic(data)"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<QIcon name="info" class="cursor-info">
|
<QIcon name="info" class="cursor-info">
|
||||||
|
@ -272,6 +313,8 @@ function uppercaseStreetModel(data) {
|
||||||
hide-selected
|
hide-selected
|
||||||
:roles-allowed-to-create="['salesAssistant', 'hr']"
|
:roles-allowed-to-create="['salesAssistant', 'hr']"
|
||||||
:disable="data.isFreelance"
|
:disable="data.isFreelance"
|
||||||
|
@update:model-value="autofillBic(data)"
|
||||||
|
:filter-options="['bic', 'name']"
|
||||||
>
|
>
|
||||||
<template #form>
|
<template #form>
|
||||||
<CreateBankEntityForm
|
<CreateBankEntityForm
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
component: RouterView,
|
component: RouterView,
|
||||||
redirect: { name: 'InvoiceInMain' },
|
redirect: { name: 'InvoiceInMain' },
|
||||||
menus: {
|
menus: {
|
||||||
main: ['InvoiceInList'],
|
main: ['InvoiceInList', 'InvoiceInSerial'],
|
||||||
card: [
|
card: [
|
||||||
'InvoiceInBasicData',
|
'InvoiceInBasicData',
|
||||||
'InvoiceInVat',
|
'InvoiceInVat',
|
||||||
|
@ -37,6 +37,16 @@ export default {
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
|
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'serial',
|
||||||
|
name: 'InvoiceInSerial',
|
||||||
|
meta: {
|
||||||
|
title: 'serial',
|
||||||
|
icon: 'view_list',
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import('src/pages/InvoiceIn/Serial/InvoiceInSerial.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'create',
|
path: 'create',
|
||||||
name: 'InvoiceInCreare',
|
name: 'InvoiceInCreare',
|
||||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
||||||
component: RouterView,
|
component: RouterView,
|
||||||
redirect: { name: 'MonitorMain' },
|
redirect: { name: 'MonitorMain' },
|
||||||
menus: {
|
menus: {
|
||||||
main: ['MonitorList'],
|
main: ['MonitorTickets', 'MonitorClientsActions'],
|
||||||
card: [],
|
card: [],
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
@ -19,16 +19,27 @@ export default {
|
||||||
path: '',
|
path: '',
|
||||||
name: 'MonitorMain',
|
name: 'MonitorMain',
|
||||||
component: () => import('src/components/common/VnSectionMain.vue'),
|
component: () => import('src/components/common/VnSectionMain.vue'),
|
||||||
redirect: { name: 'MonitorList' },
|
redirect: { name: 'MonitorTickets' },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'list',
|
path: 'tickets',
|
||||||
name: 'MonitorList',
|
name: 'MonitorTickets',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'list',
|
title: 'ticketsMonitor',
|
||||||
icon: 'grid_view',
|
icon: 'vn:ticket',
|
||||||
},
|
},
|
||||||
component: () => import('src/pages/Monitor/MonitorList.vue'),
|
component: () =>
|
||||||
|
import('src/pages/Monitor/Ticket/MonitorTickets.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'clients-actions',
|
||||||
|
name: 'MonitorClientsActions',
|
||||||
|
meta: {
|
||||||
|
title: 'clientsActionsMonitor',
|
||||||
|
icon: 'vn:client',
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import('src/pages/Monitor/MonitorClientsActions.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -19,6 +19,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
maxShipped: null,
|
maxShipped: null,
|
||||||
clientId: null,
|
clientId: null,
|
||||||
printer: null,
|
printer: null,
|
||||||
|
serialType: null,
|
||||||
},
|
},
|
||||||
addresses: [],
|
addresses: [],
|
||||||
minInvoicingDate: null,
|
minInvoicingDate: null,
|
||||||
|
@ -100,6 +101,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
maxShipped: new Date(formData.maxShipped),
|
maxShipped: new Date(formData.maxShipped),
|
||||||
clientId: formData.clientId ? formData.clientId : null,
|
clientId: formData.clientId ? formData.clientId : null,
|
||||||
companyFk: formData.companyFk,
|
companyFk: formData.companyFk,
|
||||||
|
serialType: formData.serialType,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.validateMakeInvoceParams(params, clientsToInvoice);
|
this.validateMakeInvoceParams(params, clientsToInvoice);
|
||||||
|
@ -152,7 +154,13 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
);
|
);
|
||||||
throw new Error('Invoice date in the future');
|
throw new Error('Invoice date in the future');
|
||||||
}
|
}
|
||||||
|
if (!params.serialType) {
|
||||||
|
notify(
|
||||||
|
'invoiceOut.globalInvoices.errors.chooseValidSerialType',
|
||||||
|
'negative'
|
||||||
|
);
|
||||||
|
throw new Error('Invalid Serial Type');
|
||||||
|
}
|
||||||
if (!params.companyFk) {
|
if (!params.companyFk) {
|
||||||
notify('invoiceOut.globalInvoices.errors.chooseValidCompany', 'negative');
|
notify('invoiceOut.globalInvoices.errors.chooseValidCompany', 'negative');
|
||||||
throw new Error('Invalid company');
|
throw new Error('Invalid company');
|
||||||
|
@ -180,6 +188,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
invoiceDate: new Date(formData.invoiceDate),
|
invoiceDate: new Date(formData.invoiceDate),
|
||||||
maxShipped: new Date(formData.maxShipped),
|
maxShipped: new Date(formData.maxShipped),
|
||||||
companyFk: formData.companyFk,
|
companyFk: formData.companyFk,
|
||||||
|
serialType: formData.serialType,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.status = 'invoicing';
|
this.status = 'invoicing';
|
||||||
|
@ -191,12 +200,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
this.addressIndex++;
|
this.addressIndex++;
|
||||||
this.isInvoicing = false;
|
this.isInvoicing = false;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (
|
if (err?.response?.status >= 400 && err?.response?.status < 500) {
|
||||||
err &&
|
|
||||||
err.response &&
|
|
||||||
err.response.status >= 400 &&
|
|
||||||
err.response.status < 500
|
|
||||||
) {
|
|
||||||
this.invoiceClientError(address, err.response?.data?.error?.message);
|
this.invoiceClientError(address, err.response?.data?.error?.message);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
|
@ -243,7 +247,7 @@ export const useInvoiceOutGlobalStore = defineStore({
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (data.data && data.data.error) throw new Error();
|
if (data?.data?.error) throw new Error();
|
||||||
|
|
||||||
const status = exportFile('negativeBases.csv', data, {
|
const status = exportFile('negativeBases.csv', data, {
|
||||||
encoding: 'windows-1252',
|
encoding: 'windows-1252',
|
||||||
|
|
|
@ -10,12 +10,13 @@ describe('Route', () => {
|
||||||
|
|
||||||
it('Route list create route', () => {
|
it('Route list create route', () => {
|
||||||
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
cy.get('.q-page-sticky > div > .q-btn > .q-btn__content > .q-icon').click();
|
||||||
cy.get('input[name="description"]').eq(1).type('routeTestOne{enter}');
|
cy.get('input[name="description"]').type('routeTestOne{enter}');
|
||||||
cy.get('.q-notification__message').should('have.text', 'Data created');
|
cy.get('.q-notification__message').should('have.text', 'Data created');
|
||||||
cy.url().should('include', '/summary');
|
cy.url().should('include', '/summary');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Route list search and edit', () => {
|
it('Route list search and edit', () => {
|
||||||
|
cy.get('#searchbar input').type('{enter}');
|
||||||
cy.get('input[name="description"]').type('routeTestOne{enter}');
|
cy.get('input[name="description"]').type('routeTestOne{enter}');
|
||||||
cy.get('.q-table tr')
|
cy.get('.q-table tr')
|
||||||
.its('length')
|
.its('length')
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe('Ticket descriptor', () => {
|
||||||
cy.openActionsDescriptor();
|
cy.openActionsDescriptor();
|
||||||
cy.get(toCloneOpt).click();
|
cy.get(toCloneOpt).click();
|
||||||
cy.clickConfirm();
|
cy.clickConfirm();
|
||||||
cy.get(warehouseValue).contains('-');
|
cy.get(warehouseValue).contains('Warehouse One');
|
||||||
cy.get(summaryHeader)
|
cy.get(summaryHeader)
|
||||||
.invoke('text')
|
.invoke('text')
|
||||||
.then((text) => {
|
.then((text) => {
|
||||||
|
|
|
@ -2,6 +2,9 @@ describe('WorkerCreate', () => {
|
||||||
const externalRadio = '.q-radio:nth-child(2)';
|
const externalRadio = '.q-radio:nth-child(2)';
|
||||||
const notification = '.q-notification__message';
|
const notification = '.q-notification__message';
|
||||||
const developerBossId = 120;
|
const developerBossId = 120;
|
||||||
|
const payMethodCross =
|
||||||
|
'.grid-create .full-width > :nth-child(9) .q-select .q-field__append:not(.q-anchor--skip)';
|
||||||
|
const saveBtn = '.q-mt-lg > .q-btn--standard';
|
||||||
|
|
||||||
const internal = {
|
const internal = {
|
||||||
Fi: { val: '78457139E' },
|
Fi: { val: '78457139E' },
|
||||||
|
@ -36,7 +39,8 @@ describe('WorkerCreate', () => {
|
||||||
|
|
||||||
it('should throw an error if a pay method has not been selected', () => {
|
it('should throw an error if a pay method has not been selected', () => {
|
||||||
cy.fillInForm(internal);
|
cy.fillInForm(internal);
|
||||||
cy.get('.q-mt-lg > .q-btn--standard').click();
|
cy.get(payMethodCross).click();
|
||||||
|
cy.get(saveBtn).click();
|
||||||
cy.get(notification).should('contains.text', 'Payment method is required');
|
cy.get(notification).should('contains.text', 'Payment method is required');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -45,14 +49,14 @@ describe('WorkerCreate', () => {
|
||||||
...internal,
|
...internal,
|
||||||
'Pay method': { val: 'PayMethod one', type: 'select' },
|
'Pay method': { val: 'PayMethod one', type: 'select' },
|
||||||
});
|
});
|
||||||
cy.get('.q-mt-lg > .q-btn--standard').click();
|
cy.get(saveBtn).click();
|
||||||
cy.get(notification).should('contains.text', 'Data created');
|
cy.get(notification).should('contains.text', 'Data created');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create an external', () => {
|
it('should create an external', () => {
|
||||||
cy.get(externalRadio).click();
|
cy.get(externalRadio).click();
|
||||||
cy.fillInForm(external);
|
cy.fillInForm(external);
|
||||||
cy.get('.q-mt-lg > .q-btn--standard').click();
|
cy.get(saveBtn).click();
|
||||||
cy.get(notification).should('contains.text', 'Data created');
|
cy.get(notification).should('contains.text', 'Data created');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue