feat(nestjs): migrate to NestJS

This commit is contained in:
Ahmed Bouhuolia
2025-04-07 11:51:24 +02:00
parent f068218a16
commit 55fcc908ef
3779 changed files with 631 additions and 195332 deletions

View File

@@ -0,0 +1,139 @@
/* eslint-disable global-require */
import { Model } from 'objection';
import { castArray } from 'lodash';
import { AccountTypesUtils } from '@/libs/accounts-utils/AccountTypesUtils';
import { PlaidItem } from '@/modules/BankingPlaid/models/PlaidItem';
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
export class BankAccount extends TenantBaseModel {
public name!: string;
public slug!: string;
public code!: string;
public index!: number;
public accountType!: string;
public predefined!: boolean;
public currencyCode!: string;
public active!: boolean;
public bankBalance!: number;
public lastFeedsUpdatedAt!: string | null;
public amount!: number;
public plaidItemId!: number;
public plaidItem!: PlaidItem;
/**
* Table name.
*/
static get tableName() {
return 'accounts';
}
/**
* Timestamps columns.
*/
static get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return ['accountTypeLabel'];
}
/**
* Retrieve account type label.
*/
get accountTypeLabel(): string {
return AccountTypesUtils.getType(this.accountType, 'label');
}
/**
* Allows to mark model as resourceable to viewable and filterable.
*/
static get resourceable() {
return true;
}
/**
* Model modifiers.
*/
static get modifiers() {
return {
/**
* Inactive/Active mode.
*/
inactiveMode(query, active = false) {
query.where('accounts.active', !active);
},
};
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const AccountTransaction = require('models/AccountTransaction');
return {
/**
* Account model may has many transactions.
*/
transactions: {
relation: Model.HasManyRelation,
modelClass: AccountTransaction.default,
join: {
from: 'accounts.id',
to: 'accounts_transactions.accountId',
},
},
};
}
/**
* Detarmines whether the given type equals the account type.
* @param {string} accountType
* @return {boolean}
*/
isAccountType(accountType) {
const types = castArray(accountType);
return types.indexOf(this.accountType) !== -1;
}
/**
* Detarmine whether the given parent type equals the account type.
* @param {string} parentType
* @return {boolean}
*/
isParentType(parentType) {
return AccountTypesUtils.isParentTypeEqualsKey(
this.accountType,
parentType
);
}
// /**
// * Model settings.
// */
// static get meta() {
// return CashflowAccountSettings;
// }
// /**
// * Retrieve the default custom views, roles and columns.
// */
// static get defaultViews() {
// return DEFAULT_VIEWS;
// }
/**
* Model search roles.
*/
static get searchRoles() {
return [
{ condition: 'or', fieldKey: 'name', comparator: 'contains' },
{ condition: 'or', fieldKey: 'code', comparator: 'like' },
];
}
}

View File

