Files
demo-ddd-without-oop/js-fp3/domain/account.js
T
2026-04-24 18:04:54 +01:00

73 lines
2.1 KiB
JavaScript

import { ok, fail } from '../library/result.js';
/**
* @typedef {Object} Account
* @property {string} id
* @property {import('./money.js').Money} balance
*/
/** @typedef {{ type: 'OpeningBalanceMustBeNonNegative' }} OpeningBalanceMustBeNonNegative */
/** @typedef {{ type: 'AmountMustBePositive' }} AmountMustBePositive */
/** @typedef {{ type: 'InsufficientBalance', balance: import('./money.js').Money, amount: import('./money.js').Money }} InsufficientBalance */
/** @typedef {{ type: 'AccountNotFound', accountId: string }} AccountNotFound */
/** @typedef {OpeningBalanceMustBeNonNegative | AmountMustBePositive | InsufficientBalance | AccountNotFound} AccountError */
/**
* @type {OpeningBalanceMustBeNonNegative}
*/
export const openingBalanceMustBeNonNegative = { type: 'OpeningBalanceMustBeNonNegative' };
/**
* @type {AmountMustBePositive}
*/
export const amountMustBePositive = { type: 'AmountMustBePositive' };
/**
* @param {import('./money.js').Money} balance
* @param {import('./money.js').Money} amount
* @returns {InsufficientBalance}
*/
export const insufficientBalance = (balance, amount) => ({
type: 'InsufficientBalance',
balance,
amount,
});
/**
* @param {string} accountId
* @returns {AccountNotFound}
*/
export const accountNotFound = (accountId) => ({
type: 'AccountNotFound',
accountId,
});
/**
* @param {string} id
* @param {import('./money.js').Money} openingBalance
* @returns {import('../library/result.js').Result<Account, AccountError>}
*/
export const openAccount = (id, openingBalance) =>
openingBalance.amount < 0
? fail(openingBalanceMustBeNonNegative)
: ok({ id, balance: openingBalance });
/**
* @param {Account} account
* @param {import('./money.js').Money} amount
* @returns {import('../library/result.js').Result<Account, AccountError>}
*/
export const withdraw = (account, amount) => {
if (amount.amount <= 0) {
return fail(amountMustBePositive);
}
if (account.balance.amount < amount.amount) {
return fail(insufficientBalance(account.balance, amount));
}
return ok({
...account,
balance: { amount: account.balance.amount - amount.amount },
});
};