feat: Assign default PDF template automatically

This commit is contained in:
Ahmed Bouhuolia
2024-10-02 18:18:57 +02:00
parent cbc60b3c73
commit b23112bc92
30 changed files with 501 additions and 46 deletions

View File

@@ -95,6 +95,12 @@ export default class PaymentReceivesController extends BaseController {
asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)), asyncMiddleware(this.getPaymentReceiveInvoices.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
this.getPaymentReceivedState.bind(this),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive), CheckPolicies(PaymentReceiveAction.View, AbilitySubject.PaymentReceive),
@@ -391,6 +397,29 @@ export default class PaymentReceivesController extends BaseController {
} }
} }
/**
*
* @async
* @param {Request} req -
* @param {Response} res -
*/
private async getPaymentReceivedState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
try {
const data = await this.paymentReceiveApplication.getPaymentReceivedState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Retrieve the given payment receive details. * Retrieve the given payment receive details.
* @async * @async

View File

@@ -105,6 +105,12 @@ export default class SalesEstimatesController extends BaseController {
asyncMiddleware(this.deleteEstimate.bind(this)), asyncMiddleware(this.deleteEstimate.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
this.getSaleEstimateState.bind(this),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate), CheckPolicies(SaleEstimateAction.View, AbilitySubject.SaleEstimate),
@@ -546,6 +552,23 @@ export default class SalesEstimatesController extends BaseController {
} }
}; };
private getSaleEstimateState = async (
req: Request,
res: Response,
next: NextFunction
) => {
const { tenantId } = req;
try {
const data = await this.saleEstimatesApplication.getSaleEstimateState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
};
/** /**
* Handles service errors. * Handles service errors.
* @param {Error} error * @param {Error} error

View File

@@ -130,6 +130,12 @@ export default class SaleInvoicesController extends BaseController {
this.asyncMiddleware(this.getInvoicePaymentTransactions), this.asyncMiddleware(this.getInvoicePaymentTransactions),
this.handleServiceErrors this.handleServiceErrors
); );
router.get(
'/state',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
asyncMiddleware(this.getSaleInvoiceState.bind(this)),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice), CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
@@ -138,6 +144,7 @@ export default class SaleInvoicesController extends BaseController {
asyncMiddleware(this.getSaleInvoice.bind(this)), asyncMiddleware(this.getSaleInvoice.bind(this)),
this.handleServiceErrors this.handleServiceErrors
); );
router.get( router.get(
'/', '/',
CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice), CheckPolicies(SaleInvoiceAction.View, AbilitySubject.SaleInvoice),
@@ -453,6 +460,24 @@ export default class SaleInvoicesController extends BaseController {
return res.status(200).send({ saleInvoice }); return res.status(200).send({ saleInvoice });
} }
} }
private async getSaleInvoiceState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
try {
const data = await this.saleInvoiceApplication.getSaleInvoiceState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Retrieve paginated sales invoices with custom view metadata. * Retrieve paginated sales invoices with custom view metadata.
* @param {Request} req * @param {Request} req

View File

@@ -108,6 +108,12 @@ export default class SalesReceiptsController extends BaseController {
this.handleServiceErrors, this.handleServiceErrors,
this.dynamicListService.handlerErrorsToResponse this.dynamicListService.handlerErrorsToResponse
); );
router.get(
'/state',
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
asyncMiddleware(this.getSaleReceiptState.bind(this)),
this.handleServiceErrors
);
router.get( router.get(
'/:id', '/:id',
CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt), CheckPolicies(SaleReceiptAction.View, AbilitySubject.SaleReceipt),
@@ -369,6 +375,30 @@ export default class SalesReceiptsController extends BaseController {
} }
} }
/**
*
* @param {Request} req
* @param {Response} res
* @param {NextFunction} next
*/
public async getSaleReceiptState(
req: Request,
res: Response,
next: NextFunction
) {
const { tenantId } = req;
// Retrieves receipt in pdf format.
try {
const data = await this.saleReceiptsApplication.getSaleReceiptState(
tenantId
);
return res.status(200).send({ data });
} catch (error) {
next(error);
}
}
/** /**
* Sale receipt notification via SMS. * Sale receipt notification via SMS.
* @param {Request} req * @param {Request} req

View File

@@ -238,3 +238,8 @@ export interface PaymentReceivedPdfTemplateAttributes {
showPaymentReceivedDate: boolean; showPaymentReceivedDate: boolean;
paymentReceivedDateLabel: string; paymentReceivedDateLabel: string;
} }
export interface IPaymentReceivedState {
defaultTemplateId: number;
}

View File

@@ -144,3 +144,6 @@ export interface ISaleEstimateMailPresendEvent {
messageOptions: SaleEstimateMailOptionsDTO; messageOptions: SaleEstimateMailOptionsDTO;
} }
export interface ISaleEstimateState {
defaultTemplateId: number;
}

View File

@@ -20,7 +20,7 @@ export interface PaymentIntegrationTransactionLinkEventPayload {
referenceType: string; referenceType: string;
referenceId: number; referenceId: number;
saleInvoiceId: number; saleInvoiceId: number;
trx?: Knex.Transaction trx?: Knex.Transaction;
} }
export interface PaymentIntegrationTransactionLinkDeleteEventPayload { export interface PaymentIntegrationTransactionLinkDeleteEventPayload {
@@ -30,7 +30,7 @@ export interface PaymentIntegrationTransactionLinkDeleteEventPayload {
referenceType: string; referenceType: string;
referenceId: number; referenceId: number;
oldSaleInvoiceId: number; oldSaleInvoiceId: number;
trx?: Knex.Transaction trx?: Knex.Transaction;
} }
export interface ISaleInvoice { export interface ISaleInvoice {
@@ -174,7 +174,7 @@ export interface ISaleInvoiceDeletingPayload {
tenantId: number; tenantId: number;
oldSaleInvoice: ISaleInvoice; oldSaleInvoice: ISaleInvoice;
saleInvoiceId: number; saleInvoiceId: number;
trx: Knex.Transaction; trx: Knex.Transaction;
} }
export interface ISaleInvoiceDeletedPayload { export interface ISaleInvoiceDeletedPayload {
@@ -339,3 +339,7 @@ export interface InvoicePdfTemplateAttributes {
showStatement: boolean; showStatement: boolean;
statement: string; statement: string;
} }
export interface ISaleInvocieState {
defaultTemplateId: number;
}

View File

@@ -211,3 +211,8 @@ export interface ISaleReceiptBrandingTemplateAttributes {
showReceiptDate: boolean; showReceiptDate: boolean;
receiptDateLabel: string; receiptDateLabel: string;
} }
export interface ISaleReceiptState {
defaultTemplateId: number;
}

View File

@@ -0,0 +1,20 @@
import { Service } from 'typedi';
import { ISaleEstimateState } from '@/interfaces';
@Service()
export class GetSaleEstimateState {
/**
*
* @param {Number} saleEstimateId -
* @return {Promise<ISaleEstimateState>}
*/
public async getSaleEstimateState(
tenantId: number
): Promise<ISaleEstimateState> {
return {
defaultTemplateId: 1,
};
}
}

