Newer
Older
Warehouse / src / Domain / Common / ValueObjects / Money / Money.cs
@Derek Comartin Derek Comartin on 22 Aug 2023 2 KB Init
namespace MyWarehouse.Domain.Common.ValueObjects.Money;

/// <summary>
/// Value object representing money. Simplified sample.
/// </summary>
public record Money
{
    public decimal Amount { get; init; }

    [Required]
    public Currency Currency { get; init; }

    public Money(decimal amount, Currency currency)
    {
        if (amount < 0) throw new ArgumentException("Value cannot be negative.", nameof(amount));
        if (currency == null) throw new ArgumentNullException(nameof(currency));

        (Amount, Currency) = (amount, currency);
    }

    public Money Copy()
        => new Money(this.Amount, this.Currency);

    public Money AddAmount(decimal amount)
        => new Money(Amount + amount, Currency);

    public static Money operator +(Money left, Money right)
    {
        if (!Equals(left.Currency, right.Currency))
            throw new InvalidOperationException($"Mixing currencies is not supported. Cannot add money of '{left.Currency}' and money of '{right.Currency}'.");

        return left.AddAmount(right.Amount);
    }

    public static Money operator -(Money left, Money right)
    {
        if (!Equals(left.Currency, right.Currency))
            throw new InvalidOperationException($"Mixing currencies is not supported. Cannot subtract money of '{left.Currency}' and money of '{right.Currency}'.");

        return left.AddAmount(-right.Amount);
    }

    public static Money operator *(Money left, Money right)
    {
        if (!Equals(left.Currency, right.Currency))
            throw new InvalidOperationException("Multiplication of two money instances require both to have the same currency.");

        return new Money(left.Amount * right.Amount, left.Currency);
    }

    public static Money operator *(int scalar, Money money)
        => new Money(money.Amount * scalar, money.Currency);

    public static Money operator *(Money money, int scalar)
        => scalar * money;

    public static Money operator *(decimal scalar, Money money)
        => new Money(money.Amount * scalar, money.Currency);

    public static Money operator *(Money money, decimal scalar)
        => scalar * money;

    public override string ToString()
        => string.Format("{0}{1}{2:n}",
            Currency.SymbolWellKnown ? Currency.Symbol : Currency.Code,
            Currency.SymbolWellKnown ? null : " ",
            Amount);
}