@@ -0,0 +1,239 @@
import { Model } from 'objection';
import { BaseModel } from '@/models/Model';
import {
getCashflowAccountTransactionsTypes,
getCashflowTransactionType,
} from '../utils';
import { CASHFLOW_DIRECTION, CASHFLOW_TRANSACTION_TYPE } from '../constants';
import { BankTransactionLine } from './BankTransactionLine';
import { Account } from '@/modules/Accounts/models/Account.model';
export class BankTransaction extends BaseModel {
transactionType: string;
amount: number;
exchangeRate: number;
uncategorize: boolean;
uncategorizedTransaction!: boolean;
currencyCode: string;
date: Date;
transactionNumber: string;
referenceNo: string;
description: string;
cashflowAccountId: number;
creditAccountId: number;
categorizeRefType: string;
categorizeRefId: number;
uncategorized: boolean;
branchId: number;
userId: number;
publishedAt: Date;
entries: BankTransactionLine[];
cashflowAccount: Account;
creditAccount: Account;
uncategorizedTransactionId: number;
/**
* Table name.
* @returns {string}
*/
static get tableName() {
return 'cashflow_transactions';
}
/**
* Timestamps columns.
* @returns {Array<string>}
*/
static get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Virtual attributes.
* @returns {Array<string>}
*/
static get virtualAttributes() {
return [
'localAmount',
'transactionTypeFormatted',
'isPublished',
'typeMeta',
'isCashCredit',
'isCashDebit',
];
}
/**
* Retrieves the local amount of cashflow transaction.
* @returns {number}
*/
get localAmount() {
return this.amount * this.exchangeRate;
}
/**
* Detarmines whether the cashflow transaction is published.
* @return {boolean}
*/
get isPublished() {
return !!this.publishedAt;
}
/**
* Transaction type formatted.
* @returns {string}
*/
// get transactionTypeFormatted() {
// return getCashflowTransactionFormattedType(this.transactionType);
// }
get typeMeta() {
return getCashflowTransactionType(
this.transactionType as CASHFLOW_TRANSACTION_TYPE,
);
}
/**
* Detarmines whether the cashflow transaction cash credit type.
* @returns {boolean}
*/
get isCashCredit() {
return this.typeMeta?.direction === CASHFLOW_DIRECTION.OUT;
}
/**
* Detarmines whether the cashflow transaction cash debit type.
* @returns {boolean}
*/
get isCashDebit() {
return this.typeMeta?.direction === CASHFLOW_DIRECTION.IN;
}
/**
* Detarmines whether the transaction imported from uncategorized transaction.
* @returns {boolean}
*/
get isCategroizedTranasction() {
return !!this.uncategorizedTransaction;
}
/**
* Model modifiers.
*/
static get modifiers() {
return {
/**
* Filter the published transactions.
*/
published(query) {
query.whereNot('published_at', null);
},
/**
* Filter the not categorized transactions.
*/
notCategorized(query) {
query.whereNull('cashflowTransactions.uncategorizedTransactionId');
},
/**
* Filter the categorized transactions.
*/
categorized(query) {
query.whereNotNull('cashflowTransactions.uncategorizedTransactionId');
},
};
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const { BankTransactionLine } = require('./BankTransactionLine');
const {
AccountTransaction,
} = require('../../Accounts/models/AccountTransaction.model');
const { Account } = require('../../Accounts/models/Account.model');
const {
MatchedBankTransaction,
} = require('../../BankingMatching/models/MatchedBankTransaction');
return {
/**
* Cashflow transaction entries.
*/
entries: {
relation: Model.HasManyRelation,
modelClass: BankTransactionLine,
join: {
from: 'cashflow_transactions.id',
to: 'cashflow_transaction_lines.cashflowTransactionId',
},
filter: (query) => {
query.orderBy('index', 'ASC');
},
},
/**
* Cashflow transaction has associated account transactions.
*/
transactions: {
relation: Model.HasManyRelation,
modelClass: AccountTransaction,
join: {
from: 'cashflow_transactions.id',
to: 'accounts_transactions.referenceId',
},
filter(builder) {
builder.where('reference_type', 'CashflowTransaction');
},
},
/**
* Cashflow transaction may has associated cashflow account.
*/
cashflowAccount: {
relation: Model.BelongsToOneRelation,
modelClass: Account,
join: {
from: 'cashflow_transactions.cashflowAccountId',
to: 'accounts.id',
},
},
/**
* Cashflow transcation may has associated to credit account.
*/
creditAccount: {
relation: Model.BelongsToOneRelation,
modelClass: Account,
join: {
from: 'cashflow_transactions.creditAccountId',
to: 'accounts.id',
},
},
/**
* Cashflow transaction may belongs to matched bank transaction.
*/
matchedBankTransaction: {
relation: Model.HasManyRelation,
modelClass: MatchedBankTransaction,
join: {
from: 'cashflow_transactions.id',
to: 'matched_bank_transactions.referenceId',
},
filter: (query) => {
const referenceTypes = getCashflowAccountTransactionsTypes();
query.whereIn('reference_type', referenceTypes);
},
},
};
}
}

View File

@@ -0,0 +1,53 @@
/* eslint-disable global-require */
import { Model } from 'objection';
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
export class BankTransactionLine extends TenantBaseModel{
/**
* Table name.
*/
static get tableName() {
return 'cashflow_transaction_lines';
}
/**
* Timestamps columns.
*/
static get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Determine whether the model is resourceable.
* @returns {boolean}
*/
static get resourceable(): boolean {
return false;
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const { Account } = require('../../Accounts/models/Account.model');
return {
cashflowAccount: {
relation: Model.BelongsToOneRelation,
modelClass: Account,
join: {
from: 'cashflow_transaction_lines.cashflowAccountId',
to: 'accounts.id',
},
},
creditAccount: {
relation: Model.BelongsToOneRelation,
modelClass: Account,
join: {
from: 'cashflow_transaction_lines.creditAccountId',
to: 'accounts.id',
},
},
};
}
}

View File

