-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fc49c4f
commit a08b6ae
Showing
15 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright 2023 Tecnativa - Ernesto Tejeda | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
{ | ||
"name": "Currency Rate Update: CoinGecko", | ||
"version": "16.0.1.0.0", | ||
"category": "Financial Management/Configuration", | ||
"summary": "Update exchange rates using CoinGecko", | ||
"author": "Tecnativa, Odoo Community Association (OCA)", | ||
"website": "https://github.com/OCA/currency", | ||
"license": "AGPL-3", | ||
"installable": True, | ||
"application": False, | ||
"depends": ["currency_rate_update_mapping", "crypto_currency"], | ||
"data":["data/res_currency_rate_provider.xml"], | ||
"external_dependencies": {"python": ["pycgapi"]}, | ||
} |
10 changes: 10 additions & 0 deletions
10
currency_rate_update_coingecko/data/res_currency_rate_provider.xml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?xml version="1.0" ?> | ||
<!-- | ||
Copyright 2024 Onestein | ||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
--> | ||
<odoo noupdate="1"> | ||
<record model="res.currency.rate.provider" id="res_currency_rate_provider_coingecko"> | ||
<field name="service">CoinGecko</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
from . import res_currency_rate_provider_CoinGecko |
133 changes: 133 additions & 0 deletions
133
currency_rate_update_coingecko/models/res_currency_rate_provider_CoinGecko.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
# Copyright 2024 Onestein | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
import logging | ||
from datetime import date, timedelta | ||
|
||
from pycgapi import CoinGeckoAPI | ||
|
||
from odoo import _, fields, models | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class ResCurrencyRateProviderCoinGecko(models.Model): | ||
_inherit = "res.currency.rate.provider" | ||
|
||
service = fields.Selection( | ||
selection_add=[("CoinGecko", "CoinGecko")], | ||
ondelete={"CoinGecko": "set default"}, | ||
) | ||
|
||
def _get_supported_currencies(self): | ||
self.ensure_one() | ||
if self.service != "CoinGecko": | ||
return super()._get_supported_currencies() | ||
# List of cryptocurrencies based on configured provider mappings | ||
supported_currencies = ( | ||
self.env["res.currency.rate.provider.mapping"] | ||
.search([("provider_id", "=", self.id)]) | ||
.mapped("currency_id.name") | ||
) | ||
return supported_currencies | ||
|
||
def _obtain_rates(self, base_currency, currencies, date_from, date_to): | ||
self.ensure_one() | ||
if self.service != "CoinGecko": | ||
return super()._obtain_rates(base_currency, currencies, date_from, date_to) | ||
if date_from < date.today(): | ||
return self._get_historical_rate_from_coingecko( | ||
date_from, date_to, base_currency | ||
) | ||
else: | ||
return self._get_latest_rate_from_coingecko(base_currency) | ||
|
||
def _get_latest_rate_from_coingecko(self, base_currency): | ||
"""Get all the exchange rates for today""" | ||
api = CoinGeckoAPI() | ||
today = date.today() | ||
data = {today: {}} | ||
for ( | ||
currency | ||
) in self.currency_ids.res_currency_rate_provider_mapping_ids.filtered( | ||
lambda l: l.provider_id == self | ||
): | ||
try: | ||
coin_data = api.coin_historical_on_date( | ||
currency.provider_reference, today.strftime("%m-%d-%Y") | ||
) | ||
except Exception as e: | ||
_logger.warning( | ||
'Currency Rate Provider "%(name)s" failed to obtain for %(currency)s currency' | ||
% { | ||
"name": self.name, | ||
"currency": currency.currency_id.name, | ||
}, | ||
exc_info=True, | ||
) | ||
self.message_post( | ||
subject=_("Currency Rate Provider Failure"), | ||
body=_( | ||
'Currency Rate Provider "%(name)s" failed to obtain data(check the rate provider mapping on the currency) :\n%(error)s' | ||
) | ||
% { | ||
"name": self.name, | ||
"currency": currency.currency_id.name, | ||
"error": str(e) if e else _("N/A"), | ||
}, | ||
) | ||
continue | ||
rate = ( | ||
coin_data.get("market_data") | ||
.get("current_price") | ||
.get(base_currency.lower(), 0) | ||
) | ||
if rate: | ||
data[today].update({currency.currency_id.name: 1 / rate}) | ||
return data | ||
|
||
def _get_historical_rate_from_coingecko(self, date_from, date_to, base_currency): | ||
"""Get all the exchange rates from 'date_from' to 'date_to'""" | ||
api = CoinGeckoAPI() | ||
content = {} | ||
current_date = date_from | ||
while current_date <= date_to: | ||
content[current_date] = {} | ||
for ( | ||
currency | ||
) in self.currency_ids.res_currency_rate_provider_mapping_ids.filtered( | ||
lambda l: l.provider_id == self | ||
): | ||
try: | ||
coin_data = api.coin_historical_on_date( | ||
currency.provider_reference, current_date.strftime("%m-%d-%Y") | ||
) | ||
except Exception as e: | ||
_logger.warning( | ||
'Currency Rate Provider "%(name)s" failed to obtain for %(currency)s currency' | ||
% { | ||
"name": self.name, | ||
"currency": currency.currency_id.name, | ||
}, | ||
exc_info=True, | ||
) | ||
self.message_post( | ||
subject=_("Currency Rate Provider Failure"), | ||
body=_( | ||
'Currency Rate Provider "%(name)s" failed to obtain data(check the rate provider mapping on the currency) :\n%(error)s' | ||
) | ||
% { | ||
"name": self.name, | ||
"currency": currency.currency_id.name, | ||
"error": str(e) if e else _("N/A"), | ||
}, | ||
) | ||
continue | ||
rate = ( | ||
coin_data.get("market_data") | ||
.get("current_price") | ||
.get(base_currency.lower(), 0) | ||
) | ||
if rate: | ||
content[current_date].update({currency.currency_id.name: 1 / rate}) | ||
current_date += timedelta(days=1) | ||
return content |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from . import test_currency_rate_update_coingecko |
82 changes: 82 additions & 0 deletions
82
currency_rate_update_coingecko/tests/test_currency_rate_update_coingecko.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Copyright 2024 Onestein | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from dateutil.relativedelta import relativedelta | ||
|
||
from odoo import fields | ||
from odoo.tests import common, tagged | ||
from odoo.tools import mute_logger | ||
|
||
|
||
@tagged("post_install", "-at_install") | ||
class TestResCurrencyRateProviderCoinGecko(common.TransactionCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
super().setUpClass() | ||
|
||
cls.Company = cls.env["res.company"] | ||
cls.CurrencyRate = cls.env["res.currency.rate"] | ||
cls.Currency = cls.env["res.currency"] | ||
cls.CurrencyRateProvider = cls.env["res.currency.rate.provider"] | ||
cls.CurrencyRateProviderMapping = cls.env["res.currency.rate.provider.mapping"] | ||
|
||
cls.today = fields.Date.today() | ||
cls.eur_currency = cls.env.ref("base.EUR") | ||
cls.company = cls.Company.create( | ||
{"name": "Test company", "currency_id": cls.eur_currency.id} | ||
) | ||
cls.lnk_currency = cls.Currency.create({"name": "LINK", "symbol": "LNK"}) | ||
cls.coingecko_provider = cls.CurrencyRateProvider.search([("service","=","CoinGecko")],limit =1) | ||
cls.coingecko_provider_mapping = cls.CurrencyRateProviderMapping.create( | ||
{ | ||
"currency_id": cls.lnk_currency.id, | ||
"provider_id": cls.coingecko_provider.id, | ||
"provider_reference": "chainlink", | ||
} | ||
) | ||
cls.coingecko_provider.write( | ||
{ | ||
"currency_ids": [ | ||
(4, cls.lnk_currency.id), | ||
], | ||
} | ||
) | ||
cls.env.user.company_ids += cls.company | ||
cls.env.company = cls.company | ||
cls.CurrencyRate.search([]).unlink() | ||
|
||
def test_supported_currencies_CoinGecko(self): | ||
self.coingecko_provider._get_supported_currencies() | ||
|
||
def test_cron(self): | ||
self.coingecko_provider._scheduled_update() | ||
rates = self.CurrencyRate.search([]) | ||
self.assertTrue(rates) | ||
self.assertEqual(rates.currency_id, self.lnk_currency) | ||
self.CurrencyRate.search([("company_id", "=", self.company.id)]).unlink() | ||
|
||
def test_wizard(self): | ||
wizard = ( | ||
self.env["res.currency.rate.update.wizard"] | ||
.with_context( | ||
default_provider_ids=[(6, False, self.coingecko_provider.ids)] | ||
) | ||
.create({}) | ||
) | ||
wizard.action_update() | ||
rates = self.CurrencyRate.search([]) | ||
self.assertTrue(rates) | ||
self.assertEqual(rates.currency_id, self.lnk_currency) | ||
self.CurrencyRate.search([("company_id", "=", self.company.id)]).unlink() | ||
|
||
@mute_logger( | ||
"odoo.addons.currency_rate_update_coingecko.models.res_currency_rate_provider_CoinGecko" | ||
) | ||
def test_error_CoinGecko(self): | ||
self.coingecko_provider_mapping.write({"provider_reference": "test"}) | ||
self.coingecko_provider._update(self.today, self.today) | ||
rates = self.CurrencyRate.search([]) | ||
self.assertEqual(len(rates), 0) | ||
self.coingecko_provider._update(self.today - relativedelta(days=2), self.today) | ||
rates = self.CurrencyRate.search([]) | ||
self.assertEqual(len(rates), 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright 2024 Onestein | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
{ | ||
"name": "Currency Rate Update Mapping", | ||
"version": "16.0.1.0.0", | ||
"author": "Onestein BV", | ||
"website": "https://www.onestein.eu", | ||
"license": "AGPL-3", | ||
"category": "Financial Management/Configuration", | ||
"summary": "Allows to add mappings for currency rate providers", | ||
"depends": ["currency_rate_update"], | ||
"data": [ | ||
"security/ir.model.access.csv", | ||
"views/res_currency.xml", | ||
], | ||
"installable": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
|
||
from . import res_currency | ||
from . import res_currency_rate_provider_mapping |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Copyright 2024 Onestein | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
|
||
from odoo import fields, models | ||
|
||
|
||
class ResCurrency(models.Model): | ||
_inherit = "res.currency" | ||
|
||
res_currency_rate_provider_mapping_ids = fields.One2many( | ||
comodel_name="res.currency.rate.provider.mapping", | ||
inverse_name="currency_id", | ||
string="Currency Rate Provider Mappings", | ||
copy=False, | ||
help="Currency mapping with the rate provider for updating rates", | ||
) |
22 changes: 22 additions & 0 deletions
22
currency_rate_update_mapping/models/res_currency_rate_provider_mapping.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright 2024 Onestein | ||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). | ||
from odoo import fields, models | ||
|
||
|
||
class ResCurrencyRateProviderMapping(models.Model): | ||
_name = "res.currency.rate.provider.mapping" | ||
_description = "Currency Rate Provider Mapping" | ||
|
||
currency_id = fields.Many2one( | ||
string="Currency", | ||
comodel_name="res.currency", | ||
) | ||
provider_id = fields.Many2one( | ||
string="Provider", | ||
comodel_name="res.currency.rate.provider", | ||
ondelete="restrict", | ||
) | ||
provider_reference = fields.Char( | ||
required=True, | ||
help="Defines the reference to be used when fetching rates from the provider", | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink | ||
access_res_currency_rate_update_mapping_service_admin,res.currency.rate.provider.mapping,model_res_currency_rate_provider_mapping,base.group_system,1,1,1,1 | ||
access_res_currency_rate_update_mapping_service_manager,res.currency.rate.provider.mapping,model_res_currency_rate_provider_mapping,account.group_account_manager,1,0,0,0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<?xml version="1.0" encoding="utf-8" ?> | ||
<!-- | ||
Copyright 2024 Onestein | ||
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). | ||
--> | ||
<odoo> | ||
<record model="ir.ui.view" id="view_currency_form"> | ||
<field name="name">res.currency.form</field> | ||
<field name="model">res.currency</field> | ||
<field name="inherit_id" ref="base.view_currency_form"/> | ||
<field name="arch" type="xml"> | ||
<notebook position="inside"> | ||
<page string="Rate Provider Mappings" name="rate_provider_mappings"> | ||
<field name="res_currency_rate_provider_mapping_ids" widget="one2many"> | ||
<tree editable="top" limit="25"> | ||
<field name="provider_id"/> | ||
<field name="provider_reference"/> | ||
</tree> | ||
</field> | ||
</page> | ||
</notebook> | ||
|
||
</field> | ||
</record> | ||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,3 +29,4 @@ xlrd | |
python-slugify | ||
vcrpy | ||
dnspython==2.6.1 | ||
pycgapi |