first commit

This commit is contained in:
root
2026-03-14 09:42:12 +00:00
commit 0adbd20c2c
10991 changed files with 1646955 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,118 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from decimal import Decimal
from lxml import objectify
from zeep import Client, Transport
from zeep.exceptions import Error
import trytond.config as config
from trytond.cache import Cache
from trytond.i18n import gettext
from trytond.model import fields
from trytond.modules.currency.currency import CronFetchError
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval, If
from .exceptions import RSCredentialWarning
URL = (
'https://webservices.nbs.rs/CommunicationOfficeService1_0/'
'ExchangeRateXmlService.asmx?WSDL')
def get_client(username, password, license_id):
timeout = config.getfloat('currency_rs', 'requests_timeout', default=300)
client = Client(URL, transport=Transport(operation_timeout=timeout))
client.set_default_soapheaders({
'AuthenticationHeader': {
'UserName': username,
'Password': password,
'LicenceID': license_id,
},
})
return client
class Cron(metaclass=PoolMeta):
__name__ = 'currency.cron'
_states = {
'required': Eval('source') == 'nbs_rs',
'invisible': Eval('source') != 'nbs_rs',
}
rs_username = fields.Char("Username", states=_states, strip=False)
rs_password = fields.Char("Password", states=_states, strip=False)
rs_license_id = fields.Char("License ID", states=_states, strip=False)
rs_list_type = fields.Selection(
'get_rs_list_types', "List Type", states=_states)
_rs_list_types = Cache(__name__ + '.get_rs_list_types', context=False)
del _states
@classmethod
def __setup__(cls):
super().__setup__()
cls.source.selection.append(('nbs_rs', "Serbian National Bank"))
cls.currency.domain = [
cls.currency.domain or [],
If(Eval('source') == 'nbs_rs',
('code', '=', 'RSD'),
()),
]
@fields.depends('rs_username', 'rs_password', 'rs_license_id')
def _rs_client(self):
return get_client(
self.rs_username, self.rs_password, self.rs_license_id)
@fields.depends('rs_list_type', methods=['_rs_client'])
def get_rs_list_types(self):
types = self._rs_list_types.get(None)
if types is not None:
return types
try:
client = self._rs_client()
response = client.service.GetExchangeRateListType()
except Error:
return [(self.rs_list_type, self.rs_list_type or "")]
types = []
data = objectify.fromstring(response)
for list_type in data.iterchildren():
types.append(
(str(list_type.ExchangeRateListTypeID), str(list_type.Name)))
self._rs_list_types.set(None, types)
return types
def fetch_nbs_rs(self, date):
try:
client = self._rs_client()
response = client.service.GetExchangeRateByDate(
date.strftime('%Y%m%d'), self.rs_list_type)
except Error as e:
raise CronFetchError() from e
data = objectify.fromstring(response)
return {
r.CurrencyCodeAlfaChar: (
Decimal(r.Unit.text) / Decimal(r.MiddleRate.text))
for r in data.iterchildren()
if r.Date == date.strftime('%d.%m.%Y')}
@classmethod
def check_modification(cls, mode, crons, values=None, external=False):
pool = Pool()
Warning = pool.get('res.user.warning')
super().check_modification(
mode, crons, values=values, external=external)
if (mode == 'write'
and external
and values.keys() & {
'rs_username', 'rs_password', 'rs_license_id'}):
warning_name = Warning.format('rs_credential', crons)
if Warning.check(warning_name):
raise RSCredentialWarning(
warning_name,
gettext('currency_rs.msg_rs_credential_modified'))

View File

@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<tryton>
<data>
<record model="ir.ui.view" id="cron_view_form">
<field name="model">currency.cron</field>
<field name="inherit" ref="currency.cron_view_form"/>
<field name="name">cron_form</field>
</record>
<record model="ir.model.field.access" id="access_cron_password">
<field name="model">currency.cron</field>
<field name="field">rs_password</field>
<field name="perm_read" eval="False"/>
<field name="perm_write" eval="False"/>
<field name="perm_create" eval="False"/>
<field name="perm_delete" eval="False"/>
</record>
<record model="ir.model.field.access" id="access_cron_password_currency_admin">
<field name="model">currency.cron</field>
<field name="field">rs_password</field>
<field name="group" ref="currency.group_currency_admin"/>
<field name="perm_read" eval="True"/>
<field name="perm_write" eval="True"/>
<field name="perm_create" eval="True"/>
<field name="perm_delete" eval="True"/>
</record>
</data>
</tryton>

View File

