< Summary - MechanicsSoftware — Coverage Report

Information
Class: MechanicsSoftware.Domain.Entities.Part
Assembly: MechanicsSoftware.Domain
File(s): /home/runner/work/mechanics-software/mechanics-software/src/MechanicsSoftware.Domain/Entities/Part.cs
Line coverage
100%
Covered lines: 76
Uncovered lines: 0
Coverable lines: 76
Total lines: 133
Line coverage: 100%
Branch coverage
97%
Covered branches: 33
Total branches: 34
Branch coverage: 97%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
get_Movements()100%11100%
get_AvailableQuantity()100%11100%
Create(...)100%88100%
Reserve(...)100%66100%
ConfirmUsage(...)100%66100%
Release(...)100%66100%
Update(...)50%22100%
Replenish(...)100%22100%
HasPendingReservations()100%11100%
ValidateNameAndPrice(...)100%44100%

File(s)

/home/runner/work/mechanics-software/mechanics-software/src/MechanicsSoftware.Domain/Entities/Part.cs

#LineLine coverage
 1using MechanicsSoftware.Domain.Enums;
 2using MechanicsSoftware.Domain.Exceptions;
 3using MechanicsSoftware.Domain.ValueObjects;
 4
 5namespace MechanicsSoftware.Domain.Entities;
 6
 7public sealed class Part : Entity<Guid>
 8{
 969    private readonly List<StockMovement> _movements = [];
 10
 11    public string Code { get; private set; } = null!;
 12    public string Name { get; private set; } = null!;
 13    public string? Description { get; private set; }
 14    public Money UnitPrice { get; private set; } = null!;
 15    public int StockQuantity { get; private set; }
 16    public int ReservedQuantity { get; private set; }
 17
 1618    public IReadOnlyCollection<StockMovement> Movements => _movements.AsReadOnly();
 19
 7620    public int AvailableQuantity => StockQuantity - ReservedQuantity;
 21
 28822    private Part() { }
 23
 24    public static Part Create(
 25        Guid id,
 26        string code,
 27        string name,
 28        string? description,
 29        Money unitPrice,
 30        int initialStock = 0)
 10831    {
 10832        if (string.IsNullOrWhiteSpace(code))
 433            throw new DomainException("Part code is required.");
 34
 10435        ValidateNameAndPrice(name, unitPrice);
 36
 9837        if (initialStock < 0)
 238            throw new DomainException("Initial stock cannot be negative.");
 39
 9640        var part = new Part
 9641        {
 9642            Id = id,
 9643            Code = code.Trim().ToUpperInvariant(),
 9644            Name = name.Trim(),
 9645            Description = description?.Trim(),
 9646            UnitPrice = unitPrice,
 9647            StockQuantity = initialStock
 9648        };
 49
 9650        if (initialStock > 0)
 8451            part._movements.Add(StockMovement.Create(id, StockMovementType.Inbound, initialStock));
 52
 9653        return part;
 9654    }
 55
 56    public void Reserve(int quantity, Guid reference)
 4057    {
 4058        if (quantity <= 0)
 259            throw new DomainException("Reserve quantity must be greater than zero.");
 60
 3861        if (reference == Guid.Empty)
 262            throw new DomainException("Reference is required for reservation.");
 63
 3664        if (AvailableQuantity < quantity)
 265            throw new DomainException(
 266                $"Insufficient available stock. Available: {AvailableQuantity}, requested: {quantity}.");
 67
 3468        ReservedQuantity += quantity;
 3469        _movements.Add(StockMovement.Create(Id, StockMovementType.Reservation, quantity, reference));
 3470    }
 71
 72    public void ConfirmUsage(int quantity, Guid reference)
 1473    {
 1474        if (quantity <= 0)
 275            throw new DomainException("Confirm usage quantity must be greater than zero.");
 76
 1277        if (reference == Guid.Empty)
 278            throw new DomainException("Reference is required for usage confirmation.");
 79
 1080        if (ReservedQuantity - quantity < 0)
 481            throw new DomainException(
 482                $"Cannot confirm usage: not enough reserved quantity. Reserved: {ReservedQuantity}, requested: {quantity
 83
 684        StockQuantity -= quantity;
 685        ReservedQuantity -= quantity;
 686        _movements.Add(StockMovement.Create(Id, StockMovementType.Outbound, quantity, reference));
 687    }
 88
 89    public void Release(int quantity, Guid reference)
 1290    {
 1291        if (quantity <= 0)
 292            throw new DomainException("Release quantity must be greater than zero.");
 93
 1094        if (reference == Guid.Empty)
 295            throw new DomainException("Reference is required for release.");
 96
 897        if (ReservedQuantity - quantity < 0)
 298            throw new DomainException(
 299                $"Cannot release more than reserved. Reserved: {ReservedQuantity}, requested: {quantity}.");
 100
 6101        ReservedQuantity -= quantity;
 6102        _movements.Add(StockMovement.Create(Id, StockMovementType.Release, quantity, reference));
 6103    }
 104
 105    public void Update(string name, string? description, Money unitPrice)
 10106    {
 10107        ValidateNameAndPrice(name, unitPrice);
 108
 4109        Name = name.Trim();
 4110        Description = description?.Trim();
 4111        UnitPrice = unitPrice;
 4112    }
 113
 114    public void Replenish(int quantity)
 10115    {
 10116        if (quantity <= 0)
 4117            throw new DomainException("Replenish quantity must be greater than zero.");
 118
 6119        StockQuantity += quantity;
 6120        _movements.Add(StockMovement.Create(Id, StockMovementType.Inbound, quantity));
 6121    }
 122
 8123    public bool HasPendingReservations() => ReservedQuantity > 0;
 124
 125    private static void ValidateNameAndPrice(string name, Money unitPrice)
 114126    {
 114127        if (string.IsNullOrWhiteSpace(name))
 8128            throw new DomainException("Part name is required.");
 129
 106130        if (unitPrice is null)
 4131            throw new DomainException("Unit price is required.");
 102132    }
 133}