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.

270 lines
14 KiB

  1. # coding: utf-8
  2. #from hashlib import sha1
  3. from urllib.parse import urlparse, urljoin
  4. from odoo import api, fields, tools, models, _
  5. from odoo.addons.acquirer_payplug.controllers.main import PayPlugController
  6. from odoo.http import request
  7. from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
  8. from datetime import datetime, timedelta
  9. from odoo.exceptions import AccessError, UserError, ValidationError
  10. import logging
  11. _logger = logging.getLogger(__name__)
  12. import pprint
  13. import payplug
  14. payplug.set_api_version("2019-08-06")
  15. class TxPayPlug(models.Model):
  16. _inherit = 'payment.transaction'
  17. provider_type_payplug = fields.Selection([
  18. ('payplug', 'PayPlug'),
  19. ('oney', 'Paylater by Oney'),
  20. ('amex', 'Americam Express'),
  21. ('bancontact', 'Bancontact'),
  22. ], string="Acquirer Payplug")
  23. # TO EXTRACT THE NAME AND FIRST NAME FROM THE "NAME" FIELD
  24. def _partner_values(self, partner):
  25. vals=[]
  26. if partner:
  27. if len(partner.name.split(' ')) == 1:
  28. vals.append(partner.name)
  29. vals.append('None')
  30. else:
  31. vals=partner.name.split(' ',1)
  32. return vals
  33. # CREATE SPECIFIC VALUES FOR ONEY
  34. def _order_lines_oney(self, order):
  35. shop_lines=[]
  36. if order:
  37. for line in order.order_line:
  38. shop_lines.append({
  39. 'expected_delivery_date': (datetime.now()+timedelta(days=2)).strftime(DEFAULT_SERVER_DATE_FORMAT),
  40. 'delivery_label': order.company_id.name,
  41. 'brand': order.company_id.name,
  42. 'delivery_type': 'carrier',
  43. 'merchant_item_id': 'REF-'+str(line.id),
  44. 'name': line.product_id.name,
  45. 'total_amount': int(line.price_total*100),
  46. 'price': int(line.price_unit+(line.price_tax/line.product_uom_qty)*100),
  47. 'quantity': int(line.product_uom_qty),
  48. })
  49. return shop_lines
  50. def _get_specific_rendering_values(self, processing_values):
  51. tx_values = super()._get_specific_rendering_values(processing_values)
  52. # IF NOT PROVIDER PAYPLUG
  53. if self.provider_code != 'payplug':
  54. return tx_values
  55. # DOWNLOAD SECRET KEY PAYPLUG TEST OR LIVE
  56. secret_payplug_key = request.env['payment.provider']._key_acquirer_state(self.provider_id)
  57. # BASE URL FOR RETURN
  58. base_url = self.provider_id.get_base_url()
  59. # SECRET KEY TEST OR LIVE
  60. payplug.set_secret_key(secret_payplug_key)
  61. # PROCESSING TO EXTRACT THE ORDER NUMBER WITHOUT SO000-1, SO000-2 ADD IF SEVERAL PAYMENT ATTEMPTS
  62. if self.reference:
  63. order_id = self.reference.split('-',1)[0]
  64. # FROM ORDERS
  65. order = request.env['sale.order'].sudo().search([('name', '=', order_id)])
  66. type_of_request = 'sale.order'
  67. partner_invoice = order.partner_invoice_id
  68. if not order:
  69. # FROM INVOICE
  70. order = request.env['account.move'].sudo().search([('name', '=', self.reference)])
  71. type_of_request = 'account.move'
  72. partner_invoice = order.partner_id
  73. # MANDATORY VALUE CONTROL
  74. if not order.partner_shipping_id.country_id or not order.partner_invoice_id.country_id :
  75. raise ValidationError("PayPlug: " + _("COUNTRY is required!"))
  76. if not order.partner_shipping_id.city or not order.partner_invoice_id.city :
  77. raise ValidationError("PayPlug: " + _("CITY is required!"))
  78. if not order.partner_shipping_id.zip or not order.partner_invoice_id.zip :
  79. raise ValidationError("PayPlug: " + _("ZIP is required!"))
  80. if not order.partner_shipping_id.phone or not order.partner_invoice_id.phone :
  81. raise ValidationError("PayPlug: " + _("PHONE is required!"))
  82. if not order.partner_shipping_id.email or not order.partner_invoice_id.email :
  83. raise ValidationError("PayPlug: " + _("EMAIL is required!"))
  84. # GENERATE DIGITAL KEY
  85. payment_generate_key = {
  86. 'reference': order.name,
  87. 'customer_name': order.partner_id.name,
  88. 'customer_postcode': order.partner_id.zip,
  89. }
  90. digital_Key = self.env['payment.provider']._playplug_generate_digital_sign(payment_generate_key)
  91. partner_billing=self._partner_values(order.partner_invoice_id)
  92. partner_shipping=self._partner_values(order.partner_shipping_id)
  93. # FORMAT INTERNATIONNAL PHONE BILLING
  94. if order.partner_invoice_id.phone:
  95. BillingPhoneFormat=request.env['res.partner'].sudo()._phone_format(
  96. partner_invoice.phone or order.partner_id.phone,
  97. partner_invoice.country_id,
  98. order.company_id)
  99. if BillingPhoneFormat:
  100. BillingPhoneFormat=BillingPhoneFormat.replace(' ','')
  101. # FORMAT INTERNATIONNAL PHONE SHIPPING
  102. if order.partner_shipping_id.phone:
  103. ShippingPhoneFormat=request.env['res.partner'].sudo()._phone_format(
  104. order.partner_shipping_id.phone or order.partner_id.phone,
  105. order.partner_shipping_id.country_id,
  106. order.company_id)
  107. if ShippingPhoneFormat:
  108. ShippingPhoneFormat=ShippingPhoneFormat.replace(' ','')
  109. # BILLING FULL ADDRESS
  110. billing_full_address = order.partner_id.street
  111. if partner_invoice.street2:
  112. billing_full_address += ' - '+partner_invoice.street2
  113. # SHIPPING FULL ADDRESS
  114. shipping_full_address = order.partner_shipping_id.street
  115. if order.partner_shipping_id.street2:
  116. shipping_full_address += ' - '+order.partner_shipping_id.street2
  117. payment_data = {}
  118. payment_data = {
  119. # AMOUNT DIFFERENT BY PAYPLUG PROVIDER
  120. 'currency': str(order.currency_id.name),
  121. 'billing': {
  122. 'first_name': partner_billing[0],
  123. 'last_name': partner_billing[1],
  124. 'email': partner_invoice.email,
  125. 'address1': billing_full_address,
  126. 'postcode': partner_invoice.zip,
  127. 'city': partner_invoice.city,
  128. 'country': partner_invoice.country_id.code,
  129. 'language': partner_invoice.country_id.code.lower(),
  130. },
  131. 'shipping': {
  132. 'first_name': partner_shipping[0],
  133. 'last_name': partner_shipping[0],
  134. 'email': order.partner_shipping_id.email or order.partner_id.email,
  135. 'address1': shipping_full_address,
  136. 'postcode': order.partner_shipping_id.zip,
  137. 'city': order.partner_shipping_id.city,
  138. 'country': order.partner_shipping_id.country_id.code,
  139. 'language': order.partner_shipping_id.country_id.code.lower(),
  140. 'delivery_type': 'BILLING'
  141. },
  142. 'hosted_payment': {
  143. 'return_url': '%s' % urljoin(base_url, PayPlugController._return_url+'?transaction='+str(self.id)),
  144. 'cancel_url': '%s' % urljoin(base_url, PayPlugController._webhook_url+'?transaction='+str(self.id)),
  145. },
  146. 'metadata': {
  147. 'DigitalKey': digital_Key,
  148. 'return_validate_url': '',
  149. },
  150. }
  151. # TO DEFINE THE METHOD ACCORDING TO THE PAYPLUG PROVIDER AND SPECIFIC VALUES
  152. payment_method = request.session.get('provider_payplug')
  153. payment_method_oney = request.session.get('type_oney')
  154. amount_order = int(processing_values.get('amount')*100)
  155. if payment_method == 'payplug':
  156. payment_method_type = 'payplug'
  157. payment_data['amount'] = amount_order
  158. payment_data['metadata']['payment_method'] = 'payplug'
  159. if payment_method == 'oney':
  160. payment_method_type = 'oney'
  161. payment_data['metadata']['payment_method'] = 'oney'
  162. payment_data['authorized_amount'] = amount_order
  163. payment_data['payment_method'] = payment_method_oney
  164. payment_data['billing']['mobile_phone_number'] = BillingPhoneFormat
  165. payment_data['shipping']['mobile_phone_number'] = ShippingPhoneFormat
  166. payment_data['shipping']['company_name'] = partner_invoice.parent_id.name or partner_invoice.company_id.name
  167. payment_data['payment_context'] = {}
  168. payment_data['payment_context']['cart'] = self._order_lines_oney(order)
  169. if payment_method == 'american_express':
  170. payment_method_type = 'amex'
  171. payment_data['amount'] = amount_order
  172. payment_data['payment_method'] = 'american_express'
  173. payment_data['shipping']['company_name'] = partner_invoice.parent_id.name or partner_invoice.company_id.name
  174. payment_data['metadata']['payment_method'] = 'amex'
  175. if payment_method == 'bancontact':
  176. payment_method_type = 'bancontact'
  177. payment_data['amount'] = amount_order
  178. payment_data['payment_method'] = 'bancontact'
  179. payment_data['shipping']['company_name'] = partner_invoice.parent_id.name or partner_invoice.company_id.name
  180. payment_data['metadata']['payment_method'] = 'bancontact'
  181. payplug_tx_values = {}
  182. if processing_values.get('reference') != '/':
  183. # CREATE PAYMENT
  184. payment = payplug.Payment.create(**payment_data)
  185. payment_id = str(payment.id)
  186. # RETURN URL PAYPLUG FOR PAYMENT
  187. payplug_tx_values = dict(processing_values)
  188. if self.provider_code == 'payplug':
  189. payplug_tx_values.update({
  190. 'payplug_url': '%s' % payment.hosted_payment.payment_url,
  191. })
  192. # WRITE REFERENCE SUPPLIER IN PAYMENT TRANSACTION
  193. if processing_values.get('reference') != '/':
  194. transaction_id = request.env['payment.transaction'].sudo().search([('reference', '=', str(processing_values.get('reference')))], limit=1)
  195. transaction_id.sudo().write({
  196. 'provider_reference': payment_id,
  197. 'provider_type_payplug': payment_method_type})
  198. return payplug_tx_values
  199. # RETOUR A PARTIR DU CONTROLEUR
  200. @api.model
  201. def _get_tx_from_notification_data(self, provider, Payment):
  202. tx = key = False
  203. tx = super()._get_tx_from_notification_data(provider, Payment)
  204. if provider != 'payplug' or len(tx) == 1:
  205. return tx
  206. if isinstance(Payment,object) == True:
  207. tx = self.search([('provider_reference', '=', str(Payment.id))], limit=1)
  208. if tx:
  209. vals = {
  210. 'reference': tx.reference.split('-')[0],
  211. 'customer_name': tx.partner_id.name,
  212. 'customer_postcode': tx.partner_id.zip,
  213. }
  214. # CREATE NEW DIGITAL KEY FOR CONTROL
  215. key = Payment.metadata.get('DigitalKey')
  216. control_digital_key = tx.provider_id._playplug_generate_digital_sign(vals)
  217. if key.upper() != control_digital_key.upper():
  218. raise ValidationError(
  219. "PayPlug: " + _(
  220. "Invalid Key: received %(sign)s, computed %(check)s",
  221. sign=key.upper(), check=control_digital_key.upper()
  222. )
  223. )
  224. return tx
  225. def _process_notification_data(self, notification_data):
  226. super()._process_notification_data(notification_data)
  227. if self.provider_code != 'payplug':
  228. return
  229. # SPECIFIC STATE ONEY
  230. if notification_data.metadata.get('payment_method') == 'oney':
  231. if notification_data.authorization and notification_data.authorization.get('authorized_at'):
  232. # ACCEPTED BY ONEY
  233. self.sudo().write({'provider_reference': self.provider_reference})
  234. self._set_done(_("Your payment %s has been validated by Oney.", notification_data.payment_method.get('type')))
  235. return True
  236. if notification_data.is_paid == False and notification_data.failure == None:
  237. # WAITING FOR VALIDATION BY ONEY
  238. self.sudo().write({'state_message': 'Oney: awaiting approval'})
  239. self._set_pending(_("Your payment %s has been successfully processed but is awaiting approval by Oney.", notification_data.payment_method.get('type')))
  240. return None
  241. if notification_data.is_paid == False and notification_data.failure != None:
  242. # REFUSE BY ONEY
  243. self.sudo().write({'state_message': 'Oney: feedback error'})
  244. self._set_error(_("Your payment in %s was refused by Oney.", notification_data.payment_method.get('type')))
  245. # OTHER PROVIDER PAYPLUG
  246. else:
  247. if notification_data.is_paid == True and notification_data.failure == None:
  248. # ACCEPTED
  249. self.sudo().write({'provider_reference': self.provider_reference})
  250. self._set_done()
  251. return True
  252. if notification_data.is_paid == False and notification_data.failure == None:
  253. # WAITING FOR VALIDATION
  254. self.sudo().write({'state_message': 'PayPlug: feedback error'})
  255. self._set_pending()
  256. return None
  257. if notification_data.is_paid == False and notification_data.failure != None:
  258. # REFUSE
  259. self.sudo().write({'state_message': 'PayPlug: feedback error'})
  260. self._set_error(_("Your payment was refused."))
  261. return False