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/
|
.tasks/
|
||||||
.agile/
|
.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.
|
- Availability decision outcome remains unchanged for equivalent inputs.
|
||||||
- Correlation propagation behavior remains unchanged.
|
- Correlation propagation behavior remains unchanged.
|
||||||
- Transport contracts stay stable at service boundary.
|
- Transport contracts stay stable at service boundary.
|
||||||
|
- Missing display names map to `Unknown Furniture`.
|
||||||
|
- Negative inventory quantities are clamped to `0`.
|
||||||
|
|
||||||
## Validation Approach
|
## Validation Approach
|
||||||
- Compare pre/post extraction contract examples.
|
- 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