From 01e07fb0dbc3fc43a15074b72b45acf2505e90a7 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Tue, 17 Oct 2023 22:41:31 +0000 Subject: [PATCH] [FIX] pos*_stripe: support eftpos in Australia Based on 50a91e0c531ec05a432cd8c468b74db27bd30985. By default pos_stripe does the authorization and capture in two steps. This is not supported for eftpos payments [1]. It can be supported in two ways: - always auth + capture in one step with the `automatic` `capture_method`, or - only auth + capture when manual isn't possible with the `manual_preferred` `capture_method` Although both could work, `manual_preferred` was chosen because: - it's a bit simpler to figure out whether to capture the payment in the frontend (we can just check card_present.brand), - this keeps non-eftpos transactions the same, which is more in line with our stable policy For completeness pos_restaurant_stripe was updated to not capture these eftpos payments, although this style of tipping isn't used in Australia. To test similar steps as in 50a91e0c531ec05a432cd8c468b74db27bd30985 need to be taken: 1/ use an Australian Stripe account, 2/ allow discovery of simulated readers by passing {simulated: true} to this.terminal.discoverReaders() 3/ manually simulating an eftpos payment via the browser console (necessary per payment) [2] To be safe this also guards against the possibility of there being no `charges` key on the payment intent. This was done elsewhere with 6a6057caf63d7e6a60dac190b2ea1ebb954d8f6a. It does seem that Stripe rolled back this change (maybe only for Stripe Terminal intents), because I always receive `charges` with the latest API version (2023-10-16). Additionally, 50a91e0c531ec05a432cd8c468b74db27bd30985 has been live for 3 months without issues, it would have caused errors if `charges` was missing. [1] https://stripe.com/docs/terminal/payments/regional?integration-country=AU#integration-requirements [2] posmodel.payment_methods[X].payment_terminal.terminal.setSimulatorConfiguration({testPaymentMethod: 'eftpos_au_debit'}) opw-3523604 closes odoo/odoo#142603 closes odoo/odoo#145665 X-original-commit: ffddab3aa437c997fd1d63d592b47598a4bad9f5 Signed-off-by: Quentin Lejeune (qle) Signed-off-by: Joren Van Onder (jov) --- .../src/overrides/models/payment_stripe.js | 3 +- .../pos_stripe/models/pos_payment_method.py | 6 +++- .../static/src/app/payment_stripe.js | 36 ++++++++++++------- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/addons/pos_restaurant_stripe/static/src/overrides/models/payment_stripe.js b/addons/pos_restaurant_stripe/static/src/overrides/models/payment_stripe.js index 6d1cc25a367..dd76975e19c 100644 --- a/addons/pos_restaurant_stripe/static/src/overrides/models/payment_stripe.js +++ b/addons/pos_restaurant_stripe/static/src/overrides/models/payment_stripe.js @@ -18,7 +18,8 @@ patch(PaymentStripe.prototype, { return ( this.pos.config.set_tip_after_payment && line.payment_method.use_payment_terminal === "stripe" && - line.card_type !== "interac" + line.card_type !== "interac" && + !line.card_type.includes("eftpos") ); }, }); diff --git a/addons/pos_stripe/models/pos_payment_method.py b/addons/pos_stripe/models/pos_payment_method.py index bd9bab2dfb2..92eddad1454 100644 --- a/addons/pos_stripe/models/pos_payment_method.py +++ b/addons/pos_stripe/models/pos_payment_method.py @@ -86,7 +86,11 @@ class PosPaymentMethod(models.Model): ("capture_method", "manual"), ] - if currency.name == 'CAD' and self.company_id.country_code == 'CA': + if currency.name == 'AUD' and self.company_id.country_code == 'AU': + # See https://stripe.com/docs/terminal/payments/regional?integration-country=AU + # This parameter overrides "capture_method": "manual" above. + params.append(("payment_method_options[card_present][capture_method]", "manual_preferred")) + elif currency.name == 'CAD' and self.company_id.country_code == 'CA': params.append(("payment_method_types[]", "interac_present")) try: diff --git a/addons/pos_stripe/static/src/app/payment_stripe.js b/addons/pos_stripe/static/src/app/payment_stripe.js index a61b3f6a5ae..b7a8637b7d6 100644 --- a/addons/pos_stripe/static/src/app/payment_stripe.js +++ b/addons/pos_stripe/static/src/app/payment_stripe.js @@ -115,15 +115,27 @@ export class PaymentStripe extends PaymentInterface { ); } - _getInteracTransactionId(processPayment) { - const intentCharge = processPayment.paymentIntent.charges.data[0]; - const processPaymentDetails = intentCharge.payment_method_details; - - if (processPaymentDetails.type === 'interac_present') { - return intentCharge.id; + _getCapturedCardAndTransactionId(processPayment) { + const charges = processPayment.paymentIntent.charges; + if (!charges) { + return [false, false]; } - return false; + const intentCharge = charges.data[0]; + const processPaymentDetails = intentCharge.payment_method_details; + const cardPresentBrand = processPaymentDetails.card_present.brand; + + if (processPaymentDetails.type === "interac_present") { + // Canadian interac payments should not be captured: + // https://stripe.com/docs/terminal/payments/regional?integration-country=CA#create-a-paymentintent + return ["interac", intentCharge.id]; + } else if (cardPresentBrand.includes("eftpos")) { + // Australian eftpos should not be captured: + // https://stripe.com/docs/terminal/payments/regional?integration-country=AU + return [cardPresentBrand, intentCharge.id]; + } + + return [false, false]; } async collectPayment(amount) { @@ -152,12 +164,10 @@ export class PaymentStripe extends PaymentInterface { } else if (processPayment.paymentIntent) { line.set_payment_status("waitingCapture"); - const interacTransactionId = this._getInteracTransactionId(processPayment); - if (interacTransactionId) { - // Canadian interac payments should not be captured: - // https://stripe.com/docs/terminal/payments/regional?integration-country=CA#create-a-paymentintent - line.card_type = "interac"; - line.transaction_id = interacTransactionId; + const [captured_card_type, captured_transaction_id] = this._getCapturedCardAndTransactionId(processPayment); + if (captured_card_type && captured_transaction_id) { + line.card_type = captured_card_type; + line.transaction_id = captured_transaction_id; } else { await this.captureAfterPayment(processPayment, line); }