From 7fc13208342cc28a785788e34ec3b9c79580e2c5 Mon Sep 17 00:00:00 2001
From: Ahmed Bouhuolia <a.bouhuolia@gmail.com>
Date: Fri, 1 Dec 2023 17:04:11 +0200
Subject: [PATCH 1/4] fix(server): allow decimal amount in sale/purchase
 transactions.

---
 packages/server/src/api/controllers/Purchases/Bills.ts       | 2 +-
 .../server/src/api/controllers/Purchases/BillsPayments.ts    | 2 +-
 .../server/src/api/controllers/Purchases/VendorCredit.ts     | 5 ++---
 packages/server/src/api/controllers/Sales/CreditNotes.ts     | 2 +-
 packages/server/src/api/controllers/Sales/PaymentReceives.ts | 2 +-
 packages/server/src/api/controllers/Sales/SalesReceipts.ts   | 2 +-
 6 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/packages/server/src/api/controllers/Purchases/Bills.ts b/packages/server/src/api/controllers/Purchases/Bills.ts
index 61fc5cf70d..2cd9e62ded 100644
--- a/packages/server/src/api/controllers/Purchases/Bills.ts
+++ b/packages/server/src/api/controllers/Purchases/Bills.ts
@@ -122,7 +122,7 @@ export default class BillsController extends BaseController {
       check('entries.*.index').exists().isNumeric().toInt(),
       check('entries.*.item_id').exists().isNumeric().toInt(),
       check('entries.*.rate').exists().isNumeric().toFloat(),
-      check('entries.*.quantity').exists().isNumeric().toFloat(),
+      check('entries.*.quantity').exists().isNumeric().toInt(),
       check('entries.*.discount')
         .optional({ nullable: true })
         .isNumeric()
diff --git a/packages/server/src/api/controllers/Purchases/BillsPayments.ts b/packages/server/src/api/controllers/Purchases/BillsPayments.ts
index 8959fdd8e1..a663a30329 100644
--- a/packages/server/src/api/controllers/Purchases/BillsPayments.ts
+++ b/packages/server/src/api/controllers/Purchases/BillsPayments.ts
@@ -121,7 +121,7 @@ export default class BillsPayments extends BaseController {
       check('entries').exists().isArray({ min: 1 }),
       check('entries.*.index').optional().isNumeric().toInt(),
       check('entries.*.bill_id').exists().isNumeric().toInt(),
-      check('entries.*.payment_amount').exists().isNumeric().toInt(),
+      check('entries.*.payment_amount').exists().isNumeric().toFloat(),
     ];
   }
 
