mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 22:00:31 +00:00
refactor: tenant proxy providers
This commit is contained in:
@@ -62,7 +62,7 @@
|
||||
"moment": "^2.30.1",
|
||||
"mysql": "^2.18.1",
|
||||
"mysql2": "^3.11.3",
|
||||
"nestjs-cls": "^4.4.1",
|
||||
"nestjs-cls": "^5.2.0",
|
||||
"nestjs-i18n": "^10.4.9",
|
||||
"nodemailer": "^6.3.0",
|
||||
"object-hash": "^2.0.3",
|
||||
|
||||
@@ -117,26 +117,22 @@ export interface IAccountsTypesService {
|
||||
}
|
||||
|
||||
export interface IAccountEventCreatingPayload {
|
||||
tenantId: number;
|
||||
accountDTO: any;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
export interface IAccountEventCreatedPayload {
|
||||
tenantId: number;
|
||||
account: IAccount;
|
||||
accountId: number;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IAccountEventEditedPayload {
|
||||
tenantId: number;
|
||||
account: IAccount;
|
||||
oldAccount: IAccount;
|
||||
trx: Knex.Transaction;
|
||||
}
|
||||
|
||||
export interface IAccountEventDeletedPayload {
|
||||
tenantId: number;
|
||||
accountId: number;
|
||||
oldAccount: IAccount;
|
||||
trx: Knex.Transaction;
|
||||
|
||||
4
packages/server-nest/src/interfaces/Tenant.ts
Normal file
4
packages/server-nest/src/interfaces/Tenant.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface TenantJobPayload {
|
||||
organizationId: string;
|
||||
userId: number;
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import { DynamicListModule } from '../DynamicListing/DynamicList.module';
|
||||
const models = [RegisterTenancyModel(BankAccount)];
|
||||
|
||||
@Module({
|
||||
imports: [TenancyDatabaseModule, DynamicListModule],
|
||||
imports: [TenancyDatabaseModule, DynamicListModule, ...models],
|
||||
controllers: [AccountsController],
|
||||
providers: [
|
||||
AccountsApplication,
|
||||
@@ -38,7 +38,6 @@ const models = [RegisterTenancyModel(BankAccount)];
|
||||
GetAccountTypesService,
|
||||
GetAccountTransactionsService,
|
||||
GetAccountsService,
|
||||
...models,
|
||||
],
|
||||
exports: [AccountRepository, CreateAccountService, ...models],
|
||||
})
|
||||
|
||||
@@ -6,16 +6,17 @@ import { AccountRepository } from './repositories/Account.repository';
|
||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateAccount {
|
||||
constructor(
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -25,7 +26,7 @@ export class ActivateAccount {
|
||||
*/
|
||||
public activateAccount = async (accountId: number, activate?: boolean) => {
|
||||
// Retrieve the given account or throw not found error.
|
||||
const oldAccount = await this.accountModel
|
||||
const oldAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(accountId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -9,12 +9,13 @@ import { AccountRepository } from './repositories/Account.repository';
|
||||
import { AccountTypesUtils } from './utils/AccountType.utils';
|
||||
import { CreateAccountDTO } from './CreateAccount.dto';
|
||||
import { EditAccountDTO } from './EditAccount.dto';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable({ scope: Scope.REQUEST })
|
||||
export class CommandAccountValidators {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
) {}
|
||||
|
||||
@@ -66,7 +67,7 @@ export class CommandAccountValidators {
|
||||
accountId: number,
|
||||
notAccountId?: number,
|
||||
) {
|
||||
const parentAccount = await this.accountModel
|
||||
const parentAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(accountId)
|
||||
.onBuild((query) => {
|
||||
@@ -89,7 +90,7 @@ export class CommandAccountValidators {
|
||||
accountCode: string,
|
||||
notAccountId?: number,
|
||||
) {
|
||||
const account = await this.accountModel
|
||||
const account = await this.accountModel()
|
||||
.query()
|
||||
.where('code', accountCode)
|
||||
.onBuild((query) => {
|
||||
|
||||
@@ -14,12 +14,13 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { CreateAccountDTO } from './CreateAccount.dto';
|
||||
import { PartialModelObject } from 'objection';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateAccountService {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly validator: CommandAccountValidators,
|
||||
@@ -121,9 +122,11 @@ export class CreateAccountService {
|
||||
} as IAccountEventCreatingPayload);
|
||||
|
||||
// Inserts account to the storage.
|
||||
const account = await this.accountModel.query().insert({
|
||||
...accountInputModel,
|
||||
});
|
||||
const account = await this.accountModel()
|
||||
.query()
|
||||
.insert({
|
||||
...accountInputModel,
|
||||
});
|
||||
// Triggers `onAccountCreated` event.
|
||||
await this.eventEmitter.emitAsync(events.accounts.onCreated, {
|
||||
account,
|
||||
|
||||
@@ -7,11 +7,14 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { IAccountEventDeletedPayload } from './Accounts.types';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteAccount {
|
||||
constructor(
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
private eventEmitter: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
private validator: CommandAccountValidators,
|
||||
@@ -38,7 +41,7 @@ export class DeleteAccount {
|
||||
? parentAccountId
|
||||
: [parentAccountId];
|
||||
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.whereIn('parent_account_id', accountsIds)
|
||||
.patch({ parentAccountId: null });
|
||||
@@ -50,7 +53,7 @@ export class DeleteAccount {
|
||||
*/
|
||||
public deleteAccount = async (accountId: number): Promise<void> => {
|
||||
// Retrieve account or not found service error.
|
||||
const oldAccount = await this.accountModel.query().findById(accountId);
|
||||
const oldAccount = await this.accountModel().query().findById(accountId);
|
||||
|
||||
// Authorize before delete account.
|
||||
await this.authorize(accountId, oldAccount);
|
||||
@@ -67,7 +70,7 @@ export class DeleteAccount {
|
||||
await this.unassociateChildrenAccountsFromParent(accountId, trx);
|
||||
|
||||
// Deletes account by the given id.
|
||||
await this.accountModel.query(trx).deleteById(accountId);
|
||||
await this.accountModel().query(trx).deleteById(accountId);
|
||||
|
||||
// Triggers `onAccountDeleted` event.
|
||||
await this.eventEmitter.emitAsync(events.accounts.onDeleted, {
|
||||
|
||||
@@ -6,6 +6,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { EditAccountDTO } from './EditAccount.dto';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditAccount {
|
||||
@@ -15,7 +16,7 @@ export class EditAccount {
|
||||
private readonly validator: CommandAccountValidators,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -66,7 +67,7 @@ export class EditAccount {
|
||||
accountDTO: EditAccountDTO,
|
||||
): Promise<Account> {
|
||||
// Retrieve the old account or throw not found service error.
|
||||
const oldAccount = await this.accountModel
|
||||
const oldAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(accountId)
|
||||
.throwIfNotFound();
|
||||
@@ -82,7 +83,7 @@ export class EditAccount {
|
||||
accountDTO,
|
||||
});
|
||||
// Update the account on the storage.
|
||||
const account = await this.accountModel
|
||||
const account = await this.accountModel()
|
||||
.query(trx)
|
||||
.findById(accountId)
|
||||
.updateAndFetch({ ...accountDTO });
|
||||
|
||||
@@ -5,12 +5,13 @@ import { AccountRepository } from './repositories/Account.repository';
|
||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetAccount {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
private readonly accountRepository: AccountRepository,
|
||||
private readonly transformer: TransformerInjectable,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
@@ -22,7 +23,7 @@ export class GetAccount {
|
||||
*/
|
||||
public getAccount = async (accountId: number) => {
|
||||
// Find the given account or throw not found error.
|
||||
const account = await this.accountModel
|
||||
const account = await this.accountModel()
|
||||
.query()
|
||||
.findById(accountId)
|
||||
.withGraphFetched('plaidItem')
|
||||
|
||||
@@ -7,6 +7,7 @@ import { AccountTransaction } from './models/AccountTransaction.model';
|
||||
import { Account } from './models/Account.model';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { TransformerInjectable } from '../Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetAccountTransactionsService {
|
||||
@@ -14,10 +15,12 @@ export class GetAccountTransactionsService {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(AccountTransaction.name)
|
||||
private readonly accountTransaction: typeof AccountTransaction,
|
||||
private readonly accountTransaction: TenantModelProxy<
|
||||
typeof AccountTransaction
|
||||
>,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly account: typeof Account,
|
||||
private readonly account: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -29,9 +32,9 @@ export class GetAccountTransactionsService {
|
||||
): Promise<IGetAccountTransactionPOJO[]> => {
|
||||
// Retrieve the given account or throw not found error.
|
||||
if (filter.accountId) {
|
||||
await this.account.query().findById(filter.accountId).throwIfNotFound();
|
||||
await this.account().query().findById(filter.accountId).throwIfNotFound();
|
||||
}
|
||||
const transactions = await this.accountTransaction
|
||||
const transactions = await this.accountTransaction()
|
||||
.query()
|
||||
.onBuild((query) => {
|
||||
query.orderBy('date', 'DESC');
|
||||
|
||||
@@ -7,6 +7,7 @@ import { TransformerInjectable } from '../Transformer/TransformerInjectable.serv
|
||||
import { Account } from './models/Account.model';
|
||||
import { AccountRepository } from './repositories/Account.repository';
|
||||
import { IFilterMeta } from '@/interfaces/Model';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetAccountsService {
|
||||
@@ -16,7 +17,7 @@ export class GetAccountsService {
|
||||
private readonly accountRepository: AccountRepository,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -32,14 +33,16 @@ export class GetAccountsService {
|
||||
|
||||
// Dynamic list service.
|
||||
const dynamicList = await this.dynamicListService.dynamicList(
|
||||
this.accountModel,
|
||||
this.accountModel(),
|
||||
filter,
|
||||
);
|
||||
// Retrieve accounts model based on the given query.
|
||||
const accounts = await this.accountModel.query().onBuild((builder) => {
|
||||
dynamicList.buildQuery()(builder);
|
||||
builder.modify('inactiveMode', filter.inactiveMode);
|
||||
});
|
||||
const accounts = await this.accountModel()
|
||||
.query()
|
||||
.onBuild((builder) => {
|
||||
dynamicList.buildQuery()(builder);
|
||||
builder.modify('inactiveMode', filter.inactiveMode);
|
||||
});
|
||||
const accountsGraph = await this.accountRepository.getDependencyGraph();
|
||||
|
||||
// Retrieves the transformed accounts collection.
|
||||
|
||||
@@ -117,6 +117,8 @@ import { StripePaymentModule } from '../StripePayment/StripePayment.module';
|
||||
cls.set('organizationId', req.headers['organization-id']);
|
||||
cls.set('userId', 1);
|
||||
},
|
||||
generateId: true,
|
||||
saveReq: true,
|
||||
},
|
||||
}),
|
||||
TenancyDatabaseModule,
|
||||
@@ -152,13 +154,13 @@ import { StripePaymentModule } from '../StripePayment/StripePayment.module';
|
||||
BankingTransactionsModule,
|
||||
BankingTransactionsExcludeModule,
|
||||
BankingTransactionsRegonizeModule,
|
||||
BankingMatchingModule,
|
||||
TransactionsLockingModule,
|
||||
SettingsModule,
|
||||
// BankingMatchingModule,
|
||||
// TransactionsLockingModule,
|
||||
// SettingsModule,
|
||||
InventoryAdjustmentsModule,
|
||||
PostHogModule,
|
||||
EventTrackerModule,
|
||||
FinancialStatementsModule,
|
||||
// FinancialStatementsModule,
|
||||
StripePaymentModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
|
||||
@@ -20,9 +20,8 @@ const models = [
|
||||
|
||||
@Module({
|
||||
controllers: [BankRulesController],
|
||||
imports: [forwardRef(() => BankingTransactionsRegonizeModule)],
|
||||
imports: [forwardRef(() => BankingTransactionsRegonizeModule), ...models],
|
||||
providers: [
|
||||
...models,
|
||||
CreateBankRuleService,
|
||||
EditBankRuleService,
|
||||
DeleteBankRuleService,
|
||||
@@ -30,7 +29,7 @@ const models = [
|
||||
GetBankRuleService,
|
||||
GetBankRulesService,
|
||||
BankRulesApplication,
|
||||
UnlinkBankRuleOnDeleteBankRuleSubscriber
|
||||
UnlinkBankRuleOnDeleteBankRuleSubscriber,
|
||||
],
|
||||
exports: [...models, DeleteBankRuleService, DeleteBankRulesService],
|
||||
})
|
||||
|
||||
@@ -9,13 +9,16 @@ import { BankRuleCondition } from '../models/BankRuleCondition';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBankRuleService {
|
||||
constructor(
|
||||
@Inject(BankRule.name) private bankRuleModel: typeof BankRule,
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
|
||||
@Inject(BankRuleCondition.name)
|
||||
private bankRuleConditionModel: typeof BankRuleCondition,
|
||||
private bankRuleConditionModel: TenantModelProxy<typeof BankRuleCondition>,
|
||||
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
@@ -30,7 +33,7 @@ export class DeleteBankRuleService {
|
||||
ruleId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
const oldBankRule = await this.bankRuleModel
|
||||
const oldBankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.throwIfNotFound();
|
||||
@@ -43,11 +46,12 @@ export class DeleteBankRuleService {
|
||||
trx,
|
||||
} as IBankRuleEventDeletingPayload);
|
||||
|
||||
await this.bankRuleConditionModel
|
||||
await this.bankRuleConditionModel()
|
||||
.query(trx)
|
||||
.where('ruleId', ruleId)
|
||||
.delete();
|
||||
await this.bankRuleModel.query(trx).findById(ruleId).delete();
|
||||
|
||||
await this.bankRuleModel().query(trx).findById(ruleId).delete();
|
||||
|
||||
// Triggers `onBankRuleDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onDeleted, {
|
||||
|
||||
@@ -8,6 +8,7 @@ import { BankRule } from '../models/BankRule';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditBankRuleService {
|
||||
@@ -15,7 +16,8 @@ export class EditBankRuleService {
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(BankRule.name) private bankRuleModel: typeof BankRule,
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -34,11 +36,9 @@ export class EditBankRuleService {
|
||||
* @param {number} ruleId -
|
||||
* @param {IEditBankRuleDTO} editBankDTO
|
||||
*/
|
||||
public async editBankRule(
|
||||
ruleId: number,
|
||||
editRuleDTO: IEditBankRuleDTO
|
||||
) {
|
||||
const oldBankRule = await this.bankRuleModel.query()
|
||||
public async editBankRule(ruleId: number, editRuleDTO: IEditBankRuleDTO) {
|
||||
const oldBankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.withGraphFetched('conditions')
|
||||
.throwIfNotFound();
|
||||
@@ -55,10 +55,12 @@ export class EditBankRuleService {
|
||||
} as IBankRuleEventEditingPayload);
|
||||
|
||||
// Updates the given bank rule.
|
||||
const bankRule = await this.bankRuleModel.query(trx).upsertGraphAndFetch({
|
||||
...tranformDTO,
|
||||
id: ruleId,
|
||||
});
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
...tranformDTO,
|
||||
id: ruleId,
|
||||
});
|
||||
// Triggers `onBankRuleEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.bankRules.onEdited, {
|
||||
oldBankRule,
|
||||
|
||||
@@ -3,11 +3,13 @@ import { GetBankRuleTransformer } from './GetBankRuleTransformer';
|
||||
import { TransformerInjectable } from '../../Transformer/TransformerInjectable.service';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { GetBankRulesTransformer } from './GetBankRulesTransformer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBankRuleService {
|
||||
constructor(
|
||||
@Inject(BankRule.name) private bankRuleModel: typeof BankRule,
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
private transformer: TransformerInjectable,
|
||||
) {}
|
||||
|
||||
@@ -17,15 +19,12 @@ export class GetBankRuleService {
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async getBankRule(ruleId: number): Promise<any> {
|
||||
const bankRule = await this.bankRuleModel
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.findById(ruleId)
|
||||
.withGraphFetched('conditions')
|
||||
.withGraphFetched('assignAccount');
|
||||
|
||||
return this.transformer.transform(
|
||||
bankRule,
|
||||
new GetBankRulesTransformer()
|
||||
);
|
||||
return this.transformer.transform(bankRule, new GetBankRulesTransformer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { GetBankRulesTransformer } from './GetBankRulesTransformer';
|
||||
import { BankRule } from '../models/BankRule';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBankRulesService {
|
||||
@@ -9,7 +10,7 @@ export class GetBankRulesService {
|
||||
private transformer: TransformerInjectable,
|
||||
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: typeof BankRule,
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -17,14 +18,11 @@ export class GetBankRulesService {
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
public async getBankRules(): Promise<any> {
|
||||
const bankRule = await this.bankRuleModel
|
||||
const bankRule = await this.bankRuleModel()
|
||||
.query()
|
||||
.withGraphFetched('conditions')
|
||||
.withGraphFetched('assignAccount');
|
||||
|
||||
return this.transformer.transform(
|
||||
bankRule,
|
||||
new GetBankRulesTransformer()
|
||||
);
|
||||
return this.transformer.transform(bankRule, new GetBankRulesTransformer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { events } from '@/common/events/events';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { PLAID_CLIENT } from '@/modules/Plaid/Plaid.module';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DisconnectBankAccountService {
|
||||
@@ -21,9 +22,12 @@ export class DisconnectBankAccountService {
|
||||
private eventPublisher: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
@Inject(PlaidItem.name) private plaidItemModel: typeof PlaidItem,
|
||||
@Inject(PLAID_CLIENT) private plaidClient: PlaidApi,
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(PlaidItem.name)
|
||||
private plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -33,7 +37,7 @@ export class DisconnectBankAccountService {
|
||||
*/
|
||||
public async disconnectBankAccount(bankAccountId: number) {
|
||||
// Retrieve the bank account or throw not found error.
|
||||
const account = await this.accountModel
|
||||
const account = await this.accountModel()
|
||||
.query()
|
||||
.findById(bankAccountId)
|
||||
.whereIn('account_type', [ACCOUNT_TYPE.CASH, ACCOUNT_TYPE.BANK])
|
||||
@@ -52,10 +56,13 @@ export class DisconnectBankAccountService {
|
||||
} as IBankAccountDisconnectingEventPayload);
|
||||
|
||||
// Remove the Plaid item from the system.
|
||||
await this.plaidItemModel.query(trx).findById(account.plaidItemId).delete();
|
||||
await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findById(account.plaidItemId)
|
||||
.delete();
|
||||
|
||||
// Remove the plaid item association to the bank account.
|
||||
await this.accountModel.query(trx).findById(bankAccountId).patch({
|
||||
await this.accountModel().query(trx).findById(bankAccountId).patch({
|
||||
plaidAccountId: null,
|
||||
plaidItemId: null,
|
||||
isFeedsActive: false,
|
||||
|
||||
@@ -5,23 +5,26 @@ import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class PauseBankAccountFeeds {
|
||||
constructor(
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
@Inject(PlaidItem.name) private plaidItemModel: typeof PlaidItem,
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
@Inject(PlaidItem.name)
|
||||
private plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
|
||||
private uow: UnitOfWork,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Pauses the bankfeed syncing of the given bank account.
|
||||
* Pauses the bank feed syncing of the given bank account.
|
||||
* @param {number} bankAccountId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async pauseBankAccountFeeds(bankAccountId: number) {
|
||||
const oldAccount = await this.accountModel
|
||||
const oldAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(bankAccountId)
|
||||
.withGraphFetched('plaidItem')
|
||||
@@ -36,7 +39,7 @@ export class PauseBankAccountFeeds {
|
||||
throw new ServiceError(ERRORS.BANK_ACCOUNT_FEEDS_ALREADY_PAUSED);
|
||||
}
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
await this.plaidItemModel
|
||||
await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findById(oldAccount.plaidItem.id)
|
||||
.patch({
|
||||
|
||||
@@ -4,12 +4,14 @@ import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { PLAID_CLIENT } from '@/modules/Plaid/Plaid.module';
|
||||
import { ERRORS } from '../types/BankAccounts.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class RefreshBankAccountService {
|
||||
constructor(
|
||||
@Inject(PLAID_CLIENT) private plaidClient: PlaidApi,
|
||||
@Inject(Account.name) private readonly accountModel: typeof Account,
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -18,7 +20,7 @@ export class RefreshBankAccountService {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async refreshBankAccount(bankAccountId: number) {
|
||||
const bankAccount = await this.accountModel
|
||||
const bankAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(bankAccountId)
|
||||
.withGraphFetched('plaidItem')
|
||||
|
||||
@@ -5,12 +5,16 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ResumeBankAccountFeedsService {
|
||||
constructor(
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
@Inject(PlaidItem.name) private plaidItemModel: typeof PlaidItem,
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(PlaidItem.name)
|
||||
private plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
|
||||
private uow: UnitOfWork,
|
||||
) {}
|
||||
@@ -21,7 +25,7 @@ export class ResumeBankAccountFeedsService {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async resumeBankAccountFeeds(bankAccountId: number) {
|
||||
const oldAccount = await this.accountModel
|
||||
const oldAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(bankAccountId)
|
||||
.withGraphFetched('plaidItem');
|
||||
@@ -35,7 +39,7 @@ export class ResumeBankAccountFeedsService {
|
||||
throw new ServiceError(ERRORS.BANK_ACCOUNT_FEEDS_ALREADY_RESUMED);
|
||||
}
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
await this.plaidItemModel
|
||||
await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findById(oldAccount.plaidItem.id)
|
||||
.patch({
|
||||
|
||||
@@ -2,15 +2,18 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBankAccountSummary {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -19,7 +22,7 @@ export class GetBankAccountSummary {
|
||||
* @returns {Promise<IBankAccountSummary>}
|
||||
*/
|
||||
public async getBankAccountSummary(bankAccountId: number) {
|
||||
const bankAccount = await this.accountModel
|
||||
const bankAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(bankAccountId)
|
||||
.throwIfNotFound();
|
||||
@@ -41,60 +44,68 @@ export class GetBankAccountSummary {
|
||||
|
||||
// Retrieves the uncategorized transactions count of the given bank account.
|
||||
const uncategorizedTranasctionsCount =
|
||||
await this.uncategorizedBankTransactionModel.query().onBuild((q) => {
|
||||
commonQuery(q);
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
commonQuery(q);
|
||||
|
||||
// Only the not matched bank transactions.
|
||||
q.withGraphJoined('matchedBankTransactions');
|
||||
q.whereNull('matchedBankTransactions.id');
|
||||
// Only the not matched bank transactions.
|
||||
q.withGraphJoined('matchedBankTransactions');
|
||||
q.whereNull('matchedBankTransactions.id');
|
||||
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
|
||||
// Retrives the recognized transactions count.
|
||||
const recognizedTransactionsCount =
|
||||
await this.uncategorizedBankTransactionModel.query().onBuild((q) => {
|
||||
commonQuery(q);
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
commonQuery(q);
|
||||
|
||||
q.withGraphJoined('recognizedTransaction');
|
||||
q.whereNotNull('recognizedTransaction.id');
|
||||
q.withGraphJoined('recognizedTransaction');
|
||||
q.whereNotNull('recognizedTransaction.id');
|
||||
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
// Retrieves excluded transactions count.
|
||||
const excludedTransactionsCount =
|
||||
await this.uncategorizedBankTransactionModel.query().onBuild((q) => {
|
||||
q.where('accountId', bankAccountId);
|
||||
q.modify('excluded');
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
q.where('accountId', bankAccountId);
|
||||
q.modify('excluded');
|
||||
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
// Exclude the pending transactions.
|
||||
q.modify('notPending');
|
||||
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
|
||||
// Retrieves the pending transactions count.
|
||||
const pendingTransactionsCount =
|
||||
await this.uncategorizedBankTransactionModel.query().onBuild((q) => {
|
||||
q.where('accountId', bankAccountId);
|
||||
q.modify('pending');
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
q.where('accountId', bankAccountId);
|
||||
q.modify('pending');
|
||||
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
// Count the results.
|
||||
q.count('uncategorized_cashflow_transactions.id as total');
|
||||
q.first();
|
||||
});
|
||||
|
||||
const totalUncategorizedTransactions =
|
||||
// @ts-ignore
|
||||
|
||||
@@ -6,6 +6,7 @@ import { RevertRecognizedTransactionsService } from '@/modules/BankingTranasctio
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { DeleteBankRulesService } from '@/modules/BankRules/commands/DeleteBankRules.service';
|
||||
import { BankRule } from '@/modules/BankRules/models/BankRule';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteUncategorizedTransactionsOnAccountDeleting {
|
||||
@@ -13,9 +14,13 @@ export class DeleteUncategorizedTransactionsOnAccountDeleting {
|
||||
private readonly deleteBankRules: DeleteBankRulesService,
|
||||
private readonly revertRecognizedTransactins: RevertRecognizedTransactionsService,
|
||||
|
||||
@Inject(BankRule.name) private bankRuleModel: typeof BankRule,
|
||||
@Inject(BankRule.name)
|
||||
private bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private uncategorizedCashflowTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private uncategorizedCashflowTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -28,10 +33,9 @@ export class DeleteUncategorizedTransactionsOnAccountDeleting {
|
||||
oldAccount,
|
||||
trx,
|
||||
}: IAccountEventDeletePayload) {
|
||||
const foundAssociatedRules = await this.bankRuleModel.query(trx).where(
|
||||
'applyIfAccountId',
|
||||
oldAccount.id,
|
||||
);
|
||||
const foundAssociatedRules = await this.bankRuleModel()
|
||||
.query(trx)
|
||||
.where('applyIfAccountId', oldAccount.id);
|
||||
const foundAssociatedRulesIds = foundAssociatedRules.map((rule) => rule.id);
|
||||
|
||||
// Revert the recognized transactions of the given bank rules.
|
||||
@@ -41,15 +45,12 @@ export class DeleteUncategorizedTransactionsOnAccountDeleting {
|
||||
trx,
|
||||
);
|
||||
// Delete the associated uncategorized transactions.
|
||||
await this.uncategorizedCashflowTransactionModel
|
||||
await this.uncategorizedCashflowTransactionModel()
|
||||
.query(trx)
|
||||
.where('accountId', oldAccount.id)
|
||||
.delete();
|
||||
|
||||
// Delete the given bank rules.
|
||||
await this.deleteBankRules.deleteBankRules(
|
||||
foundAssociatedRulesIds,
|
||||
trx,
|
||||
);
|
||||
await this.deleteBankRules.deleteBankRules(foundAssociatedRulesIds, trx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,20 @@ import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { PlaidApi } from 'plaid';
|
||||
import { PLAID_CLIENT } from '@/modules/Plaid/Plaid.module';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DisconnectPlaidItemOnAccountDeleted {
|
||||
constructor(
|
||||
@Inject(PLAID_CLIENT) private plaidClient: PlaidApi,
|
||||
@Inject(PlaidItem.name) private plaidItemModel: typeof PlaidItem,
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
|
||||
@Inject(PlaidItem.name)
|
||||
private plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes Plaid item from the system and Plaid once the account deleted.
|
||||
* @param {IAccountEventDeletedPayload} payload
|
||||
@@ -21,7 +27,6 @@ export class DisconnectPlaidItemOnAccountDeleted {
|
||||
*/
|
||||
@OnEvent(events.accounts.onDeleted)
|
||||
public async handleDisconnectPlaidItemOnAccountDelete({
|
||||
tenantId,
|
||||
oldAccount,
|
||||
trx,
|
||||
}: IAccountEventDeletedPayload) {
|
||||
@@ -29,11 +34,11 @@ export class DisconnectPlaidItemOnAccountDeleted {
|
||||
if (!oldAccount.plaidItemId) return;
|
||||
|
||||
// Retrieves the Plaid item that associated to the deleted account.
|
||||
const oldPlaidItem = await this.plaidItemModel
|
||||
const oldPlaidItem = await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findOne('plaidItemId', oldAccount.plaidItemId);
|
||||
// Unlink the Plaid item from all account before deleting it.
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.where('plaidItemId', oldAccount.plaidItemId)
|
||||
.patch({
|
||||
@@ -41,7 +46,7 @@ export class DisconnectPlaidItemOnAccountDeleted {
|
||||
plaidItemId: null,
|
||||
});
|
||||
// Remove the Plaid item from the system.
|
||||
await this.plaidItemModel
|
||||
await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findOne('plaidItemId', oldAccount.plaidItemId)
|
||||
.delete();
|
||||
|
||||
@@ -16,6 +16,7 @@ import { CreateBankTransactionService } from '../../BankingTransactions/commands
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CategorizeCashflowTransaction {
|
||||
@@ -26,7 +27,9 @@ export class CategorizeCashflowTransaction {
|
||||
private readonly createBankTransaction: CreateBankTransactionService,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -41,7 +44,8 @@ export class CategorizeCashflowTransaction {
|
||||
|
||||
// Retrieves the uncategorized transaction or throw an error.
|
||||
const oldUncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel.query()
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.whereIn('id', uncategorizedTransactionIds)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -81,7 +85,8 @@ export class CategorizeCashflowTransaction {
|
||||
);
|
||||
|
||||
// Updates the uncategorized transaction as categorized.
|
||||
await this.uncategorizedBankTransactionModel.query(trx)
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.whereIn('id', uncategorizedTransactionIds)
|
||||
.patch({
|
||||
categorized: true,
|
||||
@@ -90,10 +95,9 @@ export class CategorizeCashflowTransaction {
|
||||
});
|
||||
// Fetch the new updated uncategorized transactions.
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel.query(trx).whereIn(
|
||||
'id',
|
||||
uncategorizedTransactionIds,
|
||||
);
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.whereIn('id', uncategorizedTransactionIds);
|
||||
// Triggers `onCashflowTransactionCategorized` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionCategorized,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
ICashflowTransactionCategorizedPayload,
|
||||
ICategorizeCashflowTransactioDTO,
|
||||
} from '../types/BankingCategorize.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CategorizeTransactionAsExpense {
|
||||
@@ -19,7 +20,9 @@ export class CategorizeTransactionAsExpense {
|
||||
private readonly createExpenseService: CreateExpense,
|
||||
|
||||
@Inject(BankTransaction.name)
|
||||
private readonly bankTransactionModel: typeof BankTransaction,
|
||||
private readonly bankTransactionModel: TenantModelProxy<
|
||||
typeof BankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -31,7 +34,7 @@ export class CategorizeTransactionAsExpense {
|
||||
cashflowTransactionId: number,
|
||||
transactionDTO: ICategorizeCashflowTransactioDTO,
|
||||
) {
|
||||
const transaction = await this.bankTransactionModel
|
||||
const transaction = await this.bankTransactionModel()
|
||||
.query()
|
||||
.findById(cashflowTransactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -53,7 +56,7 @@ export class CategorizeTransactionAsExpense {
|
||||
});
|
||||
|
||||
// Updates the item on the storage and fetches the updated once.
|
||||
const cashflowTransaction = await this.bankTransactionModel
|
||||
const cashflowTransaction = await this.bankTransactionModel()
|
||||
.query(trx)
|
||||
.patchAndFetchById(cashflowTransactionId, {
|
||||
categorizeRefType: 'Expense',
|
||||
|
||||
@@ -9,6 +9,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UncategorizedBankTransaction } from '../../BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateUncategorizedTransactionService {
|
||||
@@ -17,7 +18,9 @@ export class CreateUncategorizedTransactionService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransaction: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransaction: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -28,34 +31,32 @@ export class CreateUncategorizedTransactionService {
|
||||
*/
|
||||
public create(
|
||||
createUncategorizedTransactionDTO: CreateUncategorizedTransactionDTO,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
return this.uow.withTransaction(
|
||||
async (trx: Knex.Transaction) => {
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionUncategorizedCreating,
|
||||
{
|
||||
createUncategorizedTransactionDTO,
|
||||
trx,
|
||||
} as IUncategorizedTransactionCreatingEventPayload
|
||||
);
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionUncategorizedCreating,
|
||||
{
|
||||
createUncategorizedTransactionDTO,
|
||||
trx,
|
||||
} as IUncategorizedTransactionCreatingEventPayload,
|
||||
);
|
||||
|
||||
const uncategorizedTransaction =
|
||||
await this.uncategorizedBankTransaction.query(trx).insertAndFetch({
|
||||
...createUncategorizedTransactionDTO,
|
||||
});
|
||||
const uncategorizedTransaction = await this.uncategorizedBankTransaction
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...createUncategorizedTransactionDTO,
|
||||
});
|
||||
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionUncategorizedCreated,
|
||||
{
|
||||
uncategorizedTransaction,
|
||||
createUncategorizedTransactionDTO,
|
||||
trx,
|
||||
} as IUncategorizedTransactionCreatedEventPayload
|
||||
);
|
||||
return uncategorizedTransaction;
|
||||
},
|
||||
trx
|
||||
);
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.cashflow.onTransactionUncategorizedCreated,
|
||||
{
|
||||
uncategorizedTransaction,
|
||||
createUncategorizedTransactionDTO,
|
||||
trx,
|
||||
} as IUncategorizedTransactionCreatedEventPayload,
|
||||
);
|
||||
return uncategorizedTransaction;
|
||||
}, trx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { UncategorizedBankTransaction } from '../../BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class UncategorizeCashflowTransactionService {
|
||||
@@ -17,7 +18,9 @@ export class UncategorizeCashflowTransactionService {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -29,7 +32,7 @@ export class UncategorizeCashflowTransactionService {
|
||||
uncategorizedTransactionId: number,
|
||||
): Promise<Array<number>> {
|
||||
const oldMainUncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -37,7 +40,7 @@ export class UncategorizeCashflowTransactionService {
|
||||
validateTransactionShouldBeCategorized(oldMainUncategorizedTransaction);
|
||||
|
||||
const associatedUncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.where(
|
||||
'categorizeRefId',
|
||||
@@ -69,7 +72,7 @@ export class UncategorizeCashflowTransactionService {
|
||||
} as ICashflowTransactionUncategorizingPayload,
|
||||
);
|
||||
// Removes the ref relation with the related transaction.
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.whereIn('id', oldUncategoirzedTransactionsIds)
|
||||
.patch({
|
||||
@@ -78,7 +81,7 @@ export class UncategorizeCashflowTransactionService {
|
||||
categorizeRefType: null,
|
||||
});
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.whereIn('id', oldUncategoirzedTransactionsIds);
|
||||
// Triggers `onTransactionUncategorized` event.
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ImportableContext } from '../../Import/interfaces';
|
||||
import { BankTransactionsSampleData } from '../../BankingTransactions/constants';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { CreateUncategorizedTransactionDTO } from '../types/BankingCategorize.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class UncategorizedTransactionsImportable extends Importable {
|
||||
@@ -15,14 +16,14 @@ export class UncategorizedTransactionsImportable extends Importable {
|
||||
private readonly createUncategorizedTransaction: CreateUncategorizedTransactionService,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Passing the sheet DTO to create uncategorized transaction.
|
||||
* @param {CreateUncategorizedTransactionDTO,} createDTO
|
||||
* @param {CreateUncategorizedTransactionDTO,} createDTO
|
||||
* @param {Knex.Transaction} trx
|
||||
*/
|
||||
public async importable(
|
||||
@@ -77,7 +78,7 @@ export class UncategorizedTransactionsImportable extends Importable {
|
||||
*/
|
||||
public async validateParams(params: Record<string, any>): Promise<void> {
|
||||
if (params.accountId) {
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query()
|
||||
.findById(params.accountId)
|
||||
.throwIfNotFound({});
|
||||
|
||||
@@ -28,12 +28,12 @@ const models = [RegisterTenancyModel(MatchedBankTransaction)];
|
||||
@Module({
|
||||
controllers: [BankingMatchingController],
|
||||
imports: [
|
||||
...models,
|
||||
BillPaymentsModule,
|
||||
BankingTransactionsModule,
|
||||
PaymentsReceivedModule,
|
||||
],
|
||||
providers: [
|
||||
...models,
|
||||
ValidateTransactionMatched,
|
||||
MatchBankTransactions,
|
||||
MatchTransactionsTypes,
|
||||
|
||||
@@ -20,6 +20,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class MatchBankTransactions {
|
||||
@@ -29,7 +30,9 @@ export class MatchBankTransactions {
|
||||
private readonly matchedBankTransactions: MatchTransactionsTypes,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -46,7 +49,7 @@ export class MatchBankTransactions {
|
||||
|
||||
// Validates the uncategorized transaction existance.
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.whereIn('id', uncategorizedTransactionIds)
|
||||
.withGraphFetched('matchedBankTransactions')
|
||||
|
||||
@@ -4,6 +4,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { MatchedBankTransaction } from '../models/MatchedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class UnmatchMatchedBankTransaction {
|
||||
@@ -12,7 +13,9 @@ export class UnmatchMatchedBankTransaction {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(MatchedBankTransaction.name)
|
||||
private readonly matchedBankTransactionModel: typeof MatchedBankTransaction,
|
||||
private readonly matchedBankTransactionModel: TenantModelProxy<
|
||||
typeof MatchedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -29,7 +32,7 @@ export class UnmatchMatchedBankTransaction {
|
||||
trx,
|
||||
} as IBankTransactionUnmatchingEventPayload);
|
||||
|
||||
await this.matchedBankTransactionModel
|
||||
await this.matchedBankTransactionModel()
|
||||
.query(trx)
|
||||
.where('uncategorizedTransactionId', uncategorizedTransactionId)
|
||||
.delete();
|
||||
|
||||
@@ -3,12 +3,15 @@ import { ERRORS } from '../types';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { MatchedBankTransaction } from '../models/MatchedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ValidateTransactionMatched {
|
||||
constructor(
|
||||
@Inject(MatchedBankTransaction.name)
|
||||
private readonly matchedBankTransactionModel: typeof MatchedBankTransaction,
|
||||
private readonly matchedBankTransactionModel: TenantModelProxy<
|
||||
typeof MatchedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -20,13 +23,15 @@ export class ValidateTransactionMatched {
|
||||
public async validateTransactionNoMatchLinking(
|
||||
referenceType: string,
|
||||
referenceId: number,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const foundMatchedTransaction =
|
||||
await this.matchedBankTransactionModel.query(trx).findOne({
|
||||
const foundMatchedTransaction = await this.matchedBankTransactionModel()
|
||||
.query(trx)
|
||||
.findOne({
|
||||
referenceType,
|
||||
referenceId,
|
||||
});
|
||||
|
||||
if (foundMatchedTransaction) {
|
||||
throw new ServiceError(ERRORS.CANNOT_DELETE_TRANSACTION_MATCHED);
|
||||
}
|
||||
|
||||
@@ -8,15 +8,18 @@ import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DecrementUncategorizedTransactionOnMatchingSubscriber {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -29,14 +32,14 @@ export class DecrementUncategorizedTransactionOnMatchingSubscriber {
|
||||
trx,
|
||||
}: IBankTransactionMatchedEventPayload) {
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel.query().whereIn(
|
||||
'id',
|
||||
uncategorizedTransactionIds
|
||||
);
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.whereIn('id', uncategorizedTransactionIds);
|
||||
|
||||
await PromisePool.withConcurrency(1)
|
||||
.for(uncategorizedTransactions)
|
||||
.process(async (transaction) => {
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.findById(transaction.accountId)
|
||||
.decrement('uncategorizedTransactions', 1);
|
||||
@@ -52,11 +55,11 @@ export class DecrementUncategorizedTransactionOnMatchingSubscriber {
|
||||
uncategorizedTransactionId,
|
||||
trx,
|
||||
}: IBankTransactionUnmatchedEventPayload) {
|
||||
const transaction =
|
||||
await this.uncategorizedBankTransactionModel.query().findById(
|
||||
uncategorizedTransactionId
|
||||
);
|
||||
await this.accountModel
|
||||
const transaction = await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId);
|
||||
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.findById(transaction.accountId)
|
||||
.increment('uncategorizedTransactions', 1);
|
||||
|
||||
@@ -3,7 +3,10 @@ import * as moment from 'moment';
|
||||
import { first, sumBy } from 'lodash';
|
||||
import { PromisePool } from '@supercharge/promise-pool';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { GetMatchedTransactionsFilter, MatchedTransactionsPOJO } from '../types';
|
||||
import {
|
||||
GetMatchedTransactionsFilter,
|
||||
MatchedTransactionsPOJO,
|
||||
} from '../types';
|
||||
import { GetMatchedTransactionsByExpenses } from './GetMatchedTransactionsByExpenses';
|
||||
import { GetMatchedTransactionsByBills } from './GetMatchedTransactionsByBills.service';
|
||||
import { GetMatchedTransactionsByManualJournals } from './GetMatchedTransactionsByManualJournals.service';
|
||||
@@ -11,6 +14,7 @@ import { GetMatchedTransactionsByCashflow } from './GetMatchedTransactionsByCash
|
||||
import { GetMatchedTransactionsByInvoices } from './GetMatchedTransactionsByInvoices.service';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { sortClosestMatchTransactions } from '../_utils';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactions {
|
||||
@@ -22,7 +26,9 @@ export class GetMatchedTransactions {
|
||||
private readonly getMatchedCashflowService: GetMatchedTransactionsByCashflow,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -46,10 +52,11 @@ export class GetMatchedTransactions {
|
||||
*/
|
||||
public async getMatchedTransactions(
|
||||
uncategorizedTransactionIds: Array<number>,
|
||||
filter: GetMatchedTransactionsFilter
|
||||
filter: GetMatchedTransactionsFilter,
|
||||
): Promise<MatchedTransactionsPOJO> {
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel.query()
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.whereIn('id', uncategorizedTransactionIds)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -66,7 +73,7 @@ export class GetMatchedTransactions {
|
||||
});
|
||||
const { perfectMatches, possibleMatches } = this.groupMatchedResults(
|
||||
uncategorizedTransactions,
|
||||
matchedTransactions
|
||||
matchedTransactions,
|
||||
);
|
||||
return {
|
||||
perfectMatches,
|
||||
@@ -84,7 +91,7 @@ export class GetMatchedTransactions {
|
||||
*/
|
||||
private groupMatchedResults(
|
||||
uncategorizedTransactions: Array<any>,
|
||||
matchedTransactions
|
||||
matchedTransactions,
|
||||
): MatchedTransactionsPOJO {
|
||||
const results = R.compose(R.flatten)(matchedTransactions?.results);
|
||||
|
||||
@@ -97,7 +104,7 @@ export class GetMatchedTransactions {
|
||||
const perfectMatches = R.filter(
|
||||
(match) =>
|
||||
match.amount === amount && moment(match.date).isSame(date, 'day'),
|
||||
closestResullts
|
||||
closestResullts,
|
||||
);
|
||||
const possibleMatches = R.difference(closestResullts, perfectMatches);
|
||||
const totalPending = sumBy(uncategorizedTransactions, 'amount');
|
||||
|
||||
@@ -13,6 +13,7 @@ import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectab
|
||||
import { IBillPaymentDTO } from '@/modules/BillPayments/types/BillPayments.types';
|
||||
import { Bill } from '@/modules/Bills/models/Bill';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType {
|
||||
@@ -21,10 +22,12 @@ export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -34,23 +37,23 @@ export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType
|
||||
* @param {number} tenantId -
|
||||
* @param {GetMatchedTransactionsFilter} filter -
|
||||
*/
|
||||
public async getMatchedTransactions(
|
||||
filter: GetMatchedTransactionsFilter,
|
||||
) {
|
||||
public async getMatchedTransactions(filter: GetMatchedTransactionsFilter) {
|
||||
// Retrieves the bill matches.
|
||||
const bills = await Bill.query().onBuild((q) => {
|
||||
q.withGraphJoined('matchedBankTransaction');
|
||||
q.whereNull('matchedBankTransaction.id');
|
||||
q.modify('published');
|
||||
const bills = await this.billModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
q.withGraphJoined('matchedBankTransaction');
|
||||
q.whereNull('matchedBankTransaction.id');
|
||||
q.modify('published');
|
||||
|
||||
if (filter.fromDate) {
|
||||
q.where('billDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
q.where('billDate', '<=', filter.toDate);
|
||||
}
|
||||
q.orderBy('billDate', 'DESC');
|
||||
});
|
||||
if (filter.fromDate) {
|
||||
q.where('billDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
q.where('billDate', '<=', filter.toDate);
|
||||
}
|
||||
q.orderBy('billDate', 'DESC');
|
||||
});
|
||||
|
||||
return this.transformer.transform(
|
||||
bills,
|
||||
@@ -67,7 +70,7 @@ export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType
|
||||
public async getMatchedTransaction(
|
||||
transactionId: number,
|
||||
): Promise<MatchedTransactionPOJO> {
|
||||
const bill = await this.billModel
|
||||
const bill = await this.billModel()
|
||||
.query()
|
||||
.findById(transactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -97,12 +100,12 @@ export class GetMatchedTransactionsByBills extends GetMatchedTransactionsByType
|
||||
);
|
||||
const uncategorizedTransactionId = first(uncategorizedTransactionIds);
|
||||
const uncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const bill = await this.billModel
|
||||
const bill = await this.billModel()
|
||||
.query(trx)
|
||||
.findById(matchTransactionDTO.referenceId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -4,6 +4,7 @@ import { GetMatchedTransactionsFilter } from '../types';
|
||||
import { BankTransaction } from '@/modules/BankingTransactions/models/BankTransaction';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByType {
|
||||
@@ -11,7 +12,9 @@ export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByTy
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(BankTransaction.name)
|
||||
private readonly bankTransactionModel: typeof BankTransaction,
|
||||
private readonly bankTransactionModel: TenantModelProxy<
|
||||
typeof BankTransaction
|
||||
>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -25,7 +28,7 @@ export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByTy
|
||||
async getMatchedTransactions(
|
||||
filter: Omit<GetMatchedTransactionsFilter, 'transactionType'>,
|
||||
) {
|
||||
const transactions = await this.bankTransactionModel
|
||||
const transactions = await this.bankTransactionModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
// Not matched to bank transaction.
|
||||
@@ -60,7 +63,7 @@ export class GetMatchedTransactionsByCashflow extends GetMatchedTransactionsByTy
|
||||
* @returns
|
||||
*/
|
||||
async getMatchedTransaction(transactionId: number) {
|
||||
const transactions = await this.bankTransactionModel
|
||||
const transactions = await this.bankTransactionModel()
|
||||
.query()
|
||||
.findById(transactionId)
|
||||
.withGraphJoined('matchedBankTransaction')
|
||||
|
||||
@@ -4,6 +4,7 @@ import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType';
|
||||
import { GetMatchedTransactionExpensesTransformer } from './GetMatchedTransactionExpensesTransformer';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { Expense } from '@/modules/Expenses/models/Expense.model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactionsByExpenses extends GetMatchedTransactionsByType {
|
||||
@@ -11,7 +12,7 @@ export class GetMatchedTransactionsByExpenses extends GetMatchedTransactionsByTy
|
||||
protected readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(Expense.name)
|
||||
protected readonly expenseModel: typeof Expense,
|
||||
protected readonly expenseModel: TenantModelProxy<typeof Expense>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -24,28 +25,30 @@ export class GetMatchedTransactionsByExpenses extends GetMatchedTransactionsByTy
|
||||
*/
|
||||
async getMatchedTransactions(filter: GetMatchedTransactionsFilter) {
|
||||
// Retrieve the expense matches.
|
||||
const expenses = await this.expenseModel.query().onBuild((query) => {
|
||||
// Filter out the not matched to bank transactions.
|
||||
query.withGraphJoined('matchedBankTransaction');
|
||||
query.whereNull('matchedBankTransaction.id');
|
||||
const expenses = await this.expenseModel()
|
||||
.query()
|
||||
.onBuild((query) => {
|
||||
// Filter out the not matched to bank transactions.
|
||||
query.withGraphJoined('matchedBankTransaction');
|
||||
query.whereNull('matchedBankTransaction.id');
|
||||
|
||||
// Filter the published onyl
|
||||
query.modify('filterByPublished');
|
||||
// Filter the published onyl
|
||||
query.modify('filterByPublished');
|
||||
|
||||
if (filter.fromDate) {
|
||||
query.where('paymentDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
query.where('paymentDate', '<=', filter.toDate);
|
||||
}
|
||||
if (filter.minAmount) {
|
||||
query.where('totalAmount', '>=', filter.minAmount);
|
||||
}
|
||||
if (filter.maxAmount) {
|
||||
query.where('totalAmount', '<=', filter.maxAmount);
|
||||
}
|
||||
query.orderBy('paymentDate', 'DESC');
|
||||
});
|
||||
if (filter.fromDate) {
|
||||
query.where('paymentDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
query.where('paymentDate', '<=', filter.toDate);
|
||||
}
|
||||
if (filter.minAmount) {
|
||||
query.where('totalAmount', '>=', filter.minAmount);
|
||||
}
|
||||
if (filter.maxAmount) {
|
||||
query.where('totalAmount', '<=', filter.maxAmount);
|
||||
}
|
||||
query.orderBy('paymentDate', 'DESC');
|
||||
});
|
||||
return this.transformer.transform(
|
||||
expenses,
|
||||
new GetMatchedTransactionExpensesTransformer(),
|
||||
@@ -61,7 +64,7 @@ export class GetMatchedTransactionsByExpenses extends GetMatchedTransactionsByTy
|
||||
public async getMatchedTransaction(
|
||||
transactionId: number,
|
||||
): Promise<MatchedTransactionPOJO> {
|
||||
const expense = await this.expenseModel
|
||||
const expense = await this.expenseModel()
|
||||
.query()
|
||||
.findById(transactionId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -14,6 +14,7 @@ import { SaleInvoice } from '@/modules/SaleInvoices/models/SaleInvoice';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { IPaymentReceivedCreateDTO } from '@/modules/PaymentReceived/types/PaymentReceived.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByType {
|
||||
@@ -22,10 +23,12 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
||||
private readonly createPaymentReceivedService: CreatePaymentReceivedService,
|
||||
|
||||
@Inject(SaleInvoice.name)
|
||||
private readonly saleInvoiceModel: typeof SaleInvoice,
|
||||
private readonly saleInvoiceModel: TenantModelProxy<typeof SaleInvoice>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@@ -36,27 +39,29 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
||||
* @returns {Promise<MatchedTransactionsPOJO>}
|
||||
*/
|
||||
public async getMatchedTransactions(
|
||||
filter: GetMatchedTransactionsFilter
|
||||
filter: GetMatchedTransactionsFilter,
|
||||
): Promise<MatchedTransactionsPOJO> {
|
||||
// Retrieve the invoices that not matched, unpaid.
|
||||
const invoices = await this.saleInvoiceModel.query().onBuild((q) => {
|
||||
q.withGraphJoined('matchedBankTransaction');
|
||||
q.whereNull('matchedBankTransaction.id');
|
||||
q.modify('unpaid');
|
||||
q.modify('published');
|
||||
const invoices = await this.saleInvoiceModel()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
q.withGraphJoined('matchedBankTransaction');
|
||||
q.whereNull('matchedBankTransaction.id');
|
||||
q.modify('unpaid');
|
||||
q.modify('published');
|
||||
|
||||
if (filter.fromDate) {
|
||||
q.where('invoiceDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
q.where('invoiceDate', '<=', filter.toDate);
|
||||
}
|
||||
q.orderBy('invoiceDate', 'DESC');
|
||||
});
|
||||
if (filter.fromDate) {
|
||||
q.where('invoiceDate', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
q.where('invoiceDate', '<=', filter.toDate);
|
||||
}
|
||||
q.orderBy('invoiceDate', 'DESC');
|
||||
});
|
||||
|
||||
return this.transformer.transform(
|
||||
invoices,
|
||||
new GetMatchedTransactionInvoicesTransformer()
|
||||
new GetMatchedTransactionInvoicesTransformer(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -67,13 +72,15 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
||||
* @returns {Promise<MatchedTransactionPOJO>}
|
||||
*/
|
||||
public async getMatchedTransaction(
|
||||
transactionId: number
|
||||
transactionId: number,
|
||||
): Promise<MatchedTransactionPOJO> {
|
||||
const invoice = await this.saleInvoiceModel.query().findById(transactionId);
|
||||
const invoice = await this.saleInvoiceModel()
|
||||
.query()
|
||||
.findById(transactionId);
|
||||
|
||||
return this.transformer.transform(
|
||||
invoice,
|
||||
new GetMatchedTransactionInvoicesTransformer()
|
||||
new GetMatchedTransactionInvoicesTransformer(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,16 +94,17 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
||||
public async createMatchedTransaction(
|
||||
uncategorizedTransactionIds: Array<number>,
|
||||
matchTransactionDTO: IMatchTransactionDTO,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
await super.createMatchedTransaction(
|
||||
uncategorizedTransactionIds,
|
||||
matchTransactionDTO,
|
||||
trx
|
||||
trx,
|
||||
);
|
||||
const uncategorizedTransactionId = first(uncategorizedTransactionIds);
|
||||
const uncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel.query(trx)
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -119,14 +127,19 @@ export class GetMatchedTransactionsByInvoices extends GetMatchedTransactionsByTy
|
||||
branchId: invoice.branchId,
|
||||
};
|
||||
// Create a payment received associated to the matched invoice.
|
||||
const paymentReceived = await this.createPaymentReceivedService.createPaymentReceived(
|
||||
createPaymentReceivedDTO,
|
||||
trx
|
||||
);
|
||||
const paymentReceived =
|
||||
await this.createPaymentReceivedService.createPaymentReceived(
|
||||
createPaymentReceivedDTO,
|
||||
trx,
|
||||
);
|
||||
// Link the create payment received with matched invoice transaction.
|
||||
await super.createMatchedTransaction(uncategorizedTransactionIds, {
|
||||
referenceType: 'PaymentReceive',
|
||||
referenceId: paymentReceived.id,
|
||||
}, trx)
|
||||
await super.createMatchedTransaction(
|
||||
uncategorizedTransactionIds,
|
||||
{
|
||||
referenceType: 'PaymentReceive',
|
||||
referenceId: paymentReceived.id,
|
||||
},
|
||||
trx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { GetMatchedTransactionsByType } from './GetMatchedTransactionsByType';
|
||||
import { GetMatchedTransactionsFilter } from '../types';
|
||||
import { ManualJournal } from '@/modules/ManualJournals/models/ManualJournal';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetMatchedTransactionsByManualJournals extends GetMatchedTransactionsByType {
|
||||
@@ -11,14 +12,13 @@ export class GetMatchedTransactionsByManualJournals extends GetMatchedTransactio
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(ManualJournal.name)
|
||||
private readonly manualJournalModel: typeof ManualJournal,
|
||||
private readonly manualJournalModel: TenantModelProxy<typeof ManualJournal>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the matched transactions of manual journals.
|
||||
* @param {number} tenantId
|
||||
* @param {GetMatchedTransactionsFilter} filter
|
||||
* @returns
|
||||
*/
|
||||
@@ -28,27 +28,29 @@ export class GetMatchedTransactionsByManualJournals extends GetMatchedTransactio
|
||||
// @todo: get the account id from the filter
|
||||
const accountId = 1000;
|
||||
|
||||
const manualJournals = await this.manualJournalModel.query().onBuild((query) => {
|
||||
query.withGraphJoined('matchedBankTransaction');
|
||||
query.whereNull('matchedBankTransaction.id');
|
||||
const manualJournals = await this.manualJournalModel()
|
||||
.query()
|
||||
.onBuild((query) => {
|
||||
query.withGraphJoined('matchedBankTransaction');
|
||||
query.whereNull('matchedBankTransaction.id');
|
||||
|
||||
query.withGraphJoined('entries');
|
||||
query.where('entries.accountId', accountId);
|
||||
query.modify('filterByPublished');
|
||||
query.withGraphJoined('entries');
|
||||
query.where('entries.accountId', accountId);
|
||||
query.modify('filterByPublished');
|
||||
|
||||
if (filter.fromDate) {
|
||||
query.where('date', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
query.where('date', '<=', filter.toDate);
|
||||
}
|
||||
if (filter.minAmount) {
|
||||
query.where('amount', '>=', filter.minAmount);
|
||||
}
|
||||
if (filter.maxAmount) {
|
||||
query.where('amount', '<=', filter.maxAmount);
|
||||
}
|
||||
});
|
||||
if (filter.fromDate) {
|
||||
query.where('date', '>=', filter.fromDate);
|
||||
}
|
||||
if (filter.toDate) {
|
||||
query.where('date', '<=', filter.toDate);
|
||||
}
|
||||
if (filter.minAmount) {
|
||||
query.where('amount', '>=', filter.minAmount);
|
||||
}
|
||||
if (filter.maxAmount) {
|
||||
query.where('amount', '<=', filter.maxAmount);
|
||||
}
|
||||
});
|
||||
return this.transformer.transform(
|
||||
manualJournals,
|
||||
new GetMatchedTransactionManualJournalsTransformer(),
|
||||
@@ -62,7 +64,8 @@ export class GetMatchedTransactionsByManualJournals extends GetMatchedTransactio
|
||||
* @returns
|
||||
*/
|
||||
public async getMatchedTransaction(transactionId: number) {
|
||||
const manualJournal = await this.manualJournalModel.query()
|
||||
const manualJournal = await this.manualJournalModel()
|
||||
.query()
|
||||
.findById(transactionId)
|
||||
.whereNotExists(ManualJournal.relatedQuery('matchedBankTransaction'))
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -8,10 +8,13 @@ import {
|
||||
import PromisePool from '@supercharge/promise-pool';
|
||||
import { MatchedBankTransaction } from '../models/MatchedBankTransaction';
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
export abstract class GetMatchedTransactionsByType {
|
||||
@Inject(MatchedBankTransaction.name)
|
||||
private readonly matchedBankTransactionModel: typeof MatchedBankTransaction;
|
||||
private readonly matchedBankTransactionModel: TenantModelProxy<
|
||||
typeof MatchedBankTransaction
|
||||
>;
|
||||
|
||||
/**
|
||||
* Retrieves the matched transactions.
|
||||
@@ -20,10 +23,10 @@ export abstract class GetMatchedTransactionsByType {
|
||||
* @returns {Promise<MatchedTransactionsPOJO>}
|
||||
*/
|
||||
public async getMatchedTransactions(
|
||||
filter: GetMatchedTransactionsFilter
|
||||
filter: GetMatchedTransactionsFilter,
|
||||
): Promise<MatchedTransactionsPOJO> {
|
||||
throw new Error(
|
||||
'The `getMatchedTransactions` method is not defined for the transaction type.'
|
||||
'The `getMatchedTransactions` method is not defined for the transaction type.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,10 +37,10 @@ export abstract class GetMatchedTransactionsByType {
|
||||
* @returns {Promise<MatchedTransactionPOJO>}
|
||||
*/
|
||||
public async getMatchedTransaction(
|
||||
transactionId: number
|
||||
transactionId: number,
|
||||
): Promise<MatchedTransactionPOJO> {
|
||||
throw new Error(
|
||||
'The `getMatchedTransaction` method is not defined for the transaction type.'
|
||||
'The `getMatchedTransaction` method is not defined for the transaction type.',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -51,12 +54,12 @@ export abstract class GetMatchedTransactionsByType {
|
||||
public async createMatchedTransaction(
|
||||
uncategorizedTransactionIds: Array<number>,
|
||||
matchTransactionDTO: IMatchTransactionDTO,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
await PromisePool.withConcurrency(2)
|
||||
.for(uncategorizedTransactionIds)
|
||||
.process(async (uncategorizedTransactionId) => {
|
||||
await this.matchedBankTransactionModel.query(trx).insert({
|
||||
await this.matchedBankTransactionModel().query(trx).insert({
|
||||
uncategorizedTransactionId,
|
||||
referenceType: matchTransactionDTO.referenceType,
|
||||
referenceId: matchTransactionDTO.referenceId,
|
||||
|
||||
@@ -16,10 +16,7 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { InjectSystemModel } from '../System/SystemModels/SystemModels.module';
|
||||
import { SystemPlaidItem } from './models/SystemPlaidItem';
|
||||
|
||||
const models = [
|
||||
RegisterTenancyModel(PlaidItem),
|
||||
InjectSystemModel(SystemPlaidItem),
|
||||
];
|
||||
const models = [RegisterTenancyModel(PlaidItem)];
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -27,9 +24,10 @@ const models = [
|
||||
AccountsModule,
|
||||
BankingCategorizeModule,
|
||||
BankingTransactionsModule,
|
||||
...models,
|
||||
],
|
||||
providers: [
|
||||
...models,
|
||||
InjectSystemModel(SystemPlaidItem),
|
||||
PlaidItemService,
|
||||
PlaidUpdateTransactions,
|
||||
PlaidSyncDb,
|
||||
|
||||
@@ -6,7 +6,11 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { SystemPlaidItem } from '../models/SystemPlaidItem';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { IPlaidItemCreatedEventPayload, PlaidItemDTO } from '../types/BankingPlaid.types';
|
||||
import {
|
||||
IPlaidItemCreatedEventPayload,
|
||||
PlaidItemDTO,
|
||||
} from '../types/BankingPlaid.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class PlaidItemService {
|
||||
@@ -15,10 +19,12 @@ export class PlaidItemService {
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(SystemPlaidItem.name)
|
||||
private readonly systemPlaidItemModel: typeof SystemPlaidItem,
|
||||
private readonly systemPlaidItemModel: TenantModelProxy<
|
||||
typeof SystemPlaidItem
|
||||
>,
|
||||
|
||||
@Inject(PlaidItem.name)
|
||||
private readonly plaidItemModel: typeof PlaidItem,
|
||||
private readonly plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
|
||||
@Inject(PLAID_CLIENT)
|
||||
private readonly plaidClient: PlaidApi,
|
||||
@@ -44,14 +50,14 @@ export class PlaidItemService {
|
||||
const plaidItemId = response.data.item_id;
|
||||
|
||||
// Store the Plaid item metadata on tenant scope.
|
||||
const plaidItem = await this.plaidItemModel.query().insertAndFetch({
|
||||
const plaidItem = await this.plaidItemModel().query().insertAndFetch({
|
||||
tenantId,
|
||||
plaidAccessToken,
|
||||
plaidItemId,
|
||||
plaidInstitutionId: institutionId,
|
||||
});
|
||||
// Stores the Plaid item id on system scope.
|
||||
await this.systemPlaidItemModel.query().insert({ tenantId, plaidItemId });
|
||||
await this.systemPlaidItemModel().query().insert({ tenantId, plaidItemId });
|
||||
|
||||
// Triggers `onPlaidItemCreated` event.
|
||||
await this.eventEmitter.emitAsync(events.plaid.onItemCreated, {
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IPlaidTransactionsSyncedEventPayload } from '../types/BankingPlaid.type
|
||||
import { UncategorizedBankTransaction } from '../../BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CreateUncategorizedTransactionService } from '@/modules/BankingCategorize/commands/CreateUncategorizedTransaction.service';
|
||||
import { TenantModelProxy } from '../../System/models/TenantBaseModel';
|
||||
|
||||
const CONCURRENCY_ASYNC = 10;
|
||||
|
||||
@@ -36,13 +37,15 @@ export class PlaidSyncDb {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(PlaidItemModel.name)
|
||||
private readonly plaidItemModel: typeof PlaidItemModel,
|
||||
private readonly plaidItemModel: TenantModelProxy<typeof PlaidItemModel>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -55,7 +58,7 @@ export class PlaidSyncDb {
|
||||
createBankAccountDTO: IAccountCreateDTO,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const plaidAccount = await this.accountModel
|
||||
const plaidAccount = await this.accountModel()
|
||||
.query(trx)
|
||||
.findOne('plaidAccountId', createBankAccountDTO.plaidAccountId);
|
||||
// Can't continue if the Plaid account is already created.
|
||||
@@ -102,7 +105,7 @@ export class PlaidSyncDb {
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
const batch = uniqid();
|
||||
const cashflowAccount = await this.accountModel
|
||||
const cashflowAccount = await this.accountModel()
|
||||
.query(trx)
|
||||
.findOne({ plaidAccountId })
|
||||
.throwIfNotFound();
|
||||
@@ -165,7 +168,7 @@ export class PlaidSyncDb {
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.whereIn('plaidTransactionId', plaidTransactionsIds);
|
||||
const uncategorizedTransactionsIds = uncategorizedTransactions.map(
|
||||
@@ -193,7 +196,7 @@ export class PlaidSyncDb {
|
||||
lastCursor: string,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
await this.plaidItemModel
|
||||
await this.plaidItemModel()
|
||||
.query(trx)
|
||||
.findOne({ plaidItemId })
|
||||
.patch({ lastCursor });
|
||||
@@ -208,7 +211,7 @@ export class PlaidSyncDb {
|
||||
plaidAccountIds: string[],
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.whereIn('plaid_account_id', plaidAccountIds)
|
||||
.patch({
|
||||
@@ -227,7 +230,7 @@ export class PlaidSyncDb {
|
||||
isFeedsActive: boolean = true,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
await this.accountModel
|
||||
await this.accountModel()
|
||||
.query(trx)
|
||||
.whereIn('plaid_account_id', plaidAccountIds)
|
||||
.patch({
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
RemovedTransaction,
|
||||
} from 'plaid';
|
||||
import { PLAID_CLIENT } from '@/modules/Plaid/Plaid.module';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class PlaidUpdateTransactions {
|
||||
@@ -19,7 +20,7 @@ export class PlaidUpdateTransactions {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(PlaidItem.name)
|
||||
private readonly plaidItemModel: typeof PlaidItem,
|
||||
private readonly plaidItemModel: TenantModelProxy<typeof PlaidItem>,
|
||||
|
||||
@Inject(PLAID_CLIENT)
|
||||
private readonly plaidClient: PlaidApi,
|
||||
@@ -105,9 +106,10 @@ export class PlaidUpdateTransactions {
|
||||
): Promise<PlaidFetchedTransactionsUpdates> {
|
||||
// the transactions endpoint is paginated, so we may need to hit it multiple times to
|
||||
// retrieve all available transactions.
|
||||
const plaidItem = await this.plaidItemModel
|
||||
const plaidItem = await this.plaidItemModel()
|
||||
.query()
|
||||
.findOne('plaidItemId', plaidItemId);
|
||||
|
||||
if (!plaidItem) {
|
||||
throw new Error('The given Plaid item id is not found.');
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@ import { BankRulesModule } from '../BankRules/BankRules.module';
|
||||
const models = [RegisterTenancyModel(RecognizedBankTransaction)];
|
||||
|
||||
@Module({
|
||||
imports: [BankingTransactionsModule, forwardRef(() => BankRulesModule)],
|
||||
providers: [
|
||||
imports: [
|
||||
BankingTransactionsModule,
|
||||
forwardRef(() => BankRulesModule),
|
||||
...models,
|
||||
],
|
||||
providers: [
|
||||
GetAutofillCategorizeTransactionService,
|
||||
RevertRecognizedTransactionsService,
|
||||
RecognizeTranasctionsService,
|
||||
|
||||
@@ -8,18 +8,23 @@ import { BankRule } from '@/modules/BankRules/models/BankRule';
|
||||
import { RecognizedBankTransaction } from '../models/RecognizedBankTransaction';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { transformToMapBy } from '@/utils/transform-to-map-by';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class RecognizeTranasctionsService {
|
||||
constructor(
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedCashflowTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedCashflowTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
|
||||
@Inject(RecognizedBankTransaction.name)
|
||||
private readonly recognizedBankTransactionModel: typeof RecognizedBankTransaction,
|
||||
private readonly recognizedBankTransactionModel: TenantModelProxy<
|
||||
typeof RecognizedBankTransaction
|
||||
>,
|
||||
|
||||
@Inject(BankRule.name)
|
||||
private readonly bankRuleModel: typeof BankRule,
|
||||
private readonly bankRuleModel: TenantModelProxy<typeof BankRule>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -33,7 +38,7 @@ export class RecognizeTranasctionsService {
|
||||
transaction: UncategorizedBankTransaction,
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const recognizedTransaction = await this.recognizedBankTransactionModel
|
||||
const recognizedTransaction = await this.recognizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.insert({
|
||||
bankRuleId: bankRule.id,
|
||||
@@ -43,7 +48,8 @@ export class RecognizeTranasctionsService {
|
||||
assignedPayee: bankRule.assignPayee,
|
||||
assignedMemo: bankRule.assignMemo,
|
||||
});
|
||||
await this.uncategorizedCashflowTransactionModel
|
||||
|
||||
await this.uncategorizedCashflowTransactionModel()
|
||||
.query(trx)
|
||||
.findById(transaction.id)
|
||||
.patch({
|
||||
@@ -52,7 +58,7 @@ export class RecognizeTranasctionsService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Regonized the uncategorized transactions.
|
||||
* Recognized the uncategorized transactions.
|
||||
* @param {number|Array<number>} ruleId - The target rule id/ids.
|
||||
* @param {RecognizeTransactionsCriteria}
|
||||
* @param {Knex.Transaction} trx -
|
||||
@@ -63,7 +69,7 @@ export class RecognizeTranasctionsService {
|
||||
trx?: Knex.Transaction,
|
||||
) {
|
||||
const uncategorizedTranasctions =
|
||||
await this.uncategorizedCashflowTransactionModel
|
||||
await this.uncategorizedCashflowTransactionModel()
|
||||
.query(trx)
|
||||
.onBuild((query) => {
|
||||
query.modify('notRecognized');
|
||||
@@ -78,14 +84,17 @@ export class RecognizeTranasctionsService {
|
||||
}
|
||||
});
|
||||
|
||||
const bankRules = await this.bankRuleModel.query(trx).onBuild((q) => {
|
||||
const rulesIds = !isEmpty(ruleId) ? castArray(ruleId) : [];
|
||||
const bankRules = await this.bankRuleModel()
|
||||
.query(trx)
|
||||
.onBuild((q) => {
|
||||
const rulesIds = !isEmpty(ruleId) ? castArray(ruleId) : [];
|
||||
|
||||
if (rulesIds?.length > 0) {
|
||||
q.whereIn('id', rulesIds);
|
||||
}
|
||||
q.withGraphFetched('conditions');
|
||||
});
|
||||
|
||||
if (rulesIds?.length > 0) {
|
||||
q.whereIn('id', rulesIds);
|
||||
}
|
||||
q.withGraphFetched('conditions');
|
||||
});
|
||||
const bankRulesByAccountId = transformToMapBy(
|
||||
bankRules,
|
||||
'applyIfAccountId',
|
||||
|
||||
@@ -3,6 +3,7 @@ import { castArray, first, uniq } from 'lodash';
|
||||
import { GetAutofillCategorizeTransctionTransformer } from './GetAutofillCategorizeTransactionTransformer';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetAutofillCategorizeTransactionService {
|
||||
@@ -10,7 +11,9 @@ export class GetAutofillCategorizeTransactionService {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -18,13 +21,14 @@ export class GetAutofillCategorizeTransactionService {
|
||||
* @param {Array<number> | number} uncategorizeTransactionsId - Uncategorized transactions ids.
|
||||
*/
|
||||
public async getAutofillCategorizeTransaction(
|
||||
uncategorizeTransactionsId: Array<number> | number
|
||||
uncategorizeTransactionsId: Array<number> | number,
|
||||
) {
|
||||
const uncategorizeTransactionsIds = uniq(
|
||||
castArray(uncategorizeTransactionsId)
|
||||
castArray(uncategorizeTransactionsId),
|
||||
);
|
||||
const uncategorizedTransactions =
|
||||
await this.uncategorizedBankTransactionModel.query()
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.whereIn('id', uncategorizeTransactionsIds)
|
||||
.withGraphFetched('recognizedTransaction.assignAccount')
|
||||
.withGraphFetched('recognizedTransaction.bankRule')
|
||||
@@ -36,7 +40,7 @@ export class GetAutofillCategorizeTransactionService {
|
||||
{
|
||||
uncategorizedTransactions,
|
||||
firstUncategorizedTransaction: first(uncategorizedTransactions),
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ const models = [
|
||||
LedgerModule,
|
||||
BranchesModule,
|
||||
DynamicListModule,
|
||||
...models,
|
||||
],
|
||||
controllers: [BankingTransactionsController],
|
||||
providers: [
|
||||
@@ -56,7 +57,6 @@ const models = [
|
||||
CommandBankTransactionValidator,
|
||||
BranchTransactionDTOTransformer,
|
||||
RemovePendingUncategorizedTransaction,
|
||||
...models,
|
||||
],
|
||||
exports: [...models, RemovePendingUncategorizedTransaction],
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
ICommandCashflowCreatedPayload,
|
||||
ICommandCashflowCreatingPayload,
|
||||
} from '../types/BankingTransactions.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateBankTransactionService {
|
||||
@@ -28,10 +29,10 @@ export class CreateBankTransactionService {
|
||||
private branchDTOTransform: BranchTransactionDTOTransformer,
|
||||
|
||||
@Inject(BankTransaction.name)
|
||||
private bankTransactionModel: typeof BankTransaction,
|
||||
private bankTransactionModel: TenantModelProxy<typeof BankTransaction>,
|
||||
|
||||
@Inject(Account.name)
|
||||
private accountModel: typeof Account,
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -118,13 +119,13 @@ export class CreateBankTransactionService {
|
||||
userId?: number,
|
||||
): Promise<BankTransaction> => {
|
||||
// Retrieves the cashflow account or throw not found error.
|
||||
const cashflowAccount = await this.accountModel
|
||||
const cashflowAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(newTransactionDTO.cashflowAccountId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Retrieves the credit account or throw not found error.
|
||||
const creditAccount = await this.accountModel
|
||||
const creditAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(newTransactionDTO.creditAccountId)
|
||||
.throwIfNotFound();
|
||||
@@ -149,7 +150,7 @@ export class CreateBankTransactionService {
|
||||
} as ICommandCashflowCreatingPayload,
|
||||
);
|
||||
// Inserts cashflow owner contribution transaction.
|
||||
const cashflowTransaction = await this.bankTransactionModel
|
||||
const cashflowTransaction = await this.bankTransactionModel()
|
||||
.query(trx)
|
||||
.upsertGraph(cashflowTransactionObj);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
ICommandCashflowDeletedPayload,
|
||||
ICommandCashflowDeletingPayload,
|
||||
} from '../types/BankingTransactions.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteCashflowTransaction {
|
||||
@@ -19,10 +20,12 @@ export class DeleteCashflowTransaction {
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
|
||||
@Inject(BankTransaction.name)
|
||||
private readonly bankTransaction: typeof BankTransaction,
|
||||
private readonly bankTransaction: TenantModelProxy<typeof BankTransaction>,
|
||||
|
||||
@Inject(BankTransactionLine.name)
|
||||
private readonly bankTransactionLine: typeof BankTransactionLine,
|
||||
private readonly bankTransactionLine: TenantModelProxy<
|
||||
typeof BankTransactionLine
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -35,7 +38,7 @@ export class DeleteCashflowTransaction {
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<BankTransaction> => {
|
||||
// Retrieve the cashflow transaction.
|
||||
const oldCashflowTransaction = await this.bankTransaction
|
||||
const oldCashflowTransaction = await this.bankTransaction()
|
||||
.query()
|
||||
.findById(cashflowTransactionId);
|
||||
// Throw not found error if the given transaction id not found.
|
||||
@@ -50,13 +53,13 @@ export class DeleteCashflowTransaction {
|
||||
} as ICommandCashflowDeletingPayload);
|
||||
|
||||
// Delete cashflow transaction associated lines first.
|
||||
await this.bankTransactionLine
|
||||
await this.bankTransactionLine()
|
||||
.query(trx)
|
||||
.where('cashflow_transaction_id', cashflowTransactionId)
|
||||
.delete();
|
||||
|
||||
// Delete cashflow transaction.
|
||||
await this.bankTransaction
|
||||
await this.bankTransaction()
|
||||
.query(trx)
|
||||
.findById(cashflowTransactionId)
|
||||
.delete();
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransac
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class RemovePendingUncategorizedTransaction {
|
||||
@@ -18,7 +19,9 @@ export class RemovePendingUncategorizedTransaction {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransaction: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransaction: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -31,7 +34,7 @@ export class RemovePendingUncategorizedTransaction {
|
||||
uncategorizedTransactionId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> {
|
||||
const pendingTransaction = await this.uncategorizedBankTransaction
|
||||
const pendingTransaction = await this.uncategorizedBankTransaction()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -49,7 +52,7 @@ export class RemovePendingUncategorizedTransaction {
|
||||
} as IPendingTransactionRemovingEventPayload,
|
||||
);
|
||||
// Removes the pending uncategorized transaction.
|
||||
await this.uncategorizedBankTransaction
|
||||
await this.uncategorizedBankTransaction()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.delete();
|
||||
|
||||
@@ -2,12 +2,15 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ERRORS } from '../constants';
|
||||
import { ServiceError } from '../../Items/ServiceError';
|
||||
import { BankTransactionLine } from '../models/BankTransactionLine';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ValidateDeleteBankAccountTransactions {
|
||||
constructor(
|
||||
@Inject(BankTransactionLine.name)
|
||||
private readonly bankTransactionLineModel: typeof BankTransactionLine,
|
||||
private readonly bankTransactionLineModel: TenantModelProxy<
|
||||
typeof BankTransactionLine
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -15,7 +18,7 @@ export class ValidateDeleteBankAccountTransactions {
|
||||
* @param {number} accountId
|
||||
*/
|
||||
public validateAccountHasNoCashflowEntries = async (accountId: number) => {
|
||||
const associatedLines = await this.bankTransactionLineModel
|
||||
const associatedLines = await this.bankTransactionLineModel()
|
||||
.query()
|
||||
.where('creditAccountId', accountId)
|
||||
.orWhere('cashflowAccountId', accountId);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { GetRecognizedTransactionTransformer } from './GetRecognizedTransactionTransformer';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetRecognizedTransactionService {
|
||||
@@ -9,7 +10,9 @@ export class GetRecognizedTransactionService {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -17,11 +20,10 @@ export class GetRecognizedTransactionService {
|
||||
* @param {number} tenantId
|
||||
* @param {number} uncategorizedTransactionId
|
||||
*/
|
||||
public async getRecognizedTransaction(
|
||||
uncategorizedTransactionId: number
|
||||
) {
|
||||
public async getRecognizedTransaction(uncategorizedTransactionId: number) {
|
||||
const uncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel.query()
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId)
|
||||
.withGraphFetched('matchedBankTransactions')
|
||||
.withGraphFetched('recognizedTransaction.assignAccount')
|
||||
@@ -31,7 +33,7 @@ export class GetRecognizedTransactionService {
|
||||
|
||||
return this.transformer.transform(
|
||||
uncategorizedTransaction,
|
||||
new GetRecognizedTransactionTransformer()
|
||||
new GetRecognizedTransactionTransformer(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,12 +12,15 @@ import {
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ExcludeBankTransactionService {
|
||||
constructor(
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
|
||||
private uow: UnitOfWork,
|
||||
private eventEmitter: EventEmitter2,
|
||||
@@ -30,7 +33,7 @@ export class ExcludeBankTransactionService {
|
||||
*/
|
||||
public async excludeBankTransaction(uncategorizedTransactionId: number) {
|
||||
const oldUncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -47,7 +50,7 @@ export class ExcludeBankTransactionService {
|
||||
trx,
|
||||
} as IBankTransactionUnexcludingEventPayload);
|
||||
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.patch({
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class UnexcludeBankTransactionService {
|
||||
@@ -20,7 +21,9 @@ export class UnexcludeBankTransactionService {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -33,7 +36,7 @@ export class UnexcludeBankTransactionService {
|
||||
uncategorizedTransactionId: number,
|
||||
): Promise<void> {
|
||||
const oldUncategorizedTransaction =
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId)
|
||||
.throwIfNotFound();
|
||||
@@ -49,7 +52,7 @@ export class UnexcludeBankTransactionService {
|
||||
uncategorizedTransactionId,
|
||||
} as IBankTransactionExcludingEventPayload);
|
||||
|
||||
await this.uncategorizedBankTransactionModel
|
||||
await this.uncategorizedBankTransactionModel()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId)
|
||||
.patch({
|
||||
|
||||
@@ -3,14 +3,21 @@ import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectab
|
||||
import { ExcludedBankTransactionsQuery } from '../types/BankTransactionsExclude.types';
|
||||
import { UncategorizedTransactionTransformer } from '@/modules/BankingCategorize/commands/UncategorizedTransaction.transformer';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetExcludedBankTransactionsService {
|
||||
/**
|
||||
* @param {TransformerInjectable} transformer
|
||||
* @param {TenantModelProxy<typeof UncategorizedBankTransaction>} uncategorizedBankTransaction
|
||||
*/
|
||||
constructor(
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransaction: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransaction: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -27,7 +34,7 @@ export class GetExcludedBankTransactionsService {
|
||||
pageSize: 20,
|
||||
...filter,
|
||||
};
|
||||
const { results, pagination } = await this.uncategorizedBankTransaction
|
||||
const { results, pagination } = await this.uncategorizedBankTransaction()
|
||||
.query()
|
||||
.onBuild((q) => {
|
||||
q.modify('excluded');
|
||||
|
||||
@@ -7,15 +7,18 @@ import {
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DecrementUncategorizedTransactionOnExclude {
|
||||
constructor(
|
||||
@Inject(Account.name)
|
||||
private readonly account: typeof Account,
|
||||
private readonly account: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(UncategorizedBankTransaction.name)
|
||||
private readonly uncategorizedBankTransaction: typeof UncategorizedBankTransaction,
|
||||
private readonly uncategorizedBankTransaction: TenantModelProxy<
|
||||
typeof UncategorizedBankTransaction
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -27,11 +30,12 @@ export class DecrementUncategorizedTransactionOnExclude {
|
||||
uncategorizedTransactionId,
|
||||
trx,
|
||||
}: IBankTransactionExcludedEventPayload) {
|
||||
const transaction = await this.uncategorizedBankTransaction.query(
|
||||
trx
|
||||
).findById(uncategorizedTransactionId);
|
||||
const transaction = await this.uncategorizedBankTransaction()
|
||||
.query(trx)
|
||||
.findById(uncategorizedTransactionId);
|
||||
|
||||
await this.account.query(trx)
|
||||
await this.account()
|
||||
.query(trx)
|
||||
.findById(transaction.accountId)
|
||||
.decrement('uncategorizedTransactions', 1);
|
||||
}
|
||||
@@ -45,11 +49,12 @@ export class DecrementUncategorizedTransactionOnExclude {
|
||||
uncategorizedTransactionId,
|
||||
trx,
|
||||
}: IBankTransactionUnexcludedEventPayload) {
|
||||
const transaction = await this.uncategorizedBankTransaction.query().findById(
|
||||
uncategorizedTransactionId
|
||||
);
|
||||
const transaction = await this.uncategorizedBankTransaction()
|
||||
.query()
|
||||
.findById(uncategorizedTransactionId);
|
||||
//
|
||||
await this.account.query(trx)
|
||||
await this.account()
|
||||
.query(trx)
|
||||
.findById(transaction.accountId)
|
||||
.increment('uncategorizedTransactions', 1);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,13 @@ import { Bill } from '../../Bills/models/Bill';
|
||||
import { IBillPaymentEntryDTO } from '../types/BillPayments.types';
|
||||
import { entriesAmountDiff } from '@/utils/entries-amount-diff';
|
||||
import Objection from 'objection';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillPaymentBillSync {
|
||||
constructor(
|
||||
@Inject(Bill.name)
|
||||
private readonly bill: typeof Bill
|
||||
private readonly bill: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -36,7 +37,7 @@ export class BillPaymentBillSync {
|
||||
if (diffEntry.paymentAmount === 0) {
|
||||
return;
|
||||
}
|
||||
const oper = this.bill.changePaymentAmount(
|
||||
const oper = this.bill().changePaymentAmount(
|
||||
diffEntry.billId,
|
||||
diffEntry.paymentAmount,
|
||||
trx,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { BillPayment } from '../models/BillPayment';
|
||||
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillPaymentGLEntries {
|
||||
@@ -15,24 +16,23 @@ export class BillPaymentGLEntries {
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a bill payment GL entries.
|
||||
* @param {number} tenantId
|
||||
* @param {number} billPaymentId
|
||||
* @param {Knex.Transaction} trx
|
||||
* @param {number} billPaymentId - Bill payment id.
|
||||
* @param {Knex.Transaction} trx - Knex transaction.
|
||||
*/
|
||||
public writePaymentGLEntries = async (
|
||||
billPaymentId: number,
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> => {
|
||||
// Retrieves the bill payment details with associated entries.
|
||||
const payment = await this.billPaymentModel
|
||||
const payment = await this.billPaymentModel()
|
||||
.query(trx)
|
||||
.findById(billPaymentId)
|
||||
.withGraphFetched('entries.bill');
|
||||
@@ -47,7 +47,7 @@ export class BillPaymentGLEntries {
|
||||
trx,
|
||||
);
|
||||
// Exchange gain or loss account.
|
||||
const EXGainLossAccount = await this.accountModel
|
||||
const EXGainLossAccount = await this.accountModel()
|
||||
.query(trx)
|
||||
.modify('findBySlug', 'exchange-grain-loss')
|
||||
.first();
|
||||
|
||||
@@ -11,21 +11,24 @@ import { BillPaymentEntry } from '../models/BillPaymentEntry';
|
||||
import { ServiceError } from '../../Items/ServiceError';
|
||||
import { ACCOUNT_TYPE } from '@/constants/accounts';
|
||||
import { Account } from '../../Accounts/models/Account.model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillPaymentValidators {
|
||||
constructor(
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
|
||||
@Inject(BillPaymentEntry.name)
|
||||
private readonly billPaymentEntryModel: typeof BillPaymentEntry,
|
||||
private readonly billPaymentEntryModel: TenantModelProxy<
|
||||
typeof BillPaymentEntry
|
||||
>,
|
||||
|
||||
@Inject(Account.name)
|
||||
private readonly accountModel: typeof Account,
|
||||
private readonly accountModel: TenantModelProxy<typeof Account>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -35,7 +38,7 @@ export class BillPaymentValidators {
|
||||
* @param {Function} next
|
||||
*/
|
||||
public async getPaymentMadeOrThrowError(paymentMadeId: number) {
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.withGraphFetched('entries')
|
||||
.findById(paymentMadeId);
|
||||
@@ -53,9 +56,10 @@ export class BillPaymentValidators {
|
||||
* @return {Promise<IAccountType>}
|
||||
*/
|
||||
public async getPaymentAccountOrThrowError(paymentAccountId: number) {
|
||||
const paymentAccount = await this.accountModel
|
||||
const paymentAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(paymentAccountId);
|
||||
|
||||
if (!paymentAccount) {
|
||||
throw new ServiceError(ERRORS.PAYMENT_ACCOUNT_NOT_FOUND);
|
||||
}
|
||||
@@ -82,7 +86,7 @@ export class BillPaymentValidators {
|
||||
paymentMadeNumber: string,
|
||||
notPaymentMadeId?: number,
|
||||
) {
|
||||
const foundBillPayment = await this.billPaymentModel
|
||||
const foundBillPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.onBuild((builder: any) => {
|
||||
builder.findOne('payment_number', paymentMadeNumber);
|
||||
@@ -107,7 +111,7 @@ export class BillPaymentValidators {
|
||||
) {
|
||||
const entriesBillsIds = billPaymentEntries.map((e: any) => e.billId);
|
||||
|
||||
const storedBills = await this.billModel
|
||||
const storedBills = await this.billModel()
|
||||
.query()
|
||||
.whereIn('id', entriesBillsIds)
|
||||
.where('vendor_id', vendorId);
|
||||
@@ -144,7 +148,7 @@ export class BillPaymentValidators {
|
||||
(entry: IBillPaymentEntryDTO) => entry.billId,
|
||||
);
|
||||
|
||||
const storedBills = await this.billModel.query().whereIn('id', billsIds);
|
||||
const storedBills = await this.billModel().query().whereIn('id', billsIds);
|
||||
const storedBillsMap = new Map(
|
||||
storedBills.map((bill) => {
|
||||
const oldEntries = oldPaymentEntries.filter(
|
||||
@@ -191,7 +195,7 @@ export class BillPaymentValidators {
|
||||
.filter((entry: any) => entry.id)
|
||||
.map((entry: any) => entry.id);
|
||||
|
||||
const storedEntries = await this.billPaymentEntryModel
|
||||
const storedEntries = await this.billPaymentEntryModel()
|
||||
.query()
|
||||
.where('bill_payment_id', billPaymentId);
|
||||
|
||||
@@ -243,7 +247,7 @@ export class BillPaymentValidators {
|
||||
* @param {number} vendorId
|
||||
*/
|
||||
public async validateVendorHasNoPayments(vendorId: number) {
|
||||
const payments = await this.billPaymentModel
|
||||
const payments = await this.billPaymentModel()
|
||||
.query()
|
||||
.where('vendor_id', vendorId);
|
||||
|
||||
|
||||
@@ -5,19 +5,20 @@ import { Bill } from '../../Bills/models/Bill';
|
||||
import { BillPayment } from '../models/BillPayment';
|
||||
import { IBillReceivePageEntry } from '../types/BillPayments.types';
|
||||
import { ServiceError } from '../../Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export default class BillPaymentsPages {
|
||||
/**
|
||||
* @param {typeof Bill} billModel - Bill model.
|
||||
* @param {typeof BillPayment} billPaymentModel - Bill payment model.
|
||||
* @param {TenantModelProxy<typeof Bill>} billModel - Bill model.
|
||||
* @param {TenantModelProxy<typeof BillPayment>} billPaymentModel - Bill payment model.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -29,7 +30,7 @@ export default class BillPaymentsPages {
|
||||
billPayment: Omit<BillPayment, 'entries'>;
|
||||
entries: IBillReceivePageEntry[];
|
||||
}> {
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.findById(billPaymentId)
|
||||
.withGraphFetched('entries.bill')
|
||||
@@ -74,7 +75,7 @@ export default class BillPaymentsPages {
|
||||
vendorId: number,
|
||||
): Promise<IBillReceivePageEntry[]> {
|
||||
// Retrieve all payable bills that associated to the payment made transaction.
|
||||
const payableBills = await this.billModel
|
||||
const payableBills = await this.billModel()
|
||||
.query()
|
||||
.modify('opened')
|
||||
.modify('dueBills')
|
||||
|
||||
@@ -13,6 +13,7 @@ import { events } from '@/common/events/events';
|
||||
import { TenancyContext } from '../../Tenancy/TenancyContext.service';
|
||||
import { BillPayment } from '../models/BillPayment';
|
||||
import { Vendor } from '../../Vendors/models/Vendor';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateBillPaymentService {
|
||||
@@ -22,8 +23,8 @@ export class CreateBillPaymentService {
|
||||
* @param {BillPaymentValidators} validators - Bill payment validators service.
|
||||
* @param {CommandBillPaymentDTOTransformer} commandTransformerDTO - Command bill payment DTO transformer service.
|
||||
* @param {TenancyContext} tenancyContext - Tenancy context service.
|
||||
* @param {typeof Vendor} vendorModel - Vendor model.
|
||||
* @param {typeof BillPayment} billPaymentModel - Bill payment model.
|
||||
* @param {TenantModelProxy<typeof Vendor>} vendorModel - Vendor model.
|
||||
* @param {TenantModelProxy<typeof BillPayment>} billPaymentModel - Bill payment model.
|
||||
*/
|
||||
constructor(
|
||||
private uow: UnitOfWork,
|
||||
@@ -33,10 +34,10 @@ export class CreateBillPaymentService {
|
||||
private tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: typeof Vendor,
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -61,7 +62,7 @@ export class CreateBillPaymentService {
|
||||
const tenantMeta = await this.tenancyContext.getTenant(true);
|
||||
|
||||
// Retrieves the payment vendor or throw not found error.
|
||||
const vendor = await this.vendorModel
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(billPaymentDTO.vendorId)
|
||||
.throwIfNotFound();
|
||||
@@ -102,7 +103,7 @@ export class CreateBillPaymentService {
|
||||
} as IBillPaymentCreatingPayload);
|
||||
|
||||
// Writes the bill payment graph to the storage.
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query(trx)
|
||||
.insertGraphAndFetch({
|
||||
...billPaymentObj,
|
||||
|
||||
@@ -9,6 +9,7 @@ import { BillPaymentEntry } from '../models/BillPaymentEntry';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBillPayment {
|
||||
@@ -23,10 +24,12 @@ export class DeleteBillPayment {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
|
||||
@Inject(BillPaymentEntry.name)
|
||||
private readonly billPaymentEntryModel: typeof BillPaymentEntry,
|
||||
private readonly billPaymentEntryModel: TenantModelProxy<
|
||||
typeof BillPaymentEntry
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -36,7 +39,7 @@ export class DeleteBillPayment {
|
||||
*/
|
||||
public async deleteBillPayment(billPaymentId: number) {
|
||||
// Retrieve the bill payment or throw not found service error.
|
||||
const oldBillPayment = await this.billPaymentModel
|
||||
const oldBillPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.withGraphFetched('entries')
|
||||
.findById(billPaymentId)
|
||||
@@ -52,13 +55,13 @@ export class DeleteBillPayment {
|
||||
} as IBillPaymentDeletingPayload);
|
||||
|
||||
// Deletes the bill payment associated entries.
|
||||
await this.billPaymentEntryModel
|
||||
await this.billPaymentEntryModel()
|
||||
.query(trx)
|
||||
.where('bill_payment_id', billPaymentId)
|
||||
.delete();
|
||||
|
||||
// Deletes the bill payment transaction.
|
||||
await this.billPaymentModel
|
||||
await this.billPaymentModel()
|
||||
.query(trx)
|
||||
.where('id', billPaymentId)
|
||||
.delete();
|
||||
|
||||
@@ -12,6 +12,7 @@ import { CommandBillPaymentDTOTransformer } from './CommandBillPaymentDTOTransfo
|
||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditBillPayment {
|
||||
@@ -23,10 +24,10 @@ export class EditBillPayment {
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: typeof Vendor,
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -53,13 +54,13 @@ export class EditBillPayment {
|
||||
): Promise<BillPayment> {
|
||||
const tenantMeta = await this.tenancyContext.getTenant(true);
|
||||
|
||||
const oldBillPayment = await this.billPaymentModel
|
||||
const oldBillPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.findById(billPaymentId)
|
||||
.withGraphFetched('entries')
|
||||
.throwIfNotFound();
|
||||
|
||||
const vendor = await this.vendorModel
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(billPaymentDTO.vendorId)
|
||||
.throwIfNotFound();
|
||||
@@ -115,7 +116,7 @@ export class EditBillPayment {
|
||||
} as IBillPaymentEditingPayload);
|
||||
|
||||
// Edits the bill payment transaction graph on the storage.
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
id: billPaymentId,
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { TransformerInjectable } from '../../Transformer/TransformerInjectable.service';
|
||||
import { BillPayment } from '../models/BillPayment';
|
||||
import { BillPaymentTransformer } from './BillPaymentTransformer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBillPayment {
|
||||
@@ -9,7 +10,7 @@ export class GetBillPayment {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -18,7 +19,7 @@ export class GetBillPayment {
|
||||
* @return {Promise<BillPayment>}
|
||||
*/
|
||||
public async getBillPayment(billPyamentId: number): Promise<BillPayment> {
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.withGraphFetched('entries.bill')
|
||||
.withGraphFetched('vendor')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Bill } from '@/modules/Bills/models/Bill';
|
||||
import { BillPayment } from '../models/BillPayment';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetPaymentBills {
|
||||
@@ -10,10 +11,10 @@ export class GetPaymentBills {
|
||||
*/
|
||||
constructor(
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(BillPayment.name)
|
||||
private readonly billPaymentModel: typeof BillPayment,
|
||||
private readonly billPaymentModel: TenantModelProxy<typeof BillPayment>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -21,14 +22,14 @@ export class GetPaymentBills {
|
||||
* @param {number} billPaymentId - Bill payment id.
|
||||
*/
|
||||
public async getPaymentBills(billPaymentId: number) {
|
||||
const billPayment = await this.billPaymentModel
|
||||
const billPayment = await this.billPaymentModel()
|
||||
.query()
|
||||
.findById(billPaymentId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const paymentBillsIds = billPayment.entries.map((entry) => entry.id);
|
||||
|
||||
const bills = await this.billModel.query().whereIn('id', paymentBillsIds);
|
||||
const bills = await this.billModel().query().whereIn('id', paymentBillsIds);
|
||||
|
||||
return bills;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import { IBillDTO } from '../Bills.types';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-index';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillDTOTransformer {
|
||||
@@ -23,8 +24,9 @@ export class BillDTOTransformer {
|
||||
private taxDTOTransformer: ItemEntriesTaxTransactions,
|
||||
private tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(ItemEntry.name) private itemEntryModel: typeof ItemEntry,
|
||||
@Inject(Item.name) private itemModel: typeof Item,
|
||||
@Inject(ItemEntry.name)
|
||||
private itemEntryModel: TenantModelProxy<typeof ItemEntry>,
|
||||
@Inject(Item.name) private itemModel: TenantModelProxy<typeof Item>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -33,7 +35,7 @@ export class BillDTOTransformer {
|
||||
* @returns {number}
|
||||
*/
|
||||
private getBillEntriesTotal(entries: ItemEntry[]): number {
|
||||
return sumBy(entries, (e) => this.itemEntryModel.calcAmount(e));
|
||||
return sumBy(entries, (e) => this.itemEntryModel().calcAmount(e));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,7 +63,7 @@ export class BillDTOTransformer {
|
||||
oldBill?: Bill,
|
||||
): Promise<Bill> {
|
||||
const amount = sumBy(billDTO.entries, (e) =>
|
||||
this.itemEntryModel.calcAmount(e),
|
||||
this.itemEntryModel().calcAmount(e),
|
||||
);
|
||||
// Retrieve the landed cost amount from landed cost entries.
|
||||
const landedCostAmount = this.getBillLandedCostAmount(billDTO);
|
||||
@@ -125,7 +127,9 @@ export class BillDTOTransformer {
|
||||
private setBillEntriesDefaultAccounts() {
|
||||
return async (entries: ItemEntry[]) => {
|
||||
const entriesItemsIds = entries.map((e) => e.itemId);
|
||||
const items = await this.itemModel.query().whereIn('id', entriesItemsIds);
|
||||
const items = await this.itemModel()
|
||||
.query()
|
||||
.whereIn('id', entriesItemsIds);
|
||||
|
||||
return entries.map((entry) => {
|
||||
const item = items.find((i) => i.id === entry.itemId);
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Bill } from '../models/Bill';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { InventoryTransactionsService } from '@/modules/InventoryCost/InventoryTransactions.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillInventoryTransactions {
|
||||
constructor(
|
||||
@@ -11,7 +13,7 @@ export class BillInventoryTransactions {
|
||||
private readonly inventoryTransactionsService: InventoryTransactionsService,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private readonly bill: typeof Bill,
|
||||
private readonly bill: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -26,7 +28,7 @@ export class BillInventoryTransactions {
|
||||
): Promise<void> {
|
||||
// Retireve bill with assocaited entries and allocated cost entries.
|
||||
|
||||
const bill = await this.bill
|
||||
const bill = await this.bill()
|
||||
.query(trx)
|
||||
.findById(billId)
|
||||
.withGraphFetched('entries.allocatedCostEntries');
|
||||
|
||||
@@ -4,6 +4,7 @@ import { AccountRepository } from '@/modules/Accounts/repositories/Account.repos
|
||||
import { Bill } from '../models/Bill';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { BillGL } from './BillsGL';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillGLEntries {
|
||||
@@ -17,7 +18,7 @@ export class BillGLEntries {
|
||||
private readonly accountRepository: AccountRepository,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -30,7 +31,7 @@ export class BillGLEntries {
|
||||
trx?: Knex.Transaction,
|
||||
) => {
|
||||
// Retrieves bill with associated entries and landed costs.
|
||||
const bill = await this.billModel
|
||||
const bill = await this.billModel()
|
||||
.query(trx)
|
||||
.findById(billId)
|
||||
.withGraphFetched('entries.item')
|
||||
|
||||
@@ -8,22 +8,25 @@ import { BillPaymentEntry } from '@/modules/BillPayments/models/BillPaymentEntry
|
||||
import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost';
|
||||
import { VendorCreditAppliedBill } from '@/modules/VendorCreditsApplyBills/models/VendorCreditAppliedBill';
|
||||
import { transformToMap } from '@/utils/transform-to-key';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class BillsValidators {
|
||||
constructor(
|
||||
@Inject(Bill.name) private billModel: typeof Bill,
|
||||
@Inject(Bill.name) private billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(BillPaymentEntry.name)
|
||||
private billPaymentEntryModel: typeof BillPaymentEntry,
|
||||
private billPaymentEntryModel: TenantModelProxy<typeof BillPaymentEntry>,
|
||||
|
||||
@Inject(BillLandedCost.name)
|
||||
private billLandedCostModel: typeof BillLandedCost,
|
||||
private billLandedCostModel: TenantModelProxy<typeof BillLandedCost>,
|
||||
|
||||
@Inject(VendorCreditAppliedBill.name)
|
||||
private vendorCreditAppliedBillModel: typeof VendorCreditAppliedBill,
|
||||
private vendorCreditAppliedBillModel: TenantModelProxy<
|
||||
typeof VendorCreditAppliedBill
|
||||
>,
|
||||
|
||||
@Inject(Item.name) private itemModel: typeof Item,
|
||||
@Inject(Item.name) private itemModel: TenantModelProxy<typeof Item>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -57,7 +60,7 @@ export class BillsValidators {
|
||||
billNumber: string,
|
||||
notBillId?: number,
|
||||
) {
|
||||
const foundBills = await this.billModel
|
||||
const foundBills = await this.billModel()
|
||||
.query()
|
||||
.where('bill_number', billNumber)
|
||||
.onBuild((builder) => {
|
||||
@@ -80,7 +83,7 @@ export class BillsValidators {
|
||||
*/
|
||||
public async validateBillHasNoEntries(billId: number) {
|
||||
// Retrieve the bill associate payment made entries.
|
||||
const entries = await this.billPaymentEntryModel
|
||||
const entries = await this.billPaymentEntryModel()
|
||||
.query()
|
||||
.where('bill_id', billId);
|
||||
|
||||
@@ -105,7 +108,7 @@ export class BillsValidators {
|
||||
* @param {number} billId
|
||||
*/
|
||||
public async validateBillHasNoLandedCost(billId: number) {
|
||||
const billLandedCosts = await this.billLandedCostModel
|
||||
const billLandedCosts = await this.billLandedCostModel()
|
||||
.query()
|
||||
.where('billId', billId);
|
||||
|
||||
@@ -123,7 +126,7 @@ export class BillsValidators {
|
||||
newEntriesDTO: IItemEntryDTO[],
|
||||
) {
|
||||
const entriesItemsIds = newEntriesDTO.map((e) => e.itemId);
|
||||
const entriesItems = await this.itemModel
|
||||
const entriesItems = await this.itemModel()
|
||||
.query()
|
||||
.whereIn('id', entriesItemsIds);
|
||||
|
||||
@@ -147,9 +150,10 @@ export class BillsValidators {
|
||||
* @param {number} billId
|
||||
*/
|
||||
public validateBillHasNoAppliedToCredit = async (billId: number) => {
|
||||
const appliedTransactions = await this.vendorCreditAppliedBillModel
|
||||
const appliedTransactions = await this.vendorCreditAppliedBillModel()
|
||||
.query()
|
||||
.where('billId', billId);
|
||||
|
||||
if (appliedTransactions.length > 0) {
|
||||
throw new ServiceError(ERRORS.BILL_HAS_APPLIED_TO_VENDOR_CREDIT);
|
||||
}
|
||||
@@ -160,7 +164,7 @@ export class BillsValidators {
|
||||
* @param {number} vendorId - Vendor id.
|
||||
*/
|
||||
public async validateVendorHasNoBills(vendorId: number) {
|
||||
const bills = await this.billModel.query().where('vendor_id', vendorId);
|
||||
const bills = await this.billModel().query().where('vendor_id', vendorId);
|
||||
|
||||
if (bills.length > 0) {
|
||||
throw new ServiceError(ERRORS.VENDOR_HAS_BILLS);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateBill {
|
||||
@@ -24,10 +25,10 @@ export class CreateBill {
|
||||
private transformerDTO: BillDTOTransformer,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private billModel: typeof Bill,
|
||||
private billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private vendorModel: typeof Vendor,
|
||||
private vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -49,7 +50,7 @@ export class CreateBill {
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<Bill> {
|
||||
// Retrieves the given bill vendor or throw not found error.
|
||||
const vendor = await this.vendorModel
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(billDTO.vendorId)
|
||||
.throwIfNotFound();
|
||||
@@ -80,7 +81,9 @@ export class CreateBill {
|
||||
} as IBillCreatingPayload);
|
||||
|
||||
// Inserts the bill graph object to the storage.
|
||||
const bill = await this.billModel.query(trx).upsertGraphAndFetch(billObj);
|
||||
const bill = await this.billModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch(billObj);
|
||||
|
||||
// Triggers `onBillCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.bill.onCreated, {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBill {
|
||||
@@ -17,8 +18,12 @@ export class DeleteBill {
|
||||
private readonly validators: BillsValidators,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
@Inject(Bill.name) private readonly billModel: typeof Bill,
|
||||
@Inject(ItemEntry.name) private readonly itemEntryModel: typeof ItemEntry,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
@Inject(ItemEntry.name)
|
||||
private readonly itemEntryModel: TenantModelProxy<typeof ItemEntry>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -28,7 +33,7 @@ export class DeleteBill {
|
||||
*/
|
||||
public async deleteBill(billId: number) {
|
||||
// Retrieve the given bill or throw not found error.
|
||||
const oldBill = await this.billModel
|
||||
const oldBill = await this.billModel()
|
||||
.query()
|
||||
.findById(billId)
|
||||
.withGraphFetched('entries');
|
||||
@@ -55,7 +60,8 @@ export class DeleteBill {
|
||||
} as IBillEventDeletingPayload);
|
||||
|
||||
// Delete all associated bill entries.
|
||||
await this.itemEntryModel.query(trx)
|
||||
await this.itemEntryModel()
|
||||
.query(trx)
|
||||
.where('reference_type', 'Bill')
|
||||
.where('reference_id', billId)
|
||||
.delete();
|
||||
|
||||
@@ -14,6 +14,7 @@ import { events } from '@/common/events/events';
|
||||
import { Vendor } from '@/modules/Vendors/models/Vendor';
|
||||
import { Knex } from 'knex';
|
||||
import { TransactionLandedCostEntriesService } from '@/modules/BillLandedCosts/TransactionLandedCostEntries.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditBillService {
|
||||
@@ -25,8 +26,8 @@ export class EditBillService {
|
||||
private transactionLandedCostEntries: TransactionLandedCostEntriesService,
|
||||
private transformerDTO: BillDTOTransformer,
|
||||
|
||||
@Inject(Bill.name) private billModel: typeof Bill,
|
||||
@Inject(Vendor.name) private contactModel: typeof Vendor,
|
||||
@Inject(Bill.name) private billModel: TenantModelProxy<typeof Bill>,
|
||||
@Inject(Vendor.name) private contactModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -45,12 +46,9 @@ export class EditBillService {
|
||||
* @param {IBillEditDTO} billDTO - The given new bill details.
|
||||
* @return {Promise<IBill>}
|
||||
*/
|
||||
public async editBill(
|
||||
billId: number,
|
||||
billDTO: IBillEditDTO,
|
||||
): Promise<Bill> {
|
||||
public async editBill(billId: number, billDTO: IBillEditDTO): Promise<Bill> {
|
||||
// Retrieve the given bill or throw not found error.
|
||||
const oldBill = await this.billModel
|
||||
const oldBill = await this.billModel()
|
||||
.query()
|
||||
.findById(billId)
|
||||
.withGraphFetched('entries');
|
||||
@@ -59,7 +57,7 @@ export class EditBillService {
|
||||
this.validators.validateBillExistance(oldBill);
|
||||
|
||||
// Retrieve vendor details or throw not found service error.
|
||||
const vendor = await this.contactModel
|
||||
const vendor = await this.contactModel()
|
||||
.query()
|
||||
.findById(billDTO.vendorId)
|
||||
.modify('vendor')
|
||||
@@ -69,44 +67,42 @@ export class EditBillService {
|
||||
if (billDTO.billNumber) {
|
||||
await this.validators.validateBillNumberExists(
|
||||
billDTO.billNumber,
|
||||
billId
|
||||
billId,
|
||||
);
|
||||
}
|
||||
// Validate the entries ids existance.
|
||||
await this.itemsEntriesService.validateEntriesIdsExistance(
|
||||
billId,
|
||||
'Bill',
|
||||
billDTO.entries
|
||||
billDTO.entries,
|
||||
);
|
||||
// Validate the items ids existance on the storage.
|
||||
await this.itemsEntriesService.validateItemsIdsExistance(
|
||||
billDTO.entries
|
||||
);
|
||||
await this.itemsEntriesService.validateItemsIdsExistance(billDTO.entries);
|
||||
// Accept the purchasable items only.
|
||||
await this.itemsEntriesService.validateNonPurchasableEntriesItems(
|
||||
billDTO.entries
|
||||
billDTO.entries,
|
||||
);
|
||||
|
||||
|
||||
// Transforms the bill DTO to model object.
|
||||
const billObj = await this.transformerDTO.billDTOToModel(
|
||||
billDTO,
|
||||
vendor,
|
||||
oldBill
|
||||
oldBill,
|
||||
);
|
||||
// Validate bill total amount should be bigger than paid amount.
|
||||
this.validators.validateBillAmountBiggerPaidAmount(
|
||||
billObj.amount,
|
||||
oldBill.paymentAmount
|
||||
oldBill.paymentAmount,
|
||||
);
|
||||
// Validate landed cost entries that have allocated cost could not be deleted.
|
||||
await this.transactionLandedCostEntries.validateLandedCostEntriesNotDeleted(
|
||||
oldBill.entries,
|
||||
billObj.entries
|
||||
billObj.entries,
|
||||
);
|
||||
// Validate new landed cost entries should be bigger than new entries.
|
||||
await this.transactionLandedCostEntries.validateLocatedCostEntriesSmallerThanNewEntries(
|
||||
oldBill.entries,
|
||||
billObj.entries
|
||||
billObj.entries,
|
||||
);
|
||||
// Edits bill transactions and associated transactions under UOW envirement.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
@@ -118,10 +114,12 @@ export class EditBillService {
|
||||
} as IBillEditingPayload);
|
||||
|
||||
// Update the bill transaction.
|
||||
const bill = await this.billModel.query(trx).upsertGraphAndFetch({
|
||||
id: billId,
|
||||
...billObj,
|
||||
});
|
||||
const bill = await this.billModel()
|
||||
.query(trx)
|
||||
.upsertGraphAndFetch({
|
||||
id: billId,
|
||||
...billObj,
|
||||
});
|
||||
// Triggers event `onBillEdited`.
|
||||
await this.eventPublisher.emitAsync(events.bill.onEdited, {
|
||||
oldBill,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class OpenBillService {
|
||||
@@ -17,7 +18,7 @@ export class OpenBillService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(Bill.name)
|
||||
private readonly billModel: typeof Bill,
|
||||
private readonly billModel: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ export class OpenBillService {
|
||||
*/
|
||||
public async openBill(billId: number): Promise<void> {
|
||||
// Retrieve the given bill or throw not found error.
|
||||
const oldBill = await this.billModel
|
||||
const oldBill = await this.billModel()
|
||||
.query()
|
||||
.findById(billId)
|
||||
.withGraphFetched('entries');
|
||||
@@ -47,7 +48,7 @@ export class OpenBillService {
|
||||
} as IBillOpeningPayload);
|
||||
|
||||
// Save the bill opened at on the storage.
|
||||
const bill = await this.billModel
|
||||
const bill = await this.billModel()
|
||||
.query(trx)
|
||||
.patchAndFetchById(billId, {
|
||||
openedAt: moment().toMySqlDateTime(),
|
||||
|
||||
@@ -3,11 +3,12 @@ import { BillsValidators } from '../commands/BillsValidators.service';
|
||||
import { BillTransformer } from './Bill.transformer';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBill {
|
||||
constructor(
|
||||
@Inject(Bill.name) private billModel: typeof Bill,
|
||||
@Inject(Bill.name) private billModel: TenantModelProxy<typeof Bill>,
|
||||
|
||||
private transformer: TransformerInjectable,
|
||||
private validators: BillsValidators,
|
||||
@@ -19,7 +20,7 @@ export class GetBill {
|
||||
* @returns {Promise<IBill>}
|
||||
*/
|
||||
public async getBill(billId: number): Promise<Bill> {
|
||||
const bill = await this.billModel
|
||||
const bill = await this.billModel()
|
||||
.query()
|
||||
.findById(billId)
|
||||
.withGraphFetched('vendor')
|
||||
@@ -31,9 +32,6 @@ export class GetBill {
|
||||
// Validates the bill existence.
|
||||
this.validators.validateBillExistance(bill);
|
||||
|
||||
return this.transformer.transform(
|
||||
bill,
|
||||
new BillTransformer(),
|
||||
);
|
||||
return this.transformer.transform(bill, new BillTransformer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import { Bill } from '../models/Bill';
|
||||
import { IFilterMeta, IPaginationMeta } from '@/interfaces/Model';
|
||||
import { BillTransformer } from './Bill.transformer';
|
||||
import { IBillsFilter } from '../Bills.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBillsService {
|
||||
@@ -13,7 +14,7 @@ export class GetBillsService {
|
||||
private transformer: TransformerInjectable,
|
||||
private dynamicListService: DynamicListService,
|
||||
|
||||
@Inject(Bill.name) private billModel: typeof Bill,
|
||||
@Inject(Bill.name) private billModel: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -30,10 +31,10 @@ export class GetBillsService {
|
||||
|
||||
// Dynamic list service.
|
||||
const dynamicFilter = await this.dynamicListService.dynamicList(
|
||||
this.billModel,
|
||||
this.billModel(),
|
||||
filter,
|
||||
);
|
||||
const { results, pagination } = await this.billModel
|
||||
const { results, pagination } = await this.billModel()
|
||||
.query()
|
||||
.onBuild((builder) => {
|
||||
builder.withGraphFetched('vendor');
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Bill } from '../models/Bill';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetDueBills {
|
||||
constructor(
|
||||
@Inject(Bill.name)
|
||||
private billModel: typeof Bill,
|
||||
@Inject(Bill.name) private billModel: TenantModelProxy<typeof Bill>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -13,14 +13,16 @@ export class GetDueBills {
|
||||
* @param {number} vendorId -
|
||||
*/
|
||||
public async getDueBills(vendorId?: number): Promise<Bill[]> {
|
||||
const dueBills = await this.billModel.query().onBuild((query) => {
|
||||
query.orderBy('bill_date', 'DESC');
|
||||
query.modify('dueBills');
|
||||
const dueBills = await this.billModel()
|
||||
.query()
|
||||
.onBuild((query) => {
|
||||
query.orderBy('bill_date', 'DESC');
|
||||
query.modify('dueBills');
|
||||
|
||||
if (vendorId) {
|
||||
query.where('vendor_id', vendorId);
|
||||
}
|
||||
});
|
||||
if (vendorId) {
|
||||
query.where('vendor_id', vendorId);
|
||||
}
|
||||
});
|
||||
return dueBills;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateBranches {
|
||||
@@ -24,7 +25,7 @@ export class ActivateBranches {
|
||||
private readonly i18n: I18nService,
|
||||
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,11 +3,12 @@ import { ERRORS } from '../constants';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
|
||||
import { ServiceError } from '../../Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
@Injectable()
|
||||
export class BranchCommandValidator {
|
||||
constructor(
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -15,7 +16,9 @@ export class BranchCommandValidator {
|
||||
* @param {number} branchId
|
||||
*/
|
||||
public validateBranchNotOnlyWarehouse = async (branchId: number) => {
|
||||
const warehouses = await this.branchModel.query().whereNot('id', branchId);
|
||||
const warehouses = await this.branchModel()
|
||||
.query()
|
||||
.whereNot('id', branchId);
|
||||
|
||||
if (warehouses.length === 0) {
|
||||
throw new ServiceError(ERRORS.COULD_NOT_DELETE_ONLY_BRANCH);
|
||||
@@ -31,7 +34,7 @@ export class BranchCommandValidator {
|
||||
code: string,
|
||||
exceptBranchId?: number,
|
||||
): Promise<void> => {
|
||||
const branch = await this.branchModel
|
||||
const branch = await this.branchModel()
|
||||
.query()
|
||||
.onBuild((query) => {
|
||||
query.select(['id']);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateBranchService {
|
||||
@@ -22,7 +23,7 @@ export class CreateBranchService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -41,10 +42,11 @@ export class CreateBranchService {
|
||||
trx,
|
||||
} as IBranchCreatePayload);
|
||||
|
||||
const branch = await this.branchModel.query().insertAndFetch({
|
||||
...createBranchDTO,
|
||||
});
|
||||
|
||||
const branch = await this.branchModel()
|
||||
.query()
|
||||
.insertAndFetch({
|
||||
...createBranchDTO,
|
||||
});
|
||||
// Triggers `onBranchCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.warehouse.onEdited, {
|
||||
createBranchDTO,
|
||||
|
||||
@@ -7,12 +7,13 @@ import { Branch } from '../models/Branch.model';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteBranchService {
|
||||
constructor(
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly validator: BranchCommandValidator,
|
||||
@@ -29,18 +30,18 @@ export class DeleteBranchService {
|
||||
|
||||
/**
|
||||
* Deletes branch.
|
||||
* @param {number} branchId
|
||||
* @param {number} branchId
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public deleteBranch = async (branchId: number): Promise<void> => {
|
||||
// Retrieves the old branch or throw not found service error.
|
||||
const oldBranch = await this.branchModel
|
||||
const oldBranch = await this.branchModel()
|
||||
.query()
|
||||
.findById(branchId)
|
||||
.throwIfNotFound();
|
||||
// .queryAndThrowIfHasRelations({
|
||||
// type: ERRORS.BRANCH_HAS_ASSOCIATED_TRANSACTIONS,
|
||||
// });
|
||||
// .queryAndThrowIfHasRelations({
|
||||
// type: ERRORS.BRANCH_HAS_ASSOCIATED_TRANSACTIONS,
|
||||
// });
|
||||
|
||||
// Authorize the branch before deleting.
|
||||
await this.authorize(branchId);
|
||||
@@ -53,7 +54,7 @@ export class DeleteBranchService {
|
||||
trx,
|
||||
} as IBranchDeletePayload);
|
||||
|
||||
await this.branchModel.query().findById(branchId).delete();
|
||||
await this.branchModel().query().findById(branchId).delete();
|
||||
|
||||
// Triggers `onBranchCreate` event.
|
||||
await this.eventPublisher.emitAsync(events.warehouse.onEdited, {
|
||||
|
||||
@@ -9,12 +9,13 @@ import { Branch } from '../models/Branch.model';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditBranchService {
|
||||
constructor(
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
) {}
|
||||
@@ -29,7 +30,7 @@ export class EditBranchService {
|
||||
editBranchDTO: IEditBranchDTO,
|
||||
) => {
|
||||
// Retrieves the old branch or throw not found service error.
|
||||
const oldBranch = await this.branchModel
|
||||
const oldBranch = await this.branchModel()
|
||||
.query()
|
||||
.findById(branchId)
|
||||
.throwIfNotFound();
|
||||
@@ -43,7 +44,7 @@ export class EditBranchService {
|
||||
} as IBranchEditPayload);
|
||||
|
||||
// Edits the branch on the storage.
|
||||
const branch = await this.branchModel
|
||||
const branch = await this.branchModel()
|
||||
.query()
|
||||
.patchAndFetchById(branchId, {
|
||||
...editBranchDTO,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class MarkBranchAsPrimaryService {
|
||||
@@ -16,7 +17,7 @@ export class MarkBranchAsPrimaryService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(Branch.name)
|
||||
private readonly branchModel: typeof Branch,
|
||||
private readonly branchModel: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -26,7 +27,7 @@ export class MarkBranchAsPrimaryService {
|
||||
*/
|
||||
public async markAsPrimary(branchId: number): Promise<Branch> {
|
||||
// Retrieves the old branch or throw not found service error.
|
||||
const oldBranch = await this.branchModel
|
||||
const oldBranch = await this.branchModel()
|
||||
.query()
|
||||
.findById(branchId)
|
||||
.throwIfNotFound();
|
||||
@@ -40,10 +41,10 @@ export class MarkBranchAsPrimaryService {
|
||||
} as IBranchMarkAsPrimaryPayload);
|
||||
|
||||
// Updates all branches as not primary.
|
||||
await this.branchModel.query(trx).update({ primary: false });
|
||||
await this.branchModel().query(trx).update({ primary: false });
|
||||
|
||||
// Updates the given branch as primary.
|
||||
const markedBranch = await this.branchModel
|
||||
const markedBranch = await this.branchModel()
|
||||
.query(trx)
|
||||
.patchAndFetchById(branchId, {
|
||||
primary: true,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Inject } from '@nestjs/common';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBranchService {
|
||||
constructor(
|
||||
@Inject(Branch.name)
|
||||
private readonly branch: typeof Branch,
|
||||
private readonly branch: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -15,7 +16,7 @@ export class GetBranchService {
|
||||
* @returns {Promise<IBranch>}
|
||||
*/
|
||||
public getBranch = async (branchId: number): Promise<Branch> => {
|
||||
const branch = await this.branch
|
||||
const branch = await this.branch()
|
||||
.query()
|
||||
.findById(branchId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Branch } from '../models/Branch.model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetBranchesService {
|
||||
constructor(
|
||||
@Inject(Branch.name)
|
||||
private readonly branch: typeof Branch,
|
||||
private readonly branch: TenantModelProxy<typeof Branch>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -13,7 +14,7 @@ export class GetBranchesService {
|
||||
* @returns
|
||||
*/
|
||||
public getBranches = async () => {
|
||||
const branches = await this.branch.query().orderBy('name', 'DESC');
|
||||
const branches = await this.branch().query().orderBy('name', 'DESC');
|
||||
|
||||
return branches;
|
||||
};
|
||||
|
||||
@@ -10,17 +10,20 @@ import {
|
||||
getPdfFilesStorageDir,
|
||||
} from './utils';
|
||||
import { Document } from './models/Document';
|
||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ChromiumlyHtmlConvert {
|
||||
/**
|
||||
* @param {typeof Document} documentModel - Document model.
|
||||
* @param {TenantModelProxy<typeof Document>} documentModel - Document model.
|
||||
*/
|
||||
constructor(@Inject(Document.name) private documentModel: typeof Document) {}
|
||||
constructor(
|
||||
@Inject(Document.name)
|
||||
private documentModel: TenantModelProxy<typeof Document>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Write HTML content to temporary file.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {string} content - HTML content.
|
||||
* @returns {Promise<[string, () => Promise<void>]>}
|
||||
*/
|
||||
@@ -31,7 +34,7 @@ export class ChromiumlyHtmlConvert {
|
||||
const filePath = getPdfFilePath(filename);
|
||||
|
||||
await fs.writeFile(filePath, content);
|
||||
await this.documentModel
|
||||
await this.documentModel()
|
||||
.query()
|
||||
.insert({ key: filename, mimeType: 'text/html' });
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { RefundCreditNote } from '@/modules/CreditNoteRefunds/models/RefundCredi
|
||||
import { CommandCreditNoteDTOTransform } from '@/modules/CreditNotes/commands/CommandCreditNoteDTOTransform.service';
|
||||
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateRefundCreditNoteService {
|
||||
@@ -19,9 +20,9 @@ export class CreateRefundCreditNoteService {
|
||||
* @param {UnitOfWork} uow - The unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - The event emitter service.
|
||||
* @param {CommandCreditNoteDTOTransform} commandCreditNoteDTOTransform - The command credit note DTO transform service.
|
||||
* @param {typeof RefundCreditNote} refundCreditNoteModel - The refund credit note model.
|
||||
* @param {typeof Account} accountModel - The account model.
|
||||
* @param {typeof CreditNote} creditNoteModel - The credit note model.
|
||||
* @param {TenantModelProxy<typeof RefundCreditNote>} refundCreditNoteModel - The refund credit note model.
|
||||
* @param {TenantModelProxy<typeof Account>} accountModel - The account model.
|
||||
* @param {TenantModelProxy<typeof CreditNote>} creditNoteModel - The credit note model.
|
||||
*/
|
||||
constructor(
|
||||
private uow: UnitOfWork,
|
||||
@@ -29,10 +30,13 @@ export class CreateRefundCreditNoteService {
|
||||
private commandCreditNoteDTOTransform: CommandCreditNoteDTOTransform,
|
||||
|
||||
@Inject(RefundCreditNote.name)
|
||||
private refundCreditNoteModel: typeof RefundCreditNote,
|
||||
private refundCreditNoteModel: TenantModelProxy<typeof RefundCreditNote>,
|
||||
|
||||
@Inject(Account.name) private accountModel: typeof Account,
|
||||
@Inject(CreditNote.name) private creditNoteModel: typeof CreditNote,
|
||||
@Inject(Account.name)
|
||||
private accountModel: TenantModelProxy<typeof Account>,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -46,13 +50,13 @@ export class CreateRefundCreditNoteService {
|
||||
newCreditNoteDTO: ICreditNoteRefundDTO,
|
||||
): Promise<RefundCreditNote> {
|
||||
// Retrieve the credit note or throw not found service error.
|
||||
const creditNote = await this.creditNoteModel
|
||||
const creditNote = await this.creditNoteModel()
|
||||
.query()
|
||||
.findById(creditNoteId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Retrieve the withdrawal account or throw not found service error.
|
||||
const fromAccount = await this.accountModel
|
||||
const fromAccount = await this.accountModel()
|
||||
.query()
|
||||
.findById(newCreditNoteDTO.fromAccountId)
|
||||
.throwIfNotFound();
|
||||
@@ -76,7 +80,7 @@ export class CreateRefundCreditNoteService {
|
||||
} as IRefundCreditNoteCreatingPayload);
|
||||
|
||||
// Stores the refund credit note graph to the storage layer.
|
||||
const refundCreditNote = await this.refundCreditNoteModel
|
||||
const refundCreditNote = await this.refundCreditNoteModel()
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...this.transformDTOToModel(creditNote, newCreditNoteDTO),
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import { RefundCreditNote } from '../models/RefundCreditNote';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteRefundCreditNoteService {
|
||||
@@ -21,7 +22,9 @@ export class DeleteRefundCreditNoteService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(RefundCreditNote.name)
|
||||
private readonly refundCreditNoteModel: typeof RefundCreditNote,
|
||||
private readonly refundCreditNoteModel: TenantModelProxy<
|
||||
typeof RefundCreditNote
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -31,7 +34,7 @@ export class DeleteRefundCreditNoteService {
|
||||
*/
|
||||
public deleteCreditNoteRefund = async (refundCreditId: number) => {
|
||||
// Retrieve the old credit note or throw not found service error.
|
||||
const oldRefundCredit = await this.refundCreditNoteModel
|
||||
const oldRefundCredit = await this.refundCreditNoteModel()
|
||||
.query()
|
||||
.findById(refundCreditId)
|
||||
.throwIfNotFound();
|
||||
@@ -56,7 +59,7 @@ export class DeleteRefundCreditNoteService {
|
||||
eventPayload,
|
||||
);
|
||||
// Deletes the refund credit note graph from the storage.
|
||||
await this.refundCreditNoteModel
|
||||
await this.refundCreditNoteModel()
|
||||
.query(trx)
|
||||
.findById(refundCreditId)
|
||||
.delete();
|
||||
|
||||
@@ -3,15 +3,18 @@ import { ERRORS } from '../../CreditNotes/constants';
|
||||
import { RefundCreditNote } from '../models/RefundCreditNote';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class RefundCreditNoteService {
|
||||
/**
|
||||
* @param {typeof RefundCreditNote} refundCreditNoteModel - The refund credit note model.
|
||||
* @param {TenantModelProxy<typeof RefundCreditNote>} refundCreditNoteModel - The refund credit note model.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(RefundCreditNote.name)
|
||||
private readonly refundCreditNoteModel: typeof RefundCreditNote,
|
||||
private readonly refundCreditNoteModel: TenantModelProxy<
|
||||
typeof RefundCreditNote
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -22,7 +25,7 @@ export class RefundCreditNoteService {
|
||||
public getCreditNoteRefundOrThrowError = async (
|
||||
refundCreditId: number,
|
||||
): Promise<RefundCreditNote> => {
|
||||
const refundCreditNote = await this.refundCreditNoteModel
|
||||
const refundCreditNote = await this.refundCreditNoteModel()
|
||||
.query()
|
||||
.findById(refundCreditId);
|
||||
if (!refundCreditNote) {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CreditNote } from '@/modules/CreditNotes/models/CreditNote';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class RefundSyncCreditNoteBalanceService {
|
||||
/**
|
||||
* @param {typeof CreditNote} creditNoteModel - The credit note model.
|
||||
* @param {TenantModelProxy<typeof CreditNote>} creditNoteModel - The credit note model.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -21,9 +22,9 @@ export class RefundSyncCreditNoteBalanceService {
|
||||
public incrementCreditNoteRefundAmount = async (
|
||||
creditNoteId: number,
|
||||
amount: number,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> => {
|
||||
await this.creditNoteModel
|
||||
await this.creditNoteModel()
|
||||
.query(trx)
|
||||
.findById(creditNoteId)
|
||||
.increment('refunded_amount', amount);
|
||||
@@ -38,9 +39,9 @@ export class RefundSyncCreditNoteBalanceService {
|
||||
public decrementCreditNoteRefundAmount = async (
|
||||
creditNoteId: number,
|
||||
amount: number,
|
||||
trx?: Knex.Transaction
|
||||
trx?: Knex.Transaction,
|
||||
): Promise<void> => {
|
||||
await this.creditNoteModel
|
||||
await this.creditNoteModel()
|
||||
.query(trx)
|
||||
.findById(creditNoteId)
|
||||
.decrement('refunded_amount', amount);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectab
|
||||
import { RefundCreditNote } from '../models/RefundCreditNote';
|
||||
import { RefundCreditNoteTransformer } from '@/modules/CreditNotes/queries/RefundCreditNoteTransformer';
|
||||
import { IRefundCreditNotePOJO } from '../types/CreditNoteRefunds.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ListCreditNoteRefunds {
|
||||
@@ -10,7 +11,9 @@ export class ListCreditNoteRefunds {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(RefundCreditNote.name)
|
||||
private readonly refundCreditNoteModel: typeof RefundCreditNote,
|
||||
private readonly refundCreditNoteModel: TenantModelProxy<
|
||||
typeof RefundCreditNote
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -22,7 +25,7 @@ export class ListCreditNoteRefunds {
|
||||
creditNoteId: number,
|
||||
): Promise<IRefundCreditNotePOJO[]> {
|
||||
// Retrieve refund credit notes associated to the given credit note.
|
||||
const refundCreditTransactions = await this.refundCreditNoteModel
|
||||
const refundCreditTransactions = await this.refundCreditNoteModel()
|
||||
.query()
|
||||
.where('creditNoteId', creditNoteId)
|
||||
.withGraphFetched('creditNote')
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { RefundCreditNote } from '../models/RefundCreditNote';
|
||||
import { RefundCreditNoteTransformer } from '../../CreditNotes/queries/RefundCreditNoteTransformer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetRefundCreditNoteTransaction {
|
||||
@@ -12,9 +13,10 @@ export class GetRefundCreditNoteTransaction {
|
||||
private readonly transformer: RefundCreditNoteTransformer,
|
||||
|
||||
@Inject(RefundCreditNote.name)
|
||||
private readonly refundCreditNoteModel: typeof RefundCreditNote,
|
||||
) {
|
||||
}
|
||||
private readonly refundCreditNoteModel: TenantModelProxy<
|
||||
typeof RefundCreditNote
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieve credit note associated invoices to apply.
|
||||
@@ -22,9 +24,9 @@ export class GetRefundCreditNoteTransaction {
|
||||
* @returns {Promise<IRefundCreditNote>}
|
||||
*/
|
||||
public async getRefundCreditTransaction(
|
||||
refundCreditId: number
|
||||
refundCreditId: number,
|
||||
): Promise<RefundCreditNote> {
|
||||
const refundCreditNote = await this.refundCreditNoteModel
|
||||
const refundCreditNote = await this.refundCreditNoteModel()
|
||||
.query()
|
||||
.findById(refundCreditId)
|
||||
.withGraphFetched('fromAccount')
|
||||
|
||||
@@ -12,6 +12,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreateCreditNoteService {
|
||||
@@ -30,10 +31,10 @@ export class CreateCreditNoteService {
|
||||
private readonly commandCreditNoteDTOTransform: CommandCreditNoteDTOTransform,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
|
||||
@Inject(Contact.name)
|
||||
private readonly contactModel: typeof Contact,
|
||||
private readonly contactModel: TenantModelProxy<typeof Contact>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -49,7 +50,7 @@ export class CreateCreditNoteService {
|
||||
creditNoteDTO,
|
||||
});
|
||||
// Validate customer existance.
|
||||
const customer = await this.contactModel
|
||||
const customer = await this.contactModel()
|
||||
.query()
|
||||
.modify('customer')
|
||||
.findById(creditNoteDTO.customerId)
|
||||
@@ -78,9 +79,11 @@ export class CreateCreditNoteService {
|
||||
} as ICreditNoteCreatingPayload);
|
||||
|
||||
// Upsert the credit note graph.
|
||||
const creditNote = await this.creditNoteModel.query(trx).upsertGraph({
|
||||
...creditNoteModel,
|
||||
});
|
||||
const creditNote = await this.creditNoteModel()
|
||||
.query(trx)
|
||||
.upsertGraph({
|
||||
...creditNoteModel,
|
||||
});
|
||||
// Triggers `onCreditNoteCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.creditNote.onCreated, {
|
||||
creditNoteDTO,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { LedgerStorageService } from '@/modules/Ledger/LedgerStorage.service';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { AccountRepository } from '@/modules/Accounts/repositories/Account.repository';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class CreditNoteGLEntries {
|
||||
@@ -12,7 +13,7 @@ export class CreditNoteGLEntries {
|
||||
private readonly accountRepository: AccountRepository,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,14 +7,13 @@ import {
|
||||
import { ERRORS } from '../constants';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { CreditNoteAppliedInvoice } from '../../CreditNotesApplyInvoice/models/CreditNoteAppliedInvoice';
|
||||
import {
|
||||
RefundCreditNote as RefundCreditNoteModel,
|
||||
} from '../../CreditNoteRefunds/models/RefundCreditNote';
|
||||
import { RefundCreditNote as RefundCreditNoteModel } from '../../CreditNoteRefunds/models/RefundCreditNote';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteCreditNoteService {
|
||||
@@ -31,16 +30,20 @@ export class DeleteCreditNoteService {
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
|
||||
@Inject(ItemEntry.name)
|
||||
private readonly itemEntryModel: typeof ItemEntry,
|
||||
private readonly itemEntryModel: TenantModelProxy<typeof ItemEntry>,
|
||||
|
||||
@Inject(CreditNoteAppliedInvoice.name)
|
||||
private readonly creditNoteAppliedInvoiceModel: typeof CreditNoteAppliedInvoice,
|
||||
private readonly creditNoteAppliedInvoiceModel: TenantModelProxy<
|
||||
typeof CreditNoteAppliedInvoice
|
||||
>,
|
||||
|
||||
@Inject(RefundCreditNoteModel.name)
|
||||
private readonly refundCreditNoteModel: typeof RefundCreditNoteModel,
|
||||
private readonly refundCreditNoteModel: TenantModelProxy<
|
||||
typeof RefundCreditNoteModel
|
||||
>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -50,7 +53,7 @@ export class DeleteCreditNoteService {
|
||||
*/
|
||||
public async deleteCreditNote(creditNoteId: number): Promise<void> {
|
||||
// Retrieve the credit note or throw not found service error.
|
||||
const oldCreditNote = await this.creditNoteModel
|
||||
const oldCreditNote = await this.creditNoteModel()
|
||||
.query()
|
||||
.findById(creditNoteId)
|
||||
.throwIfNotFound();
|
||||
@@ -70,14 +73,14 @@ export class DeleteCreditNoteService {
|
||||
} as ICreditNoteDeletingPayload);
|
||||
|
||||
// Deletes the associated credit note entries.
|
||||
await this.itemEntryModel
|
||||
await this.itemEntryModel()
|
||||
.query(trx)
|
||||
.where('reference_id', creditNoteId)
|
||||
.where('reference_type', 'CreditNote')
|
||||
.delete();
|
||||
|
||||
// Deletes the credit note transaction.
|
||||
await this.creditNoteModel.query(trx).findById(creditNoteId).delete();
|
||||
await this.creditNoteModel().query(trx).findById(creditNoteId).delete();
|
||||
|
||||
// Triggers `onCreditNoteDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.creditNote.onDeleted, {
|
||||
@@ -96,7 +99,7 @@ export class DeleteCreditNoteService {
|
||||
private async validateCreditNoteHasNoRefundTransactions(
|
||||
creditNoteId: number,
|
||||
): Promise<void> {
|
||||
const refundTransactions = await this.refundCreditNoteModel
|
||||
const refundTransactions = await this.refundCreditNoteModel()
|
||||
.query()
|
||||
.where('creditNoteId', creditNoteId);
|
||||
|
||||
@@ -113,7 +116,7 @@ export class DeleteCreditNoteService {
|
||||
private async validateCreditNoteHasNoApplyInvoiceTransactions(
|
||||
creditNoteId: number,
|
||||
): Promise<void> {
|
||||
const appliedTransactions = await this.creditNoteAppliedInvoiceModel
|
||||
const appliedTransactions = await this.creditNoteAppliedInvoiceModel()
|
||||
.query()
|
||||
.where('creditNoteId', creditNoteId);
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { events } from '@/common/events/events';
|
||||
import { CommandCreditNoteDTOTransform } from './CommandCreditNoteDTOTransform.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditCreditNoteService {
|
||||
@@ -24,8 +25,11 @@ export class EditCreditNoteService {
|
||||
* @param {UnitOfWork} uow - The unit of work.
|
||||
*/
|
||||
constructor(
|
||||
@Inject(CreditNote.name) private creditNoteModel: typeof CreditNote,
|
||||
@Inject(Contact.name) private contactModel: typeof Contact,
|
||||
@Inject(CreditNote.name)
|
||||
private creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
@Inject(Contact.name)
|
||||
private contactModel: TenantModelProxy<typeof Contact>,
|
||||
|
||||
private commandCreditNoteDTOTransform: CommandCreditNoteDTOTransform,
|
||||
private itemsEntriesService: ItemsEntriesService,
|
||||
private eventPublisher: EventEmitter2,
|
||||
@@ -41,13 +45,13 @@ export class EditCreditNoteService {
|
||||
creditNoteEditDTO: ICreditNoteEditDTO,
|
||||
) {
|
||||
// Retrieve the sale invoice or throw not found service error.
|
||||
const oldCreditNote = await this.creditNoteModel
|
||||
const oldCreditNote = await this.creditNoteModel()
|
||||
.query()
|
||||
.findById(creditNoteId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validate customer existance.
|
||||
const customer = await this.contactModel
|
||||
const customer = await this.contactModel()
|
||||
.query()
|
||||
.findById(creditNoteEditDTO.customerId);
|
||||
|
||||
@@ -82,10 +86,12 @@ export class EditCreditNoteService {
|
||||
} as ICreditNoteEditingPayload);
|
||||
|
||||
// Saves the credit note graph to the storage.
|
||||
const creditNote = await this.creditNoteModel.query(trx).upsertGraph({
|
||||
id: creditNoteId,
|
||||
...creditNoteModel,
|
||||
});
|
||||
const creditNote = await this.creditNoteModel()
|
||||
.query(trx)
|
||||
.upsertGraph({
|
||||
id: creditNoteId,
|
||||
...creditNoteModel,
|
||||
});
|
||||
// Triggers `onCreditNoteEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.creditNote.onEdited, {
|
||||
trx,
|
||||
|
||||
@@ -10,6 +10,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class OpenCreditNoteService {
|
||||
@@ -23,7 +24,7 @@ export class OpenCreditNoteService {
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ export class OpenCreditNoteService {
|
||||
*/
|
||||
public openCreditNote = async (creditNoteId: number): Promise<CreditNote> => {
|
||||
// Retrieve the sale invoice or throw not found service error.
|
||||
const oldCreditNote = await this.creditNoteModel
|
||||
const oldCreditNote = await this.creditNoteModel()
|
||||
.query()
|
||||
.findById(creditNoteId)
|
||||
.throwIfNotFound();
|
||||
@@ -59,7 +60,7 @@ export class OpenCreditNoteService {
|
||||
eventPayload,
|
||||
);
|
||||
// Saves the credit note graph to the storage.
|
||||
const creditNote = await this.creditNoteModel
|
||||
const creditNote = await this.creditNoteModel()
|
||||
.query(trx)
|
||||
.updateAndFetchById(creditNoteId, {
|
||||
openedAt: new Date(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CreditNoteTransformer } from './CreditNoteTransformer';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class GetCreditNote {
|
||||
@@ -11,18 +12,16 @@ export class GetCreditNote {
|
||||
private readonly transformer: TransformerInjectable,
|
||||
|
||||
@Inject(CreditNote.name)
|
||||
private readonly creditNoteModel: typeof CreditNote,
|
||||
private readonly creditNoteModel: TenantModelProxy<typeof CreditNote>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Retrieve the credit note graph.
|
||||
* @param {number} tenantId
|
||||
* @param {number} creditNoteId
|
||||
* @returns
|
||||
*/
|
||||
public async getCreditNote(creditNoteId: number) {
|
||||
// Retrieve the vendor credit model graph.
|
||||
const creditNote = await this.creditNoteModel
|
||||
const creditNote = await this.creditNoteModel()
|
||||
.query()
|
||||
.findById(creditNoteId)
|
||||
.withGraphFetched('entries.item')
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user