mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -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' },
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user