View File

@@ -20,6 +20,7 @@ import { RejectSaleEstimate } from './RejectSaleEstimate';
import { SaleEstimateNotifyBySms } from './SaleEstimateSmsNotify'; import { SaleEstimateNotifyBySms } from './SaleEstimateSmsNotify';
import { SaleEstimatesPdf } from './SaleEstimatesPdf'; import { SaleEstimatesPdf } from './SaleEstimatesPdf';
import { SendSaleEstimateMail } from './SendSaleEstimateMail'; import { SendSaleEstimateMail } from './SendSaleEstimateMail';
import { GetSaleEstimateState } from './GetSaleEstimateState';
@Service() @Service()
export class SaleEstimatesApplication { export class SaleEstimatesApplication {
@@ -56,6 +57,9 @@ export class SaleEstimatesApplication {
@Inject() @Inject()
private sendEstimateMailService: SendSaleEstimateMail; private sendEstimateMailService: SendSaleEstimateMail;
@Inject()
private getSaleEstimateStateService: GetSaleEstimateState;
/** /**
* Create a sale estimate. * Create a sale estimate.
* @param {number} tenantId - The tenant id. * @param {number} tenantId - The tenant id.
@@ -249,4 +253,13 @@ export class SaleEstimatesApplication {
saleEstimateId saleEstimateId
); );
} }
/**
* Retrieves the current state of the sale estimate.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<ISaleEstimateState>} - A promise resolving to the sale estimate state.
*/
public getSaleEstimateStat(tenantId: number) {
return this.getSaleEstimateStateService.getSaleEstimateState(tenantId);
}
} }

View File

@@ -0,0 +1,18 @@
import { Service } from 'typedi';
import { ISaleInvocieState } from '@/interfaces';
@Service()
export class GetSaleInvoiceState {
/**
*
* @param {Number} saleInvoiceId -
* @return {Promise<ISaleInvoice>}
*/
public async getSaleInvoiceState(
tenantId: number
): Promise<ISaleInvocieState> {
return {
defaultTemplateId: 1,
};
}
}

View File

@@ -28,6 +28,7 @@ import { SaleInvoiceNotifyBySms } from './SaleInvoiceNotifyBySms';
import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder'; import { SendInvoiceMailReminder } from './SendSaleInvoiceMailReminder';
import { SendSaleInvoiceMail } from './SendSaleInvoiceMail'; import { SendSaleInvoiceMail } from './SendSaleInvoiceMail';
import { GetSaleInvoiceMailReminder } from './GetSaleInvoiceMailReminder'; import { GetSaleInvoiceMailReminder } from './GetSaleInvoiceMailReminder';
import { GetSaleInvoiceState } from './GetSaleInvoiceState';
@Service() @Service()
export class SaleInvoiceApplication { export class SaleInvoiceApplication {
@@ -73,6 +74,9 @@ export class SaleInvoiceApplication {
@Inject() @Inject()
private getSaleInvoiceReminderService: GetSaleInvoiceMailReminder; private getSaleInvoiceReminderService: GetSaleInvoiceMailReminder;
@Inject()
private getSaleInvoiceStateService: GetSaleInvoiceState;
/** /**
* Creates a new sale invoice with associated GL entries. * Creates a new sale invoice with associated GL entries.
* @param {number} tenantId * @param {number} tenantId
@@ -169,6 +173,16 @@ export class SaleInvoiceApplication {
); );
} }
/**
* Retrieves the sale invoice state.
* @param {number} tenantId
* @param {number} saleInvoiceId
* @returns
*/
public getSaleInvoiceState(tenantId: number) {
return this.getSaleInvoiceStateService.getSaleInvoiceState(tenantId);
}
/** /**
* Mark the given sale invoice as delivered. * Mark the given sale invoice as delivered.
* @param {number} tenantId * @param {number} tenantId

View File

@@ -0,0 +1,18 @@
import { Service } from 'typedi';
import { IPaymentReceivedState } from '@/interfaces';
@Service()
export class GetPaymentReceivedState {
/**
* Retrieves the current state of the payment received.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<IPaymentReceivedState>} - A promise resolving to the payment received state.
*/
public async getPaymentReceivedState(
tenantId: number
): Promise<IPaymentReceivedState> {
return {
defaultTemplateId: 1,
};
}
}

View File

@@ -19,6 +19,7 @@ import { GetPaymentReceivedInvoices } from './GetPaymentReceivedInvoices';
import { PaymentReceiveNotifyBySms } from './PaymentReceivedSmsNotify'; import { PaymentReceiveNotifyBySms } from './PaymentReceivedSmsNotify';
import GetPaymentReceivedPdf from './GetPaymentReceivedPdf'; import GetPaymentReceivedPdf from './GetPaymentReceivedPdf';
import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification'; import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification';
import { GetPaymentReceivedState } from './GetPaymentReceivedState';
@Service() @Service()
export class PaymentReceivesApplication { export class PaymentReceivesApplication {
@@ -49,6 +50,9 @@ export class PaymentReceivesApplication {
@Inject() @Inject()
private getPaymentReceivePdfService: GetPaymentReceivedPdf; private getPaymentReceivePdfService: GetPaymentReceivedPdf;
@Inject()
private getPaymentReceivedStateService: GetPaymentReceivedState;
/** /**
* Creates a new payment receive. * Creates a new payment receive.
* @param {number} tenantId * @param {number} tenantId
@@ -223,4 +227,10 @@ export class PaymentReceivesApplication {
paymentReceiveId paymentReceiveId
); );
}; };
public getPaymentReceivedState = (tenantId: number) => {
return this.getPaymentReceivedStateService.getPaymentReceivedState(
tenantId
);
};
} }

View File

@@ -0,0 +1,18 @@
import { Service } from 'typedi';
import { ISaleReceiptState } from '@/interfaces';
@Service()
export class GetSaleReceiptState {
/**
* Retireves the sale receipt state.
* @param {Number} tenantId -
* @return {Promise<ISaleReceiptState>}
*/
public async getSaleReceiptState(
tenantId: number
): Promise<ISaleReceiptState> {
return {
defaultTemplateId: 1,
};
}
}

View File

@@ -4,6 +4,7 @@ import {
IFilterMeta, IFilterMeta,
IPaginationMeta, IPaginationMeta,
ISaleReceipt, ISaleReceipt,
ISaleReceiptState,
ISalesReceiptsFilter, ISalesReceiptsFilter,
SaleReceiptMailOpts, SaleReceiptMailOpts,
SaleReceiptMailOptsDTO, SaleReceiptMailOptsDTO,
@@ -16,6 +17,7 @@ import { CloseSaleReceipt } from './CloseSaleReceipt';
import { SaleReceiptsPdf } from './SaleReceiptsPdfService'; import { SaleReceiptsPdf } from './SaleReceiptsPdfService';
import { SaleReceiptNotifyBySms } from './SaleReceiptNotifyBySms'; import { SaleReceiptNotifyBySms } from './SaleReceiptNotifyBySms';
import { SaleReceiptMailNotification } from './SaleReceiptMailNotification'; import { SaleReceiptMailNotification } from './SaleReceiptMailNotification';
import { GetSaleReceiptState } from './GetSaleReceiptState';
@Service() @Service()
export class SaleReceiptApplication { export class SaleReceiptApplication {
@@ -46,6 +48,9 @@ export class SaleReceiptApplication {
@Inject() @Inject()
private saleReceiptNotifyByMailService: SaleReceiptMailNotification; private saleReceiptNotifyByMailService: SaleReceiptMailNotification;
@Inject()
private getSaleReceiptStateService: GetSaleReceiptState;
/** /**
* Creates a new sale receipt with associated entries. * Creates a new sale receipt with associated entries.
* @param {number} tenantId * @param {number} tenantId
@@ -207,4 +212,13 @@ export class SaleReceiptApplication {
saleReceiptId saleReceiptId
); );
} }
/**
* Retrieves the current state of the sale receipt.
* @param {number} tenantId - The ID of the tenant.
* @returns {Promise<ISaleReceiptState>} - A promise resolving to the sale receipt state.
*/
public getSaleReceiptState(tenantId: number): Promise<ISaleReceiptState> {
return this.getSaleReceiptStateService.getSaleReceiptState(tenantId);
}
} }

View File

@@ -17,10 +17,19 @@ import {
useBranches, useBranches,
useSettingsCreditNotes, useSettingsCreditNotes,
useInvoice, useInvoice,
useGetCreditNoteState,
CreditNoteStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
const CreditNoteFormContext = React.createContext(); interface CreditNoteFormProviderValue {
creditNoteState: CreditNoteStateResponse;
isCreditNoteStateLoading: boolean;
}
const CreditNoteFormContext = React.createContext<CreditNoteFormProviderValue>(
{} as CreditNoteFormProviderValue,
);
/** /**
* Credit note data provider. * Credit note data provider.
@@ -78,6 +87,10 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'PaymentReceive' }); useGetPdfTemplates({ resource: 'PaymentReceive' });
// Fetches the credit note state.
const { data: creditNoteState, isLoading: isCreditNoteStateLoading } =
useGetCreditNoteState();
// Handle fetching settings. // Handle fetching settings.
useSettingsCreditNotes(); useSettingsCreditNotes();
@@ -124,6 +137,10 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
// Branding templates. // Branding templates.
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Credit note state
creditNoteState,
isCreditNoteStateLoading,
}; };
const isLoading = const isLoading =
@@ -140,6 +157,7 @@ function CreditNoteFormProvider({ creditNoteId, ...props }) {
); );
} }
const useCreditNoteFormContext = () => React.useContext(CreditNoteFormContext); const useCreditNoteFormContext = () =>
React.useContext<CreditNoteFormProviderValue>(CreditNoteFormContext);
export { CreditNoteFormProvider, useCreditNoteFormContext }; export { CreditNoteFormProvider, useCreditNoteFormContext };

View File

@@ -58,6 +58,7 @@ function EstimateForm({
submitPayload, submitPayload,
createEstimateMutate, createEstimateMutate,
editEstimateMutate, editEstimateMutate,
saleEstimateState,
} = useEstimateFormContext(); } = useEstimateFormContext();
const estimateNumber = transactionNumber( const estimateNumber = transactionNumber(
@@ -79,6 +80,7 @@ function EstimateForm({
currency_code: base_currency, currency_code: base_currency,
terms_conditions: defaultTo(estimateTermsConditions, ''), terms_conditions: defaultTo(estimateTermsConditions, ''),
note: defaultTo(estimateCustomerNotes, ''), note: defaultTo(estimateCustomerNotes, ''),
pdf_template_id: saleEstimateState?.defaultTemplateId,
}), }),
}; };

View File

@@ -11,6 +11,8 @@ import {
useSettingsEstimates, useSettingsEstimates,
useCreateEstimate, useCreateEstimate,
useEditEstimate, useEditEstimate,
useGetSaleEstimatesState,
ISaleEstimatesStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
@@ -18,7 +20,12 @@ import { Features } from '@/constants';
import { useFeatureCan } from '@/hooks/state'; import { useFeatureCan } from '@/hooks/state';
import { ITEMS_FILTER_ROLES } from './utils'; import { ITEMS_FILTER_ROLES } from './utils';
const EstimateFormContext = createContext(); interface EstimateFormProviderValues {
saleEstimateState: ISaleEstimatesStateResponse;
isSaleEstimateStateLoading: boolean;
}
const EstimateFormContext = createContext({} as EstimateFormProviderValues);
/** /**
* Estimate form provider. * Estimate form provider.
@@ -76,6 +83,10 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'SaleEstimate' }); useGetPdfTemplates({ resource: 'SaleEstimate' });
// Fetches the sale estimate state.
const { data: saleEstimateState, isLoading: isSaleEstimateStateLoading } =
useGetSaleEstimatesState();
// Handle fetch settings. // Handle fetch settings.
useSettingsEstimates(); useSettingsEstimates();
@@ -118,15 +129,21 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
createEstimateMutate, createEstimateMutate,
editEstimateMutate, editEstimateMutate,
// Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Estimate state
saleEstimateState,
isSaleEstimateStateLoading,
}; };
const isLoading = const isLoading =
isCustomersLoading || isCustomersLoading ||
isItemsLoading || isItemsLoading ||
isEstimateLoading || isEstimateLoading ||
isBrandingTemplatesLoading; isBrandingTemplatesLoading ||
isSaleEstimateStateLoading;
return ( return (
<DashboardInsider loading={isLoading} name={'estimate-form'}> <DashboardInsider loading={isLoading} name={'estimate-form'}>
@@ -135,6 +152,7 @@ function EstimateFormProvider({ query, estimateId, ...props }) {
); );
} }
const useEstimateFormContext = () => useContext(EstimateFormContext); const useEstimateFormContext = () =>
useContext<EstimateFormProviderValues>(EstimateFormContext);
export { EstimateFormProvider, useEstimateFormContext }; export { EstimateFormProvider, useEstimateFormContext };

View File

@@ -61,6 +61,7 @@ function InvoiceForm({
createInvoiceMutate, createInvoiceMutate,
editInvoiceMutate, editInvoiceMutate,
submitPayload, submitPayload,
saleInvoiceState
} = useInvoiceFormContext(); } = useInvoiceFormContext();
// Invoice number. // Invoice number.
@@ -83,6 +84,7 @@ function InvoiceForm({
currency_code: base_currency, currency_code: base_currency,
invoice_message: defaultTo(invoiceCustomerNotes, ''), invoice_message: defaultTo(invoiceCustomerNotes, ''),
terms_conditions: defaultTo(invoiceTermsConditions, ''), terms_conditions: defaultTo(invoiceTermsConditions, ''),
pdf_template_id: saleInvoiceState?.defaultTemplateId,
...newInvoice, ...newInvoice,
}), }),
}; };

View File

@@ -16,13 +16,22 @@ import {
useEditInvoice, useEditInvoice,
useSettingsInvoices, useSettingsInvoices,
useEstimate, useEstimate,
useGetSaleInvoiceState,
GetSaleInvoiceStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useTaxRates } from '@/hooks/query/taxRates'; import { useTaxRates } from '@/hooks/query/taxRates';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
import { useGetPaymentServices } from '@/hooks/query/payment-services'; import { useGetPaymentServices } from '@/hooks/query/payment-services';
const InvoiceFormContext = createContext(); interface InvoiceFormContextValue {
saleInvoiceState: GetSaleInvoiceStateResponse | null;
isInvoiceStateLoading: boolean;
}
const InvoiceFormContext = createContext<InvoiceFormContextValue>(
{} as InvoiceFormContextValue,
);
/** /**
* Accounts chart data provider. * Accounts chart data provider.
@@ -100,6 +109,9 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
isSuccess: isBranchesSuccess, isSuccess: isBranchesSuccess,
} = useBranches({}, { enabled: isBranchFeatureCan }); } = useBranches({}, { enabled: isBranchFeatureCan });
const { data: saleInvoiceState, isLoading: isInvoiceStateLoading } =
useGetSaleInvoiceState();
// Handle fetching settings. // Handle fetching settings.
const { isLoading: isSettingsLoading } = useSettingsInvoices(); const { isLoading: isSettingsLoading } = useSettingsInvoices();
@@ -154,6 +166,10 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
// Payment Services // Payment Services
paymentServices, paymentServices,
isPaymentServicesLoading, isPaymentServicesLoading,
// Invoice state
saleInvoiceState,
isInvoiceStateLoading,
}; };
return ( return (
@@ -172,6 +188,7 @@ function InvoiceFormProvider({ invoiceId, baseCurrency, ...props }) {
); );
} }
const useInvoiceFormContext = () => React.useContext(InvoiceFormContext); const useInvoiceFormContext = () =>
React.useContext<InvoiceFormContextValue>(InvoiceFormContext);
export { InvoiceFormProvider, useInvoiceFormContext }; export { InvoiceFormProvider, useInvoiceFormContext };

View File

@@ -69,6 +69,7 @@ function PaymentReceiveForm({
editPaymentReceiveMutate, editPaymentReceiveMutate,
createPaymentReceiveMutate, createPaymentReceiveMutate,
isExcessConfirmed, isExcessConfirmed,
paymentReceivedState,
} = usePaymentReceiveFormContext(); } = usePaymentReceiveFormContext();
// Payment receive number. // Payment receive number.
@@ -77,29 +78,21 @@ function PaymentReceiveForm({
paymentReceiveNextNumber, paymentReceiveNextNumber,
); );
// Form initial values. // Form initial values.
const initialValues = useMemo( const initialValues = {
() => ({ ...(!isEmpty(paymentReceiveEditPage)
...(!isEmpty(paymentReceiveEditPage) ? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage)
? transformToEditForm(paymentReceiveEditPage, paymentEntriesEditPage) : {
: { ...defaultPaymentReceive,
...defaultPaymentReceive, // If the auto-increment mode is enabled, take the next payment
// If the auto-increment mode is enabled, take the next payment // number from the settings.
// number from the settings. ...(paymentReceiveAutoIncrement && {
...(paymentReceiveAutoIncrement && { payment_receive_no: nextPaymentNumber,
payment_receive_no: nextPaymentNumber,
}),
deposit_account_id: defaultTo(preferredDepositAccount, ''),
currency_code: base_currency,
}), }),
}), deposit_account_id: defaultTo(preferredDepositAccount, ''),
[ currency_code: base_currency,
paymentReceiveEditPage, pdf_template_id: paymentReceivedState.defaultTemplateId,
nextPaymentNumber, }),
paymentEntriesEditPage, };
paymentReceiveAutoIncrement,
preferredDepositAccount,
],
);
// Handle form submit. // Handle form submit.
const handleSubmitForm = ( const handleSubmitForm = (
values, values,

View File

@@ -12,11 +12,21 @@ import {
useBranches, useBranches,
useCreatePaymentReceive, useCreatePaymentReceive,
useEditPaymentReceive, useEditPaymentReceive,
usePaymentReceivedState,
PaymentReceivedStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
interface PaymentReceivedFormContextValue {
isPaymentReceivedStateLoading: boolean;
paymentReceivedState: PaymentReceivedStateResponse;
}
// Payment receive form context. // Payment receive form context.
const PaymentReceiveFormContext = createContext(); const PaymentReceiveFormContext =
createContext<PaymentReceivedFormContextValue>(
{} as PaymentReceivedFormContextValue,
);
/** /**
* Payment receive form provider. * Payment receive form provider.
@@ -70,6 +80,12 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'PaymentReceive' }); useGetPdfTemplates({ resource: 'PaymentReceive' });
// Fetches the payment received initial state.
const {
data: paymentReceivedState,
isLoading: isPaymentReceivedStateLoading,
} = usePaymentReceivedState();
// Detarmines whether the new mode. // Detarmines whether the new mode.
const isNewMode = !paymentReceiveId; const isNewMode = !paymentReceiveId;
@@ -111,6 +127,10 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
// Branding templates // Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// Payment received state
isPaymentReceivedStateLoading,
paymentReceivedState,
}; };
const isLoading = const isLoading =
@@ -127,6 +147,6 @@ function PaymentReceiveFormProvider({ query, paymentReceiveId, ...props }) {
} }
const usePaymentReceiveFormContext = () => const usePaymentReceiveFormContext = () =>
useContext(PaymentReceiveFormContext); useContext<PaymentReceivedFormContextValue>(PaymentReceiveFormContext);
export { PaymentReceiveFormProvider, usePaymentReceiveFormContext }; export { PaymentReceiveFormProvider, usePaymentReceiveFormContext };

View File

@@ -63,6 +63,7 @@ function ReceiptForm({
createReceiptMutate, createReceiptMutate,
submitPayload, submitPayload,
isNewMode, isNewMode,
saleReceiptState,
} = useReceiptFormContext(); } = useReceiptFormContext();
// The next receipt number. // The next receipt number.
@@ -84,6 +85,7 @@ function ReceiptForm({
currency_code: base_currency, currency_code: base_currency,
receipt_message: receiptMessage, receipt_message: receiptMessage,
terms_conditions: receiptTermsConditions, terms_conditions: receiptTermsConditions,
pdf_template_id: saleReceiptState?.pdfTemplateId,
}), }),
}; };
// Handle the form submit. // Handle the form submit.

View File

@@ -13,11 +13,20 @@ import {
useItems, useItems,
useCreateReceipt, useCreateReceipt,
useEditReceipt, useEditReceipt,
useGetReceiptState,
IGetReceiptStateResponse,
} from '@/hooks/query'; } from '@/hooks/query';
import { useProjects } from '@/containers/Projects/hooks'; import { useProjects } from '@/containers/Projects/hooks';
import { useGetPdfTemplates } from '@/hooks/query/pdf-templates'; import { useGetPdfTemplates } from '@/hooks/query/pdf-templates';
const ReceiptFormContext = createContext(); const ReceiptFormContext = createContext<ReceiptFormProviderValue>(
{} as ReceiptFormProviderValue,
);
interface ReceiptFormProviderValue {
isSaleReceiptStateLoading: boolean;
saleReceiptState: IGetReceiptStateResponse;
}
/** /**
* Receipt form provider. * Receipt form provider.
@@ -96,6 +105,10 @@ function ReceiptFormProvider({ receiptId, ...props }) {
const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } = const { data: brandingTemplates, isLoading: isBrandingTemplatesLoading } =
useGetPdfTemplates({ resource: 'SaleReceipt' }); useGetPdfTemplates({ resource: 'SaleReceipt' });
// Fetches the sale receipt state.
const { data: saleReceiptState, isLoading: isSaleReceiptStateLoading } =
useGetReceiptState();
// Fetch receipt settings. // Fetch receipt settings.
const { isLoading: isSettingLoading } = useSettingsReceipts(); const { isLoading: isSettingLoading } = useSettingsReceipts();
@@ -137,6 +150,10 @@ function ReceiptFormProvider({ receiptId, ...props }) {
// Branding templates // Branding templates
brandingTemplates, brandingTemplates,
isBrandingTemplatesLoading, isBrandingTemplatesLoading,
// State
isSaleReceiptStateLoading,
saleReceiptState,
}; };
const isLoading = const isLoading =
isReceiptLoading || isReceiptLoading ||
@@ -144,7 +161,8 @@ function ReceiptFormProvider({ receiptId, ...props }) {
isCustomersLoading || isCustomersLoading ||
isItemsLoading || isItemsLoading ||
isSettingLoading || isSettingLoading ||
isBrandingTemplatesLoading; isBrandingTemplatesLoading ||
isSaleReceiptStateLoading;
return ( return (
<DashboardInsider loading={isLoading} name={'receipt-form'}> <DashboardInsider loading={isLoading} name={'receipt-form'}>
@@ -153,6 +171,7 @@ function ReceiptFormProvider({ receiptId, ...props }) {
); );
} }
const useReceiptFormContext = () => React.useContext(ReceiptFormContext); const useReceiptFormContext = () =>
React.useContext<ReceiptFormProviderValue>(ReceiptFormContext);
export { ReceiptFormProvider, useReceiptFormContext }; export { ReceiptFormProvider, useReceiptFormContext };

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types'; import t from './types';
@@ -356,3 +356,21 @@ export function useRefundCreditTransaction(id, props, requestProps) {
export function usePdfCreditNote(creditNoteId) { export function usePdfCreditNote(creditNoteId) {
return useRequestPdf({ url: `sales/credit_notes/${creditNoteId}` }); return useRequestPdf({ url: `sales/credit_notes/${creditNoteId}` });
} }
export interface CreditNoteStateResponse {
defaultTemplateId: number;
}
export function useGetCreditNoteState(
options?: UseQueryOptions<CreditNoteStateResponse, Error>,
): UseQueryResult<CreditNoteStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<CreditNoteStateResponse, Error>(
['CREDIT_NOTE_STATE'],
() =>
apiRequest
.get('/sales/credit_notes/state')
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -2,7 +2,7 @@
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import t from './types'; import t from './types';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
@@ -270,3 +270,22 @@ export function useSaleEstimateDefaultOptions(estimateId, props) {
}, },
); );
} }
export interface ISaleEstimatesStateResponse {
defaultTemplateId: number;
}
export function useGetSaleEstimatesState(
options?: UseQueryOptions<ISaleEstimatesStateResponse, Error>,
): UseQueryResult<ISaleEstimatesStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<ISaleEstimatesStateResponse, Error>(
['SALE_ESTIMATES_STATE'],
() =>
apiRequest
.get('/sales/estimates/state')
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -1,7 +1,7 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import { useQueryClient, useMutation, useQuery } from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import { transformPagination } from '@/utils'; import { transformPagination, transformToCamelCase } from '@/utils';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types'; import t from './types';
@@ -341,3 +341,22 @@ export function useSaleInvoiceDefaultOptions(invoiceId, props) {
}, },
); );
} }
export interface GetSaleInvoiceStateResponse {
defaultTemplateId: number;
}
export function useGetSaleInvoiceState(
options?: UseQueryOptions<GetSaleInvoiceStateResponse, Error>,
): UseQueryResult<GetSaleInvoiceStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<GetSaleInvoiceStateResponse, Error>(
['SALE_INVOICE_STATE'],
() =>
apiRequest
.get(`/sales/invoices/state`)
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}

View File

@@ -1,11 +1,17 @@
// @ts-nocheck // @ts-nocheck
import { useMutation, useQueryClient } from 'react-query'; import {
import { useRequestQuery } from '../useQueryRequest'; useMutation,
useQueryClient,
QueryClient,
UseQueryOptions,
UseQueryResult,
useQuery,
} from 'react-query';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { useRequestQuery } from '../useQueryRequest';
import { transformPagination, saveInvoke } from '@/utils'; import { transformPagination, saveInvoke } from '@/utils';
import t from './types';
import { useRequestPdf } from '../useRequestPdf'; import { useRequestPdf } from '../useRequestPdf';
import t from './types';
// Common invalidate queries. // Common invalidate queries.
const commonInvalidateQueries = (client) => { const commonInvalidateQueries = (client) => {
@@ -269,3 +275,31 @@ export function usePaymentReceiveDefaultOptions(paymentReceiveId, props) {
}, },
); );
} }
export interface PaymentReceivedStateResponse {
defaultTemplateId: number;
}
/**
* Retrieves the payment receive state.
* @param {Record<string, any>} query - Query parameters for the request.
* @param {UseQueryOptions<PaymentReceivedStateResponse, Error>} options - Optional query options.
* @returns {UseQueryResult<PaymentReceivedStateResponse, Error>} The query result.
*/
export function usePaymentReceivedState(
query: Record<string, any>,
options?: UseQueryOptions<PaymentReceivedStateResponse, Error>,
): UseQueryResult<PaymentReceivedStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<PaymentReceivedStateResponse, Error>(
[t.PAYMENT_RECEIVE_STATE, query],
() =>
apiRequest
.get('/sales/payment_receives/state', { params: query })
.then((res) => res.data),
{
...options,
},
);
}

View File

@@ -1,5 +1,11 @@
// @ts-nocheck // @ts-nocheck
import { useQueryClient, useMutation } from 'react-query'; import {
useQueryClient,
useMutation,
UseQueryResult,
UseQueryOptions,
useQuery,
} from 'react-query';
import { useRequestQuery } from '../useQueryRequest'; import { useRequestQuery } from '../useQueryRequest';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
import { transformPagination } from '@/utils'; import { transformPagination } from '@/utils';
@@ -244,3 +250,22 @@ export function useSaleReceiptDefaultOptions(invoiceId, props) {
}, },
); );
} }
export interface IGetReceiptStateResponse {
pdfTemplateId: number;
}
export function useGetReceiptState(
options?: UseQueryOptions<IGetReceiptStateResponse, Error>,
): UseQueryResult<IGetReceiptStateResponse, Error> {
const apiRequest = useApiRequest();
return useQuery<IGetReceiptStateResponse, Error>(
['SALE_RECEIPT_STATE'],
() =>
apiRequest
.get(`/sales/receipts/state`)
.then((res) => transformToCamelCase(res.data?.data)),
{ ...options },
);
}