From cfd1bfa374abe4e1283bdfe91f341c04cb91f605 Mon Sep 17 00:00:00 2001 From: Carlos Lopez Date: Mon, 4 Dec 2023 01:13:25 -0500 Subject: [PATCH] [17.0][ADD] payment_payphone: new payment provider --- payment_payphone/README.rst | 89 ++++ payment_payphone/__init__.py | 11 + payment_payphone/__manifest__.py | 23 + payment_payphone/controllers/__init__.py | 1 + payment_payphone/controllers/main.py | 34 ++ .../data/payment_provider_data.xml | 32 ++ payment_payphone/models/__init__.py | 2 + payment_payphone/models/payment_provider.py | 70 +++ .../models/payment_transaction.py | 137 ++++++ payment_payphone/pyproject.toml | 3 + payment_payphone/readme/CONFIGURE.md | 1 + payment_payphone/readme/DESCRIPTION.md | 1 + payment_payphone/readme/USAGE.md | 7 + .../static/description/configure.png | Bin 0 -> 58113 bytes payment_payphone/static/description/icon.jpeg | Bin 0 -> 3738 bytes .../static/description/index.html | 432 ++++++++++++++++++ payment_payphone/tests/__init__.py | 2 + payment_payphone/tests/common.py | 78 ++++ .../tests/test_payment_transaction.py | 169 +++++++ .../views/payment_provider_templates.xml | 15 + .../views/payment_provider_views.xml | 22 + 21 files changed, 1129 insertions(+) create mode 100644 payment_payphone/README.rst create mode 100644 payment_payphone/__init__.py create mode 100644 payment_payphone/__manifest__.py create mode 100644 payment_payphone/controllers/__init__.py create mode 100644 payment_payphone/controllers/main.py create mode 100644 payment_payphone/data/payment_provider_data.xml create mode 100644 payment_payphone/models/__init__.py create mode 100644 payment_payphone/models/payment_provider.py create mode 100644 payment_payphone/models/payment_transaction.py create mode 100644 payment_payphone/pyproject.toml create mode 100644 payment_payphone/readme/CONFIGURE.md create mode 100644 payment_payphone/readme/DESCRIPTION.md create mode 100644 payment_payphone/readme/USAGE.md create mode 100644 payment_payphone/static/description/configure.png create mode 100644 payment_payphone/static/description/icon.jpeg create mode 100644 payment_payphone/static/description/index.html create mode 100644 payment_payphone/tests/__init__.py create mode 100644 payment_payphone/tests/common.py create mode 100644 payment_payphone/tests/test_payment_transaction.py create mode 100644 payment_payphone/views/payment_provider_templates.xml create mode 100644 payment_payphone/views/payment_provider_views.xml diff --git a/payment_payphone/README.rst b/payment_payphone/README.rst new file mode 100644 index 00000000..ea5559d7 --- /dev/null +++ b/payment_payphone/README.rst @@ -0,0 +1,89 @@ +========================= +Payphone Payment Provider +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:61dadd3e2996246649ce8044e6192e97e205e0f7a474685a1e61ef2e21eeeef3 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fl10n--ecuador-lightgray.png?logo=github + :target: https://github.com/OCA/l10n-ecuador/tree/17.0/payment_payphone + :alt: OCA/l10n-ecuador +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/l10n-ecuador-17-0/l10n-ecuador-17-0-payment_payphone + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/l10n-ecuador&target_branch=17.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Payment Payphone provider by redirection + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +See https://docs.payphone.app/doc/redireccion/ + +Usage +===== + +To configure this module, you need to: + +- Go to Payment providers Menu +- Configure your Access Token from your Payphone account +- Enable the payment method + +|image| + +.. |image| image:: https://raw.githubusercontent.com/OCA/l10n-ecuador/17.0/payment_payphone/static/description/configure.png + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Carlos Lopez + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/l10n-ecuador `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/payment_payphone/__init__.py b/payment_payphone/__init__.py new file mode 100644 index 00000000..eead65ff --- /dev/null +++ b/payment_payphone/__init__.py @@ -0,0 +1,11 @@ +from . import models +from . import controllers +from odoo.addons.payment import setup_provider, reset_payment_provider + + +def post_init_hook(env): + setup_provider(env, "payphone") + + +def uninstall_hook(env): + reset_payment_provider(env, "payphone") diff --git a/payment_payphone/__manifest__.py b/payment_payphone/__manifest__.py new file mode 100644 index 00000000..9068667e --- /dev/null +++ b/payment_payphone/__manifest__.py @@ -0,0 +1,23 @@ +{ + "name": "Payphone Payment Provider", + "category": "Accounting/Payment Acquirers", + "summary": "Payphone Payment Provider", + "version": "17.0.1.0.0", + "author": "Odoo Community Association (OCA), Carlos Lopez", + "website": "https://github.com/OCA/l10n-ecuador", + "license": "AGPL-3", + "depends": [ + "payment", + ], + "external_dependencies": { + "python": [], + }, + "data": [ + "views/payment_provider_templates.xml", + "data/payment_provider_data.xml", + "views/payment_provider_views.xml", + ], + "installable": True, + "post_init_hook": "post_init_hook", + "uninstall_hook": "uninstall_hook", +} diff --git a/payment_payphone/controllers/__init__.py b/payment_payphone/controllers/__init__.py new file mode 100644 index 00000000..12a7e529 --- /dev/null +++ b/payment_payphone/controllers/__init__.py @@ -0,0 +1 @@ +from . import main diff --git a/payment_payphone/controllers/main.py b/payment_payphone/controllers/main.py new file mode 100644 index 00000000..b34ab298 --- /dev/null +++ b/payment_payphone/controllers/main.py @@ -0,0 +1,34 @@ +import logging +import pprint + +from odoo import http +from odoo.http import request + +_logger = logging.getLogger(__name__) + + +class PayphoneController(http.Controller): + _return_url = "/payment/payphone/return" + + @http.route( + _return_url, + type="http", + methods=["GET"], + auth="public", + csrf=False, + save_session=False, + ) + def payphone_return_from_checkout(self, **data): + """Process the notification data + sent by Payphone after redirection from checkout. + + :param dict data: The notification data. + """ + # Handle the notification data. + _logger.debug( + "Handling redirection from Payphone with data:\n%s", pprint.pformat(data) + ) + request.env["payment.transaction"].sudo()._handle_notification_data( + "payphone", data + ) + return request.redirect("/payment/status") diff --git a/payment_payphone/data/payment_provider_data.xml b/payment_payphone/data/payment_provider_data.xml new file mode 100644 index 00000000..5653b78c --- /dev/null +++ b/payment_payphone/data/payment_provider_data.xml @@ -0,0 +1,32 @@ + + + + Payphone + payphone + 10 + + False + False + + + + + Payphone + + payphone + + + + + diff --git a/payment_payphone/models/__init__.py b/payment_payphone/models/__init__.py new file mode 100644 index 00000000..9afbccd3 --- /dev/null +++ b/payment_payphone/models/__init__.py @@ -0,0 +1,2 @@ +from . import payment_provider +from . import payment_transaction diff --git a/payment_payphone/models/payment_provider.py b/payment_payphone/models/payment_provider.py new file mode 100644 index 00000000..d596d7ed --- /dev/null +++ b/payment_payphone/models/payment_provider.py @@ -0,0 +1,70 @@ +import logging +import pprint + +import requests +from werkzeug import urls + +from odoo import _, fields, models +from odoo.exceptions import ValidationError + +_logger = logging.getLogger(__name__) + +PAYPHONE_URL = "https://pay.payphonetodoesposible.com/" + + +class PaymentProvider(models.Model): + _inherit = "payment.provider" + + code = fields.Selection( + selection_add=[("payphone", "Payphone")], ondelete={"payphone": "set default"} + ) + payphone_access_token = fields.Char( + required_if_provider="payphone", + groups="base.group_system", + ) + + def _payphone_make_request(self, endpoint, payload): + """Make a request to Payphone API at the specified endpoint. + + Note: self.ensure_one() + + :param str endpoint: The endpoint to be reached by the request. + :param dict payload: The payload of the request. + :return The JSON-formatted content of the response. + :rtype: dict + :raise ValidationError: If an HTTP error occurs. + """ + self.ensure_one() + url = urls.url_join(PAYPHONE_URL, f"api/{endpoint}") + headers = {"Authorization": f"Bearer {self.payphone_access_token}"} + response_content = {} + try: + response = requests.post(url, json=payload, headers=headers, timeout=10) + response_content = response.json() + response.raise_for_status() + except Exception: + _logger.exception( + "Invalid API request at %s with data:\n%s", + url, + pprint.pformat(payload), + ) + message_list = [] + if response_content.get("message"): + message_list.append( + f"Error Code: {response_content.get('errorCode')}. " + f"Descripcion: {response_content.get('message')}" + ) + for messaje in response_content.get("errors", []): + msj = messaje.get("message") + msj_description = "".join(messaje.get("errorDescriptions")) + message_list.append( + f"Error Code: {msj}. Descripcion: {msj_description}" + ) + raise ValidationError( + _( + "Payphone: The communication with the API failed. " + "Payphone gave us the following information: '%s'", + "\n".join(message_list), + ) + ) from None + return response_content diff --git a/payment_payphone/models/payment_transaction.py b/payment_payphone/models/payment_transaction.py new file mode 100644 index 00000000..d1f2bb96 --- /dev/null +++ b/payment_payphone/models/payment_transaction.py @@ -0,0 +1,137 @@ +import logging + +from werkzeug import urls + +from odoo import _, models +from odoo.exceptions import ValidationError + +from ..controllers.main import PayphoneController + +_logger = logging.getLogger(__name__) + + +class PaymentTransaction(models.Model): + _inherit = "payment.transaction" + + def _get_specific_rendering_values(self, processing_values): + """Override of `payment` to return Payphone-specific rendering values. + :param dict processing_values: + The generic and specific processing values of the transaction + :return: The dict of provider-specific processing values. + :rtype: dict + """ + res = super()._get_specific_rendering_values(processing_values) + if self.provider_code != "payphone": + return res + + # Initiate the payment and retrieve the payment link data. + payload = self._payphone_prepare_preference_request_payload() + payphone_response = self.provider_id._payphone_make_request( + "button/Prepare", payload=payload + ) + + # Extract the payment link URL and params and embed them in the redirect form. + self.write({"provider_reference": payphone_response.get("paymentId")}) + api_url = payphone_response.get("payWithPayPhone") + parsed_url = urls.url_parse(api_url) + url_params = urls.url_decode(parsed_url.query) + rendering_values = { + "api_url": api_url, + "url_params": url_params, # Encore the params as inputs to preserve them. + } + return rendering_values + + def _payphone_prepare_preference_request_payload(self): + """Create the payload for the preference request + based on the transaction values. + + :return: The request payload. + :rtype: dict + """ + base_url = self.provider_id.get_base_url() + return_url = urls.url_join(base_url, PayphoneController._return_url) + return { + "amount": int(self.amount * 100), + "AmountWithoutTax": int(self.amount * 100), + "currency": "USD", + "clientTransactionId": self.reference, + "reference": self.reference, + "ResponseUrl": return_url, + "cancellationUrl": return_url, + } + + def _get_tx_from_notification_data(self, provider_code, notification_data): + """Override of `payment` to find the transaction based on Payphone data. + + :param str provider_code: The code of the provider that handled the transaction. + :param dict notification_data: The notification data sent by the provider. + :return: The transaction if found. + :rtype: recordset of `payment.transaction` + :raise ValidationError: If inconsistent data were received. + :raise ValidationError: If the data match no transaction. + """ + tx = super()._get_tx_from_notification_data(provider_code, notification_data) + if provider_code != "payphone" or len(tx) == 1: + return tx + + reference = notification_data.get("clientTransactionId") + if not reference: + raise ValidationError(_("Payphone: Received data with missing reference.")) + + tx = self.search( + [("reference", "=", reference), ("provider_code", "=", "payphone")] + ) + if not tx: + raise ValidationError( + _("Payphone: 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 Payphone data. + + Note: self.ensure_one() from `_process_notification_data` + + :param dict notification_data: The notification data sent by the provider. + :return: None + :raise ValidationError: If inconsistent data were received. + """ + super()._process_notification_data(notification_data) + if self.provider_code != "payphone": + return + + if notification_data.get("id") == "0": + self._set_canceled() + return + if ( + "id" not in notification_data + and "Su dominio no está autorizado" in notification_data.get("msg", "") + ): + self._set_error(notification_data.get("msg", "")) + return + payload = { + "id": notification_data.get("id"), + "clientTxId": notification_data.get("clientTransactionId"), + } + # Verify the notification data. + verified_payment_data = self.provider_id._payphone_make_request( + "button/V2/Confirm", payload=payload + ) + + # Update the payment method. + payment_status = verified_payment_data.get("statusCode") + if payment_status == 3: + self._set_done() + elif payment_status == 2: + self._set_canceled() + else: # Classify unsupported payment status as the `error` tx state. + _logger.warning( + "Received data for transaction " + "with reference %s with invalid payment status: %s", + self.reference, + payment_status, + ) + self._set_error( + "Payphone: " + + _("Received data with invalid status: %s", payment_status) + ) diff --git a/payment_payphone/pyproject.toml b/payment_payphone/pyproject.toml new file mode 100644 index 00000000..4231d0cc --- /dev/null +++ b/payment_payphone/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/payment_payphone/readme/CONFIGURE.md b/payment_payphone/readme/CONFIGURE.md new file mode 100644 index 00000000..bdc0dc94 --- /dev/null +++ b/payment_payphone/readme/CONFIGURE.md @@ -0,0 +1 @@ +See diff --git a/payment_payphone/readme/DESCRIPTION.md b/payment_payphone/readme/DESCRIPTION.md new file mode 100644 index 00000000..a129c778 --- /dev/null +++ b/payment_payphone/readme/DESCRIPTION.md @@ -0,0 +1 @@ +Payment Payphone provider by redirection diff --git a/payment_payphone/readme/USAGE.md b/payment_payphone/readme/USAGE.md new file mode 100644 index 00000000..6ef1bd6b --- /dev/null +++ b/payment_payphone/readme/USAGE.md @@ -0,0 +1,7 @@ +To configure this module, you need to: + +- Go to Payment providers Menu +- Configure your Access Token from your Payphone account +- Enable the payment method + +![image](../static/description/configure.png) diff --git a/payment_payphone/static/description/configure.png b/payment_payphone/static/description/configure.png new file mode 100644 index 0000000000000000000000000000000000000000..2a5c3747d6276b993a8d88c171ca04d9128bdd04 GIT binary patch literal 58113 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 Ab^rhX literal 0 HcmV?d00001 diff --git a/payment_payphone/static/description/icon.jpeg b/payment_payphone/static/description/icon.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..8eb367241e8d2fae0b834b8e6f9cd2f5b96280ef GIT binary patch literal 3738 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 Det@V+ literal 0 HcmV?d00001 diff --git a/payment_payphone/static/description/index.html b/payment_payphone/static/description/index.html new file mode 100644 index 00000000..31edc183 --- /dev/null +++ b/payment_payphone/static/description/index.html @@ -0,0 +1,432 @@ + + + + + +Payphone Payment Provider + + + +
+