@@ -0,0 +1,8 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.exceptions import UserWarning
class RSCredentialWarning(UserWarning):
pass

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "ID de llicència"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Tipus de llistat"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Contrasenya"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Nom d'usuari"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banc Nacional de Sèrbia"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "Lizenz ID"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Listentyp"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Passwort"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Benutzername"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Serbische Nationalbank"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "ID de licencia"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Tipo de listado"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Contraseña"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Nombre de usuario"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banco Nacional de Serbia"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "ID de licence"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Type de liste"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Mot de passe"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Nom d'utilisateur"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banque nationale Serbe"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "ID licenza"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Tipo di lista"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Password"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Nome utente"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banca nazionale Serba"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "Licentie-ID"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Lijsttype"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Paswoord"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "gebruikersnaam"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Servische Nationale Bank"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "ID Licença"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Tipo de Lista"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Senha"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Nome de Usuário"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banco Nacional Sérvio"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr "Licența ID"
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr "Tip Lista"
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr "Parola"
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr "Utilizator"
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr "Banca Naționala al Serbiei"

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,23 @@
#
msgid ""
msgstr "Content-Type: text/plain; charset=utf-8\n"
msgctxt "field:currency.cron,rs_license_id:"
msgid "License ID"
msgstr ""
msgctxt "field:currency.cron,rs_list_type:"
msgid "List Type"
msgstr ""
msgctxt "field:currency.cron,rs_password:"
msgid "Password"
msgstr ""
msgctxt "field:currency.cron,rs_username:"
msgid "Username"
msgstr ""
msgctxt "selection:currency.cron,source:"
msgid "Serbian National Bank"
msgstr ""

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,61 @@
====================
Currency RS Scenario
====================
Imports::
>>> import datetime as dt
>>> import os
>>> from proteus import Model
>>> from trytond.tests.tools import activate_modules
>>> today = dt.date.today()
>>> previous_week = today - dt.timedelta(days=7)
>>> before_previous_week = previous_week - dt.timedelta(days=1)
Activate modules::
>>> config = activate_modules('currency_rs')
Import models::
>>> Currency = Model.get('currency.currency')
>>> Cron = Model.get('currency.cron')
Create some currencies::
>>> eur = Currency(name="Euro", code='EUR', symbol="€")
>>> eur.save()
>>> rsd = Currency(name="Serbian Dinar", code='RSD', symbol="din.")
>>> rsd.save()
Setup cron::
>>> cron = Cron()
>>> cron.source = 'nbs_rs'
>>> cron.rs_username = os.getenv('NBS_RS_USERNAME')
>>> cron.rs_password = os.getenv('NBS_RS_PASSWORD')
>>> cron.rs_license_id = os.getenv('NBS_RS_LICENSE_ID')
>>> cron.rs_list_type = '3'
>>> cron.frequency = 'daily'
>>> cron.day = None
>>> cron.currency = rsd
>>> cron.currencies.append(Currency(eur.id))
>>> cron.last_update = before_previous_week
>>> cron.save()
Run update::
>>> cron.click('run')
>>> cron.last_update >= previous_week
True
>>> rsd.reload()
>>> rate = [r for r in rsd.rates if r.date < today][0]
>>> rate.rate
Decimal('1.000000')
>>> eur.reload()
>>> rate = [r for r in eur.rates if r.date < today][0]
>>> bool(rate.rate)
True

View File

@@ -0,0 +1,12 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.tests.test_tryton import ModuleTestCase
class CurrencyRsTestCase(ModuleTestCase):
'Test Currency Rs module'
module = 'currency_rs'
del ModuleTestCase

View File

@@ -0,0 +1,15 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
from trytond.tests.test_tryton import TEST_NETWORK, load_doc_tests
def load_tests(*args, **kwargs):
if (not TEST_NETWORK
or not (os.getenv('NBS_RS_USERNAME')
and os.getenv('NBS_RS_PASSWORD')
and os.getenv('NBS_RS_LICENSE_ID'))):
kwargs.setdefault('skips', set()).add('scenario_currency_rs.rst')
return load_doc_tests(__name__, __file__, *args, **kwargs)

View File

@@ -0,0 +1,11 @@
[tryton]
version=7.8.0
depends:
currency
ir
xml:
currency.xml
[register]
model:
currency.Cron

View File

@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<data>
<xpath expr="//group[@id='frequency']" position="after">
<label name="rs_username"/>
<field name="rs_username"/>
<label name="rs_password"/>
<field name="rs_password" widget="password"/>
<label name="rs_license_id"/>
<field name="rs_license_id"/>
<label name="rs_list_type"/>
<field name="rs_list_type"/>
</xpath>
</data>