trytond-sale_per_country_re.../sale.py

250 lines
9.0 KiB
Python

# The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import itertools
from functools import partial
from trytond.model import ModelView, fields, ModelSQL
from trytond.pool import PoolMeta, Pool
from trytond.pyson import Eval
from trytond.report import Report
from trytond.transaction import Transaction
from trytond.wizard import StateReport
from trytond.wizard import Wizard, StateTransition, StateView, Button
from trytond.tools.multivalue import migrate_property
from trytond.modules.company.model import CompanyValueMixin
# XXX fix: https://genshi.edgewall.org/ticket/582
from genshi.template.astutil import ASTCodeGenerator, ASTTransformer
if not hasattr(ASTCodeGenerator, 'visit_NameConstant'):
def visit_NameConstant(self, node):
if node.value is None:
self._write('None')
elif node.value is True:
self._write('True')
elif node.value is False:
self._write('False')
else:
raise Exception("Unknown NameConstant %r" % (node.value,))
ASTCodeGenerator.visit_NameConstant = visit_NameConstant
if not hasattr(ASTTransformer, 'visit_NameConstant'):
# Re-use visit_Name because _clone is deleted
ASTTransformer.visit_NameConstant = ASTTransformer.visit_Name
class SaleConfiguration(metaclass=PoolMeta):
__name__ = 'sale.configuration'
report_country_filter = fields.MultiValue(
fields.Char('Default countries for report',
help='String with IDs of countries concatenated with ";".')
)
def get_report_countries(self):
if not self.report_country_filter:
return []
return list(map(int, self.report_country_filter.split(';')))
class ConfigurationReportCountryFilter(ModelSQL, CompanyValueMixin):
"Sale Configuration Report Country Filter"
__name__ = 'sale.configuration.report_country_filter'
report_country_filter = fields.Char('Default countries for report',
help='String with IDs of countries concatenated with ";".')
@classmethod
def __register__(cls, module_name):
table_h = cls.__table_handler__(module_name)
exist = table_h.table_exist(cls._table)
super(ConfigurationReportCountryFilter, cls).__register__(module_name)
if not exist:
cls._migrate_property([], [], [])
@classmethod
def _migrate_property(cls, field_names, value_names, fields):
field_names.append('report_country_filter')
value_names.append('report_country_filter')
fields.append('company')
migrate_property(
'sale.configuration', field_names, cls, value_names,
fields=fields)
class SaleCountryNote(Report):
"""Sales per country note"""
__name__ = 'sale.sale_per_country'
@classmethod
def get_context(cls, records, header, data):
pool = Pool()
Company = pool.get('company.company')
Uom = pool.get('product.uom')
Saleline = pool.get('sale.line')
Country = pool.get('country.country')
Category = pool.get('product.category')
report_context = super(SaleCountryNote, cls).get_context(records,
header, data)
company = Company(data['company'])
_address = company.party.address_get()
country_filter = cls._get_country_criteria()
_states = ['confirmed', 'processing', 'done']
if data['quotation']:
_states.append('quotation')
address_country = 'sale.%s_address.country' % data['address_type']
report_context['company'] = company
report_context['start_date'] = data['start_date']
report_context['end_date'] = data['end_date']
_domain = [('sale.sale_date', '>=', data['start_date']),
('sale.sale_date', '<=', data['end_date']),
('sale.company', '=', report_context['company']),
('sale.state', 'in', _states),
('type', '=', 'line'),
('product', '!=', None)]
if data['type'] != 'all':
_domain.append((address_country, country_filter[data['type']],
_address.country))
if data['category']:
cats = Category.search([
('parent', 'child_of', data['category'])])
_domain.append(
('product.categories', 'in', [c.id for c in cats]))
if data['countries']:
_domain.append((address_country, 'in', data['countries']))
lines = Saleline.search(_domain)
res = {}
keyfunc = partial(cls._get_grouped_key, data['address_type'])
lines = sorted(lines, key=keyfunc)
country_ids = {}
for key, grouped_lines in itertools.groupby(lines, key=keyfunc):
grouped_lines = list(grouped_lines)
res.setdefault(key[0], [])
if key[1] and key[1] not in country_ids:
country_ids[key[1]] = Country(key[1])
res[key[0]].append({
'item': country_ids.get(key[1], None),
'quantity': sum(Uom.compute_qty(
l.unit, l.quantity, l.product.default_uom)
for l in grouped_lines),
'uom': grouped_lines[0].product.default_uom
})
if data['grouping'] == 'country':
new_res = {}
for key, values in res.items():
for value in values:
new_item = value.copy()
new_item['item'] = key
new_res.setdefault(value['item'], []).append(new_item)
res = new_res
info = []
for key, values in res.items():
new_values = sorted(values,
key=lambda x: x['item'] and x['item'].rec_name or '')
info.append((key, new_values))
info = sorted(info, key=lambda x: x[0] and x[0].rec_name or '')
report_context['products'] = info
return report_context
@staticmethod
def _get_country_criteria():
return {'export': '!=',
'national': '='}
@classmethod
def _get_grouped_key(cls, address_type, line):
address = getattr(line.sale, '%s_address' % address_type)
return (line.product, address.country and address.country.id or 0, )
class PrintSaleCountryNoteParam(ModelView):
"""Sales per country note param"""
__name__ = 'sale.sale_per_country.params'
start_date = fields.Date('Start date', required=True)
end_date = fields.Date('End date', required=True)
category = fields.Many2One('product.category', 'Product category')
quotation = fields.Boolean('Consider quotations')
type_ = fields.Selection([('export', 'Export'),
('national', 'National'),
('all', 'All')], 'Type', required=True)
restrict_countries = fields.Boolean('Restrict countries')
countries = fields.One2Many('country.country', None, 'Countries',
states={'invisible': ~Eval('restrict_countries')},
depends=['restrict_countries'])
invoice_address = fields.Boolean('Use invoice address')
grouping = fields.Selection([
('product', 'Product'),
('country', 'Country')], 'Grouping', required=True)
@staticmethod
def default_type_():
return 'export'
@classmethod
def default_quotation(cls):
return True
@classmethod
def default_restrict_countries(cls):
return cls.default_countries() != []
@classmethod
def default_countries(cls):
Conf = Pool().get('sale.configuration')
conf = Conf(1)
return conf.get_report_countries()
@classmethod
def default_invoice_address(cls):
return False
@classmethod
def default_grouping(cls):
return 'product'
class PrintSaleCountryNote(Wizard):
"""Print Sales per country note"""
__name__ = 'sale.sale_per_country.print'
start = StateTransition()
params = StateView('sale.sale_per_country.params',
'sale_per_country_report.sale_per_country_params_view_form',
[Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-print', default=True)])
print_ = StateReport('sale.sale_per_country')
def transition_start(self):
return 'params'
def do_print_(self, action):
data = {}
if Transaction().context.get('active_ids'):
_ = Transaction().context['active_ids'].pop()
data['company'] = Transaction().context['company']
data['start_date'] = self.params.start_date
data['end_date'] = self.params.end_date
data['category'] = \
self.params.category.id if self.params.category else None
data['type'] = self.params.type_
data['quotation'] = self.params.quotation
data['countries'] = (list(map(int, self.params.countries))
if self.params.countries and self.params.restrict_countries
else [])
data['address_type'] = \
'invoice' if self.params.invoice_address else 'shipment'
data['grouping'] = self.params.grouping
return action, data