I'm trying to model aggregate transition from state to state with transition in both directions i.e.State1 --> State2 and State2 --> State1.
For example, there is SalesOrderRequest AR that can transition to WarehouseFulfillment AR. In other words, sales department is making a Order Request and than it's forwarded to other department (warehouse) for fulfillment.
For whatever reason warehouse department can ask for Order Request changes. In that case WarehouseFulfillment should transition back to SalesOrderRequest.
I should mention I'm using event sourcing.
public class SalesOrderRequest
{
private Guid _id:
private bool _isActive = true;
public SalesOrderRequest(Guid id)
{
this.Update(new SalesOrderRequestMadeEvent(id));
}
public WarehouseFulfillment ForwardToWarehouse()
{
this.Update(new ForwardedToWarehouseEvent());
return WarehouseFulfillment.CreateNew(_id);
}
public void Reopen()
{
this.Update(new SalesRequestReopenedEvent() );
}
private void OnForwardedToWarehouse(ForwardedToWarehouseEvent e)
{
_isActive = false;
}
private void OnSalesOrderRequestMade(SalesOrderRequestMadeEvent e)
{
_id = e.Id;
_isActive = true;
}
private void OnReopened(SalesRequestReopenedEvent e)
{
_isActive = true;
}
}
public class WarehouseFulfillment
{
private Guid _id:
private bool _isActive = true;
public SalesOrderRequest SendBackToSales()
{
this.Update(new SentBackToSalesEvent() );
return new SalesOrderRequest.CreateNew(_id);
}
private OnSentBackToSales(SentBackToSalesEvent e)
{
_isActive = false;
}
}
What I'm struggling with is how to model WarehouseFulfillment.
Specifically, should SendBackToSales return new SalesOrderRequest ? In that case SalesOrderRequestMadeEvent will be appended to SalesOrderRequest and _isActive will be set to true.
But that event is not "true". SalesOrderRequest is reopened not made.
Is there another way ?
Also, domain service that handles transition back to SalesOrderRequest looks like this
public class OrderTransitionService : IOrderTransitionService
{
public void SendRequestBackToSales(Guid requestId)
{
WarehouseFulfillment fulfillment = _warehaouseFulfillmentRepo.GetById(requestId);
SalesOrderRequest salesOrderRequest = fulfillment.SendBackToSales();
salesOrderRequestRepo.Add(salesOrderRequest);
_unitOfWork.Commit();
}
}
Since I'm using unit of work (both repositories share the same instance of uow) changes on both aggregates are persisted in the same transaction.
But, I'm altering two aggregates in same transaction which I think is a no no.
Maybe I should also mention both aggregates have its own event stream. By own event stream I mean events are loaded (filtered) by aggregate id and aggregate type. So, although both AR have same id, they differ by type.