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.
		
		
		
		
		
			
		
			
				
					
					
						
							202 lines
						
					
					
						
							8.4 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							202 lines
						
					
					
						
							8.4 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################### | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |
| #    Author: Cybrosys Techno Solutions (odoo@cybrosys.com) | |
| # | |
| #    You can modify it under the terms of the GNU LESSER | |
| #    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | |
| # | |
| #    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | |
| #    (LGPL v3) along with this program. | |
| #    If not, see <http://www.gnu.org/licenses/>. | |
| # | |
| ############################################################################### | |
| import logging | |
| from werkzeug import urls | |
| from odoo import api, models, _ | |
| from odoo.exceptions import ValidationError | |
| from odoo.addons.payment import utils as payment_utils | |
| from odoo.addons.payment_paytabs_odoo.controllers.payment_paytabs_odoo import PaymentPaytabs | |
| 
 | |
| _logger = logging.getLogger(__name__) | |
| 
 | |
| 
 | |
| class PaymentTransaction(models.Model): | |
|     """ | |
|        Inherit the payment transactions, to add Paytabs specific functionality. | |
|  | |
|        Methods: | |
|            _compute_reference: Override of `payment` to ensure that APS' | |
|        requirements for references are satisfied. | |
|        _get_specific_rendering_values: Override of | |
|        `_get_specific_rendering_values` to handle specific rendering values | |
|        for Paytabs. | |
|        execute_payment: Fetching data and Executing Payment. | |
|        _get_tx_from_notification_data: Get payment status from Paytabs. | |
|  | |
|        _handle_notification_data: Handle the notification data received | |
|        from Paytabs. | |
|  | |
|        _process_notification_data: Process the notification data received | |
|        from Paytabs. | |
|        """ | |
|     _inherit = 'payment.transaction' | |
| 
 | |
|     @api.model | |
|     def _compute_reference(self, provider_code, prefix=None, separator='-', | |
|                            **kwargs): | |
|         """ Override of `payment` to ensure that APS' requirements for | |
|         references are satisfied. | |
|  | |
|         APS' requirements for transaction are as follows: - References can | |
|         only be made of alphanumeric characters and/or '-' and '_'. The | |
|         prefix is generated with 'tx' as default. This prevents the prefix | |
|         from being generated based on document names that may contain | |
|         non-allowed characters (eg: INV/2020/...). | |
|  | |
|         :param str provider_code: The code of the provider handling the | |
|         transaction. | |
|         :param str prefix: The custom prefix used to compute the | |
|         full reference. | |
|         :param str separator: The custom separator used to separate the prefix | |
|         from the suffix. | |
|         :return: The unique reference | |
|         for the transaction. | |
|         :rtype: str | |
|         """ | |
|         if provider_code == 'paytabs': | |
|             prefix = payment_utils.singularize_reference_prefix() | |
|         return super()._compute_reference(provider_code, prefix=prefix, | |
|                                           separator=separator, **kwargs) | |
| 
 | |
|     def _get_specific_rendering_values(self, processing_values): | |
|         """ Override of `_get_specific_rendering_values` to handle specific | |
|         rendering values for PayTabs. | |
|  | |
|         :param processing_values: The processing values dictionary. | |
|         :return: The rendering values.""" | |
|         res = super()._get_specific_rendering_values(processing_values) | |
|         if self.provider_code != 'paytabs': | |
|             return res | |
|         return self.execute_payment() | |
| 
 | |
