changes
This commit is contained in:
@@ -464,24 +464,26 @@ class CloverPaymentWizard(models.TransientModel):
|
||||
provider = self._get_provider_sudo()
|
||||
capture = not provider.capture_manually
|
||||
|
||||
minor_amount = clover_utils.format_clover_amount(
|
||||
self.amount, self.currency_id,
|
||||
# Tokenize the card client-server FIRST (Clover's tokenization
|
||||
# endpoint), then charge using only the token. Raw PAN never
|
||||
# reaches /v1/charges and is never persisted in Odoo.
|
||||
card_token = provider._clover_tokenize_card(
|
||||
card_number=self.card_number,
|
||||
exp_month=int(self.exp_month),
|
||||
exp_year=int(self.exp_year) if len(self.exp_year) == 4
|
||||
else 2000 + int(self.exp_year),
|
||||
cvv=self.cvv,
|
||||
cardholder_name=self.cardholder_name or '',
|
||||
)
|
||||
|
||||
payload = {
|
||||
'amount': minor_amount,
|
||||
'currency': self.currency_id.name.lower(),
|
||||
'capture': capture,
|
||||
'ecomind': 'moto',
|
||||
'description': reference,
|
||||
'source': self.card_number.replace(' ', ''),
|
||||
'metadata': {
|
||||
'odoo_reference': reference,
|
||||
},
|
||||
}
|
||||
|
||||
result = provider._clover_make_ecom_request(
|
||||
'POST', 'v1/charges', payload=payload,
|
||||
result = provider._clover_create_charge(
|
||||
source_token=card_token,
|
||||
amount=self.amount,
|
||||
currency=self.currency_id,
|
||||
capture=capture,
|
||||
description=reference,
|
||||
ecomind='moto',
|
||||
metadata={'odoo_reference': reference},
|
||||
)
|
||||
|
||||
charge_id = result.get('id', '')
|
||||
@@ -497,6 +499,11 @@ class CloverPaymentWizard(models.TransientModel):
|
||||
'clover_charge_id': charge_id,
|
||||
'clover_status': status,
|
||||
'source': result.get('source', {}),
|
||||
# Pass amount + currency back so Odoo 19's amount-tamper
|
||||
# check (_validate_amount) can verify Clover charged the
|
||||
# exact amount we asked for.
|
||||
'amount': result.get('amount'),
|
||||
'currency': result.get('currency'),
|
||||
}
|
||||
|
||||
if status == 'failed':
|
||||
@@ -586,6 +593,15 @@ class CloverPaymentWizard(models.TransientModel):
|
||||
raise UserError(_("Please enter a valid expiry year."))
|
||||
if not self.cvv or not self.cvv.isdigit():
|
||||
raise UserError(_("Please enter the CVV."))
|
||||
# Clover production rejects cards without a 2-part name
|
||||
# ("Firstname Lastname"). Sandbox is lenient. Validate here so the
|
||||
# error message is helpful instead of a generic API 400.
|
||||
if not self.cardholder_name or len(self.cardholder_name.strip().split()) < 2:
|
||||
raise UserError(_(
|
||||
"Please enter the cardholder's name as it appears on "
|
||||
"the card (e.g. \"John Doe\"). Clover requires both "
|
||||
"first and last name."
|
||||
))
|
||||
|
||||
def _create_payment_transaction(self):
|
||||
"""Create a payment.transaction linked to the invoice."""
|
||||
|
||||
@@ -83,7 +83,8 @@
|
||||
required="payment_mode == 'card' and state in ('draft', 'error')"
|
||||
password="True"/>
|
||||
<field name="cardholder_name"
|
||||
placeholder="Name on card"/>
|
||||
placeholder="Firstname Lastname"
|
||||
required="payment_mode == 'card' and state in ('draft', 'error')"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="exp_month"
|
||||
|
||||
Reference in New Issue
Block a user