import Decimal from 'decimal.js'; import { UserId, AssetType, LedgerEntryType, Money } from '@/domain/value-objects'; export class LedgerEntry { private readonly _id: bigint; private readonly _accountSequence: bigint; // 跨服务关联标识 (全局唯一业务ID) private readonly _userId: UserId; // 保留兼容 private readonly _entryType: LedgerEntryType; private readonly _amount: Money; private readonly _balanceAfter: Money | null; private readonly _refOrderId: string | null; private readonly _refTxHash: string | null; private readonly _memo: string | null; private readonly _payloadJson: Record | null; private readonly _createdAt: Date; private constructor( id: bigint, accountSequence: bigint, userId: UserId, entryType: LedgerEntryType, amount: Money, balanceAfter: Money | null, refOrderId: string | null, refTxHash: string | null, memo: string | null, payloadJson: Record | null, createdAt: Date, ) { this._id = id; this._accountSequence = accountSequence; this._userId = userId; this._entryType = entryType; this._amount = amount; this._balanceAfter = balanceAfter; this._refOrderId = refOrderId; this._refTxHash = refTxHash; this._memo = memo; this._payloadJson = payloadJson; this._createdAt = createdAt; } // Getters get id(): bigint { return this._id; } get accountSequence(): bigint { return this._accountSequence; } get userId(): UserId { return this._userId; } get entryType(): LedgerEntryType { return this._entryType; } get amount(): Money { return this._amount; } get assetType(): string { return this._amount.currency; } get balanceAfter(): Money | null { return this._balanceAfter; } get refOrderId(): string | null { return this._refOrderId; } get refTxHash(): string | null { return this._refTxHash; } get memo(): string | null { return this._memo; } get payloadJson(): Record | null { return this._payloadJson; } get createdAt(): Date { return this._createdAt; } static create(params: { accountSequence: bigint; userId: UserId; entryType: LedgerEntryType; amount: Money; balanceAfter?: Money; refOrderId?: string; refTxHash?: string; memo?: string; payloadJson?: Record; }): LedgerEntry { return new LedgerEntry( BigInt(0), // Will be set by database params.accountSequence, params.userId, params.entryType, params.amount, params.balanceAfter ?? null, params.refOrderId ?? null, params.refTxHash ?? null, params.memo ?? null, params.payloadJson ?? null, new Date(), ); } static reconstruct(params: { id: bigint; accountSequence: bigint; userId: bigint; entryType: string; amount: Decimal; assetType: string; balanceAfter: Decimal | null; refOrderId: string | null; refTxHash: string | null; memo: string | null; payloadJson: Record | null; createdAt: Date; }): LedgerEntry { return new LedgerEntry( params.id, params.accountSequence, UserId.create(params.userId), params.entryType as LedgerEntryType, Money.signed(params.amount, params.assetType), // Use signed() to allow negative amounts for deductions params.balanceAfter ? Money.create(params.balanceAfter, params.assetType) : null, params.refOrderId, params.refTxHash, params.memo, params.payloadJson, params.createdAt, ); } }