|     def execute_payment(self): | |
|         """Fetching data and Executing Payment | |
|         :return: The response content.""" | |
|         api_url = self.env['payment.provider'].search( | |
|             [('code', '=', 'paytabs')]).domain | |
|         base_url = self.env['ir.config_parameter'].get_param('web.base.url') | |
|         sale_order = self.env['payment.transaction'].search( | |
|             [('id', '=', self.id)]).sale_order_ids | |
|         paytabs_values = { | |
|             "profile_id": int(self.provider_id.profile_key), | |
|             "tran_type": "sale", | |
|             "tran_class": "ecom", | |
|             "cart_description": self.reference, | |
|             "cart_id": self.reference, | |
|             "cart_currency": self.currency_id.name, | |
|             "cart_amount": (self.amount - sale_order.amount_tax), | |
|             'return': urls.url_join(base_url, | |
|                                     PaymentPaytabs._return_url), | |
|             'callback': urls.url_join(base_url, | |
|                                       PaymentPaytabs._return_url), | |
|             "api_url": api_url, | |
|             "customer_details": { | |
|                 "name": self.partner_name, | |
|                 "email": self.partner_email, | |
|                 "street1": self.partner_address, | |
|                 "city": self.partner_city, | |
|                 "state": self.partner_state_id.code, | |
|                 "country": self.partner_country_id.code, | |
|                 "zip": self.partner_zip | |
|             }, | |
|             "shipping_details": { | |
|                 "name": self.partner_name, | |
|                 "email": self.partner_email, | |
|                 "street1": self.partner_address, | |
|                 "city": self.partner_city, | |
|                 "state": self.partner_state_id.code, | |
|                 "country": self.partner_country_id.code, | |
|                 "zip": self.partner_zip | |
|             }, | |
|         } | |
|         response_content = self.provider_id._paytabs_make_request( | |
|             api_url, paytabs_values) | |
|         response_content['api_url'] = response_content.get('redirect_url') | |
|         return response_content | |
| 
 | |
|     def _get_tx_from_notification_data(self, provider_code, notification_data): | |
|         """ | |
|         Get payment status from Paytabs. | |
|  | |
|         :param provider_code: The code of the provider handling the transaction. | |
|         :param notification_data: The data received from Paytabs notification. | |
|         :return: The transaction matching the reference. | |
|         """ | |
|         tx = super()._get_tx_from_notification_data(provider_code, | |
|                                                     notification_data) | |
|         if provider_code != 'paytabs': | |
|             return tx | |
|         reference = notification_data.get('cartId', False) | |
|         if not reference: | |
|             raise ValidationError(_("PayTabs: No reference found.")) | |
|         tx = self.search( | |
|             [('reference', '=', reference), ('provider_code', '=', 'paytabs')]) | |
|         if not tx: | |
|             raise ValidationError( | |
|                 _("PayTabs: No transaction found matching reference" | |
|                   "%s.") % reference) | |
|         return tx | |
| 
 | |
|     def _handle_notification_data(self, provider_code, notification_data): | |
|         """ | |
|         Handle the notification data received from Paytabs. | |
|  | |
|         This method retrieves the transaction corresponding to the | |
|         notification data, processes the notification data, and executes the | |
|         callback. | |
|  | |
|         :param provider_code: The code of the provider handling the transaction. | |
|         :param notification_data: The data received from Paytabs notification. | |
|         :return: The transaction object. | |
|         """ | |
|         tx = self._get_tx_from_notification_data(provider_code, | |
|                                                  notification_data) | |
|         tx._process_notification_data(notification_data) | |
|         tx._execute_callback() | |
|         return tx | |
| 
 | |
|     def _process_notification_data(self, notification_data): | |
|         """ | |
|         Process the notification data received from PayTabs. | |
|  | |
|         This method processes the notification data and updates the payment | |
|         state of the transaction accordingly. | |
|  | |
|         :param notification_data: The data received from PayTabs notification. | |
|             """ | |
|         super()._process_notification_data(notification_data) | |
|         if self.provider_code != 'paytabs': | |
|             return | |
| 
 | |
|         status = notification_data.get('respStatus') | |
|         if status == 'A': | |
|             self._set_done(state_message="Authorised") | |
|         elif status == 'APPROVED': | |
|             self._set_pending(state_message="Authorised but on hold for " | |
|                                             "further anti-fraud review") | |
|         elif status in ('E', 'D'): | |
|             self._set_canceled(state_message="Error") | |
|         else: | |
|             _logger.warning("Received unrecognized payment state %s for " | |
|                             "transaction with reference %s", | |
|                             status, self.reference) | |
|             self._set_error("PayTabs: " + _("Invalid payment status."))
 | |
| 
 |