Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

qubiq_proposals #3

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 14 additions & 27 deletions controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,48 @@
#
# TropiPay.
# [email protected]
#
#
#############################################################################


import logging
import pprint
import json
import requests
from odoo import http
from odoo.http import request
import ast

_logger = logging.getLogger(__name__)


class PaymentTppController(http.Controller):
_return_url = '/payment/tpp/_return_url'
_information_url = '/payment/tpp/_information_url'
_information_url = '/payment/tpp/_information_url'

@http.route(_return_url, type='http', auth='public',
methods=['GET'])
def tpp__checkout(self, **data):
#_logger.info("Recibiendo de Tropipay los datos de retorno:\n%s",
# pprint.pformat(data))
# tx_sudo = request.env[
# 'payment.transaction'].sudo()._get_tx_from_notification_data(
# 'tpp', data)
#tx_sudo._handle_notification_data('tpp', data)
return request.redirect('/payment/status')



@http.route(_information_url, type='json', auth='public',
methods=['GET', 'POST'],csrf=False)
methods=['GET', 'POST'], csrf=False)
def tpp__checkout2(self, **data):
#_logger.info("Recibiendo de Tropipay EN EL URL INFORMATION: los datos de retorno:\n%s", pprint.pformat(data))
_logger.info("Cuerpo de la solicitud HTTP: %s", request.httprequest.data)
_logger.debug("Cuerpo de la solicitud HTTP: %s", request.httprequest.data)
data_dict = json.loads(request.httprequest.data) # convierte la cadena JSON a un diccionario
status = data_dict['status'] # 'OK'
#if status === OK
status = data_dict['status'] # 'OK'
if status == 'OK':
data_dict = data_dict['data'] # {'id': 383663, 'reference': 'S00047'}
data_id = data_dict['id'] # 383663
data_reference = data_dict['reference'] # 'S00047'
_logger.info("status, id, reference: %s %s %s",
data_dict = data_dict['data'] # {'id': 383663, 'reference': 'S00047'}
data_id = data_dict['id'] # 383663
data_reference = data_dict['reference'] # 'S00047'
_logger.debug(
"status, id, reference: %s %s %s",
status,
data_id,
data_reference)
tx_sudo = request.env['payment.transaction'].sudo()._get_tx_from_notification_data('tpp', request.httprequest.data)
tx_sudo._handle_notification_data('tpp', request.httprequest.data)
#return request.redirect('/payment/status')
return {'status': 'OK'}, 200
# return request.redirect('/payment/status')
return {'status': 'OK'}, 200

@http.route('/payment/tpp/failed', type='http', auth='user',
website=True, )
def payment_failed(self, redirect=None):
# return request.render("tpp_payment_gateway.tpp_payment_gateway_failed_form")
#return request.redirect('/payment/status')error-al-pagar
return request.redirect('/error-al-pagar')
return request.redirect('/error-al-pagar')
4 changes: 4 additions & 0 deletions data/payment_provider_data.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
file="tpp_payment_gateway/static/description/tropipaylogo.png"/>
<field name="company_id" ref="base.main_company"/>
<field name="redirect_form_view_id" ref="redirect_form"/>
<field name="pre_msg">
<![CDATA[
<p>Serás redirigido a la pasarela de Tropipay después de finalizar tu compra.</p>]]>
</field>
</record>

</odoo>
3 changes: 1 addition & 2 deletions models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,4 @@

from . import payment_provider
from . import payment_transaction


from . import res_partner
42 changes: 31 additions & 11 deletions models/payment_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,48 @@ def _get_payment_method_information(self):
res['tpp'] = {'mode': 'unique', 'domain': [('type', '=', 'bank')]}
return res

@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
"""Decide whether to show Tropipay as an option or not"""
providers = super()._get_compatible_providers(
*args, currency_id=currency_id, **kwargs
)
"""
We want to show Tropipay only for companies whose main currency is "EUR".
In case we select a different currency during an order,
we just convert the amount life to "EUR" on transaction creation.
"""
currency = self.main_currency_id
if currency and currency.name != "EUR":
providers = providers.filtered(lambda x: x.code != 'tpp')
return providers

def _tpp_get_api_url(self):
""" Return the API URL according to the provider state.
Note: self.ensure_one()
:return: The API URL
:rtype: str
"""
self.ensure_one()

if self.state == 'enabled':
return 'https://www.tropipay.com/api/v2/access/token'
else:
return 'https://tropipay-dev.herokuapp.com/api/v2/access/token'
website_id = self.env['website'].get_current_website()
for sel in self.filtered(lambda x: x.website_id == website_id):
sel.ensure_one()
if sel.state == 'enabled':
return 'https://www.tropipay.com/api/v2/access/token'
else:
return 'https://tropipay-dev.herokuapp.com/api/v2/access/token'

def _tpp_get_endpoint_url(self):
""" Return the ENDPOINT URL according to the provider state.
Note: self.ensure_one()
:return: The API URL
:rtype: str
"""
self.ensure_one()
website_id = self.env['website'].get_current_website()
for sel in self.filtered(lambda x: x.website_id == website_id):
sel.ensure_one()

if sel.state == 'enabled':
return 'https://www.tropipay.com/api/v2/paymentcards'
else:
return 'https://tropipay-dev.herokuapp.com/api/v2/paymentcards'

if self.state == 'enabled':
return 'https://www.tropipay.com/api/v2/paymentcards'
else:
return 'https://tropipay-dev.herokuapp.com/api/v2/paymentcards'
122 changes: 66 additions & 56 deletions models/payment_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,15 @@

import hashlib
import logging
import pprint

from werkzeug import urls

from odoo import _, api, fields, models
from odoo import _, models, fields
from odoo.exceptions import ValidationError
from odoo.tools import float_round

from odoo.addons.payment import utils as payment_utils
from odoo.http import request
# Import required libraries (make sure it is installed!)
import requests
import json
import time
import sys
from datetime import datetime
import random

_logger = logging.getLogger(__name__)

Expand All @@ -40,15 +34,19 @@ def _get_specific_rendering_values(self, processing_values):
def execute_payment(self):
"""Fetching data and Executing Payment"""
endpoint_url = self.env['payment.provider'].search([('code', '=', 'tpp')])._tpp_get_endpoint_url()
_logger.info("*****ENDPOINT ********************")
_logger.info(endpoint_url)
odoo_base_url = self.env['ir.config_parameter'].get_param('web.base.url')
_logger.debug("*****ENDPOINT ********************")
_logger.debug(endpoint_url)
odoo_base_url = \
self.env['website'].browse(self.env.context.get('website_id')).domain or \
self.env['ir.config_parameter'].get_param('web.base.url')
# TODO: sale_order is never used (!) --> delete ?
sale_order = self.env['payment.transaction'].search(
[('id', '=', self.id)]).sale_order_ids

order_line = self.env['payment.transaction'].search(
[('id', '=', self.id)]).sale_order_ids.order_line

# TODO: invoice_items is never used (!) --> delete ?
invoice_items = [
{
'ItemName': rec.product_id.name,
Expand All @@ -65,87 +63,89 @@ def execute_payment(self):
'Authorization': f'Bearer {token}'
}
amount = self.amount
ahora=datetime.now()
ahora = datetime.now()
fecha = ahora.strftime("%Y-%m-%d")
_logger.info("Mostrando country:\n%s",
self.partner_id.country_id.code)
_logger.info(f' La fecha que viene{fecha}')
# Extraer first_name y last_name de partner_name
name_parts = self.partner_name.split()
first_name = name_parts[0] if name_parts else ''
last_name = ' '.join(name_parts[1:]) if len(name_parts) > 1 else '.'

_logger.debug(
"Mostrando country:\n%s",
self.partner_id.country_id.code)
_logger.debug(f' La fecha que viene{fecha}')
payload = {
"reference": self.reference,
"concept": "Compra en la web",
"favorite": False,
"description": "Compra de productos en la tienda en linea",
"amount": round(amount * 100, 2), # float(f"{self.amount}00"), #str(self.amount)+"00",
"currency": self.currency_id.name,
# Amount in EUR, in cents.
"amount": int(float_round(self._convert_to_eur(amount, self.currency_id.name, "EUR"), precision_digits=2) * 100),
"currency": "EUR",
"singleUse": True,
"reasonId": 34,
"expirationDays": 1,
"lang": "es",
"urlSuccess": f"{odoo_base_url}/payment/tpp/_return_url",
"urlFailed": f"{odoo_base_url}/payment/tpp/failed",
#urlNotification": "https://webhook.site/bc45e9cd-5bf0-432f-994e-4f86e762788f",
#"urlNotification": f"{odoo_base_url}/payment/tpp/call-back",
"urlNotification": f"{odoo_base_url}/payment/tpp/_information_url",
"serviceDate": fecha,
"directPayment": True,
"client": {
"name": first_name,
"lastName": last_name,
"name": self.partner_id.get_partner_name(),
"lastName": self.partner_id.get_partner_surname(),
"address": self.partner_address,
"phone": self.partner_phone,
"phone": self.partner_phone or self.partner_id.mobile,
"email": self.partner_email,
"countryIso": self.partner_id.country_id.code,
"termsAndConditions": "true",
"postCode": self.partner_id.zip,
"city": self.partner_id.city
"city": self.partner_id.city_id.name or self.partner_id.city,
"postCode": int(self.partner_id.zip_id.name or self.partner_id.zip),
}
}
_logger.info(endpoint_url)
_logger.info(payload)
self.partner_id.check_client_details_tropipay()
_logger.debug(endpoint_url)
_logger.debug(payload)
response = requests.post(endpoint_url, json=payload, headers=headers)
_logger.info("La URL corta obtenid es")
_logger.info(response)
_logger.info(response.json())
_logger.debug("Tropipay response:" + str(response.text))
# If we receive an error we block that payment method but we can choose another one
if not str(response.status_code).startswith("2"):
_logger.error("Tropipay error:" + str(response.text))
raise ValidationError("")

_logger.debug("La URL corta obtenida es")
_logger.debug(response)
_logger.debug(response.json())
rendering_values = {
'api_url': response.json()["shortUrl"],
'payment_url': response.json()["paymentUrl"],
}
return rendering_values


def _get_tx_from_notification_data(self, provider_code, notification_data):
"""Getting payment status from tropipay"""
#notification_data_str = notification_data.decode('utf-8')
# Deserialize the JSON string
tx = super()._get_tx_from_notification_data(provider_code, notification_data)
if provider_code != 'tpp' or len(tx) == 1:
return tx
notification_data_dict = json.loads(notification_data)
_logger.info("asdfasf: %s", notification_data_dict)
_logger.debug("asdfasf: %s", notification_data_dict)

# Access the payment_status field
payment_status = notification_data_dict['data']['state']
_logger.info("payment_status: %s", payment_status)
_logger.debug("payment_status: %s", payment_status)
# payment_status = notification_data['state'] #5 cuando el pago se realizo correctamente
_logger.info("mi clientid: %s", self.env['payment.provider'].search([('code', '=', 'tpp')]).client_id)
clientid = self.env['payment.provider'].search([('code', '=', 'tpp')]).client_id
clientsecret = self.env['payment.provider'].search([('code', '=', 'tpp')]).client_secret
website_id = self.env['website'].get_current_website()
_logger.debug("mi clientid: %s", self.env['payment.provider'].search([('code', '=', 'tpp'), ('website_id', '=', website_id.id)]).client_id)
clientid = self.env['payment.provider'].search([('code', '=', 'tpp'), ('website_id', '=', website_id.id)]).client_id
clientsecret = self.env['payment.provider'].search([('code', '=', 'tpp'), ('website_id', '=', website_id.id)]).client_secret
bankOrderCode = notification_data_dict['data']['bankOrderCode']
originalCurrencyAmount = notification_data_dict['data']['originalCurrencyAmount']
# Concatenar los valores
data = "{}{}{}{}".format(bankOrderCode,clientid,clientsecret,originalCurrencyAmount)

data = "{}{}{}{}".format(bankOrderCode, clientid, clientsecret, originalCurrencyAmount)
_logger.info("data: {}".format(data))
# Calcular la firma utilizando SHA256
signature = hashlib.sha256(data.encode()).hexdigest()
_logger.info("misignature: {}".format(signature))
_logger.info("Firma remota: {}, Firma local: {}".format(notification_data_dict['data']['signaturev2'],signature))
_logger.info("Firma remota: {}, Firma local: {}".format(notification_data_dict['data']['signaturev2'], signature))
reference = notification_data_dict['data']['reference']
if signature != notification_data_dict['data']['signaturev2']:
_logger.info("TPP: Signature does not match")
raise ValidationError(
"tpp: " + _(
"Invalid Signature %s.",
Expand All @@ -163,8 +163,7 @@ def _get_tx_from_notification_data(self, provider_code, notification_data):
reference)
)
return tx



def _process_notification_data(self, notification_data):
super()._process_notification_data(notification_data)
if self.provider_code != 'tpp':
Expand All @@ -180,11 +179,22 @@ def _handle_notification_data(self, provider_code, notification_data):
tx._execute_callback()
return tx

def _convert_to_eur(self, amount, currency_orig, currency_dest="EUR"):
currency_orig = self.env['res.currency'].search([('name', '=', currency_orig)], limit=1)
currency_dest = self.env['res.currency'].search([('name', '=', currency_dest)], limit=1)
# Minimize probability to have outdated exchange rate, but don't call with every transaction.
if random.randint(1, 100) == 1:
self.env['res.config.settings'].search([], limit=1).update_currency_rates_manually()
res = currency_orig._convert(
amount, currency_dest, self.company_id, fields.Date.today()
)
return res

def login(self):
base_api_url = self.env['payment.provider'].search([('code', '=', 'tpp')])._tpp_get_api_url()
client_id = self.env['payment.provider'].search([('code', '=', 'tpp')]).client_id
client_secret = self.env['payment.provider'].search([('code', '=', 'tpp')]).client_secret
website_id = self.env['website'].get_current_website()
base_api_url = self.env['payment.provider'].search([('code', '=', 'tpp'), ('website_id', '=', website_id.id)])._tpp_get_api_url()
client_id = self.env['payment.provider'].search([('code', '=', 'tpp'),('website_id', '=', website_id.id)]).client_id
client_secret = self.env['payment.provider'].search([('code', '=', 'tpp'),('website_id', '=', website_id.id)]).client_secret
scope = "ALLOW_EXTERNAL_CHARGE"
grandtype = "client_credentials"
response = requests.post(base_api_url, json={
Expand All @@ -194,10 +204,10 @@ def login(self):
"scope": scope
})
data = response.json()
_logger.info("******LOS DATOS PARA VER SI SE AUTENTICO EN TROPIPAY*****")
_logger.info(data)
_logger.info(base_api_url)
_logger.info(client_id)
_logger.info(client_secret)
_logger.info("******FIN DE LOS DATOS *****")
_logger.debug("******LOS DATOS PARA VER SI SE AUTENTICO EN TROPIPAY*****")
_logger.debug(data)
_logger.debug(base_api_url)
_logger.debug(client_id)
_logger.debug(client_secret)
_logger.debug("******FIN DE LOS DATOS *****")
return data
Loading