#6942 improve invoiceIn #220

Merged
jorgep merged 63 commits from 6942-improveInvoceIn into dev 2024-05-29 07:03:46 +00:00
13 changed files with 292 additions and 210 deletions
Showing only changes of commit 0fd83cf435 - Show all commits

View File

@ -96,8 +96,7 @@ onMounted(async () => {
});
onBeforeRouteLeave((to, from, next) => {
if (!hasChanges.value) next();
if (hasChanges.value) {
quasar.dialog({
component: VnConfirm,
componentProps: {
@ -106,6 +105,7 @@ onBeforeRouteLeave((to, from, next) => {
promise: () => next(),
},
});
} else next();
});
onUnmounted(() => {
Review

Lo he pasado aquí para que todos los hooks estén agrupados.

Lo he pasado aquí para que todos los hooks estén agrupados.

View File

@ -698,6 +698,7 @@ export default {
intrastat: 'Intrastat',
corrective: 'Corrective',
log: 'Logs',
create: 'Create',
},
list: {
ref: 'Reference',

View File

@ -756,6 +756,7 @@ export default {
intrastat: 'Intrastat',
corrective: 'Rectificativa',
log: 'Registros de auditoría',
create: 'Crear',
},
list: {
ref: 'Referencia',

View File

@ -1,6 +1,6 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
@ -10,9 +10,12 @@ import FormModel from 'components/FormModel.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import FetchData from 'src/components/FetchData.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInput from 'src/components/common/VnInput.vue';
const quasar = useQuasar();
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const dms = ref({});
@ -32,14 +35,11 @@ const warehouses = ref([]);
const warehousesRef = ref();
const allowTypesRef = ref();
const allowedContentTypes = ref([]);
const sageWithholdings = ref([]);
const inputFileRef = ref();
const editDmsRef = ref();
const createDmsRef = ref();
const requiredFieldRule = (val) => val || t('globals.requiredField');
const dateMask = '####-##-##';
const fillMask = '_';
async function checkFileExists(dmsId) {
if (!dmsId) return;
try {
@ -175,11 +175,19 @@ async function upsert() {
auto-load
/>
<FetchData url="Expenses" auto-load @on-fetch="(data) => (expenses = data)" />
<FetchData
url="SageWithholdings"
auto-load
@on-fetch="(data) => (sageWithholdings = data)"
/>
<FormModel
v-if="invoiceIn"
:url="`InvoiceIns/${route.params.id}`"
model="invoiceIn"
:auto-load="true"
auto-load
@on-data-saved="
router.push({ name: 'InvoiceInVat', params: { id: route.params.id } })
"
>
<template #form="{ data }">
<VnRow>
@ -203,7 +211,7 @@ async function upsert() {
</QItem>
</template>
</VnSelectFilter>
<QInput
<VnInput
clearable
clear-icon="close"
:label="t('Supplier ref')"
@ -211,60 +219,12 @@ async function upsert() {
/>
</VnRow>
<VnRow>
<QInput
:label="t('Expedition date')"
v-model="data.issued"
:mask="dateMask"
>
<template #append>
<QIcon name="event" class="cursor-pointer" :fill-mask="fillMask">
<QPopupProxy
cover
transition-show="scale"
transition-hide="scale"
>
<QDate v-model="data.issued">
<div class="row items-center justify-end">
<QBtn
v-close-popup
label="Close"
color="primary"
flat
/>
</div>
</QDate>
</QPopupProxy>
</QIcon>
</template>
</QInput>
<QInput
<VnInputDate :label="t('Expedition date')" v-model="data.issued" />
<VnInputDate
:label="t('Operation date')"
v-model="data.operated"
:mask="dateMask"
:fill-mask="fillMask"
autofocus
>
<template #append>
<QIcon name="event" class="cursor-pointer">
<QPopupProxy
cover
transition-show="scale"
transition-hide="scale"
>
<QDate v-model="data.operated" :mask="dateMask">
<div class="row items-center justify-end">
<QBtn
v-close-popup
label="Close"
color="primary"
flat
/>
</div>
</QDate>
</QPopupProxy>
</QIcon>
</template>
</QInput>
</VnRow>
<VnRow>
<VnSelectFilter
@ -281,8 +241,7 @@ async function upsert() {
</QItem>
</template>
</VnSelectFilter>
<QInput
<VnInput
:label="t('Document')"
v-model="data.dmsFk"
clearable
@ -327,68 +286,11 @@ async function upsert() {
<QTooltip>{{ t('Create document') }}</QTooltip>
</QBtn>
</template>
</QInput>
</VnInput>
</VnRow>
<VnRow>
<QInput
:label="t('Entry date')"
v-model="data.bookEntried"
clearable
clear-icon="close"
:mask="dateMask"
:fill-mask="fillMask"
>
<template #append>
<QIcon name="event" class="cursor-pointer">
<QPopupProxy
cover
transition-show="scale"
transition-hide="scale"
>
<QDate v-model="data.bookEntried" :mask="dateMask">
<div class="row items-center justify-end">
<QBtn
v-close-popup
label="Close"
color="primary"
flat
/>
</div>
</QDate>
</QPopupProxy>
</QIcon>
</template>
</QInput>
<QInput
:label="t('Accounted date')"
v-model="data.booked"
clearable
clear-icon="close"
:mask="dateMask"
:fill-mask="fillMask"
>
<template #append>
<QIcon name="event" class="cursor-pointer">
<QPopupProxy
cover
transition-show="scale"
transition-hide="scale"
>
<QDate v-model="data.booked" :mask="maskDate">
<div class="row items-center justify-end">
<QBtn
v-close-popup
label="Close"
color="primary"
flat
/>
</div>
</QDate>
</QPopupProxy>
</QIcon>
</template>
</QInput>
<VnInputDate :label="t('Entry date')" v-model="data.bookEntried" />
<VnInputDate :label="t('Accounted date')" v-model="data.booked" />
</VnRow>
<VnRow>
<VnSelectFilter
@ -409,10 +311,19 @@ async function upsert() {
/>
</VnRow>
<VnRow>
<VnSelectFilter
:label="t('invoiceIn.summary.sage')"
v-model="data.withholdingSageFk"
:options="sageWithholdings"
option-value="id"
option-label="withholding"
/>
<span>
<QCheckbox
:label="t('invoiceIn.summary.booked')"
v-model="data.isBooked"
/>
</span>
</VnRow>
</template>
</FormModel>
@ -429,7 +340,7 @@ async function upsert() {
</QCardSection>
<QCardSection class="q-py-none">
<QItem>
<QInput
<VnInput
class="full-width q-pa-xs"
:label="t('Reference')"
v-model="dms.reference"
@ -438,45 +349,45 @@ async function upsert() {
/>
<VnSelectFilter
class="full-width q-pa-xs"
:label="`${t('Company')}*`"
:label="t('Company')"
v-model="dms.companyId"
:options="companies"
option-value="id"
option-label="code"
:rules="[requiredFieldRule]"
:required="true"
/>
</QItem>
<QItem>
<VnSelectFilter
class="full-width q-pa-xs"
:label="`${t('Warehouse')}*`"
:label="t('Warehouse')"
v-model="dms.warehouseId"
:options="warehouses"
option-value="id"
option-label="name"
:rules="[requiredFieldRule]"
:required="true"
/>
<VnSelectFilter
class="full-width q-pa-xs"
:label="`${t('Type')}*`"
:label="t('Type')"
v-model="dms.dmsTypeId"
:options="dmsTypes"
option-value="id"
option-label="name"
:rules="[requiredFieldRule]"
:required="true"
/>
</QItem>
<QItem>
<QInput
class="full-width q-pa-xs"
<VnInput
:label="t('Description')"
v-model="dms.description"
:required="true"
type="textarea"
class="full-width q-pa-xs"
size="lg"
autogrow
:label="`${t('Description')}*`"
v-model="dms.description"
clearable
clear-icon="close"
:rules="[(val) => val.length || t('Required field')]"
/>
</QItem>
<QItem>
@ -540,7 +451,7 @@ async function upsert() {
</QCardSection>
<QCardSection class="q-pb-none">
<QItem>
<QInput
<VnInput
class="full-width q-pa-xs"
:label="t('Reference')"
v-model="dms.reference"
@ -552,7 +463,7 @@ async function upsert() {
:options="companies"
option-value="id"
option-label="code"
:rules="[requiredFieldRule]"
:required="true"
/>
</QItem>
<QItem>
@ -563,7 +474,7 @@ async function upsert() {
:options="warehouses"
option-value="id"
option-label="name"
:rules="[requiredFieldRule]"
:required="true"
/>
<VnSelectFilter
class="full-width q-pa-xs"
@ -572,11 +483,11 @@ async function upsert() {
:options="dmsTypes"
option-value="id"
option-label="name"
:rules="[requiredFieldRule]"
:required="true"
/>
</QItem>
<QItem>
<QInput
<VnInput
class="full-width q-pa-xs"
type="textarea"
size="lg"

View File

@ -28,15 +28,10 @@ const filter = {
},
},
},
{
relation: 'invoiceInDueDay',
},
{
relation: 'company',
},
{
relation: 'currency',
},
{ relation: 'invoiceInDueDay' },
{ relation: 'company' },
{ relation: 'currency' },
{ relation: 'sageWithholding' },
],
};
const arrayData = useArrayData('InvoiceIn', {
@ -47,7 +42,7 @@ const arrayData = useArrayData('InvoiceIn', {
onMounted(async () => await arrayData.fetch({ append: false }));
watch(
() => route.params.id,
async (newId, oldId) => {
async (newId) => {
if (newId) {
arrayData.store.url = `InvoiceIns/${newId}`;
await arrayData.fetch({ append: false });

View File

@ -17,6 +17,7 @@ import SendEmailDialog from 'components/common/SendEmailDialog.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import { useCapitalize } from 'src/composables/useCapitalize';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
const $props = defineProps({
id: {
@ -408,10 +409,14 @@ const createInvoiceInCorrection = async () => {
<VnLv :label="t('invoiceIn.card.issued')" :value="toDate(entity.issued)" />
<VnLv :label="t('invoiceIn.summary.booked')" :value="toDate(entity.booked)" />
<VnLv :label="t('invoiceIn.card.amount')" :value="toCurrency(totalAmount)" />
<VnLv
:label="t('invoiceIn.summary.supplier')"
:value="entity.supplier?.nickname"
/>
<VnLv :label="t('invoiceIn.summary.supplier')">
<template #value>
<span class="link">
{{ invoiceIn?.supplier?.nickname }}
<SupplierDescriptorProxy :id="invoiceIn?.supplierFk" />
</span>
</template>
</VnLv>
</template>
<template #actions="{ entity }">
<QCardActions>

View File

@ -9,6 +9,7 @@ import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue';
import { toCurrency } from 'src/filters';
const route = useRoute();
const { t } = useI18n();
@ -73,6 +74,7 @@ async function insert() {
await axios.post('/InvoiceInDueDays/new ', { id: +invoiceId });
await invoiceInFormRef.value.reload();
}
const getTotalAmount = (rows) => rows.reduce((acc, cur) => acc + cur.amount, 0);
</script>
<template>
<FetchData url="Banks" auto-load limit="30" @on-fetch="(data) => (banks = data)" />
@ -180,6 +182,17 @@ async function insert() {
/>
</QTd>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd />
<QTd />
<QTd />
<QTd>
jorgep marked this conversation as resolved
Review

http://localhost:9000/#/invoice-in/4/due-day al entrar en esta seccion me dice Access Denied en ingles con developer, cuando en realidad esta seccion la deben de poder usar el rol administrative.

http://localhost:9000/#/invoice-in/4/due-day al entrar en esta seccion me dice Access Denied en ingles con developer, cuando en realidad esta seccion la deben de poder usar el rol administrative.
Review

A mi no me da ningún fallo . Compruebalo de nuevo y me dices.

A mi no me da ningún fallo . Compruebalo de nuevo y me dices.
Review

No me da fallo.
Pregunta: la fecha y el placeholder está como yyyy/mm/dd, es correcto?

No me da fallo. Pregunta: la fecha y el placeholder está como yyyy/mm/dd, es correcto?
Review

@jsegarra Ahora se usa VnInputDate.

@jsegarra Ahora se usa VnInputDate.
{{ toCurrency(getTotalAmount(rows)) }}
</QTd>
<QTd />
</QTr>
</template>
<template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
<QCard>

View File

@ -6,6 +6,7 @@ import { toCurrency, toDate } from 'src/filters';
import { getUrl } from 'src/composables/getUrl';
import CardSummary from 'components/ui/CardSummary.vue';
import VnLv from 'src/components/ui/VnLv.vue';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
onMounted(async () => {
salixUrl.value = await getUrl('');
@ -217,7 +218,14 @@ function getLink(param) {
<VnLv
:label="t('invoiceIn.summary.supplier')"
:value="invoiceIn.supplier?.name"
/>
>
<template #value>
<span class="link">
{{ invoiceIn.supplier?.name }}
<SupplierDescriptorProxy :id="invoiceIn.supplierFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('invoiceIn.summary.supplierRef')"
:value="invoiceIn.supplierRef"
@ -282,21 +290,14 @@ function getLink(param) {
</QCard>
<QCard class="vn-one">
<QCardSection class="q-pa-none">
<a class="header" :href="getLink('basic-data')">
{{ t('invoiceIn.pageTitles.basicData') }}
<QIcon name="open_in_new" color="primary" />
</a>
<span class="header">{{ t('Totals') }}</span>
</QCardSection>
<QCardSection class="q-pa-none">
<div class="bordered q-px-sm q-mx-auto">
<VnLv
:label="t('invoiceIn.summary.taxableBase')"
:value="toCurrency(invoiceIn.totals.totalTaxableBase)"
/>
<VnLv
label="Total"
:value="toCurrency(invoiceIn.totals.totalVat)"
/>
<VnLv label="Total" :value="toCurrency(invoiceIn.totals.totalVat)" />
<VnLv :label="t('invoiceIn.summary.dueTotal')">
<template #value>
<QChip
@ -313,11 +314,10 @@ function getLink(param) {
</QChip>
</template>
</VnLv>
</div>
</QCardSection>
</QCard>
<!--Vat-->
<QCard v-if="invoiceIn.invoiceInTax.length">
<QCard v-if="invoiceIn.invoiceInTax.length" class="vn-two">
<a class="header" :href="getLink('vat')">
{{ t('invoiceIn.card.vat') }}
<QIcon name="open_in_new" color="primary" />
@ -350,7 +350,7 @@ function getLink(param) {
</QTable>
</QCard>
<!--Due Day-->
<QCard v-if="invoiceIn.invoiceInDueDay.length">
<QCard v-if="invoiceIn.invoiceInDueDay.length" class="vn-one">
<a class="header" :href="getLink('due-day')">
{{ t('invoiceIn.card.dueDay') }}
<QIcon name="open_in_new" color="primary" />
@ -416,13 +416,16 @@ function getLink(param) {
.bg {
background-color: var(--vn-light-gray);
}
.bordered {
border: 1px solid var(--vn-text);
max-width: 18em;
@media (max-width: $breakpoint-md) {
.cardSummary .summaryBody > .q-card.vn-two {
flex: 100%;
}
}
</style>
<i18n>
es:
Search invoice: Buscar factura recibida
You can search by invoice reference: Puedes buscar por referencia de la factura
Totals: Totales
</i18n>

View File

@ -1,6 +1,6 @@
<script setup>
import { ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
@ -12,6 +12,7 @@ import CrudModel from 'src/components/CrudModel.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue';
const route = useRoute();
const router = useRouter();
const { t } = useI18n();
const quasar = useQuasar();
@ -154,6 +155,7 @@ async function addExpense() {
});
}
}
const getTotalTaxableBase = (rows) => rows.reduce((acc, cur) => acc + cur.taxableBase, 0);
</script>
<template>
<FetchData
@ -177,6 +179,9 @@ async function addExpense() {
:data-required="{ invoiceInFk: route.params.id }"
auto-load
v-model:selected="rowsSelected"
@save-changes="
router.push({ name: 'InvoiceInDueDay', params: { id: route.params.id } })
"
>
<template #body="{ rows }">
<QTable
@ -299,6 +304,19 @@ async function addExpense() {
/>
</QTd>
</template>
<template #bottom-row>
<QTr class="bg">
<QTd />
<QTd />
<QTd>
{{ toCurrency(getTotalTaxableBase(rows)) }}
</QTd>
<QTd />
<QTd />
<QTd />
<QTd />
</QTr>
jorgep marked this conversation as resolved
Review

En esta seccion en los desplegables Sage iva, transactionTypeSageFk no quieren ver la descripcion solo la clave primaria de la tabla. si despliegan veran el valor

En esta seccion en los desplegables Sage iva, transactionTypeSageFk no quieren ver la descripcion solo la clave primaria de la tabla. si despliegan veran el valor
</template>
<template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 grid-style-transition">
<QCard bordered flat class="q-my-xs">

View File

@ -0,0 +1,123 @@
<script setup>
import { reactive, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import FormModel from 'components/FormModel.vue';
import VnRow from 'components/ui/VnRow.vue';
import VnSelectFilter from 'src/components/common/VnSelectFilter.vue';
import FetchData from 'components/FetchData.vue';
import VnSubToolbar from 'src/components/ui/VnSubToolbar.vue';
import VnSearchbar from 'src/components/ui/VnSearchbar.vue';
import { useStateStore } from 'stores/useStateStore';
import { useState } from 'src/composables/useState';
import VnInputDate from 'src/components/common/VnInputDate.vue';
import VnInput from 'src/components/common/VnInput.vue';
const state = useState();
const { t } = useI18n();
const route = useRoute();
const router = useRouter();
const stateStore = useStateStore();
const user = state.getUser();
const newInvoiceIn = reactive({
supplierFk: +route.query?.supplierFk || null,
supplierRef: null,
companyFk: user.value.companyFk || null,
issued: Date.vnNew(),
});
const suppliersOptions = ref([]);
const companiesOptions = ref([]);
const redirectToInvoiceInBasicData = (_, { id }) =>
router.push({ name: 'InvoiceInBasicData', params: { id } });
</script>
<template>
<FetchData
url="Suppliers"
:filter="{ fields: ['id', 'nickname'] }"
order="nickname"
@on-fetch="(data) => (suppliersOptions = data)"
auto-load
/>
<FetchData
ref="companiesRef"
url="Companies"
:filter="{ fields: ['id', 'code'] }"
order="code"
@on-fetch="(data) => (companiesOptions = data)"
auto-load
/>
<template v-if="stateStore.isHeaderMounted()">
<Teleport to="#searchbar">
<VnSearchbar
custom-route-redirect-name="InvoiceInSummary"
data-key="InvoiceInSummary"
/>
</Teleport>
</template>
<QPage>
<VnSubToolbar />
<FormModel
url-create="InvoiceIns"
model="Invoice"
:form-initial-data="newInvoiceIn"
@on-data-saved="redirectToInvoiceInBasicData"
>
<template #form="{ data, validate }">
<VnRow>
<VnSelectFilter
:label="t('Supplier')"
v-model="data.supplierFk"
:options="suppliersOptions"
option-value="id"
option-label="nickname"
hide-selected
:required="true"
:rules="validate('entry.supplierFk')"
>
<template #option="scope">
<QItem v-bind="scope.itemProps">
<QItemSection>
<QItemLabel>{{ scope.opt?.nickname }}</QItemLabel>
<QItemLabel caption>
#{{ scope.opt?.id }}
</QItemLabel>
</QItemSection>
</QItem>
</template>
</VnSelectFilter>
<VnInput
:label="t('invoiceIn.summary.supplierRef')"
v-model="data.supplierRef"
/>
</VnRow>
<VnRow>
<VnSelectFilter
:label="t('Company')"
v-model="data.companyFk"
:options="companiesOptions"
option-value="id"
option-label="code"
map-options
hide-selected
:required="true"
:rules="validate('invoiceIn.companyFk')"
/>
<VnInputDate
:label="t('invoiceIn.summary.issued')"
v-model="data.issued"
/>
</VnRow>
</template>
</FormModel>
</QPage>
</template>
<i18n>
es:
Supplier: Proveedor
Travel: Envío
Company: Empresa
</i18n>

View File

@ -13,6 +13,7 @@ import InvoiceInFilter from './InvoiceInFilter.vue';
import { getUrl } from 'src/composables/getUrl';
import InvoiceInSummary from './Card/InvoiceInSummary.vue';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
const stateStore = useStateStore();
const router = useRouter();
@ -85,7 +86,15 @@ function navigate(id) {
<VnLv
:label="t('invoiceIn.list.supplier')"
:value="row.supplierName"
/>
@click.stop
>
<template #value>
<span class="link">
{{ row.supplierName }}
<SupplierDescriptorProxy :id="row.supplierFk" />
</span>
</template>
</VnLv>
<VnLv
:label="t('invoiceIn.list.serialNumber')"
:value="row.serialNumber"
@ -138,13 +147,7 @@ function navigate(id) {
</div>
</QPage>
<QPageSticky position="bottom-right" :offset="[20, 20]">
<QBtn
color="primary"
icon="add"
size="lg"
round
:href="`${url}invoice-in/create`"
/>
<QBtn color="primary" icon="add" size="lg" round :href="`/#/invoice-in/create`" />
</QPageSticky>
</template>

View File

@ -178,7 +178,7 @@ const getEntryQueryParams = (supplier) => {
<QTooltip>{{ t('Go to client') }}</QTooltip>
</QBtn>
<QBtn
:href="`${url}invoice-in/create?supplierFk=${entity.id}`"
:href="`#/invoice-in/create?supplierFk=${entity.id}`"
size="md"
icon="vn:invoice-in-create"
color="primary"

View File

@ -36,6 +36,15 @@ export default {
},
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
},
{
path: 'create',
name: 'InvoiceInCreate',
meta: {
title: 'create',
icon: 'vn:settings',
},
component: () => import('src/pages/InvoiceIn/InvoiceInCreate.vue'),
},
],
},
{