[IMP] payment(_*): show available currencies for payment providers

Before this commit, the lists of supported currencies by payment
provider were hard-coded in the Python scripts, which made them
unavailable to the users.

With this commit, the implemented initial lists of supported currencies
are displayed on the form view and are editable, because Odoo lists may
not be up-to-date. Empty lists do not trigger any filtering on the
payment providers to access payment methods.

For Authorize.net and Asiapay payment providers, the specific
`(authorize,asiapay)_currency_id` are removed and the generic payment
provider field `available_currency_ids` is restricted to a single-item
list when one of those providers is enabled.

task-2926016

closes odoo/odoo#101018

Related: odoo/enterprise#34158
Related: odoo/documentation#2788
Related: odoo/upgrade#4069
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
Valentin Vallaeys (vava)
2023-01-05 16:51:56 +01:00
parent 8726fcf822
commit 90af85c2e4
35 changed files with 385 additions and 197 deletions
@@ -3,7 +3,7 @@
from odoo import api, fields, models
class Paymentprovider(models.Model):
class PaymentProvider(models.Model):
_inherit = 'payment.provider'
journal_id = fields.Many2one(
+57 -2
View File
@@ -102,6 +102,19 @@ class PaymentProvider(models.Model):
column1='payment_id',
column2='country_id',
)
available_currency_ids = fields.Many2many(
string="Currencies",
help="The currencies available with this payment provider. Leave empty not to restrict "
"any.",
comodel_name='res.currency',
relation='payment_currency_rel',
column1="payment_provider_id",
column2="currency_id",
compute='_compute_available_currency_ids',
store=True,
readonly=False,
context={'active_test': False},
)
maximum_amount = fields.Monetary(
string="Maximum Amount",
help="The maximum payment amount that this payment provider is available for. Leave blank "
@@ -190,6 +203,22 @@ class PaymentProvider(models.Model):
#=== COMPUTE METHODS ===#
@api.depends('code')
def _compute_available_currency_ids(self):
""" Compute the available currencies based on their support by the providers.
If the provider does not filter out any currency, the field is left empty for UX reasons.
:return: None
"""
all_currencies = self.env['res.currency'].with_context(active_test=False).search([])
for provider in self:
supported_currencies = provider._get_supported_currencies()
if supported_currencies < all_currencies: # Some currencies have been filtered out.
provider.available_currency_ids = supported_currencies
else:
provider.available_currency_ids = None
@api.depends('state', 'module_state')
def _compute_color(self):
""" Update the color of the kanban card based on the state of the provider.
@@ -242,6 +271,7 @@ class PaymentProvider(models.Model):
'show_cancel_msg': True,
})
@api.depends('code')
def _compute_feature_support_fields(self):
""" Compute the feature support fields based on the provider.
@@ -415,8 +445,8 @@ class PaymentProvider(models.Model):
""" Select and return the providers matching the criteria.
The criteria are that providers must not be disabled, be in the company that is provided,
and support the country of the partner if it exists. The criteria can be further refined
by providing the keyword arguments.
support the country of the partner if it exists, and be compatible with the currency if
provided. The criteria can be further refined by providing the keyword arguments.
:param int company_id: The company to which providers must belong, as a `res.company` id.
:param int partner_id: The partner making the payment, as a `res.partner` id.
@@ -462,6 +492,16 @@ class PaymentProvider(models.Model):
]
])
# Handle the available currencies (only if supported currencies list is not empty).
if currency:
domain = expression.AND([
domain, [
'|',
('available_currency_ids', '=', False),
('available_currency_ids', 'in', [currency.id]),
]
])
# Handle tokenization support requirements.
if force_tokenization or self._is_tokenization_required(**kwargs):
domain = expression.AND([domain, [('allow_tokenization', '=', True)]])
@@ -473,6 +513,21 @@ class PaymentProvider(models.Model):
compatible_providers = self.env['payment.provider'].search(domain)
return compatible_providers
def _get_supported_currencies(self):
""" Return the supported currencies for the payment provider.
By default, all currencies are considered supported, including the inactive ones. For a
provider to filter out specific currencies, it must override this method and return the
subset of supported currencies.
Note: `self.ensure_one()`
:return: The supported currencies.
:rtype: res.currency
"""
self.ensure_one()
return self.env['res.currency'].with_context(active_test=False).search([])
def _is_tokenization_required(self, **kwargs):
""" Return whether tokenizing the transaction is required given its context.
+1
View File
@@ -79,6 +79,7 @@ class PaymentCommon(BaseCommon):
'is_published': True,
'allow_tokenization': True,
'redirect_form_view_id': redirect_form.id,
'available_currency_ids': [Command.set((cls.currency_euro + cls.currency_usd).ids)],
})
cls.provider = cls.dummy_provider
@@ -2,6 +2,7 @@
from unittest.mock import patch
from odoo import Command
from odoo.tests import tagged
from odoo.addons.payment.tests.common import PaymentCommon
@@ -70,6 +71,30 @@ class TestPaymentProvider(PaymentCommon):
)
self.assertNotIn(self.provider, compatible_providers)
def test_provider_compatible_with_available_currencies(self):
""" Test that the provider is compatible with its available currencies. """
compatible_providers = self.provider._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=self.currency_euro.id
)
self.assertIn(self.provider, compatible_providers)
def test_provider_not_compatible_with_unavailable_currencies(self):
""" Test that the provider is not compatible with a currency that is not available. """
# Make sure the list of available currencies is not empty.
self.provider.available_currency_ids = [Command.unlink(self.currency_usd.id)]
compatible_providers = self.provider._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=self.currency_usd.id
)
self.assertNotIn(self.provider, compatible_providers)
def test_provider_compatible_when_no_available_currency_set(self):
""" Test that the provider is always compatible when no available currency is set. """
self.provider.available_currency_ids = [Command.clear()]
compatible_providers = self.provider._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=self.currency_euro.id
)
self.assertIn(self.provider, compatible_providers)
def test_fees_null_when_deactivated(self):
""" Test that extra fees of a provider are null if these fees are deactivated. """
self.provider.write({
@@ -84,10 +84,19 @@
</group>
<group string="Availability" name="availability">
<field name="maximum_amount"/>
<label for="available_currency_ids"/>
<!-- Use `o_row` to allow placing a button next to the field in overrides. -->
<div name="available_currencies" class="o_row">
<field name="available_currency_ids"
widget="many2many_tags"
placeholder="Select currencies. Leave empty not to restrict any."
context="{'active_test': False}"
options="{'no_create': True}"/>
</div>
<field name="available_country_ids"
widget="many2many_tags"
placeholder="Select countries. Leave empty to make available everywhere."
options="{'no_open': True, 'no_create': True}"/>
options="{'no_create': True}"/>
</group>
<group string="Payment Followup" name="payment_followup" invisible="1"/>
</group>
@@ -41,7 +41,8 @@ class PaymentProvider(models.Model):
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist Alipay providers for unsupported currencies. """
""" Override of payment to unlist Alipay providers when the currency is not CNY in case of
express checkout. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
@@ -1,6 +1,5 @@
-- disable asiapay payment provider
UPDATE payment_provider
SET asiapay_merchant_id = NULL,
asiapay_currency_id = NULL,
asiapay_secure_hash_secret = NULL,
asiapay_secure_hash_function = NULL;
@@ -2,7 +2,8 @@
from hashlib import new as hashnew
from odoo import api, fields, models
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
from odoo.addons.payment_asiapay import const
@@ -10,10 +11,6 @@ from odoo.addons.payment_asiapay import const
class PaymentProvider(models.Model):
_inherit = 'payment.provider'
def _domain_asiapay_currency_id(self):
currency_xmlids = [f'base.{key}' for key in const.CURRENCY_MAPPING]
return [('id', 'in', [self.env.ref(xmlid).id for xmlid in currency_xmlids])]
code = fields.Selection(
selection_add=[('asiapay', "AsiaPay")], ondelete={'asiapay': 'set default'}
)
@@ -22,13 +19,6 @@ class PaymentProvider(models.Model):
help="The Merchant ID solely used to identify your AsiaPay account.",
required_if_provider='asiapay',
)
asiapay_currency_id = fields.Many2one(
string="AsiaPay Currency",
help="The currency associated to your AsiaPay account.",
comodel_name='res.currency',
domain=_domain_asiapay_currency_id,
required_if_provider='asiapay',
)
asiapay_secure_hash_secret = fields.Char(
string="AsiaPay Secure Hash Secret",
required_if_provider='asiapay',
@@ -42,21 +32,16 @@ class PaymentProvider(models.Model):
required_if_provider='asiapay',
)
# ==== CONSTRAINT METHODS ===#
@api.constrains('available_currency_ids', 'state')
def _limit_available_currency_ids(self):
for provider in self.filtered(lambda p: p.code == 'asiapay'):
if len(provider.available_currency_ids) > 1 and provider.state != 'disabled':
raise ValidationError(_("Only one currency can be selected by AsiaPay account."))
# === BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of `payment` to filter out AsiaPay providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency:
providers = providers.filtered(
lambda p: p.code != 'asiapay' or currency == p.asiapay_currency_id
)
return providers
def _asiapay_get_api_url(self):
""" Return the URL of the API corresponding to the provider's state.
@@ -88,7 +88,7 @@ class PaymentTransaction(models.Model):
'merchant_id': self.provider_id.asiapay_merchant_id,
'amount': self.amount,
'reference': self.reference,
'currency_code': const.CURRENCY_MAPPING[self.provider_id.asiapay_currency_id.name],
'currency_code': const.CURRENCY_MAPPING[self.provider_id.available_currency_ids[0].name],
'mps_mode': 'SCP',
'return_url': urls.url_join(base_url, AsiaPayController._return_url),
'payment_type': 'N',
+3 -1
View File
@@ -1,5 +1,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import Command
from odoo.addons.payment.tests.common import PaymentCommon
@@ -11,9 +13,9 @@ class AsiaPayCommon(PaymentCommon):
cls.asiapay = cls._prepare_provider('asiapay', update_values={
'asiapay_merchant_id': '123456789',
'asiapay_currency_id': cls.currency_euro,
'asiapay_secure_hash_secret': 'coincoin_motherducker',
'asiapay_secure_hash_function': 'sha1',
'available_currency_ids': [Command.set(cls.currency_euro.ids)],
})
cls.provider = cls.asiapay
@@ -11,9 +11,6 @@
<field name="asiapay_merchant_id"
string="Merchant ID"
attrs="{'required': [('code', '=', 'asiapay'), ('state', '!=', 'disabled')]}"/>
<field name="asiapay_currency_id"
string="Currency"
attrs="{'required': [('code', '=', 'asiapay'), ('state', '!=', 'disabled')]}"/>
<field name="asiapay_secure_hash_secret"
string="Secure Hash Secret"
attrs="{'required': [('code', '=', 'asiapay'), ('state', '!=', 'disabled')]}"
@@ -24,6 +21,9 @@
groups="base.group_no_one"/>
</group>
</group>
<field name="available_currency_ids" position="attributes">
<attribute name="attrs">{'required': [('code', '=', 'asiapay'), ('state', '!=', 'disabled')]}</attribute>
</field>
</field>
</record>
@@ -27,10 +27,6 @@ class PaymentProvider(models.Model):
authorize_client_key = fields.Char(
string="API Client Key",
help="The public client key. To generate directly from Odoo or from Authorize.Net backend.")
# Authorize.Net supports only one currency: "One gateway account is required for each currency"
# See https://community.developer.authorize.net/t5/The-Authorize-Net-Developer-Blog/Authorize-Net-UK-Europe-Update/ba-p/35957
authorize_currency_id = fields.Many2one(
string="Authorize Currency", comodel_name='res.currency')
authorize_payment_method_type = fields.Selection(
string="Allow Payments From",
help="Determines with what payment method the customer can pay.",
@@ -51,6 +47,16 @@ class PaymentProvider(models.Model):
"method type on the duplicated provider."
))
# Authorize.Net supports only one currency: "One gateway account is required for each currency"
# See https://community.developer.authorize.net/t5/The-Authorize-Net-Developer-Blog/Authorize-Net-UK-Europe-Update/ba-p/35957
@api.constrains('available_currency_ids', 'state')
def _limit_available_currency_ids(self):
for provider in self.filtered(lambda p: p.code == 'authorize'):
if len(provider.available_currency_ids) > 1 and provider.state != 'disabled':
raise ValidationError(
_("Only one currency can be selected by Authorize.Net account.")
)
#=== COMPUTE METHODS ===#
def _compute_feature_support_fields(self):
@@ -104,24 +110,11 @@ class PaymentProvider(models.Model):
raise UserError(_("Could not fetch merchant details:\n%s", res_content['err_msg']))
currency = self.env['res.currency'].search([('name', 'in', res_content.get('currencies'))])
self.authorize_currency_id = currency
self.available_currency_ids = [Command.set(currency.ids)]
self.authorize_client_key = res_content.get('publicClientKey')
# === BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist Authorize providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency:
providers = providers.filtered(
lambda p: p.code != 'authorize' or currency == p.authorize_currency_id
)
return providers
def _get_validation_amount(self):
""" Override of payment to return the amount for Authorize.Net validation operations.
@@ -144,4 +137,4 @@ class PaymentProvider(models.Model):
if self.code != 'authorize':
return res
return self.authorize_currency_id
return self.available_currency_ids[0]
+3 -1
View File
@@ -1,5 +1,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.fields import Command
from odoo.addons.payment.tests.common import PaymentCommon
@@ -13,7 +15,7 @@ class AuthorizeCommon(PaymentCommon):
'authorize_login': 'dummy',
'authorize_transaction_key': 'dummy',
'authorize_signature_key': '00000000',
'authorize_currency_id': cls.currency_usd.id,
'available_currency_ids': [Command.set(cls.currency_usd.ids)]
})
cls.provider = cls.authorize
@@ -14,7 +14,7 @@ from .common import AuthorizeCommon
class AuthorizeTest(AuthorizeCommon):
def test_compatible_providers(self):
# Note: in the test common, 'USD' is specified as authorize_currency_id
# Note: in the test common, 'USD' is specified as the currency linked to the user account.
unsupported_currency = self._prepare_currency('CHF')
providers = self.env['payment.provider']._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=unsupported_currency.id
@@ -43,6 +43,6 @@ class AuthorizeTest(AuthorizeCommon):
))
def test_validation(self):
self.assertEqual(self.authorize.authorize_currency_id, self.currency_usd)
self.assertEqual(self.authorize.available_currency_ids[0], self.currency_usd)
self.assertEqual(self.authorize._get_validation_amount(), 0.01)
self.assertEqual(self.authorize._get_validation_currency(), self.currency_usd)
@@ -27,15 +27,14 @@
<field name="authorize_payment_method_type"
attrs="{'invisible': [('code', '!=', 'authorize')], 'required':[('code', '=', 'authorize'), ('state', '!=', 'disabled')]}"/>
</field>
<field name="available_country_ids" position="after">
<label for="authorize_currency_id" string="Currency" attrs="{'invisible': [('code', '!=', 'authorize')]}"/>
<div class="o_row" col="2" attrs="{'invisible': [('code', '!=', 'authorize')]}">
<field name="authorize_currency_id"/>
<button class="oe_link" icon="fa-refresh" type="object"
name="action_update_merchant_details"
string="Set Account Currency"/>
</div>
</field>
<div name="available_currencies" position="inside">
<button string="Set Account Currency"
type="object"
name="action_update_merchant_details"
attrs="{'invisible': [('code', '!=', 'authorize')]}"
icon="fa-refresh"
class="oe_link"/>
</div>
</field>
</record>
+14
View File
@@ -10,3 +10,17 @@ STATUS_CODES_MAPPING = {
'refused': (690,),
'error': (490, 491, 492,),
}
# The currencies supported by Buckaroo, in ISO 4217 format.
# See https://support.buckaroo.eu/frequently-asked-questions
# Last seen online: 7 November 2022.
SUPPORTED_CURRENCIES = [
'EUR',
'GBP',
'PLN',
'DKK',
'NOK',
'SEK',
'CHF',
'USD',
]
@@ -6,6 +6,8 @@ from werkzeug import urls
from odoo import fields, models
from odoo.addons.payment_buckaroo.const import SUPPORTED_CURRENCIES
class PaymentProvider(models.Model):
_inherit = 'payment.provider'
@@ -18,6 +20,15 @@ class PaymentProvider(models.Model):
buckaroo_secret_key = fields.Char(
string="Buckaroo Secret Key", required_if_provider='buckaroo', groups='base.group_system')
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'buckaroo':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _buckaroo_get_api_url(self):
""" Return the API URL according to the state.
+1 -1
View File
@@ -7,6 +7,7 @@
SUPPORTED_CURRENCIES = [
'GBP',
'CAD',
'XAF',
'CLP',
'COP',
'EGP',
@@ -24,7 +25,6 @@ SUPPORTED_CURRENCIES = [
'TZS',
'UGX',
'USD',
'XAF',
'XOF',
'ZMW',
]
@@ -49,19 +49,24 @@ class PaymentProvider(models.Model):
# === BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, is_validation=False, **kwargs):
""" Override of payment to filter out Flutterwave providers for unsupported currencies or
for validation operations. """
providers = super()._get_compatible_providers(
*args, currency_id=currency_id, is_validation=is_validation, **kwargs
)
def _get_compatible_providers(self, *args, is_validation=False, **kwargs):
""" Override of `payment` to filter out Flutterwave providers for validation operations. """
providers = super()._get_compatible_providers(*args, is_validation=is_validation, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if (currency and currency.name not in SUPPORTED_CURRENCIES) or is_validation:
if is_validation:
providers = providers.filtered(lambda p: p.code != 'flutterwave')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'flutterwave':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _flutterwave_make_request(self, endpoint, payload=None, method='POST'):
""" Make a request to Flutterwave API at the specified endpoint.
@@ -6,7 +6,7 @@ import pprint
import requests
from werkzeug import urls
from odoo import _, api, fields, models
from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo.addons.payment_mercado_pago.const import SUPPORTED_CURRENCIES
@@ -15,7 +15,7 @@ from odoo.addons.payment_mercado_pago.const import SUPPORTED_CURRENCIES
_logger = logging.getLogger(__name__)
class Paymentprovider(models.Model):
class PaymentProvider(models.Model):
_inherit = 'payment.provider'
code = fields.Selection(
@@ -29,16 +29,14 @@ class Paymentprovider(models.Model):
# === BUSINESS METHODS === #
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of `payment` to unlist Mercado Pago providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'mercado_pago')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'mercado_pago':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _mercado_pago_make_request(self, endpoint, payload=None, method='POST'):
""" Make a request to Mercado Pago API at the specified endpoint.
@@ -62,7 +62,7 @@ class TestPaymentTransaction(MercadoPagoCommon, PaymentHttpCommon):
successful payment. """
tx = self._create_transaction(flow='redirect')
with patch(
'odoo.addons.payment_mercado_pago.models.payment_provider.Paymentprovider'
'odoo.addons.payment_mercado_pago.models.payment_provider.PaymentProvider'
'._mercado_pago_make_request', return_value=self.verification_data
):
tx._process_notification_data(self.redirect_notification_data)
+32 -6
View File
@@ -12,11 +12,37 @@ SUPPORTED_LOCALES = [
]
# Currency codes in ISO 4217 format supported by mollie.
# See https://docs.mollie.com/payments/multicurrency
# Note: support varies per payment method.
# See https://docs.mollie.com/payments/multicurrency. Last seen online: 22 September 2022.
SUPPORTED_CURRENCIES = [
'AED', 'AUD', 'BGN', 'BRL', 'CAD', 'CHF',
'CZK', 'DKK', 'EUR', 'GBP', 'HKD', 'HRK',
'HUF', 'ILS', 'ISK', 'JPY', 'MXN', 'MYR',
'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'RUB',
'SEK', 'SGD', 'THB', 'TWD', 'USD', 'ZAR'
'AED',
'AUD',
'BGN',
'BRL',
'CAD',
'CHF',
'CZK',
'DKK',
'EUR',
'GBP',
'HKD',
'HRK',
'HUF',
'ILS',
'ISK',
'JPY',
'MXN',
'MYR',
'NOK',
'NZD',
'PHP',
'PLN',
'RON',
'RUB',
'SEK',
'SGD',
'THB',
'TWD',
'USD',
'ZAR'
]
@@ -5,7 +5,7 @@ import logging
import requests
from werkzeug import urls
from odoo import _, api, fields, models, service
from odoo import _, fields, models, service
from odoo.exceptions import ValidationError
from odoo.addons.payment_mollie.const import SUPPORTED_CURRENCIES
@@ -27,16 +27,14 @@ class PaymentProvider(models.Model):
#=== BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist Mollie providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'mollie')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'mollie':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _mollie_make_request(self, endpoint, data=None, method='POST'):
""" Make a request at mollie endpoint.
+2
View File
@@ -1,6 +1,8 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# ISO 4217 codes of currencies supported by PayPal
# See https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/.
# Last seen on: 22 September 2022.
SUPPORTED_CURRENCIES = (
'AUD',
'BRL',
@@ -2,7 +2,7 @@
import logging
from odoo import _, api, fields, models
from odoo import _, fields, models
from odoo.addons.payment_paypal.const import SUPPORTED_CURRENCIES
@@ -35,16 +35,14 @@ class PaymentProvider(models.Model):
#=== BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist PayPal providers when the currency is not supported. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'paypal')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'paypal':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _paypal_get_api_url(self):
""" Return the API URL according to the provider state.
+14
View File
@@ -0,0 +1,14 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# Supported currencies of PayuLatam, in ISO 4217 currency codes.
# https://developers.payulatam.com/latam/en/docs/getting-started/response-codes-and-variables.html#accepted-currencies.
# Last seen online: 22 September 2022.
SUPPORTED_CURRENCIES = [
'ARS',
'BRL',
'CLP',
'COP',
'MXN',
'PEN',
'USD'
]
@@ -2,11 +2,10 @@
from hashlib import md5
from odoo import api, fields, models
from odoo import fields, models
from odoo.tools.float_utils import float_repr
SUPPORTED_CURRENCIES = ('ARS', 'BRL', 'CLP', 'COP', 'MXN', 'PEN', 'USD')
from odoo.addons.payment_payulatam.const import SUPPORTED_CURRENCIES
class PaymentProvider(models.Model):
_inherit = 'payment.provider'
@@ -25,16 +24,14 @@ class PaymentProvider(models.Model):
string="PayU Latam API Key", required_if_provider='payulatam',
groups='base.group_system')
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist PayU Latam providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'payulatam')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'payulatam':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _payulatam_generate_sign(self, values, incoming=True):
""" Generate the signature for incoming or outgoing communications.
@@ -12,22 +12,12 @@ from odoo.tools import mute_logger
from odoo.addons.payment.tests.http_common import PaymentHttpCommon
from odoo.addons.payment_payulatam.controllers.main import PayuLatamController
from odoo.addons.payment_payulatam.models.payment_provider import SUPPORTED_CURRENCIES
from odoo.addons.payment_payulatam.tests.common import PayULatamCommon
@tagged('post_install', '-at_install')
class PayULatamTest(PayULatamCommon, PaymentHttpCommon):
def test_compatibility_with_supported_currencies(self):
""" Test that the PayULatam provider is compatible with all supported currencies. """
for supported_currency_code in SUPPORTED_CURRENCIES:
supported_currency = self._prepare_currency(supported_currency_code)
compatible_providers = self.env['payment.provider']._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=supported_currency.id
)
self.assertIn(self.payulatam, compatible_providers)
def test_incompatibility_with_unsupported_currency(self):
""" Test that the PayULatam provider is not compatible with an unsupported currency. """
compatible_providers = self.env['payment.provider']._get_compatible_providers(
@@ -2,7 +2,7 @@
import hashlib
from odoo import api, fields, models
from odoo import fields, models
class PaymentProvider(models.Model):
@@ -16,16 +16,12 @@ class PaymentProvider(models.Model):
payumoney_merchant_salt = fields.Char(
string="Merchant Salt", required_if_provider='payumoney', groups='base.group_system')
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist PayUmoney providers when the currency is not INR. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name != 'INR':
providers = providers.filtered(lambda p: p.code != 'payumoney')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return EUR as the only supported currency. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'payumoney':
supported_currencies = supported_currencies.filtered(lambda c: c.name == 'INR')
return supported_currencies
def _payumoney_generate_sign(self, values, incoming=True):
""" Generate the shasign for incoming or outgoing communications.
+93 -8
View File
@@ -2,15 +2,100 @@
# The currencies supported by Razorpay, in ISO 4217 format. Last updated on May 26, 2021.
# See https://razorpay.com/docs/payments/payments/international-payments/#supported-currencies.
# Last seen online: 16 November 2022.
SUPPORTED_CURRENCIES = [
'AED', 'ALL', 'AMD', 'ARS', 'AUD', 'AWG', 'BBD', 'BDT', 'BMD', 'BND', 'BOB', 'BSD', 'BWP',
'BZD', 'CAD', 'CHF', 'CNY', 'COP', 'CRC', 'CUP', 'CZK', 'DKK', 'DOP', 'DZD', 'EGP', 'ETB',
'EUR', 'FJD', 'GBP', 'GHS', 'GIP', 'GMD', 'GTQ', 'GYD', 'HKD', 'HNL', 'HRK', 'HTG', 'HUF',
'IDR', 'ILS', 'INR', 'JMD', 'KES', 'KGS', 'KHR', 'KYD', 'KZT', 'LAK', 'LBP', 'LKR', 'LRD',
'LSL', 'MAD', 'MDL', 'MKD', 'MMK', 'MNT', 'MOP', 'MUR', 'MVR', 'MWK', 'MXN', 'MYR', 'NAD',
'NGN', 'NIO', 'NOK', 'NPR', 'NZD', 'PEN', 'PGK', 'PHP', 'PKR', 'QAR', 'RUB', 'SAR', 'SCR',
'SEK', 'SGD', 'SLL', 'SOS', 'SSP', 'SVC', 'SZL', 'THB', 'TTD', 'TZS', 'USD', 'UYU', 'UZS',
'YER', 'ZAR',
'AED',
'ALL',
'AMD',
'ARS',
'AUD',
'AWG',
'BBD',
'BDT',
'BMD',
'BND',
'BOB',
'BSD',
'BWP',
'BZD',
'CAD',
'CHF',
'CNY',
'COP',
'CRC',
'CUP',
'CZK',
'DKK',
'DOP',
'DZD',
'EGP',
'ETB',
'EUR',
'FJD',
'GBP',
'GHS',
'GIP',
'GMD',
'GTQ',
'GYD',
'HKD',
'HNL',
'HRK',
'HTG',
'HUF',
'IDR',
'ILS',
'INR',
'JMD',
'KES',
'KGS',
'KHR',
'KYD',
'KZT',
'LAK',
'LKR',
'LRD',
'LSL',
'MAD',
'MDL',
'MKD',
'MMK',
'MNT',
'MOP',
'MUR',
'MVR',
'MWK',
'MXN',
'MYR',
'NAD',
'NGN',
'NIO',
'NOK',
'NPR',
'NZD',
'PEN',
'PGK',
'PHP',
'PKR',
'QAR',
'RUB',
'SAR',
'SCR',
'SEK',
'SGD',
'SLL',
'SOS',
'SSP',
'SVC',
'SZL',
'THB',
'TTD',
'TZS',
'USD',
'UYU',
'UZS',
'YER',
'ZAR',
]
# Mapping of transaction states to Razorpay's payment statuses.
@@ -8,7 +8,7 @@ import pprint
import requests
from werkzeug.urls import url_join
from odoo import _, api, fields, models
from odoo import _, fields, models
from odoo.exceptions import ValidationError
from odoo.addons.payment_razorpay.const import SUPPORTED_CURRENCIES
@@ -51,16 +51,14 @@ class PaymentProvider(models.Model):
# === BUSINESS METHODS ===#
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of `payment` to filter out Razorpay providers for unsupported currencies. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'razorpay')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'razorpay':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES
)
return supported_currencies
def _razorpay_make_request(self, endpoint, payload=None, method='POST'):
""" Make a request to Razorpay API at the specified endpoint.
@@ -3,12 +3,7 @@
# ISO 4217 Data for currencies supported by sips
# NOTE: these are listed on the Atos Wordline SIPS POST documentation page
# at https://documentation.sips.worldline.com/en/WLSIPS.001-GD-Data-dictionary.html#Sips.001_DD_en-Value-currencyCode
# Yet with the simu environment, some of these currencies are *not* working
# I have no way to know if this is caused by the SIMU environment, or if it's
# the doc of SIPS that lists currencies that don't work, but since this list is
# restrictive, I'm gonna assume they are supported when using the right flow
# and payment methods, which may not work in SIMU...
# Since SIPS advises to use 'in production', well...
# Last seen on: 22 September 2022.
SUPPORTED_CURRENCIES = {
'ARS': '032',
'AUD': '036',
+10 -12
View File
@@ -3,9 +3,9 @@
from hashlib import sha256
from odoo import api, fields, models
from odoo import fields, models
from .const import SUPPORTED_CURRENCIES
from odoo.addons.payment_sips.const import SUPPORTED_CURRENCIES
class PaymentProvider(models.Model):
@@ -29,16 +29,14 @@ class PaymentProvider(models.Model):
sips_version = fields.Char(
string="Interface Version", required_if_provider='sips', default="HP_2.31")
@api.model
def _get_compatible_providers(self, *args, currency_id=None, **kwargs):
""" Override of payment to unlist Sips providers when the currency is not supported. """
providers = super()._get_compatible_providers(*args, currency_id=currency_id, **kwargs)
currency = self.env['res.currency'].browse(currency_id).exists()
if currency and currency.name not in SUPPORTED_CURRENCIES:
providers = providers.filtered(lambda p: p.code != 'sips')
return providers
def _get_supported_currencies(self):
""" Override of `payment` to return the supported currencies. """
supported_currencies = super()._get_supported_currencies()
if self.code == 'sips':
supported_currencies = supported_currencies.filtered(
lambda c: c.name in SUPPORTED_CURRENCIES.keys()
)
return supported_currencies
def _sips_generate_shasign(self, data):
""" Generate the shasign for incoming or outgoing communications.
@@ -10,8 +10,8 @@ from odoo import _, api, models
from odoo.exceptions import ValidationError
from odoo.addons.payment import utils as payment_utils
from odoo.addons.payment_sips.const import RESPONSE_CODES_MAPPING, SUPPORTED_CURRENCIES
from odoo.addons.payment_sips.controllers.main import SipsController
from .const import RESPONSE_CODES_MAPPING, SUPPORTED_CURRENCIES
_logger = logging.getLogger(__name__)
-8
View File
@@ -12,7 +12,6 @@ from odoo.tools import mute_logger
from odoo.addons.payment.tests.http_common import PaymentHttpCommon
from odoo.addons.payment_sips.controllers.main import SipsController
from odoo.addons.payment_sips.models.payment_provider import SUPPORTED_CURRENCIES
from odoo.addons.payment_sips.tests.common import SipsCommon
@@ -20,13 +19,6 @@ from odoo.addons.payment_sips.tests.common import SipsCommon
class SipsTest(SipsCommon, PaymentHttpCommon):
def test_compatible_providers(self):
for curr in SUPPORTED_CURRENCIES:
currency = self._prepare_currency(curr)
providers = self.env['payment.provider']._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=currency.id
)
self.assertIn(self.sips, providers)
unsupported_currency = self._prepare_currency('VEF')
providers = self.env['payment.provider']._get_compatible_providers(
self.company.id, self.partner.id, self.amount, currency_id=unsupported_currency.id