diff --git a/packages/server/src/api/controllers/Purchases/VendorCredit.ts b/packages/server/src/api/controllers/Purchases/VendorCredit.ts
index 95405851c3..3d28323087 100644
--- a/packages/server/src/api/controllers/Purchases/VendorCredit.ts
+++ b/packages/server/src/api/controllers/Purchases/VendorCredit.ts
@@ -173,7 +173,7 @@ export default class VendorCreditController extends BaseController {
       check('entries.*.index').exists().isNumeric().toInt(),
       check('entries.*.item_id').exists().isNumeric().toInt(),
       check('entries.*.rate').exists().isNumeric().toFloat(),
-      check('entries.*.quantity').exists().isNumeric().toFloat(),
+      check('entries.*.quantity').exists().isNumeric().toInt(),
       check('entries.*.discount')
         .optional({ nullable: true })
         .isNumeric()
@@ -211,12 +211,11 @@ export default class VendorCreditController extends BaseController {
       check('branch_id').optional({ nullable: true }).isNumeric().toInt(),
 
       check('entries').isArray({ min: 1 }),
-
       check('entries.*.id').optional().isNumeric().toInt(),
       check('entries.*.index').exists().isNumeric().toInt(),
       check('entries.*.item_id').exists().isNumeric().toInt(),
       check('entries.*.rate').exists().isNumeric().toFloat(),
-      check('entries.*.quantity').exists().isNumeric().toFloat(),
+      check('entries.*.quantity').exists().isNumeric().toInt(),
       check('entries.*.discount')
         .optional({ nullable: true })
         .isNumeric()
diff --git a/packages/server/src/api/controllers/Sales/CreditNotes.ts b/packages/server/src/api/controllers/Sales/CreditNotes.ts
index 29bcae2fb1..77b506c7dd 100644
--- a/packages/server/src/api/controllers/Sales/CreditNotes.ts
+++ b/packages/server/src/api/controllers/Sales/CreditNotes.ts
@@ -222,7 +222,7 @@ export default class PaymentReceivesController extends BaseController {
       check('entries.*.index').exists().isNumeric().toInt(),
       check('entries.*.item_id').exists().isNumeric().toInt(),
       check('entries.*.rate').exists().isNumeric().toFloat(),
-      check('entries.*.quantity').exists().isNumeric().toFloat(),
+      check('entries.*.quantity').exists().isNumeric().toInt(),
       check('entries.*.discount')
         .optional({ nullable: true })
         .isNumeric()
diff --git a/packages/server/src/api/controllers/Sales/PaymentReceives.ts b/packages/server/src/api/controllers/Sales/PaymentReceives.ts
index ec210ad236..7cfa93a003 100644
--- a/packages/server/src/api/controllers/Sales/PaymentReceives.ts
+++ b/packages/server/src/api/controllers/Sales/PaymentReceives.ts
@@ -142,7 +142,7 @@ export default class PaymentReceivesController extends BaseController {
       check('entries.*.id').optional({ nullable: true }).isNumeric().toInt(),
       check('entries.*.index').optional().isNumeric().toInt(),
       check('entries.*.invoice_id').exists().isNumeric().toInt(),
-      check('entries.*.payment_amount').exists().isNumeric().toInt(),
+      check('entries.*.payment_amount').exists().isNumeric().toFloat(),
     ];
   }
 
diff --git a/packages/server/src/api/controllers/Sales/SalesReceipts.ts b/packages/server/src/api/controllers/Sales/SalesReceipts.ts
index d364826b6c..3eabcf84ef 100644
--- a/packages/server/src/api/controllers/Sales/SalesReceipts.ts
+++ b/packages/server/src/api/controllers/Sales/SalesReceipts.ts
@@ -117,7 +117,7 @@ export default class SalesReceiptsController extends BaseController {
       check('entries.*.index').exists().isNumeric().toInt(),
       check('entries.*.item_id').exists().isNumeric().toInt(),
       check('entries.*.quantity').exists().isNumeric().toInt(),
-      check('entries.*.rate').exists().isNumeric().toInt(),
+      check('entries.*.rate').exists().isNumeric().toFloat(),
       check('entries.*.discount')
         .optional({ nullable: true })
         .isNumeric()

From 0f39cfb3afa188e293b918512dc281c7840555ac Mon Sep 17 00:00:00 2001
From: Ahmed Bouhuolia <a.bouhuolia@gmail.com>
Date: Sat, 2 Dec 2023 15:15:12 +0200
Subject: [PATCH 2/4] fix: change rate column to decimal of item entries table

---
 .../20231202124014_change_item_entries_rate_to_float.js  | 9 +++++++++
 packages/server/src/interfaces/Roles.ts                  | 5 +++--
 2 files changed, 12 insertions(+), 2 deletions(-)
 create mode 100644 packages/server/src/database/migrations/20231202124014_change_item_entries_rate_to_float.js

diff --git a/packages/server/src/database/migrations/20231202124014_change_item_entries_rate_to_float.js b/packages/server/src/database/migrations/20231202124014_change_item_entries_rate_to_float.js
new file mode 100644
index 0000000000..8024400452
--- /dev/null
+++ b/packages/server/src/database/migrations/20231202124014_change_item_entries_rate_to_float.js
@@ -0,0 +1,9 @@
+exports.up = function (knex) {
+  return knex.schema.alterTable('items_entries', (table) => {
+    table.decimal('rate', 15, 5).alter();
+  });
+};
+
+exports.down = function (knex) {
+  return knex.table('items_entries', (table) => {});
+};
diff --git a/packages/server/src/interfaces/Roles.ts b/packages/server/src/interfaces/Roles.ts
index cfa7276ad1..f9d3382682 100644
--- a/packages/server/src/interfaces/Roles.ts
+++ b/packages/server/src/interfaces/Roles.ts
@@ -1,5 +1,5 @@
+import { Knex } from 'knex';
 import { Ability, RawRuleOf, ForcedSubject } from '@casl/ability';
-import Knex from 'knex';
 
 export const actions = [
   'manage',
@@ -96,7 +96,8 @@ export enum AbilitySubject {
   Preferences = 'Preferences',
   CreditNote = 'CreditNode',
   VendorCredit = 'VendorCredit',
-  Project = 'Project'
+  Project = 'Project',
+  TaxRate = 'TaxRate'
 }
 
 export interface IRoleCreatedPayload {

From fb70c9446523e48ae72cac2b149ef88ceb02f65a Mon Sep 17 00:00:00 2001
From: Ahmed Bouhuolia <a.bouhuolia@gmail.com>
Date: Mon, 4 Dec 2023 08:21:06 +0200
Subject: [PATCH 3/4] fix(server): add formatted values to responses
 transformers

---
 .../CreditNotes/CreditNoteTransformer.ts      | 18 ++++++++-
 .../BillPaymentEntryTransformer.ts            | 20 ++++++++++
 .../BillPayments/BillPaymentTransformer.ts    | 10 ++++-
 .../Bills/PurchaseInvoiceTransformer.ts       | 13 +++++++
 .../VendorCredits/VendorCreditTransformer.ts  | 16 +++++++-
 .../Estimates/SaleEstimateTransformer.ts      | 14 ++++++-
 .../Sales/Invoices/ItemEntryTransformer.ts    | 37 +++++++++++++++++++
 .../Sales/Invoices/SaleInvoiceTransformer.ts  | 14 +++++++
 .../GetPaymentReceiveInvoices.ts              |  2 +-
 .../PaymentReceiveEntryTransformer.ts         | 29 +++++++++++++++
 .../PaymentReceiveTransformer.ts              | 10 ++---
 .../Sales/Receipts/SaleReceiptTransformer.ts  | 19 +++++++++-
 12 files changed, 189 insertions(+), 13 deletions(-)
 create mode 100644 packages/server/src/services/Purchases/BillPayments/BillPaymentEntryTransformer.ts
 create mode 100644 packages/server/src/services/Sales/Invoices/ItemEntryTransformer.ts
 create mode 100644 packages/server/src/services/Sales/PaymentReceives/PaymentReceiveEntryTransformer.ts

diff --git a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts
index 79d731ce32..f532c2eab2 100644
--- a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts
+++ b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts
@@ -1,5 +1,7 @@
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
+import { ItemEntryTransformer } from '../Sales/Invoices/ItemEntryTransformer';
+import { ICreditNote } from '@/interfaces';
 
 export class CreditNoteTransformer extends Transformer {
   /**
@@ -11,7 +13,8 @@ export class CreditNoteTransformer extends Transformer {
       'formattedCreditsRemaining',
       'formattedCreditNoteDate',
       'formattedAmount',
-      'formattedCreditsUsed'
+      'formattedCreditsUsed',
+      'entries',
     ];
   };
 
@@ -51,9 +54,20 @@ export class CreditNoteTransformer extends Transformer {
    * @param {ICreditNote} credit
    * @returns {string}
    */
-   protected formattedCreditsUsed = (credit) => {
+  protected formattedCreditsUsed = (credit) => {
     return formatNumber(credit.creditsUsed, {
       currencyCode: credit.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the credit note.
+   * @param {ICreditNote} credit
+   * @returns {}
+   */
+  protected entries = (credit) => {
+    return this.item(credit.entries, new ItemEntryTransformer(), {
+      currencyCode: credit.currencyCode,
+    });
+  };
 }
diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentEntryTransformer.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentEntryTransformer.ts
new file mode 100644
index 0000000000..19dcbacb56
--- /dev/null
+++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentEntryTransformer.ts
@@ -0,0 +1,20 @@
+import { Transformer } from '@/lib/Transformer/Transformer';
+import { formatNumber } from '@/utils';
+
+export class BillPaymentEntryTransformer extends Transformer {
+  /**
+   * Include these attributes to bill payment object.
+   * @returns {Array}
+   */
+  public includeAttributes = (): string[] => {
+    return ['paymentAmountFormatted'];
+  };
+
+  /**
+   * Retreives the payment amount formatted.
+   * @returns {string}
+   */
+  protected paymentAmountFormatted(entry) {
+    return formatNumber(entry.paymentAmount, { money: false });
+  }
+}
diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts
index 4345f028be..a6662dc2d4 100644
--- a/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts
+++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts
@@ -1,6 +1,7 @@
 import { IBillPayment } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
+import { BillPaymentEntryTransformer } from './BillPaymentEntryTransformer';
 
 export class BillPaymentTransformer extends Transformer {
   /**
@@ -8,7 +9,7 @@ export class BillPaymentTransformer extends Transformer {
    * @returns {Array}
    */
   public includeAttributes = (): string[] => {
-    return ['formattedPaymentDate', 'formattedAmount'];
+    return ['formattedPaymentDate', 'formattedAmount', 'entries'];
   };
 
   /**
@@ -30,4 +31,11 @@ export class BillPaymentTransformer extends Transformer {
       currencyCode: billPayment.currencyCode,
     });
   };
+
+  /**
+   * Retreives the bill payment entries.
+   */
+  protected entries = (billPayment) => {
+    return this.item(billPayment.entries, new BillPaymentEntryTransformer());
+  };
 }
diff --git a/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts b/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts
index 07d3a78d68..4ec163d8b6 100644
--- a/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts
+++ b/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts
@@ -1,5 +1,6 @@
 import { IBill } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
+import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer';
 import { SaleInvoiceTaxEntryTransformer } from '@/services/Sales/Invoices/SaleInvoiceTaxEntryTransformer';
 import { formatNumber } from 'utils';
 
@@ -23,6 +24,7 @@ export class PurchaseInvoiceTransformer extends Transformer {
       'totalFormatted',
       'totalLocalFormatted',
       'taxes',
+      'entries',
     ];
   };
 
@@ -178,4 +180,15 @@ export class PurchaseInvoiceTransformer extends Transformer {
       currencyCode: bill.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the bill.
+   * @param {Bill} credit
+   * @returns {}
+   */
+  protected entries = (bill) => {
+    return this.item(bill.entries, new ItemEntryTransformer(), {
+      currencyCode: bill.currencyCode,
+    });
+  };
 }
diff --git a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
index f4d75409e1..3d74ee7701 100644
--- a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
+++ b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts
@@ -1,4 +1,6 @@
+import { IVendorCredit } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
+import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer';
 import { formatNumber } from 'utils';
 
 export class VendorCreditTransformer extends Transformer {
@@ -8,9 +10,10 @@ export class VendorCreditTransformer extends Transformer {
    */
   public includeAttributes = (): string[] => {
     return [
-      'formattedVendorCreditDate',
       'formattedAmount',
+      'formattedVendorCreditDate',
       'formattedCreditsRemaining',
+      'entries',
     ];
   };
 
@@ -44,4 +47,15 @@ export class VendorCreditTransformer extends Transformer {
       currencyCode: credit.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the bill.
+   * @param {IVendorCredit} vendorCredit
+   * @returns {}
+   */
+  protected entries = (vendorCredit) => {
+    return this.item(vendorCredit.entries, new ItemEntryTransformer(), {
+      currencyCode: vendorCredit.currencyCode,
+    });
+  };
 }
diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts
index 770a13c3cd..1102f7bd0b 100644
--- a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts
+++ b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts
@@ -1,7 +1,7 @@
-import { Service } from 'typedi';
 import { ISaleEstimate } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
+import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer';
 
 export class SaleEstimateTransfromer extends Transformer {
   /**
@@ -16,6 +16,7 @@ export class SaleEstimateTransfromer extends Transformer {
       'formattedDeliveredAtDate',
       'formattedApprovedAtDate',
       'formattedRejectedAtDate',
+      'entries',
     ];
   };
 
@@ -74,4 +75,15 @@ export class SaleEstimateTransfromer extends Transformer {
       currencyCode: estimate.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the sale estimate.
+   * @param {ISaleEstimate} estimate
+   * @returns {}
+   */
+  protected entries = (estimate) => {
+    return this.item(estimate.entries, new ItemEntryTransformer(), {
+      currencyCode: estimate.currencyCode,
+    });
+  };
 }
diff --git a/packages/server/src/services/Sales/Invoices/ItemEntryTransformer.ts b/packages/server/src/services/Sales/Invoices/ItemEntryTransformer.ts
new file mode 100644
index 0000000000..ad0d88525a
--- /dev/null
+++ b/packages/server/src/services/Sales/Invoices/ItemEntryTransformer.ts
@@ -0,0 +1,37 @@
+import { IItemEntry } from '@/interfaces';
+import { Transformer } from '@/lib/Transformer/Transformer';
+import { formatNumber } from '@/utils';
+
+export class ItemEntryTransformer extends Transformer {
+  /**
+   * Include these attributes to item entry object.
+   * @returns {Array}
+   */
+  public includeAttributes = (): string[] => {
+    return ['rateFormatted', 'totalFormatted'];
+  };
+
+  /**
+   * Retrieves the formatted rate of item entry.
+   * @param {IItemEntry} itemEntry -
+   * @returns {string}
+   */
+  protected rateFormatted = (entry: IItemEntry): string => {
+    return formatNumber(entry.rate, {
+      currencyCode: this.context.currencyCode,
+      money: false,
+    });
+  };
+
+  /**
+   * Retrieves the formatted total of item entry.
+   * @param {IItemEntry} entry
+   * @returns {string}
+   */
+  protected totalFormatted = (entry: IItemEntry): string => {
+    return formatNumber(entry.total, {
+      currencyCode: this.context.currencyCode,
+      money: false,
+    });
+  };
+}
diff --git a/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts b/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts
index 979b312a9f..878160b967 100644
--- a/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts
+++ b/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts
@@ -1,6 +1,7 @@
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
 import { SaleInvoiceTaxEntryTransformer } from './SaleInvoiceTaxEntryTransformer';
+import { ItemEntryTransformer } from './ItemEntryTransformer';
 
 export class SaleInvoiceTransformer extends Transformer {
   /**
@@ -23,6 +24,7 @@ export class SaleInvoiceTransformer extends Transformer {
       'totalFormatted',
       'totalLocalFormatted',
       'taxes',
+      'entries',
     ];
   };
 
@@ -95,6 +97,7 @@ export class SaleInvoiceTransformer extends Transformer {
   protected subtotalFormatted = (invoice): string => {
     return formatNumber(invoice.subtotal, {
       currencyCode: this.context.organization.baseCurrency,
+      money: false,
     });
   };
 
@@ -176,4 +179,15 @@ export class SaleInvoiceTransformer extends Transformer {
       currencyCode: invoice.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the sale invoice.
+   * @param {ISaleInvoice} invoice
+   * @returns {}
+   */
+  protected entries = (invoice) => {
+    return this.item(invoice.entries, new ItemEntryTransformer(), {
+      currencyCode: invoice.currencyCode,
+    });
+  };
 }
diff --git a/packages/server/src/services/Sales/PaymentReceives/GetPaymentReceiveInvoices.ts b/packages/server/src/services/Sales/PaymentReceives/GetPaymentReceiveInvoices.ts
index 48629770ca..901c6b4927 100644
--- a/packages/server/src/services/Sales/PaymentReceives/GetPaymentReceiveInvoices.ts
+++ b/packages/server/src/services/Sales/PaymentReceives/GetPaymentReceiveInvoices.ts
@@ -1,5 +1,5 @@
-import HasTenancyService from '@/services/Tenancy/TenancyService';
 import { Inject, Service } from 'typedi';
+import HasTenancyService from '@/services/Tenancy/TenancyService';
 import { PaymentReceiveValidators } from './PaymentReceiveValidators';
 
 @Service()
diff --git a/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveEntryTransformer.ts b/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveEntryTransformer.ts
new file mode 100644
index 0000000000..fe9fe9b679
--- /dev/null
+++ b/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveEntryTransformer.ts
@@ -0,0 +1,29 @@
+import { Transformer } from '@/lib/Transformer/Transformer';
+import { SaleInvoiceTransformer } from '../Invoices/SaleInvoiceTransformer';
+import { formatNumber } from '@/utils';
+
+export class PaymentReceiveEntryTransfromer extends Transformer {
+  /**
+   * Include these attributes to payment receive entry object.
+   * @returns {Array}
+   */
+  public includeAttributes = (): string[] => {
+    return ['paymentAmountFormatted', 'entry'];
+  };
+
+  /**
+   * Retreives the payment amount formatted.
+   * @param entry
+   * @returns {string}
+   */
+  protected paymentAmountFormatted(entry) {
+    return formatNumber(entry.paymentAmount, { money: false });
+  }
+
+  /**
+   * Retreives the transformed invoice.
+   */
+  protected invoice(entry) {
+    return this.item(entry.invoice, new SaleInvoiceTransformer());
+  }
+}
diff --git a/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveTransformer.ts b/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveTransformer.ts
index 0cb45a9733..afce4203bb 100644
--- a/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveTransformer.ts
+++ b/packages/server/src/services/Sales/PaymentReceives/PaymentReceiveTransformer.ts
@@ -2,6 +2,7 @@ import { IPaymentReceive, IPaymentReceiveEntry } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
 import { SaleInvoiceTransformer } from '../Invoices/SaleInvoiceTransformer';
+import { PaymentReceiveEntryTransfromer } from './PaymentReceiveEntryTransformer';
 
 export class PaymentReceiveTransfromer extends Transformer {
   /**
@@ -45,14 +46,11 @@ export class PaymentReceiveTransfromer extends Transformer {
   };
 
   /**
-   * Retrieves the 
-   * @param {IPaymentReceive} payment 
+   * Retrieves the payment entries.
+   * @param {IPaymentReceive} payment
    * @returns {IPaymentReceiveEntry[]}
    */
   protected entries = (payment: IPaymentReceive): IPaymentReceiveEntry[] => {
-    return payment?.entries?.map((entry) => ({
-      ...entry,
-      invoice: this.item(entry.invoice, new SaleInvoiceTransformer()),
-    }));
+    return this.item(payment.entries, new PaymentReceiveEntryTransfromer());
   };
 }
diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts
index 0469adfa00..c8b9507111 100644
--- a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts
+++ b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts
@@ -2,6 +2,7 @@ import { Service } from 'typedi';
 import { ISaleReceipt } from '@/interfaces';
 import { Transformer } from '@/lib/Transformer/Transformer';
 import { formatNumber } from 'utils';
+import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer';
 
 @Service()
 export class SaleReceiptTransformer extends Transformer {
@@ -10,7 +11,12 @@ export class SaleReceiptTransformer extends Transformer {
    * @returns {Array}
    */
   public includeAttributes = (): string[] => {
-    return ['formattedAmount', 'formattedReceiptDate', 'formattedClosedAtDate'];
+    return [
+      'formattedAmount',
+      'formattedReceiptDate',
+      'formattedClosedAtDate',
+      'entries',
+    ];
   };
 
   /**
@@ -41,4 +47,15 @@ export class SaleReceiptTransformer extends Transformer {
       currencyCode: receipt.currencyCode,
     });
   };
+
+  /**
+   * Retrieves the entries of the credit note.
+   * @param {ISaleReceipt} credit
+   * @returns {}
+   */
+  protected entries = (receipt) => {
+    return this.item(receipt.entries, new ItemEntryTransformer(), {
+      currencyCode: receipt.currencyCode,
+    });
+  };
 }

From 33afa3af6408c988a9afec1eabdb637e780a4ae8 Mon Sep 17 00:00:00 2001
From: Ahmed Bouhuolia <a.bouhuolia@gmail.com>
Date: Mon, 4 Dec 2023 08:31:18 +0200
Subject: [PATCH 4/4] fix(webapp): use the server formatted value

---
 .../webapp/src/containers/Drawers/BillDrawer/utils.tsx |  8 +++-----
 .../Drawers/CreditNoteDetailDrawer/utils.tsx           | 10 ++++------
 .../containers/Drawers/EstimateDetailDrawer/utils.tsx  |  9 ++++-----
 .../InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx   |  2 +-
 .../containers/Drawers/InvoiceDetailDrawer/utils.tsx   | 10 ++++------
 .../Drawers/PaymentMadeDetailDrawer/utils.tsx          |  5 ++---
 .../Drawers/PaymentReceiveDetailDrawer/utils.tsx       |  5 ++---
 .../ReceiptDetailDrawerProvider.tsx                    |  9 +++------
 .../ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx   |  2 +-
 .../containers/Drawers/ReceiptDetailDrawer/utils.tsx   |  6 ++----
 .../VendorCreditDetailDrawerFooter.tsx                 |  2 +-
 .../Drawers/VendorCreditDetailDrawer/utils.tsx         | 10 ++++------
 12 files changed, 31 insertions(+), 47 deletions(-)

diff --git a/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx
index 39cf8052d6..9b9691ddfa 100644
--- a/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/BillDrawer/utils.tsx
@@ -63,8 +63,7 @@ export const useBillReadonlyEntriesTableColumns = () => {
       },
       {
         Header: intl.get('rate'),
-        accessor: 'rate',
-        Cell: FormatNumberCell,
+        accessor: 'rate_formatted',
         width: getColumnWidth(entries, 'rate', {
           minWidth: 60,
           magicSpacing: 5,
@@ -75,9 +74,8 @@ export const useBillReadonlyEntriesTableColumns = () => {
       },
       {
         Header: intl.get('amount'),
-        accessor: 'amount',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'amount', {
+        accessor: 'total_formatted',
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx
index b9bb3a1e8a..85e57c5ee9 100644
--- a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/utils.tsx
@@ -60,9 +60,8 @@ export const useCreditNoteReadOnlyEntriesColumns = () => {
       },
       {
         Header: intl.get('rate'),
-        accessor: 'rate',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'rate', {
+        accessor: 'rate_formatted',
+        width: getColumnWidth(entries, 'rate_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
@@ -72,9 +71,8 @@ export const useCreditNoteReadOnlyEntriesColumns = () => {
       },
       {
         Header: intl.get('amount'),
-        accessor: 'amount',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'amount', {
+        accessor: 'total_formatted',
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/utils.tsx
index 3172feae40..71c869c7e9 100644
--- a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/utils.tsx
@@ -47,9 +47,8 @@ export const useEstimateReadonlyEntriesColumns = () => {
       },
       {
         Header: intl.get('rate'),
-        accessor: 'rate',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'rate', {
+        accessor: 'rate_formatted',
+        width: getColumnWidth(entries, 'rate_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
@@ -59,9 +58,9 @@ export const useEstimateReadonlyEntriesColumns = () => {
       },
       {
         Header: intl.get('amount'),
-        accessor: 'amount',
+        accessor: 'total_formatted',
         Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'amount', {
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx
index 899f2bb7b6..dd225739c7 100644
--- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx
+++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx
@@ -23,7 +23,7 @@ export function InvoiceDetailTableFooter() {
       <InvoiceTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
         <TotalLine
           title={<T id={'invoice.details.subtotal'} />}
-          value={<FormatNumber value={invoice.subtotal_formatted} />}
+          value={invoice.subtotal_formatted}
           borderStyle={TotalLineBorderStyle.SingleDark}
         />
         {invoice.taxes.map((taxRate) => (
diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx
index 063c335eb3..fc2d3d1b4e 100644
--- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/utils.tsx
@@ -64,24 +64,22 @@ export const useInvoiceReadonlyEntriesColumns = () => {
       },
       {
         Header: intl.get('rate'),
-        accessor: 'rate',
-        Cell: FormatNumberCell,
+        accessor: 'rate_formatted',
         align: 'right',
         disableSortBy: true,
         textOverview: true,
-        width: getColumnWidth(entries, 'rate', {
+        width: getColumnWidth(entries, 'rate_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
       },
       {
         Header: intl.get('amount'),
-        accessor: 'amount',
-        Cell: FormatNumberCell,
+        accessor: 'total_formatted',
         align: 'right',
         disableSortBy: true,
         textOverview: true,
-        width: getColumnWidth(entries, 'amount', {
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/PaymentMadeDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/PaymentMadeDetailDrawer/utils.tsx
index 4721e88c4d..939778772c 100644
--- a/packages/webapp/src/containers/Drawers/PaymentMadeDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/PaymentMadeDetailDrawer/utils.tsx
@@ -52,9 +52,8 @@ export const usePaymentMadeEntriesColumns = () => {
       },
       {
         Header: intl.get('payment_amount'),
-        accessor: 'payment_amount',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'payment_amount', {
+        accessor: 'payment_amount_formatted',
+        width: getColumnWidth(entries, 'payment_amount_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/PaymentReceiveDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/PaymentReceiveDetailDrawer/utils.tsx
index c0fda5844f..8971f3ec60 100644
--- a/packages/webapp/src/containers/Drawers/PaymentReceiveDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/PaymentReceiveDetailDrawer/utils.tsx
@@ -63,10 +63,9 @@ export const usePaymentReceiveEntriesColumns = () => {
       },
       {
         Header: intl.get('payment_amount'),
-        accessor: 'invoice.payment_amount',
-        Cell: FormatNumberCell,
+        accessor: 'payment_amount_formatted',
         align: 'right',
-        width: getColumnWidth(entries, 'invoice.payment_amount', {
+        width: getColumnWidth(entries, 'payment_amount_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailDrawerProvider.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailDrawerProvider.tsx
index 577ef092e3..ae87dfe02b 100644
--- a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailDrawerProvider.tsx
+++ b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailDrawerProvider.tsx
@@ -18,12 +18,9 @@ function ReceiptDetailDrawerProvider({ receiptId, ...props }) {
   const { featureCan } = useFeatureCan();
 
   // Fetch sale receipt details.
-  const { data: receipt, isFetching: isReceiptLoading } = useReceipt(
-    receiptId,
-    {
-      enabled: !!receiptId,
-    },
-  );
+  const { data: receipt, isLoading: isReceiptLoading } = useReceipt(receiptId, {
+    enabled: !!receiptId,
+  });
 
   // Provider.
   const provider = {
diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx
index 56ee5c87b1..657606f176 100644
--- a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx
+++ b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx
@@ -23,7 +23,7 @@ export default function ReceiptDetailTableFooter() {
       <ReceiptTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
         <TotalLine
           title={<T id={'receipt.details.subtotal'} />}
-          value={<FormatNumber value={receipt.amount} />}
+          value={receipt.formatted_amount}
         />
         <TotalLine
           title={<T id={'receipt.details.total'} />}
diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx
index cf48f1d9a4..0241d3e762 100644
--- a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/utils.tsx
@@ -43,8 +43,7 @@ export const useReceiptReadonlyEntriesTableColumns = () => {
       {
         Header: intl.get('rate'),
         accessor: 'rate',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'rate', {
+        width: getColumnWidth(entries, 'rate_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
@@ -55,8 +54,7 @@ export const useReceiptReadonlyEntriesTableColumns = () => {
       {
         Header: intl.get('amount'),
         accessor: 'amount',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'amount', {
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
diff --git a/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/VendorCreditDetailDrawerFooter.tsx b/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/VendorCreditDetailDrawerFooter.tsx
index 42fd4eb60d..e11cbce671 100644
--- a/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/VendorCreditDetailDrawerFooter.tsx
+++ b/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/VendorCreditDetailDrawerFooter.tsx
@@ -23,7 +23,7 @@ export default function VendorCreditDetailDrawerFooter() {
       <VendorCreditTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
         <TotalLine
           title={<T id={'vendor_credit.drawer.label_subtotal'} />}
-          value={<FormatNumber value={vendorCredit.formatted_amount} />}
+          value={vendorCredit.formatted_amount}
           borderStyle={TotalLineBorderStyle.SingleDark}
         />
         <TotalLine
diff --git a/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/utils.tsx b/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/utils.tsx
index 70c8ae7352..95d7bba67d 100644
--- a/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/utils.tsx
+++ b/packages/webapp/src/containers/Drawers/VendorCreditDetailDrawer/utils.tsx
@@ -61,9 +61,8 @@ export const useVendorCreditReadonlyEntriesTableColumns = () => {
       },
       {
         Header: intl.get('rate'),
-        accessor: 'rate',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'rate', {
+        accessor: 'rate_formatted',
+        width: getColumnWidth(entries, 'rate_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),
@@ -73,9 +72,8 @@ export const useVendorCreditReadonlyEntriesTableColumns = () => {
       },
       {
         Header: intl.get('amount'),
-        accessor: 'amount',
-        Cell: FormatNumberCell,
-        width: getColumnWidth(entries, 'amount', {
+        accessor: 'total_formatted',
+        width: getColumnWidth(entries, 'total_formatted', {
           minWidth: 60,
           magicSpacing: 5,
         }),