+
@@ -19,7 +19,4 @@ const $props = defineProps({
a {
font-size: large;
}
-.titleBox {
- padding-bottom: 2%;
-}
diff --git a/src/components/ui/CardDescriptor.vue b/src/components/ui/CardDescriptor.vue
index d2ba21888..0e74016cd 100644
--- a/src/components/ui/CardDescriptor.vue
+++ b/src/components/ui/CardDescriptor.vue
@@ -5,6 +5,7 @@ import SkeletonDescriptor from 'components/ui/SkeletonDescriptor.vue';
import { useArrayData } from 'composables/useArrayData';
import { useSummaryDialog } from 'src/composables/useSummaryDialog';
import { useState } from 'src/composables/useState';
+import { useRoute } from 'vue-router';
const $props = defineProps({
url: {
@@ -15,21 +16,21 @@ const $props = defineProps({
type: Object,
default: null,
},
- module: {
- type: String,
- required: true,
- },
title: {
type: String,
default: '',
},
subtitle: {
type: Number,
- default: 0,
+ default: null,
},
dataKey: {
type: String,
- default: '',
+ default: null,
+ },
+ module: {
+ type: String,
+ default: null,
},
summary: {
type: Object,
@@ -40,21 +41,27 @@ const $props = defineProps({
const state = useState();
const { t } = useI18n();
const { viewSummary } = useSummaryDialog();
-const arrayData = useArrayData($props.dataKey || $props.module, {
- url: $props.url,
- filter: $props.filter,
- skip: 0,
-});
-const { store } = arrayData;
-const entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
+let arrayData;
+let store;
+let entity;
const isLoading = ref(false);
-defineExpose({
- getData,
-});
+defineExpose({ getData });
+
onBeforeMount(async () => {
- await getData();
- watch($props, async () => await getData());
+ arrayData = useArrayData($props.dataKey, {
+ url: $props.url,
+ filter: $props.filter,
+ skip: 0,
+ });
+ store = arrayData.store;
+ entity = computed(() => (Array.isArray(store.data) ? store.data[0] : store.data));
+ // It enables to load data only once if the module is the same as the dataKey
+ if ($props.dataKey !== useRoute().meta.moduleName) await getData();
+ watch(
+ () => [$props.url, $props.filter],
+ async () => await getData()
+ );
});
async function getData() {
@@ -132,7 +139,7 @@ const emit = defineEmits(['onFetch']);
- {{ $props.title }}
+ {{ entity[title] ?? $props.title }}
diff --git a/src/components/ui/VnSearchbar.vue b/src/components/ui/VnSearchbar.vue
index 38dcf97d1..e5b2f02d2 100644
--- a/src/components/ui/VnSearchbar.vue
+++ b/src/components/ui/VnSearchbar.vue
@@ -1,5 +1,5 @@
-import { ref, reactive, computed, onBeforeMount, watch } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
+import { ref, reactive, computed, onBeforeMount } from 'vue';
+import { useRouter, onBeforeRouteLeave } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import axios from 'axios';
import { toCurrency, toDate } from 'src/filters';
import { useRole } from 'src/composables/useRole';
-import useCardDescription from 'src/composables/useCardDescription';
import { downloadFile } from 'src/composables/downloadFile';
import { useArrayData } from 'src/composables/useArrayData';
import { usePrintService } from 'composables/usePrintService';
@@ -17,27 +16,23 @@ import SendEmailDialog from 'components/common/SendEmailDialog.vue';
import VnConfirm from 'src/components/ui/VnConfirm.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import { useCapitalize } from 'src/composables/useCapitalize';
+import SupplierDescriptorProxy from 'src/pages/Supplier/Card/SupplierDescriptorProxy.vue';
+import InvoiceInToBook from '../InvoiceInToBook.vue';
-const $props = defineProps({
- id: {
- type: Number,
- required: false,
- default: null,
- },
-});
+const $props = defineProps({ id: { type: Number, default: null } });
+
+const { push, currentRoute } = useRouter();
-const route = useRoute();
-const router = useRouter();
const quasar = useQuasar();
const { hasAny } = useRole();
const { t } = useI18n();
const { openReport, sendEmail } = usePrintService();
-const arrayData = useArrayData('InvoiceIn');
+const { store } = useArrayData(currentRoute.value.meta.moduleName);
-const invoiceIn = computed(() => arrayData.store.data);
+const invoiceIn = computed(() => store.data);
const cardDescriptorRef = ref();
const correctionDialogRef = ref();
-const entityId = computed(() => $props.id || +route.params.id);
+const entityId = computed(() => $props.id || +currentRoute.value.params.id);
const totalAmount = ref();
const currentAction = ref();
const config = ref();
@@ -45,28 +40,21 @@ const cplusRectificationTypes = ref([]);
const siiTypeInvoiceOuts = ref([]);
const invoiceCorrectionTypes = ref([]);
const actions = {
- book: {
- title: 'Are you sure you want to book this invoice?',
- cb: checkToBook,
- action: toBook,
+ unbook: {
+ title: t('assertAction', { action: t('unbook') }),
+ action: toUnbook,
},
delete: {
- title: 'Are you sure you want to delete this invoice?',
+ title: t('assertAction', { action: t('delete') }),
action: deleteInvoice,
},
clone: {
- title: 'Are you sure you want to clone this invoice?',
+ title: t('assertAction', { action: t('clone') }),
action: cloneInvoice,
},
- showPdf: {
- cb: showPdfInvoice,
- },
- sendPdf: {
- cb: sendPdfInvoiceConfirmation,
- },
- correct: {
- cb: () => correctionDialogRef.value.show(),
- },
+ showPdf: { cb: showPdfInvoice },
+ sendPdf: { cb: sendPdfInvoiceConfirmation },
+ correct: { cb: () => correctionDialogRef.value.show() },
};
const filter = {
include: [
@@ -94,11 +82,7 @@ const filter = {
},
],
};
-const data = ref(useCardDescription());
-const invoiceInCorrection = reactive({
- correcting: [],
- corrected: null,
-});
+const invoiceInCorrection = reactive({ correcting: [], corrected: null });
const routes = reactive({
getSupplier: (id) => {
return { name: 'SupplierCard', params: { id } };
@@ -139,16 +123,17 @@ const correctionFormData = reactive({
});
const isNotFilled = computed(() => Object.values(correctionFormData).includes(null));
-onBeforeMount(async () => await setInvoiceCorrection(entityId.value));
+onBeforeMount(async () => {
+ await setInvoiceCorrection(entityId.value);
+ const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`);
+ totalAmount.value = data.totalDueDay;
+});
-watch(
- () => route.params.id,
- async (newId) => {
- invoiceInCorrection.correcting.length = 0;
- invoiceInCorrection.corrected = null;
- if (newId) await setInvoiceCorrection(entityId.value);
- }
-);
+onBeforeRouteLeave(async (to, from) => {
+ invoiceInCorrection.correcting.length = 0;
+ invoiceInCorrection.corrected = null;
+ if (to.params.id !== from.params.id) await setInvoiceCorrection(entityId.value);
+});
async function setInvoiceCorrection(id) {
const [{ data: correctingData }, { data: correctedData }] = await Promise.all([
@@ -179,17 +164,6 @@ async function setInvoiceCorrection(id) {
);
}
-async function setData(entity) {
- data.value = useCardDescription(entity.supplierRef, entity.id);
- const { totalDueDay } = await getTotals();
- totalAmount.value = totalDueDay;
-}
-
-async function getTotals() {
- const { data } = await axios.get(`InvoiceIns/${entityId.value}/getTotals`);
- return data;
-}
-
function openDialog() {
quasar.dialog({
component: VnConfirm,
@@ -200,38 +174,17 @@ function openDialog() {
});
}
-async function checkToBook() {
- let directBooking = true;
+async function toUnbook() {
+ const { data } = await axios.post(`InvoiceIns/${entityId.value}/toUnbook`);
+ const { isLinked, bookEntry, accountingEntries } = data;
- const totals = await getTotals();
- const taxableBaseNotEqualDueDay = totals.totalDueDay != totals.totalTaxableBase;
- const vatNotEqualDueDay = totals.totalDueDay != totals.totalVat;
+ const type = isLinked ? 'warning' : 'positive';
+ const message = isLinked
+ ? t('isLinked', { bookEntry, accountingEntries })
+ : t('isNotLinked', { bookEntry });
- if (taxableBaseNotEqualDueDay && vatNotEqualDueDay) directBooking = false;
-
- const { data: dueDaysCount } = await axios.get('InvoiceInDueDays/count', {
- where: {
- invoiceInFk: entityId.value,
- dueDated: { gte: Date.vnNew() },
- },
- });
-
- if (dueDaysCount) directBooking = false;
-
- if (!directBooking) openDialog();
- else toBook();
-}
-
-async function toBook() {
- await axios.post(`InvoiceIns/${entityId.value}/toBook`);
-
- quasar.notify({
- type: 'positive',
- message: t('globals.dataSaved'),
- });
-
- await cardDescriptorRef.value.getData();
- setTimeout(() => location.reload(), 500);
+ quasar.notify({ type, message });
+ if (!isLinked) store.data.isBooked = false;
}
async function deleteInvoice() {
@@ -240,7 +193,7 @@ async function deleteInvoice() {
type: 'positive',
message: t('Invoice deleted'),
});
- router.push({ path: '/invoice-in' });
+ push({ path: '/invoice-in' });
}
async function cloneInvoice() {
@@ -249,11 +202,9 @@ async function cloneInvoice() {
type: 'positive',
message: t('Invoice cloned'),
});
- router.push({ path: `/invoice-in/${data.id}/summary` });
+ push({ path: `/invoice-in/${data.id}/summary` });
}
-const requiredFieldRule = (val) => val || t('globals.requiredField');
-
const isAdministrative = () => hasAny(['administrative']);
const isAgricultural = () =>
@@ -299,10 +250,9 @@ const createInvoiceInCorrection = async () => {
'InvoiceIns/corrective',
Object.assign(correctionFormData, { id: entityId.value })
);
- router.push({ path: `/invoice-in/${correctingId}/summary` });
+ push({ path: `/invoice-in/${correctingId}/summary` });
};
-
{
+
+
+
+ {{ t('To book') }}
+
+
+
- {{ t('To book') }}
+
+ {{ t('To unbook') }}
+
{
>
{{ t('components.smartCard.downloadFile') }}
-
- {{ t('components.smartCard.downloadFile') }}
-
-
+
+
+
+ {{ entity?.supplier?.nickname }}
+
+
+
+
-
+
{
:options="siiTypeInvoiceOuts"
option-value="id"
option-label="code"
- :rules="[requiredFieldRule]"
+ :required="true"
/>
@@ -496,7 +457,7 @@ const createInvoiceInCorrection = async () => {
:options="cplusRectificationTypes"
option-value="id"
option-label="description"
- :rules="[requiredFieldRule]"
+ :required="true"
/>
{
:options="invoiceCorrectionTypes"
option-value="id"
option-label="description"
- :rules="[requiredFieldRule]"
+ :required="true"
/>
@@ -544,11 +505,18 @@ const createInvoiceInCorrection = async () => {
}
+en:
+ isNotLinked: The entry {bookEntry} has been deleted with {accountingEntries} entries
+ isLinked: The entry {bookEntry} has been linked to Sage. Please contact administration for further information
+ assertAction: Are you sure you want to {action} this invoice?
es:
+ book: asentar
+ unbook: desasentar
+ delete: eliminar
+ clone: clonar
To book: Contabilizar
- Are you sure you want to book this invoice?: Estas seguro de querer asentar esta factura?
+ To unbook: Descontabilizar
Delete invoice: Eliminar factura
- Are you sure you want to delete this invoice?: Estas seguro de querer eliminar esta factura?
Invoice deleted: Factura eliminada
Clone invoice: Clonar factura
Invoice cloned: Factura clonada
@@ -560,4 +528,7 @@ es:
Rectificative invoice: Factura rectificativa
Original invoice: Factura origen
Entry: entrada
+ isNotLinked: Se ha eliminado el asiento nº {bookEntry} con {accountingEntries} apuntes
+ isLinked: El asiento {bookEntry} fue enlazado a Sage, por favor contacta con administración
+ assertAction: Estas seguro de querer {action} esta factura?
diff --git a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
index 0e68b740f..de59b142e 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInDueDay.vue
@@ -9,24 +9,21 @@ import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue';
+import { toCurrency } from 'src/filters';
const route = useRoute();
const { t } = useI18n();
-const arrayData = useArrayData('InvoiceIn');
+const arrayData = useArrayData(route.meta.moduleName);
const invoiceIn = computed(() => arrayData.store.data);
const rowsSelected = ref([]);
const banks = ref([]);
const invoiceInFormRef = ref();
-const invoiceId = route.params.id;
+const invoiceId = +route.params.id;
const placeholder = 'yyyy/mm/dd';
-const filter = {
- where: {
- invoiceInFk: invoiceId,
- },
-};
+const filter = { where: { invoiceInFk: invoiceId } };
const columns = computed(() => [
{
@@ -73,6 +70,7 @@ async function insert() {
await axios.post('/InvoiceInDueDays/new', { id: +invoiceId });
await invoiceInFormRef.value.reload();
}
+const getTotalAmount = (rows) => rows.reduce((acc, { amount }) => acc + +amount, 0);
+
+
+
+
+
+
+ {{
+ toCurrency(getTotalAmount(rows), invoiceIn.currency.code)
+ }}
+
+
+
+
@@ -294,7 +305,11 @@ async function insert() {
-
+
es:
Date: Fecha
diff --git a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
index 6bdc1c0b5..1d1205d9e 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInIntrastat.vue
@@ -6,26 +6,21 @@ import { toCurrency } from 'src/filters';
import CrudModel from 'src/components/CrudModel.vue';
import FetchData from 'src/components/FetchData.vue';
import VnSelect from 'src/components/common/VnSelect.vue';
-import VnLv from 'src/components/ui/VnLv.vue';
+import { useArrayData } from 'src/composables/useArrayData';
const { t } = useI18n();
-const route = useRoute();
+const route = useRoute();
+const currency = computed(
+ () => useArrayData(route.meta.moduleName).store.data?.currency?.code
+);
const invoceInIntrastat = ref([]);
-const amountTotal = computed(() => getTotal('amount'));
-const netTotal = computed(() => getTotal('net'));
-const stemsTotal = computed(() => getTotal('stems'));
const rowsSelected = ref([]);
const countries = ref([]);
const intrastats = ref([]);
const invoiceInFormRef = ref();
-
-const filter = {
- where: {
- invoiceInFk: route.params.id,
- },
-};
-
+const invoiceInId = computed(() => +route.params.id);
+const filter = { where: { invoiceInFk: invoiceInId.value } };
const columns = computed(() => [
{
name: 'code',
@@ -77,13 +72,8 @@ const columns = computed(() => [
},
]);
-function getTotal(type) {
- if (!invoceInIntrastat.value.length) return 0.0;
- return invoceInIntrastat.value.reduce(
- (total, intrastat) => total + intrastat[type],
- 0.0
- );
-}
+const getTotal = (data, key) =>
+ data.reduce((acc, cur) => acc + +String(cur[key]).replace(',', '.'), 0);
(intrastats = data)"
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
(invoceInIntrastat = data)"
@@ -172,6 +144,22 @@ function getTotal(type) {
/>
+
+
+
+
+
+ {{ toCurrency(getTotal(rows, 'amount'), currency) }}
+
+
+ {{ getTotal(rows, 'net') }}
+
+
+ {{ getTotal(rows, 'stems') }}
+
+
+
+
diff --git a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
index d58dad2b4..3ee90b5c2 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInSummary.vue
@@ -3,32 +3,24 @@ import { onMounted, ref, computed } from 'vue';
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { toCurrency, toDate } from 'src/filters';
+import { useArrayData } from 'src/composables/useArrayData';
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';
+import InvoiceIntoBook from '../InvoiceInToBook.vue';
import VnTitle from 'src/components/common/VnTitle.vue';
-onMounted(async () => {
- salixUrl.value = await getUrl('');
- invoiceInUrl.value = salixUrl.value + `invoiceIn/${entityId.value}/`;
-});
-
-const route = useRoute();
+const props = defineProps({ id: { type: [Number, String], default: 0 } });
const { t } = useI18n();
+const route = useRoute();
-const $props = defineProps({
- id: {
- type: Number,
- default: 0,
- },
-});
-
-const entityId = computed(() => $props.id || route.params.id);
-
-const salixUrl = ref();
+const entityId = computed(() => props.id || +route.params.id);
+const invoiceIn = computed(() => useArrayData(route.meta.moduleName).store.data);
+const currency = computed(() => invoiceIn.value?.currency?.code);
const invoiceInUrl = ref();
const amountsNotMatch = ref(null);
-const intrastatTotals = ref({});
+const intrastatTotals = ref({ amount: 0, net: 0, stems: 0 });
const vatColumns = ref([
{
@@ -42,14 +34,16 @@ const vatColumns = ref([
name: 'landed',
label: 'invoiceIn.summary.taxableBase',
field: (row) => row.taxableBase,
- format: (value) => toCurrency(value),
+ format: (value) => toCurrency(value, currency.value),
sortable: true,
align: 'left',
},
{
name: 'vat',
label: 'invoiceIn.summary.sageVat',
- field: (row) => row.taxTypeSage?.vat,
+ field: (row) => {
+ if (row.taxTypeSage) return `#${row.taxTypeSage.id} : ${row.taxTypeSage.vat}`;
+ },
format: (value) => value,
sortable: true,
align: 'left',
@@ -57,7 +51,10 @@ const vatColumns = ref([
{
name: 'transaction',
label: 'invoiceIn.summary.sageTransaction',
- field: (row) => row.transactionTypeSage?.transaction,
+ field: (row) => {
+ if (row.transactionTypeSage)
+ return `#${row.transactionTypeSage.id} : ${row.transactionTypeSage?.transaction}`;
+ },
format: (value) => value,
sortable: true,
align: 'left',
@@ -66,9 +63,9 @@ const vatColumns = ref([
name: 'rate',
label: 'invoiceIn.summary.rate',
field: (row) => taxRate(row.taxableBase, row.taxTypeSage?.rate),
- format: (value) => toCurrency(value),
+ format: (value) => toCurrency(value, currency.value),
sortable: true,
- align: 'left',
+ align: 'center',
},
{
name: 'currency',
@@ -99,7 +96,7 @@ const dueDayColumns = ref([
name: 'amount',
label: 'invoiceIn.summary.amount',
field: (row) => row.amount,
- format: (value) => toCurrency(value),
+ format: (value) => toCurrency(value, currency.value),
sortable: true,
align: 'left',
},
@@ -122,13 +119,15 @@ const intrastatColumns = ref([
},
sortable: true,
align: 'left',
+ style: 'width: 10px',
},
{
name: 'amount',
label: 'invoiceIn.summary.amount',
- field: (row) => toCurrency(row.amount),
+ field: (row) => toCurrency(row.amount, currency.value),
sortable: true,
align: 'left',
+ style: 'width: 10px',
},
{
name: 'net',
@@ -155,58 +154,55 @@ const intrastatColumns = ref([
},
]);
-function getAmountNotMatch(totals) {
- return (
+onMounted(async () => {
+ invoiceInUrl.value = `${await getUrl('')}invoiceIn/${entityId.value}/`;
+});
+
+const init = (data) => {
+ if (!data) return;
+
+ const { totals, invoiceInIntrastat } = data;
+ amountsNotMatch.value =
totals.totalDueDay != totals.totalTaxableBase &&
- totals.totalDueDay != totals.totalVat
- );
-}
+ totals.totalDueDay != totals.totalVat;
-function getIntrastatTotals(intrastat) {
- const totals = {
- amount: intrastat.reduce((acc, cur) => acc + cur.amount, 0),
- net: intrastat.reduce((acc, cur) => acc + cur.net, 0),
- stems: intrastat.reduce((acc, cur) => acc + cur.stems, 0),
- };
+ invoiceInIntrastat.forEach((val) => {
+ intrastatTotals.value.amount += val.amount;
+ intrastatTotals.value.net += val.net;
+ intrastatTotals.value.stems += val.stems;
+ });
+};
- return totals;
-}
+const taxRate = (taxableBase = 0, rate = 0) => (rate / 100) * taxableBase;
-function getTaxTotal(tax) {
- return tax.reduce(
- (acc, cur) => acc + taxRate(cur.taxableBase, cur.taxTypeSage?.rate),
- 0
- );
-}
+const getTotalTax = (tax) =>
+ tax.reduce((acc, cur) => acc + taxRate(cur.taxableBase, cur.taxTypeSage?.rate), 0);
-function setData(entity) {
- if (!entity) return false;
-
- amountsNotMatch.value = getAmountNotMatch(entity.totals);
-
- if (entity.invoiceInIntrastat.length)
- intrastatTotals.value = { ...getIntrastatTotals(entity.invoiceInIntrastat) };
-}
-
-function taxRate(taxableBase = 0, rate = 0) {
- return (rate / 100) * taxableBase;
-}
-
-function getLink(param) {
- return `#/invoice-in/${entityId.value}/${param}`;
-}
+const getLink = (param) => `#/invoice-in/${entityId.value}/${param}`;
setData(data)"
+ @on-fetch="(data) => init(data)"
>
-
- {{ invoiceIn.id }} - {{ invoiceIn.supplier?.name }}
+
+ {{ entity.id }} - {{ entity.supplier?.name }}
-
+
+
+
+
+
+
+
+
@@ -217,19 +213,26 @@ function getLink(param) {
+ :value="entity.supplier?.name"
+ >
+
+
+ {{ entity.supplier?.name }}
+
+
+
+
@@ -242,19 +245,19 @@ function getLink(param) {
@@ -266,20 +269,19 @@ function getLink(param) {
-
@@ -290,58 +292,62 @@ function getLink(param) {
/>
-
-
-
-
-
-
- {{ toCurrency(invoiceIn.totals.totalDueDay) }}
-
-
-
-
+
+
+
+
+
+ {{ toCurrency(entity.totals.totalDueDay, currency) }}
+
+
+
-
+
-
-
-
+
+
+
{{ t(col.label) }}
-
- {{ toCurrency(invoiceIn.totals.totalTaxableBase) }}
-
{{
- toCurrency(getTaxTotal(invoiceIn.invoiceInTax))
+ toCurrency(entity.totals.totalTaxableBase, currency)
+ }}
+
+
+ {{
+ toCurrency(getTotalTax(entity.invoiceInTax, currency))
}}
@@ -349,17 +355,17 @@ function getLink(param) {
-
+
-
-
-
-
+
+
+
+
{{ t(col.label) }}
@@ -368,26 +374,32 @@ function getLink(param) {
- {{ toCurrency(invoiceIn.totals.totalDueDay) }}
+
+ {{ toCurrency(entity.totals.totalDueDay, currency) }}
+
-
+
-
-
-
+
+
+
{{ t(col.label) }}
@@ -395,7 +407,7 @@ function getLink(param) {
- {{ toCurrency(intrastatTotals.amount) }}
+ {{ toCurrency(intrastatTotals.amount, currency) }}
{{ intrastatTotals.net }}
{{ intrastatTotals.stems }}
@@ -410,13 +422,28 @@ function getLink(param) {
.bg {
background-color: var(--vn-accent-color);
}
-.bordered {
- border: 1px solid var(--vn-text-color);
- max-width: 18em;
+@media (min-width: $breakpoint-md) {
+ .summaryBody {
+ .vat {
+ flex: 65%;
+ }
+
+ .due-day {
+ flex: 30%;
+ }
+ .vat,
+ .due-day {
+ .q-table th {
+ padding-right: 0;
+ }
+ }
+ }
}
es:
Search invoice: Buscar factura recibida
You can search by invoice reference: Puedes buscar por referencia de la factura
+ Totals: Totales
+ To book: Contabilizar
diff --git a/src/pages/InvoiceIn/Card/InvoiceInVat.vue b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
index ae3aa9349..6fc844eff 100644
--- a/src/pages/InvoiceIn/Card/InvoiceInVat.vue
+++ b/src/pages/InvoiceIn/Card/InvoiceInVat.vue
@@ -11,13 +11,14 @@ import VnSelect from 'src/components/common/VnSelect.vue';
import CrudModel from 'src/components/CrudModel.vue';
import VnCurrency from 'src/components/common/VnCurrency.vue';
-const route = useRoute();
+const router = useRoute();
const { t } = useI18n();
const quasar = useQuasar();
-const arrayData = useArrayData('InvoiceIn');
+const arrayData = useArrayData(router.meta.moduleName);
const invoiceIn = computed(() => arrayData.store.data);
-
+const invoiceId = +router.params.id;
+const currency = computed(() => invoiceIn.value?.currency?.code);
const expenses = ref([]);
const sageTaxTypes = ref([]);
const sageTransactionTypes = ref([]);
@@ -55,7 +56,7 @@ const columns = computed(() => [
{
name: 'taxablebase',
label: t('Taxable base'),
- field: (row) => toCurrency(row.taxableBase),
+ field: (row) => toCurrency(row.taxableBase, currency.value),
model: 'taxableBase',
sortable: true,
tabIndex: 2,
@@ -68,7 +69,7 @@ const columns = computed(() => [
options: sageTaxTypes.value,
model: 'taxTypeSageFk',
optionValue: 'id',
- optionLabel: 'vat',
+ optionLabel: 'id',
sortable: true,
tabindex: 3,
align: 'left',
@@ -80,7 +81,7 @@ const columns = computed(() => [
options: sageTransactionTypes.value,
model: 'transactionTypeSageFk',
optionValue: 'id',
- optionLabel: 'transaction',
+ optionLabel: 'id',
sortable: true,
tabIndex: 4,
align: 'left',
@@ -90,7 +91,7 @@ const columns = computed(() => [
label: t('Rate'),
sortable: true,
tabIndex: 5,
- field: (row) => toCurrency(taxRate(row, row.taxTypeSageFk)),
+ field: (row) => toCurrency(taxRate(row, row.taxTypeSageFk), currency.value),
align: 'left',
},
{
@@ -114,7 +115,7 @@ const filter = {
'transactionTypeSageFk',
],
where: {
- invoiceInFk: route.params.id,
+ invoiceInFk: invoiceId,
},
};
@@ -161,6 +162,9 @@ async function addExpense() {
});
}
}
+const getTotalTaxableBase = (rows) =>
+ rows.reduce((acc, { taxableBase }) => acc + +taxableBase, 0);
+const getTotalRate = (rows) => rows.reduce((acc, cur) => acc + +taxRate(cur), 0);
@@ -303,6 +308,19 @@ async function addExpense() {
/>
+
+
+
+
+
+ {{ toCurrency(getTotalTaxableBase(rows), currency) }}
+
+
+
+ {{ toCurrency(getTotalRate(rows), currency) }}
+
+
+
@@ -391,7 +409,7 @@ async function addExpense() {
- {{ toCurrency(taxRate(props.row)) }}
+ {{ toCurrency(taxRate(props.row), currency) }}
diff --git a/src/pages/Zone/Card/ZoneLocationsTree.vue b/src/pages/Zone/Card/ZoneLocationsTree.vue
new file mode 100644
index 000000000..a42111592
--- /dev/null
+++ b/src/pages/Zone/Card/ZoneLocationsTree.vue
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+ {{ node.name }}
+
+
+
+
+
diff --git a/src/pages/Zone/locale/en.yml b/src/pages/Zone/locale/en.yml
index bae89fda9..a1d741b84 100644
--- a/src/pages/Zone/locale/en.yml
+++ b/src/pages/Zone/locale/en.yml
@@ -42,6 +42,8 @@ summary:
filterPanel:
name: Name
agencyModeFk: Agency
+zoneLocations:
+ locations: Locations
deliveryPanel:
pickup: Pick up
delivery: Delivery
diff --git a/src/pages/Zone/locale/es.yml b/src/pages/Zone/locale/es.yml
index d74238a6e..d12c4f204 100644
--- a/src/pages/Zone/locale/es.yml
+++ b/src/pages/Zone/locale/es.yml
@@ -42,6 +42,8 @@ summary:
filterPanel:
name: Nombre
agencyModeFk: Agencia
+zoneLocations:
+ locations: Localizaciones
deliveryPanel:
pickup: Recogida
delivery: Entrega
diff --git a/src/router/modules/invoiceIn.js b/src/router/modules/invoiceIn.js
index 869a3555a..75d0612aa 100644
--- a/src/router/modules/invoiceIn.js
+++ b/src/router/modules/invoiceIn.js
@@ -37,6 +37,15 @@ export default {
},
component: () => import('src/pages/InvoiceIn/InvoiceInList.vue'),
},
+ {
+ path: 'create',
+ name: 'InvoiceInCreare',
+ meta: {
+ title: 'invoiceInCreate',
+ icon: 'create',
+ },
+ component: () => import('src/pages/InvoiceIn/InvoiceInCreate.vue'),
+ },
],
},
{
diff --git a/src/router/modules/zone.js b/src/router/modules/zone.js
index c355856b1..cf2e5321e 100644
--- a/src/router/modules/zone.js
+++ b/src/router/modules/zone.js
@@ -106,7 +106,7 @@ export default {
path: 'location',
meta: {
title: 'locations',
- icon: 'vn:greuge',
+ icon: 'my_location',
},
component: () => import('src/pages/Zone/Card/ZoneLocations.vue'),
},
diff --git a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
index 963dda3e2..77a11969b 100644
--- a/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInBasicData.spec.js
@@ -2,8 +2,7 @@
describe('InvoiceInBasicData', () => {
const formInputs = '.q-form > .q-card input';
const firstFormSelect = '.q-card > .vn-row:nth-child(1) > .q-select';
- const appendBtns = '.q-form label button';
- const dialogAppendBtns = '.q-dialog label button';
+ const documentBtns = '.q-form .q-field button';
const dialogInputs = '.q-dialog input';
const dialogActionBtns = '.q-card__actions button';
@@ -15,8 +14,7 @@ describe('InvoiceInBasicData', () => {
it('should edit the provideer and supplier ref', () => {
cy.selectOption(firstFormSelect, 'Bros');
cy.get('[title="Reset"]').click();
- cy.get(appendBtns).eq(0).click();
- cy.get(formInputs).eq(1).type(4739);
+ cy.get(formInputs).eq(1).type('{selectall}4739');
cy.saveCard();
cy.get(`${firstFormSelect} input`).invoke('val').should('eq', 'Plants nick');
@@ -27,22 +25,20 @@ describe('InvoiceInBasicData', () => {
const firtsInput = 'Ticket:65';
const secondInput = "I don't know what posting here!";
- cy.get(appendBtns).eq(3).click();
- cy.get(dialogAppendBtns).eq(0).click();
- cy.get(dialogInputs).eq(0).type(firtsInput);
- cy.get(dialogAppendBtns).eq(1).click();
- cy.get('textarea').type(secondInput);
+ cy.get(documentBtns).eq(1).click();
+ cy.get(dialogInputs).eq(0).type(`{selectall}${firtsInput}`);
+ cy.get('textarea').type(`{selectall}${secondInput}`);
cy.get(dialogActionBtns).eq(1).click();
- cy.get(appendBtns).eq(3).click();
-
+ cy.get(documentBtns).eq(1).click();
cy.get(dialogInputs).eq(0).invoke('val').should('eq', firtsInput);
cy.get('textarea').invoke('val').should('eq', secondInput);
});
it('should throw an error creating a new dms if a file is not attached', () => {
- cy.get(appendBtns).eq(2).click();
- cy.get(appendBtns).eq(1).click();
+ cy.get(formInputs).eq(5).click();
+ cy.get(formInputs).eq(5).type('{selectall}{backspace}');
+ cy.get(documentBtns).eq(0).click();
cy.get(dialogActionBtns).eq(1).click();
cy.get('.q-notification__message').should(
'have.text',
diff --git a/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
new file mode 100644
index 000000000..f2d9a3497
--- /dev/null
+++ b/test/cypress/integration/invoiceIn/invoiceInDescriptor.spec.js
@@ -0,0 +1,24 @@
+describe('InvoiceInDescriptor', () => {
+ const dialogBtns = '.q-card__actions button';
+ const firstDescritorOpt = '.q-menu > .q-list > :nth-child(1) > .q-item__section';
+ const isBookedField =
+ '.q-card:nth-child(3) .vn-label-value:nth-child(5) > .value > span';
+
+ it('should booking and unbooking the invoice properly', () => {
+ cy.login('developer');
+ cy.visit(`/#/invoice-in/1/summary?limit=10`);
+
+ cy.openLeftMenu();
+ cy.openActionsDescriptor();
+ cy.get(firstDescritorOpt).click();
+ cy.get(dialogBtns).eq(1).click();
+ cy.get('.fullscreen').first().click();
+ cy.get(isBookedField).should('have.attr', 'title', 'true');
+
+ cy.openLeftMenu();
+ cy.openActionsDescriptor();
+ cy.get(firstDescritorOpt).click();
+ cy.get(dialogBtns).eq(1).click();
+ cy.get(isBookedField).should('have.attr', 'title', 'false');
+ });
+});
diff --git a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
index 389be671c..63e99eac1 100644
--- a/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
+++ b/test/cypress/integration/invoiceIn/invoiceInVat.spec.js
@@ -18,7 +18,7 @@ describe('InvoiceInVat', () => {
cy.saveCard();
cy.visit(`/#/invoice-in/1/vat`);
- cy.getValue(firstLineVat).should('equal', 'H.P. IVA 21% CEE');
+ cy.getValue(firstLineVat).should('equal', '8');
});
it('should add a new row', () => {
diff --git a/test/cypress/integration/vnLog.spec.js b/test/cypress/integration/vnLog.spec.js
index 80b9d07df..4db724e99 100644
--- a/test/cypress/integration/vnLog.spec.js
+++ b/test/cypress/integration/vnLog.spec.js
@@ -9,15 +9,15 @@ describe('VnLog', () => {
cy.visit(`/#/claim/${1}/log`);
cy.openRightMenu();
});
-
- it('should filter by insert actions', () => {
+ // Se tiene que cambiar el Accept-Language a 'en', ya hay una tarea para eso #7189.
+ xit('should filter by insert actions', () => {
cy.checkOption(':nth-child(7) > .q-checkbox');
cy.get('.q-page').click();
cy.validateContent(chips[0], 'Document');
cy.validateContent(chips[1], 'Beginning');
});
- it('should filter by entity', () => {
+ xit('should filter by entity', () => {
cy.selectOption('.q-drawer--right .q-item > .q-select', 'Claim');
cy.get('.q-page').click();
cy.validateContent(chips[0], 'Claim');
diff --git a/test/cypress/integration/worker/workerLocker.spec.js b/test/cypress/integration/worker/workerLocker.spec.js
index 2ae15e983..ef2f88300 100644
--- a/test/cypress/integration/worker/workerLocker.spec.js
+++ b/test/cypress/integration/worker/workerLocker.spec.js
@@ -1,4 +1,4 @@
-describe('WorkerList', () => {
+describe('WorkerLocker', () => {
const workerId = 1109;
const lockerCode = '2F';
const input = '.q-card input';
diff --git a/test/cypress/support/commands.js b/test/cypress/support/commands.js
index e7f8cb9d9..a237622e6 100755
--- a/test/cypress/support/commands.js
+++ b/test/cypress/support/commands.js
@@ -92,8 +92,13 @@ Cypress.Commands.add('checkOption', (selector) => {
// Global buttons
Cypress.Commands.add('saveCard', () => {
+ const dropdownArrow = '.q-btn-dropdown__arrow-container > .q-btn__content > .q-icon';
+ cy.get('#st-actions').then(($el) => {
+ if ($el.find(dropdownArrow).length) cy.get(dropdownArrow).click();
+ });
cy.get('[title="Save"]').click();
});
+
Cypress.Commands.add('resetCard', () => {
cy.get('[title="Reset"]').click();
});
diff --git a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInBasicData.spec.js b/test/vitest/__tests__/pages/InvoiceIn/InvoiceInBasicData.spec.js
deleted file mode 100644
index a3c383f74..000000000
--- a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInBasicData.spec.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { vi, describe, expect, it, beforeAll } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
-import InvoiceInBasicData from 'src/pages/InvoiceIn/Card/InvoiceInBasicData.vue';
-
-describe('InvoiceInBasicData', () => {
- let vm;
-
- beforeAll(() => {
- vm = createWrapper(InvoiceInBasicData, {
- global: {
- stubs: [],
- mocks: {
- fetch: vi.fn(),
- },
- },
- }).vm;
- });
-
- describe('upsert()', () => {
- it('should throw an error when data is empty', async () => {
- vi.spyOn(axios, 'post').mockResolvedValue({ data: [] });
- vi.spyOn(vm.quasar, 'notify');
-
- await vm.upsert();
-
- expect(vm.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- message: `The company can't be empty`,
- type: 'negative',
- })
- );
- });
- });
-});
diff --git a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInIntrastat.spec.js b/test/vitest/__tests__/pages/InvoiceIn/InvoiceInIntrastat.spec.js
index 55ca19d71..adfb054c6 100644
--- a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInIntrastat.spec.js
+++ b/test/vitest/__tests__/pages/InvoiceIn/InvoiceInIntrastat.spec.js
@@ -19,13 +19,13 @@ describe('InvoiceInIntrastat', () => {
describe('getTotal()', () => {
it('should correctly handle the sum', () => {
- vm.invoceInIntrastat = [
+ const invoceInIntrastat = [
{ amount: 10, stems: 162 },
{ amount: 20, stems: 21 },
];
- const totalAmount = vm.getTotal('amount');
- const totalStems = vm.getTotal('stems');
+ const totalAmount = vm.getTotal(invoceInIntrastat, 'amount');
+ const totalStems = vm.getTotal(invoceInIntrastat, 'stems');
expect(totalAmount).toBe(10 + 20);
expect(totalStems).toBe(162 + 21);
diff --git a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInVat.spec.js b/test/vitest/__tests__/pages/InvoiceIn/InvoiceInVat.spec.js
index 6cc082a35..76453f65a 100644
--- a/test/vitest/__tests__/pages/InvoiceIn/InvoiceInVat.spec.js
+++ b/test/vitest/__tests__/pages/InvoiceIn/InvoiceInVat.spec.js
@@ -1,5 +1,5 @@
import { vi, describe, expect, it, beforeAll } from 'vitest';
-import { createWrapper, axios } from 'app/test/vitest/helper';
+import { createWrapper } from 'app/test/vitest/helper';
import InvoiceInVat from 'src/pages/InvoiceIn/Card/InvoiceInVat.vue';
describe('InvoiceInVat', () => {
@@ -16,41 +16,6 @@ describe('InvoiceInVat', () => {
}).vm;
});
- describe('addExpense()', () => {
- beforeAll(() => {
- vi.spyOn(axios, 'post').mockResolvedValue({ data: [] });
- vi.spyOn(axios, 'get').mockResolvedValue({ data: [] });
- vi.spyOn(vm.quasar, 'notify');
- });
-
- it('should throw an error when the code property is undefined', async () => {
- await vm.addExpense();
-
- expect(vm.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- message: `The code can't be empty`,
- type: 'negative',
- })
- );
- });
-
- it('should correctly handle expense addition', async () => {
- vm.newExpense = {
- code: 123,
- isWithheld: false,
- description: 'Descripción del gasto',
- };
-
- await vm.addExpense();
- expect(vm.quasar.notify).toHaveBeenCalledWith(
- expect.objectContaining({
- message: 'Data saved',
- type: 'positive',
- })
- );
- });
- });
-
describe('taxRate()', () => {
it('should correctly compute the tax rate', () => {
const invoiceInTax = { taxableBase: 100, taxTypeSageFk: 1 };
diff --git a/test/vitest/helper.js b/test/vitest/helper.js
index 89cc640fd..4eeea25a8 100644
--- a/test/vitest/helper.js
+++ b/test/vitest/helper.js
@@ -24,6 +24,7 @@ vi.mock('vue-router', () => ({
params: {
id: 1,
},
+ meta: { moduleName: 'mockName' },
},
},
}),
@@ -31,6 +32,7 @@ vi.mock('vue-router', () => ({
matched: [],
query: {},
params: {},
+ meta: { moduleName: 'mockName' },
}),
}));