Merge branch 'dev' into 6336-migrationClaim-v5
gitea/salix-front/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Alex Moreno 2024-07-09 09:27:16 +00:00
commit bb8f0b43f0
10 changed files with 436 additions and 331 deletions

View File

@ -143,6 +143,7 @@ function setUserParams(watchedParams) {
const where = JSON.parse(watchedParams?.filter)?.where;
watchedParams = { ...watchedParams, ...where };
delete watchedParams.filter;
delete params.value?.filter;
params.value = { ...params.value, ...watchedParams };
}
@ -225,6 +226,7 @@ defineExpose({
v-model="params"
:disable-submit-event="true"
:search-url="searchUrl"
:redirect="!!redirect"
>
<template #body>
<VnTableFilter
@ -300,6 +302,7 @@ defineExpose({
:options="tableModes"
/>
<QBtn
v-if="$props.rightSearch"
icon="filter_alt"
title="asd"
class="bg-vn-section-color q-ml-md"

View File

@ -26,6 +26,10 @@ const props = defineProps({
type: Object,
default: null,
},
userFilter: {
type: Object,
default: null,
},
where: {
type: Object,
default: null,
@ -80,6 +84,7 @@ const pagination = ref({
const arrayData = useArrayData(props.dataKey, {
url: props.url,
filter: props.filter,
userFilter: props.userFilter,
where: props.where,
limit: props.limit,
order: props.order,

View File

@ -1,11 +1,10 @@
<script setup>
import { useRoute, useRouter } from 'vue-router';
import { reactive, ref } from 'vue';
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import axios from 'axios';
import { useState } from 'composables/useState';
import FormModel from 'components/FormModel.vue';
import FetchData from 'components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelect from 'components/common/VnSelect.vue';
import VnInputDate from 'components/common/VnInputDate.vue';
@ -18,29 +17,9 @@ const ORDER_MODEL = 'order';
const router = useRouter();
const isNew = Boolean(!route.params.id);
const initialFormState = reactive({
clientFk: null,
addressFk: null,
agencyModeFk: null,
landed: null,
});
const clientList = ref([]);
const agencyList = ref([]);
const addressList = ref([]);
const clientId = ref(null);
const onClientsFetched = (data) => {
clientList.value = data;
initialFormState.clientFk = Number(route.query?.clientFk) || null;
clientId.value = initialFormState.clientFk;
const client = clientList.value.find(
(client) => client.id === initialFormState.clientFk
);
if (!client?.defaultAddressFk)
throw new Error(t(`No default address found for the client`));
fetchAddressList(client.defaultAddressFk);
};
const fetchAddressList = async (addressId) => {
try {
@ -128,28 +107,19 @@ const onClientChange = async (clientId) => {
}
};
async function onDataSaved(data) {
await router.push({ path: `/order/${data}/catalog` });
async function onDataSaved({ id }) {
await router.push({ path: `/order/${id}/catalog` });
}
</script>
<template>
<FetchData
url="Clients"
@on-fetch="(data) => onClientsFetched(data)"
:filter="{ fields: ['id', 'name', 'defaultAddressFk'] }"
auto-load
/>
<VnSubToolbar v-if="isNew" />
<div class="q-pa-md">
<FormModel
:url="!isNew ? `Orders/${route.params.id}` : null"
url-create="Orders/new"
:url="`Orders/${route.params.id}`"
@on-data-saved="onDataSaved"
:model="ORDER_MODEL"
:form-initial-data="isNew ? initialFormState : null"
:observe-form-changes="!isNew"
:mapper="isNew ? orderMapper : null"
:mapper="orderMapper"
:filter="orderFilter"
@on-fetch="fetchOrderDetails"
auto-load
@ -157,11 +127,15 @@ async function onDataSaved(data) {
<template #form="{ data }">
<VnRow class="row q-gutter-md q-mb-md">
<VnSelect
url="Clients"
:label="t('order.form.clientFk')"
v-model="data.clientFk"
:options="clientList"
option-value="id"
option-label="name"
:filter="{
fields: ['id', 'name', 'defaultAddressFk'],
}"
hide-selected
@update:model-value="onClientChange"
>
@ -183,7 +157,6 @@ async function onDataSaved(data) {
option-label="street"
hide-selected
:disable="!addressList?.length"
@update:model-value="onAddressChange"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">

View File

@ -196,7 +196,7 @@ const detailsColumns = ref([
{{ props.row.quantity }}
</QTd>
<QTd key="price" :props="props">
{{ props.row.price }}
{{ toCurrency(props.row.price) }}
</QTd>
<QTd key="amount" :props="props">
{{

View File

@ -1,33 +1,70 @@
<script setup>
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { useQuasar } from 'quasar';
import VnPaginate from 'components/ui/VnPaginate.vue';
import FetchData from 'components/FetchData.vue';
import VnLv from 'components/ui/VnLv.vue';
import FetchedTags from 'components/ui/FetchedTags.vue';
import VnConfirm from 'components/ui/VnConfirm.vue';
import VnImg from 'components/ui/VnImg.vue';
import { toCurrency, toDate } from 'src/filters';
import axios from 'axios';
import ItemDescriptorProxy from '../Item/Card/ItemDescriptorProxy.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
import FetchData from 'src/components/FetchData.vue';
import VnImg from 'src/components/ui/VnImg.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import FetchedTags from 'src/components/ui/FetchedTags.vue';
import { useStateStore } from 'stores/useStateStore';
const stateStore = useStateStore();
const route = useRoute();
const { t } = useI18n();
const quasar = useQuasar();
const componentKey = ref(0);
const tableLinesRef = ref();
const order = ref();
const refresh = () => {
componentKey.value += 1;
};
const orderSummary = ref({
total: null,
vat: null,
});
const componentKey = ref(0);
const order = ref(0);
const refresh = () => {
componentKey.value += 1;
};
const lineFilter = ref({
include: [
{
relation: 'item',
scope: {
fields: [
'id',
'name',
'subName',
'image',
'tag4',
'value4',
'tag5',
'value5',
'tag6',
'value6',
'tag7',
'value7',
'tag8',
'value8',
'tag9',
'value9',
'tag10',
'value10',
],
},
},
{
relation: 'warehouse',
scope: {
fields: ['id', 'name'],
},
},
],
where: { orderFk: route.params.id },
});
function confirmRemove(item) {
quasar.dialog({
@ -60,53 +97,103 @@ async function confirmOrder() {
});
}
const detailsColumns = ref([
const columns = computed(() => [
{
name: 'img',
label: '',
field: (row) => row?.item?.id,
align: 'center',
label: t('lines.image'),
name: 'image',
columnField: {
component: VnImg,
attrs: (id) => {
return {
id,
width: '50px',
};
},
},
columnFilter: false,
},
{
name: 'item',
label: t('order.summary.item'),
field: (row) => row?.item?.id,
sortable: true,
align: 'left',
name: 'id',
label: t('lines.item'),
chip: {
condition: () => true,
},
isId: true,
},
{
name: 'description',
align: 'left',
name: 'itemFk',
label: t('globals.description'),
field: (row) => row?.item?.name,
isTitle: true,
cardVisible: true,
component: 'select',
attrs: {
url: 'Items',
fields: ['id', 'name', 'subName'],
},
columnField: {
component: null,
},
format: (row) => row?.item?.name,
},
{
name: 'warehouse',
label: t('warehouse'),
field: (row) => row?.warehouse?.name,
sortable: true,
align: 'left',
name: 'warehouseFk',
label: t('lines.warehouse'),
cardVisible: true,
component: 'select',
attrs: {
url: 'Warehouses',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
format: (row) => row?.warehouse?.name,
},
{
align: 'left',
name: 'shipped',
label: t('shipped'),
field: (row) => toDate(row?.shipped),
label: t('lines.shipped'),
cardVisible: true,
component: 'date',
columnField: {
component: null,
},
format: (row) => toDate(row.shipped),
},
{
align: 'left',
name: 'quantity',
label: t('order.summary.quantity'),
field: (row) => row?.quantity,
label: t('lines.quantity'),
},
{
align: 'left',
name: 'price',
label: t('order.summary.price'),
field: (row) => toCurrency(row?.price),
label: t('lines.price'),
cardVisible: true,
format: (row) => toCurrency(row.price),
},
{
align: 'left',
name: 'amount',
label: t('order.summary.amount'),
field: (row) => toCurrency(row?.quantity * row?.price),
label: t('lines.amount'),
format: (row) => toCurrency(row.amount),
},
{
name: 'actions',
align: 'right',
label: '',
field: (row) => row?.id,
name: 'tableActions',
actions: [
{
title: t('delete'),
icon: 'delete',
click: (row) => confirmRemove(row.item),
isPrimary: true,
},
],
},
]);
</script>
@ -130,120 +217,60 @@ const detailsColumns = ref([
@on-fetch="(data) => (orderSummary.vat = data)"
auto-load
/>
<QPage :key="componentKey" class="column items-center q-pa-md">
<div class="order-list full-width">
<div v-if="!orderSummary.total" class="no-result">
{{ t('globals.noResults') }}
</div>
<QDrawer side="right" :width="270" show-if-above>
<QDrawer side="right" :width="270" v-model="stateStore.rightDrawer">
<QCard class="order-lines-summary q-pa-lg">
<p class="header text-right block">
{{ t('summary') }}
</p>
<VnLv
v-if="orderSummary.vat && orderSummary.total"
:label="t('subtotal')"
:label="t('subtotal') + ': '"
:value="toCurrency(orderSummary.total - orderSummary.vat)"
/>
<VnLv
v-if="orderSummary.vat"
:label="t('VAT')"
:label="t('VAT') + ': '"
:value="toCurrency(orderSummary?.vat)"
/>
<VnLv
v-if="orderSummary.total"
:label="t('total')"
:label="t('total') + ': '"
:value="toCurrency(orderSummary?.total)"
/>
</QCard>
</QDrawer>
<VnPaginate
<QPage :key="componentKey" class="column items-center">
<div class="order-list full-width">
<div v-if="!orderSummary.total" class="no-result">
{{ t('globals.noResults') }}
</div>
<VnTable
ref="tableLinesRef"
data-key="OrderLines"
url="OrderRows"
:limit="20"
:columns="columns"
default-mode="table"
:right-search="false"
:use-model="true"
auto-load
:filter="{
include: [
{
relation: 'item',
},
{
relation: 'warehouse',
},
],
where: { orderFk: route.params.id },
}"
:user-filter="lineFilter"
>
<template #body="{ rows }">
<div class="q-pa-md">
<QTable
:columns="detailsColumns"
:rows="rows"
flat
class="full-width"
style="text-align: center"
>
<template #header="props">
<QTr class="tr-header" :props="props">
<QTh
v-for="col in props.cols"
:key="col.name"
:props="props"
style="text-align: center"
>
{{ t(col.label) }}
</QTh>
</QTr>
</template>
<template #body-cell-img="{ value }">
<QTd>
<template #column-image="{ row }">
<div class="image-wrapper">
<VnImg :id="value" class="rounded" />
<VnImg :id="parseInt(row?.item?.image)" class="rounded" />
</div>
</QTd>
</template>
<template #body-cell-item="{ value }">
<QTd class="item">
<span class="link">
<QBtn flat>
{{ value }}
</QBtn>
<ItemDescriptorProxy :id="value" />
</span>
</QTd>
</template>
<template #body-cell-description="{ row, value }">
<QTd>
<div
class="row column full-width justify-between items-start"
>
{{ value }}
<div v-if="value" class="subName">
{{ value.toUpperCase() }}
</div>
</div>
<FetchedTags :item="row.item" :max-length="6" />
</QTd>
</template>
<template #body-cell-actions="{ value }">
<QTd>
<QIcon
name="delete"
color="primary"
size="sm"
class="cursor-pointer"
@click.stop="confirmRemove(value)"
>
<QTooltip>{{ t('Remove thermograph') }}</QTooltip>
</QIcon>
</QTd>
</template>
</QTable>
<template #column-itemFk="{ row }">
<div class="row column full-width justify-between items-start">
{{ row?.item?.name }}
<div v-if="row?.item?.subName" class="subName">
{{ row?.item?.subName.toUpperCase() }}
</div>
</div>
<FetchedTags :item="row?.item" :max-length="6" />
</template>
</VnPaginate>
</VnTable>
</div>
<QPageSticky :offset="[20, 20]" v-if="!order?.isConfirmed">
<QBtn fab icon="check" color="primary" @click="confirmOrder()" />
@ -253,7 +280,8 @@ const detailsColumns = ref([
</QPageSticky>
</QPage>
</template>
<style lang="scss">
<style lang="scss" scoped>
.order-lines-summary {
.vn-label-value {
display: flex;
@ -274,8 +302,13 @@ const detailsColumns = ref([
}
}
}
</style>
<style lang="scss" scoped>
.image-wrapper {
height: 50px;
width: 50px;
margin-left: 30%;
}
.header {
color: $primary;
font-weight: bold;
@ -284,12 +317,6 @@ const detailsColumns = ref([
display: inline-block;
}
.image-wrapper {
height: 50px;
width: 50px;
margin-left: 30%;
}
.no-result {
font-size: 24px;
font-weight: bold;
@ -302,6 +329,7 @@ const detailsColumns = ref([
color: var(--vn-label-color);
}
</style>
<i18n>
en:
summary: Summary

View File

@ -1,30 +1,135 @@
<script setup>
import axios from 'axios';
import { useI18n } from 'vue-i18n';
import { onMounted, onUnmounted } from 'vue';
import { useRouter } from 'vue-router';
import { useStateStore } from 'stores/useStateStore';
import { toCurrency, toDate } from 'src/filters';
import CardList from 'components/ui/CardList.vue';
import WorkerDescriptorProxy from 'pages/Worker/Card/WorkerDescriptorProxy.vue';
import CustomerDescriptorProxy from 'pages/Customer/Card/CustomerDescriptorProxy.vue';
import VnPaginate from 'components/ui/VnPaginate.vue';
import VnLv from 'components/ui/VnLv.vue';
import { computed, ref } from 'vue';
import { dashIfEmpty, toCurrency, toDate } from 'src/filters';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import OrderFilter from 'pages/Order/Card/OrderFilter.vue';
import OrderSummary from 'pages/Order/Card/OrderSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import RightMenu from 'src/components/common/RightMenu.vue';
import VnTable from 'src/components/VnTable/VnTable.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
const stateStore = useStateStore();
const router = useRouter();
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
const tableRef = ref();
const clientList = ref([]);
const agencyList = ref([]);
const selectedAddress = ref();
onMounted(() => (stateStore.rightDrawer = true));
onUnmounted(() => (stateStore.rightDrawer = false));
const columns = computed(() => [
{
align: 'left',
name: 'id',
label: t('module.id'),
chip: {
condition: () => true,
},
isId: true,
},
{
align: 'left',
name: 'clientName',
label: t('module.customer'),
isTitle: true,
cardVisible: true,
component: 'select',
attrs: {
url: 'Clients',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
},
{
align: 'left',
name: 'name',
label: t('module.salesPerson'),
component: 'select',
attrs: {
url: 'Workers/activeWithInheritedRole',
fields: ['id', 'name'],
where: { role: 'salesPerson' },
},
columnField: {
component: null,
},
},
{
align: 'left',
name: 'isConfirmed',
label: t('module.isConfirmed'),
},
{
align: 'left',
name: 'created',
label: t('module.created'),
component: 'date',
cardVisible: true,
format: (row) => toDate(row?.landed),
columnField: {
component: null,
},
},
{
align: 'left',
name: 'landed',
label: t('module.landed'),
component: 'date',
format: (row) => toDate(row?.landed),
columnField: {
component: null,
},
style: 'color="positive"',
},
{
align: 'left',
name: 'hour',
label: t('module.hour'),
format: ({ hourTheoretical, hourEffective }) =>
dashIfEmpty(hourTheoretical || hourEffective),
},
{
align: 'left',
name: 'agencyName',
label: t('module.agency'),
component: 'select',
cardVisible: true,
attrs: {
url: 'Agencies',
fields: ['id', 'name'],
},
columnField: {
component: null,
},
},
{
align: 'left',
name: 'total',
label: t('module.total'),
format: ({ total }) => toCurrency(total),
cardVisible: true,
},
{
align: 'right',
label: '',
name: 'tableActions',
actions: [
{
title: t('InvoiceOutSummary'),
icon: 'preview',
action: (row) => viewSummary(row.id, OrderSummary),
},
],
},
]);
function navigate(id) {
router.push({ path: `/order/${id}` });
async function fetchClientAddress(id, data) {
console.log('data: ', data);
const clientData = await axios.get(`Clients/${id}`);
selectedAddress.value = clientData.data.defaultAddressFk;
data.addressId = selectedAddress.value;
}
</script>
<template>
@ -33,100 +138,53 @@ function navigate(id) {
:label="t('Search order')"
:info="t('You can search orders by reference')"
/>
<RightMenu>
<template #right-panel>
<OrderFilter data-key="OrderList" />
</template>
</RightMenu>
<QPage class="column items-center q-pa-md">
<div class="vn-card-list">
<VnPaginate
<VnTable
ref="tableRef"
data-key="OrderList"
url="Orders/filter"
:limit="20"
:order="['landed DESC', 'clientFk', 'id DESC']"
:user-params="{ showEmpty: false }"
:keep-opts="['userParams']"
:create="{
urlCreate: 'Orders/new',
title: 'Create Order',
onDataSaved: (url) => {
tableRef.redirect(url);
},
formInitialData: {
active: true,
addressId: null,
},
}"
:columns="columns"
default-mode="table"
redirect="order"
auto-load
>
<template #body="{ rows }">
<CardList
v-for="row of rows"
:key="row.id"
:id="row.id"
:title="`${row?.clientName} (${row?.clientFk})`"
@click="navigate(row.id)"
>
<template #list-items>
<VnLv
:label="t('order.field.salesPersonFk')"
:title-label="t('order.field.salesPersonFk')"
>
<template #value>
<span class="link" @click.stop>
{{ row?.name || '-' }}
<WorkerDescriptorProxy :id="row?.salesPersonFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('order.field.clientFk')"
:title-label="t('order.field.clientFk')"
>
<template #value>
<span class="link" @click.stop>
{{ row?.clientName || '-' }}
<CustomerDescriptorProxy :id="row?.clientFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('order.field.isConfirmed')"
:value="row?.isConfirmed === 1"
<template #more-create-dialog="{ data }">
<VnSelect
url="Clients"
v-model="data.id"
:label="t('module.customer')"
:options="clientList"
option-value="id"
option-label="name"
@update:model-value="(id) => fetchClientAddress(id, data)"
/>
<VnLv
:label="t('order.field.created')"
:value="toDate(row?.created)"
<VnSelect
url="Clients"
v-model="selectedAddress"
:label="t('module.address')"
:options="selectedAddress"
option-value="defaultAddressFk"
option-label="street"
/>
<VnLv :label="t('order.field.landed')">
<template #value>
<QBadge text-color="black" color="positive" dense>
{{ toDate(row?.landed) }}
</QBadge>
</template>
</VnLv>
<VnLv
:label="t('order.field.hour')"
:value="row.hourTheoretical || row.hourEffective"
/>
<VnLv
:label="t('order.field.agency')"
:value="row?.agencyName"
/>
<VnLv
:label="t('order.field.total')"
:value="toCurrency(row?.total)"
<VnInputDate v-model="data.landed" :label="t('module.landed')" />
<VnSelect
url="Agencies"
v-model="data.agencyModeId"
:label="t('module.agency')"
:options="agencyList"
option-value="id"
option-label="name"
/>
</template>
<template #actions>
<QBtn
:label="t('components.smartCard.openSummary')"
@click.stop="viewSummary(row.id, OrderSummary)"
color="primary"
style="margin-top: 15px"
/>
</template>
</CardList>
</template>
</VnPaginate>
</div>
<QPageSticky :offset="[20, 20]">
<RouterLink :to="{ name: 'OrderCreate' }">
<QBtn fab icon="add" color="primary" />
<QTooltip>
{{ t('order.list.newOrder') }}
</QTooltip>
</RouterLink>
</QPageSticky>
</QPage>
</VnTable>
</template>

View File

@ -0,0 +1,22 @@
module:
id: ID
name: Name
customer: Client
isConfirmed: Confirmed
created: Created
landed: Landed
hour: Hour
agency: Agency
total: Total
salesPerson: Sales Person
address: Address
lines:
item: Item
warehouse: Warehouse
shipped: Shipped
quantity: Quantity
price: Price
amount: Amount
image: Image
params:
tagGroups: Tags

View File

@ -0,0 +1,22 @@
module:
id: ID
name: Nombre
customer: Cliente
isConfirmed: Confirmado
created: Creado
landed: F. Entrega
hour: Hora
agency: Agencia
total: Total
salesPerson: Comercial
address: Dirección
lines:
item: Artículo
warehouse: Almacén
shipped: Envío
quantity: Cantidad
price: Precio
amount: Importe
image: Imagen
params:
tagGroups: Tags

View File

@ -515,8 +515,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
</QBtnGroup>
</template>
</VnSubToolbar>
<RightMenu>
<template #right-panel>
<QDrawer side="right" :width="270" v-model="stateStore.rightDrawer">
<div
class="q-pa-md q-mb-md q-ma-md color-vn-text"
style="border: 2px solid black"
@ -528,9 +527,7 @@ onUnmounted(() => (stateStore.rightDrawer = false));
<span>{{ toCurrency(store.data?.totalWithoutVat) }}</span>
</QCardSection>
<QCardSection class="justify-center text-subtitle1" horizontal>
<span class="q-mr-xs color-vn-label">
{{ t('ticketSale.tax') }}:
</span>
<span class="q-mr-xs color-vn-label"> {{ t('ticketSale.tax') }}: </span>
<span>{{
toCurrency(store.data?.totalWithVat - store.data?.totalWithoutVat)
}}</span>
@ -539,14 +536,11 @@ onUnmounted(() => (stateStore.rightDrawer = false));
class="justify-center text-weight-bold text-subtitle1"
horizontal
>
<span class="q-mr-xs color-vn-label">
{{ t('ticketSale.total') }}:
</span>
<span class="q-mr-xs color-vn-label"> {{ t('ticketSale.total') }}: </span>
<span>{{ toCurrency(store.data?.totalWithVat) }}</span>
</QCardSection>
</div>
</template>
</RightMenu>
</div></QDrawer
>
<QTable
:rows="sales"
:columns="columns"

View File

@ -37,7 +37,7 @@ export default {
title: 'orderCreate',
icon: 'add',
},
component: () => import('src/pages/Order/Card/OrderForm.vue'),
component: () => import('src/pages/Order/OrderList.vue'),
},
],
},