From cfdbcea9c08c0bcd4f3ce8a2220c8f9b9234dab1 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Tue, 28 May 2024 23:34:51 +0200 Subject: [PATCH] feat: wip UI upload attachments --- .../api/controllers/Sales/SalesReceipts.ts | 2 + packages/server/src/models/SaleEstimate.ts | 2 +- packages/server/src/models/SaleInvoice.ts | 2 +- .../events/AttachmentsOnManualJournals.ts | 2 - .../CreditNotes/CreditNoteTransformer.ts | 11 +++ .../ManualJournals/EditManualJournal.ts | 3 +- .../ManualJournals/GetManualJournal.ts | 2 +- .../ManualJournalTransformer.ts | 17 ++++- .../BillPayments/BillPaymentTransformer.ts | 17 ++++- .../CommandBillPaymentDTOTransformer.ts | 6 +- .../Purchases/BillPayments/GetBillPayment.ts | 3 +- .../src/services/Purchases/Bills/GetBill.ts | 3 +- .../Bills/PurchaseInvoiceTransformer.ts | 11 +++ .../VendorCredits/BaseVendorCredit.ts | 2 +- .../VendorCredits/GetVendorCredit.ts | 3 +- .../VendorCredits/VendorCreditTransformer.ts | 11 +++ .../Sales/Estimates/GetSaleEstimate.ts | 3 +- .../Estimates/SaleEstimateTransformer.ts | 13 +++- .../Sales/Receipts/CreateSaleReceipt.ts | 1 + .../Sales/Receipts/EditSaleReceipt.ts | 1 + .../services/Sales/Receipts/GetSaleReceipt.ts | 3 +- .../Receipts/SaleReceiptDTOTransformer.ts | 7 +- .../Sales/Receipts/SaleReceiptTransformer.ts | 11 +++ .../MakeJournal/MakeJournalEntriesForm.tsx | 4 +- .../MakeJournal/MakeJournalFormFooter.tsx | 2 + .../Accounting/MakeJournal/utils.tsx | 5 ++ .../UploadAttachmentButton.module.scss | 0 .../UploadAttachmentButton.tsx | 8 +- ...UploadAttachmentPopoverContent.module.scss | 0 .../UploadAttachmentsPopoverContent.tsx | 73 +++++++++---------- .../src/containers/Attachments/utils.ts | 19 +++++ .../ExpenseForm/ExpenseFormFooter.tsx | 2 + .../containers/Expenses/ExpenseForm/utils.tsx | 10 +++ .../containers/Import/ImportDropzoneFile.tsx | 2 +- .../Bills/BillForm/BillFormFooter.tsx | 2 + .../Purchases/Bills/BillForm/utils.tsx | 10 +++ .../VendorCreditNoteFormFooter.tsx | 2 + .../CreditNotes/CreditNoteForm/utils.tsx | 10 +++ .../PaymentForm/PaymentMadeFooter.tsx | 2 + .../PaymentMades/PaymentForm/utils.tsx | 12 ++- .../CreditNoteForm/CreditNoteFormFooter.tsx | 2 + .../CreditNotes/CreditNoteForm/utils.tsx | 11 ++- .../EstimateForm/EstimateFormFooter.tsx | 2 + .../Sales/Estimates/EstimateForm/utils.tsx | 11 +++ .../InvoiceForm/InvoiceFormFooter.tsx | 2 +- .../PaymentReceiveFormFooter.tsx | 2 + .../PaymentReceiveForm/utils.tsx | 12 ++- .../ReceiptForm/ReceiptFormFooter.tsx | 2 + .../Sales/Receipts/ReceiptForm/utils.tsx | 10 +++ 49 files changed, 286 insertions(+), 67 deletions(-) rename packages/webapp/src/containers/{Sales/Invoices/InvoiceForm => Attachments}/UploadAttachmentButton.module.scss (100%) rename packages/webapp/src/containers/{Sales/Invoices/InvoiceForm => Attachments}/UploadAttachmentButton.tsx (84%) rename packages/webapp/src/containers/{Sales/Invoices/InvoiceForm => Attachments}/UploadAttachmentPopoverContent.module.scss (100%) rename packages/webapp/src/containers/{Sales/Invoices/InvoiceForm => Attachments}/UploadAttachmentsPopoverContent.tsx (77%) create mode 100644 packages/webapp/src/containers/Attachments/utils.ts diff --git a/packages/server/src/api/controllers/Sales/SalesReceipts.ts b/packages/server/src/api/controllers/Sales/SalesReceipts.ts index 04edfd9f8..ceeea9fe7 100644 --- a/packages/server/src/api/controllers/Sales/SalesReceipts.ts +++ b/packages/server/src/api/controllers/Sales/SalesReceipts.ts @@ -158,6 +158,8 @@ export default class SalesReceiptsController extends BaseController { .toInt(), check('receipt_message').optional().trim().escape(), check('statement').optional().trim().escape(), + check('attachments').isArray().optional(), + check('attachments.*.key').exists().isString(), ]; } diff --git a/packages/server/src/models/SaleEstimate.ts b/packages/server/src/models/SaleEstimate.ts index 0df7f2468..35fa723ec 100644 --- a/packages/server/src/models/SaleEstimate.ts +++ b/packages/server/src/models/SaleEstimate.ts @@ -236,7 +236,7 @@ export default class SaleEstimate extends mixin(TenantModel, [ to: 'documents.id', }, filter(query) { - query.where('model_ref', 'Expense'); + query.where('model_ref', 'SaleEstimate'); }, }, }; diff --git a/packages/server/src/models/SaleInvoice.ts b/packages/server/src/models/SaleInvoice.ts index 6c86bdaac..76a3b437e 100644 --- a/packages/server/src/models/SaleInvoice.ts +++ b/packages/server/src/models/SaleInvoice.ts @@ -540,7 +540,7 @@ export default class SaleInvoice extends mixin(TenantModel, [ to: 'documents.id', }, filter(query) { - query.where('model_ref', 'Expense'); + query.where('model_ref', 'SaleInvoice'); }, }, }; diff --git a/packages/server/src/services/Attachments/events/AttachmentsOnManualJournals.ts b/packages/server/src/services/Attachments/events/AttachmentsOnManualJournals.ts index 468daf047..ec2ef21a4 100644 --- a/packages/server/src/services/Attachments/events/AttachmentsOnManualJournals.ts +++ b/packages/server/src/services/Attachments/events/AttachmentsOnManualJournals.ts @@ -99,8 +99,6 @@ export class AttachmentsOnManualJournals { manualJournalDTO, manualJournal, }: IManualJournalEventEditedPayload) { - // if (isEmpty(saleInvoiceDTO.attachments)) return; - const keys = manualJournalDTO.attachments?.map( (attachment) => attachment.key ); diff --git a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts index 6ed80a6f0..67b51b40d 100644 --- a/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts +++ b/packages/server/src/services/CreditNotes/CreditNoteTransformer.ts @@ -2,6 +2,7 @@ import { Transformer } from '@/lib/Transformer/Transformer'; import { formatNumber } from 'utils'; import { ItemEntryTransformer } from '../Sales/Invoices/ItemEntryTransformer'; import { ICreditNote } from '@/interfaces'; +import { AttachmentTransformer } from '../Attachments/AttachmentTransformer'; export class CreditNoteTransformer extends Transformer { /** @@ -16,6 +17,7 @@ export class CreditNoteTransformer extends Transformer { 'formattedCreditsUsed', 'formattedSubtotal', 'entries', + 'attachments', ]; }; @@ -80,4 +82,13 @@ export class CreditNoteTransformer extends Transformer { currencyCode: credit.currencyCode, }); }; + + /** + * Retrieves the credit note attachments. + * @param {ISaleInvoice} invoice + * @returns + */ + protected attachments = (creditNote) => { + return this.item(creditNote.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/ManualJournals/EditManualJournal.ts b/packages/server/src/services/ManualJournals/EditManualJournal.ts index 39ff8cb8e..56ba1cf7d 100644 --- a/packages/server/src/services/ManualJournals/EditManualJournal.ts +++ b/packages/server/src/services/ManualJournals/EditManualJournal.ts @@ -78,7 +78,7 @@ export class EditManualJournal { return { id: oldManualJournal.id, - ...omit(manualJournalDTO, ['publish']), + ...omit(manualJournalDTO, ['publish', 'attachments']), ...(manualJournalDTO.publish && !oldManualJournal.publishedAt ? { publishedAt: moment().toMySqlDateTime() } : {}), @@ -143,6 +143,7 @@ export class EditManualJournal { tenantId, manualJournal, oldManualJournal, + manualJournalDTO, trx, } as IManualJournalEventEditedPayload); diff --git a/packages/server/src/services/ManualJournals/GetManualJournal.ts b/packages/server/src/services/ManualJournals/GetManualJournal.ts index 97142a494..8be45f948 100644 --- a/packages/server/src/services/ManualJournals/GetManualJournal.ts +++ b/packages/server/src/services/ManualJournals/GetManualJournal.ts @@ -28,7 +28,7 @@ export class GetManualJournal { .withGraphFetched('entries.contact') .withGraphFetched('entries.branch') .withGraphFetched('transactions') - .withGraphFetched('media') + .withGraphFetched('attachments') .throwIfNotFound(); return this.transformer.transform( diff --git a/packages/server/src/services/ManualJournals/ManualJournalTransformer.ts b/packages/server/src/services/ManualJournals/ManualJournalTransformer.ts index 7df4f71ae..cd4d0baa9 100644 --- a/packages/server/src/services/ManualJournals/ManualJournalTransformer.ts +++ b/packages/server/src/services/ManualJournals/ManualJournalTransformer.ts @@ -1,6 +1,7 @@ import { IManualJournal } from '@/interfaces'; import { Transformer } from '@/lib/Transformer/Transformer'; import { formatNumber } from 'utils'; +import { AttachmentTransformer } from '../Attachments/AttachmentTransformer'; export class ManualJournalTransfromer extends Transformer { /** @@ -8,7 +9,12 @@ export class ManualJournalTransfromer extends Transformer { * @returns {Array} */ public includeAttributes = (): string[] => { - return ['formattedAmount', 'formattedDate', 'formattedPublishedAt']; + return [ + 'formattedAmount', + 'formattedDate', + 'formattedPublishedAt', + 'attachments', + ]; }; /** @@ -39,4 +45,13 @@ export class ManualJournalTransfromer extends Transformer { protected formattedPublishedAt = (manualJorunal: IManualJournal): string => { return this.formatDate(manualJorunal.publishedAt); }; + + /** + * Retrieves the manual journal attachments. + * @param {ISaleInvoice} invoice + * @returns + */ + protected attachments = (manualJorunal: IManualJournal) => { + return this.item(manualJorunal.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts b/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts index a6662dc2d..adf77dd41 100644 --- a/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts +++ b/packages/server/src/services/Purchases/BillPayments/BillPaymentTransformer.ts @@ -2,6 +2,7 @@ import { IBillPayment } from '@/interfaces'; import { Transformer } from '@/lib/Transformer/Transformer'; import { formatNumber } from 'utils'; import { BillPaymentEntryTransformer } from './BillPaymentEntryTransformer'; +import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer'; export class BillPaymentTransformer extends Transformer { /** @@ -9,7 +10,12 @@ export class BillPaymentTransformer extends Transformer { * @returns {Array} */ public includeAttributes = (): string[] => { - return ['formattedPaymentDate', 'formattedAmount', 'entries']; + return [ + 'formattedPaymentDate', + 'formattedAmount', + 'entries', + 'attachments', + ]; }; /** @@ -38,4 +44,13 @@ export class BillPaymentTransformer extends Transformer { protected entries = (billPayment) => { return this.item(billPayment.entries, new BillPaymentEntryTransformer()); }; + + /** + * Retrieves the bill attachments. + * @param {ISaleInvoice} invoice + * @returns + */ + protected attachments = (billPayment) => { + return this.item(billPayment.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts index cefad23ec..5b6f1451d 100644 --- a/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts +++ b/packages/server/src/services/Purchases/BillPayments/CommandBillPaymentDTOTransformer.ts @@ -1,6 +1,6 @@ import { Inject, Service } from 'typedi'; import * as R from 'ramda'; -import { sumBy } from 'lodash'; +import { omit, sumBy } from 'lodash'; import { IBillPayment, IBillPaymentDTO, IVendor } from '@/interfaces'; import { BranchTransactionDTOTransform } from '@/services/Branches/Integrations/BranchTransactionDTOTransform'; import { formatDateFields } from '@/utils'; @@ -24,7 +24,9 @@ export class CommandBillPaymentDTOTransformer { oldBillPayment?: IBillPayment ): Promise { const initialDTO = { - ...formatDateFields(billPaymentDTO, ['paymentDate']), + ...formatDateFields(omit(billPaymentDTO, ['attachments']), [ + 'paymentDate', + ]), amount: sumBy(billPaymentDTO.entries, 'paymentAmount'), currencyCode: vendor.currencyCode, exchangeRate: billPaymentDTO.exchangeRate || 1, diff --git a/packages/server/src/services/Purchases/BillPayments/GetBillPayment.ts b/packages/server/src/services/Purchases/BillPayments/GetBillPayment.ts index ccb1cab77..6383c8a4e 100644 --- a/packages/server/src/services/Purchases/BillPayments/GetBillPayment.ts +++ b/packages/server/src/services/Purchases/BillPayments/GetBillPayment.ts @@ -13,7 +13,7 @@ export class GetBillPayment { private transformer: TransformerInjectable; /** - * Retrieve bill payment. + * Retrieves bill payment. * @param {number} tenantId * @param {number} billPyamentId * @return {Promise} @@ -30,6 +30,7 @@ export class GetBillPayment { .withGraphFetched('paymentAccount') .withGraphFetched('transactions') .withGraphFetched('branch') + .withGraphFetched('attachments') .findById(billPyamentId) .throwIfNotFound(); diff --git a/packages/server/src/services/Purchases/Bills/GetBill.ts b/packages/server/src/services/Purchases/Bills/GetBill.ts index 03f6a8361..0efc5dfd1 100644 --- a/packages/server/src/services/Purchases/Bills/GetBill.ts +++ b/packages/server/src/services/Purchases/Bills/GetBill.ts @@ -29,7 +29,8 @@ export class GetBill { .withGraphFetched('vendor') .withGraphFetched('entries.item') .withGraphFetched('branch') - .withGraphFetched('taxes.taxRate'); + .withGraphFetched('taxes.taxRate') + .withGraphFetched('attachments'); // Validates the bill existance. this.validators.validateBillExistance(bill); diff --git a/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts b/packages/server/src/services/Purchases/Bills/PurchaseInvoiceTransformer.ts index 4cb92adf9..43b8a4b1a 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 { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer'; import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer'; import { SaleInvoiceTaxEntryTransformer } from '@/services/Sales/Invoices/SaleInvoiceTaxEntryTransformer'; import { formatNumber } from 'utils'; @@ -26,6 +27,7 @@ export class PurchaseInvoiceTransformer extends Transformer { 'totalLocalFormatted', 'taxes', 'entries', + 'attachments', ]; }; @@ -192,4 +194,13 @@ export class PurchaseInvoiceTransformer extends Transformer { currencyCode: bill.currencyCode, }); }; + + /** + * Retrieves the bill attachments. + * @param {ISaleInvoice} invoice + * @returns + */ + protected attachments = (bill) => { + return this.item(bill.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts b/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts index 3782562f7..a07fcc79b 100644 --- a/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts +++ b/packages/server/src/services/Purchases/VendorCredits/BaseVendorCredit.ts @@ -64,7 +64,7 @@ export default class BaseVendorCredit { autoNextNumber; const initialDTO = { - ...omit(vendorCreditDTO, ['open']), + ...omit(vendorCreditDTO, ['open', 'attachments']), amount, currencyCode: vendorCurrencyCode, exchangeRate: vendorCreditDTO.exchangeRate || 1, diff --git a/packages/server/src/services/Purchases/VendorCredits/GetVendorCredit.ts b/packages/server/src/services/Purchases/VendorCredits/GetVendorCredit.ts index 19a437976..5a1f373f0 100644 --- a/packages/server/src/services/Purchases/VendorCredits/GetVendorCredit.ts +++ b/packages/server/src/services/Purchases/VendorCredits/GetVendorCredit.ts @@ -26,7 +26,8 @@ export default class GetVendorCredit { .findById(vendorCreditId) .withGraphFetched('entries.item') .withGraphFetched('vendor') - .withGraphFetched('branch'); + .withGraphFetched('branch') + .withGraphFetched('attachments'); if (!vendorCredit) { throw new ServiceError(ERRORS.VENDOR_CREDIT_NOT_FOUND); diff --git a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts index 282b6f08e..86518c23e 100644 --- a/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts +++ b/packages/server/src/services/Purchases/VendorCredits/VendorCreditTransformer.ts @@ -1,5 +1,6 @@ import { IVendorCredit } from '@/interfaces'; import { Transformer } from '@/lib/Transformer/Transformer'; +import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer'; import { ItemEntryTransformer } from '@/services/Sales/Invoices/ItemEntryTransformer'; import { formatNumber } from 'utils'; @@ -16,6 +17,7 @@ export class VendorCreditTransformer extends Transformer { 'formattedCreditsRemaining', 'formattedInvoicedAmount', 'entries', + 'attachments', ]; }; @@ -80,4 +82,13 @@ export class VendorCreditTransformer extends Transformer { currencyCode: vendorCredit.currencyCode, }); }; + + /** + * Retrieves the vendor credit attachments. + * @param {IVendorCredit} invoice + * @returns + */ + protected attachments = (vendorCredit) => { + return this.item(vendorCredit.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/Sales/Estimates/GetSaleEstimate.ts b/packages/server/src/services/Sales/Estimates/GetSaleEstimate.ts index f4d0d1419..c1a89c20d 100644 --- a/packages/server/src/services/Sales/Estimates/GetSaleEstimate.ts +++ b/packages/server/src/services/Sales/Estimates/GetSaleEstimate.ts @@ -28,7 +28,8 @@ export class GetSaleEstimate { .findById(estimateId) .withGraphFetched('entries.item') .withGraphFetched('customer') - .withGraphFetched('branch'); + .withGraphFetched('branch') + .withGraphFetched('attachments'); // Validates the estimate existance. this.validators.validateEstimateExistance(estimate); diff --git a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts index 8cd99a9db..9e6cb1be3 100644 --- a/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts +++ b/packages/server/src/services/Sales/Estimates/SaleEstimateTransformer.ts @@ -2,6 +2,7 @@ import { ISaleEstimate } from '@/interfaces'; import { Transformer } from '@/lib/Transformer/Transformer'; import { formatNumber } from 'utils'; import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer'; +import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer'; export class SaleEstimateTransfromer extends Transformer { /** @@ -18,6 +19,7 @@ export class SaleEstimateTransfromer extends Transformer { 'formattedApprovedAtDate', 'formattedRejectedAtDate', 'entries', + 'attachments', ]; }; @@ -91,9 +93,18 @@ export class SaleEstimateTransfromer extends Transformer { * @param {ISaleEstimate} estimate * @returns {} */ - protected entries = (estimate) => { + protected entries = (estimate: ISaleEstimate) => { return this.item(estimate.entries, new ItemEntryTransformer(), { currencyCode: estimate.currencyCode, }); }; + + /** + * Retrieves the sale estimate attachments. + * @param {ISaleInvoice} invoice + * @returns + */ + protected attachments = (estimate: ISaleEstimate) => { + return this.item(estimate.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/server/src/services/Sales/Receipts/CreateSaleReceipt.ts b/packages/server/src/services/Sales/Receipts/CreateSaleReceipt.ts index 65129125f..b66fe7daf 100644 --- a/packages/server/src/services/Sales/Receipts/CreateSaleReceipt.ts +++ b/packages/server/src/services/Sales/Receipts/CreateSaleReceipt.ts @@ -101,6 +101,7 @@ export class CreateSaleReceipt { tenantId, saleReceipt, saleReceiptId: saleReceipt.id, + saleReceiptDTO, trx, } as ISaleReceiptCreatedPayload); diff --git a/packages/server/src/services/Sales/Receipts/EditSaleReceipt.ts b/packages/server/src/services/Sales/Receipts/EditSaleReceipt.ts index fbdb397e4..793494199 100644 --- a/packages/server/src/services/Sales/Receipts/EditSaleReceipt.ts +++ b/packages/server/src/services/Sales/Receipts/EditSaleReceipt.ts @@ -110,6 +110,7 @@ export class EditSaleReceipt { oldSaleReceipt, saleReceipt, saleReceiptId, + saleReceiptDTO, trx, } as ISaleReceiptEditedPayload); diff --git a/packages/server/src/services/Sales/Receipts/GetSaleReceipt.ts b/packages/server/src/services/Sales/Receipts/GetSaleReceipt.ts index b2da2660c..c66a93019 100644 --- a/packages/server/src/services/Sales/Receipts/GetSaleReceipt.ts +++ b/packages/server/src/services/Sales/Receipts/GetSaleReceipt.ts @@ -28,7 +28,8 @@ export class GetSaleReceipt { .withGraphFetched('entries.item') .withGraphFetched('customer') .withGraphFetched('depositAccount') - .withGraphFetched('branch'); + .withGraphFetched('branch') + .withGraphFetched('attachments'); // Valdiates the sale receipt existance. this.validators.validateReceiptExistance(saleReceipt); diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts index 3fd078862..86c391f6e 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptDTOTransformer.ts @@ -68,9 +68,10 @@ export class SaleReceiptDTOTransformer { const initialDTO = { amount, - ...formatDateFields(omit(saleReceiptDTO, ['closed', 'entries']), [ - 'receiptDate', - ]), + ...formatDateFields( + omit(saleReceiptDTO, ['closed', 'entries', 'attachments']), + ['receiptDate'] + ), currencyCode: paymentCustomer.currencyCode, exchangeRate: saleReceiptDTO.exchangeRate || 1, receiptNumber, diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts index 9e5d3a127..f031e567a 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptTransformer.ts @@ -3,6 +3,7 @@ import { ISaleReceipt } from '@/interfaces'; import { Transformer } from '@/lib/Transformer/Transformer'; import { formatNumber } from 'utils'; import { ItemEntryTransformer } from '../Invoices/ItemEntryTransformer'; +import { AttachmentTransformer } from '@/services/Attachments/AttachmentTransformer'; @Service() export class SaleReceiptTransformer extends Transformer { @@ -17,6 +18,7 @@ export class SaleReceiptTransformer extends Transformer { 'formattedReceiptDate', 'formattedClosedAtDate', 'entries', + 'attachments', ]; }; @@ -68,4 +70,13 @@ export class SaleReceiptTransformer extends Transformer { currencyCode: receipt.currencyCode, }); }; + + /** + * Retrieves the sale receipt attachments. + * @param {ISaleReceipt} invoice + * @returns + */ + protected attachments = (receipt) => { + return this.item(receipt.attachments, new AttachmentTransformer()); + }; } diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.tsx index 205d4c0b4..a47b3b6aa 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalEntriesForm.tsx @@ -32,6 +32,7 @@ import { defaultManualJournal, } from './utils'; import { JournalSyncIncrementSettingsToForm } from './components'; +import { transformAttachmentsToRequest } from '@/containers/Attachments/utils'; /** * Journal entries form. @@ -61,7 +62,6 @@ function MakeJournalEntriesForm({ journalNumberPrefix, journalNextNumber, ); - // Form initial values. const initialValues = useMemo( () => ({ @@ -112,6 +112,7 @@ function MakeJournalEntriesForm({ setSubmitting(false); return; } + const attachments = transformAttachmentsToRequest(values); const form = { ...omit(values, ['journal_number_manually']), ...(values.journal_number_manually && { @@ -119,6 +120,7 @@ function MakeJournalEntriesForm({ }), entries: R.compose(orderingLinesIndexes)(entries), publish: submitPayload.publish, + attachments, }; // Handle the request error. const handleError = ({ diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooter.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooter.tsx index 0fcf729a8..1266dee98 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooter.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/MakeJournalFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { MakeJournalFormFooterLeft } from './MakeJournalFormFooterLeft'; import { MakeJournalFormFooterRight } from './MakeJournalFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; export default function MakeJournalFormFooter() { return ( @@ -15,6 +16,7 @@ export default function MakeJournalFormFooter() { + diff --git a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx index 5259a554e..ab7ff4c49 100644 --- a/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx +++ b/packages/webapp/src/containers/Accounting/MakeJournal/utils.tsx @@ -18,6 +18,7 @@ import { AppToaster } from '@/components'; import { useFormikContext } from 'formik'; import { useMakeJournalFormContext } from './MakeJournalProvider'; import { useCurrentOrganization } from '@/hooks/state'; +import { transformAttachmentsToForm } from '@/containers/Attachments/utils'; const ERROR = { JOURNAL_NUMBER_ALREADY_EXISTS: 'JOURNAL.NUMBER.ALREADY.EXISTS', @@ -57,6 +58,7 @@ export const defaultManualJournal = { branch_id: '', exchange_rate: 1, entries: [...repeatValue(defaultEntry, DEFAULT_LINES_NUMBER)], + attachments: [], }; // Transform to edit form. @@ -76,9 +78,12 @@ export function transformToEditForm(manualJournal) { ensureEntriesHasEmptyLine(MIN_LINES_NUMBER, defaultEntry), )(initialEntries); + const attachments = transformAttachmentsToForm(manualJournal); + return { ...transformToForm(manualJournal, defaultManualJournal), entries, + attachments, }; } diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/UploadAttachmentButton.module.scss b/packages/webapp/src/containers/Attachments/UploadAttachmentButton.module.scss similarity index 100% rename from packages/webapp/src/containers/Sales/Invoices/InvoiceForm/UploadAttachmentButton.module.scss rename to packages/webapp/src/containers/Attachments/UploadAttachmentButton.module.scss diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/UploadAttachmentButton.tsx b/packages/webapp/src/containers/Attachments/UploadAttachmentButton.tsx similarity index 84% rename from packages/webapp/src/containers/Sales/Invoices/InvoiceForm/UploadAttachmentButton.tsx rename to packages/webapp/src/containers/Attachments/UploadAttachmentButton.tsx index d9d0fbc4b..667ab8986 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/UploadAttachmentButton.tsx +++ b/packages/webapp/src/containers/Attachments/UploadAttachmentButton.tsx @@ -9,6 +9,7 @@ import { } from '@blueprintjs/core'; import { FFormGroup } from '@/components'; import { UploadAttachmentsPopoverContent } from './UploadAttachmentsPopoverContent'; +import { transformToCamelCase, transfromToSnakeCase } from '@/utils'; import styles from './UploadAttachmentButton.module.scss'; function UploadAttachmentButtonButtonContentField() { @@ -16,9 +17,9 @@ function UploadAttachmentButtonButtonContentField() { {({ form: { setFieldValue }, field: { value } }) => ( { - setFieldValue('attachments', value); + value={transformToCamelCase(value)} + onChange={(changedValue) => { + setFieldValue('attachments', transfromToSnakeCase(changedValue)); }} /> )} @@ -35,6 +36,7 @@ export function UploadAttachmentButton() { name={'attachments'} label={'Attachments'} className={styles.attachmentField} + fastField={true} > void; + onUploadedChange?: (value: AttachmentFile[]) => void; + dropzoneFieldProps?: ImportDropzoneFieldProps; } /** @@ -38,6 +40,8 @@ export function UploadAttachmentsPopoverContent({ initialValue, value, onChange, + onUploadedChange, + dropzoneFieldProps, }: UploadAttachmentsPopoverContentProps) { // Controlled/uncontrolled value state. const [localFiles, handleFilesChange] = useUncontrolled({ @@ -66,45 +70,23 @@ export function UploadAttachmentsPopoverContent({ }; // Uploads the attachments. const { mutateAsync: uploadAttachments } = useUploadAttachments({ - onSuccess: (data, variables, context) => { + onSuccess: (data) => { const newLocalFiles = stopLoadingAttachment( localFiles, data.config.data.get('internalKey'), data.data.data.key, ); handleFilesChange(newLocalFiles); + onUploadedChange && onUploadedChange(newLocalFiles); }, }); - // Deletes the attachment. - const { mutateAsync: deleteAttachment } = useDeleteAttachment(); - // Deletes the attachment of the given file key. - const DeleteButton = ({ fileKey }: { fileKey: string }) => { - const [loading, setLoading] = useState(false); - - const handleClick = () => { - setLoading(true); - deleteAttachment(fileKey).then(() => { - const updatedFiles = localFiles.filter( - (file, i) => file.key !== fileKey, - ); - handleFilesChange(updatedFiles); - setLoading(false); - }); - }; - return ( - - ); + const handleClick = (key: string) => () => { + const updatedFiles = localFiles.filter((file, i) => file.key !== key); + handleFilesChange(updatedFiles); + onUploadedChange && onUploadedChange(updatedFiles); }; + // Handle change dropzone. const handleChangeDropzone = (file: File) => { const formData = new FormData(); @@ -136,6 +118,16 @@ export function UploadAttachmentsPopoverContent({ title={''} classNames={{ root: styles.dropzoneRoot }} onChange={handleChangeDropzone} + dropzoneProps={{ + accept: [ + MIME_TYPES.doc, + MIME_TYPES.docx, + MIME_TYPES.pdf, + MIME_TYPES.png, + MIME_TYPES.jpeg, + ], + }} + {...dropzoneFieldProps} /> Formats: CSV, XLSX @@ -180,7 +172,14 @@ export function UploadAttachmentsPopoverContent({ - + )} diff --git a/packages/webapp/src/containers/Attachments/utils.ts b/packages/webapp/src/containers/Attachments/utils.ts new file mode 100644 index 000000000..168aabc77 --- /dev/null +++ b/packages/webapp/src/containers/Attachments/utils.ts @@ -0,0 +1,19 @@ +// @ts-nocheck +import { transformToForm } from '@/utils'; + +const attachmentReqSchema = { + key: '', + size: '', + origin_name: '', + mime_type: '', +}; + +export const transformAttachmentsToForm = (values) => { + return values.attachments?.map((attachment) => + transformToForm(attachment, attachmentReqSchema), + ); +}; + +export const transformAttachmentsToRequest = (values) => { + return values.attachments?.map((attachment) => ({ key: attachment.key })); +}; diff --git a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooter.tsx b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooter.tsx index e3f0d2027..4178c27ca 100644 --- a/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooter.tsx +++ b/packages/webapp/src/containers/Expenses/ExpenseForm/ExpenseFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { ExpenseFormFooterLeft } from './ExpenseFormFooterLeft'; import { ExpenseFormFooterRight } from './ExpenseFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; export default function ExpenseFormFooter() { return ( @@ -15,6 +16,7 @@ export default function ExpenseFormFooter() { + diff --git a/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx b/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx index 73c28bdad..e411d810a 100644 --- a/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx +++ b/packages/webapp/src/containers/Expenses/ExpenseForm/utils.tsx @@ -18,6 +18,10 @@ import { formattedAmount, } from '@/utils'; import { useCurrentOrganization } from '@/hooks/state'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; const ERROR = { EXPENSE_ALREADY_PUBLISHED: 'EXPENSE.ALREADY.PUBLISHED', @@ -46,6 +50,7 @@ export const defaultExpense = { branch_id: '', exchange_rate: 1, categories: [...repeatValue(defaultExpenseEntry, MIN_LINES_NUMBER)], + attachments: [], }; /** @@ -93,9 +98,12 @@ export const transformToEditForm = ( ensureEntriesHasEmptyLine(MIN_LINES_NUMBER, expenseEntry), )(initialEntries); + const attachments = transformAttachmentsToForm(expense); + return { ...transformToForm(expense, defaultExpense), categories, + attachments, }; }; @@ -133,10 +141,12 @@ export const filterNonZeroEntries = (categories) => { */ export const transformFormValuesToRequest = (values) => { const categories = filterNonZeroEntries(values.categories); + const attachments = transformAttachmentsToRequest(values); return { ...values, categories: R.compose(orderingLinesIndexes)(categories), + attachments, }; }; diff --git a/packages/webapp/src/containers/Import/ImportDropzoneFile.tsx b/packages/webapp/src/containers/Import/ImportDropzoneFile.tsx index c37c5d78f..b2705d84c 100644 --- a/packages/webapp/src/containers/Import/ImportDropzoneFile.tsx +++ b/packages/webapp/src/containers/Import/ImportDropzoneFile.tsx @@ -8,7 +8,7 @@ import { MIME_TYPES } from '@/components/Dropzone/mine-types'; import { useUncontrolled } from '@/hooks/useUncontrolled'; import styles from './ImportDropzone.module.css'; -interface ImportDropzoneFieldProps { +export interface ImportDropzoneFieldProps { initialValue?: File; value?: File; onChange?: (file: File) => void; diff --git a/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormFooter.tsx b/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormFooter.tsx index bd20a7c13..da530548b 100644 --- a/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormFooter.tsx +++ b/packages/webapp/src/containers/Purchases/Bills/BillForm/BillFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Paper, Row, Col } from '@/components'; import { BillFormFooterLeft } from './BillFormFooterLeft'; import { BillFormFooterRight } from './BillFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; // Bill form floating actions. export default function BillFormFooter() { @@ -16,6 +17,7 @@ export default function BillFormFooter() { + diff --git a/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx b/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx index f98f02757..e4f3e41e4 100644 --- a/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/Bills/BillForm/utils.tsx @@ -27,6 +27,10 @@ import { } from '@/containers/Entries/utils'; import { useBillFormContext } from './BillFormProvider'; import { TaxType } from '@/interfaces/TaxRates'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const MIN_LINES_NUMBER = 1; @@ -60,6 +64,7 @@ export const defaultBill = { exchange_rate: 1, currency_code: '', entries: [...repeatValue(defaultBillEntry, MIN_LINES_NUMBER)], + attachments: [], }; export const ERRORS = { @@ -88,12 +93,15 @@ export const transformToEditForm = (bill) => { updateItemsEntriesTotal, )(initialEntries); + const attachments = transformAttachmentsToForm(bill); + return { ...transformToForm(bill, defaultBill), inclusive_exclusive_tax: bill.is_inclusive_tax ? TaxType.Inclusive : TaxType.Exclusive, entries, + attachments, }; }; @@ -120,11 +128,13 @@ export const filterNonZeroEntries = (entries) => { */ export const transformFormValuesToRequest = (values) => { const entries = filterNonZeroEntries(values.entries); + const attachments = transformAttachmentsToRequest(values); return { ...values, entries: transformEntriesToSubmit(entries), open: false, + attachments, }; }; diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.tsx index cce9d88c5..7f91451f1 100644 --- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.tsx +++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/VendorCreditNoteFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { VendorCreditNoteFormFooterLeft } from './VendorCreditNoteFormFooterLeft'; import { VendorCreditNoteFormFooterRight } from './VendorCreditNoteFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; /** * Vendor Credit note form footer. @@ -18,6 +19,7 @@ export default function VendorCreditNoteFormFooter() { + diff --git a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx index db276ea11..a4ce4c66a 100644 --- a/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/CreditNotes/CreditNoteForm/utils.tsx @@ -20,6 +20,10 @@ import { useFormikContext } from 'formik'; import { useVendorCreditNoteFormContext } from './VendorCreditNoteFormProvider'; import { useCurrentOrganization } from '@/hooks/state'; import { getEntriesTotal } from '@/containers/Entries/utils'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const MIN_LINES_NUMBER = 1; @@ -48,6 +52,7 @@ export const defaultVendorsCreditNote = { exchange_rate: 1, currency_code: '', entries: [...repeatValue(defaultCreditNoteEntry, MIN_LINES_NUMBER)], + attachments: [], }; /** @@ -68,9 +73,12 @@ export const transformToEditForm = (creditNote) => { updateItemsEntriesTotal, )(initialEntries); + const attachments = transformAttachmentsToForm(creditNote); + return { ...transformToForm(creditNote, defaultVendorsCreditNote), entries, + attachments, }; }; @@ -100,11 +108,13 @@ export const filterNonZeroEntries = (entries) => { */ export const transformFormValuesToRequest = (values) => { const entries = filterNonZeroEntries(values.entries); + const attachments = transformAttachmentsToRequest(values); return { ...values, entries: transformEntriesToSubmit(entries), open: false, + attachments, }; }; diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFooter.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFooter.tsx index d42ad288b..8db56462e 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFooter.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/PaymentMadeFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { PaymentMadeFormFooterLeft } from './PaymentMadeFormFooterLeft'; import { PaymentMadeFormFooterRight } from './PaymentMadeFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; /** * Payment made form footer. @@ -18,6 +19,7 @@ export default function PaymentMadeFooter() { + diff --git a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx index 1b94ef4d6..fd469ce88 100644 --- a/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx +++ b/packages/webapp/src/containers/Purchases/PaymentMades/PaymentForm/utils.tsx @@ -16,6 +16,10 @@ import { } from '@/utils'; import { useCurrentOrganization } from '@/hooks/state'; import { PAYMENT_MADE_ERRORS } from '../constants'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const ERRORS = { PAYMENT_NUMBER_NOT_UNIQUE: 'PAYMENT.NUMBER.NOT.UNIQUE', @@ -44,9 +48,12 @@ export const defaultPaymentMade = { branch_id: '', exchange_rate: 1, entries: [], + attachments: [], }; export const transformToEditForm = (paymentMade, paymentMadeEntries) => { + const attachments = transformAttachmentsToForm(paymentMade); + return { ...transformToForm(paymentMade, defaultPaymentMade), full_amount: safeSumBy(paymentMadeEntries, 'payment_amount'), @@ -56,6 +63,7 @@ export const transformToEditForm = (paymentMade, paymentMadeEntries) => { payment_amount: paymentMadeEntry.payment_amount || '', })), ], + attachments, }; }; @@ -101,7 +109,9 @@ export const transformFormToRequest = (form) => { ...pick(entry, ['payment_amount', 'bill_id']), })); - return { ...form, entries: orderingLinesIndexes(entries) }; + const attachments = transformAttachmentsToRequest(form); + + return { ...form, entries: orderingLinesIndexes(entries), attachments }; }; export const useSetPrimaryBranchToForm = () => { diff --git a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.tsx b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.tsx index 5c0a62ddc..ba55d2443 100644 --- a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.tsx +++ b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/CreditNoteFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { CreditNoteFormFooterLeft } from './CreditNoteFormFooterLeft'; import { CreditNoteFormFooterRight } from './CreditNoteFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; /** * Credit note form footer. @@ -18,6 +19,7 @@ export default function CreditNoteFormFooter() { + diff --git a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/utils.tsx b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/utils.tsx index 2200146de..52af20853 100644 --- a/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/CreditNotes/CreditNoteForm/utils.tsx @@ -8,7 +8,6 @@ import { defaultFastFieldShouldUpdate, transformToForm, repeatValue, - transactionNumber, formattedAmount, orderingLinesIndexes, } from '@/utils'; @@ -21,6 +20,10 @@ import { } from '@/containers/Entries/utils'; import { useCurrentOrganization } from '@/hooks/state'; import { getEntriesTotal } from '@/containers/Entries/utils'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const MIN_LINES_NUMBER = 1; @@ -51,6 +54,7 @@ export const defaultCreditNote = { exchange_rate: 1, currency_code: '', entries: [...repeatValue(defaultCreditNoteEntry, MIN_LINES_NUMBER)], + attachments: [] }; /** @@ -71,9 +75,12 @@ export function transformToEditForm(creditNote) { updateItemsEntriesTotal, )(initialEntries); + const attachment = transformAttachmentsToForm(creditNote); + return { ...transformToForm(creditNote, defaultCreditNote), entries, + attachment, }; } @@ -103,11 +110,13 @@ export const filterNonZeroEntries = (entries) => { */ export const transformFormValuesToRequest = (values) => { const entries = filterNonZeroEntries(values.entries); + const attachments = transformAttachmentsToRequest(values); return { ...values, entries: transformEntriesToSubmit(entries), open: false, + attachments, }; }; diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormFooter.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormFooter.tsx index 13d269299..9e9ae1970 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormFooter.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/EstimateFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { EstimateFormFooterLeft } from './EstimateFormFooterLeft'; import { EstimateFormFooterRight } from './EstimateFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; /** * Estimate form footer. @@ -18,6 +19,7 @@ export default function EstiamteFormFooter() { + diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx index 486c1de21..48088a524 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateForm/utils.tsx @@ -18,6 +18,10 @@ import { } from '@/containers/Entries/utils'; import { useCurrentOrganization } from '@/hooks/state'; import { getEntriesTotal } from '@/containers/Entries/utils'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const MIN_LINES_NUMBER = 1; @@ -56,6 +60,7 @@ export const defaultEstimate = { exchange_rate: 1, currency_code: '', entries: [...repeatValue(defaultEstimateEntry, MIN_LINES_NUMBER)], + attachments: [] }; const ERRORS = { @@ -78,9 +83,12 @@ export const transformToEditForm = (estimate) => { updateItemsEntriesTotal, )(initialEntries); + const attachments = transformAttachmentsToForm(estimate); + return { ...transformToForm(estimate, defaultEstimate), entries, + attachments, }; }; @@ -150,6 +158,8 @@ export const transfromsFormValuesToRequest = (values) => { const entries = values.entries.filter( (item) => item.item_id && item.quantity, ); + const attachments = transformAttachmentsToRequest(values); + return { ...omit(values, ['estimate_number_manually', 'estimate_number']), // The `estimate_number_manually` will be presented just if the auto-increment @@ -160,6 +170,7 @@ export const transfromsFormValuesToRequest = (values) => { entries: entries.map((entry) => ({ ...transformToForm(entry, defaultEstimateEntryReq), })), + attachments, }; }; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormFooter.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormFooter.tsx index 23e7b7cef..df91621a9 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormFooter.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceForm/InvoiceFormFooter.tsx @@ -7,7 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Paper, Row, Col } from '@/components'; import { InvoiceFormFooterLeft } from './InvoiceFormFooterLeft'; import { InvoiceFormFooterRight } from './InvoiceFormFooterRight'; -import { UploadAttachmentButton } from './UploadAttachmentButton'; +import { UploadAttachmentButton } from '../../../Attachments/UploadAttachmentButton'; export default function InvoiceFormFooter() { return ( diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFooter.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFooter.tsx index bcf85e68b..97d2eac68 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFooter.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/PaymentReceiveFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Row, Col, Paper } from '@/components'; import { PaymentReceiveFormFootetLeft } from './PaymentReceiveFormFootetLeft'; import { PaymentReceiveFormFootetRight } from './PaymentReceiveFormFootetRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; /** * Payment receive form footer. @@ -18,6 +19,7 @@ export default function PaymentReceiveFormFooter() { + diff --git a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx index 900eb9f9a..71f75280a 100644 --- a/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/PaymentReceives/PaymentReceiveForm/utils.tsx @@ -9,13 +9,16 @@ import { AppToaster } from '@/components'; import { usePaymentReceiveFormContext } from './PaymentReceiveFormProvider'; import { defaultFastFieldShouldUpdate, - transactionNumber, transformToForm, safeSumBy, orderingLinesIndexes, formattedAmount, } from '@/utils'; import { useCurrentOrganization } from '@/hooks/state'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; // Default payment receive entry. export const defaultPaymentReceiveEntry = { @@ -39,11 +42,12 @@ export const defaultPaymentReceive = { // Holds the payment number that entered manually only. payment_receive_no_manually: '', statement: '', - full_amount: '', + full_amount: '', currency_code: '', branch_id: '', exchange_rate: 1, entries: [], + attachments: [] }; export const defaultRequestPaymentEntry = { @@ -74,6 +78,7 @@ export const transformToEditForm = (paymentReceive, paymentReceiveEntries) => ({ payment_amount: paymentReceiveEntry.payment_amount || '', })), ], + attachments: transformAttachmentsToForm(paymentReceive), }); /** @@ -155,6 +160,8 @@ export const transformFormToRequest = (form) => { ...pick(entry, Object.keys(defaultRequestPaymentEntry)), })); + const attachments = transformAttachmentsToRequest(form); + return { ...omit(form, ['payment_receive_no_manually', 'payment_receive_no']), // The `payment_receive_no_manually` will be presented just if the auto-increment @@ -163,6 +170,7 @@ export const transformFormToRequest = (form) => { payment_receive_no: form.payment_receive_no, }), entries: orderingLinesIndexes(entries), + attachments, }; }; diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormFooter.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormFooter.tsx index d3c93658a..500b1e785 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormFooter.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/ReceiptFormFooter.tsx @@ -7,6 +7,7 @@ import { CLASSES } from '@/constants/classes'; import { Paper, Row, Col } from '@/components'; import { ReceiptFormFooterLeft } from './ReceiptFormFooterLeft'; import { ReceiptFormFooterRight } from './ReceiptFormFooterRight'; +import { UploadAttachmentButton } from '@/containers/Attachments/UploadAttachmentButton'; export default function ReceiptFormFooter({}) { return ( @@ -15,6 +16,7 @@ export default function ReceiptFormFooter({}) { + diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/utils.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/utils.tsx index d58cb6179..d92a7cd91 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/utils.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptForm/utils.tsx @@ -18,6 +18,10 @@ import { } from '@/containers/Entries/utils'; import { useCurrentOrganization } from '@/hooks/state'; import { getEntriesTotal } from '@/containers/Entries/utils'; +import { + transformAttachmentsToForm, + transformAttachmentsToRequest, +} from '@/containers/Attachments/utils'; export const MIN_LINES_NUMBER = 1; @@ -56,6 +60,7 @@ export const defaultReceipt = { exchange_rate: 1, currency_code: '', entries: [...repeatValue(defaultReceiptEntry, MIN_LINES_NUMBER)], + attachments: [], }; const ERRORS = { @@ -81,9 +86,12 @@ export const transformToEditForm = (receipt) => { updateItemsEntriesTotal, )(initialEntries); + const attachments = transformAttachmentsToForm(receipt); + return { ...transformToForm(receipt, defaultReceipt), entries, + attachments, }; }; @@ -142,6 +150,7 @@ export const transformFormValuesToRequest = (values) => { const entries = values.entries.filter( (item) => item.item_id && item.quantity, ); + const attachments = transformAttachmentsToRequest(values); return { ...omit(values, ['receipt_number_manually', 'receipt_number']), @@ -152,6 +161,7 @@ export const transformFormValuesToRequest = (values) => { ...transformToForm(entry, defaultReceiptEntryReq), })), closed: false, + attachments, }; };