trytond-carrier_load/cmr.py

258 lines
9.3 KiB
Python

# The COPYRIGHT file at the top level of this repository contains the full
# copyright notices and license terms.
import os
from functools import partial
from trytond.model import fields, ModelSQL, ModelView, DeactivableMixin, Model
from trytond.pool import Pool
from trytond.pyson import Eval
from trytond.transaction import Transaction
from trytond.modules.company import CompanyReport
from .load import NoteMixin
from genshi.template import TextTemplate
from sql import Literal
file_id = 'cmr_template_image_id'
store_prefix = None
class CMRTemplate(DeactivableMixin, ModelSQL, ModelView):
'''CMR Template'''
__name__ = 'carrier.load.cmr.template'
name = fields.Char('Name', required=True)
lines = fields.One2Many('carrier.load.cmr.template.line', 'template',
'Lines')
copy_as_sender = fields.Boolean('Copy with Company as sender',
help='If checked add a copy on CMR with Company as sender. '
'Only when Shipment Party defined.')
def get_section(self, section):
for line in self.lines:
if line.section == section:
return line
def get_section_text(self, section, record=None, lang=None, *args):
line = self.get_section(section)
if not line:
return ''
if not lang or lang.code == Transaction().context['language']:
text = line.text
else:
with Transaction().set_context(language=lang.code):
text = line.__class__(line.id).text
return self.eval(text, record, *(list(args) + [lang]))
def get_section_image(self, section):
line = self.get_section(section)
if not line or not line.image:
# use a blank image to avoid failed render icon
blank = os.path.join(os.path.dirname(__file__), 'images',
'blank.png')
with open(blank, 'rb') as fp:
return fp.read()
return line.image
@classmethod
def eval(cls, expression, record, *args):
if not expression:
return ''
template = TextTemplate(expression)
template_context = cls.template_context(record, *args)
text = template.generate(**template_context).render()
return '\n'.join([x.strip() for x in text.splitlines()])
@staticmethod
def template_context(record, *args):
User = Pool().get('res.user')
user = None
if Transaction().user:
user = User(Transaction().user)
res = {
'record': record,
'user': user,
}
for arg in args:
if not isinstance(arg, Model):
continue
if arg.__name__ == 'party.address':
res['full_address'] = arg.full_address
res.update(arg._get_address_substitutions())
arg = arg.party
if arg.__name__ == 'party.party':
res.update({
'party_full_name': arg.full_name,
'party_tax_identifier': arg.tax_identifier and
arg.tax_identifier.code or '',
})
if arg.__name__ == 'ir.lang':
res['lang'] = arg
return res
@staticmethod
def _get_section_defaults():
return {
'1':
'${party_full_name}\n'
'${full_address}',
'2':
'${party_full_name}\n'
'${full_address}',
'3':
'${full_address}',
'4':
'${party_full_name}\n'
'${city}\n'
'${subdivision}'
}
@classmethod
def default_lines(cls):
return [{'section': k, 'text': v}
for k, v in cls._get_section_defaults().items()]
class CMRTemplateLine(ModelSQL, ModelView):
'''CMR Template Line'''
__name__ = 'carrier.load.cmr.template.line'
template = fields.Many2One('carrier.load.cmr.template', 'Template',
required=True, select=True, ondelete='CASCADE')
section = fields.Selection([
('1', '1 - Sender'),
('1-right', '1 - Sender (Right)'),
('2', '2 - Consignee'),
('2-right', '2 - Consignee (Right)'),
('3', '3 - Place of delivery of the goods'),
('3-right', '3 - Place of delivery of the goods (Right)'),
('4', '4 - Place of taking over the goods'),
('5', '5 - Documents attached'),
('6-9', '6 to 9 - Bottom notes'),
('13', '13 - Instructions'),
('18', '18 - Carrier reservations'),
('19', '19 - Special agreements'),
('22', '22 - Signature & stamp of sender'),
('head-right', 'Header (Right)'),
('head-left', 'Header (Left)'),
], 'Section', required=True, sort=False)
text = fields.Text('Text', translate=True, states={
'invisible': (Eval('section') == '22'),
},
help='Define static text or expression to evaluate with '
'current load order (eg. ${record.shipment.number})',
depends=['section'])
image = fields.Binary('Image', file_id='image_id',
store_prefix=store_prefix, states={
'invisible': (Eval('section') != '22'),
'required': (Eval('section') == '22')
},
depends=['section'])
image_id = fields.Char('Image ID', readonly=True)
@fields.depends('section', 'text')
def on_change_section(self):
Template = Pool().get('carrier.load.cmr.template')
defaults = Template._get_section_defaults()
if self.section in defaults and not self.text:
self.text = defaults[self.section]
@classmethod
def __register__(cls, module_name):
cursor = Transaction().connection.cursor()
Template = Pool().get('carrier.load.cmr.template')
table = cls.__table__()
template = Template.__table__()
super().__register__(module_name)
# backward compatibility
for section, text in Template._get_section_defaults().items():
cursor.execute(*table.select(
table.id,
where=(table.section == section)))
if not cursor.fetchone():
cursor.execute(*table.insert([
table.create_uid,
table.write_uid,
table.create_date,
table.write_date,
table.template,
table.section,
table.text
],
template.select(
template.create_uid,
template.write_uid,
template.create_date,
template.write_date,
template.id,
Literal(section),
Literal(text))
)
)
class CMR(NoteMixin, CompanyReport):
"""CMR report"""
__name__ = 'carrier.load.order.cmr'
@classmethod
def get_context(cls, records, header, data):
Configuration = Pool().get('carrier.configuration')
report_context = super(CMR, cls).get_context(records, header, data)
report_context['copies'] = Configuration(1).cmr_copies or 3
report_context['addresses'] = lambda order: cls.addresses(order)
report_context['sender_text'] = (lambda order, language, *args:
partial(cls.get_section_text, '1')(order, language, *args))
report_context['consignee_text'] = (lambda order, language, *args:
partial(cls.get_section_text, '2')(order, language, *args))
report_context['delivery_text'] = (lambda order, language, *args:
partial(cls.get_section_text, '3')(order, language, *args))
report_context['load_text'] = (lambda order, language, *args:
partial(cls.get_section_text, '4')(order, language, *args))
return report_context
@classmethod
def instructions(cls, order, language):
Order = Pool().get('carrier.load.order')
with Transaction().set_context(language=language):
value = Order(order.id).cmr_instructions
if value:
value = value.splitlines()
return value or []
@classmethod
def addresses(cls, order):
addresses = {
'sender': cls.sender_address(order, cls.sender(order)),
'consignee': cls.consignee_address(order),
'delivery': cls.delivery_address(order)
}
res = [addresses]
if order.cmr_template and order.cmr_template.copy_as_sender and \
addresses['sender'].party != order.company.party:
res.append({
'sender': order.company.party.address_get(type='invoice'),
'consignee': addresses['sender'],
'delivery': addresses['consignee']
})
return res
@classmethod
def get_section_text(cls, section, order, language, *args):
if not args or not args[0]:
return ''
return order.cmr_template and \
order.cmr_template.get_section_text(section, order,
language, *args) or ''
@classmethod
def execute(cls, ids, data):
with Transaction().set_context(_check_access=False):
# allow to print without sale group
return super().execute(ids, data)