mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 15:20:34 +00:00
refactor: bank rules e2e test cases
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import { QueryBuilder } from 'objection';
|
import { QueryBuilder, Model } from 'objection';
|
||||||
import Objection, { Model, Page } from 'objection';
|
|
||||||
|
|
||||||
interface PaginationResult<M extends Model> {
|
interface PaginationResult<M extends Model> {
|
||||||
results: M[];
|
results: M[];
|
||||||
@@ -10,13 +9,19 @@ interface PaginationResult<M extends Model> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class PaginationQueryBuilder<
|
export type PaginationQueryBuilderType<M extends Model> = QueryBuilder<
|
||||||
M extends Model,
|
M,
|
||||||
R = M[],
|
PaginationResult<M>
|
||||||
> extends Model.QueryBuilder<M, R> {
|
>;
|
||||||
pagination(page: number, pageSize: number): QueryBuilder<M, PaginationResult<M>> {
|
|
||||||
// @ts-ignore
|
class PaginationQueryBuilder<M extends Model, R = M[]> extends QueryBuilder<
|
||||||
return super.page(page, pageSize).runAfter(({ results, total }) => {
|
M,
|
||||||
|
R
|
||||||
|
> {
|
||||||
|
pagination(page: number, pageSize: number): PaginationQueryBuilderType<M> {
|
||||||
|
const query = super.page(page, pageSize);
|
||||||
|
|
||||||
|
return query.runAfter(({ results, total }) => {
|
||||||
return {
|
return {
|
||||||
results,
|
results,
|
||||||
pagination: {
|
pagination: {
|
||||||
@@ -25,7 +30,7 @@ class PaginationQueryBuilder<
|
|||||||
pageSize,
|
pageSize,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
}) as unknown as PaginationQueryBuilderType<M>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ export class Account extends TenantModel {
|
|||||||
// const ExpenseEntry = require('models/ExpenseCategory');
|
// const ExpenseEntry = require('models/ExpenseCategory');
|
||||||
// const ItemEntry = require('models/ItemEntry');
|
// const ItemEntry = require('models/ItemEntry');
|
||||||
// const UncategorizedTransaction = require('models/UncategorizedCashflowTransaction');
|
// const UncategorizedTransaction = require('models/UncategorizedCashflowTransaction');
|
||||||
const { PlaidItem } = require('../../Banking/models/PlaidItem.model');
|
const { PlaidItem } = require('../../BankingPlaid/models/PlaidItem');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -140,10 +140,10 @@ import { BankingTransactionsModule } from '../BankingTransactions/BankingTransac
|
|||||||
LedgerModule,
|
LedgerModule,
|
||||||
BankAccountsModule,
|
BankAccountsModule,
|
||||||
BankRulesModule,
|
BankRulesModule,
|
||||||
BankingTransactionsExcludeModule,
|
|
||||||
BankingTransactionsRegonizeModule,
|
|
||||||
BankingMatchingModule,
|
|
||||||
BankingTransactionsModule,
|
BankingTransactionsModule,
|
||||||
|
// BankingTransactionsExcludeModule,
|
||||||
|
// BankingTransactionsRegonizeModule,
|
||||||
|
// BankingMatchingModule,
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@@ -9,15 +9,18 @@ import {
|
|||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { BankRulesApplication } from './BankRulesApplication';
|
import { BankRulesApplication } from './BankRulesApplication';
|
||||||
import { ICreateBankRuleDTO, IEditBankRuleDTO } from './types';
|
import { ICreateBankRuleDTO, IEditBankRuleDTO } from './types';
|
||||||
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
|
import { BankRule } from './models/BankRule';
|
||||||
|
|
||||||
@Controller('banking/rules')
|
@Controller('banking/rules')
|
||||||
|
@PublicRoute()
|
||||||
export class BankRulesController {
|
export class BankRulesController {
|
||||||
constructor(private readonly bankRulesApplication: BankRulesApplication) {}
|
constructor(private readonly bankRulesApplication: BankRulesApplication) {}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
async createBankRule(
|
async createBankRule(
|
||||||
@Body() createRuleDTO: ICreateBankRuleDTO,
|
@Body() createRuleDTO: ICreateBankRuleDTO,
|
||||||
): Promise<void> {
|
): Promise<BankRule> {
|
||||||
return this.bankRulesApplication.createBankRule(createRuleDTO);
|
return this.bankRulesApplication.createBankRule(createRuleDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { EditBankRuleService } from './commands/EditBankRule.service';
|
|||||||
import { GetBankRuleService } from './queries/GetBankRule.service';
|
import { GetBankRuleService } from './queries/GetBankRule.service';
|
||||||
import { GetBankRulesService } from './queries/GetBankRules.service';
|
import { GetBankRulesService } from './queries/GetBankRules.service';
|
||||||
import { ICreateBankRuleDTO, IEditBankRuleDTO } from './types';
|
import { ICreateBankRuleDTO, IEditBankRuleDTO } from './types';
|
||||||
|
import { BankRule } from './models/BankRule';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BankRulesApplication {
|
export class BankRulesApplication {
|
||||||
@@ -21,7 +22,9 @@ export class BankRulesApplication {
|
|||||||
* @param {ICreateBankRuleDTO} createRuleDTO - Bank rule data.
|
* @param {ICreateBankRuleDTO} createRuleDTO - Bank rule data.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public createBankRule(createRuleDTO: ICreateBankRuleDTO): Promise<void> {
|
public createBankRule(
|
||||||
|
createRuleDTO: ICreateBankRuleDTO,
|
||||||
|
): Promise<BankRule> {
|
||||||
return this.createBankRuleService.createBankRule(createRuleDTO);
|
return this.createBankRuleService.createBankRule(createRuleDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,9 +22,8 @@ export class CreateBankRuleService {
|
|||||||
/**
|
/**
|
||||||
* Transforms the DTO to model.
|
* Transforms the DTO to model.
|
||||||
* @param {ICreateBankRuleDTO} createDTO
|
* @param {ICreateBankRuleDTO} createDTO
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
private transformDTO(createDTO: ICreateBankRuleDTO): Partial<BankRule> {
|
private transformDTO(createDTO: ICreateBankRuleDTO) {
|
||||||
return {
|
return {
|
||||||
...createDTO,
|
...createDTO,
|
||||||
};
|
};
|
||||||
@@ -33,19 +32,21 @@ export class CreateBankRuleService {
|
|||||||
/**
|
/**
|
||||||
* Creates a new bank rule.
|
* Creates a new bank rule.
|
||||||
* @param {ICreateBankRuleDTO} createRuleDTO
|
* @param {ICreateBankRuleDTO} createRuleDTO
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<BankRule>}
|
||||||
*/
|
*/
|
||||||
public async createBankRule(createRuleDTO: ICreateBankRuleDTO): Promise<void> {
|
public async createBankRule(
|
||||||
|
createRuleDTO: ICreateBankRuleDTO,
|
||||||
|
): Promise<BankRule> {
|
||||||
const transformDTO = this.transformDTO(createRuleDTO);
|
const transformDTO = this.transformDTO(createRuleDTO);
|
||||||
|
|
||||||
await this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||||
// Triggers `onBankRuleCreating` event.
|
// Triggers `onBankRuleCreating` event.
|
||||||
await this.eventPublisher.emitAsync(events.bankRules.onCreating, {
|
await this.eventPublisher.emitAsync(events.bankRules.onCreating, {
|
||||||
createRuleDTO,
|
createRuleDTO,
|
||||||
trx,
|
trx,
|
||||||
} as IBankRuleEventCreatingPayload);
|
} as IBankRuleEventCreatingPayload);
|
||||||
|
|
||||||
const bankRule = await this.bankRuleModel.query(trx).upsertGraph({
|
const bankRule = await this.bankRuleModel.query(trx).upsertGraphAndFetch({
|
||||||
...transformDTO,
|
...transformDTO,
|
||||||
});
|
});
|
||||||
// Triggers `onBankRuleCreated` event.
|
// Triggers `onBankRuleCreated` event.
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ export class GetBankRuleService {
|
|||||||
const bankRule = await this.bankRuleModel
|
const bankRule = await this.bankRuleModel
|
||||||
.query()
|
.query()
|
||||||
.findById(ruleId)
|
.findById(ruleId)
|
||||||
.withGraphFetched('conditions');
|
.withGraphFetched('conditions')
|
||||||
|
.withGraphFetched('assignAccount');
|
||||||
|
|
||||||
return this.transformer.transform(
|
return this.transformer.transform(
|
||||||
bankRule,
|
bankRule,
|
||||||
|
|||||||
@@ -80,10 +80,9 @@ export class PlaidSyncDb {
|
|||||||
item: PlaidItem,
|
item: PlaidItem,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const transformToPlaidAccounts = transformPlaidAccountToCreateAccount(
|
const transformToPlaidAccounts = R.curry(
|
||||||
item,
|
transformPlaidAccountToCreateAccount,
|
||||||
institution,
|
)(item, institution);
|
||||||
);
|
|
||||||
const accountCreateDTOs = R.map(transformToPlaidAccounts)(plaidAccounts);
|
const accountCreateDTOs = R.map(transformToPlaidAccounts)(plaidAccounts);
|
||||||
|
|
||||||
await bluebird.map(
|
await bluebird.map(
|
||||||
@@ -112,7 +111,7 @@ export class PlaidSyncDb {
|
|||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
// Transformes the Plaid transactions to cashflow create DTOs.
|
// Transformes the Plaid transactions to cashflow create DTOs.
|
||||||
const transformTransaction = transformPlaidTrxsToCashflowCreate(
|
const transformTransaction = R.curry(transformPlaidTrxsToCashflowCreate)(
|
||||||
cashflowAccount.id,
|
cashflowAccount.id,
|
||||||
);
|
);
|
||||||
const uncategorizedTransDTOs =
|
const uncategorizedTransDTOs =
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { CreateUncategorizedTransactionDTO } from '../BankingCategorize/types/Ba
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
const getAccountTypeFromPlaidAccountType = (
|
const getAccountTypeFromPlaidAccountType = (
|
||||||
plaidAccountType: PlaidAccountType
|
plaidAccountType: PlaidAccountType,
|
||||||
) => {
|
) => {
|
||||||
if (plaidAccountType === PlaidAccountType.Credit) {
|
if (plaidAccountType === PlaidAccountType.Credit) {
|
||||||
return ACCOUNT_TYPE.CREDIT_CARD;
|
return ACCOUNT_TYPE.CREDIT_CARD;
|
||||||
@@ -31,12 +31,11 @@ const getAccountTypeFromPlaidAccountType = (
|
|||||||
* @param {PlaidAccount} plaidAccount - Plaid account.
|
* @param {PlaidAccount} plaidAccount - Plaid account.
|
||||||
* @returns {IAccountCreateDTO}
|
* @returns {IAccountCreateDTO}
|
||||||
*/
|
*/
|
||||||
export const transformPlaidAccountToCreateAccount = R.curry(
|
export const transformPlaidAccountToCreateAccount = (
|
||||||
(
|
|
||||||
item: PlaidItem,
|
item: PlaidItem,
|
||||||
institution: PlaidInstitution,
|
institution: PlaidInstitution,
|
||||||
plaidAccount: PlaidAccount
|
plaidAccount: PlaidAccount,
|
||||||
): IAccountCreateDTO => {
|
): IAccountCreateDTO => {
|
||||||
return {
|
return {
|
||||||
name: `${institution.name} - ${plaidAccount.name}`,
|
name: `${institution.name} - ${plaidAccount.name}`,
|
||||||
code: '',
|
code: '',
|
||||||
@@ -49,8 +48,7 @@ export const transformPlaidAccountToCreateAccount = R.curry(
|
|||||||
plaidAccountId: plaidAccount.account_id,
|
plaidAccountId: plaidAccount.account_id,
|
||||||
plaidItemId: item.item_id,
|
plaidItemId: item.item_id,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transformes the plaid transaction to cashflow create DTO.
|
* Transformes the plaid transaction to cashflow create DTO.
|
||||||
@@ -59,10 +57,9 @@ export const transformPlaidAccountToCreateAccount = R.curry(
|
|||||||
* @param {PlaidTransaction} plaidTranasction - Plaid transaction.
|
* @param {PlaidTransaction} plaidTranasction - Plaid transaction.
|
||||||
* @returns {CreateUncategorizedTransactionDTO}
|
* @returns {CreateUncategorizedTransactionDTO}
|
||||||
*/
|
*/
|
||||||
export const transformPlaidTrxsToCashflowCreate = R.curry(
|
export const transformPlaidTrxsToCashflowCreate = (
|
||||||
(
|
|
||||||
cashflowAccountId: number,
|
cashflowAccountId: number,
|
||||||
plaidTranasction: PlaidTransactionBase
|
plaidTranasction: PlaidTransactionBase,
|
||||||
): CreateUncategorizedTransactionDTO => {
|
): CreateUncategorizedTransactionDTO => {
|
||||||
return {
|
return {
|
||||||
date: plaidTranasction.date,
|
date: plaidTranasction.date,
|
||||||
@@ -81,5 +78,4 @@ export const transformPlaidTrxsToCashflowCreate = R.curry(
|
|||||||
pending: plaidTranasction.pending,
|
pending: plaidTranasction.pending,
|
||||||
pendingPlaidTransactionId: plaidTranasction.pending_transaction_id,
|
pendingPlaidTransactionId: plaidTranasction.pending_transaction_id,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ export class RecognizedBankTransaction extends BaseModel {
|
|||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const UncategorizedCashflowTransaction = require('./UncategorizedCashflowTransaction');
|
const {
|
||||||
const Account = require('./Account');
|
UncategorizedBankTransaction,
|
||||||
const { BankRule } = require('./BankRule');
|
} = require('../../BankingTransactions/models/UncategorizedBankTransaction');
|
||||||
|
const { Account } = require('../../Accounts/models/Account.model');
|
||||||
|
const { BankRule } = require('../../BankRules/models/BankRule');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +46,7 @@ export class RecognizedBankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
uncategorizedTransactions: {
|
uncategorizedTransactions: {
|
||||||
relation: Model.HasManyRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelClass: UncategorizedCashflowTransaction.default,
|
modelClass: UncategorizedBankTransaction,
|
||||||
join: {
|
join: {
|
||||||
from: 'recognized_bank_transactions.uncategorizedTransactionId',
|
from: 'recognized_bank_transactions.uncategorizedTransactionId',
|
||||||
to: 'uncategorized_cashflow_transactions.id',
|
to: 'uncategorized_cashflow_transactions.id',
|
||||||
@@ -56,7 +58,7 @@ export class RecognizedBankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
assignAccount: {
|
assignAccount: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'recognized_bank_transactions.assignedAccountId',
|
from: 'recognized_bank_transactions.assignedAccountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
|
import { Body, Controller, Delete, Get, Param, Post } from '@nestjs/common';
|
||||||
import { BankingTransactionsApplication } from './BankingTransactionsApplication.service';
|
import { BankingTransactionsApplication } from './BankingTransactionsApplication.service';
|
||||||
import { ICashflowNewCommandDTO } from './types/BankingTransactions.types';
|
import { ICashflowNewCommandDTO } from './types/BankingTransactions.types';
|
||||||
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
|
|
||||||
@Controller('banking/transactions')
|
@Controller('banking/transactions')
|
||||||
|
@PublicRoute()
|
||||||
export class BankingTransactionsController {
|
export class BankingTransactionsController {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly bankingTransactionsApplication: BankingTransactionsApplication,
|
private readonly bankingTransactionsApplication: BankingTransactionsApplication,
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import { Model } from 'objection';
|
|||||||
// import { CASHFLOW_DIRECTION } from '@/services/Cashflow/constants';
|
// import { CASHFLOW_DIRECTION } from '@/services/Cashflow/constants';
|
||||||
// import { getCashflowTransactionFormattedType } from '@/utils/transactions-types';
|
// import { getCashflowTransactionFormattedType } from '@/utils/transactions-types';
|
||||||
import { BaseModel } from '@/models/Model';
|
import { BaseModel } from '@/models/Model';
|
||||||
import { getCashflowAccountTransactionsTypes, getCashflowTransactionType } from '../utils';
|
import {
|
||||||
|
getCashflowAccountTransactionsTypes,
|
||||||
|
getCashflowTransactionType,
|
||||||
|
} from '../utils';
|
||||||
import { CASHFLOW_DIRECTION, CASHFLOW_TRANSACTION_TYPE } from '../constants';
|
import { CASHFLOW_DIRECTION, CASHFLOW_TRANSACTION_TYPE } from '../constants';
|
||||||
import { BankTransactionLine } from './BankTransactionLine';
|
import { BankTransactionLine } from './BankTransactionLine';
|
||||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||||
@@ -159,10 +162,14 @@ export class BankTransaction extends BaseModel {
|
|||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const CashflowTransactionLine = require('models/CashflowTransactionLine');
|
const { BankTransactionLine } = require('./BankTransactionLine');
|
||||||
const AccountTransaction = require('models/AccountTransaction');
|
const {
|
||||||
const Account = require('models/Account');
|
AccountTransaction,
|
||||||
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
} = require('../../Accounts/models/AccountTransaction.model');
|
||||||
|
const { Account } = require('../../Accounts/models/Account.model');
|
||||||
|
const {
|
||||||
|
MatchedBankTransaction,
|
||||||
|
} = require('../../BankingMatching/models/MatchedBankTransaction');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -170,7 +177,7 @@ export class BankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
entries: {
|
entries: {
|
||||||
relation: Model.HasManyRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelClass: CashflowTransactionLine.default,
|
modelClass: BankTransactionLine,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transactions.id',
|
from: 'cashflow_transactions.id',
|
||||||
to: 'cashflow_transaction_lines.cashflowTransactionId',
|
to: 'cashflow_transaction_lines.cashflowTransactionId',
|
||||||
@@ -185,7 +192,7 @@ export class BankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
transactions: {
|
transactions: {
|
||||||
relation: Model.HasManyRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelClass: AccountTransaction.default,
|
modelClass: AccountTransaction,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transactions.id',
|
from: 'cashflow_transactions.id',
|
||||||
to: 'accounts_transactions.referenceId',
|
to: 'accounts_transactions.referenceId',
|
||||||
@@ -200,7 +207,7 @@ export class BankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
cashflowAccount: {
|
cashflowAccount: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transactions.cashflowAccountId',
|
from: 'cashflow_transactions.cashflowAccountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
@@ -212,7 +219,7 @@ export class BankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
creditAccount: {
|
creditAccount: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transactions.creditAccountId',
|
from: 'cashflow_transactions.creditAccountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ export class BankTransactionLine extends BaseModel{
|
|||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const Account = require('models/Account');
|
const { Account } = require('../../Accounts/models/Account.model');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cashflowAccount: {
|
cashflowAccount: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transaction_lines.cashflowAccountId',
|
from: 'cashflow_transaction_lines.cashflowAccountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
@@ -35,7 +35,7 @@ export class BankTransactionLine extends BaseModel{
|
|||||||
},
|
},
|
||||||
creditAccount: {
|
creditAccount: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'cashflow_transaction_lines.creditAccountId',
|
from: 'cashflow_transaction_lines.creditAccountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
|
|||||||
@@ -195,11 +195,11 @@ export class UncategorizedBankTransaction extends BaseModel {
|
|||||||
* Relationship mapping.
|
* Relationship mapping.
|
||||||
*/
|
*/
|
||||||
static get relationMappings() {
|
static get relationMappings() {
|
||||||
const Account = require('models/Account');
|
const { Account } = require('../../Accounts/models/Account.model');
|
||||||
const {
|
const {
|
||||||
RecognizedBankTransaction,
|
RecognizedBankTransaction,
|
||||||
} = require('models/RecognizedBankTransaction');
|
} = require('../../BankingTranasctionsRegonize/models/RecognizedBankTransaction');
|
||||||
const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
const { MatchedBankTransaction } = require('../../BankingMatching/models/MatchedBankTransaction');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
/**
|
/**
|
||||||
@@ -207,7 +207,7 @@ export class UncategorizedBankTransaction extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
account: {
|
account: {
|
||||||
relation: Model.BelongsToOneRelation,
|
relation: Model.BelongsToOneRelation,
|
||||||
modelClass: Account.default,
|
modelClass: Account,
|
||||||
join: {
|
join: {
|
||||||
from: 'uncategorized_cashflow_transactions.accountId',
|
from: 'uncategorized_cashflow_transactions.accountId',
|
||||||
to: 'accounts.id',
|
to: 'accounts.id',
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export class BankTransactionTransformer extends Transformer {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
protected transactionTypeFormatted = (transaction) => {
|
protected transactionTypeFormatted = (transaction) => {
|
||||||
return this.context.i18n.t(transaction.transactionTypeFormatted);
|
return this.context.i18n.t(transaction.transactionType);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
import { TransformerInjectable } from '@/modules/Transformer/TransformerInjectable.service';
|
||||||
import { initialize } from 'objection';
|
|
||||||
import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction';
|
import { UncategorizedBankTransaction } from '../models/UncategorizedBankTransaction';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { UncategorizedTransactionTransformer } from '../../BankingCategorize/commands/UncategorizedTransaction.transformer';
|
import { UncategorizedTransactionTransformer } from '../../BankingCategorize/commands/UncategorizedTransaction.transformer';
|
||||||
|
import { IGetUncategorizedTransactionsQuery } from '../types/BankingTransactions.types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class GetUncategorizedTransactions {
|
export class GetUncategorizedTransactions {
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ export interface IBillPaymentEntryDTO {
|
|||||||
|
|
||||||
export interface IBillPaymentDTO {
|
export interface IBillPaymentDTO {
|
||||||
vendorId: number;
|
vendorId: number;
|
||||||
amount: number;
|
amount?: number;
|
||||||
paymentAccountId: number;
|
paymentAccountId: number;
|
||||||
paymentNumber?: string;
|
paymentNumber?: string;
|
||||||
paymentDate: Date | string;
|
paymentDate: Date | string;
|
||||||
exchangeRate?: number;
|
exchangeRate?: number;
|
||||||
statement: string;
|
statement?: string;
|
||||||
reference: string;
|
reference?: string;
|
||||||
entries: IBillPaymentEntryDTO[];
|
entries: IBillPaymentEntryDTO[];
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
attachments?: AttachmentLinkDTO[];
|
attachments?: AttachmentLinkDTO[];
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import * as R from 'ramda';
|
|||||||
// import CustomViewBaseModel from './CustomViewBaseModel';
|
// import CustomViewBaseModel from './CustomViewBaseModel';
|
||||||
// import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
// import { DEFAULT_VIEWS } from '@/services/Purchases/Bills/constants';
|
||||||
// import ModelSearchable from './ModelSearchable';
|
// import ModelSearchable from './ModelSearchable';
|
||||||
import { BaseModel } from '@/models/Model';
|
import { BaseModel, PaginationQueryBuilderType } from '@/models/Model';
|
||||||
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
import { ItemEntry } from '@/modules/TransactionItemEntry/models/ItemEntry';
|
||||||
import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost';
|
import { BillLandedCost } from '@/modules/BillLandedCosts/models/BillLandedCost';
|
||||||
import { DiscountType } from '@/common/types/Discount';
|
import { DiscountType } from '@/common/types/Discount';
|
||||||
import { Knex } from 'knex';
|
import type { Knex, QueryBuilder } from 'knex';
|
||||||
|
|
||||||
export class Bill extends BaseModel {
|
export class Bill extends BaseModel {
|
||||||
public amount: number;
|
public amount: number;
|
||||||
@@ -482,6 +482,7 @@ export class Bill extends BaseModel {
|
|||||||
const { Branch } = require('../../Branches/models/Branch.model');
|
const { Branch } = require('../../Branches/models/Branch.model');
|
||||||
const { Warehouse } = require('../../Warehouses/models/Warehouse.model');
|
const { Warehouse } = require('../../Warehouses/models/Warehouse.model');
|
||||||
const { TaxRateModel } = require('../../TaxRates/models/TaxRate.model');
|
const { TaxRateModel } = require('../../TaxRates/models/TaxRate.model');
|
||||||
|
const { TaxRateTransaction } = require('../../TaxRates/models/TaxRateTransaction.model');
|
||||||
const { Document } = require('../../ChromiumlyTenancy/models/Document');
|
const { Document } = require('../../ChromiumlyTenancy/models/Document');
|
||||||
// const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
// const { MatchedBankTransaction } = require('models/MatchedBankTransaction');
|
||||||
|
|
||||||
@@ -549,7 +550,7 @@ export class Bill extends BaseModel {
|
|||||||
*/
|
*/
|
||||||
taxes: {
|
taxes: {
|
||||||
relation: Model.HasManyRelation,
|
relation: Model.HasManyRelation,
|
||||||
modelClass: TaxRateModel,
|
modelClass: TaxRateTransaction,
|
||||||
join: {
|
join: {
|
||||||
from: 'bills.id',
|
from: 'bills.id',
|
||||||
to: 'tax_rate_transactions.referenceId',
|
to: 'tax_rate_transactions.referenceId',
|
||||||
@@ -616,8 +617,13 @@ export class Bill extends BaseModel {
|
|||||||
return notFoundBillsIds;
|
return notFoundBillsIds;
|
||||||
}
|
}
|
||||||
|
|
||||||
static changePaymentAmount(billId, amount, trx: Knex.Transaction) {
|
static changePaymentAmount(
|
||||||
|
billId: number,
|
||||||
|
amount: number,
|
||||||
|
trx: Knex.Transaction,
|
||||||
|
) {
|
||||||
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
const changeMethod = amount > 0 ? 'increment' : 'decrement';
|
||||||
|
|
||||||
return this.query(trx)
|
return this.query(trx)
|
||||||
.where('id', billId)
|
.where('id', billId)
|
||||||
[changeMethod]('payment_amount', Math.abs(amount));
|
[changeMethod]('payment_amount', Math.abs(amount));
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { IModelMetaField2 } from "@/interfaces/Model";
|
import { IModelMetaField2 } from "@/interfaces/Model";
|
||||||
|
import { Import } from "./models/Import";
|
||||||
|
|
||||||
export interface ImportMappingAttr {
|
export interface ImportMappingAttr {
|
||||||
from: string;
|
from: string;
|
||||||
|
|||||||
87
packages/server-nest/src/modules/Import/models/Import.ts
Normal file
87
packages/server-nest/src/modules/Import/models/Import.ts
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import { Model, ModelObject } from 'objection';
|
||||||
|
// import SystemModel from './SystemModel';
|
||||||
|
import { BaseModel } from '@/models/Model';
|
||||||
|
|
||||||
|
export class Import extends BaseModel {
|
||||||
|
resource: string;
|
||||||
|
tenantId: number;
|
||||||
|
mapping!: string;
|
||||||
|
columns!: string;
|
||||||
|
params!: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table name.
|
||||||
|
*/
|
||||||
|
static get tableName() {
|
||||||
|
return 'imports';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Virtual attributes.
|
||||||
|
*/
|
||||||
|
static get virtualAttributes() {
|
||||||
|
return ['mappingParsed'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamps columns.
|
||||||
|
*/
|
||||||
|
get timestamps() {
|
||||||
|
return ['createdAt', 'updatedAt'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines whether the import is mapped.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
public get isMapped() {
|
||||||
|
return Boolean(this.mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get columnsParsed() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(this.columns);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get paramsParsed() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(this.params);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get mappingParsed() {
|
||||||
|
try {
|
||||||
|
return JSON.parse(this.mapping);
|
||||||
|
} catch {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Relationship mapping.
|
||||||
|
*/
|
||||||
|
static get relationMappings() {
|
||||||
|
const Tenant = require('system/models/Tenant');
|
||||||
|
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* System user may belongs to tenant model.
|
||||||
|
*/
|
||||||
|
tenant: {
|
||||||
|
relation: Model.BelongsToOneRelation,
|
||||||
|
modelClass: Tenant.default,
|
||||||
|
join: {
|
||||||
|
from: 'imports.tenantId',
|
||||||
|
to: 'tenants.id',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ImportShape = ModelObject<Import>;
|
||||||
@@ -213,7 +213,7 @@ export class ItemsEntriesService {
|
|||||||
/**
|
/**
|
||||||
* Sets the cost/sell accounts to the invoice entries.
|
* Sets the cost/sell accounts to the invoice entries.
|
||||||
*/
|
*/
|
||||||
public setItemsEntriesDefaultAccounts = async (entries: ItemEntry[]) => {
|
public setItemsEntriesDefaultAccounts = async (entries: IItemEntryDTO[]) => {
|
||||||
const entriesItemsIds = entries.map((e) => e.itemId);
|
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);
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { PaymentReceived } from '../models/PaymentReceived';
|
|||||||
export interface IPaymentReceivedCreateDTO {
|
export interface IPaymentReceivedCreateDTO {
|
||||||
customerId: number;
|
customerId: number;
|
||||||
paymentDate: Date | string;
|
paymentDate: Date | string;
|
||||||
amount: number;
|
amount?: number;
|
||||||
exchangeRate: number;
|
exchangeRate?: number;
|
||||||
referenceNo: string;
|
referenceNo?: string;
|
||||||
depositAccountId: number;
|
depositAccountId: number;
|
||||||
paymentReceiveNo?: string;
|
paymentReceiveNo?: string;
|
||||||
statement: string;
|
statement?: string;
|
||||||
entries: IPaymentReceivedEntryDTO[];
|
entries: IPaymentReceivedEntryDTO[];
|
||||||
|
|
||||||
branchId?: number;
|
branchId?: number;
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ export interface IItemEntryDTO {
|
|||||||
landedCost?: boolean;
|
landedCost?: boolean;
|
||||||
warehouseId?: number;
|
warehouseId?: number;
|
||||||
|
|
||||||
|
sellAccountId?: number;
|
||||||
|
costAccountId?: number;
|
||||||
|
|
||||||
projectRefId?: number;
|
projectRefId?: number;
|
||||||
projectRefType?: ProjectLinkRefType;
|
projectRefType?: ProjectLinkRefType;
|
||||||
projectRefInvoicedAmount?: number;
|
projectRefInvoicedAmount?: number;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { groupBy } from 'lodash';
|
import { groupBy } from 'lodash';
|
||||||
|
|
||||||
export const transformToMapBy = (collection, key) => {
|
export const transformToMapBy = <T>(collection: T[], key: keyof T): Map<string, T[]> => {
|
||||||
return new Map(Object.entries(groupBy(collection, key)));
|
return new Map(Object.entries(groupBy(collection, key)));
|
||||||
};
|
};
|
||||||
|
|||||||
88
packages/server-nest/test/bank-rules.e2e-spec.ts
Normal file
88
packages/server-nest/test/bank-rules.e2e-spec.ts
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import * as request from 'supertest';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { app } from './init-app-test';
|
||||||
|
|
||||||
|
const requestBankRule = () => ({
|
||||||
|
name: faker.company.name(),
|
||||||
|
order: 1,
|
||||||
|
applyIfAccountId: 1001,
|
||||||
|
applyIfTransactionType: 'deposit',
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
field: 'description',
|
||||||
|
comparator: 'contains',
|
||||||
|
value: faker.finance.transactionDescription(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
assignCategory: 'Deposit',
|
||||||
|
assignAccountId: 1002,
|
||||||
|
assignPayee: faker.company.name(),
|
||||||
|
assignMemo: faker.lorem.sentence(),
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Bank Rules (e2e)', () => {
|
||||||
|
it('/banking/rules (POST)', () => {
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.post('/banking/rules')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule())
|
||||||
|
.expect(201);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/rules/:id (PUT)', async () => {
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/rules')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule());
|
||||||
|
|
||||||
|
const ruleId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.put(`/banking/rules/${ruleId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule())
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/rules/:id (DELETE)', async () => {
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/rules')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule());
|
||||||
|
|
||||||
|
const ruleId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.delete(`/banking/rules/${ruleId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/rules/:id (GET)', async () => {
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/rules')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule());
|
||||||
|
|
||||||
|
const ruleId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.get(`/banking/rules/${ruleId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/rules (GET)', async () => {
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/rules')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(requestBankRule());
|
||||||
|
|
||||||
|
const ruleId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.get(`/banking/rules/${ruleId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
61
packages/server-nest/test/banking-transactions.e2e-spec.ts
Normal file
61
packages/server-nest/test/banking-transactions.e2e-spec.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import * as request from 'supertest';
|
||||||
|
import { faker } from '@faker-js/faker';
|
||||||
|
import { app } from './init-app-test';
|
||||||
|
|
||||||
|
const createOwnerContributionTransaction = () => ({
|
||||||
|
date: '2024-01-01',
|
||||||
|
transactionNumber: faker.string.alphanumeric(10),
|
||||||
|
referenceNo: faker.string.alphanumeric(8),
|
||||||
|
transactionType: 'owner_contribution',
|
||||||
|
description: faker.lorem.sentence(),
|
||||||
|
amount: faker.number.float({ min: 100, max: 10000, precision: 2 }),
|
||||||
|
// exchangeRate: 1,
|
||||||
|
// currencyCode: 'USD',
|
||||||
|
creditAccountId: 1014,
|
||||||
|
cashflowAccountId: 1000,
|
||||||
|
publish: true,
|
||||||
|
branchId: 1,
|
||||||
|
// plaidTransactionId: faker.string.uuid()
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Banking Transactions (e2e)', () => {
|
||||||
|
it('/banking/transactions (POST)', () => {
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.post('/banking/transactions')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(createOwnerContributionTransaction())
|
||||||
|
.expect(201);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/transactions/:id (GET)', async () => {
|
||||||
|
const transaction = createOwnerContributionTransaction();
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/transactions')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(transaction)
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
const transactionId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.get(`/banking/transactions/${transactionId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('/banking/transactions/:id (DELETE)', async () => {
|
||||||
|
const transaction = createOwnerContributionTransaction();
|
||||||
|
const response = await request(app.getHttpServer())
|
||||||
|
.post('/banking/transactions')
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.send(transaction)
|
||||||
|
.expect(201);
|
||||||
|
|
||||||
|
const transactionId = response.body.id;
|
||||||
|
|
||||||
|
return request(app.getHttpServer())
|
||||||
|
.delete(`/banking/transactions/${transactionId}`)
|
||||||
|
.set('organization-id', '4064541lv40nhca')
|
||||||
|
.expect(200);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,7 +23,8 @@ export class GetBankRuleService {
|
|||||||
|
|
||||||
const bankRule = await BankRule.query()
|
const bankRule = await BankRule.query()
|
||||||
.findById(ruleId)
|
.findById(ruleId)
|
||||||
.withGraphFetched('conditions');
|
.withGraphFetched('conditions')
|
||||||
|
.withGraphFetched('assignAccount');
|
||||||
|
|
||||||
return this.transformer.transform(
|
return this.transformer.transform(
|
||||||
tenantId,
|
tenantId,
|
||||||
|
|||||||
Reference in New Issue
Block a user