You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
9.0 KiB
254 lines
9.0 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# Cybrosys Technologies Pvt. Ltd.
|
|
#
|
|
# Copyright (C) 2025-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
|
|
# Author: Afra K (odoo@cybrosys.com)
|
|
#
|
|
# You can modify it under the terms of the GNU AFFERO
|
|
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
|
|
#
|
|
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
|
# (AGPL v3) along with this program.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
###############################################################################
|
|
import logging
|
|
|
|
from odoo import _, fields, models
|
|
from odoo.exceptions import UserError, ValidationError
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class PaymentTransaction(models.Model):
|
|
_inherit = 'payment.transaction'
|
|
|
|
capture_manually = fields.Boolean(related='provider_id.capture_manually')
|
|
|
|
# === ACTION METHODS ===#
|
|
|
|
def action_credit_pay_set_done(self):
|
|
""" Set the state of the credit_pay transaction to 'done'.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
self.ensure_one()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
notification_data = {'reference': self.reference,
|
|
'simulated_state': 'done'}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
def action_credit_pay_set_canceled(self):
|
|
""" Set the state of the credit_pay transaction to 'cancel'.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
self.ensure_one()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
notification_data = {'reference': self.reference,
|
|
'simulated_state': 'cancel'}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
def action_credit_pay_set_error(self):
|
|
""" Set the state of the credit_pay transaction to 'error'.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
self.ensure_one()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
notification_data = {'reference': self.reference,
|
|
'simulated_state': 'error'}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
# === BUSINESS METHODS ===#
|
|
|
|
def _send_payment_request(self):
|
|
""" Override of payment to simulate a payment request.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
super()._send_payment_request()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
if not self.token_id:
|
|
raise UserError(
|
|
"Demo: " + _("The transaction is not linked to a token."))
|
|
|
|
simulated_state = self.token_id.credit_pay_simulated_state
|
|
notification_data = {'reference': self.reference,
|
|
'simulated_state': simulated_state}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
def _send_refund_request(self, **kwargs):
|
|
""" Override of payment to simulate a refund.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:param dict kwargs: The keyword arguments.
|
|
:return: The refund transaction created to process the refund request.
|
|
:rtype: recordset of `payment.transaction`
|
|
"""
|
|
refund_tx = super()._send_refund_request(**kwargs)
|
|
if self.provider_code != 'credit_pay':
|
|
return refund_tx
|
|
|
|
notification_data = {'reference': refund_tx.reference,
|
|
'simulated_state': 'done'}
|
|
refund_tx._handle_notification_data('credit_pay', notification_data)
|
|
|
|
return refund_tx
|
|
|
|
def _send_capture_request(self):
|
|
""" Override of payment to simulate a capture request.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
super()._send_capture_request()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
notification_data = {
|
|
'reference': self.reference,
|
|
'simulated_state': 'done',
|
|
'manual_capture': True,
|
|
# Distinguish manual captures from regular one-step captures.
|
|
}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
def _send_void_request(self):
|
|
""" Override of payment to simulate a void request.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:return: None
|
|
"""
|
|
super()._send_void_request()
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
notification_data = {'reference': self.reference,
|
|
'simulated_state': 'cancel'}
|
|
self._handle_notification_data('credit_pay', notification_data)
|
|
|
|
def _get_tx_from_notification_data(self, provider_code, notification_data):
|
|
""" Override of payment to find the transaction based on dummy data.
|
|
|
|
:param str provider_code: The code of the provider that handled the
|
|
transaction :param dict notification_data: The dummy notification
|
|
data :return: The transaction if found :rtype: recordset of
|
|
`payment.transaction` :raise: ValidationError if the data match no
|
|
transaction
|
|
"""
|
|
tx = super()._get_tx_from_notification_data(provider_code,
|
|
notification_data)
|
|
if provider_code != 'credit_pay' or len(tx) == 1:
|
|
return tx
|
|
|
|
reference = notification_data.get('reference')
|
|
tx = self.search([('reference', '=', reference),
|
|
('provider_code', '=', 'credit_pay')])
|
|
if not tx:
|
|
raise ValidationError(
|
|
"Demo: " + _("No transaction found matching reference %s.",
|
|
reference)
|
|
)
|
|
return tx
|
|
|
|
def _process_notification_data(self, notification_data):
|
|
""" Override of payment to process the transaction based on dummy data.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:param dict notification_data: The dummy notification data
|
|
:return: None
|
|
:raise: ValidationError if inconsistent data were received
|
|
"""
|
|
super()._process_notification_data(notification_data)
|
|
if self.provider_code != 'credit_pay':
|
|
return
|
|
|
|
self.provider_reference = f'credit_pay-{self.reference}'
|
|
|
|
if self.tokenize:
|
|
# The reasons why we immediately tokenize the transaction
|
|
# regardless of the state rather than waiting for the payment
|
|
# method to be validated ('authorized' or 'done') like the other
|
|
# payment providers do are: - To save the simulated state and
|
|
# payment details on the token while we have them. - To allow
|
|
# customers to create tokens whose transactions will always end
|
|
# up in the said simulated state.
|
|
self._credit_pay_tokenize_from_notification_data(notification_data)
|
|
|
|
state = notification_data['simulated_state']
|
|
if state == 'pending':
|
|
self._set_pending()
|
|
elif state == 'done':
|
|
if self.capture_manually and not notification_data.get(
|
|
'manual_capture'):
|
|
self._set_authorized()
|
|
else:
|
|
self._set_done()
|
|
# Immediately post-process the transaction if it is a refund,
|
|
# as the post-processing will not be triggered by a customer
|
|
# browsing the transaction from the portal.
|
|
if self.operation == 'refund':
|
|
self.env.ref(
|
|
'payment.cron_post_process_payment_tx')._trigger()
|
|
elif state == 'cancel':
|
|
self._set_canceled()
|
|
else: # Simulate an error state.
|
|
self._set_error(
|
|
_("You selected the following credit_pay payment status: %s",
|
|
state))
|
|
|
|
def _credit_pay_tokenize_from_notification_data(self, notification_data):
|
|
""" Create a new token based on the notification data.
|
|
|
|
Note: self.ensure_one()
|
|
|
|
:param dict notification_data: The fake notification data to tokenize
|
|
from. :return: None
|
|
"""
|
|
self.ensure_one()
|
|
|
|
state = notification_data['simulated_state']
|
|
token = self.env['payment.token'].create({
|
|
'provider_id': self.provider_id.id,
|
|
'payment_details': notification_data['payment_details'],
|
|
'partner_id': self.partner_id.id,
|
|
'provider_ref': 'fake provider reference',
|
|
'verified': True,
|
|
'credit_pay_simulated_state': state,
|
|
})
|
|
self.write({
|
|
'token_id': token,
|
|
'tokenize': False,
|
|
})
|
|
_logger.info(
|
|
"Created token with id %s for partner with id %s.", token.id,
|
|
self.partner_id.id
|
|
)
|
|
|