investment/import_wiz.py
Frederik Jaeckel 0275ee09e9 formatting
2023-06-07 18:44:53 +02:00

210 lines
6.5 KiB
Python

# -*- coding: utf-8 -*-
# This file is part of the investment-module from m-ds.de for Tryton.
# The COPYRIGHT file at the top level of this repository contains the
# full copyright notices and license terms.
from io import StringIO
from datetime import datetime, date
from decimal import Decimal
import csv
from trytond.pool import Pool
from trytond.model import ModelView, fields
from trytond.wizard import Wizard, StateTransition, StateView, Button
from trytond.transaction import Transaction
from trytond.exceptions import UserError
from trytond.i18n import gettext
sel_dec_divider = [
(',', ','),
('.', '.'),
]
sel_date_fmt = [
('%d.%m.%Y', 'dd.mm.yyyy'),
('%Y-%m-%d', 'yyyy-mm-dd'),
('%m/%d/%Y', 'mm/dd/yyyy'),
]
sel_field_delimiter = [
(';', ';'),
(',', ','),
]
class ImportWizardStart(ModelView):
'Import CSV-File'
__name__ = 'investment.imp_wiz.start'
asset = fields.Many2One(
string='Asset', readonly=True, model_name='investment.asset')
file_ = fields.Binary(string="CSV-File", required=True)
dec_divider = fields.Selection(
string='Decimal divider', required=True, selection=sel_dec_divider)
date_fmt = fields.Selection(
string='Date format', required=True, selection=sel_date_fmt)
field_delimiter = fields.Selection(
string='Field delimiter', required=True, selection=sel_field_delimiter)
# end ImportWizardStart
class ImportWizard(Wizard):
'Import CSV-File'
__name__ = 'investment.imp_wiz'
start_state = 'start'
start = StateView(
model_name='investment.imp_wiz.start',
view='investment.imp_wiz_start_form',
buttons=[
Button(string='Cancel', state='end', icon='tryton-cancel'),
Button(
string='Import File', state='importf',
icon='tryton-import', default=True),
])
importf = StateTransition()
def default_start(self, fields):
""" show asset
"""
context = Transaction().context
values = {
'dec_divider': ',',
'date_fmt': '%d.%m.%Y',
'field_delimiter': ';',
}
values['asset'] = context.get('active_id', None)
return values
def transition_importf(self):
""" read file, import
"""
pool = Pool()
ImportWiz = pool.get('investment.imp_wiz', type='wizard')
if self.start.file_ is not None:
(lines, max_date, min_date) = ImportWiz.read_csv_file(
self.start.file_.decode('utf8'),
dec_divider=self.start.dec_divider,
date_fmt=self.start.date_fmt,
delimiter=self.start.field_delimiter)
if len(lines) > 0:
ImportWiz.upload_rates(
self.start.asset,
lines, min_date, max_date)
return 'end'
@classmethod
def upload_rates(cls, asset, rates_list, min_date, max_date):
""" upload new rates to asset
"""
Rate = Pool().get('investment.rate')
# get rate in date-range
rates = Rate.search([
('asset.id', '=', asset.id),
('date', '>=', min_date),
('date', '<=', max_date),
])
existing_dates = [x.date for x in rates]
done_dates = []
to_create = []
for rate in rates_list:
if rate['date'] in existing_dates:
continue
if rate['date'] in done_dates:
continue
to_create.append({
'asset': asset.id,
'date': rate['date'],
'rate': rate['rate'],
})
done_dates.append(rate['date'])
if len(to_create) > 0:
Rate.create(to_create)
@classmethod
def read_csv_file(cls, file_content, dec_divider, date_fmt, delimiter):
""" read file-content from csv
"""
result = []
del_chars = ['.', ',']
del_chars.remove(dec_divider)
min_date = None
max_date = None
min_rate = None
max_rate = None
with StringIO(file_content) as fhdl:
csv_lines = csv.DictReader(
fhdl,
fieldnames=['date', 'rate'],
dialect='excel',
delimiter=delimiter)
for line in csv_lines:
# skip first line
if line.get('date', '') == 'date':
continue
try:
date_val = datetime.strptime(
line.get('date', None).strip(), date_fmt).date()
except Exception:
raise UserError(gettext(
'investment.msg_import_err_date',
datefmt=date_fmt,
colnr='1',
))
try:
rate_val = line.get('rate', None).replace(
del_chars[0], '').strip()
rate_val = Decimal(rate_val.replace(dec_divider, '.'))
except Exception:
raise UserError(gettext(
'investment.msg_import_err_date',
datefmt='dd%sdd' % dec_divider,
colnr='2'))
if isinstance(date_val, date) and isinstance(rate_val, Decimal):
result.append({'date': date_val, 'rate': rate_val})
# date range
if max_date is None:
max_date = date_val
else:
if max_date < date_val:
max_date = date_val
if min_date is None:
min_date = date_val
else:
if min_date > date_val:
min_date = date_val
# rate range
if max_rate is None:
max_rate = rate_val
else:
if max_rate < rate_val:
max_rate = rate_val
if min_rate is None:
min_rate = rate_val
else:
if min_rate > rate_val:
min_rate = rate_val
else:
raise UserError(gettext(
'investment.msg_err_unknown_content',
linetxt=line))
return (result, max_date, min_date)
# end ImportWizard