refactor: single bank operation projection and domain rules (WealthLedger/backend#168) (#189)
This commit was merged in pull request #189.
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { BankOperationKind } from './bank-operation-kind';
|
||||
|
||||
export type OperationFields = {
|
||||
cardId: string;
|
||||
categoryId?: null | string;
|
||||
kind: BankOperationKind;
|
||||
originalExpenseId?: null | string;
|
||||
targetCardId?: null | string;
|
||||
};
|
||||
|
||||
export enum OperationFieldRule {
|
||||
InvalidCombination = 'invalidCombination',
|
||||
MissingOriginalExpense = 'missingOriginalExpense',
|
||||
MissingTargetCard = 'missingTargetCard',
|
||||
SameTargetCard = 'sameTargetCard',
|
||||
}
|
||||
|
||||
function transferConflict(fields: OperationFields): null | OperationFieldRule {
|
||||
if (!fields.targetCardId) {
|
||||
return OperationFieldRule.MissingTargetCard;
|
||||
}
|
||||
if (fields.targetCardId === fields.cardId) {
|
||||
return OperationFieldRule.SameTargetCard;
|
||||
}
|
||||
if (fields.categoryId || fields.originalExpenseId) {
|
||||
return OperationFieldRule.InvalidCombination;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function expenseConflict(fields: OperationFields): null | OperationFieldRule {
|
||||
if (fields.originalExpenseId) {
|
||||
return OperationFieldRule.InvalidCombination;
|
||||
}
|
||||
// Expense without a category uses the user's default category in the service.
|
||||
return null;
|
||||
}
|
||||
|
||||
function refundConflict(fields: OperationFields): null | OperationFieldRule {
|
||||
return fields.originalExpenseId
|
||||
? null
|
||||
: OperationFieldRule.MissingOriginalExpense;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pure kind/field compatibility rules for bank operations; no Prisma or Nest.
|
||||
* Returns the first violated rule, or null when the combination is allowed.
|
||||
*/
|
||||
export function operationFieldConflict(
|
||||
fields: OperationFields,
|
||||
): null | OperationFieldRule {
|
||||
if (fields.kind === BankOperationKind.Transfer) {
|
||||
return transferConflict(fields);
|
||||
}
|
||||
if (fields.targetCardId) return OperationFieldRule.InvalidCombination;
|
||||
if (fields.kind === BankOperationKind.Expense) {
|
||||
return expenseConflict(fields);
|
||||
}
|
||||
if (fields.categoryId) return OperationFieldRule.InvalidCombination;
|
||||
if (fields.kind === BankOperationKind.Refund) {
|
||||
return refundConflict(fields);
|
||||
}
|
||||
// Topup: no target, no category, no purchase link.
|
||||
return fields.originalExpenseId
|
||||
? OperationFieldRule.InvalidCombination
|
||||
: null;
|
||||
}
|
||||
|
||||
export function operationKindChanged(
|
||||
oldKind: string,
|
||||
newKind: string,
|
||||
oldOriginalExpenseId: null | string,
|
||||
newOriginalExpenseId: null | string,
|
||||
): boolean {
|
||||
return (
|
||||
oldKind !== newKind ||
|
||||
oldOriginalExpenseId !== newOriginalExpenseId
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user