[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) <qle@odoo.com>
Signed-off-by: Joren Van Onder (jov) <jov@odoo.com>
This commit is contained in:
Joren Van Onder
2023-12-09 00:11:02 +00:00
parent 399de9b5d1
commit 01e07fb0db
3 changed files with 30 additions and 15 deletions
@@ -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")
);
},
});
@@ -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:
@@ -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);
}