Skip to content

Commit

Permalink
Added Product and Category to Warehouse Module
Browse files Browse the repository at this point in the history
  • Loading branch information
danielmackay committed Jan 2, 2024
1 parent 121f24e commit 3b520c2
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 124 deletions.
3 changes: 3 additions & 0 deletions src/Common/SharedKernel/Domain/Identifiers/ProductId.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace SharedKernel.Domain.Identifiers;

public record ProductId(Guid Value);
11 changes: 5 additions & 6 deletions src/Modules/Orders/Modules.Orders.Domain/Orders/LineItem.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
using Ardalis.GuardClauses;

using Modules.Orders.Domain.Products;

using SharedKernel.Domain.Base;
using SharedKernel.Domain.Entities;
using SharedKernel.Domain.Identifiers;

namespace Modules.Orders.Domain.Orders;

Expand All @@ -13,7 +11,7 @@ public class LineItem : Entity<LineItemId>

public required ProductId ProductId { get; init; }

public Product? Product { get; init; }
//public Product? Product { get; init; }

// Detatch price from product to capture the price at the time of purchase
public required Money Price { get; init; }
Expand Down Expand Up @@ -47,7 +45,8 @@ internal static LineItem Create(OrderId orderId, ProductId productId, Money pric

internal void RemoveQuantity(int quantity)
{
Guard.Against.Expression(_ => Quantity - quantity <= 0, quantity, "Can't remove all units. Remove the entire item instead.");
Guard.Against.Expression(_ => Quantity - quantity <= 0, quantity,
"Can't remove all units. Remove the entire item instead.");
Quantity -= quantity;
}
}
}
15 changes: 8 additions & 7 deletions src/Modules/Orders/Modules.Orders.Domain/Orders/Order.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using Ardalis.GuardClauses;

using Modules.Orders.Domain.Customers;
using Modules.Orders.Domain.Products;

using SharedKernel.Domain.Base;
using SharedKernel.Domain.Entities;
using SharedKernel.Domain.Exceptions;
using SharedKernel.Domain.Identifiers;

namespace Modules.Orders.Domain.Orders;

Expand Down Expand Up @@ -61,10 +59,12 @@ public static Order Create(CustomerId customerId)

public LineItem AddLineItem(ProductId productId, Money price, int quantity)
{
Guard.Against.Expression(_ => Status != OrderStatus.PendingPayment, Status, "Can't modify order once payment is done");
Guard.Against.Expression(_ => Status != OrderStatus.PendingPayment, Status,
"Can't modify order once payment is done");

if (OrderCurrency != null && OrderCurrency != price.Currency)
throw new DomainException($"Cannot add line item with currency {price.Currency} to and order than already contains a currency of {price.Currency}");
throw new DomainException(
$"Cannot add line item with currency {price.Currency} to and order than already contains a currency of {price.Currency}");

var existingLineItem = _lineItems.FirstOrDefault(li => li.ProductId == productId);
if (existingLineItem != null)
Expand All @@ -82,7 +82,8 @@ public LineItem AddLineItem(ProductId productId, Money price, int quantity)

public void RemoveLineItem(ProductId productId)
{
Guard.Against.Expression(_ => Status != OrderStatus.PendingPayment, Status, "Can't modify order once payment is done");
Guard.Against.Expression(_ => Status != OrderStatus.PendingPayment, Status,
"Can't modify order once payment is done");

var lineItem = _lineItems.RemoveAll(x => x.ProductId == productId);
}
Expand Down Expand Up @@ -123,4 +124,4 @@ public void ShipOrder(TimeProvider timeProvider)
ShippingDate = timeProvider.GetUtcNow();
Status = OrderStatus.InTransit;
}
}
}
126 changes: 63 additions & 63 deletions src/Modules/Orders/Modules.Orders.Domain/Products/Product.cs
Original file line number Diff line number Diff line change
@@ -1,63 +1,63 @@
using Ardalis.GuardClauses;

using SharedKernel.Domain.Base;
using SharedKernel.Domain.Entities;

namespace Modules.Orders.Domain.Products;

public class Product : AggregateRoot<ProductId>
{
//public CategoryId CategoryId { get; set; } = null!;

//public Category Category { get; set; } = null!;

public string Name { get; private set; } = null!;

public Money Price { get; private set; } = null!;

public Sku Sku { get; private set; } = null!;

private Product() { }

// NOTE: Need to use a factory, as EF does not let owned entities (i.e Money & Sku) be passed via the constructor
public static Product Create(string name, Money price, Sku sku/*, CategoryId categoryId*/)
{
Guard.Against.NullOrWhiteSpace(name);
Guard.Against.Null(sku);
Guard.Against.Null(price);
Guard.Against.ZeroOrNegative(price.Amount);
//Guard.Against.Null(categoryId);

var product = new Product
{
Id = new ProductId(Guid.NewGuid()),
// CategoryId = categoryId,
Name = name,
Price = price,
Sku = sku
};

product.AddDomainEvent(ProductCreatedEvent.Create(product));

return product;
}

public void UpdateName(string name)
{
Guard.Against.NullOrWhiteSpace(name);
Name = name;
}

public void UpdatePrice(Money price)
{
Guard.Against.Null(price);
Guard.Against.ZeroOrNegative(price.Amount);
Price = price;
}

public void UpdateSku(Sku sku)
{
Guard.Against.Null(sku);
Sku = sku;
}
}
// using Ardalis.GuardClauses;
//
// using SharedKernel.Domain.Base;
// using SharedKernel.Domain.Entities;
//
// namespace Modules.Orders.Domain.Products;
//
// public class Product : AggregateRoot<ProductId>
// {
// //public CategoryId CategoryId { get; set; } = null!;
//
// //public Category Category { get; set; } = null!;
//
// public string Name { get; private set; } = null!;
//
// public Money Price { get; private set; } = null!;
//
// public Sku Sku { get; private set; } = null!;
//
// private Product() { }
//
// // NOTE: Need to use a factory, as EF does not let owned entities (i.e Money & Sku) be passed via the constructor
// public static Product Create(string name, Money price, Sku sku/*, CategoryId categoryId*/)
// {
// Guard.Against.NullOrWhiteSpace(name);
// Guard.Against.Null(sku);
// Guard.Against.Null(price);
// Guard.Against.ZeroOrNegative(price.Amount);
// //Guard.Against.Null(categoryId);
//
// var product = new Product
// {
// Id = new ProductId(Guid.NewGuid()),
// // CategoryId = categoryId,
// Name = name,
// Price = price,
// Sku = sku
// };
//
// product.AddDomainEvent(ProductCreatedEvent.Create(product));
//
// return product;
// }
//
// public void UpdateName(string name)
// {
// Guard.Against.NullOrWhiteSpace(name);
// Name = name;
// }
//
// public void UpdatePrice(Money price)
// {
// Guard.Against.Null(price);
// Guard.Against.ZeroOrNegative(price.Amount);
// Price = price;
// }
//
// public void UpdateSku(Sku sku)
// {
// Guard.Against.Null(sku);
// Sku = sku;
// }
// }
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using Ardalis.Specification;

