Install
Works with Drupal: ^11.3 || ^12Using Composer to manage Drupal site dependencies
Alternative installation files
Release notes
No update hook: reinstall kessai_engine, as for every alpha, and upgrade both sides of a remote setup together. This release adds base fields to kessai_payment and its movements (among them store_payment_method, payment_method_valid_until, released, money_after_end, source_payment, last_reconciled and a request_key on claims and refunds), renames token to payment_method_id and token_operation to payment_method_operation, and replaces the reversal movement with a release movement (kessai_release). A site keeping its payments installs the new fields, copies the old columns across and uninstalls the old fields by hand. The wire names change, so an alpha10 host and an alpha11 consumer do not understand each other: upgrade the site running kessai_server and its consumer sites at the same time. Re-import the French catalogs with drush locale:import fr MODULE/translations/fr.po --type=not-customized --override=not-customized, one per catalog. orchestra and yoyaku need their releases that follow these names.
Breaking changes in the API
- #3622020. A caller never names a stored payment method.
authorizeToken()andchargeToken()areauthorizeStoredPaymentMethod()andchargeStoredPaymentMethod(), with no$tokenargument: the engine uses the subject's latest stored payment method whose payer still agrees. Across the wire the door is/kessai-api/payments/with-stored-payment-method. - #3622020. The provider's id of a stored payment method is a payment method id:
getPaymentMethodId(),PaymentQuery'spayment_method_idandhas_payment_method_id(on the wire too),payment_method_operationandPAYMENT_METHOD_OPERATION_*,isStoredMethodPayment(),recordStoredPaymentMethod(), andStoredPaymentMethodGatewayInterfacewithchargeStoredPaymentMethod()anddeleteStoredPaymentMethod(). "Token" now means only the OAuth access token and the handoff and return links. - #3622015. A hold nobody collected is released:
release(), the release movement, thereleasedstate and theRELEASEDandPARTIALLY_RELEASEDevents. Canceled now means only a pending payment called off. - #3622015.
capture(),refund()andrelease()take an optional request key, and recording what a provider already took isrecordPaymentReceived(), split fromcapture(). - #3622015. The consumer is out of the contract: an engine acts for this site, or for one consumer through
forConsumer(). - #3622015. The agreement to charge later is
store_payment_methodandpayment_method_valid_until, withdrawn withforgetStoredPaymentMethods(). It is refused on a zero amount and on an account that cannot charge later. Kinds and metadata names starting withkessai_are reserved.
Money moves once
- #3622015. A claim, refund, release, hold or charge asked again after its answer was lost no longer moves the money a second time. Asked again under the same request key, the movement it made answers. A claim, refund or release unanswered for 23 hours or more is looked up among the transaction's operations instead of being sent again.
- #3622015. A rejected first attempt no longer fails a checkout the payer can still pay, two late acceptances arriving together no longer overwrite each other, and a released hold reported again is no longer read as new money.
- #3622015. A payment whose money is still moving cannot be deleted through any door, money a provider took after a payment ended is given back once, and a lapsed hold leaves "authorized".
- #3622020. On SQLite, which reads a decimal back with 14 significant digits, the largest amount is 9999999999.9999, and a larger one is refused rather than stored rounded. Other databases keep 999999999999999.9999.
- #3622020. The simulator declines a hold or a charge with no stored card, so a forgotten card is no longer charged again on it.
Input checked before storage
- #3622015. A value kessai matches on (subject, metadata, consumer, payment method id, client id) may not end in whitespace, which MySQL ignores on exact-match columns. Text that is not UTF-8, or a value longer than its column, is refused with
\InvalidArgumentException(400 over the wire) instead of failing in the database.
Each site's payments kept apart
- #3622015. On a host, another site's payment no longer loads the host's own entity as its subject. A site running its own engine beside a client no longer sends its own payment to the host. The client refuses a host's answer about another payment, and only a payment settled by hand takes a consumer's word that it was paid.
- #3622015. A site copied to another environment no longer trusts the host it was copied from: what a remote learns is kept with the address and client id it was learned from.
- #3622015. A consumer site installed under a path is told when its payments move, and a site serving several domains gives each domain a remote of its own.
Payers sent back to the right page
- #3622019. A return address keeps its language prefix, so a payer who left from
/fr/node/1comes back to it rather than to the English page, and a site installed under a path no longer gets that path twice. A return address is taken asUrl::toString()writes it.
Code and documentation
#3622020: docs and docblocks that no longer matched the code, tests for three guards no test covered, and a refreshed metrics page.