Do we always have to have immediate consistency across all Invoices
because of that use-case?
What are the options for modeling that
collaboration between aggregates?
It would be interesting to hear if there are any options where we can
satisfy this use-case as well as keep invoice as a separate concept.
I would consider the collection of invoices as the AR with invoices as entities inside the aggregate. This collection of invoices might be the CustomerAccount or CustomerFolio or something other depending on the language of the domain and would be responsible for the consistency rules between invoices when recieving a Payment. So in the end, I would only have one aggregate.
So you have an event ... BankTransactionReceived -> PaymentReceived. You also have a list of Pending Invoices.
class InvoicesPending // some Aggregate
{
List<PendingInvoice> listOfPendingInvoices;
void Pay(Money amount); // declares InvoicePaid
void Pay(Guid invoiceId, Money amount); // declares one or more InvoicePaid. It may also declare a MoneyLeft event
void AddPendingInvoice(PendingInvoice i);
void CancelPendingInvoice(PendingInvoice i);
Handle(PaymentReceived fact) {}
Handle(InvoiceIssued fact) {}
Handle(InvoiceCancelled fact) {}
Declare(InvoicePaid fact) {}
Declare(MoneyLeft fact) {}
}
PendingInvoice is a value object representing the invoice within this context. Some other object will take care of returning MoneyLeft over's. Different companies have different rules about when the money is returned.
There might be a case where say an Invoice is payed just before is cancelled. In which case you might also have to return the money. So you would issue in those case a MoneyLeft event.
Cheers,
Nuno
So you have a list of invoices yet to be paid.
Customer Invoice Payment Queue ?
Don't know if this is an account in a traditional sense. But it seams to be a domain concept. It might be implicit in some other concept, but you can make it explicit (SRP?).
Cheers,
Nuno