[FIX] website_sale, website_portal_sale: SO auto-confirm
1. Setup authorize.net acquirer
Published on website
Order Confirmation: capture manually
Store card: always
2. Buy something on the store => SO gets confirmed
3. Buy again but select the saved card
4. You get a confirmation screen on the website, but the SO is not
actually confirmed in the backend (but it should)
The issue is that the confirmation of the SO is located in the
`form_feedback` method. When paying with a saved credit card, there is
no form filled in since we use a S2S transaction. Therefore, the method
is never called, and the SO never confirmed.
Fixes #14007
opw-693517
This commit is contained in:
@@ -41,32 +41,42 @@ class PaymentTransaction(models.Model):
|
||||
tx = None
|
||||
res = super(PaymentTransaction, self).form_feedback(data, acquirer_name)
|
||||
|
||||
# fetch the tx, check its state, confirm the potential SO
|
||||
try:
|
||||
tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
|
||||
if hasattr(self, tx_find_method_name):
|
||||
tx = getattr(self, tx_find_method_name)(data)
|
||||
_logger.info('<%s> transaction processed: tx ref:%s, tx amount: %s', acquirer_name, tx.reference if tx else 'n/a', tx.amount if tx else 'n/a')
|
||||
# fetch the tx
|
||||
tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name
|
||||
if hasattr(self, tx_find_method_name):
|
||||
tx = getattr(self, tx_find_method_name)(data)
|
||||
_logger.info('<%s> transaction processed: tx ref:%s, tx amount: %s', acquirer_name, tx.reference if tx else 'n/a', tx.amount if tx else 'n/a')
|
||||
|
||||
if tx and tx.sale_order_id and tx.sale_order_id.state in ['draft', 'sent']:
|
||||
# verify SO/TX match, excluding tx.fees which are currently not included in SO
|
||||
amount_matches = float_compare(tx.amount, tx.sale_order_id.amount_total, 2) == 0
|
||||
if amount_matches:
|
||||
if tx.state == 'authorized' and tx.acquirer_id.auto_confirm == 'authorize':
|
||||
_logger.info('<%s> transaction authorized, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.with_context(send_email=True).action_confirm()
|
||||
if tx.state == 'done' and tx.acquirer_id.auto_confirm in ['confirm_so', 'generate_and_pay_invoice']:
|
||||
_logger.info('<%s> transaction completed, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.with_context(send_email=True).action_confirm()
|
||||
|
||||
if tx.acquirer_id.auto_confirm == 'generate_and_pay_invoice':
|
||||
self._generate_and_pay_invoice(tx, acquirer_name)
|
||||
elif tx.state not in ['cancel', 'error'] and tx.sale_order_id.state == 'draft':
|
||||
_logger.info('<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.force_quotation_send()
|
||||
else:
|
||||
_logger.warning('<%s> transaction MISMATCH for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
except Exception:
|
||||
_logger.exception('Fail to confirm the order or send the confirmation email%s', tx and ' for the transaction %s' % tx.reference or '')
|
||||
if tx:
|
||||
# Auto-confirm SO if necessary
|
||||
tx._confirm_so(acquirer_name=acquirer_name)
|
||||
|
||||
return res
|
||||
|
||||
def _confirm_so(self, acquirer_name=False):
|
||||
for tx in self:
|
||||
try:
|
||||
# check tx state, confirm the potential SO
|
||||
if tx.sale_order_id and tx.sale_order_id.state in ['draft', 'sent']:
|
||||
# verify SO/TX match, excluding tx.fees which are currently not included in SO
|
||||
amount_matches = float_compare(tx.amount, tx.sale_order_id.amount_total, 2) == 0
|
||||
if amount_matches:
|
||||
if not acquirer_name:
|
||||
acquirer_name = tx.sale_order_id.payment_acquirer_id.provider or 'unknown'
|
||||
if tx.state == 'authorized' and tx.acquirer_id.auto_confirm == 'authorize':
|
||||
_logger.info('<%s> transaction authorized, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.with_context(send_email=True).action_confirm()
|
||||
if tx.state == 'done' and tx.acquirer_id.auto_confirm in ['confirm_so', 'generate_and_pay_invoice']:
|
||||
_logger.info('<%s> transaction completed, auto-confirming order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.with_context(send_email=True).action_confirm()
|
||||
|
||||
if tx.acquirer_id.auto_confirm == 'generate_and_pay_invoice':
|
||||
self._generate_and_pay_invoice(tx, acquirer_name)
|
||||
elif tx.state not in ['cancel', 'error'] and tx.sale_order_id.state == 'draft':
|
||||
_logger.info('<%s> transaction pending/to confirm manually, sending quote email for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
tx.sale_order_id.force_quotation_send()
|
||||
else:
|
||||
_logger.warning('<%s> transaction MISMATCH for order %s (ID %s)', acquirer_name, tx.sale_order_id.name, tx.sale_order_id.id)
|
||||
|
||||
except Exception:
|
||||
_logger.exception('Fail to confirm the order or send the confirmation email%s', tx and ' for the transaction %s' % tx.reference or '')
|
||||
|
||||
@@ -753,7 +753,10 @@ class WebsiteSale(http.Controller):
|
||||
valid_state = 'authorized' if tx.acquirer_id.auto_confirm == 'authorize' else 'done'
|
||||
if not s2s_result or tx.state != valid_state:
|
||||
return dict(success=False, error=_("Payment transaction failed (%s)") % tx.state_message)
|
||||
return dict(success=True, url='/shop/payment/validate')
|
||||
else:
|
||||
# Auto-confirm SO if necessary
|
||||
tx._confirm_so()
|
||||
return dict(success=True, url='/shop/payment/validate')
|
||||
except Exception, e:
|
||||
_logger.warning(_("Payment transaction (%s) failed : <%s>") % (tx.id, str(e)))
|
||||
return dict(success=False, error=_("Payment transaction failed (Contact Administrator)"))
|
||||
|
||||
Reference in New Issue
Block a user