Repository navigation
feat(payment): rework the payment process around a durable record of provider events (#118761) - #230
Open
kac-axelor wants to merge 46 commits into
Open
kac-axelor wants to merge 46 commits into
kac-axelor wants to merge 46 commits into
Conversation
- A payment is written when the buyer presses a payment button and every provider event about it is appended; its status is derived from those events
- The outcome is shown on one result page at /{workspace}/payments/{reference} that survives a refresh, a closed tab and a forwarded link
- The browser return and the provider's webhook settle through the same keyed ledger, so a payment confirmed after the tab was closed is still recorded once
- The ERP projection is queued in the same transaction as the capture and run by AOS right after it
- Invoices are paid by card through Stripe with the new flow; a cancelled or declined attempt can be retried from the result page
…edger (#118761) - PayPal approves in its own window and the order is captured by our server when the buyer comes back; a window closed on an approved order is still captured, an abandoned one is recorded as cancelled - PayPal notifications are verified against the configured webhook id and record captures, refusals, refunds and disputes; an order approved but never completed by the browser is captured from the notification - Paybox and Up2Pay send the browser and their server-to-server confirmation back through the same signed reading, so a payment confirmed only by the IPN is recorded like any other - An Up2Pay confirmation that names a payment of another system is still forwarded to the legacy ERP - Each attempt at these gateways is told apart, so a second try after a refusal shows its own outcome
… them (#118761) - A Paybox or Up2Pay return is accepted again: the signature covers the whole address Verifone sends the browser to, not only its own fields - A return that cannot be read still lands on the payment's page - Up2Pay opens its payment page again; the platform's address redirects, which lost a posted form - Two attempts on the same payment are told apart on both gateways, so a second refusal shows its own outcome
…gh the payment ledger (#118761) - Invoices offer Stripe bank transfer and HUB PISP next to the other gateways; HUB PISP lists each configured transfer type as its own option - A bank transfer shows its IBAN or account details, holder, reference and remaining amount on the payment page while the bank is awaited - Partial funding is recorded without overstating the captured amount; Stripe refunds and disputes land on the ledger - Paybox returns whose values arrive percent-encoded now verify, so the payment page no longer shows a failure after a successful payment - HUB PISP report links carry an expiring signed grant instead of relying on the browser cookie
…118761) - Marketplace checkout offers the shared payment buttons; the outcome is shown on the payment page, which continues to the purchase confirmation - The order and its lines are recorded the moment the capture lands, so access is granted at once; the ERP builds the sale order and invoice afterwards and the purchases page links them - The purchased products are taken out of the cart on the confirmation page; anything else in the cart is kept - A payment method the workspace maps to no ERP payment mode is not offered on the marketplace checkout
…118761) - A priced registration is paid with the shared payment buttons; the payment page shows the outcome and continues to the registration confirmation - Participants are registered the moment the capture lands, after the event's rules are checked again; the ERP invoices the registration afterwards - A registration the ERP cannot invoice at the amount charged is held for a decision before any confirmation mail is sent - Every payment now records the app configuration it was made under
- A shop checkout is paid with the shared payment buttons; the payment page shows the outcome and continues to an order confirmation that survives a refresh or a forwarded link - Prices, the order total and any advance are settled by the server on every press, so what is charged no longer depends on what the browser holds - The order is recorded the moment the capture lands and built in the ERP afterwards, so a closed tab no longer loses a paid order - Delivery and invoicing addresses are checked against the buyer before anything is charged, rather than when the ERP builds the order - A payment that ended with nothing charged, or one the ERP could not complete, sends the buyer back to their cart instead of to a confirmation - The cart empties once per paid order, so reopening a confirmation no longer clears a cart that has since been refilled
…(#118761) - Bank transfer and HUB PISP are offered on invoices only, as before the payment ledger; a checkout that names one elsewhere is refused before anything is charged - Stripe is one "Pay with Stripe" button again: it goes straight to card, or lets an invoice payer choose between card and bank transfer - A bank transfer asks for confirmation first, since Stripe may settle it at once from the payer's existing balance - A double click on a payment button starts one payment, not two
…ledger (#118761) - Bank transfers and HUB PISP payments started on an invoice and still awaiting the bank are listed on the invoice again, for signed-in payers and invoice links alike - Each pending transfer shows its amount, what remains, its date and, where the bank has given them, the details and reference to wire to - A pending transfer links to its payment page wherever that page will open for the viewer - Payment amounts follow the app's language rather than the browser's default
…ds (#118761) - A payer can cancel a pending Stripe bank transfer from the invoice, as before the payment ledger; a transfer that has already received money is not cancelled - Once a payment lands on an invoice, pending transfers it no longer needs are cancelled, so money wired later cannot pay the invoice twice - A cancellation is recorded as the same event the bank would report, so the bank's own notice later changes nothing - Expired or finished HUB PISP links drop off the invoice's pending list, as the bank reports them - Up2Pay is offered on invoices only, as before the payment ledger
… currency and scale (#118761) - Each payment attempt keeps the amount, currency and scale it asked the provider for; a second press never changes an earlier attempt or the payment's amount - A different amount, cart or subject on a second press starts a new payment instead of rewriting the first - Pending transfers, and the check that cancels them, measure each transfer against what it asked for - Money captured beyond what a payment was for is flagged for a human, and the flag clears once the excess is refunded - Part payments of an invoice and advances on a cart are labelled as such - Payment starts are refused for a currency whose ERP scale differs from what a card or form-post provider expects
…it is part-funded (#118761) - While a bank transfer on an invoice has received part of its amount, no other payment can be started on that invoice, whatever the method - The payer is told how much the transfer still expects and pointed to its bank details - The invoice page hides the pay buttons in that case and explains why, and the pending transfer says the rest is expected - A part-funded transfer that the provider cancels or expires no longer holds the invoice back
- Paid event registrations again send the registration mail with its calendar invite, and the push to other participants with a portal account - Invoice payments send a confirmation mail and the payment push on every payment method; an invoice paid through its link gets a mail that leads back to it - Marketplace purchases and shop orders send a confirmation mail with the amount, the payment reference and a link to the order - Confirmations are sent even when the payer's request ends early, retried while mail is unavailable, and never sent for a payment that could not be delivered or was refunded first - Registration mails no longer carry markup typed into the registration form
- The payer's registration mail for a paid event shows the amount paid and the payment reference; the other participants' mails are unchanged - A payer who registers only other people gets a payment confirmation with the amount, the reference and the event - Free registrations keep their mail as it was
…ng us about (#118761) - A payment whose provider went quiet is checked with the provider once it stops being payable, and what the provider reports is recorded, including a PayPal payment approved but never captured - Payments that cannot be checked with their provider, and ones still unresolved long after they expired, are listed for a person with what to look up - A Stripe bank transfer is never treated as expired by the portal; it is checked daily and listed for a person after two weeks, also when only part of it arrived - A refund or dispute reported before its payment was known is attached to the payment once the payment is recorded - Open payments left from before this change are picked up when the server starts; the old HUB PISP polling at startup is gone - Payments settled in the background no longer fail when the registration or cart has changed since the payer paid
…rmed (#118761) - A Paybox or Up2Pay payment with no notification a week after it expired is closed as having no answer from the provider, never as failed or cancelled - A payment start that never reached the payer is closed the same way, except a Stripe bank transfer, which still goes to a person - A notification that arrives later still records the payment as usual, with delivery and confirmation - The payer keeps seeing that the payment is waiting for confirmation
…rmed (#118761) - A PayPal payment whose order PayPal no longer has is closed as having no answer from the provider and listed as unconfirmed, instead of waiting for a person - Any other failure to reach PayPal is still retried and then listed for a person
- A capture, refund or cancellation an operator records in the ERP is applied to the payment exactly as the provider's own notification would be, with delivery, projection and confirmation - An unmatched provider event an operator matches to a payment is applied under the provider's own reference
…te outcomes (#118761) - Every refund and dispute on a payment is listed for finance to book in the ERP by hand, one entry each, with its amount, reference, date and what the payment still holds; nothing is booked automatically - A refund no longer lowers what the ERP records for the purchase, and a refund of money captured beyond the amount due says it has nothing to reverse - A dispute the provider decides in our favour, or closes without a decision, no longer reads charged back; a lost one stays charged back - Stripe and PayPal dispute outcomes and response deadlines are now recorded - What a payment is for is stored as a record reference, so a new kind of purchase needs no new column
…health (#118761) - A tenant whose database lacks the payment tables or columns has payments turned off, loudly, at boot: no payment method is shown, none can start, and invoice and payment pages still render; it turns back on by itself once the database is fixed - Every hour the log names providers whose webhook is not confirming captures, and payment jobs of any kind past their time
…matched currency scales (#118761) - Every provider's events are recognised the same way, so a notification that arrives twice, or both from the browser and the provider, is counted once for any provider - An event entered by hand in the ERP with a reference that belongs to another payment is refused with that payment named, instead of being marked applied while nothing changed - A payment in a currency whose decimals in the ERP differ from the providers' is refused before it starts, for every provider
…iour (#118761) - How often a provider is asked about a pending payment, and when it goes to a person, is now each provider's own setting; the schedules themselves are unchanged - A part-funded transfer and a start that can move money before the payer acts are recognised by what the provider can do rather than by its name - A provider or payment source missing from the registry is reported when the server starts rather than when a payment first needs it
… guide (#118761) - Upgrading has a runbook for the payment ledger: settling payments still in flight, each tenant's schema, the providers' webhooks and settings, and what finance does from the ERP's payment lists - Developers have a guide to adding a payment provider or an app that takes payments, covering both goovee and the ERP module - The changelog describes the whole payment change
- The previous per-provider payment code, its payment context records and live-update stream are gone; every payment goes through the ledger - Its addresses under /api/payment/ no longer answer, so a payment begun on an earlier release is not completed by this one - Texts only the previous flow showed are removed from the translations
…gelog (#118761) - The runbook has the previous portal stopped before AOS is upgraded, and an optional last step that drops the previous release's payment records - The changelog says a payment begun on an earlier release is not completed by this one
…e runbook (#118761) - Explains that previous payment contexts are not moved and must be settled before the upgrade, including pending Stripe bank transfers - Asks operators to stop the previous portal before upgrading AOS, since its booking endpoints are removed - Says where refunds and disputes on payments made before the upgrade show up, per provider
…ayment gaps (#118761) - A purchase that fails to deliver no longer loses its capture: the payment is recorded as undeliverable and waits for a person - An invoice can no longer be paid again while an earlier payment is still being booked, and no payment can exceed what is owed - Stripe refunds count only once they succeed, including ones that complete later - Background jobs no longer send the same confirmation twice, and pressing pay again cannot reopen a payment that was just captured - The last seat of a paid event cannot be sold twice, and a transfer type the workspace doesn't offer is refused - Payment result pages check access before asking the provider, and unverified Up2Pay notifications are no longer forwarded
- Payments no longer switch themselves off for a tenant whose database lacks the payment tables; running the matching axelor-portal version is a deployment requirement - The upgrade runbook no longer refers to the startup check or its log line
…8761) - The portal no longer checks at startup that every payment source and provider has a registry entry; type-check before merge covers it - Updates the extension guide to match
…er (#118761) - No behaviour change: payment confirmation links are built the same way as other portal links
…age (#118761) - A payer without a portal account gets the confirmation in the language set on their partner in the ERP, instead of the default - Where several partners share the payer's address, the one activated on the portal decides the language
- The portal no longer logs an hourly payment health report; unconfirmed webhook captures and late payment jobs are watched in the ERP's payment menus - The upgrade runbook points to the ERP list instead of the log line
…d (#118761) - A payment whose saved purchase details are incomplete is set aside for the ERP to decide, with a reason saying so - Confirmation mails and onward links fall back as before when those details can't be read
…n (#118761) - Shop, marketplace and event payments use the signed-in user's own email address as the payer, with no extra lookup
- The portal no longer scans open payments for a missing provider check each time it starts; every payment gets its check when it begins
…e (#118761) - Payment and paid event registration confirmations are handed to the mail service like every other portal mail; its retries decide delivery - A mail server outage no longer holds up or repeats the rest of a payment's confirmation, such as the push
…ake (#118761) - No behaviour change: shop and marketplace deliveries read the saved purchase details as they are
…an't be delivered (#118761) - A payment set aside because its saved purchase details are incomplete names the missing or wrong fields in its reason in the ERP
- PayPal and HUB PISP calls give up after 30 seconds, so a provider that stops answering can no longer hang a payer's checkout or stall the background payment jobs - A payment whose provider call timed out is left as it was and checked again later, never marked failed
…#118761) - Each app can only link a payment to the kind of record it sells; a mismatch no longer builds - A delivery that clashes with a record another payment is already for is set aside with the capture kept, and its reason names the clashing key
…e (#118761) - Payment and paid registration push notifications are handed off like mail; a slow push service no longer holds up the confirmation or sends it twice
…olve payments with a reason (#118761) - Refunds and disputes are no longer tracked by the portal; they are handled at the provider and booked in the ERP by finance - A payment captured for more than it was for still waits for a person, who resolves it with a reason once the excess is dealt with at the provider - A payment resolved in the ERP shows the payer the same message as one that could not be delivered - The upgrade runbook covers the removed tables and statuses for databases that ran earlier builds
…#118761) - A Stripe bank transfer not fully paid within 14 days is cancelled at Stripe, and any part already sent is held for the payer at Stripe; the payer is told the deadline - A payment the provider has not finished is asked about daily past its deadline, and closed as unconfirmed for finance after 30 days - A provider answer that cannot belong to the payment, or a bank transfer that never reached Stripe, closes as unconfirmed instead of waiting for a person
…#118761) - Payers see plainer wording on the payment result page, with the bank's transfer reference named apart from the payment reference and a hint on where to enter it - Amount wording is consistent between the invoice total, the result page and pending transfers - French translations cover every new or changed payment text
…(#118761) - No behaviour change: payment tasks, manual entries, fulfilment and registration are named the same in the database and code as on screen - The upgrade runbook covers only the upgrade from the previous release
- No behaviour change for released data: bank transfer and manual entry handling no longer carries fallbacks for payments made by unreleased builds - Manual captures entered in the ERP are for the full amount due, so a bank transfer is never left half-recorded
kac-axelor
force-pushed
the
durable-payments-RM-118761
branch
from
September 25, 2026 14:51
6617b59 to
b521974
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://redmine.axelor.com/issues/118761
axelor-portal: https://git.axelor.com/axelor-hub/axelor-enterprise/axelor-portal/-/merge_requests/52