import { Knex } from 'knex'; import { Inject, Injectable, Scope } from '@nestjs/common'; import { TenantRepository } from '@/common/repository/TenantRepository'; import { TENANCY_DB_CONNECTION } from '@/modules/Tenancy/TenancyDB/TenancyDB.constants'; import { Account } from '../models/Account.model'; import { I18nService } from 'nestjs-i18n'; import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; import { PrepardExpenses, StripeClearingAccount, TaxPayableAccount, UnearnedRevenueAccount, } from '../Accounts.constants'; @Injectable({ scope: Scope.REQUEST }) export class AccountRepository extends TenantRepository { constructor( private readonly i18n: I18nService, private readonly tenancyContext: TenancyContext, @Inject(TENANCY_DB_CONNECTION) private readonly tenantDBKnex: Knex, ) { super(); } /** * Gets the repository's model. */ get model(): typeof Account { return Account.bindKnex(this.tenantDBKnex); } /** * Retrieve accounts dependency graph. * @param {string} withRelation * @param {Knex.Transaction} trx * @returns {} */ public async getDependencyGraph( withRelation?: string, trx?: Knex.Transaction, ) { const accounts = await this.all(withRelation, trx); return this.model.toDependencyGraph(accounts); } /** * Retrieve account by slug. * @param {string} slug * @return {Promise} */ public findBySlug(slug: string) { return this.findOne({ slug }); } // /** // * Changes account balance. // * @param {number} accountId // * @param {number} amount // * @return {Promise} // */ // async balanceChange(accountId: number, amount: number): Promise { // const method: string = amount < 0 ? 'decrement' : 'increment'; // await this.model.query().where('id', accountId)[method]('amount', amount); // this.flushCache(); // } /** * Activate user by the given id. * @param {number} userId - User id. * @return {Promise} */ activateById(userId: number): Promise { return super.update({ active: 1 }, { id: userId }); } /** * Inactivate user by the given id. * @param {number} userId - User id. * @return {Promise} */ inactivateById(userId: number): Promise { return super.update({ active: 0 }, { id: userId }); } /** * Activate user by the given id. * @param {number} userId - User id. * @return {Promise} */ async activateByIds(userIds: number[], trx): Promise { const results = await this.model .query(trx) .whereIn('id', userIds) .patch({ active: true }); return results; } /** * Inactivate user by the given id. * @param {number} userId - User id. * @return {Promise} */ async inactivateByIds(userIds: number[], trx): Promise { const results = await this.model .query(trx) .whereIn('id', userIds) .patch({ active: false }); return results; } /** * * @param {string} currencyCode * @param extraAttrs * @param trx * @returns */ findOrCreateAccountReceivable = async ( currencyCode: string = '', extraAttrs = {}, trx?: Knex.Transaction, ) => { let result = await this.model .query(trx) .onBuild((query) => { if (currencyCode) { query.where('currencyCode', currencyCode); } query.where('accountType', 'accounts-receivable'); }) .first(); if (!result) { result = await this.model.query(trx).insertAndFetch({ name: this.i18n.t('account.accounts_receivable.currency', { args: { currency: currencyCode }, }), accountType: 'accounts-receivable', currencyCode, active: 1, ...extraAttrs, }); } return result; }; /** * Find or create tax payable account. * @param {Record}extraAttrs * @param {Knex.Transaction} trx * @returns */ async findOrCreateTaxPayable( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { let result = await this.model .query(trx) .findOne({ slug: TaxPayableAccount.slug, ...extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...TaxPayableAccount, ...extraAttrs, }); } return result; } findOrCreateAccountsPayable = async ( currencyCode: string = '', extraAttrs = {}, trx?: Knex.Transaction, ) => { let result = await this.model .query(trx) .onBuild((query) => { if (currencyCode) { query.where('currencyCode', currencyCode); } query.where('accountType', 'accounts-payable'); }) .first(); if (!result) { result = await this.model.query(trx).insertAndFetch({ name: this.i18n.t('account.accounts_payable.currency', { args: { currency: currencyCode }, }), accountType: 'accounts-payable', currencyCode, active: 1, ...extraAttrs, }); } return result; }; /** * Finds or creates the unearned revenue. * @param {Record} extraAttrs * @param {Knex.Transaction} trx * @returns */ public async findOrCreateUnearnedRevenue( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: UnearnedRevenueAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...UnearnedRevenueAccount, ..._extraAttrs, }); } return result; } /** * Finds or creates the prepard expenses account. * @param {Record} extraAttrs * @param {Knex.Transaction} trx * @returns */ public async findOrCreatePrepardExpenses( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: PrepardExpenses.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...PrepardExpenses, ..._extraAttrs, }); } return result; } /** * Finds or creates the stripe clearing account. * @param {Record} extraAttrs * @param {Knex.Transaction} trx * @returns */ public async findOrCreateStripeClearing( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: StripeClearingAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...StripeClearingAccount, ..._extraAttrs, }); } return result; } /** * Finds or creates the discount expense account. * @param {Record} extraAttrs * @param {Knex.Transaction} trx * @returns */ public async findOrCreateDiscountAccount( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: DiscountExpenseAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...DiscountExpenseAccount, ..._extraAttrs, }); } return result; } public async findOrCreatePurchaseDiscountAccount( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: PurchaseDiscountAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...PurchaseDiscountAccount, ..._extraAttrs, }); } return result; } public async findOrCreateOtherChargesAccount( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: OtherChargesAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...OtherChargesAccount, ..._extraAttrs, }); } return result; } public async findOrCreateOtherExpensesAccount( extraAttrs: Record = {}, trx?: Knex.Transaction, ) { const tenantMeta = await this.tenancyContext.getTenantMetadata(); const _extraAttrs = { currencyCode: tenantMeta.baseCurrency, ...extraAttrs, }; let result = await this.model .query(trx) .findOne({ slug: OtherExpensesAccount.slug, ..._extraAttrs }); if (!result) { result = await this.model.query(trx).insertAndFetch({ ...OtherExpensesAccount, ..._extraAttrs, }); } return result; } }