Files
tryton/customs.py
T
Cédric Krier b1a6a5869b Initial commit
issue4796
review12171002
2015-08-10 10:40:47 +02:00

204 lines
7.0 KiB
Python

# 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
from decimal import Decimal
from sql import Null
from trytond.model import ModelSQL, ModelView, MatchMixin, fields
from trytond.pyson import Eval, If, Bool
from trytond.pool import Pool
from trytond.modules.product import price_digits
__all__ = ['TariffCode', 'DutyRate']
# Use 2 chars numbering to allow string comparison
MONTHS = [
(None, ''),
('01', 'January'),
('02', 'February'),
('03', 'March'),
('04', 'April'),
('05', 'May'),
('06', 'June'),
('07', 'July'),
('08', 'August'),
('09', 'September'),
('10', 'October'),
('11', 'November'),
('12', 'December'),
]
class TariffCode(ModelSQL, ModelView, MatchMixin):
'Tariff Code'
__name__ = 'customs.tariff.code'
_rec_name = 'code'
code = fields.Char('Code', required=True,
help='The code from Harmonized System of Nomenclature')
description = fields.Char('Description', translate=True)
active = fields.Boolean('Active', select=True)
country = fields.Many2One('country.country', 'Country')
# TODO country group
start_month = fields.Selection(MONTHS, 'Start Month', sort=False,
states={
'required': Eval('end_month') | Eval('start_day'),
},
depends=['end_month', 'start_day'])
start_day = fields.Integer('Start Day',
domain=['OR',
('start_day', '<=', If(Eval('start_month').in_(
['01', '03', '05', '07', '08', '10', '12']), 31,
If(Eval('start_month') == '02', 29, 30))),
('start_day', '=', None),
],
states={
'required': Bool(Eval('start_month')),
},
depends=['start_month'])
end_month = fields.Selection(MONTHS, 'End Month', sort=False,
states={
'required': Eval('start_month') | Eval('end_day'),
},
depends=['start_month', 'end_day'])
end_day = fields.Integer('End Day',
domain=['OR',
('end_day', '<=', If(Eval('end_month').in_(
['01', '03', '05', '07', '08', '10', '12']), 31,
If(Eval('end_month') == '02', 29, 30))),
('end_day', '=', None),
],
states={
'required': Bool(Eval('end_month')),
},
depends=['end_month'])
duty_rates = fields.One2Many('customs.duty.rate', 'tariff_code',
'Duty Rates')
@classmethod
def __setup__(cls):
super(TariffCode, cls).__setup__()
cls._order.insert(0, ('code', 'ASC'))
@classmethod
def default_active(cls):
return True
def match(self, pattern):
if 'date' in pattern:
pattern = pattern.copy()
date = pattern.pop('date')
if self.start_month and self.end_month:
start = (int(self.start_month), self.start_day)
end = (int(self.end_month), self.end_day)
date = (date.month, date.day)
if start <= end:
if not (start <= date <= end):
return False
else:
if end <= date <= start:
return False
return super(TariffCode, self).match(pattern)
def get_duty_rate(self, pattern):
for rate in self.duty_rates:
if rate.match(pattern):
return rate
class DutyRate(ModelSQL, ModelView, MatchMixin):
'Duty Rate'
__name__ = 'customs.duty.rate'
tariff_code = fields.Many2One('customs.tariff.code', 'Tariff Code',
required=True, select=True)
country = fields.Many2One('country.country', 'Country')
# TODO country group
type = fields.Selection([
('import', 'Import'),
('export', 'Export'),
], 'Type')
start_date = fields.Date('Start Date',
domain=['OR',
('start_date', '<=', If(Bool(Eval('end_date')),
Eval('end_date', datetime.date.max), datetime.date.max)),
('start_date', '=', None),
],
depends=['end_date'])
end_date = fields.Date('End Date',
domain=['OR',
('end_date', '>=', If(Bool(Eval('start_date')),
Eval('start_date', datetime.date.min), datetime.date.min)),
('end_date', '=', None),
],
depends=['start_date'])
computation_type = fields.Selection([
('amount', 'Amount'),
('quantity', 'Quantity'),
], 'Computation Type')
amount = fields.Numeric('Amount', digits=price_digits,
states={
'required': Eval('computation_type').in_(['amount', 'quantity']),
'invisible': ~Eval('computation_type').in_(['amount', 'quantity']),
},
depends=['computation_type'])
currency = fields.Many2One('currency.currency', 'Currency',
states={
'required': Eval('computation_type').in_(['amount', 'quantity']),
'invisible': ~Eval('computation_type').in_(['amount', 'quantity']),
},
depends=['computation_type'])
uom = fields.Many2One('product.uom', 'Uom',
states={
'required': Eval('computation_type') == 'quantity',
'invisible': Eval('computation_type') != 'quantity',
},
depends=['computation_type'])
@classmethod
def __setup__(cls):
super(DutyRate, cls).__setup__()
cls._order.insert(0, ('start_date', 'ASC'))
cls._order.insert(0, ('end_date', 'ASC'))
@classmethod
def default_type(cls):
return 'import'
@staticmethod
def order_start_date(tables):
table, _ = tables[None]
return [table.start_date == Null, table.start_date]
@staticmethod
def order_end_date(tables):
table, _ = tables[None]
return [table.end_date == Null, table.end_date]
def match(self, pattern):
if 'date' in pattern:
pattern = pattern.copy()
start = self.start_date or datetime.date.min
end = self.end_date or datetime.date.max
if not (start <= pattern.pop('date') <= end):
return False
return super(DutyRate, self).match(pattern)
def compute(self, currency, quantity, uom, **kwargs):
return getattr(self, 'compute_%s' % self.computation_type)(
currency, quantity, uom, **kwargs)
def compute_amount(self, currency, quantity, uom, **kwargs):
pool = Pool()
Currency = pool.get('currency.currency')
return Currency.compute(self.currency, self.amount, currency)
def compute_quantity(self, currency, quantity, uom, **kwargs):
pool = Pool()
Currency = pool.get('currency.currency')
Uom = pool.get('product.uom')
amount = Uom.compute_price(self.uom, self.amount, uom)
amount *= Decimal(str(quantity))
return Currency.compute(self.currency, amount, currency)