merge(furniture-domain): integrate domain decision baseline
This commit is contained in:
commit
05f4ed1d79
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,2 +1,8 @@
|
||||
.tasks/
|
||||
.agile/
|
||||
bin/
|
||||
obj/
|
||||
TestResults/
|
||||
.vs/
|
||||
*.user
|
||||
*.suo
|
||||
|
||||
8
Furniture.Domain.slnx
Normal file
8
Furniture.Domain.slnx
Normal file
@ -0,0 +1,8 @@
|
||||
<Solution>
|
||||
<Folder Name="/src/">
|
||||
<Project Path="src/Furniture.Domain/Furniture.Domain.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/tests/">
|
||||
<Project Path="tests/Furniture.Domain.UnitTests/Furniture.Domain.UnitTests.csproj" />
|
||||
</Folder>
|
||||
</Solution>
|
||||
@ -4,6 +4,8 @@
|
||||
- Availability decision outcome remains unchanged for equivalent inputs.
|
||||
- Correlation propagation behavior remains unchanged.
|
||||
- Transport contracts stay stable at service boundary.
|
||||
- Missing display names map to `Unknown Furniture`.
|
||||
- Negative inventory quantities are clamped to `0`.
|
||||
|
||||
## Validation Approach
|
||||
- Compare pre/post extraction contract examples.
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Furniture.Domain.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Domain input for furniture availability decisions.
|
||||
/// </summary>
|
||||
/// <param name="FurnitureId">Furniture identifier.</param>
|
||||
/// <param name="CorrelationId">Correlation identifier.</param>
|
||||
public sealed record FurnitureAvailabilityDecisionRequest(string FurnitureId, string CorrelationId);
|
||||
@ -0,0 +1,12 @@
|
||||
namespace Furniture.Domain.Contracts;
|
||||
|
||||
/// <summary>
|
||||
/// Domain output for furniture availability decisions.
|
||||
/// </summary>
|
||||
/// <param name="FurnitureId">Furniture identifier.</param>
|
||||
/// <param name="DisplayName">Furniture display name.</param>
|
||||
/// <param name="QuantityAvailable">Quantity available.</param>
|
||||
public sealed record FurnitureAvailabilityDecisionResponse(
|
||||
string FurnitureId,
|
||||
string DisplayName,
|
||||
int QuantityAvailable);
|
||||
@ -0,0 +1,8 @@
|
||||
namespace Furniture.Domain.Conventions;
|
||||
|
||||
/// <summary>
|
||||
/// Marker type for furniture-domain package discovery.
|
||||
/// </summary>
|
||||
public sealed class FurnitureDomainPackageContract
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
using BuildingBlock.Catalog.Contracts.Conventions;
|
||||
using BuildingBlock.Catalog.Contracts.Products;
|
||||
using BuildingBlock.Catalog.Contracts.Responses;
|
||||
using BuildingBlock.Inventory.Contracts.Conventions;
|
||||
using BuildingBlock.Inventory.Contracts.Requests;
|
||||
using BuildingBlock.Inventory.Contracts.Responses;
|
||||
using Furniture.Domain.Contracts;
|
||||
|
||||
namespace Furniture.Domain.Decisions;
|
||||
|
||||
/// <summary>
|
||||
/// Default domain implementation for furniture availability composition decisions.
|
||||
/// </summary>
|
||||
public sealed class FurnitureAvailabilityDecisionService : IFurnitureAvailabilityDecisionService
|
||||
{
|
||||
private const string ContractVersion = "1.0.0";
|
||||
|
||||
/// <inheritdoc />
|
||||
public InventoryItemLookupRequest BuildInventoryRequest(FurnitureAvailabilityDecisionRequest request)
|
||||
{
|
||||
return new InventoryItemLookupRequest(
|
||||
new InventoryContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
|
||||
request.FurnitureId);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProductContract BuildCatalogRequest(FurnitureAvailabilityDecisionRequest request)
|
||||
{
|
||||
return new ProductContract(
|
||||
new CatalogContractEnvelope(ContractVersion, ResolveCorrelationId(request.CorrelationId)),
|
||||
request.FurnitureId,
|
||||
string.Empty);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public FurnitureAvailabilityDecisionResponse ComposeResponse(
|
||||
FurnitureAvailabilityDecisionRequest request,
|
||||
ProductContractResponse catalogResponse,
|
||||
InventoryItemLookupResponse inventoryResponse)
|
||||
{
|
||||
var displayName = string.IsNullOrWhiteSpace(catalogResponse.DisplayName)
|
||||
? "Unknown Furniture"
|
||||
: catalogResponse.DisplayName;
|
||||
var quantityAvailable = inventoryResponse.QuantityAvailable < 0
|
||||
? 0
|
||||
: inventoryResponse.QuantityAvailable;
|
||||
|
||||
return new FurnitureAvailabilityDecisionResponse(
|
||||
request.FurnitureId,
|
||||
displayName,
|
||||
quantityAvailable);
|
||||
}
|
||||
|
||||
private static string ResolveCorrelationId(string correlationId)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(correlationId))
|
||||
{
|
||||
return correlationId;
|
||||
}
|
||||
|
||||
return $"corr-{Guid.NewGuid():N}";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
using BuildingBlock.Catalog.Contracts.Products;
|
||||
using BuildingBlock.Catalog.Contracts.Responses;
|
||||
using BuildingBlock.Inventory.Contracts.Requests;
|
||||
using BuildingBlock.Inventory.Contracts.Responses;
|
||||
using Furniture.Domain.Contracts;
|
||||
|
||||
namespace Furniture.Domain.Decisions;
|
||||
|
||||
/// <summary>
|
||||
/// Defines domain decision boundary for furniture availability composition.
|
||||
/// </summary>
|
||||
public interface IFurnitureAvailabilityDecisionService
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates inventory capability request from furniture availability input.
|
||||
/// </summary>
|
||||
InventoryItemLookupRequest BuildInventoryRequest(FurnitureAvailabilityDecisionRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Creates catalog capability request from furniture availability input.
|
||||
/// </summary>
|
||||
ProductContract BuildCatalogRequest(FurnitureAvailabilityDecisionRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// Composes final furniture availability response from capability responses.
|
||||
/// </summary>
|
||||
FurnitureAvailabilityDecisionResponse ComposeResponse(
|
||||
FurnitureAvailabilityDecisionRequest request,
|
||||
ProductContractResponse catalogResponse,
|
||||
InventoryItemLookupResponse inventoryResponse);
|
||||
}
|
||||
11
src/Furniture.Domain/Furniture.Domain.csproj
Normal file
11
src/Furniture.Domain/Furniture.Domain.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\building-block-catalog\src\BuildingBlock.Catalog.Contracts\BuildingBlock.Catalog.Contracts.csproj" />
|
||||
<ProjectReference Include="..\..\..\building-block-inventory\src\BuildingBlock.Inventory.Contracts\BuildingBlock.Inventory.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.collector" Version="6.0.4" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Using Include="Xunit" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Furniture.Domain\Furniture.Domain.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -0,0 +1,92 @@
|
||||
using BuildingBlock.Catalog.Contracts.Conventions;
|
||||
using BuildingBlock.Catalog.Contracts.Responses;
|
||||
using BuildingBlock.Inventory.Contracts.Conventions;
|
||||
using BuildingBlock.Inventory.Contracts.Responses;
|
||||
using Furniture.Domain.Contracts;
|
||||
using Furniture.Domain.Decisions;
|
||||
|
||||
namespace Furniture.Domain.UnitTests;
|
||||
|
||||
public class FurnitureAvailabilityDecisionServiceTests
|
||||
{
|
||||
[Fact]
|
||||
public void BuildCatalogRequest_WhenCalled_UsesFurnitureIdAsProductId()
|
||||
{
|
||||
var service = new FurnitureAvailabilityDecisionService();
|
||||
|
||||
var request = service.BuildCatalogRequest(new FurnitureAvailabilityDecisionRequest("FUR-001", "corr-001"));
|
||||
|
||||
Assert.Equal("FUR-001", request.ProductId);
|
||||
Assert.Equal("corr-001", request.Envelope.CorrelationId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildInventoryRequest_WhenCorrelationMissing_GeneratesCorrelation()
|
||||
{
|
||||
var service = new FurnitureAvailabilityDecisionService();
|
||||
|
||||
var request = service.BuildInventoryRequest(new FurnitureAvailabilityDecisionRequest("FUR-001", string.Empty));
|
||||
|
||||
Assert.Equal("FUR-001", request.ItemCode);
|
||||
Assert.NotEmpty(request.Envelope.CorrelationId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComposeResponse_WhenCalled_UsesCatalogAndInventoryValues()
|
||||
{
|
||||
var service = new FurnitureAvailabilityDecisionService();
|
||||
var request = new FurnitureAvailabilityDecisionRequest("FUR-001", "corr-001");
|
||||
var catalog = new ProductContractResponse(
|
||||
new CatalogContractEnvelope("1.0.0", "corr-001"),
|
||||
"FUR-001",
|
||||
"Chair");
|
||||
var inventory = new InventoryItemLookupResponse(
|
||||
new InventoryContractEnvelope("1.0.0", "corr-001"),
|
||||
"FUR-001",
|
||||
12);
|
||||
|
||||
var response = service.ComposeResponse(request, catalog, inventory);
|
||||
|
||||
Assert.Equal("FUR-001", response.FurnitureId);
|
||||
Assert.Equal("Chair", response.DisplayName);
|
||||
Assert.Equal(12, response.QuantityAvailable);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComposeResponse_WhenCatalogDisplayNameMissing_UsesFallbackName()
|
||||
{
|
||||
var service = new FurnitureAvailabilityDecisionService();
|
||||
var request = new FurnitureAvailabilityDecisionRequest("FUR-004", "corr-004");
|
||||
var catalog = new ProductContractResponse(
|
||||
new CatalogContractEnvelope("1.0.0", "corr-004"),
|
||||
"FUR-004",
|
||||
string.Empty);
|
||||
var inventory = new InventoryItemLookupResponse(
|
||||
new InventoryContractEnvelope("1.0.0", "corr-004"),
|
||||
"FUR-004",
|
||||
5);
|
||||
|
||||
var response = service.ComposeResponse(request, catalog, inventory);
|
||||
|
||||
Assert.Equal("Unknown Furniture", response.DisplayName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ComposeResponse_WhenInventoryNegative_ClampsQuantityToZero()
|
||||
{
|
||||
var service = new FurnitureAvailabilityDecisionService();
|
||||
var request = new FurnitureAvailabilityDecisionRequest("FUR-005", "corr-005");
|
||||
var catalog = new ProductContractResponse(
|
||||
new CatalogContractEnvelope("1.0.0", "corr-005"),
|
||||
"FUR-005",
|
||||
"Shelf");
|
||||
var inventory = new InventoryItemLookupResponse(
|
||||
new InventoryContractEnvelope("1.0.0", "corr-005"),
|
||||
"FUR-005",
|
||||
-3);
|
||||
|
||||
var response = service.ComposeResponse(request, catalog, inventory);
|
||||
|
||||
Assert.Equal(0, response.QuantityAvailable);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user