Newer
Older
Warehouse / src / Domain / Transactions / Transaction.cs
@Derek Comartin Derek Comartin on 22 Aug 2023 1 KB Init
using MyWarehouse.Domain.Common;
using MyWarehouse.Domain.Common.ValueObjects.Money;
using MyWarehouse.Domain.Partners;
using MyWarehouse.Domain.Products;

namespace MyWarehouse.Domain.Transactions;

/// <summary>
/// Represents inventory movement, with a total value calculated as
/// inventory movement total as the time of the transaction.
/// Does not model traditional purchase and sales orders.
/// </summary>
public class Transaction : MyEntity
{
    public TransactionType TransactionType { get; private set; }

    [Required]
    public Money Total { get; private set; } = new Money(0, Currency.USD);

    public int PartnerId { get; private set; }
    public virtual Partner Partner { get; private set; }

    public virtual IReadOnlyCollection<TransactionLine> TransactionLines => _transactionLines.AsReadOnly();
    private readonly List<TransactionLine> _transactionLines = new();

    private Transaction() // EF
    {
        Partner = null!;
    }

    internal Transaction(TransactionType type, Partner partner)
    {
        TransactionType = type;
        Partner = partner;
    }

    internal void AddTransactionLine(Product product, int quantity)
    {
        if (product == null)
            throw new ArgumentNullException(nameof(product));

        if (quantity < 1)
            throw new ArgumentException("Value must be equal to or greater than 1.", nameof(quantity));

        // Sales quantity vs Product stock validation is a Product responsibility; see RecordTransaction().

        var transactionLine = new TransactionLine()
        {
            Transaction = this,
            Product = product,
            Quantity = quantity,
            UnitPrice = product.Price.Copy()
        };

        product.RecordTransaction(transactionLine);

        _transactionLines.Add(transactionLine);

        var currency = _transactionLines.First().UnitPrice.Currency;
        Total = TransactionLines.Aggregate(new Money(0, currency),
            (total, line) => total + (line.UnitPrice * line.Quantity));
    }
}