Payphone Payment Provider

+ + +

Beta License: AGPL-3 OCA/l10n-ecuador Translate me on Weblate Try me on Runboat

+

Payment Payphone provider by redirection

+

Table of contents

+ + +
+

Usage

+

To configure this module, you need to:

+
    +
  • Go to Payment providers Menu
  • +
  • Configure your Access Token from your Payphone account
  • +
  • Enable the payment method
  • +
+

image

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Carlos Lopez
  • +
+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/l10n-ecuador project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/payment_payphone/tests/__init__.py b/payment_payphone/tests/__init__.py new file mode 100644 index 00000000..96b5f13e --- /dev/null +++ b/payment_payphone/tests/__init__.py @@ -0,0 +1,2 @@ +from . import common +from . import test_payment_transaction diff --git a/payment_payphone/tests/common.py b/payment_payphone/tests/common.py new file mode 100644 index 00000000..ff741d11 --- /dev/null +++ b/payment_payphone/tests/common.py @@ -0,0 +1,78 @@ +import json + +from requests import PreparedRequest, Response, Session +from werkzeug import urls + +from odoo.addons.payment.tests.common import PaymentCommon +from odoo.addons.payment_payphone.models.payment_provider import PAYPHONE_URL + +PAYPHONE_DUMMY_ID = "DUMMY_ID" + + +class PayphoneCommon(PaymentCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.amount = 10 + cls.currency = cls.currency_usd + cls.provider = cls._prepare_provider( + "payphone", + update_values={ + "payphone_access_token": "DUMMY_ACCESS_TOKEN", + }, + ) + cls.init_transaction_vals = { + "paymentId": PAYPHONE_DUMMY_ID, + "payWithPayPhone": urls.url_join( + PAYPHONE_URL, f"PayPhone/Index?paymentId={PAYPHONE_DUMMY_ID}" + ), + } + cls.payphone_wrong_account = { + "message": "Su aplicación no esta autorizada para acceder a este recurso", + } + cls.payphone_result = { + "id": PAYPHONE_DUMMY_ID, + "clientTransactionId": cls.reference, + } + cls.payphone_result_cancel = dict(cls.payphone_result, id="0") + cls.payphone_transaction = { + "email": "test@example.com", + "cardType": "Test", + "bin": "777300", + "lastDigits": "2632", + "deferredCode": "00000000", + "deferred": False, + "cardBrand": "PayPhone PayPhone", + "amount": 10, + "clientTransactionId": PAYPHONE_DUMMY_ID, + "phoneNumber": "593123456789", + "statusCode": 3, + "transactionStatus": "Approved", + "authorizationCode": "W23801042", + "messageCode": 0, + } + # statusCode: 3 = OK, 2 = Cancel, else: Error + cls.payphone_transaction_ok = dict(cls.payphone_transaction) + cls.payphone_transaction_rejected = dict(cls.payphone_transaction, statusCode=2) + cls.payphone_transaction_error = dict(cls.payphone_transaction, statusCode=4) + + @classmethod + def _request_handler(cls, s: Session, res: PreparedRequest, /, **kw): + # Payphone transaction init, set default values + if res.url.startswith(PAYPHONE_URL) and "button/Prepare" in res.url: + return cls._make_payphone_requests(res.url, cls.init_transaction_vals) + return super()._request_handler(s, res, **kw) + + @classmethod + def _make_payphone_requests(cls, url, json_data=None, status_code=200): + """ + :param json_data: dict to response + :param status_code: + :returns response: requests response""" + json_content = json_data or {} + response = Response() + response.status_code = status_code + response._content = json.dumps(json_content).encode() + response.url = url + response.headers["Content-Type"] = "application/json" + return response diff --git a/payment_payphone/tests/test_payment_transaction.py b/payment_payphone/tests/test_payment_transaction.py new file mode 100644 index 00000000..2bf8ace3 --- /dev/null +++ b/payment_payphone/tests/test_payment_transaction.py @@ -0,0 +1,169 @@ +from unittest.mock import patch + +import requests + +from odoo import _ +from odoo.exceptions import ValidationError +from odoo.tests import tagged +from odoo.tools import mute_logger + +from odoo.addons.payment.tests.http_common import PaymentHttpCommon +from odoo.addons.payment_payphone.controllers.main import PayphoneController +from odoo.addons.payment_payphone.tests.common import PayphoneCommon + + +@tagged("post_install", "-at_install") +class TestPaymentTransaction(PayphoneCommon, PaymentHttpCommon): + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_01_redirect_form_values(self): + tx = self._create_transaction(flow="redirect") + processing_values = tx._get_processing_values() + form_info = self._extract_values_from_html_form( + processing_values["redirect_form_html"] + ) + self.assertEqual( + form_info["action"], self.init_transaction_vals["payWithPayPhone"] + ) + self.assertEqual(form_info["method"], "get") + self.assertEqual( + form_info["inputs"].get("paymentId"), + self.init_transaction_vals["paymentId"], + ) + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_01_transaction_error_account(self): + _origin_post = requests.post + + def _patch_get_payphone(url, *args, **kwargs): + if "button/Prepare" in url: + return PayphoneCommon._make_payphone_requests( + url, self.payphone_wrong_account, status_code=401 + ) + return _origin_post(url, *args, **kwargs) + + tx = self._create_transaction(flow="redirect") + with patch.object(requests, "post", _patch_get_payphone): + with self.assertRaises(ValidationError), self.assertLogs( + level="ERROR" + ) as log_catcher: + tx._get_processing_values() + self.assertEqual( + len(log_catcher.output), 1, "Exactly one warning should be logged" + ) + self.assertIn("Invalid API request", log_catcher.output[0]) + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_02_feedback_done(self): + _origin_post = requests.post + + def _patch_get_payphone(url, *args, **kwargs): + if "button/V2/Confirm" in url: + return PayphoneCommon._make_payphone_requests( + url, self.payphone_transaction_ok + ) + return _origin_post(url, *args, **kwargs) + + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + with patch.object(requests, "post", _patch_get_payphone): + tx._handle_notification_data(tx.provider_code, self.payphone_result) + self.assertEqual(tx.state, "done") + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_03_feedback_rejected(self): + _origin_post = requests.post + + def _patch_get_payphone(url, *args, **kwargs): + if "button/V2/Confirm" in url: + return PayphoneCommon._make_payphone_requests( + url, self.payphone_transaction_rejected + ) + return _origin_post(url, *args, **kwargs) + + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + with patch.object(requests, "post", _patch_get_payphone): + tx._handle_notification_data( + tx.provider_code, self.payphone_transaction_rejected + ) + self.assertEqual(tx.state, "cancel") + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_04_feedback_cancel(self): + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + tx._handle_notification_data(tx.provider_code, self.payphone_result_cancel) + self.assertEqual(tx.state, "cancel") + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_05_feedback_error(self): + _origin_post = requests.post + + def _patch_get_payphone(url, *args, **kwargs): + if "button/V2/Confirm" in url: + return PayphoneCommon._make_payphone_requests( + url, self.payphone_transaction_error + ) + return _origin_post(url, *args, **kwargs) + + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + with patch.object(requests, "post", _patch_get_payphone): + tx._handle_notification_data( + tx.provider_code, self.payphone_transaction_error + ) + self.assertEqual(tx.state, "error") + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_06_provider_none(self): + self.provider = self.dummy_provider + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + tx._handle_notification_data(tx.provider_code, {}) + # en provider none no se ejecutara codigo, asi que deberia seguir en draft + self.assertEqual(tx.state, "draft") + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_07_transaction_from_controller_ok(self): + _origin_post = requests.post + + def _patch_get_payphone(url, *args, **kwargs): + if "button/V2/Confirm" in url: + return PayphoneCommon._make_payphone_requests( + url, self.payphone_transaction_ok + ) + return _origin_post(url, *args, **kwargs) + + return_url = self._build_url(PayphoneController._return_url) + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + with patch.object(requests, "post", _patch_get_payphone): + controller_response = self._make_http_get_request( + return_url, params=self.payphone_result + ) + self.assertEqual(controller_response.status_code, 200) + self.assertEqual(tx.state, "done") + self.assertTrue("/payment/status" in controller_response.url) + + @mute_logger("odoo.addons.payment.models.payment_transaction") + def test_08_controller_wrong_client_transaction_id(self): + return_url = self._build_url(PayphoneController._return_url) + tx = self._create_transaction(flow="redirect") + tx._get_processing_values() + controller_response = self._make_http_get_request( + return_url, + params={}, # no clientTransactionId + ) + self.assertEqual(controller_response.status_code, 400) + text_expected = _("Payphone: Received data with missing reference.") + self.assertIn(text_expected, controller_response.text) + clientTransactionId = "WRONG" + controller_response = self._make_http_get_request( + return_url, + params={"clientTransactionId": clientTransactionId}, + ) + self.assertEqual(controller_response.status_code, 400) + text_expected = _( + "Payphone: No transaction found matching reference %s.", clientTransactionId + ) + self.assertIn(text_expected, controller_response.text) diff --git a/payment_payphone/views/payment_provider_templates.xml b/payment_payphone/views/payment_provider_templates.xml new file mode 100644 index 00000000..ccedbc6c --- /dev/null +++ b/payment_payphone/views/payment_provider_templates.xml @@ -0,0 +1,15 @@ + + + + diff --git a/payment_payphone/views/payment_provider_views.xml b/payment_payphone/views/payment_provider_views.xml new file mode 100644 index 00000000..476b8afd --- /dev/null +++ b/payment_payphone/views/payment_provider_views.xml @@ -0,0 +1,22 @@ + + + + + Payphone Provider Form + payment.provider + + + + + + + + + + +