From 3a19518440d8b9defd93d7324dabc059d96ef360 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 3 Dec 2024 17:53:37 +0200 Subject: [PATCH 1/5] fix: update financial forms to use new formatted amount utilities and add adjustment fields --- .../components/PageForm/PageFormBigNumber.tsx | 14 +++-- .../BillDrawer/BillDetailTableFooter.tsx | 6 ++ .../CreditNoteDetailHeader.tsx | 2 +- .../CreditNoteDetailTableFooter.tsx | 8 ++- .../InvoiceDetailTableFooter.tsx | 8 ++- .../ReceiptDetailHeader.tsx | 2 +- .../ReceiptDetailTableFooter.tsx | 11 +++- .../ExpenseForm/ExpenseFormFooterRight.tsx | 12 ++-- .../ExpenseForm/ExpenseFormHeader.tsx | 19 ++---- .../containers/Expenses/ExpenseForm/utils.tsx | 58 +++++++++++++------ .../Bills/BillForm/BillFormHeader.tsx | 18 ++---- .../Purchases/Bills/BillForm/utils.tsx | 9 ++- .../VendorCreditNoteFormHeader.tsx | 16 +---- .../CreditNotes/CreditNoteForm/utils.tsx | 6 +- .../CreditNoteForm/CreditNoteFormHeader.tsx | 14 +---- .../EstimateForm/EstimateFormDialogs.tsx | 1 + .../EstimateForm/EstimateFormHeader.tsx | 19 ++---- .../Sales/Estimates/EstimateForm/utils.tsx | 1 + .../InvoiceForm/InvoiceFormHeader.tsx | 15 +---- .../Sales/Invoices/InvoiceForm/utils.tsx | 4 +- .../ReceiptForm/ReceiptFormHeader.tsx | 18 ++---- 21 files changed, 128 insertions(+), 133 deletions(-) diff --git a/packages/webapp/src/components/PageForm/PageFormBigNumber.tsx b/packages/webapp/src/components/PageForm/PageFormBigNumber.tsx index 5508b8fdb..914cc95a0 100644 --- a/packages/webapp/src/components/PageForm/PageFormBigNumber.tsx +++ b/packages/webapp/src/components/PageForm/PageFormBigNumber.tsx @@ -2,18 +2,22 @@ import React from 'react'; import classNames from 'classnames'; import { CLASSES } from '@/constants/classes'; -import { Money } from '@/components'; import '@/style/components/BigAmount.scss'; -export function PageFormBigNumber({ label, amount, currencyCode }) { +interface PageFormBigNumberProps { + label: string; + amount: string | number; +} +export function PageFormBigNumber({ + label, + amount, +}: PageFormBigNumberProps) { return (
{label} -

- -

+

{amount}

); diff --git a/packages/webapp/src/containers/Drawers/BillDrawer/BillDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/BillDrawer/BillDetailTableFooter.tsx index 458705217..558d0f1ca 100644 --- a/packages/webapp/src/containers/Drawers/BillDrawer/BillDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/BillDrawer/BillDetailTableFooter.tsx @@ -42,6 +42,12 @@ export function BillDetailTableFooter() { textStyle={TotalLineTextStyle.Regular} /> )} + {bill.adjustment > 0 && ( + + )} } value={bill.total_formatted} diff --git a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailHeader.tsx b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailHeader.tsx index ffb1f7985..c5bec8978 100644 --- a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailHeader.tsx +++ b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailHeader.tsx @@ -30,7 +30,7 @@ export default function CreditNoteDetailHeader() { - {creditNote.formatted_amount} + {creditNote.total_formatted} diff --git a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailTableFooter.tsx index 881ac1def..ddb828370 100644 --- a/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/CreditNoteDetailDrawer/CreditNoteDetailTableFooter.tsx @@ -21,6 +21,7 @@ export default function CreditNoteDetailTableFooter() { } value={creditNote.formatted_subtotal} + borderStyle={TotalLineBorderStyle.SingleDark} /> {creditNote.discount_amount > 0 && ( + )} + {creditNote.adjustment > 0 && ( + )} )} + {invoice.adjustment > 0 && ( + + )} {invoice.taxes.map((taxRate) => ( ))} - } value={invoice.total_formatted} diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailHeader.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailHeader.tsx index a55d47ee6..21bd0a923 100644 --- a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailHeader.tsx +++ b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailHeader.tsx @@ -31,7 +31,7 @@ export default function ReceiptDetailHeader() { -

{receipt.formatted_amount}

+

{receipt.total_formatted}

diff --git a/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/ReceiptDetailDrawer/ReceiptDetailTableFooter.tsx index d142f0775..ee799c2a7 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() { } - value={receipt.formatted_subtotal} + value={receipt.subtotal_formatted} /> {receipt.discount_amount > 0 && ( )} + {receipt.adjustment > 0 && ( + + )} } - value={receipt.formatted_amount} + value={receipt.total_formatted} borderStyle={TotalLineBorderStyle.DoubleDark} textStyle={TotalLineTextStyle.Bold} /> diff --git a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooterRight.tsx b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooterRight.tsx index 31b1172d5..0eb41999e 100644 --- a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooterRight.tsx +++ b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooterRight.tsx @@ -8,21 +8,25 @@ import { TotalLineBorderStyle, TotalLineTextStyle, } from '@/components'; -import { useExpensesTotals } from './utils'; +import { + useExpenseSubtotalFormatted, + useExpenseTotalFormatted, +} from './utils'; export function ExpenseFormFooterRight() { - const { formattedSubtotal, formattedTotal } = useExpensesTotals(); + const totalFormatted = useExpenseTotalFormatted(); + const subtotalFormatted = useExpenseSubtotalFormatted(); return ( } - value={formattedSubtotal} + value={subtotalFormatted} borderStyle={TotalLineBorderStyle.None} /> } - value={formattedTotal} + value={totalFormatted} textStyle={TotalLineTextStyle.Bold} /> diff --git a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormHeader.tsx b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormHeader.tsx index 97dbd2399..858b0bc35 100644 --- a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormHeader.tsx +++ b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormHeader.tsx @@ -1,34 +1,23 @@ // @ts-nocheck -import React, { useMemo } from 'react'; +import React from 'react'; import classNames from 'classnames'; -import { sumBy } from 'lodash'; -import { useFormikContext } from 'formik'; import { FormattedMessage as T } from '@/components'; import { CLASSES } from '@/constants/classes'; - import ExpenseFormHeaderFields from './ExpenseFormHeaderFields'; import { PageFormBigNumber } from '@/components'; +import { useExpenseTotalFormatted } from './utils'; // Expense form header. export default function ExpenseFormHeader() { - const { - values: { currency_code, categories }, - } = useFormikContext(); - - // Calculates the expense entries amount. - const totalExpenseAmount = useMemo( - () => sumBy(categories, 'amount'), - [categories], - ); + const totalFormatted = useExpenseTotalFormatted(); return (
} - amount={totalExpenseAmount} - currencyCode={currency_code} + amount={totalFormatted} />
); diff --git a/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx b/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx index e411d810a..19cb5ab0a 100644 --- a/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx +++ b/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx @@ -166,30 +166,52 @@ export const useSetPrimaryBranchToForm = () => { }; /** - * Retreives the Journal totals. + * Retrieves the expense subtotal. + * @returns {number} */ -export const useExpensesTotals = () => { +export const useExpenseSubtotal = () => { const { - values: { categories, currency_code: currencyCode }, + values: { categories }, } = useFormikContext(); - const total = sumBy(categories, 'amount'); + // Calculates the expense entries amount. + return React.useMemo(() => sumBy(categories, 'amount'), [categories]); +}; - // Retrieves the formatted total money. - const formattedTotal = React.useMemo( - () => formattedAmount(total, currencyCode), - [total, currencyCode], - ); - // Retrieves the formatted subtotal. - const formattedSubtotal = React.useMemo( - () => formattedAmount(total, currencyCode, { money: false }), - [total, currencyCode], - ); +/** + * Retrieves the expense subtotal formatted. + * @returns {string} + */ +export const useExpenseSubtotalFormatted = () => { + const subtotal = useExpenseSubtotal(); + const { + values: { currency_code }, + } = useFormikContext(); - return { - formattedTotal, - formattedSubtotal, - }; + return formattedAmount(subtotal, currency_code); +}; + +/** + * Retrieves the expense total. + * @returns {number} + */ +export const useExpenseTotal = () => { + const subtotal = useExpenseSubtotal(); + + return subtotal; +}; + +/** + * Retrieves the expense total formatted. + * @returns {string} + */ +export const useExpenseTotalFormatted = () => { + const total = useExpenseTotal(); + const { + values: { currency_code }, + } = useFormikContext(); + + return formattedAmount(total, currency_code); }; /** diff --git a/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormHeader.tsx b/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormHeader.tsx index b3439fa4c..d4e5149d4 100644 --- a/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormHeader.tsx +++ b/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormHeader.tsx @@ -1,13 +1,12 @@ // @ts-nocheck -import React, { useMemo } from 'react'; +import React from 'react'; import intl from 'react-intl-universal'; import classNames from 'classnames'; -import { sumBy } from 'lodash'; -import { useFormikContext } from 'formik'; import { CLASSES } from '@/constants/classes'; import { PageFormBigNumber } from '@/components'; import BillFormHeaderFields from './BillFormHeaderFields'; +import { useBillTotalFormatted } from './utils'; /** * Fill form header. @@ -22,19 +21,10 @@ function BillFormHeader() { } function BillFormBigTotal() { - const { - values: { currency_code, entries }, - } = useFormikContext(); - - // Calculate the total due amount of bill entries. - const totalDueAmount = useMemo(() => sumBy(entries, 'amount'), [entries]); + const totalFormatted = useBillTotalFormatted(); return ( - + ); } diff --git a/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx b/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx index 80de66529..35296368a 100644 --- a/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx @@ -325,7 +325,7 @@ export const useBillSubtotal = () => { */ export const useBillSubtotalFormatted = () => { const subtotal = useBillSubtotal(); - const { values} = useFormikContext(); + const { values } = useFormikContext(); return formattedAmount(subtotal, values.currency_code); }; @@ -336,8 +336,12 @@ export const useBillSubtotalFormatted = () => { */ export const useBillDiscountAmount = () => { const { values } = useFormikContext(); + const subtotal = useBillSubtotal(); + const discount = toSafeNumber(values.discount); - return toSafeNumber(values.discount); + return values?.discount_type === 'percentage' + ? (subtotal * discount) / 100 + : discount; }; /** @@ -384,7 +388,6 @@ export const useBillTotalTaxAmount = () => { .filter((entry) => entry.tax_amount) .sumBy('tax_amount') .value(); - }, [values.entries]); }; diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.tsx index 4ae780e45..9c1b66a5a 100644 --- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.tsx +++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormHeader.tsx @@ -2,33 +2,23 @@ import React from 'react'; import intl from 'react-intl-universal'; import classNames from 'classnames'; -import { useFormikContext } from 'formik'; import { CLASSES } from '@/constants/classes'; import VendorCreditNoteFormHeaderFields from './VendorCreditNoteFormHeaderFields'; - -import { getEntriesTotal } from '@/containers/Entries/utils'; import { PageFormBigNumber } from '@/components'; - +import { useVendorCreditTotalFormatted } from './utils'; /** * Vendor Credit note header. */ function VendorCreditNoteFormHeader() { - const { values:{entries ,currency_code} } = useFormikContext(); - - // Calculate the total amount. - const totalAmount = React.useMemo( - () => getEntriesTotal(entries), - [entries], - ); + const totalFormatted = useVendorCreditTotalFormatted(); return (
); diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx index 3dc3c0a72..e796d85d3 100644 --- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx @@ -206,8 +206,12 @@ export const useVendorCreditSubtotal = () => { */ export const useVendorCreditDiscountAmount = () => { const { values } = useFormikContext(); + const subtotal = useVendorCreditSubtotal(); + const discount = toSafeNumber(values.discount); - return toSafeNumber(values.discount); + return values.discount_type === 'percentage' + ? (subtotal * discount) / 100 + : discount; }; /** diff --git a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeader.tsx b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeader.tsx index 06ed4837d..9a3f450e1 100644 --- a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeader.tsx +++ b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormHeader.tsx @@ -1,11 +1,9 @@ // @ts-nocheck import React from 'react'; import intl from 'react-intl-universal'; -import { useFormikContext } from 'formik'; import CreditNoteFormHeaderFields from './CreditNoteFormHeaderFields'; - -import { getEntriesTotal } from '@/containers/Entries/utils'; import { Group, PageFormBigNumber } from '@/components'; +import { useCreditNoteTotalFormatted } from './utils'; /** * Credit note header. @@ -31,18 +29,12 @@ function CreditNoteFormHeader() { * @returns {React.ReactNode} */ function CreditNoteFormBigNumber() { - const { - values: { entries, currency_code }, - } = useFormikContext(); - - // Calculate the total amount. - const totalAmount = React.useMemo(() => getEntriesTotal(entries), [entries]); + const totalFormatted = useCreditNoteTotalFormatted(); return ( ); } diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormDialogs.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormDialogs.tsx index 33f8dbe3e..aa1c165a1 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormDialogs.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormDialogs.tsx @@ -1,5 +1,6 @@ // @ts-nocheck import React from 'react'; +import { useFormikContext } from 'formik'; import EstimateNumberDialog from '@/containers/Dialogs/EstimateNumberDialog'; /** diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.tsx index ac62fc4da..a8d924784 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormHeader.tsx @@ -1,12 +1,10 @@ // @ts-nocheck -import React, { useMemo } from 'react'; +import React from 'react'; import intl from 'react-intl-universal'; -import { useFormikContext } from 'formik'; -import { x } from '@xstyled/emotion'; import EstimateFormHeaderFields from './EstimateFormHeaderFields'; -import { getEntriesTotal } from '@/containers/Entries/utils'; import { Group, PageFormBigNumber } from '@/components'; +import { useEstimateTotalFormatted } from './utils'; // Estimate form top header. function EstimateFormHeader() { @@ -29,19 +27,10 @@ function EstimateFormHeader() { * @returns {React.ReactNode} */ function EstimateFormBigTotal() { - const { - values: { entries, currency_code }, - } = useFormikContext(); - - // Calculate the total due amount of bill entries. - const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]); + const totalFormatted = useEstimateTotalFormatted(); return ( - + ); } diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx index 5c3307b0b..3669bf868 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx @@ -245,6 +245,7 @@ export const useEstimateSubtotalFormatted = () => { */ export const useEstimateDiscount = () => { const { values } = useFormikContext(); + const subtotal = useEstimateSubtotal(); const discount = toSafeNumber(values.discount); return values?.discount_type === 'percentage' diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.tsx index 78a6e7b2f..ae63a1012 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormHeader.tsx @@ -1,10 +1,9 @@ // @ts-nocheck import React from 'react'; import intl from 'react-intl-universal'; -import { useFormikContext } from 'formik'; import { Group, PageFormBigNumber } from '@/components'; import InvoiceFormHeaderFields from './InvoiceFormHeaderFields'; -import { useInvoiceDueAmount } from './utils'; +import { useInvoiceTotalFormatted } from './utils'; /** * Invoice form header section. @@ -29,19 +28,11 @@ function InvoiceFormHeader() { * @returns {React.ReactNode} */ function InvoiceFormBigTotal() { - const { - values: { currency_code }, - } = useFormikContext(); - // Calculate the total due amount of invoice entries. - const totalDueAmount = useInvoiceDueAmount(); + const totalFormatted = useInvoiceTotalFormatted(); return ( - + ); } export default InvoiceFormHeader; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx index 844415483..93fb58841 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/utils.tsx @@ -324,7 +324,7 @@ export const useInvoiceSubtotalFormatted = () => { export const useInvoiceDiscountAmount = () => { const { values } = useFormikContext(); const subtotal = useInvoiceSubtotal(); - const discount = parseFloat(values.discount); + const discount = toSafeNumber(values.discount); return values?.discount_type === 'percentage' ? (subtotal * discount) / 100 @@ -350,7 +350,7 @@ export const useInvoiceDiscountAmountFormatted = () => { */ export const useInvoiceAdjustmentAmount = () => { const { values } = useFormikContext(); - const adjustment = parseFloat(values.adjustment); + const adjustment = toSafeNumber(values.adjustment); return adjustment; }; diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.tsx index 9c6d8ac2e..997e4f66f 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormHeader.tsx @@ -1,10 +1,9 @@ // @ts-nocheck -import React, { useMemo } from 'react'; +import React from 'react'; import intl from 'react-intl-universal'; -import { useFormikContext } from 'formik'; import { Group, PageFormBigNumber } from '@/components'; import ReceiptFormHeaderFields from './ReceiptFormHeaderFields'; -import { getEntriesTotal } from '@/containers/Entries/utils'; +import { useReceiptTotalFormatted } from './utils'; /** * Receipt form header section. @@ -35,19 +34,10 @@ function ReceiptFormHeader({ * @returns {React.ReactNode} */ function ReceiptFormHeaderBigTotal() { - const { - values: { currency_code, entries }, - } = useFormikContext(); - - // Calculate the total due amount of bill entries. - const totalDueAmount = useMemo(() => getEntriesTotal(entries), [entries]); + const totalFormatted = useReceiptTotalFormatted(); return ( - + ); } From fabc88c81ac33a6e559dc2b87b355f008dbc1958 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 3 Dec 2024 23:37:55 +0200 Subject: [PATCH 2/5] feat: add adjustment total in estimates, invoices, and receipts pdf templates --- .../Sales/Estimates/SaleEstimatesPdf.ts | 6 +-- .../src/services/Sales/Estimates/utils.ts | 5 ++- .../services/Sales/Invoices/SaleInvoicePdf.ts | 8 ++-- .../src/services/Sales/Invoices/utils.ts | 6 ++- .../Sales/Receipts/SaleReceiptsPdfService.ts | 10 +++-- .../src/services/Sales/Receipts/utils.ts | 9 ++--- .../Accounting/MakeJournal/utils.tsx | 1 + shared/pdf-templates/package.json | 2 +- .../src/components/EstimatePaperTemplate.tsx | 18 ++++++++- .../src/components/InvoicePaperTemplate.tsx | 39 +++++++++++++++---- .../src/components/ReceiptPaperTemplate.tsx | 16 ++++++++ .../renders/render-invoice-paper-template.tsx | 4 +- 12 files changed, 91 insertions(+), 33 deletions(-) diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimatesPdf.ts b/packages/server/src/services/Sales/Estimates/SaleEstimatesPdf.ts index 65b965388..4cb6c8f3b 100644 --- a/packages/server/src/services/Sales/Estimates/SaleEstimatesPdf.ts +++ b/packages/server/src/services/Sales/Estimates/SaleEstimatesPdf.ts @@ -1,14 +1,12 @@ import { Inject, Service } from 'typedi'; import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy'; -import { TemplateInjectable } from '@/services/TemplateInjectable/TemplateInjectable'; import { GetSaleEstimate } from './GetSaleEstimate'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { SaleEstimatePdfTemplate } from '../Invoices/SaleEstimatePdfTemplate'; import { transformEstimateToPdfTemplate } from './utils'; -import { EstimatePdfBrandingAttributes } from './constants'; import events from '@/subscribers/events'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; -import { renderEstimatePaperTemplateHtml } from '@bigcapital/pdf-templates'; +import { renderEstimatePaperTemplateHtml, EstimatePaperTemplateProps } from '@bigcapital/pdf-templates'; @Service() export class SaleEstimatesPdf { @@ -97,7 +95,7 @@ export class SaleEstimatesPdf { async getEstimateBrandingAttributes( tenantId: number, estimateId: number - ): Promise { + ): Promise { const { PdfTemplate } = this.tenancy.models(tenantId); const saleEstimate = await this.getSaleEstimate.getEstimate( tenantId, diff --git a/packages/server/src/services/Sales/Estimates/utils.ts b/packages/server/src/services/Sales/Estimates/utils.ts index c77029ba1..c5d100cd9 100644 --- a/packages/server/src/services/Sales/Estimates/utils.ts +++ b/packages/server/src/services/Sales/Estimates/utils.ts @@ -1,9 +1,9 @@ +import { EstimatePaperTemplateProps } from '@bigcapital/pdf-templates'; import { contactAddressTextFormat } from '@/utils/address-text-format'; -import { EstimatePdfBrandingAttributes } from './constants'; export const transformEstimateToPdfTemplate = ( estimate -): Partial => { +): Partial => { return { expirationDate: estimate.formattedExpirationDate, estimateNumebr: estimate.estimateNumber, @@ -17,6 +17,7 @@ export const transformEstimateToPdfTemplate = ( })), total: estimate.formattedSubtotal, subtotal: estimate.formattedSubtotal, + adjustment: estimate.adjustmentFormatted, customerNote: estimate.note, termsConditions: estimate.termsConditions, customerAddress: contactAddressTextFormat(estimate.customer), diff --git a/packages/server/src/services/Sales/Invoices/SaleInvoicePdf.ts b/packages/server/src/services/Sales/Invoices/SaleInvoicePdf.ts index 54ae28319..1c492b9ce 100644 --- a/packages/server/src/services/Sales/Invoices/SaleInvoicePdf.ts +++ b/packages/server/src/services/Sales/Invoices/SaleInvoicePdf.ts @@ -1,10 +1,12 @@ import { Inject, Service } from 'typedi'; -import { renderInvoicePaperTemplateHtml } from '@bigcapital/pdf-templates'; +import { + renderInvoicePaperTemplateHtml, + InvoicePaperTemplateProps, +} from '@bigcapital/pdf-templates'; import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy'; import { GetSaleInvoice } from './GetSaleInvoice'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { transformInvoiceToPdfTemplate } from './utils'; -import { InvoicePdfTemplateAttributes } from '@/interfaces'; import { SaleInvoicePdfTemplate } from './SaleInvoicePdfTemplate'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; @@ -100,7 +102,7 @@ export class SaleInvoicePdf { async getInvoiceBrandingAttributes( tenantId: number, invoiceId: number - ): Promise { + ): Promise { const { PdfTemplate } = this.tenancy.models(tenantId); const invoice = await this.getInvoiceService.getSaleInvoice( diff --git a/packages/server/src/services/Sales/Invoices/utils.ts b/packages/server/src/services/Sales/Invoices/utils.ts index 2fcfce6f2..af8ba6145 100644 --- a/packages/server/src/services/Sales/Invoices/utils.ts +++ b/packages/server/src/services/Sales/Invoices/utils.ts @@ -1,6 +1,7 @@ import { pickBy } from 'lodash'; -import { InvoicePdfTemplateAttributes, ISaleInvoice } from '@/interfaces'; +import { ISaleInvoice } from '@/interfaces'; import { contactAddressTextFormat } from '@/utils/address-text-format'; +import { InvoicePaperTemplateProps } from '@bigcapital/pdf-templates'; export const mergePdfTemplateWithDefaultAttributes = ( brandingTemplate?: Record, @@ -18,7 +19,7 @@ export const mergePdfTemplateWithDefaultAttributes = ( export const transformInvoiceToPdfTemplate = ( invoice: ISaleInvoice -): Partial => { +): Partial => { return { dueDate: invoice.dueDateFormatted, dateIssue: invoice.invoiceDateFormatted, @@ -29,6 +30,7 @@ export const transformInvoiceToPdfTemplate = ( paymentMade: invoice.paymentAmountFormatted, dueAmount: invoice.dueAmountFormatted, discount: invoice.discountAmountFormatted, + adjustment: invoice.adjustmentFormatted, discountLabel: invoice.discountPercentageFormatted ? `Discount [${invoice.discountPercentageFormatted}]` : 'Discount', diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptsPdfService.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptsPdfService.ts index f8b6f57ea..2aab47659 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptsPdfService.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptsPdfService.ts @@ -1,13 +1,15 @@ import { Inject, Service } from 'typedi'; import { ChromiumlyTenancy } from '@/services/ChromiumlyTenancy/ChromiumlyTenancy'; +import { + renderReceiptPaperTemplateHtml, + ReceiptPaperTemplateProps, +} from '@bigcapital/pdf-templates'; import { GetSaleReceipt } from './GetSaleReceipt'; import HasTenancyService from '@/services/Tenancy/TenancyService'; import { SaleReceiptBrandingTemplate } from './SaleReceiptBrandingTemplate'; import { transformReceiptToBrandingTemplateAttributes } from './utils'; -import { ISaleReceiptBrandingTemplateAttributes } from '@/interfaces'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; -import { renderReceiptPaperTemplateHtml } from '@bigcapital/pdf-templates'; @Service() export class SaleReceiptsPdf { @@ -90,12 +92,12 @@ export class SaleReceiptsPdf { * Retrieves receipt branding attributes. * @param {number} tenantId * @param {number} receiptId - * @returns {Promise} + * @returns {Promise} */ public async getReceiptBrandingAttributes( tenantId: number, receiptId: number - ): Promise { + ): Promise { const { PdfTemplate } = this.tenancy.models(tenantId); const saleReceipt = await this.getSaleReceiptService.getSaleReceipt( diff --git a/packages/server/src/services/Sales/Receipts/utils.ts b/packages/server/src/services/Sales/Receipts/utils.ts index 2586c0b33..3d3bb8733 100644 --- a/packages/server/src/services/Sales/Receipts/utils.ts +++ b/packages/server/src/services/Sales/Receipts/utils.ts @@ -1,12 +1,10 @@ -import { - ISaleReceipt, - ISaleReceiptBrandingTemplateAttributes, -} from '@/interfaces'; +import { ISaleReceipt } from '@/interfaces'; import { contactAddressTextFormat } from '@/utils/address-text-format'; +import { ReceiptPaperTemplateProps } from '@bigcapital/pdf-templates'; export const transformReceiptToBrandingTemplateAttributes = ( saleReceipt: ISaleReceipt -): Partial => { +): Partial => { return { total: saleReceipt.totalFormatted, subtotal: saleReceipt.subtotalFormatted, @@ -23,6 +21,7 @@ export const transformReceiptToBrandingTemplateAttributes = ( discountLabel: saleReceipt.discountPercentageFormatted ? `Discount [${saleReceipt.discountPercentageFormatted}]` : 'Discount', + adjustment: saleReceipt.adjustmentFormatted, customerAddress: contactAddressTextFormat(saleReceipt.customer), }; }; diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx index 38fa852e5..72d0e8023 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx @@ -239,6 +239,7 @@ export const useJournalTotals = () => { const totalDebit = safeSumBy(entries, 'debit'); const total = Math.max(totalCredit, totalDebit); + // Retrieves the formatted total money. const formattedTotal = React.useMemo( () => formattedAmount(total, currencyCode), diff --git a/shared/pdf-templates/package.json b/shared/pdf-templates/package.json index d636d9d37..6ebda5ccb 100644 --- a/shared/pdf-templates/package.json +++ b/shared/pdf-templates/package.json @@ -9,7 +9,7 @@ }, "main": "./dist/components.umd.js", "module": "./dist/components.es.js", - "types": "./dist/src/index.d.ts", + "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/src/index.d.ts", diff --git a/shared/pdf-templates/src/components/EstimatePaperTemplate.tsx b/shared/pdf-templates/src/components/EstimatePaperTemplate.tsx index 837ab30aa..e28a292a2 100644 --- a/shared/pdf-templates/src/components/EstimatePaperTemplate.tsx +++ b/shared/pdf-templates/src/components/EstimatePaperTemplate.tsx @@ -43,7 +43,7 @@ export interface EstimatePaperTemplateProps extends PaperTemplateProps { companyAddress?: string; billedToLabel?: string; - // Totals + // Total total?: string; showTotal?: boolean; totalLabel?: string; @@ -53,6 +53,11 @@ export interface EstimatePaperTemplateProps extends PaperTemplateProps { showDiscount?: boolean; discountLabel?: string; + // # Adjustment + adjustment?: string; + showAdjustment?: boolean; + adjustmentLabel?: string; + // # Subtotal subtotal?: string; showSubtotal?: boolean; @@ -117,6 +122,11 @@ export function EstimatePaperTemplate({ subtotalLabel = 'Subtotal', showSubtotal = true, + // # Adjustment + adjustment = '', + showAdjustment = true, + adjustmentLabel = 'Adjustment', + // # Customer Note showCustomerNote = true, customerNote = DefaultPdfTemplateStatement, @@ -240,6 +250,12 @@ export function EstimatePaperTemplate({ amount={discount} /> )} + {showAdjustment && adjustment && ( + + )} {showTotal && ( )} diff --git a/shared/pdf-templates/src/components/InvoicePaperTemplate.tsx b/shared/pdf-templates/src/components/InvoicePaperTemplate.tsx index f14561921..f2ff68e3a 100644 --- a/shared/pdf-templates/src/components/InvoicePaperTemplate.tsx +++ b/shared/pdf-templates/src/components/InvoicePaperTemplate.tsx @@ -1,3 +1,4 @@ +import { isEmpty } from 'lodash'; import { PaperTemplate, PaperTemplateProps, @@ -33,17 +34,21 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps { primaryColor?: string; secondaryColor?: string; + // Company showCompanyLogo?: boolean; companyLogoUri?: string; + // Invoice number showInvoiceNumber?: boolean; invoiceNumber?: string; invoiceNumberLabel?: string; + // Date of issue showDateIssue?: boolean; dateIssue?: string; dateIssueLabel?: string; + // Due date showDueDate?: boolean; dueDate?: string; dueDateLabel?: string; @@ -66,7 +71,7 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps { lineRateLabel?: string; lineTotalLabel?: string; - // Totals + // Total showTotal?: boolean; totalLabel?: string; total?: string; @@ -76,11 +81,17 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps { discountLabel?: string; discount?: string; + // Adjustment + showAdjustment?: boolean; + adjustmentLabel?: string; + adjustment?: string; + // Subtotal showSubtotal?: boolean; subtotalLabel?: string; subtotal?: string; + // Payment made showPaymentMade?: boolean; paymentMadeLabel?: string; paymentMade?: string; @@ -97,6 +108,7 @@ export interface InvoicePaperTemplateProps extends PaperTemplateProps { showTermsConditions?: boolean; termsConditions?: string; + // Statement statementLabel?: string; showStatement?: boolean; statement?: string; @@ -145,20 +157,24 @@ export function InvoicePaperTemplate({ totalLabel = 'Total', subtotalLabel = 'Subtotal', discountLabel = 'Discount', + adjustmentLabel = 'Adjustment', paymentMadeLabel = 'Payment Made', dueAmountLabel = 'Balance Due', // Totals showTotal = true, + total = '$662.75', + showSubtotal = true, showDiscount = true, showTaxes = true, showPaymentMade = true, showDueAmount = true, + showAdjustment = true, - total = '$662.75', subtotal = '630.00', discount = '0.00', + adjustment = '', paymentMade = '100.00', dueAmount = '$562.75', @@ -243,17 +259,18 @@ export function InvoicePaperTemplate({ accessor: (data) => ( {data.item} - + {data.description} ), thStyle: { width: '60%' }, }, - { label: lineQuantityLabel, accessor: 'quantity', align: 'right' }, + { + label: lineQuantityLabel, + accessor: 'quantity', + align: 'right', + }, { label: lineRateLabel, accessor: 'rate', align: 'right' }, { label: lineTotalLabel, accessor: 'total', align: 'right' }, ]} @@ -267,12 +284,18 @@ export function InvoicePaperTemplate({ border={PaperTemplateTotalBorder.Gray} /> )} - {showDiscount && ( + {showDiscount && !isEmpty(discount) && ( )} + {showAdjustment && !isEmpty(adjustment) && ( + + )} {showTaxes && ( <> {taxes.map((tax, index) => ( diff --git a/shared/pdf-templates/src/components/ReceiptPaperTemplate.tsx b/shared/pdf-templates/src/components/ReceiptPaperTemplate.tsx index 3144c15de..68a19c9e9 100644 --- a/shared/pdf-templates/src/components/ReceiptPaperTemplate.tsx +++ b/shared/pdf-templates/src/components/ReceiptPaperTemplate.tsx @@ -39,6 +39,11 @@ export interface ReceiptPaperTemplateProps extends PaperTemplateProps { showDiscount?: boolean; discountLabel?: string; + // # Adjustment + adjustment?: string; + showAdjustment?: boolean; + adjustmentLabel?: string; + // Total total?: string; showTotal?: boolean; @@ -111,6 +116,11 @@ export function ReceiptPaperTemplate({ discountLabel = 'Discount', showDiscount = true, + // # Adjustment + adjustment = '', + adjustmentLabel = 'Adjustment', + showAdjustment = true, + // # Subtotal subtotal = '1000/00', subtotalLabel = 'Subtotal', @@ -228,6 +238,12 @@ export function ReceiptPaperTemplate({ amount={discount} /> )} + {showAdjustment && adjustment && ( + + )} {showTotal && ( )} diff --git a/shared/pdf-templates/src/renders/render-invoice-paper-template.tsx b/shared/pdf-templates/src/renders/render-invoice-paper-template.tsx index 1ce9e2de1..84e035b29 100644 --- a/shared/pdf-templates/src/renders/render-invoice-paper-template.tsx +++ b/shared/pdf-templates/src/renders/render-invoice-paper-template.tsx @@ -8,8 +8,6 @@ export const renderInvoicePaperTemplateHtml = ( props: InvoicePaperTemplateProps ) => { return renderSSR( - + ); }; From 6ab461a212b67d87ae364e0b063da7c52a5edd12 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 4 Dec 2024 12:00:22 +0200 Subject: [PATCH 3/5] feat: enhance discount and adjustment formatting --- .../src/services/CreditNotes/CreditNoteTransformer.ts | 2 ++ .../services/Purchases/Bills/PurchaseInvoiceTransformer.ts | 2 ++ .../Purchases/VendorCredits/VendorCreditTransformer.ts | 2 ++ .../src/services/Sales/Estimates/SaleEstimateTransformer.ts | 2 ++ .../src/services/Sales/Invoices/SaleInvoiceTransformer.ts | 6 ++++-- .../src/services/Sales/Receipts/SaleReceiptTransformer.ts | 2 ++ .../Drawers/EstimateDetailDrawer/EstimateDetailHeader.tsx | 2 +- .../EstimateDetailDrawer/EstimateDetailTableFooter.tsx | 6 +++--- .../InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx | 6 +++--- .../VendorCreditDetailDrawerFooter.tsx | 6 +++--- 10 files changed, 24 insertions(+), 12 deletions(-) diff --git a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts index c136c463e..611d006ad 100644 --- a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts +++ b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts @@ -96,6 +96,7 @@ export class CreditNoteTransformer extends Transformer { protected discountAmountFormatted = (credit): string => { return formatNumber(credit.discountAmount, { currencyCode: credit.currencyCode, + excerptZero: true, }); }; @@ -118,6 +119,7 @@ export class CreditNoteTransformer extends Transformer { protected adjustmentFormatted = (credit): string => { return this.formatMoney(credit.adjustment, { currencyCode: credit.currencyCode, + excerptZero: true, }); }; diff --git a/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts b/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts index 6fba33c2e..a6766a0db 100644 --- a/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts +++ b/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts @@ -171,6 +171,7 @@ export class PurchaseInvoiceTransformer extends Transformer { protected discountAmountFormatted = (bill): string => { return formatNumber(bill.discountAmount, { currencyCode: bill.currencyCode, + excerptZero: true, }); }; @@ -193,6 +194,7 @@ export class PurchaseInvoiceTransformer extends Transformer { protected adjustmentFormatted = (bill): string => { return formatNumber(bill.adjustment, { currencyCode: bill.currencyCode, + excerptZero: true, }); }; diff --git a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts index 594c6aa14..b42c90ea0 100644 --- a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts +++ b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts @@ -82,6 +82,7 @@ export class VendorCreditTransformer extends Transformer { protected discountAmountFormatted = (credit): string => { return formatNumber(credit.discountAmount, { currencyCode: credit.currencyCode, + excerptZero: true, }); }; @@ -102,6 +103,7 @@ export class VendorCreditTransformer extends Transformer { protected adjustmentFormatted = (credit): string => { return formatNumber(credit.adjustment, { currencyCode: credit.currencyCode, + excerptZero: true, }); }; diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts index dff7915ca..91e7d0ab5 100644 --- a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts +++ b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts @@ -111,6 +111,7 @@ export class SaleEstimateTransfromer extends Transformer { protected discountAmountFormatted = (estimate: ISaleEstimate): string => { return formatNumber(estimate.discountAmount, { currencyCode: estimate.currencyCode, + excerptZero: true, }); }; @@ -133,6 +134,7 @@ export class SaleEstimateTransfromer extends Transformer { protected adjustmentFormatted = (estimate: ISaleEstimate): string => { return this.formatMoney(estimate.adjustment, { currencyCode: estimate.currencyCode, + excerptZero: true, }); }; diff --git a/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts b/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts index e54a59b72..05dce98b7 100644 --- a/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts +++ b/packages/server/src/services/Sales/Invoices/SaleInvoiceTransformer.ts @@ -170,6 +170,7 @@ export class SaleInvoiceTransformer extends Transformer { protected discountAmountFormatted = (invoice): string => { return formatNumber(invoice.discountAmount, { currencyCode: invoice.currencyCode, + excerptZero: true, }); }; @@ -192,8 +193,9 @@ export class SaleInvoiceTransformer extends Transformer { protected adjustmentFormatted = (invoice): string => { return this.formatMoney(invoice.adjustment, { currencyCode: invoice.currencyCode, - }) - } + excerptZero: true, + }); + }; /** * Retrieves formatted total in foreign currency. diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts index 4a92bc873..422e88e83 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts @@ -113,6 +113,7 @@ export class SaleReceiptTransformer extends Transformer { protected discountAmountFormatted = (receipt: ISaleReceipt): string => { return formatNumber(receipt.discountAmount, { currencyCode: receipt.currencyCode, + excerptZero: true, }); }; @@ -135,6 +136,7 @@ export class SaleReceiptTransformer extends Transformer { protected adjustmentFormatted = (receipt: ISaleReceipt): string => { return this.formatMoney(receipt.adjustment, { currencyCode: receipt.currencyCode, + excerptZero: true, }); }; diff --git a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailHeader.tsx b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailHeader.tsx index a6ae51468..a448b8d96 100644 --- a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailHeader.tsx +++ b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailHeader.tsx @@ -30,7 +30,7 @@ export default function EstimateDetailHeader() { - {estimate.formatted_amount} + {estimate.total_formatted} diff --git a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx index ade4f2690..6533267b3 100644 --- a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx @@ -25,11 +25,11 @@ export default function EstimateDetailTableFooter() { value={estimate.formatted_subtotal} borderStyle={TotalLineBorderStyle.SingleDark} /> - {estimate.discount_amount > 0 && ( + {estimate?.discount_amount > 0 && ( } - value={estimate.formatted_amount} + value={estimate.total_formatted} borderStyle={TotalLineBorderStyle.DoubleDark} textStyle={TotalLineTextStyle.Bold} /> diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx index 3d034b0c4..509d32f66 100644 --- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx @@ -26,7 +26,7 @@ export function InvoiceDetailTableFooter() { value={invoice.subtotal_formatted} borderStyle={TotalLineBorderStyle.SingleDark} /> - {invoice.discount_amount > 0 && ( + {invoice?.discount_amount > 0 && ( )} - {invoice.adjustment > 0 && ( + {invoice?.adjustment > 0 && ( )} - {invoice.taxes.map((taxRate) => ( + {invoice?.taxes?.map((taxRate) => ( - {vendorCredit.discount_amount > 0 && ( + {vendorCredit.discount_amount_formatted && ( Date: Wed, 4 Dec 2024 12:18:20 +0200 Subject: [PATCH 4/5] fix: discount and adjustment fields --- packages/server/src/api/controllers/Purchases/Bills.ts | 4 ++-- .../server/src/api/controllers/Sales/SalesEstimates.ts | 4 ++-- .../EstimateDetailDrawer/EstimateDetailTableFooter.tsx | 9 ++++++++- .../InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx | 2 +- .../VendorCreditDetailDrawerFooter.tsx | 9 ++++++++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/server/src/api/controllers/Purchases/Bills.ts b/packages/server/src/api/controllers/Purchases/Bills.ts index 71fcf2f5c..629579863 100644 --- a/packages/server/src/api/controllers/Purchases/Bills.ts +++ b/packages/server/src/api/controllers/Purchases/Bills.ts @@ -153,7 +153,7 @@ export default class BillsController extends BaseController { check('discount_type') .default(DiscountType.Amount) .isIn([DiscountType.Amount, DiscountType.Percentage]), - check('discount').optional().isDecimal().toFloat(), + check('discount').optional({ nullable: true }).isDecimal().toFloat(), // # Adjustment check('adjustment').optional({ nullable: true }).isNumeric().toFloat(), @@ -204,7 +204,7 @@ export default class BillsController extends BaseController { check('discount_type') .default(DiscountType.Amount) .isIn([DiscountType.Amount, DiscountType.Percentage]), - check('discount').optional().isDecimal().toFloat(), + check('discount').optional({ nullable: true }).isDecimal().toFloat(), // # Adjustment check('adjustment').optional({ nullable: true }).isNumeric().toFloat(), diff --git a/packages/server/src/api/controllers/Sales/SalesEstimates.ts b/packages/server/src/api/controllers/Sales/SalesEstimates.ts index dbbef3e7b..3af6b9805 100644 --- a/packages/server/src/api/controllers/Sales/SalesEstimates.ts +++ b/packages/server/src/api/controllers/Sales/SalesEstimates.ts @@ -204,13 +204,13 @@ export default class SalesEstimatesController extends BaseController { check('pdf_template_id').optional({ nullable: true }).isNumeric().toInt(), // # Discount - check('discount').optional().isNumeric().toFloat(), + check('discount').optional({ nullable: true }).isNumeric().toFloat(), check('discount_type') .default(DiscountType.Amount) .isIn([DiscountType.Amount, DiscountType.Percentage]), // # Adjustment - check('adjustment').optional().isNumeric().toFloat(), + check('adjustment').optional({ nullable: true }).isNumeric().toFloat(), ]; } diff --git a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx index 6533267b3..f2f02f8aa 100644 --- a/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/EstimateDetailDrawer/EstimateDetailTableFooter.tsx @@ -25,7 +25,7 @@ export default function EstimateDetailTableFooter() { value={estimate.formatted_subtotal} borderStyle={TotalLineBorderStyle.SingleDark} /> - {estimate?.discount_amount > 0 && ( + {estimate?.discount_amount_formatted && ( )} + {estimate?.adjustment_formatted && ( + + )} } value={estimate.total_formatted} diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx index 509d32f66..1b3c26e3f 100644 --- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx +++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailTableFooter.tsx @@ -37,7 +37,7 @@ export function InvoiceDetailTableFooter() { textStyle={TotalLineTextStyle.Regular} /> )} - {invoice?.adjustment > 0 && ( + {invoice?.adjustment_formatted && ( - {vendorCredit.discount_amount_formatted && ( + {vendorCredit?.discount_amount_formatted && ( )} + {vendorCredit?.adjustment_formatted && ( + + )} } value={vendorCredit.formatted_amount} From a25ab3964765520430f6cb6fc8a512ada5699382 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Wed, 4 Dec 2024 13:23:40 +0200 Subject: [PATCH 5/5] refactor: replace journal total calculations with new formatted amount hooks --- .../MakeJournal/MakeJournalEntriesHeader.tsx | 17 +--- .../MakeJournalFormFooterRight.tsx | 10 ++- .../Accounting/MakeJournal/utils.tsx | 90 +++++++++++++------ .../InvoiceDetailHeader.tsx | 2 - 4 files changed, 74 insertions(+), 45 deletions(-) diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.tsx index fe3cf3cd3..174c66854 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesHeader.tsx @@ -1,11 +1,10 @@ // @ts-nocheck import React from 'react'; import classNames from 'classnames'; -import { useFormikContext } from 'formik'; import { CLASSES } from '@/constants/classes'; -import { safeSumBy } from '@/utils'; import { PageFormBigNumber, FormattedMessage as T } from '@/components'; import MakeJournalEntriesHeaderFields from './MakeJournalEntriesHeaderFields'; +import { useManualJournalTotalFormatted } from './utils'; export default function MakeJournalEntriesHeader() { return ( @@ -21,19 +20,9 @@ export default function MakeJournalEntriesHeader() { * @returns {React.ReactNode} */ function MakeJournalHeaderBigNumber() { - const { - values: { entries, currency_code }, - } = useFormikContext(); - const totalCredit = safeSumBy(entries, 'credit'); - const totalDebit = safeSumBy(entries, 'debit'); - - const total = Math.max(totalCredit, totalDebit); + const totalFormatted = useManualJournalTotalFormatted(); return ( - } - amount={total} - currencyCode={currency_code} - /> + } amount={totalFormatted} /> ); } diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooterRight.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooterRight.tsx index 3aecd7e3d..59c8f6e0d 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooterRight.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooterRight.tsx @@ -8,10 +8,14 @@ import { TotalLineBorderStyle, TotalLineTextStyle, } from '@/components'; -import { useJournalTotals } from './utils'; +import { + useManualJournalSubtotalFormatted, + useManualJournalTotalFormatted, +} from './utils'; export function MakeJournalFormFooterRight() { - const { formattedSubtotal, formattedTotal } = useJournalTotals(); + const formattedSubtotal = useManualJournalSubtotalFormatted(); + const formattedTotal = useManualJournalTotalFormatted(); return ( @@ -29,7 +33,7 @@ export function MakeJournalFormFooterRight() { ); } -const MakeJouranlTotalLines =styled(TotalLines)` +const MakeJouranlTotalLines = styled(TotalLines)` width: 100%; color: #555555; `; diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx index 72d0e8023..bd17c58af 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx @@ -226,35 +226,73 @@ export const useSetPrimaryBranchToForm = () => { }, [isBranchesSuccess, setFieldValue, branches]); }; -/** - * Retreives the Journal totals. - */ -export const useJournalTotals = () => { - const { - values: { entries, currency_code: currencyCode }, - } = useFormikContext(); +export const useManualJournalCreditTotal = () => { + const { values } = useFormikContext(); + const totalCredit = safeSumBy(values.entries, 'credit'); - // Retrieves the invoice entries total. - const totalCredit = safeSumBy(entries, 'credit'); - const totalDebit = safeSumBy(entries, 'debit'); + return totalCredit; +}; - const total = Math.max(totalCredit, totalDebit); - - // Retrieves the formatted total money. - const formattedTotal = React.useMemo( - () => formattedAmount(total, currencyCode), - [total, currencyCode], - ); - // Retrieves the formatted subtotal. - const formattedSubtotal = React.useMemo( - () => formattedAmount(total, currencyCode, { money: false }), - [total, currencyCode], - ); +export const useManualJournalCreditTotalFormatted = () => { + const totalCredit = useManualJournalCreditTotal(); + const { values } = useFormikContext(); - return { - formattedTotal, - formattedSubtotal, - }; + return formattedAmount(totalCredit, values.currency_code); +}; + +export const useManualJournalDebitTotal = () => { + const { values } = useFormikContext(); + const totalDebit = safeSumBy(values.entries, 'debit'); + + return totalDebit; +}; + +export const useManualJournalDebitTotalFormatted = () => { + const totalDebit = useManualJournalDebitTotal(); + const { values } = useFormikContext(); + + return formattedAmount(totalDebit, values.currency_code); +}; + +export const useManualJournalSubtotal = () => { + const totalCredit = useManualJournalCreditTotal(); + const totalDebit = useManualJournalDebitTotal(); + + return Math.max(totalCredit, totalDebit); +}; + +export const useManualJournalSubtotalFormatted = () => { + const subtotal = useManualJournalSubtotal(); + const { values } = useFormikContext(); + + return formattedAmount(subtotal, values.currency_code); +}; + +export const useManualJournalTotalDifference = () => { + const totalCredit = useManualJournalCreditTotal(); + const totalDebit = useManualJournalDebitTotal(); + + return Math.abs(totalCredit - totalDebit); +}; + +export const useManualJournalTotalDifferenceFormatted = () => { + const difference = useManualJournalTotalDifference(); + const { values } = useFormikContext(); + + return formattedAmount(difference, values.currency_code); +}; + +export const useManualJournalTotal = () => { + const total = useManualJournalSubtotal(); + + return total; +}; + +export const useManualJournalTotalFormatted = () => { + const total = useManualJournalTotal(); + const { values } = useFormikContext(); + + return formattedAmount(total, values.currency_code); }; /** diff --git a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailHeader.tsx b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailHeader.tsx index 9231132a8..ea27e90c1 100644 --- a/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailHeader.tsx +++ b/packages/webapp/src/containers/Drawers/InvoiceDetailDrawer/InvoiceDetailHeader.tsx @@ -5,12 +5,10 @@ import styled from 'styled-components'; import { defaultTo } from 'lodash'; import { - ButtonLink, Row, Col, DetailsMenu, DetailItem, - FormatDate, CommercialDocHeader, CommercialDocTopHeader, CustomerDrawerLink,