mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-27 01:59:48 +00:00
- Add AccountsSettingsService for managing account-related settings - Update validators, create and edit services to use settings - Add constants for account configuration - Update frontend utils and translations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
157 lines
5.6 KiB
TypeScript
157 lines
5.6 KiB
TypeScript
import { Inject, Injectable } from '@nestjs/common';
|
|
import { kebabCase } from 'lodash';
|
|
import { Knex } from 'knex';
|
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
|
import {
|
|
IAccountEventCreatingPayload,
|
|
CreateAccountParams,
|
|
IAccountEventCreatedPayload,
|
|
} from './Accounts.types';
|
|
import { CommandAccountValidators } from './CommandAccountValidators.service';
|
|
import { Account } from './models/Account.model';
|
|
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
|
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';
|
|
import { AccountsSettingsService } from './AccountsSettings.service';
|
|
|
|
@Injectable()
|
|
export class CreateAccountService {
|
|
/**
|
|
* @param {TenantModelProxy<typeof Account>} accountModel - The account model proxy.
|
|
* @param {EventEmitter2} eventEmitter - The event emitter.
|
|
* @param {UnitOfWork} uow - The unit of work.
|
|
* @param {CommandAccountValidators} validator - The command account validators.
|
|
* @param {TenancyContext} tenancyContext - The tenancy context.
|
|
*/
|
|
constructor(
|
|
@Inject(Account.name)
|
|
private readonly accountModel: TenantModelProxy<typeof Account>,
|
|
private readonly eventEmitter: EventEmitter2,
|
|
private readonly uow: UnitOfWork,
|
|
private readonly validator: CommandAccountValidators,
|
|
private readonly tenancyContext: TenancyContext,
|
|
private readonly accountsSettings: AccountsSettingsService,
|
|
) {}
|
|
|
|
/**
|
|
* Authorize the account creation.
|
|
* @param {CreateAccountDTO} accountDTO
|
|
*/
|
|
private authorize = async (
|
|
accountDTO: CreateAccountDTO,
|
|
baseCurrency: string,
|
|
params?: CreateAccountParams,
|
|
) => {
|
|
const { accountCodeRequired, accountCodeUnique } =
|
|
await this.accountsSettings.getAccountsSettings();
|
|
|
|
// Validate account code required when setting is enabled.
|
|
if (accountCodeRequired) {
|
|
this.validator.validateAccountCodeRequiredOrThrow(accountDTO.code);
|
|
}
|
|
// Validate the account code uniquiness when setting is enabled.
|
|
if (accountCodeUnique && accountDTO.code?.trim()) {
|
|
await this.validator.isAccountCodeUniqueOrThrowError(accountDTO.code);
|
|
}
|
|
// Validate account name uniquiness.
|
|
if (!params.ignoreUniqueName) {
|
|
await this.validator.validateAccountNameUniquiness(accountDTO.name);
|
|
}
|
|
// Retrieve the account type meta or throw service error if not found.
|
|
this.validator.getAccountTypeOrThrowError(accountDTO.accountType);
|
|
|
|
// Ingore the parent account validation if not presented.
|
|
if (accountDTO.parentAccountId) {
|
|
const parentAccount = await this.validator.getParentAccountOrThrowError(
|
|
accountDTO.parentAccountId,
|
|
);
|
|
this.validator.throwErrorIfParentHasDiffType(accountDTO, parentAccount);
|
|
|
|
// Inherit active status from parent account.
|
|
accountDTO.active = parentAccount.active;
|
|
|
|
// Validate should currency code be the same currency of parent account.
|
|
this.validator.validateCurrentSameParentAccount(
|
|
accountDTO,
|
|
parentAccount,
|
|
baseCurrency,
|
|
);
|
|
// Validates the max depth level of accounts chart.
|
|
await this.validator.validateMaxParentAccountDepthLevels(
|
|
accountDTO.parentAccountId,
|
|
);
|
|
}
|
|
// Validates the given account type supports the multi-currency.
|
|
this.validator.validateAccountTypeSupportCurrency(accountDTO, baseCurrency);
|
|
};
|
|
|
|
/**
|
|
* Transformes the create account DTO to input model.
|
|
* @param {IAccountCreateDTO} createAccountDTO
|
|
*/
|
|
private transformDTOToModel = (
|
|
createAccountDTO: CreateAccountDTO,
|
|
baseCurrency: string,
|
|
): PartialModelObject<Account> => {
|
|
return {
|
|
...createAccountDTO,
|
|
slug: kebabCase(createAccountDTO.name),
|
|
currencyCode: createAccountDTO.currencyCode || baseCurrency,
|
|
|
|
// Mark the account is Plaid owner since Plaid item/account is defined on creating.
|
|
isSyncingOwner: Boolean(
|
|
createAccountDTO.plaidAccountId || createAccountDTO.plaidItemId,
|
|
),
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Creates a new account on the storage.
|
|
* @param {IAccountCreateDTO} accountDTO
|
|
* @returns {Promise<IAccount>}
|
|
*/
|
|
public createAccount = async (
|
|
accountDTO: CreateAccountDTO,
|
|
trx?: Knex.Transaction,
|
|
params: CreateAccountParams = { ignoreUniqueName: false },
|
|
): Promise<Account> => {
|
|
// Retrieves the given tenant metadata.
|
|
const tenant = await this.tenancyContext.getTenant(true);
|
|
|
|
// Authorize the account creation.
|
|
await this.authorize(accountDTO, tenant.metadata.baseCurrency, params);
|
|
|
|
// Transformes the DTO to model.
|
|
const accountInputModel = this.transformDTOToModel(
|
|
accountDTO,
|
|
tenant.metadata.baseCurrency,
|
|
);
|
|
// Creates a new account with associated transactions under unit-of-work envirement.
|
|
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
|
// Triggers `onAccountCreating` event.
|
|
await this.eventEmitter.emitAsync(events.accounts.onCreating, {
|
|
accountDTO,
|
|
trx,
|
|
} as IAccountEventCreatingPayload);
|
|
|
|
// Inserts account to the storage.
|
|
const account = await this.accountModel()
|
|
.query()
|
|
.insert({
|
|
...accountInputModel,
|
|
});
|
|
// Triggers `onAccountCreated` event.
|
|
await this.eventEmitter.emitAsync(events.accounts.onCreated, {
|
|
account,
|
|
accountId: account.id,
|
|
trx,
|
|
} as IAccountEventCreatedPayload);
|
|
|
|
return account;
|
|
}, trx);
|
|
};
|
|
}
|