This file is indexed.

/usr/lib/python3/dist-packages/trytond/modules/currency/currency.py is in tryton-modules-currency 4.6.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# 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 datetime
import json

from decimal import Decimal, ROUND_HALF_EVEN
from trytond.model import ModelView, ModelSQL, fields, Unique, Check
from trytond.tools import datetime_strftime
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond.rpc import RPC

__all__ = ['Currency', 'Rate']


class Currency(ModelSQL, ModelView):
    'Currency'
    __name__ = 'currency.currency'
    name = fields.Char('Name', required=True, translate=True)
    symbol = fields.Char('Symbol', size=10, required=True)
    code = fields.Char('Code', size=3, required=True)
    numeric_code = fields.Char('Numeric Code', size=3)
    rate = fields.Function(fields.Numeric('Current rate', digits=(12, 6)),
        'get_rate')
    rates = fields.One2Many('currency.currency.rate', 'currency', 'Rates')
    rounding = fields.Numeric('Rounding factor', digits=(12, 6), required=True)
    digits = fields.Integer('Display Digits', required=True)
    active = fields.Boolean('Active')

    # monetary formatting
    mon_grouping = fields.Char('Grouping', required=True)
    mon_decimal_point = fields.Char('Decimal Separator', required=True)
    mon_thousands_sep = fields.Char('Thousands Separator')
    p_sign_posn = fields.Integer('Positive Sign Position', required=True)
    n_sign_posn = fields.Integer('Negative Sign Position', required=True)
    positive_sign = fields.Char('Positive Sign')
    negative_sign = fields.Char('Negative Sign')
    p_cs_precedes = fields.Boolean('Positive Currency Symbol Precedes')
    n_cs_precedes = fields.Boolean('Negative Currency Symbol Precedes')
    p_sep_by_space = fields.Boolean('Positive Separate by Space')
    n_sep_by_space = fields.Boolean('Negative Separate by Space')

    @classmethod
    def __setup__(cls):
        super(Currency, cls).__setup__()
        cls._order.insert(0, ('code', 'ASC'))
        cls._error_messages.update({
                'no_rate': ('No rate found for currency "%(currency)s" on '
                    '"%(date)s"'),
                'invalid_mon_grouping': ('Invalid grouping "%(grouping)s" on '
                    'currency "%(currency)s".'),
                })
        cls.__rpc__.update({
                'compute': RPC(),
                })

    @staticmethod
    def default_active():
        return True

    @staticmethod
    def default_rounding():
        return Decimal('0.01')

    @staticmethod
    def default_digits():
        return 2

    @staticmethod
    def default_mon_grouping():
        return '[]'

    @staticmethod
    def default_mon_thousands_sep():
        return ','

    @staticmethod
    def default_mon_decimal_point():
        return '.'

    @staticmethod
    def default_p_sign_posn():
        return 1

    @staticmethod
    def default_n_sign_posn():
        return 1

    @staticmethod
    def default_negative_sign():
        return '-'

    @staticmethod
    def default_positive_sign():
        return ''

    @staticmethod
    def default_p_cs_precedes():
        return True

    @staticmethod
    def default_n_cs_precedes():
        return True

    @staticmethod
    def default_p_sep_by_space():
        return False

    @staticmethod
    def default_n_sep_by_space():
        return False

    @classmethod
    def validate(cls, currencies):
        super(Currency, cls).validate(currencies)
        for currency in currencies:
            currency.check_mon_grouping()

    def check_mon_grouping(self):
        '''
        Check if mon_grouping is list of numbers
        '''
        try:
            grouping = json.loads(self.mon_grouping)
            for i in grouping:
                if not isinstance(i, int):
                    raise ValueError
        except Exception:
            self.raise_user_error('invalid_mon_grouping', {
                    'grouping': self.mon_grouping,
                    'currency': self.rec_name,
                    })

    @classmethod
    def check_xml_record(cls, records, values):
        return True

    @classmethod
    def search_global(cls, text):
        for record, rec_name, icon in super(Currency, cls).search_global(text):
            icon = icon or 'tryton-currency'
            yield record, rec_name, icon

    @classmethod
    def search_rec_name(cls, name, clause):
        currencies = None
        field = None
        for field in ('code', 'numeric_code'):
            currencies = cls.search([(field,) + tuple(clause[1:])], limit=1)
            if currencies:
                break
        if currencies:
            return [(field,) + tuple(clause[1:])]
        return [(cls._rec_name,) + tuple(clause[1:])]

    @fields.depends('rates')
    def on_change_with_rate(self):
        now = datetime.date.today()
        closer = datetime.date.min
        res = Decimal('0.0')
        for rate in self.rates or []:
            date = getattr(rate, 'date', None) or now
            if date <= now and date > closer:
                res = rate.rate
                closer = date
        return res

    @staticmethod
    def get_rate(currencies, name):
        '''
        Return the rate at the date from the context or the current date
        '''
        Rate = Pool().get('currency.currency.rate')
        Date = Pool().get('ir.date')

        res = {}
        date = Transaction().context.get('date', Date.today())
        for currency in currencies:
            rates = Rate.search([
                    ('currency', '=', currency.id),
                    ('date', '<=', date),
                    ], limit=1, order=[('date', 'DESC')])
            if rates:
                res[currency.id] = rates[0].id
            else:
                res[currency.id] = 0
        rate_ids = [x for x in list(res.values()) if x]
        rates = Rate.browse(rate_ids)
        id2rate = {}
        for rate in rates:
            id2rate[rate.id] = rate
        for currency_id in list(res.keys()):
            if res[currency_id]:
                res[currency_id] = id2rate[res[currency_id]].rate
        return res

    def round(self, amount, rounding=ROUND_HALF_EVEN):
        'Round the amount depending of the currency'
        return (amount / self.rounding).quantize(Decimal('1.'),
                rounding=rounding) * self.rounding

    def is_zero(self, amount):
        'Return True if the amount can be considered as zero for the currency'
        return abs(self.round(amount)) < self.rounding

    @classmethod
    def compute(cls, from_currency, amount, to_currency, round=True):
        '''
        Take a currency and an amount
        Return the amount to the new currency
        Use the rate of the date of the context or the current date
        '''
        Date = Pool().get('ir.date')
        Lang = Pool().get('ir.lang')
        from_currency = cls(from_currency.id)
        to_currency = cls(to_currency.id)

        if to_currency == from_currency:
            if round:
                return to_currency.round(amount)
            else:
                return amount
        if (not from_currency.rate) or (not to_currency.rate):
            date = Transaction().context.get('date', Date.today())
            if not from_currency.rate:
                name = from_currency.name
            else:
                name = to_currency.name

            languages = Lang.search([
                    ('code', '=', Transaction().language),
                    ])
            cls.raise_user_error('no_rate', {
                    'currency': name,
                    'date': datetime_strftime(date, str(languages[0].date))
                    })
        if round:
            return to_currency.round(
                amount * to_currency.rate / from_currency.rate)
        else:
            return amount * to_currency.rate / from_currency.rate


class Rate(ModelSQL, ModelView):
    'Rate'
    __name__ = 'currency.currency.rate'
    date = fields.Date('Date', required=True, select=True)
    rate = fields.Numeric('Rate', digits=(12, 6), required=1)
    currency = fields.Many2One('currency.currency', 'Currency',
            ondelete='CASCADE',)

    @classmethod
    def __setup__(cls):
        super(Rate, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('date_currency_uniq', Unique(t, t.date, t.currency),
                'A currency can only have one rate by date.'),
            ('check_currency_rate', Check(t, t.rate >= 0),
                'The currency rate must greater than or equal to 0'),
            ]
        cls._order.insert(0, ('date', 'DESC'))

    @staticmethod
    def default_date():
        Date = Pool().get('ir.date')
        return Date.today()

    @classmethod
    def check_xml_record(self, records, values):
        return True

    def get_rec_name(self, name):
        return str(self.date)