@@ -0,0 +1,240 @@
/* eslint-disable global-require */
import * as moment from 'moment';
import { Model } from 'objection';
import { BaseModel } from '@/models/Model';
export class UncategorizedBankTransaction extends BaseModel {
readonly amount!: number;
readonly date!: Date | string;
readonly categorized!: boolean;
readonly accountId!: number;
readonly referenceNo!: string;
readonly payee!: string;
readonly description!: string;
readonly plaidTransactionId!: string;
readonly recognizedTransactionId!: number;
readonly excludedAt: Date;
readonly pending: boolean;
readonly categorizeRefId!: number;
readonly categorizeRefType!: string;
/**
* Table name.
*/
static get tableName() {
return 'uncategorized_cashflow_transactions';
}
/**
* Timestamps columns.
*/
get timestamps() {
return ['createdAt', 'updatedAt'];
}
/**
* Virtual attributes.
*/
static get virtualAttributes() {
return [
'withdrawal',
'deposit',
'isDepositTransaction',
'isWithdrawalTransaction',
'isRecognized',
'isExcluded',
'isPending',
];
}
// static get meta() {
// return UncategorizedCashflowTransactionMeta;
// }
/**
* Retrieves the withdrawal amount.
* @returns {number}
*/
public get withdrawal() {
return this.amount < 0 ? Math.abs(this.amount) : 0;
}
/**
* Retrieves the deposit amount.
* @returns {number}
*/
public get deposit(): number {
return this.amount > 0 ? Math.abs(this.amount) : 0;
}
/**
* Detarmines whether the transaction is deposit transaction.
*/
public get isDepositTransaction(): boolean {
return 0 < this.deposit;
}
/**
* Detarmines whether the transaction is withdrawal transaction.
*/
public get isWithdrawalTransaction(): boolean {
return 0 < this.withdrawal;
}
/**
* Detarmines whether the transaction is recognized.
*/
public get isRecognized(): boolean {
return !!this.recognizedTransactionId;
}
/**
* Detarmines whether the transaction is excluded.
* @returns {boolean}
*/
public get isExcluded(): boolean {
return !!this.excludedAt;
}
/**
* Detarmines whether the transaction is pending.
* @returns {boolean}
*/
public get isPending(): boolean {
return !!this.pending;
}
/**
* Model modifiers.
*/
static get modifiers() {
return {
/**
* Filters the not excluded transactions.
*/
notExcluded(query) {
query.whereNull('excluded_at');
},
/**
* Filters the excluded transactions.
*/
excluded(query) {
query.whereNotNull('excluded_at');
},
/**
* Filter out the recognized transactions.
* @param query
*/
recognized(query) {
query.whereNotNull('recognizedTransactionId');
},
/**
* Filter out the not recognized transactions.
* @param query
*/
notRecognized(query) {
query.whereNull('recognizedTransactionId');
},
categorized(query) {
query.whereNotNull('categorizeRefType');
query.whereNotNull('categorizeRefId');
},
notCategorized(query) {
query.whereNull('categorizeRefType');
query.whereNull('categorizeRefId');
},
/**
* Filters the not pending transactions.
*/
notPending(query) {
query.where('pending', false);
},
/**
* Filters the pending transactions.
*/
pending(query) {
query.where('pending', true);
},
minAmount(query, minAmount) {
query.where('amount', '>=', minAmount);
},
maxAmount(query, maxAmount) {
query.where('amount', '<=', maxAmount);
},
toDate(query, toDate) {
const dateFormat = 'YYYY-MM-DD';
const _toDate = moment(toDate).endOf('day').format(dateFormat);
query.where('date', '<=', _toDate);
},
fromDate(query, fromDate) {
const dateFormat = 'YYYY-MM-DD';
const _fromDate = moment(fromDate).startOf('day').format(dateFormat);
query.where('date', '>=', _fromDate);
},
};
}
/**
* Relationship mapping.
*/
static get relationMappings() {
const { Account } = require('../../Accounts/models/Account.model');
const {
RecognizedBankTransaction,
} = require('../../BankingTranasctionsRegonize/models/RecognizedBankTransaction');
const {
MatchedBankTransaction,
} = require('../../BankingMatching/models/MatchedBankTransaction');
return {
/**
* Transaction may has associated to account.
*/
account: {
relation: Model.BelongsToOneRelation,
modelClass: Account,
join: {
from: 'uncategorized_cashflow_transactions.accountId',
to: 'accounts.id',
},
},
/**
* Transaction may has association to recognized transaction.
*/
recognizedTransaction: {
relation: Model.HasOneRelation,
modelClass: RecognizedBankTransaction,
join: {
from: 'uncategorized_cashflow_transactions.recognizedTransactionId',
to: 'recognized_bank_transactions.id',
},
},
/**
* Uncategorized transaction may has association to matched transaction.
*/
matchedBankTransactions: {
relation: Model.HasManyRelation,
modelClass: MatchedBankTransaction,
join: {
from: 'uncategorized_cashflow_transactions.id',
to: 'matched_bank_transactions.uncategorizedTransactionId',
},
},
};
}
}