Issue #3623038: Ask kessai for its payments instead of querying its tables
yoyaku wrote queries against kessai_payment by hand in nine places: the payments taken for an order, the one carrying a stored token, the held guarantees, the refundable captures, whether a checkout took any money, which other orders share a payer's token, and the purge when an order is deleted.
Those are another project's rows. They can only be read by a yoyaku sharing kessai's database, they go wrong the moment kessai changes how it stores a payment, and the delete left each payment's claims, refunds and reversals behind — records of money nobody can read any more.
The reason they existed is that kessai's contract could create a payment and settle it, and could not find one. It can now.
Depends on kessai !79 and orchestra !498, both merged.
Every lookup goes through the contract
findPayments(), each call with a PaymentQuery naming what it wants: the order as the subject, the kind and the states, a token exactly or at all. One question where there were nine queries.
The narrowing that is not kessai's business stays here — whether a balance is left to refund, and taking the first of what comes back, which is the most recent because the finder says so rather than because a caller sorted it.
CardTokenMatcher is the one that names no single subject: it asks which other orders carry a payer's token, so it passes the subject type without an id.
Deleting goes through the contract too
deletePayments() takes each payment's claims, refunds and reversals with it. Deleting the rows here left those behind.
The client is injected as the contract
Drupal\kessai\PaymentClientInterface rather than fetched as kessai.payment_engine. A client bound in the engine's place is bound to the interface, and a caller naming the service id walks straight past it.
And the dependency is kessai:kessai, not the engine: which module settles a site's payments is the site's decision, and naming the engine made it yoyaku's.
Also
create()takes aPaymentRequest, and the thing being paid for is named withPaymentSubject.- The end-to-end scenarios pin their payments as payment metadata, the way the payment step's own code does, rather than by setting a base field orchestra no longer adds.
What is left
yoyaku_payment_views joins kessai_payment to an order in Views data. That is a join in a database and only ever works in one, so it stays as it is.
Checked
phpstan level 5, phpcs, cspell and the translation audit clean; kernel and functional green in CI, including the next-major lanes.
AI-Generated: Yes (Claude Code was used to help produce this change.)