From f07d25edbe6dcdddff94ede23d0dcdcc61977c88 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 1 Sep 2024 13:32:47 +0200 Subject: [PATCH] fix: Set default index to transaction entries --- packages/server/src/interfaces/CreditNote.ts | 10 ++++---- packages/server/src/interfaces/ItemEntry.ts | 1 + .../server/src/interfaces/PaymentReceive.ts | 2 +- .../src/services/CreditNotes/CreditNotes.ts | 23 +++++++++++++++---- .../Expenses/CRUD/ExpenseDTOTransformer.ts | 12 +++++++--- packages/server/src/services/Items/utils.ts | 16 +++++++++++++ .../ManualJournals/CreateManualJournal.ts | 10 +++++++- .../CommandBillPaymentDTOTransformer.ts | 10 ++++++-- .../Purchases/Bills/BillDTOTransformer.ts | 13 +++++++---- .../VendorCredits/BaseVendorCredit.ts | 18 +++++++++++---- .../Sales/Estimates/CreateSaleEstimate.ts | 3 +-- .../Estimates/SaleEstimateDTOTransformer.ts | 14 +++++++---- .../CommandSaleInvoiceDTOTransformer.ts | 6 ++++- .../PaymentReceivedDTOTransformer.ts | 10 +++++--- .../Receipts/SaleReceiptDTOTransformer.ts | 8 ++++++- 15 files changed, 119 insertions(+), 37 deletions(-) create mode 100644 packages/server/src/services/Items/utils.ts diff --git a/packages/server/src/interfaces/CreditNote.ts b/packages/server/src/interfaces/CreditNote.ts index 73f4bbc14..e3e6df1cf 100644 --- a/packages/server/src/interfaces/CreditNote.ts +++ b/packages/server/src/interfaces/CreditNote.ts @@ -1,10 +1,10 @@ import { Knex } from 'knex'; -import { IDynamicListFilter, IItemEntry, IVendorCredit } from '@/interfaces'; +import { IDynamicListFilter, IItemEntry } from '@/interfaces'; import { ILedgerEntry } from './Ledger'; import { AttachmentLinkDTO } from './Attachments'; export interface ICreditNoteEntryNewDTO { - index: number; + index?: number; itemId: number; rate: number; quantity: number; @@ -22,7 +22,7 @@ export interface ICreditNoteNewDTO { entries: ICreditNoteEntryNewDTO[]; branchId?: number; warehouseId?: number; - attachments?: AttachmentLinkDTO[] + attachments?: AttachmentLinkDTO[]; } export interface ICreditNoteEditDTO { @@ -35,7 +35,7 @@ export interface ICreditNoteEditDTO { entries: ICreditNoteEntryNewDTO[]; branchId?: number; warehouseId?: number; - attachments?: AttachmentLinkDTO[] + attachments?: AttachmentLinkDTO[]; } export interface ICreditNoteEntry extends IItemEntry {} @@ -61,7 +61,7 @@ export interface ICreditNote { localAmount?: number; branchId?: number; warehouseId: number; - createdAt?: Date, + createdAt?: Date; } export enum CreditNoteAction { diff --git a/packages/server/src/interfaces/ItemEntry.ts b/packages/server/src/interfaces/ItemEntry.ts index 575c3ae44..210eadf40 100644 --- a/packages/server/src/interfaces/ItemEntry.ts +++ b/packages/server/src/interfaces/ItemEntry.ts @@ -48,6 +48,7 @@ export interface IItemEntry { export interface IItemEntryDTO { id?: number; + index?: number; itemId: number; landedCost?: boolean; warehouseId?: number; diff --git a/packages/server/src/interfaces/PaymentReceive.ts b/packages/server/src/interfaces/PaymentReceive.ts index b7c216abd..2b77c77e9 100644 --- a/packages/server/src/interfaces/PaymentReceive.ts +++ b/packages/server/src/interfaces/PaymentReceive.ts @@ -66,7 +66,7 @@ export interface IPaymentReceivedEntry { export interface IPaymentReceivedEntryDTO { id?: number; - index: number; + index?: number; paymentReceiveId?: number; invoiceId: number; paymentAmount: number; diff --git a/packages/server/src/services/CreditNotes/CreditNotes.ts b/packages/server/src/services/CreditNotes/CreditNotes.ts index 6fedf3245..414be0e2a 100644 --- a/packages/server/src/services/CreditNotes/CreditNotes.ts +++ b/packages/server/src/services/CreditNotes/CreditNotes.ts @@ -5,11 +5,17 @@ import * as R from 'ramda'; import { ServiceError } from '@/exceptions'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { ERRORS } from './constants'; -import { ICreditNote, ICreditNoteEditDTO, ICreditNoteNewDTO } from '@/interfaces'; +import { + ICreditNote, + ICreditNoteEditDTO, + ICreditNoteEntryNewDTO, + ICreditNoteNewDTO, +} from '@/interfaces'; import ItemsEntriesService from '@/services/Items/ItemsEntriesService'; import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService'; import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; +import { assocItemEntriesDefaultIndex } from '../Items/utils'; @Service() export default class BaseCreditNotes { @@ -43,10 +49,17 @@ export default class BaseCreditNotes { const amount = this.itemsEntriesService.getTotalItemsEntries( creditNoteDTO.entries ); - const entries = creditNoteDTO.entries.map((entry) => ({ - ...entry, - referenceType: 'CreditNote', - })); + const entries = R.compose( + // Associate the default index to each item entry. + assocItemEntriesDefaultIndex, + + // Associate the reference type to credit note entries. + R.map((entry: ICreditNoteEntryNewDTO) => ({ + ...entry, + referenceType: 'CreditNote', + })) + )(creditNoteDTO.entries); + // Retreive the next credit note number. const autoNextNumber = this.getNextCreditNumber(tenantId); diff --git a/packages/server/src/services/Expenses/CRUD/ExpenseDTOTransformer.ts b/packages/server/src/services/Expenses/CRUD/ExpenseDTOTransformer.ts index d53148e92..bff0e1d24 100644 --- a/packages/server/src/services/Expenses/CRUD/ExpenseDTOTransformer.ts +++ b/packages/server/src/services/Expenses/CRUD/ExpenseDTOTransformer.ts @@ -11,6 +11,7 @@ import { } from '@/interfaces'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; import { TenantMetadata } from '@/system/models'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export class ExpenseDTOTransformer { @@ -40,8 +41,8 @@ export class ExpenseDTOTransformer { /** * Mapping expense DTO to model. - * @param {IExpenseDTO} expenseDTO - * @param {ISystemUser} authorizedUser + * @param {IExpenseDTO} expenseDTO + * @param {ISystemUser} authorizedUser * @return {IExpense} */ private expenseDTOToModel( @@ -52,9 +53,14 @@ export class ExpenseDTOTransformer { const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO); const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories); + const categories = R.compose( + // Associate the default index to categories lines. + assocItemEntriesDefaultIndex + )(expenseDTO.categories || []); + const initialDTO = { - categories: [], ...omit(expenseDTO, ['publish', 'attachments']), + categories, totalAmount, landedCostAmount, paymentDate: moment(expenseDTO.paymentDate).toMySqlDateTime(), diff --git a/packages/server/src/services/Items/utils.ts b/packages/server/src/services/Items/utils.ts new file mode 100644 index 000000000..58e9b8de0 --- /dev/null +++ b/packages/server/src/services/Items/utils.ts @@ -0,0 +1,16 @@ +import { IItemEntry } from '@/interfaces'; +import { isNull, isUndefined } from 'lodash'; + +export function assocItemEntriesDefaultIndex( + entries: Array +): Array { + return entries.map((entry, index) => { + return { + index: + isUndefined(entry.index) || isNull(entry.index) + ? index + 1 + : entry.index, + ...entry, + }; + }); +} diff --git a/packages/server/src/services/ManualJournals/CreateManualJournal.ts b/packages/server/src/services/ManualJournals/CreateManualJournal.ts index 513f8d642..9908f5485 100644 --- a/packages/server/src/services/ManualJournals/CreateManualJournal.ts +++ b/packages/server/src/services/ManualJournals/CreateManualJournal.ts @@ -18,6 +18,8 @@ import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import { CommandManualJournalValidators } from './CommandManualJournalValidators'; import { AutoIncrementManualJournal } from './AutoIncrementManualJournal'; import { ManualJournalBranchesDTOTransformer } from '@/services/Branches/Integrations/ManualJournals/ManualJournalDTOTransformer'; +import { assocItemEntriesDefaultIndex } from '../Items/utils'; + @Service() export class CreateManualJournalService { @Inject() @@ -58,16 +60,22 @@ export class CreateManualJournalService { // The manual or auto-increment journal number. const journalNumber = manualJournalDTO.journalNumber || autoNextNumber; + const entries = R.compose( + // Associate the default index to each item entry. + assocItemEntriesDefaultIndex + )(manualJournalDTO.entries); + const initialDTO = { ...omit(manualJournalDTO, ['publish', 'attachments']), ...(manualJournalDTO.publish ? { publishedAt: moment().toMySqlDateTime() } : {}), amount, + date, currencyCode: manualJournalDTO.currencyCode || baseCurrency, exchangeRate: manualJournalDTO.exchangeRate || 1, - date, journalNumber, + entries, userId: authorizedUser.id, }; return R.compose( diff --git a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts index 215d822da..9edacd478 100644 --- a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts +++ b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts @@ -3,8 +3,8 @@ import * as R from 'ramda'; import { omit, sumBy } from 'lodash'; import { IBillPayment, IBillPaymentDTO, IVendor } from '@/interfaces'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; import { formatDateFields } from '@/utils'; -import HasTenancyService from '@/services/Tenancy/TenancyService'; @Service() export class CommandBillPaymentDTOTransformer { @@ -27,6 +27,12 @@ export class CommandBillPaymentDTOTransformer { const amount = billPaymentDTO.amount ?? sumBy(billPaymentDTO.entries, 'paymentAmount'); + // Associate the default index to each item entry. + const entries = R.compose( + // Associate the default index to payment entries. + assocItemEntriesDefaultIndex + )(billPaymentDTO.entries); + const initialDTO = { ...formatDateFields(omit(billPaymentDTO, ['attachments']), [ 'paymentDate', @@ -34,7 +40,7 @@ export class CommandBillPaymentDTOTransformer { amount, currencyCode: vendor.currencyCode, exchangeRate: billPaymentDTO.exchangeRate || 1, - entries: billPaymentDTO.entries, + entries, }; return R.compose( this.branchDTOTransform.transformDTO(tenantId) diff --git a/packages/server/src/services/Purchases/Bills/BillDTOTransformer.ts b/packages/server/src/services/Purchases/Bills/BillDTOTransformer.ts index 50808340d..f391c4464 100644 --- a/packages/server/src/services/Purchases/Bills/BillDTOTransformer.ts +++ b/packages/server/src/services/Purchases/Bills/BillDTOTransformer.ts @@ -3,7 +3,7 @@ import moment from 'moment'; import { Inject, Service } from 'typedi'; import * as R from 'ramda'; import composeAsync from 'async/compose'; -import { formatDateFields } from 'utils'; +import { assocDepthLevelToObjectTree, formatDateFields } from 'utils'; import { IBillDTO, IBill, @@ -15,6 +15,7 @@ import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/ import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export class BillDTOTransformer { @@ -54,9 +55,9 @@ export class BillDTOTransformer { /** * Converts create bill DTO to model. - * @param {number} tenantId - * @param {IBillDTO} billDTO - * @param {IBill} oldBill + * @param {number} tenantId + * @param {IBillDTO} billDTO + * @param {IBill} oldBill * @returns {IBill} */ public async billDTOToModel( @@ -92,7 +93,9 @@ export class BillDTOTransformer { const entries = R.compose( // Remove tax code from entries. - R.map(R.omit(['taxCode'])) + R.map(R.omit(['taxCode'])), + // Associate the default index to each item entry line. + assocItemEntriesDefaultIndex )(asyncEntries); const initialDTO = { diff --git a/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts b/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts index a07fcc79b..c6e9a1d54 100644 --- a/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts +++ b/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts @@ -9,11 +9,13 @@ import { IVendorCredit, IVendorCreditCreateDTO, IVendorCreditEditDTO, + IVendorCreditEntryDTO, } from '@/interfaces'; import ItemsEntriesService from '@/services/Items/ItemsEntriesService'; import AutoIncrementOrdersService from '@/services/Sales/AutoIncrementOrdersService'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrations/WarehouseTransactionDTOTransform'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export default class BaseVendorCredit { @@ -50,10 +52,18 @@ export default class BaseVendorCredit { const amount = this.itemsEntriesService.getTotalItemsEntries( vendorCreditDTO.entries ); - const entries = vendorCreditDTO.entries.map((entry) => ({ - ...entry, - referenceType: 'VendorCredit', - })); + + const entries = R.compose( + // Associate the default index to each item entry. + assocItemEntriesDefaultIndex, + + // Associate the reference type to item entries. + R.map((entry: IVendorCreditEntryDTO) => ({ + referenceType: 'VendorCredit', + ...entry, + })) + )(vendorCreditDTO.entries); + // Retreive the next vendor credit number. const autoNextNumber = this.getNextCreditNumber(tenantId); diff --git a/packages/server/src/services/Sales/Estimates/CreateSaleEstimate.ts b/packages/server/src/services/Sales/Estimates/CreateSaleEstimate.ts index c7fed6e36..1529368dc 100644 --- a/packages/server/src/services/Sales/Estimates/CreateSaleEstimate.ts +++ b/packages/server/src/services/Sales/Estimates/CreateSaleEstimate.ts @@ -103,5 +103,4 @@ export class CreateSaleEstimate { }, trx ); - } -} + } \ No newline at end of file diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimateDTOTransformer.ts b/packages/server/src/services/Sales/Estimates/SaleEstimateDTOTransformer.ts index df982c816..80879af7f 100644 --- a/packages/server/src/services/Sales/Estimates/SaleEstimateDTOTransformer.ts +++ b/packages/server/src/services/Sales/Estimates/SaleEstimateDTOTransformer.ts @@ -9,6 +9,7 @@ import { WarehouseTransactionDTOTransform } from '@/services/Warehouses/Integrat import { formatDateFields } from '@/utils'; import moment from 'moment'; import { SaleEstimateIncrement } from './SaleEstimateIncrement'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export class SaleEstimateDTOTransformer { @@ -56,6 +57,14 @@ export class SaleEstimateDTOTransformer { // Validate the sale estimate number require. this.validators.validateEstimateNoRequire(estimateNumber); + const entries = R.compose( + // Associate the reference type to item entries. + R.map((entry) => R.assoc('reference_type', 'SaleEstimate', entry)), + + // Associate default index to item entries. + assocItemEntriesDefaultIndex + )(estimateDTO.entries); + const initialDTO = { amount, ...formatDateFields( @@ -65,10 +74,7 @@ export class SaleEstimateDTOTransformer { currencyCode: paymentCustomer.currencyCode, exchangeRate: estimateDTO.exchangeRate || 1, ...(estimateNumber ? { estimateNumber } : {}), - entries: estimateDTO.entries.map((entry) => ({ - reference_type: 'SaleEstimate', - ...entry, - })), + entries, // Avoid rewrite the deliver date in edit mode when already published. ...(estimateDTO.delivered && !oldSaleEstimate?.deliveredAt && { diff --git a/packages/server/src/services/Sales/Invoices/CommandSaleInvoiceDTOTransformer.ts b/packages/server/src/services/Sales/Invoices/CommandSaleInvoiceDTOTransformer.ts index 4a4f5f6ea..8013fe7af 100644 --- a/packages/server/src/services/Sales/Invoices/CommandSaleInvoiceDTOTransformer.ts +++ b/packages/server/src/services/Sales/Invoices/CommandSaleInvoiceDTOTransformer.ts @@ -17,6 +17,7 @@ import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators'; import { SaleInvoiceIncrement } from './SaleInvoiceIncrement'; import { formatDateFields } from 'utils'; import { ItemEntriesTaxTransactions } from '@/services/TaxRates/ItemEntriesTaxTransactions'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; import { ItemEntry } from '@/models'; @Service() @@ -81,7 +82,10 @@ export class CommandSaleInvoiceDTOTransformer { const entries = R.compose( // Remove tax code from entries. - R.map(R.omit(['taxCode'])) + R.map(R.omit(['taxCode'])), + + // Associate the default index for each item entry lin. + assocItemEntriesDefaultIndex )(asyncEntries); const initialDTO = { diff --git a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedDTOTransformer.ts b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedDTOTransformer.ts index e9eed9110..24f0b0737 100644 --- a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedDTOTransformer.ts +++ b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedDTOTransformer.ts @@ -11,6 +11,7 @@ import { PaymentReceivedValidators } from './PaymentReceivedValidators'; import { PaymentReceivedIncrement } from './PaymentReceivedIncrement'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; import { formatDateFields } from '@/utils'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export class PaymentReceiveDTOTransformer { @@ -52,6 +53,11 @@ export class PaymentReceiveDTOTransformer { this.validators.validatePaymentNoRequire(paymentReceiveNo); + const entries = R.compose( + // Associate the default index to each item entry line. + assocItemEntriesDefaultIndex + )(paymentReceiveDTO.entries); + const initialDTO = { ...formatDateFields(omit(paymentReceiveDTO, ['entries', 'attachments']), [ 'paymentDate', @@ -60,9 +66,7 @@ export class PaymentReceiveDTOTransformer { currencyCode: customer.currencyCode, ...(paymentReceiveNo ? { paymentReceiveNo } : {}), exchangeRate: paymentReceiveDTO.exchangeRate || 1, - entries: paymentReceiveDTO.entries.map((entry) => ({ - ...entry, - })), + entries, }; return R.compose( this.branchDTOTransform.transformDTO(tenantId) diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts index 86c391f6e..ae492099a 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts @@ -11,6 +11,7 @@ import { ICustomer, ISaleReceipt, ISaleReceiptDTO } from '@/interfaces'; import { formatDateFields } from '@/utils'; import { SaleReceiptIncrement } from './SaleReceiptIncrement'; import { ItemEntry } from '@/models'; +import { assocItemEntriesDefaultIndex } from '@/services/Items/utils'; @Service() export class SaleReceiptDTOTransformer { @@ -61,11 +62,16 @@ export class SaleReceiptDTOTransformer { ...entry, })); - const entries = await composeAsync( + const asyncEntries = await composeAsync( // Sets default cost and sell account to receipt items entries. this.itemsEntriesService.setItemsEntriesDefaultAccounts(tenantId) )(initialEntries); + const entries = R.compose( + // Associate the default index for each item entry. + assocItemEntriesDefaultIndex + )(asyncEntries); + const initialDTO = { amount, ...formatDateFields(