mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af80afcf59 | ||
|
|
66cb0521e5 | ||
|
|
9204b76346 | ||
|
|
36cbb1eef5 | ||
|
|
441e27581b | ||
|
|
e0d9a56a29 | ||
|
|
5a017104ce | ||
|
|
25ca620836 | ||
|
|
5a3655e093 | ||
|
|
49c2777587 | ||
|
|
a5680c08c2 | ||
|
|
d909dad1bf | ||
|
|
f32cc752ef | ||
|
|
a7f98201cc | ||
|
|
a1d0fc3f0a | ||
|
|
11575cfb96 |
@@ -6,4 +6,5 @@ export default registerAs('s3', () => ({
|
|||||||
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
|
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
|
||||||
endpoint: process.env.S3_ENDPOINT,
|
endpoint: process.env.S3_ENDPOINT,
|
||||||
bucket: process.env.S3_BUCKET,
|
bucket: process.env.S3_BUCKET,
|
||||||
|
forcePathStyle: process.env.S3_FORCE_PATH_STYLE === 'true',
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { ToNumber } from '@/common/decorators/Validators';
|
|||||||
|
|
||||||
class BankRuleConditionDto {
|
class BankRuleConditionDto {
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsIn(['description', 'amount'])
|
@IsIn(['description', 'amount', 'payee'])
|
||||||
field: string;
|
field: string;
|
||||||
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
|||||||
@@ -15,8 +15,13 @@ export const RecognizeUncategorizedTransactionsJob =
|
|||||||
export const RecognizeUncategorizedTransactionsQueue =
|
export const RecognizeUncategorizedTransactionsQueue =
|
||||||
'recognize-uncategorized-transactions-queue';
|
'recognize-uncategorized-transactions-queue';
|
||||||
|
|
||||||
|
|
||||||
export interface RecognizeUncategorizedTransactionsJobPayload extends TenantJobPayload {
|
export interface RecognizeUncategorizedTransactionsJobPayload extends TenantJobPayload {
|
||||||
ruleId: number,
|
ruleId: number,
|
||||||
transactionsCriteria: any;
|
transactionsCriteria?: RecognizeTransactionsCriteria;
|
||||||
|
/**
|
||||||
|
* When true, first reverts recognized transactions before recognizing again.
|
||||||
|
* Used when a bank rule is edited to ensure transactions previously recognized
|
||||||
|
* by lower-priority rules are re-evaluated against the updated rule.
|
||||||
|
*/
|
||||||
|
shouldRevert?: boolean;
|
||||||
}
|
}
|
||||||
@@ -93,6 +93,10 @@ export class RecognizeTranasctionsService {
|
|||||||
q.whereIn('id', rulesIds);
|
q.whereIn('id', rulesIds);
|
||||||
}
|
}
|
||||||
q.withGraphFetched('conditions');
|
q.withGraphFetched('conditions');
|
||||||
|
|
||||||
|
// Order by the 'order' field to ensure higher priority rules (lower order values)
|
||||||
|
// are matched first.
|
||||||
|
q.orderBy('order', 'asc');
|
||||||
});
|
});
|
||||||
|
|
||||||
const bankRulesByAccountId = transformToMapBy(
|
const bankRulesByAccountId = transformToMapBy(
|
||||||
|
|||||||
@@ -69,10 +69,13 @@ export class TriggerRecognizedTransactionsSubscriber {
|
|||||||
const tenantPayload = await this.tenancyContect.getTenantJobPayload();
|
const tenantPayload = await this.tenancyContect.getTenantJobPayload();
|
||||||
const payload = {
|
const payload = {
|
||||||
ruleId: bankRule.id,
|
ruleId: bankRule.id,
|
||||||
|
shouldRevert: true,
|
||||||
...tenantPayload,
|
...tenantPayload,
|
||||||
} as RecognizeUncategorizedTransactionsJobPayload;
|
} as RecognizeUncategorizedTransactionsJobPayload;
|
||||||
|
|
||||||
// Re-recognize the transactions based on the new rules.
|
// Re-recognize the transactions based on the new rules.
|
||||||
|
// Setting shouldRevert to true ensures that transactions previously recognized
|
||||||
|
// by this or lower-priority rules are re-evaluated against the updated rule.
|
||||||
await this.recognizeTransactionsQueue.add(
|
await this.recognizeTransactionsQueue.add(
|
||||||
RecognizeUncategorizedTransactionsJob,
|
RecognizeUncategorizedTransactionsJob,
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Processor, WorkerHost } from '@nestjs/bullmq';
|
|||||||
import { Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { ClsService, UseCls } from 'nestjs-cls';
|
import { ClsService, UseCls } from 'nestjs-cls';
|
||||||
import { RecognizeTranasctionsService } from '../commands/RecognizeTranasctions.service';
|
import { RecognizeTranasctionsService } from '../commands/RecognizeTranasctions.service';
|
||||||
|
import { RevertRecognizedTransactionsService } from '../commands/RevertRecognizedTransactions.service';
|
||||||
import {
|
import {
|
||||||
RecognizeUncategorizedTransactionsJobPayload,
|
RecognizeUncategorizedTransactionsJobPayload,
|
||||||
RecognizeUncategorizedTransactionsQueue,
|
RecognizeUncategorizedTransactionsQueue,
|
||||||
@@ -15,10 +16,12 @@ import {
|
|||||||
export class RegonizeTransactionsPrcessor extends WorkerHost {
|
export class RegonizeTransactionsPrcessor extends WorkerHost {
|
||||||
/**
|
/**
|
||||||
* @param {RecognizeTranasctionsService} recognizeTranasctionsService -
|
* @param {RecognizeTranasctionsService} recognizeTranasctionsService -
|
||||||
|
* @param {RevertRecognizedTransactionsService} revertRecognizedTransactionsService -
|
||||||
* @param {ClsService} clsService -
|
* @param {ClsService} clsService -
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private readonly recognizeTranasctionsService: RecognizeTranasctionsService,
|
private readonly recognizeTranasctionsService: RecognizeTranasctionsService,
|
||||||
|
private readonly revertRecognizedTransactionsService: RevertRecognizedTransactionsService,
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
@@ -29,12 +32,21 @@ export class RegonizeTransactionsPrcessor extends WorkerHost {
|
|||||||
*/
|
*/
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async process(job: Job<RecognizeUncategorizedTransactionsJobPayload>) {
|
async process(job: Job<RecognizeUncategorizedTransactionsJobPayload>) {
|
||||||
const { ruleId, transactionsCriteria } = job.data;
|
const { ruleId, transactionsCriteria, shouldRevert } = job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', job.data.organizationId);
|
this.clsService.set('organizationId', job.data.organizationId);
|
||||||
this.clsService.set('userId', job.data.userId);
|
this.clsService.set('userId', job.data.userId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// If shouldRevert is true, first revert recognized transactions before re-recognizing.
|
||||||
|
// This is used when a bank rule is edited to ensure transactions previously recognized
|
||||||
|
// by lower-priority rules are re-evaluated against the updated rule.
|
||||||
|
if (shouldRevert) {
|
||||||
|
await this.revertRecognizedTransactionsService.revertRecognizedTransactions(
|
||||||
|
ruleId,
|
||||||
|
transactionsCriteria,
|
||||||
|
);
|
||||||
|
}
|
||||||
await this.recognizeTranasctionsService.recognizeTransactions(
|
await this.recognizeTranasctionsService.recognizeTransactions(
|
||||||
ruleId,
|
ruleId,
|
||||||
transactionsCriteria,
|
transactionsCriteria,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { BullBoardModule } from '@bull-board/nestjs';
|
import { BullBoardModule } from '@bull-board/nestjs';
|
||||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||||
import { BullModule } from '@nestjs/bull';
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
import { PaymentReceivesController } from './PaymentsReceived.controller';
|
import { PaymentReceivesController } from './PaymentsReceived.controller';
|
||||||
import { PaymentReceivesApplication } from './PaymentReceived.application';
|
import { PaymentReceivesApplication } from './PaymentReceived.application';
|
||||||
import { CreatePaymentReceivedService } from './commands/CreatePaymentReceived.serivce';
|
import { CreatePaymentReceivedService } from './commands/CreatePaymentReceived.serivce';
|
||||||
@@ -99,7 +99,7 @@ import { ValidateBulkDeletePaymentReceivedService } from './ValidateBulkDeletePa
|
|||||||
BullModule.registerQueue({ name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE }),
|
BullModule.registerQueue({ name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE }),
|
||||||
BullBoardModule.forFeature({
|
BullBoardModule.forFeature({
|
||||||
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
||||||
adapter: BullAdapter,
|
adapter: BullMQAdapter,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||||
import { Job } from 'bull';
|
import { Job } from 'bullmq';
|
||||||
import { Inject, Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { ClsService, UseCls } from 'nestjs-cls';
|
import { ClsService, UseCls } from 'nestjs-cls';
|
||||||
import {
|
import {
|
||||||
SEND_PAYMENT_RECEIVED_MAIL_JOB,
|
SEND_PAYMENT_RECEIVED_MAIL_JOB,
|
||||||
@@ -13,20 +13,18 @@ import { SendPaymentReceivedMailPayload } from '../types/PaymentReceived.types';
|
|||||||
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
name: SEND_PAYMENT_RECEIVED_MAIL_QUEUE,
|
||||||
scope: Scope.REQUEST,
|
scope: Scope.REQUEST,
|
||||||
})
|
})
|
||||||
export class SendPaymentReceivedMailProcessor {
|
export class SendPaymentReceivedMailProcessor extends WorkerHost {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sendPaymentReceivedMail: SendPaymentReceiveMailNotification,
|
private readonly sendPaymentReceivedMail: SendPaymentReceiveMailNotification,
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(JOB_REF)
|
|
||||||
private readonly jobRef: Job<SendPaymentReceivedMailPayload>,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
@Process(SEND_PAYMENT_RECEIVED_MAIL_JOB)
|
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async handleSendMail() {
|
async process(job: Job<SendPaymentReceivedMailPayload>) {
|
||||||
const { messageOptions, paymentReceivedId, organizationId, userId } =
|
const { messageOptions, paymentReceivedId, organizationId, userId } =
|
||||||
this.jobRef.data;
|
job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', organizationId);
|
this.clsService.set('organizationId', organizationId);
|
||||||
this.clsService.set('userId', userId);
|
this.clsService.set('userId', userId);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { BullBoardModule } from '@bull-board/nestjs';
|
import { BullBoardModule } from '@bull-board/nestjs';
|
||||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||||
import { BullModule } from '@nestjs/bull';
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||||
import { TenancyDatabaseModule } from '../Tenancy/TenancyDB/TenancyDB.module';
|
import { TenancyDatabaseModule } from '../Tenancy/TenancyDB/TenancyDB.module';
|
||||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||||
@@ -58,7 +58,7 @@ import { SendSaleEstimateMailProcess } from './processes/SendSaleEstimateMail.pr
|
|||||||
BullModule.registerQueue({ name: SendSaleEstimateMailQueue }),
|
BullModule.registerQueue({ name: SendSaleEstimateMailQueue }),
|
||||||
BullBoardModule.forFeature({
|
BullBoardModule.forFeature({
|
||||||
name: SendSaleEstimateMailQueue,
|
name: SendSaleEstimateMailQueue,
|
||||||
adapter: BullAdapter,
|
adapter: BullMQAdapter,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
controllers: [SaleEstimatesController],
|
controllers: [SaleEstimatesController],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { InjectQueue } from '@nestjs/bullmq';
|
import { InjectQueue } from '@nestjs/bullmq';
|
||||||
import { Queue } from 'bull';
|
import { Queue } from 'bullmq';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { ContactMailNotification } from '@/modules/MailNotification/ContactMailNotification';
|
import { ContactMailNotification } from '@/modules/MailNotification/ContactMailNotification';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Process, Processor } from '@nestjs/bull';
|
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||||
import { Job } from 'bull';
|
import { Job } from 'bullmq';
|
||||||
import { Inject, Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { JOB_REF } from '@nestjs/bull';
|
|
||||||
import {
|
import {
|
||||||
SendSaleEstimateMailJob,
|
SendSaleEstimateMailJob,
|
||||||
SendSaleEstimateMailQueue,
|
SendSaleEstimateMailQueue,
|
||||||
@@ -13,18 +12,17 @@ import { ClsService, UseCls } from 'nestjs-cls';
|
|||||||
name: SendSaleEstimateMailQueue,
|
name: SendSaleEstimateMailQueue,
|
||||||
scope: Scope.REQUEST,
|
scope: Scope.REQUEST,
|
||||||
})
|
})
|
||||||
export class SendSaleEstimateMailProcess {
|
export class SendSaleEstimateMailProcess extends WorkerHost {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sendEstimateMailService: SendSaleEstimateMail,
|
private readonly sendEstimateMailService: SendSaleEstimateMail,
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
@Inject(JOB_REF)
|
) {
|
||||||
private readonly jobRef: Job,
|
super();
|
||||||
) { }
|
}
|
||||||
|
|
||||||
@Process(SendSaleEstimateMailJob)
|
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async handleSendMail() {
|
async process(job: Job) {
|
||||||
const { saleEstimateId, messageOptions, organizationId, userId } = this.jobRef.data;
|
const { saleEstimateId, messageOptions, organizationId, userId } = job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', organizationId);
|
this.clsService.set('organizationId', organizationId);
|
||||||
this.clsService.set('userId', userId);
|
this.clsService.set('userId', userId);
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
|||||||
import { MailNotificationModule } from '../MailNotification/MailNotification.module';
|
import { MailNotificationModule } from '../MailNotification/MailNotification.module';
|
||||||
import { SendSaleInvoiceMailProcessor } from './processors/SendSaleInvoiceMail.processor';
|
import { SendSaleInvoiceMailProcessor } from './processors/SendSaleInvoiceMail.processor';
|
||||||
import { BullBoardModule } from '@bull-board/nestjs';
|
import { BullBoardModule } from '@bull-board/nestjs';
|
||||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||||
import { BullModule } from '@nestjs/bull';
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
import { SendSaleInvoiceQueue } from './constants';
|
import { SendSaleInvoiceQueue } from './constants';
|
||||||
import { InvoicePaymentIntegrationSubscriber } from './subscribers/InvoicePaymentIntegrationSubscriber';
|
import { InvoicePaymentIntegrationSubscriber } from './subscribers/InvoicePaymentIntegrationSubscriber';
|
||||||
import { InvoiceChangeStatusOnMailSentSubscriber } from './subscribers/InvoiceChangeStatusOnMailSentSubscriber';
|
import { InvoiceChangeStatusOnMailSentSubscriber } from './subscribers/InvoiceChangeStatusOnMailSentSubscriber';
|
||||||
@@ -85,7 +85,7 @@ import { ValidateBulkDeleteSaleInvoicesService } from './ValidateBulkDeleteSaleI
|
|||||||
BullModule.registerQueue({ name: SendSaleInvoiceQueue }),
|
BullModule.registerQueue({ name: SendSaleInvoiceQueue }),
|
||||||
BullBoardModule.forFeature({
|
BullBoardModule.forFeature({
|
||||||
name: SendSaleInvoiceQueue,
|
name: SendSaleInvoiceQueue,
|
||||||
adapter: BullAdapter,
|
adapter: BullMQAdapter,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
controllers: [SaleInvoicesController],
|
controllers: [SaleInvoicesController],
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||||
import { Job } from 'bull';
|
import { Job } from 'bullmq';
|
||||||
import { SendSaleInvoiceMailJob, SendSaleInvoiceQueue } from '../constants';
|
import { SendSaleInvoiceMailJob, SendSaleInvoiceQueue } from '../constants';
|
||||||
import { SendSaleInvoiceMail } from '../commands/SendSaleInvoiceMail';
|
import { SendSaleInvoiceMail } from '../commands/SendSaleInvoiceMail';
|
||||||
import { Inject, Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { REQUEST } from '@nestjs/core';
|
|
||||||
import { ClsService, UseCls } from 'nestjs-cls';
|
import { ClsService, UseCls } from 'nestjs-cls';
|
||||||
import { SendSaleInvoiceMailJobPayload } from '../SaleInvoice.types';
|
import { SendSaleInvoiceMailJobPayload } from '../SaleInvoice.types';
|
||||||
|
|
||||||
@@ -11,20 +10,18 @@ import { SendSaleInvoiceMailJobPayload } from '../SaleInvoice.types';
|
|||||||
name: SendSaleInvoiceQueue,
|
name: SendSaleInvoiceQueue,
|
||||||
scope: Scope.REQUEST,
|
scope: Scope.REQUEST,
|
||||||
})
|
})
|
||||||
export class SendSaleInvoiceMailProcessor {
|
export class SendSaleInvoiceMailProcessor extends WorkerHost {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sendSaleInvoiceMail: SendSaleInvoiceMail,
|
private readonly sendSaleInvoiceMail: SendSaleInvoiceMail,
|
||||||
@Inject(REQUEST) private readonly request: Request,
|
|
||||||
@Inject(JOB_REF)
|
|
||||||
private readonly jobRef: Job<SendSaleInvoiceMailJobPayload>,
|
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
) { }
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Process(SendSaleInvoiceMailJob)
|
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async handleSendInvoice() {
|
async process(job: Job<SendSaleInvoiceMailJobPayload>) {
|
||||||
const { messageOptions, saleInvoiceId, organizationId, userId } =
|
const { messageOptions, saleInvoiceId, organizationId, userId } =
|
||||||
this.jobRef.data;
|
job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', organizationId);
|
this.clsService.set('organizationId', organizationId);
|
||||||
this.clsService.set('userId', userId);
|
this.clsService.set('userId', userId);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { BullBoardModule } from '@bull-board/nestjs';
|
import { BullBoardModule } from '@bull-board/nestjs';
|
||||||
import { BullAdapter } from '@bull-board/api/bullAdapter';
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||||
import { BullModule } from '@nestjs/bull';
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
import { SaleReceiptApplication } from './SaleReceiptApplication.service';
|
import { SaleReceiptApplication } from './SaleReceiptApplication.service';
|
||||||
import { CreateSaleReceipt } from './commands/CreateSaleReceipt.service';
|
import { CreateSaleReceipt } from './commands/CreateSaleReceipt.service';
|
||||||
import { EditSaleReceipt } from './commands/EditSaleReceipt.service';
|
import { EditSaleReceipt } from './commands/EditSaleReceipt.service';
|
||||||
@@ -66,7 +66,7 @@ import { ValidateBulkDeleteSaleReceiptsService } from './ValidateBulkDeleteSaleR
|
|||||||
BullModule.registerQueue({ name: SendSaleReceiptMailQueue }),
|
BullModule.registerQueue({ name: SendSaleReceiptMailQueue }),
|
||||||
BullBoardModule.forFeature({
|
BullBoardModule.forFeature({
|
||||||
name: SendSaleReceiptMailQueue,
|
name: SendSaleReceiptMailQueue,
|
||||||
adapter: BullAdapter,
|
adapter: BullMQAdapter,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { InjectQueue } from '@nestjs/bull';
|
import { InjectQueue } from '@nestjs/bullmq';
|
||||||
import { Queue } from 'bullmq';
|
import { Queue } from 'bullmq';
|
||||||
import {
|
import {
|
||||||
DEFAULT_RECEIPT_MAIL_CONTENT,
|
DEFAULT_RECEIPT_MAIL_CONTENT,
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
import { Process, Processor } from '@nestjs/bull';
|
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||||
import { Job } from 'bull';
|
import { Job } from 'bullmq';
|
||||||
import { Inject, Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { JOB_REF } from '@nestjs/bull';
|
|
||||||
import { SendSaleReceiptMailQueue, SendSaleReceiptMailJob } from '../constants';
|
import { SendSaleReceiptMailQueue, SendSaleReceiptMailJob } from '../constants';
|
||||||
import { SaleReceiptMailNotification } from '../commands/SaleReceiptMailNotification';
|
import { SaleReceiptMailNotification } from '../commands/SaleReceiptMailNotification';
|
||||||
import { SaleReceiptSendMailPayload } from '../types/SaleReceipts.types';
|
|
||||||
import { ClsService, UseCls } from 'nestjs-cls';
|
import { ClsService, UseCls } from 'nestjs-cls';
|
||||||
|
|
||||||
@Processor({
|
@Processor({
|
||||||
name: SendSaleReceiptMailQueue,
|
name: SendSaleReceiptMailQueue,
|
||||||
scope: Scope.REQUEST,
|
scope: Scope.REQUEST,
|
||||||
})
|
})
|
||||||
export class SendSaleReceiptMailProcess {
|
export class SendSaleReceiptMailProcess extends WorkerHost {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly saleReceiptMailNotification: SaleReceiptMailNotification,
|
private readonly saleReceiptMailNotification: SaleReceiptMailNotification,
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Inject(JOB_REF)
|
|
||||||
private readonly jobRef: Job<SaleReceiptSendMailPayload>,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
@Process(SendSaleReceiptMailJob)
|
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async handleSendMailJob() {
|
async process(job: Job) {
|
||||||
const { messageOpts, saleReceiptId, organizationId, userId } =
|
const { messageOpts, saleReceiptId, organizationId, userId } =
|
||||||
this.jobRef.data;
|
job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', organizationId);
|
this.clsService.set('organizationId', organizationId);
|
||||||
this.clsService.set('userId', userId);
|
this.clsService.set('userId', userId);
|
||||||
|
|||||||
@@ -62,10 +62,11 @@ export class TaxRatesApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the tax rates list.
|
* Retrieves the tax rates list.
|
||||||
* @returns {Promise<ITaxRate[]>}
|
* @returns {Promise<{ data: ITaxRate[] }>}
|
||||||
*/
|
*/
|
||||||
public getTaxRates() {
|
public async getTaxRates() {
|
||||||
return this.getTaxRatesService.getTaxRates();
|
const taxRates = await this.getTaxRatesService.getTaxRates();
|
||||||
|
return { data: taxRates };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -85,9 +85,14 @@ export class TaxRatesController {
|
|||||||
status: 200,
|
status: 200,
|
||||||
description: 'The tax rates have been successfully retrieved.',
|
description: 'The tax rates have been successfully retrieved.',
|
||||||
schema: {
|
schema: {
|
||||||
type: 'array',
|
type: 'object',
|
||||||
items: {
|
properties: {
|
||||||
$ref: getSchemaPath(TaxRateResponseDto),
|
data: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
$ref: getSchemaPath(TaxRateResponseDto),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { ToNumber } from '@/common/decorators/Validators';
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import {
|
import {
|
||||||
@@ -30,6 +31,7 @@ export class CommandTaxRateDto {
|
|||||||
*/
|
*/
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
@ToNumber()
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
description: 'The rate of the tax rate.',
|
description: 'The rate of the tax rate.',
|
||||||
example: 10,
|
example: 10,
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { BullModule } from '@nestjs/bullmq';
|
||||||
|
import { BullBoardModule } from '@bull-board/nestjs';
|
||||||
|
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
||||||
import { ActivateUserService } from './commands/ActivateUser.service';
|
import { ActivateUserService } from './commands/ActivateUser.service';
|
||||||
import { DeleteUserService } from './commands/DeleteUser.service';
|
import { DeleteUserService } from './commands/DeleteUser.service';
|
||||||
import { EditUserService } from './commands/EditUser.service';
|
import { EditUserService } from './commands/EditUser.service';
|
||||||
@@ -18,11 +21,24 @@ import { AcceptInviteUserService } from './commands/AcceptInviteUser.service';
|
|||||||
import { InviteTenantUserService } from './commands/InviteUser.service';
|
import { InviteTenantUserService } from './commands/InviteUser.service';
|
||||||
import { UsersInviteController } from './UsersInvite.controller';
|
import { UsersInviteController } from './UsersInvite.controller';
|
||||||
import { InjectSystemModel } from '../System/SystemModels/SystemModels.module';
|
import { InjectSystemModel } from '../System/SystemModels/SystemModels.module';
|
||||||
|
import { SendInviteUserMailQueue } from './Users.constants';
|
||||||
|
import InviteSendMainNotificationSubscribe from './subscribers/InviteSendMailNotification.subscriber';
|
||||||
|
import { SendInviteUserMailProcessor } from './processors/SendInviteUserMail.processor';
|
||||||
|
import { SendInviteUsersMailMessage } from './commands/SendInviteUsersMailMessage.service';
|
||||||
|
import { MailModule } from '../Mail/Mail.module';
|
||||||
|
|
||||||
const models = [InjectSystemModel(UserInvite)];
|
const models = [InjectSystemModel(UserInvite)];
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [TenancyModule],
|
imports: [
|
||||||
|
TenancyModule,
|
||||||
|
MailModule,
|
||||||
|
BullModule.registerQueue({ name: SendInviteUserMailQueue }),
|
||||||
|
BullBoardModule.forFeature({
|
||||||
|
name: SendInviteUserMailQueue,
|
||||||
|
adapter: BullMQAdapter,
|
||||||
|
}),
|
||||||
|
],
|
||||||
exports: [...models],
|
exports: [...models],
|
||||||
providers: [
|
providers: [
|
||||||
...models,
|
...models,
|
||||||
@@ -39,6 +55,9 @@ const models = [InjectSystemModel(UserInvite)];
|
|||||||
SyncTenantUserMutateSubscriber,
|
SyncTenantUserMutateSubscriber,
|
||||||
SyncSystemSendInviteSubscriber,
|
SyncSystemSendInviteSubscriber,
|
||||||
SyncTenantAcceptInviteSubscriber,
|
SyncTenantAcceptInviteSubscriber,
|
||||||
|
InviteSendMainNotificationSubscribe,
|
||||||
|
SendInviteUserMailProcessor,
|
||||||
|
SendInviteUsersMailMessage,
|
||||||
UsersApplication
|
UsersApplication
|
||||||
],
|
],
|
||||||
controllers: [UsersController, UsersInviteController],
|
controllers: [UsersController, UsersInviteController],
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ export interface ITenantUserDeletedPayload {
|
|||||||
export interface IUserInvitedEventPayload {
|
export interface IUserInvitedEventPayload {
|
||||||
inviteToken: string;
|
inviteToken: string;
|
||||||
user: ModelObject<TenantUser>;
|
user: ModelObject<TenantUser>;
|
||||||
|
invitingUser: ModelObject<TenantUser>;
|
||||||
}
|
}
|
||||||
export interface IUserInviteTenantSyncedEventPayload {
|
export interface IUserInviteTenantSyncedEventPayload {
|
||||||
invite: ModelObject<UserInvite>;
|
invite: ModelObject<UserInvite>;
|
||||||
user: ModelObject<TenantUser>;
|
user: ModelObject<TenantUser>;
|
||||||
|
invitingUser: ModelObject<TenantUser>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserInviteResendEventPayload {
|
export interface IUserInviteResendEventPayload {
|
||||||
|
|||||||
@@ -15,11 +15,13 @@ import { events } from '@/common/events/events';
|
|||||||
import { Role } from '@/modules/Roles/models/Role.model';
|
import { Role } from '@/modules/Roles/models/Role.model';
|
||||||
import { ModelObject } from 'objection';
|
import { ModelObject } from 'objection';
|
||||||
import { SendInviteUserDto } from '../dtos/InviteUser.dto';
|
import { SendInviteUserDto } from '../dtos/InviteUser.dto';
|
||||||
|
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InviteTenantUserService {
|
export class InviteTenantUserService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly eventEmitter: EventEmitter2,
|
private readonly eventEmitter: EventEmitter2,
|
||||||
|
private readonly tenancyContext: TenancyContext,
|
||||||
|
|
||||||
@Inject(TenantUser.name)
|
@Inject(TenantUser.name)
|
||||||
private readonly tenantUserModel: TenantModelProxy<typeof TenantUser>,
|
private readonly tenantUserModel: TenantModelProxy<typeof TenantUser>,
|
||||||
@@ -53,10 +55,18 @@ export class InviteTenantUserService {
|
|||||||
active: true,
|
active: true,
|
||||||
invitedAt: new Date(),
|
invitedAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Retrieves the authorized user (inviting user).
|
||||||
|
const authorizedUser = await this.tenancyContext.getSystemUser();
|
||||||
|
const invitingUser = await this.tenantUserModel()
|
||||||
|
.query()
|
||||||
|
.findOne({ systemUserId: authorizedUser.id });
|
||||||
|
|
||||||
// Triggers `onUserSendInvite` event.
|
// Triggers `onUserSendInvite` event.
|
||||||
await this.eventEmitter.emitAsync(events.inviteUser.sendInvite, {
|
await this.eventEmitter.emitAsync(events.inviteUser.sendInvite, {
|
||||||
inviteToken,
|
inviteToken,
|
||||||
user,
|
user,
|
||||||
|
invitingUser,
|
||||||
} as IUserInvitedEventPayload);
|
} as IUserInvitedEventPayload);
|
||||||
|
|
||||||
return { invitedUser: user };
|
return { invitedUser: user };
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export class SendInviteUsersMailMessage {
|
|||||||
invite: ModelObject<UserInvite>,
|
invite: ModelObject<UserInvite>,
|
||||||
) {
|
) {
|
||||||
const tenant = await this.tenancyContext.getTenant(true);
|
const tenant = await this.tenancyContext.getTenant(true);
|
||||||
const root = path.join(global.__views_dir, '/images/bigcapital.png');
|
const root = path.join(global.__images_dirname, '/bigcapital.png');
|
||||||
const baseURL = this.configService.get('baseURL');
|
const baseURL = this.configService.get('baseURL');
|
||||||
|
|
||||||
const mail = new Mail()
|
const mail = new Mail()
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { JOB_REF, Process, Processor } from '@nestjs/bull';
|
import { Processor, WorkerHost } from '@nestjs/bullmq';
|
||||||
import { Job } from 'bull';
|
import { Job } from 'bullmq';
|
||||||
import { Inject, Scope } from '@nestjs/common';
|
import { Scope } from '@nestjs/common';
|
||||||
import { REQUEST } from '@nestjs/core';
|
|
||||||
import { ClsService, UseCls } from 'nestjs-cls';
|
import { ClsService, UseCls } from 'nestjs-cls';
|
||||||
import {
|
import {
|
||||||
SendInviteUserMailJob,
|
SendInviteUserMailJob,
|
||||||
@@ -14,19 +13,17 @@ import { SendInviteUsersMailMessage } from '../commands/SendInviteUsersMailMessa
|
|||||||
name: SendInviteUserMailQueue,
|
name: SendInviteUserMailQueue,
|
||||||
scope: Scope.REQUEST,
|
scope: Scope.REQUEST,
|
||||||
})
|
})
|
||||||
export class SendInviteUserMailProcessor {
|
export class SendInviteUserMailProcessor extends WorkerHost {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly sendInviteUsersMailService: SendInviteUsersMailMessage,
|
private readonly sendInviteUsersMailService: SendInviteUsersMailMessage,
|
||||||
@Inject(REQUEST) private readonly request: Request,
|
|
||||||
@Inject(JOB_REF)
|
|
||||||
private readonly jobRef: Job<SendInviteUserMailJobPayload>,
|
|
||||||
private readonly clsService: ClsService,
|
private readonly clsService: ClsService,
|
||||||
) { }
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
@Process(SendInviteUserMailJob)
|
|
||||||
@UseCls()
|
@UseCls()
|
||||||
async handleSendInviteMail() {
|
async process(job: Job<SendInviteUserMailJobPayload>) {
|
||||||
const { fromUser, invite, organizationId, userId } = this.jobRef.data;
|
const { fromUser, invite, organizationId, userId } = job.data;
|
||||||
|
|
||||||
this.clsService.set('organizationId', organizationId);
|
this.clsService.set('organizationId', organizationId);
|
||||||
this.clsService.set('userId', userId);
|
this.clsService.set('userId', userId);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { InjectQueue } from '@nestjs/bull';
|
import { InjectQueue } from '@nestjs/bullmq';
|
||||||
import { Queue } from 'bull';
|
import { Queue } from 'bullmq';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { OnEvent } from '@nestjs/event-emitter';
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
import {
|
import {
|
||||||
@@ -29,6 +29,7 @@ export default class InviteSendMainNotificationSubscribe {
|
|||||||
async sendMailNotification({
|
async sendMailNotification({
|
||||||
invite,
|
invite,
|
||||||
user,
|
user,
|
||||||
|
invitingUser,
|
||||||
}: IUserInviteTenantSyncedEventPayload) {
|
}: IUserInviteTenantSyncedEventPayload) {
|
||||||
const tenant = await this.tenancyContext.getTenant();
|
const tenant = await this.tenancyContext.getTenant();
|
||||||
const authedUser = await this.tenancyContext.getSystemUser();
|
const authedUser = await this.tenancyContext.getSystemUser();
|
||||||
@@ -37,7 +38,7 @@ export default class InviteSendMainNotificationSubscribe {
|
|||||||
const userId = authedUser.id;
|
const userId = authedUser.id;
|
||||||
|
|
||||||
this.sendInviteMailQueue.add(SendInviteUserMailJob, {
|
this.sendInviteMailQueue.add(SendInviteUserMailJob, {
|
||||||
fromUser: user,
|
fromUser: invitingUser,
|
||||||
invite,
|
invite,
|
||||||
userId,
|
userId,
|
||||||
organizationId,
|
organizationId,
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class SyncSystemSendInviteSubscriber {
|
|||||||
* @param {IUserInvitedEventPayload} payload -
|
* @param {IUserInvitedEventPayload} payload -
|
||||||
*/
|
*/
|
||||||
@OnEvent(events.inviteUser.sendInvite)
|
@OnEvent(events.inviteUser.sendInvite)
|
||||||
async syncSendInviteSystem({ inviteToken, user }: IUserInvitedEventPayload) {
|
async syncSendInviteSystem({ inviteToken, user, invitingUser }: IUserInvitedEventPayload) {
|
||||||
const authorizedUser = await this.tenancyContext.getSystemUser();
|
const authorizedUser = await this.tenancyContext.getSystemUser();
|
||||||
const tenantId = authorizedUser.tenantId;
|
const tenantId = authorizedUser.tenantId;
|
||||||
|
|
||||||
@@ -63,6 +63,7 @@ export class SyncSystemSendInviteSubscriber {
|
|||||||
{
|
{
|
||||||
invite,
|
invite,
|
||||||
user,
|
user,
|
||||||
|
invitingUser,
|
||||||
} as IUserInviteTenantSyncedEventPayload,
|
} as IUserInviteTenantSyncedEventPayload,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ const Schema = Yup.object().shape({
|
|||||||
.label(intl.get('display_name_')),
|
.label(intl.get('display_name_')),
|
||||||
|
|
||||||
email: Yup.string().email().nullable(),
|
email: Yup.string().email().nullable(),
|
||||||
work_phone: Yup.number(),
|
work_phone: Yup.string().nullable(),
|
||||||
personal_phone: Yup.number(),
|
personal_phone: Yup.string().nullable(),
|
||||||
website: Yup.string().url().nullable(),
|
website: Yup.string().url().nullable(),
|
||||||
|
|
||||||
active: Yup.boolean(),
|
active: Yup.boolean(),
|
||||||
@@ -30,7 +30,7 @@ const Schema = Yup.object().shape({
|
|||||||
billing_address_city: Yup.string().trim(),
|
billing_address_city: Yup.string().trim(),
|
||||||
billing_address_state: Yup.string().trim(),
|
billing_address_state: Yup.string().trim(),
|
||||||
billing_address_postcode: Yup.string().nullable(),
|
billing_address_postcode: Yup.string().nullable(),
|
||||||
billing_address_phone: Yup.number(),
|
billing_address_phone: Yup.string().nullable(),
|
||||||
|
|
||||||
shipping_address_country: Yup.string().trim(),
|
shipping_address_country: Yup.string().trim(),
|
||||||
shipping_address_1: Yup.string().trim(),
|
shipping_address_1: Yup.string().trim(),
|
||||||
@@ -38,7 +38,7 @@ const Schema = Yup.object().shape({
|
|||||||
shipping_address_city: Yup.string().trim(),
|
shipping_address_city: Yup.string().trim(),
|
||||||
shipping_address_state: Yup.string().trim(),
|
shipping_address_state: Yup.string().trim(),
|
||||||
shipping_address_postcode: Yup.string().nullable(),
|
shipping_address_postcode: Yup.string().nullable(),
|
||||||
shipping_address_phone: Yup.number(),
|
shipping_address_phone: Yup.string().nullable(),
|
||||||
|
|
||||||
opening_balance: Yup.number().nullable(),
|
opening_balance: Yup.number().nullable(),
|
||||||
currency_code: Yup.string(),
|
currency_code: Yup.string(),
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { useContactDetailDrawerContext } from './ContactDetailDrawerProvider';
|
|||||||
import { withAlertActions } from '@/containers/Alert/withAlertActions';
|
import { withAlertActions } from '@/containers/Alert/withAlertActions';
|
||||||
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
import { DashboardActionsBar, Icon, FormattedMessage as T } from '@/components';
|
import { DrawerActionsBar, Icon, FormattedMessage as T } from '@/components';
|
||||||
|
|
||||||
import { safeCallback, compose } from '@/utils';
|
import { safeCallback, compose } from '@/utils';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ function ContactDetailActionsBar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
@@ -63,7 +63,7 @@ function ContactDetailActionsBar({
|
|||||||
onClick={safeCallback(onDeleteContact)}
|
onClick={safeCallback(onDeleteContact)}
|
||||||
/>
|
/>
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</DashboardActionsBar>
|
</DrawerActionsBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import { withDialogActions } from '@/containers/Dialog/withDialogActions';
|
|||||||
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DashboardActionsBar,
|
|
||||||
Can,
|
Can,
|
||||||
Icon,
|
Icon,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
If,
|
If,
|
||||||
Icon,
|
Icon,
|
||||||
FormattedMessage as T,
|
FormattedMessage as T,
|
||||||
DashboardActionsBar,
|
DrawerActionsBar,
|
||||||
Can,
|
Can,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ function VendorCreditDetailActionsBar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<Can I={VendorCreditAction.Edit} a={AbilitySubject.VendorCredit}>
|
<Can I={VendorCreditAction.Edit} a={AbilitySubject.VendorCredit}>
|
||||||
<Button
|
<Button
|
||||||
@@ -105,7 +105,7 @@ function VendorCreditDetailActionsBar({
|
|||||||
</If>
|
</If>
|
||||||
</Can>
|
</Can>
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</DashboardActionsBar>
|
</DrawerActionsBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useDrawerActions } from '@/hooks/state';
|
|||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
||||||
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
||||||
|
import { Box } from '@/components';
|
||||||
|
|
||||||
export function CreditNoteCustomizeContent() {
|
export function CreditNoteCustomizeContent() {
|
||||||
const { payload, name } = useDrawerContext();
|
const { payload, name } = useDrawerContext();
|
||||||
@@ -45,7 +46,9 @@ function CreditNoteCustomizeFormContent() {
|
|||||||
return (
|
return (
|
||||||
<ElementCustomizeContent>
|
<ElementCustomizeContent>
|
||||||
<ElementCustomize.PaperTemplate>
|
<ElementCustomize.PaperTemplate>
|
||||||
<CreditNotePaperTemplateFormConnected />
|
<Box overflow="auto" flex="1 1" px={4} py={6}>
|
||||||
|
<CreditNotePaperTemplateFormConnected />
|
||||||
|
</Box>
|
||||||
</ElementCustomize.PaperTemplate>
|
</ElementCustomize.PaperTemplate>
|
||||||
|
|
||||||
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useDrawerActions } from '@/hooks/state';
|
|||||||
import { BrandingTemplateForm } from '@/containers/BrandingTemplates/BrandingTemplateForm';
|
import { BrandingTemplateForm } from '@/containers/BrandingTemplates/BrandingTemplateForm';
|
||||||
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
||||||
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
||||||
|
import { Box } from '@/components';
|
||||||
|
|
||||||
export function EstimateCustomizeContent() {
|
export function EstimateCustomizeContent() {
|
||||||
const { payload, name } = useDrawerContext();
|
const { payload, name } = useDrawerContext();
|
||||||
@@ -44,7 +45,9 @@ function EstimateCustomizeFormContent() {
|
|||||||
return (
|
return (
|
||||||
<ElementCustomizeContent>
|
<ElementCustomizeContent>
|
||||||
<ElementCustomize.PaperTemplate>
|
<ElementCustomize.PaperTemplate>
|
||||||
<EstimatePaperTemplateFormConnected />
|
<Box overflow="auto" flex="1 1" px={4} py={6}>
|
||||||
|
<EstimatePaperTemplateFormConnected />
|
||||||
|
</Box>
|
||||||
</ElementCustomize.PaperTemplate>
|
</ElementCustomize.PaperTemplate>
|
||||||
|
|
||||||
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { useDrawerActions } from '@/hooks/state';
|
|||||||
import { BrandingTemplateForm } from '@/containers/BrandingTemplates/BrandingTemplateForm';
|
import { BrandingTemplateForm } from '@/containers/BrandingTemplates/BrandingTemplateForm';
|
||||||
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
||||||
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
||||||
|
import { Box } from '@/components';
|
||||||
|
|
||||||
export function PaymentReceivedCustomizeContent() {
|
export function PaymentReceivedCustomizeContent() {
|
||||||
const { payload, name } = useDrawerContext();
|
const { payload, name } = useDrawerContext();
|
||||||
@@ -51,7 +52,9 @@ function PaymentReceivedCustomizeFormContent() {
|
|||||||
return (
|
return (
|
||||||
<ElementCustomizeContent>
|
<ElementCustomizeContent>
|
||||||
<ElementCustomize.PaperTemplate>
|
<ElementCustomize.PaperTemplate>
|
||||||
<PaymentReceivedPaperTemplateFormConnected />
|
<Box overflow="auto" flex="1 1" px={4} py={6}>
|
||||||
|
<PaymentReceivedPaperTemplateFormConnected />
|
||||||
|
</Box>
|
||||||
</ElementCustomize.PaperTemplate>
|
</ElementCustomize.PaperTemplate>
|
||||||
|
|
||||||
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useDrawerActions } from '@/hooks/state';
|
|||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
import { useElementCustomizeContext } from '@/containers/ElementCustomize/ElementCustomizeProvider';
|
||||||
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
import { useIsTemplateNamedFilled } from '@/containers/BrandingTemplates/utils';
|
||||||
|
import { Box } from '@/components';
|
||||||
|
|
||||||
export function ReceiptCustomizeContent() {
|
export function ReceiptCustomizeContent() {
|
||||||
const { payload, name } = useDrawerContext();
|
const { payload, name } = useDrawerContext();
|
||||||
@@ -44,7 +45,9 @@ function ReceiptCustomizeFormContent() {
|
|||||||
return (
|
return (
|
||||||
<ElementCustomizeContent>
|
<ElementCustomizeContent>
|
||||||
<ElementCustomize.PaperTemplate>
|
<ElementCustomize.PaperTemplate>
|
||||||
<ReceiptPaperTemplateFormConnected />
|
<Box overflow="auto" flex="1 1" px={4} py={6}>
|
||||||
|
<ReceiptPaperTemplateFormConnected />
|
||||||
|
</Box>
|
||||||
</ElementCustomize.PaperTemplate>
|
</ElementCustomize.PaperTemplate>
|
||||||
|
|
||||||
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
<ElementCustomize.FieldsTab id={'general'} label={'General'}>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Intent, Tag } from '@blueprintjs/core';
|
import { Intent, Tag, Classes } from '@blueprintjs/core';
|
||||||
import { Align } from '@/constants';
|
import { Align } from '@/constants';
|
||||||
import styled from 'styled-components';
|
import clsx from 'classnames';
|
||||||
|
|
||||||
const codeAccessor = (taxRate) => {
|
const codeAccessor = (taxRate) => {
|
||||||
return (
|
return (
|
||||||
@@ -28,13 +28,17 @@ const nameAccessor = (taxRate) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>{taxRate.name}</span>
|
<span>{taxRate.name}</span>
|
||||||
{!!taxRate.is_compound && <CompoundText>(Compound tax)</CompoundText>}
|
{!!taxRate.is_compound && (
|
||||||
|
<span className={clsx(Classes.TEXT_MUTED)}>(Compound tax)</span>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DescriptionAccessor = (taxRate) => {
|
const DescriptionAccessor = (taxRate) => {
|
||||||
return <DescriptionText>{taxRate.description}</DescriptionText>;
|
return (
|
||||||
|
<span className={clsx(Classes.TEXT_MUTED)}>{taxRate.description}</span>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,11 +76,3 @@ export const useTaxRatesTableColumns = () => {
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
const CompoundText = styled('span')`
|
|
||||||
color: #738091;
|
|
||||||
margin-left: 5px;
|
|
||||||
`;
|
|
||||||
|
|
||||||
const DescriptionText = styled('span')`
|
|
||||||
color: #5f6b7c;
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { AppToaster, Can, DashboardActionsBar, Icon } from '@/components';
|
import { AppToaster, Can, DrawerActionsBar, Icon } from '@/components';
|
||||||
import { AbilitySubject, TaxRateAction } from '@/constants/abilityOption';
|
import { AbilitySubject, TaxRateAction } from '@/constants/abilityOption';
|
||||||
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
import { withDrawerActions } from '@/containers/Drawer/withDrawerActions';
|
||||||
import { withAlertActions } from '@/containers/Alert/withAlertActions';
|
import { withAlertActions } from '@/containers/Alert/withAlertActions';
|
||||||
@@ -83,7 +83,7 @@ function TaxRateDetailsContentActionsBar({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
<Can I={TaxRateAction.Edit} a={AbilitySubject.TaxRate}>
|
<Can I={TaxRateAction.Edit} a={AbilitySubject.TaxRate}>
|
||||||
<Button
|
<Button
|
||||||
@@ -137,7 +137,7 @@ function TaxRateDetailsContentActionsBar({
|
|||||||
</Popover>
|
</Popover>
|
||||||
</Can>
|
</Can>
|
||||||
</NavbarGroup>
|
</NavbarGroup>
|
||||||
</DashboardActionsBar>
|
</DrawerActionsBar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,9 +74,13 @@ const TaxRateHeader = styled(`div`)`
|
|||||||
const TaxRateAmount = styled('div')`
|
const TaxRateAmount = styled('div')`
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
color: #565b71;
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
color: var(--x-color-amount-text, #565b71);
|
||||||
|
|
||||||
|
.bp4-dark & {
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const TaxRateActiveTag = styled(Tag)`
|
const TaxRateActiveTag = styled(Tag)`
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ const Schema = Yup.object().shape({
|
|||||||
display_name: Yup.string().trim().required().label(intl.get('display_name_')),
|
display_name: Yup.string().trim().required().label(intl.get('display_name_')),
|
||||||
|
|
||||||
email: Yup.string().email().nullable(),
|
email: Yup.string().email().nullable(),
|
||||||
work_phone: Yup.number(),
|
work_phone: Yup.string().nullable(),
|
||||||
personal_phone: Yup.number(),
|
personal_phone: Yup.string().nullable(),
|
||||||
website: Yup.string().url().nullable(),
|
website: Yup.string().url().nullable(),
|
||||||
|
|
||||||
active: Yup.boolean(),
|
active: Yup.boolean(),
|
||||||
@@ -23,7 +23,7 @@ const Schema = Yup.object().shape({
|
|||||||
billing_address_city: Yup.string().trim(),
|
billing_address_city: Yup.string().trim(),
|
||||||
billing_address_state: Yup.string().trim(),
|
billing_address_state: Yup.string().trim(),
|
||||||
billing_address_postcode: Yup.string().nullable(),
|
billing_address_postcode: Yup.string().nullable(),
|
||||||
billing_address_phone: Yup.number(),
|
billing_address_phone: Yup.string().nullable(),
|
||||||
|
|
||||||
shipping_address_country: Yup.string().trim(),
|
shipping_address_country: Yup.string().trim(),
|
||||||
shipping_address_1: Yup.string().trim(),
|
shipping_address_1: Yup.string().trim(),
|
||||||
@@ -31,7 +31,7 @@ const Schema = Yup.object().shape({
|
|||||||
shipping_address_city: Yup.string().trim(),
|
shipping_address_city: Yup.string().trim(),
|
||||||
shipping_address_state: Yup.string().trim(),
|
shipping_address_state: Yup.string().trim(),
|
||||||
shipping_address_postcode: Yup.string().nullable(),
|
shipping_address_postcode: Yup.string().nullable(),
|
||||||
shipping_address_phone: Yup.number(),
|
shipping_address_phone: Yup.string().nullable(),
|
||||||
|
|
||||||
opening_balance: Yup.number().nullable(),
|
opening_balance: Yup.number().nullable(),
|
||||||
currency_code: Yup.string(),
|
currency_code: Yup.string(),
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ export function useTaxRate(taxRateId: string, props) {
|
|||||||
[QUERY_TYPES.TAX_RATES, taxRateId],
|
[QUERY_TYPES.TAX_RATES, taxRateId],
|
||||||
{
|
{
|
||||||
method: 'get',
|
method: 'get',
|
||||||
url: `tax-rates/${taxRateId}}`,
|
url: `tax-rates/${taxRateId}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
select: (res) => res.data.data,
|
select: (res) => res.data,
|
||||||
...props,
|
...props,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -106,7 +106,7 @@ export function useActivateTaxRate(props) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation((id) => apiRequest.post(`tax-rates/${id}/active`), {
|
return useMutation((id) => apiRequest.put(`tax-rates/${id}/activate`), {
|
||||||
onSuccess: (res, id) => {
|
onSuccess: (res, id) => {
|
||||||
commonInvalidateQueries(queryClient);
|
commonInvalidateQueries(queryClient);
|
||||||
queryClient.invalidateQueries([QUERY_TYPES.TAX_RATES, id]);
|
queryClient.invalidateQueries([QUERY_TYPES.TAX_RATES, id]);
|
||||||
@@ -122,7 +122,7 @@ export function useInactivateTaxRate(props) {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const apiRequest = useApiRequest();
|
const apiRequest = useApiRequest();
|
||||||
|
|
||||||
return useMutation((id) => apiRequest.post(`tax-rates/${id}/inactive`), {
|
return useMutation((id) => apiRequest.put(`tax-rates/${id}/inactivate`), {
|
||||||
onSuccess: (res, id) => {
|
onSuccess: (res, id) => {
|
||||||
commonInvalidateQueries(queryClient);
|
commonInvalidateQueries(queryClient);
|
||||||
queryClient.invalidateQueries([QUERY_TYPES.TAX_RATES, id]);
|
queryClient.invalidateQueries([QUERY_TYPES.TAX_RATES, id]);
|
||||||
|
|||||||
Reference in New Issue
Block a user