feat: sale invoice model tax attributes

This commit is contained in:
Ahmed Bouhuolia
2023-09-06 14:01:40 +02:00
parent ac072d29fc
commit 983ceb5cc6
14 changed files with 346 additions and 161 deletions

View File

@@ -13,17 +13,14 @@ import {
import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform';
import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform';
import ItemsEntriesService from '@/services/Items/ItemsEntriesService';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators';
import { SaleInvoiceIncrement } from './SaleInvoiceIncrement';
import { formatDateFields } from 'utils';
import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions';
import { ItemEntry } from '@/models';
@Service()
export class CommandSaleInvoiceDTOTransformer {
@Inject()
private tenancy: HasTenancyService;
@Inject()
private branchDTOTransform: BranchTransactionDTOTransform;
@@ -55,11 +52,9 @@ export class CommandSaleInvoiceDTOTransformer {
authorizedUser: ITenantUser,
oldSaleInvoice?: ISaleInvoice
): Promise<ISaleInvoice> {
const { ItemEntry } = this.tenancy.models(tenantId);
const entriesModels = this.transformDTOEntriesToModels(saleInvoiceDTO);
const amount = this.getDueBalanceItemEntries(entriesModels);
const balance = sumBy(saleInvoiceDTO.entries, (e) =>
ItemEntry.calcAmount(e)
);
// Retreive the next invoice number.
const autoNextNumber = this.invoiceIncrement.getNextInvoiceNumber(tenantId);
@@ -72,6 +67,7 @@ export class CommandSaleInvoiceDTOTransformer {
const initialEntries = saleInvoiceDTO.entries.map((entry) => ({
referenceType: 'SaleInvoice',
isInclusiveTax: saleInvoiceDTO.isInclusiveTax,
...entry,
}));
const entries = await composeAsync(
@@ -87,7 +83,7 @@ export class CommandSaleInvoiceDTOTransformer {
['invoiceDate', 'dueDate']
),
// Avoid rewrite the deliver date in edit mode when already published.
balance,
amount,
currencyCode: customer.currencyCode,
exchangeRate: saleInvoiceDTO.exchangeRate || 1,
...(saleInvoiceDTO.delivered &&
@@ -107,4 +103,29 @@ export class CommandSaleInvoiceDTOTransformer {
this.warehouseDTOTransform.transformDTO<ISaleInvoice>(tenantId)
)(initialDTO);
}
/**
* Transforms the DTO entries to invoice entries models.
* @param {ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO} entries
* @returns {IItemEntry[]}
*/
private transformDTOEntriesToModels = (
saleInvoiceDTO: ISaleInvoiceCreateDTO | ISaleInvoiceEditDTO
): ItemEntry[] => {
return saleInvoiceDTO.entries.map((entry) => {
return ItemEntry.fromJson({
...entry,
isInclusiveTax: saleInvoiceDTO.isInclusiveTax,
});
});
};
/**
* Gets the due balance from the invoice entries.
* @param {IItemEntry[]} entries
* @returns {number}
*/
private getDueBalanceItemEntries = (entries: ItemEntry[]) => {
return sumBy(entries, (e) => e.amount);
};
}

View File

@@ -93,7 +93,7 @@ export class SaleInvoiceGLEntries {
'SaleInvoice',
trx
);
};
};
/**
* Retrieves the given invoice ledger.
@@ -156,7 +156,7 @@ export class SaleInvoiceGLEntries {
return {
...commonEntry,
debit: saleInvoice.totalBcy,
debit: saleInvoice.totalLocal,
accountId: ARAccountId,
contactId: saleInvoice.customerId,
accountNormal: AccountNormal.DEBIT,

View File

@@ -1,4 +1,7 @@
import { Transformer } from '@/lib/Transformer/Transformer';
import { formatNumber } from '@/utils';
import { getExlusiveTaxAmount, getInclusiveTaxAmount } from '@/utils/taxRate';
import { format } from 'mathjs';
export class SaleInvoiceTaxEntryTransformer extends Transformer {
/**
@@ -6,7 +9,14 @@ export class SaleInvoiceTaxEntryTransformer extends Transformer {
* @returns {Array}
*/
public includeAttributes = (): string[] => {
return ['name', 'taxRateCode', 'raxRate', 'taxRateId'];
return [
'name',
'taxRateCode',
'taxRate',
'taxRateId',
'taxRateAmount',
'taxRateAmountFormatted',
];
};
/**
@@ -31,7 +41,7 @@ export class SaleInvoiceTaxEntryTransformer extends Transformer {
* @param taxEntry
* @returns {number}
*/
protected raxRate = (taxEntry) => {
protected taxRate = (taxEntry) => {
return taxEntry.taxAmount || taxEntry.taxRate.rate;
};
@@ -43,4 +53,26 @@ export class SaleInvoiceTaxEntryTransformer extends Transformer {
protected name = (taxEntry) => {
return taxEntry.taxRate.name;
};
/**
* Retrieve tax rate amount.
* @param taxEntry
*/
protected taxRateAmount = (taxEntry) => {
const taxRate = this.taxRate(taxEntry);
return this.options.isInclusiveTax
? getInclusiveTaxAmount(this.options.amount, taxRate)
: getExlusiveTaxAmount(this.options.amount, taxRate);
};
/**
* Retrieve formatted tax rate amount.
* @returns {string}
*/
protected taxRateAmountFormatted = (taxEntry) => {
return formatNumber(this.taxRateAmount(taxEntry), {
currencyCode: this.options.currencyCode,
});
};
}

View File

@@ -9,13 +9,19 @@ export class SaleInvoiceTransformer extends Transformer {
*/
public includeAttributes = (): string[] => {
return [
'formattedInvoiceDate',
'formattedDueDate',
'formattedAmount',
'formattedDueAmount',
'formattedPaymentAmount',
'formattedBalanceAmount',
'formattedExchangeRate',
'invoiceDateFormatted',
'dueDateFormatted',
'dueAmountFormatted',
'paymentAmountFormatted',
'balanceAmountFormatted',
'exchangeRateFormatted',
'subtotalFormatted',
'subtotalLocalFormatted',
'subtotalExludingTaxFormatted',
'taxAmountWithheldFormatted',
'taxAmountWithheldLocalFormatted',
'totalFormatted',
'totalLocalFormatted',
'taxes',
];
};
@@ -25,7 +31,7 @@ export class SaleInvoiceTransformer extends Transformer {
* @param {ISaleInvoice} invoice
* @returns {String}
*/
protected formattedInvoiceDate = (invoice): string => {
protected invoiceDateFormatted = (invoice): string => {
return this.formatDate(invoice.invoiceDate);
};
@@ -34,27 +40,16 @@ export class SaleInvoiceTransformer extends Transformer {
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedDueDate = (invoice): string => {
protected dueDateFormatted = (invoice): string => {
return this.formatDate(invoice.dueDate);
};
/**
* Retrieve formatted invoice amount.
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedAmount = (invoice): string => {
return formatNumber(invoice.balance, {
currencyCode: invoice.currencyCode,
});
};
/**
* Retrieve formatted invoice due amount.
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedDueAmount = (invoice): string => {
protected dueAmountFormatted = (invoice): string => {
return formatNumber(invoice.dueAmount, {
currencyCode: invoice.currencyCode,
});
@@ -65,7 +60,7 @@ export class SaleInvoiceTransformer extends Transformer {
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedPaymentAmount = (invoice): string => {
protected paymentAmountFormatted = (invoice): string => {
return formatNumber(invoice.paymentAmount, {
currencyCode: invoice.currencyCode,
});
@@ -76,7 +71,7 @@ export class SaleInvoiceTransformer extends Transformer {
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedBalanceAmount = (invoice): string => {
protected balanceAmountFormatted = (invoice): string => {
return formatNumber(invoice.balanceAmount, {
currencyCode: invoice.currencyCode,
});
@@ -87,15 +82,98 @@ export class SaleInvoiceTransformer extends Transformer {
* @param {ISaleInvoice} invoice
* @returns {string}
*/
protected formattedExchangeRate = (invoice): string => {
protected exchangeRateFormatted = (invoice): string => {
return formatNumber(invoice.exchangeRate, { money: false });
};
/**
* Retrieves formatted subtotal in base currency.
* (Tax inclusive if the tax inclusive is enabled)
* @param invoice
* @returns {string}
*/
protected subtotalFormatted = (invoice): string => {
return formatNumber(invoice.subtotal, {
currencyCode: this.context.organization.baseCurrency,
});
};
/**
* Retrieves formatted subtotal in foreign currency.
* (Tax inclusive if the tax inclusive is enabled)
* @param invoice
* @returns {string}
*/
protected subtotalLocalFormatted = (invoice): string => {
return formatNumber(invoice.subtotalLocal, {
currencyCode: invoice.currencyCode,
});
};
/**
* Retrieves formatted subtotal excluding tax in foreign currency.
* @param invoice
* @returns {string}
*/
protected subtotalExludingTaxFormatted = (invoice): string => {
return formatNumber(invoice.subtotalExludingTax, {
currencyCode: invoice.currencyCode,
});
};
/**
* Retrieves formatted tax amount withheld in foreign currency.
* @param invoice
* @returns {string}
*/
protected taxAmountWithheldFormatted = (invoice): string => {
return formatNumber(invoice.taxAmountWithheld, {
currencyCode: invoice.currencyCode,
});
};
/**
* Retrieves formatted tax amount withheld in base currency.
* @param invoice
* @returns {string}
*/
protected taxAmountWithheldLocalFormatted = (invoice): string => {
return formatNumber(invoice.taxAmountWithheldLocal, {
currencyCode: this.context.organization.baseCurrency,
});
};
/**
* Retrieves formatted total in foreign currency.
* @param invoice
* @returns {string}
*/
protected totalFormatted = (invoice): string => {
return formatNumber(invoice.total, {
currencyCode: invoice.currencyCode,
});
};
/**
* Retrieves formatted total in base currency.
* @param invoice
* @returns {string}
*/
protected totalLocalFormatted = (invoice): string => {
return formatNumber(invoice.totalLocal, {
currencyCode: this.context.organization.baseCurrency,
});
};
/**
* Retrieve the taxes lines of sale invoice.
* @param {ISaleInvoice} invoice
*/
protected taxes = (invoice) => {
return this.item(invoice.taxes, new SaleInvoiceTaxEntryTransformer());
return this.item(invoice.taxes, new SaleInvoiceTaxEntryTransformer(), {
amount: invoice.amount,
isInclusiveTax: invoice.isInclusiveTax,
currencyCode: invoice.currencyCode,
});
};
}

View File

@@ -1,6 +1,5 @@
import { Inject, Service } from 'typedi';
import { keyBy, sumBy } from 'lodash';
import * as R from 'ramda';
import { ItemEntry } from '@/models';
import HasTenancyService from '../Tenancy/TenancyService';