I'm designing a payment system that uses different gateways. I'm facing an architectural challenge when trying to adhere strictly to Domain-Driven Design principles:
I need to create a payment intent on the external gateway first. Then, I want to create my internal PaymentIntent, which will contain the external gateway's payment intent as a child entity. Before creating an external gateway payment intent, I have specific domain rules that need to be checked.
My dilemma:
Injecting Services into Entities: If I were to check these rules inside the entity, I'd need to inject the gateway service into the domain entity, which violates the principle of model purity.
Always-Valid Domain Model: If I first create the PaymentIntent and then set the external gateway payment intent, I violate the always-valid domain model principle.
Domain Logic in Service: Currently, I'm checking these rules in a domain service. However, I'm concerned this approach leaks domain logic. Here's a simplified version of my code:
export class PaymentIntentService {
async create({
marketplaceId, gateway, customerId, amount,
paymentMethodType, paymentSplitsData,
}: CreatePaymentIntentParams) {
checkRules(
new TotalPaymentSplitsEqualsIntentAmountRule(amount, paymentSplitsData),
new PaymentSplitReceiversMustBeUniqueRule(paymentSplitsData),
);
const externalGatewayPaymentIntent = await this.gatewayService.createPaymentIntent({
amount, paymentMethodType, gatewayCustomerId,
});
const paymentIntent = PaymentIntent.create({
paymentSplitsData, marketplaceId, customerId, amount,
paymentMethodType, gateway, businessEntityId: '',
gatewayPaymentIntent: externalGatewayPaymentIntent,
});
await this.paymentIntentRepository.create(paymentIntent);
return paymentIntent;
}
}
How should I structure this to best adhere to DDD principles while ensuring proper domain logic encapsulation and always-valid state?
Aucun commentaire:
Enregistrer un commentaire