When managing payments in Dynamics 365 Finance and Operations (D365FO), it is essential to validate the information before generating payment files. Incorrect or incomplete data can result in bank rejections, causing reconciliation issues and delays in operations.
D365FO allows the configuration of multiple payment methods with export formats such as ISO20022 or national standards. However, some banks enforce additional controls, requiring system adjustments to ensure that critical data is correctly populated before processing payments.
In this article, we will explore how to implement custom validations for customer and vendor payment methods to prevent errors and ensure data integrity.

How does payment validation work in D365FO?
Dynamics 365 Finance and Operations dispone de controles estándar para validar los pagos tanto de clientes como de proveedores. En cada forma de pago, es posible activar verificaciones específicas que se aplican al procesar el diario, asegurando que los datos requeridos estén correctamente informados.


From a technical perspective, validation occurs at the payment journal line level. The checkPaymentFilledOk method in the LedgerJournalTrans table executes these controls. This method distinguishes between customer and vendor payments and applies the corresponding validations based on the transaction type.

Different objects handle the validation logic for customer and vendor payments. Let’s examine them in detail:
• Vendor payments
For vendor payments, payment method validations are stored in the VendPaymMethodVal table. These validations originate from the abstract class VendPaymentFieldValidator. Based on the VendPaymentValidate enumeration, the system instantiates the appropriate validation class.



• Customer payments
For customer payments, validations are linked to payment methods via the CustPaymMethodVal table. Unlike vendor payments, this process does not use inheritance. Instead, the system performs checks using a switch statement within the LedgerJournalTrans table, specifically in the custPaymentFilledOk method.



Custom vendor payment validation
To illustrate how to customize vendor payment validation, let’s consider a scenario where vendor transactions in the journal must always include an invoice number.
The first step is to extend the VendPaymentValidate enumeration, which we covered earlier, by adding a new value representing this validation.

Once the new value is created in the enumeration, the next step is to develop an implementation of the VendPaymentFieldValidator class. This new class is automatically instantiated by VendPaymentFieldValidatorFactory when the system checks the active validations for a given payment method and finds that our new control is enabled.
To complete this, we need to define three key methods:
• Constructor: Initializes the validation configuration.
• isValid: Evaluates whether the transaction meets the required condition.
• getCheckFailedMessage: Returns an error message when validation fails.

And to illustrate this, here’s an example:

Custom customer payment validation
For customer payments, we will use the same requirement as in the previous example.
Again, we start by extending the CustPaymentValidate enumeration to add the new validation.

As we previously discussed, customer payment validation is simpler than vendor payment validation. Instead of using class inheritance, we only need to subscribe to the custPaymentFilledOkDelegate delegate in the LedgerJournalTrans table and check which enumeration value is passed to apply the appropriate validation.

Another example:

Conclusion
Ensuring accurate payment validation in Dynamics 365 Finance and Operations is crucial to prevent errors that could lead to banking issues. While the standard system provides basic controls for customers and vendors, extending these validations is often necessary to meet specific requirements.
In this article, we explored how payment validation works in D365FO and how to customize it to enforce business rules.
I hope you liked it, and I hope you find it useful, see you next time!