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 ); }