namespace Modules.Orders.Domain.Products;

public class ProductByIdSpec : Specification<Product>, ISingleResultSpecification<Product>
{
public ProductByIdSpec(ProductId id) : base()
{
Query.Where(i => i.Id == id);
}
}
// using Ardalis.Specification;
//
// namespace Modules.Orders.Domain.Products;
//
// public class ProductByIdSpec : Specification<Product>, ISingleResultSpecification<Product>
// {
// public ProductByIdSpec(ProductId id) : base()
// {
// Query.Where(i => i.Id == id);
// }
// }
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using SharedKernel.Domain.Base;

namespace Modules.Orders.Domain.Products;

public record ProductCreatedEvent(ProductId Product, string ProductName) : DomainEvent
{
public static ProductCreatedEvent Create(Product product) => new(product.Id, product.Name);
}
// using SharedKernel.Domain.Base;
//
// namespace Modules.Orders.Domain.Products;
//
// public record ProductCreatedEvent(ProductId Product, string ProductName) : DomainEvent
// {
// public static ProductCreatedEvent Create(Product product) => new(product.Id, product.Name);
// }
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
namespace Modules.Orders.Domain.Products;

public record ProductId(Guid Value);
// namespace Modules.Orders.Domain.Products;
//
// public record ProductId(Guid Value);
42 changes: 21 additions & 21 deletions src/Modules/Orders/Modules.Orders.Domain/Products/Sku.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
namespace Modules.Orders.Domain.Products;

public record Sku
{
private const int DefaultLength = 8;

public string Value { get; }

private Sku(string value) => Value = value;

public static Sku? Create(string value)
{
if (string.IsNullOrWhiteSpace(value))
return null;

if (value.Length != DefaultLength)
return null;

return new Sku(value);
}
}
// namespace Modules.Orders.Domain.Products;
//
// public record Sku
// {
// private const int DefaultLength = 8;
//
// public string Value { get; }
//
// private Sku(string value) => Value = value;
//
// public static Sku? Create(string value)
// {
// if (string.IsNullOrWhiteSpace(value))
// return null;
//
// if (value.Length != DefaultLength)
// return null;
//
// return new Sku(value);
// }
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using Ardalis.GuardClauses;

using SharedKernel.Domain.Base;
using SharedKernel.Domain.Exceptions;

namespace Modules.Warehouse.Domain.Categories;

public class Category : AggregateRoot<CategoryId>
{
public string Name { get; private set; } = default!;

private Category() { }

// NOTE: Need to use a factory, as EF does not let owned entities (i.e Money & Sku) be passed via the constructor
public static Category Create(string name, ICategoryService categoryService)
{
var category = new Category
{
Id = new CategoryId(Guid.NewGuid()),
};

category.UpdateName(name, categoryService);

category.AddDomainEvent(new CategoryCreatedEvent(category.Id, category.Name));

return category;
}

public void UpdateName(string name, ICategoryService categoryService)
{
Guard.Against.NullOrWhiteSpace(name);

if (categoryService.CategoryExists(name))
throw new DomainException($"Category {name} already exists");

Name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using Ardalis.Specification;

namespace Modules.Warehouse.Domain.Categories;

public class CategoryByIdSpec : Specification<Category>, ISingleResultSpecification<Category>
{
public CategoryByIdSpec(CategoryId id) : base()
{
Query.Where(i => i.Id == id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using SharedKernel.Domain.Base;

namespace Modules.Warehouse.Domain.Categories;

public record CategoryCreatedEvent(CategoryId Id, string Name) : DomainEvent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace Modules.Warehouse.Domain.Categories;

public record CategoryId(Guid Value);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Modules.Warehouse.Domain.Categories;

public interface ICategoryService
{
bool CategoryExists(string categoryName);
}
5 changes: 0 additions & 5 deletions src/Modules/Warehouse/Modules.Warehouse.Domain/Class1.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,12 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\Common\SharedKernel\SharedKernel.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Ardalis.Specification" Version="6.1.0" />
</ItemGroup>

</Project>
Loading

0 comments on commit 3b520c2

Please sign in to comment.