trytonpsk-farming/charge.py

395 lines
14 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.
from trytond.model import Workflow, ModelView, ModelSQL, fields
from trytond.wizard import Wizard, StateView, Button, StateReport
from trytond.pyson import Eval
from trytond.transaction import Transaction
from trytond.modules.company import CompanyReport
from trytond.pool import Pool
from trytond.exceptions import UserError
from trytond.report import Report
STATES = {
'readonly': (Eval('state') != 'draft'),
}
class ChargeVehicle(ModelSQL, ModelView):
"Charge Vehicle"
__name__ = 'exportation.charge.vehicle'
_rec_name = 'plate'
plate = fields.Char('Plate')
class ExportationPort(ModelSQL, ModelView):
"Exportation Port"
__name__ = 'exportation.port'
name = fields.Char('Name')
city_info = fields.Char('City Info')
class ExportationCharge(Workflow, ModelSQL, ModelView):
"Exportation Charge"
__name__ = 'exportation.charge'
date = fields.Date('Date', required=True, states=STATES)
number = fields.Char('Number', readonly=True)
company = fields.Many2One('company.company', 'Company', required=True,
states=STATES)
carrier = fields.Many2One('party.party', 'Carrier', select=True,
states=STATES)
port = fields.Many2One('exportation.port', 'Port', select=True)
out_time = fields.Time('Out Time', states=STATES, required=False)
driver = fields.Many2One('party.party', 'Driver', required=True,
select=True)
driver2 = fields.Many2One('party.party', 'Driver 2',
select=True)
vehicle = fields.Many2One('exportation.charge.vehicle', 'Vehicle',
states=STATES, required=True)
vehicle2 = fields.Many2One('exportation.charge.vehicle', 'Vehicle 2',
states=STATES)
seal = fields.Char('Seal', states=STATES, required=False)
band = fields.Char('Band', states=STATES, required=False)
hts_list = fields.Function(fields.Char('HTS List'), 'get_hts_list')
description = fields.Char('Description', required=False)
lines = fields.One2Many('exportation.charge.line', 'charge', 'Lines',
states=STATES)
state = fields.Selection([
('draft', 'Draft'),
('confirm', 'Confirm'),
('cancel', 'Canceled'),
], 'State', readonly=True, select=True)
sales = fields.Function(fields.One2Many('sale.sale', None, 'Sales'),
'get_sales')
total_amount = fields.Function(fields.Numeric('Total Charge',
digits=(16, 2)), 'get_total_amount')
pieces = fields.Function(fields.Float('Total Pieces',
digits=(6, 2)), 'get_value_uom')
units = fields.Function(fields.Float('Total Units',
digits=(6, 2)), 'get_value_uom')
fulles = fields.Function(fields.Float('Total Boxes',
digits=(6, 2)), 'get_value_uom')
dispatched_by = fields.Many2One('company.employee', 'Dispatched By',
states=STATES)
@classmethod
def __setup__(cls):
super(ExportationCharge, cls).__setup__()
cls._order.insert(0, ('date', 'DESC'))
cls._transitions |= set((
('draft', 'confirm'),
('draft', 'cancel'),
('confirm', 'draft'),
))
cls._buttons.update({
'cancel': {
'invisible': Eval('state') != 'draft'
},
'draft': {
'invisible': Eval('state') == 'draft',
},
'confirm': {
'invisible': Eval('state') != 'draft',
},
'select_sales': {
'invisible': Eval('state') != 'draft',
},
})
@staticmethod
def default_state():
return 'draft'
@staticmethod
def default_date():
Date = Pool().get('ir.date')
return Date.today()
@staticmethod
def default_company():
return Transaction().context.get('company') or False
def get_hts_list(self, name=None):
# Lista de subpartidas arancelarias (hts)
res = []
for line in self.lines:
if line.product.template.hts:
res.append(line.product.template.hts[0:4])
res = set(res)
return ' - '.join(list(res))
@classmethod
@ModelView.button
def select_sales(cls, records):
pool = Pool()
Sale = pool.get('sale.sale')
for charge in records:
if not charge.carrier:
continue
sales = Sale.search([
('carrier', '=', charge.carrier.id),
('state', '=', 'processing'),
('charge', '=', None),
('shipping_date', '=', charge.date),
])
for sale in sales:
freight_forwader = sale.freight_forwader
party = sale.invoice_party if sale.invoice_party else sale.party
if not freight_forwader:
raise UserError('Falta el agente aduanero en la venta! %s' % sale.number)
products = {}
for line in sale.lines:
key_ = (line.product, line.packing_uom)
if key_ not in products.keys():
products[key_] = {
'freight_forwader': freight_forwader.id,
'mawb': sale.mawb,
'hawb': sale.hawb,
'consignee': party.id,
'uom': line.packing_uom.id,
'pieces': line.packing_qty,
'fulles': round(line.boxes, 2),
'export_target_city': sale.export_target_city,
'export_route': sale.export_route,
'sale_lines': [('add', [line])],
}
else:
products[key_]['pieces'] += line.packing_qty
products[key_]['fulles'] += round(line.boxes, 2)
products[key_]['sale_lines'][0][1].append(line)
for pr in products.values():
pr['fulles'] = round(pr['fulles'], 2)
cls.write([charge], {'lines': [
('create', products.values())
]})
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, records):
pass
@classmethod
@ModelView.button
@Workflow.transition('cancel')
def cancel(cls, records):
pass
@classmethod
@ModelView.button
@Workflow.transition('confirm')
def confirm(cls, records):
for rec in records:
rec.set_number()
def set_number(self):
"""
Fill the number field with the booking sequence
"""
pool = Pool()
Config = pool.get('farming.configuration')
config = Config.get_config()
if self.number or not config.charge_form_sequence:
return
number = config.charge_form_sequence.get()
self.write([self], {'number': number})
def get_value_uom(self, name=None):
res = []
for line in self.lines:
value = getattr(line, name)
if value:
res.append(value)
val = round(sum(res), 2)
return val
def get_sales(self, name=None):
pass
def get_total_amount(self, name=None):
pass
def subtotals(self):
subtotals = {}
class Sub():
pass
for line in self.lines:
lkey = (line.freight_forwader, line.consignee, line.hawb, line.mawb)
if lkey not in subtotals.keys():
sub = Sub()
sub.hawb = line.hawb
sub.mawb = line.mawb
sub.freight_forwader = line.freight_forwader
sub.consignee = line.consignee
sub.lines = [line]
sub.pieces = line.pieces
sub.fulles = line.fulles
subtotals[lkey] = sub
else:
subtotals[lkey].lines.append(line)
subtotals[lkey].pieces += line.pieces
subtotals[lkey].fulles += line.fulles
return subtotals.values()
@classmethod
def copy(cls, records, default=None):
default = {}
return super(ExportationCharge, cls).copy(ExportationCharge, default)
class ExportationChargeLine(ModelSQL, ModelView):
"Exportation Charge Line"
__name__ = 'exportation.charge.line'
charge = fields.Many2One('exportation.charge', 'Charge', select=True,
ondelete='CASCADE')
product = fields.Many2One('product.product', 'Product',
domain=[('salable', '=', 'True')])
uom = fields.Many2One('product.uom', 'UOM')
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'get_unit_digits')
freight_forwader = fields.Many2One('party.party', 'Freight Forwader')
consignee = fields.Many2One('party.party', 'Consignee', required=True)
export_target_city = fields.Many2One('party.city_code', 'Target City',
required=True, select=True)
export_route = fields.Char('Route', select=True)
mawb = fields.Char('MAWB')
hawb = fields.Char('HAWB')
pieces = fields.Float('Pieces', digits=(6, 2))
units = fields.Float('Units', digits=(6, 2))
fulles = fields.Float('Fulles', digits=(6, 2))
sale_lines = fields.One2Many('sale.line', 'charge_line', 'Sale Lines',
states=STATES)
@classmethod
def __setup__(cls):
super(ExportationChargeLine, cls).__setup__()
cls._order.insert(0, ('consignee.name', 'ASC'))
@staticmethod
def default_unit_digits():
return 2
@fields.depends('product', 'uom', 'unit_digits')
def on_change_product(self):
if self.product:
self.uom = self.product.default_uom.id
self.unit_digits = self.product.default_uom.digits
self.unit_digits = 2
def get_uom(self, name):
return self.product.default_uom.id
def get_unit_digits(self, name):
return self.product.default_uom.digits
class ExportationChargeReport(CompanyReport):
__name__ = 'exportation.charge'
class LetterOfResponsability(CompanyReport):
__name__ = 'exportation.charge.letter_of_responsability'
@classmethod
def get_context(cls, records, header, data):
context = super().get_context(records, header, data)
for rec in records:
_lines = {}
for line in rec.lines:
lkey = (line.hawb, line.consignee.id)
if lkey not in _lines.keys():
_lines[lkey] = {
'hawb': line.hawb,
'mawb': line.mawb,
'consignee': line.consignee.name,
'pieces': line.pieces,
'freight_forwader': line.freight_forwader.name,
'freight_forwader_id': line.freight_forwader.id_number,
'target_city': line.export_target_city.name,
'export_route': line.export_route,
}
else:
_lines[lkey]['pieces'] += line.pieces
rec._lines = _lines.values()
return context
class DispatchControlStart(ModelView):
'Dispatch Report Start'
__name__ = 'exportation.dispatch_control.start'
company = fields.Many2One('company.company', 'Company', required=True)
date_ = fields.Date("Date", required=True)
@staticmethod
def default_company():
return Transaction().context.get('company')
class DispatchControl(Wizard):
'Dispatch Control Report'
__name__ = 'exportation.dispatch_control'
start = StateView('exportation.dispatch_control.start',
'farming.dispatch_control_start_view_form', [
Button('Cancel', 'end', 'tryton-cancel'),
Button('Print', 'print_', 'tryton-ok', default=True),
])
print_ = StateReport('exportation.dispatch_control_report')
def do_print_(self, action):
data = {
'company': self.start.company.id,
'date': self.start.date_,
}
return action, data
def transition_print_(self):
return 'end'
class DispatchControlReport(Report):
__name__ = 'exportation.dispatch_control_report'
@classmethod
def get_context(cls, records, header, data):
report_context = super().get_context(records, header, data)
pool = Pool()
Company = pool.get('company.company')
Charge = pool.get('exportation.charge')
charges = Charge.search([
('company', '=', data['company']),
('date', '=', data['date']),
], order=[('id', 'ASC')])
records = {}
for charge in charges:
for line in charge.lines:
lkey = (line.consignee.id, line.hawb, line.freight_forwader.id)
numbers = list(set([sl.sale.number for sl in line.sale_lines]))
if lkey not in records.keys():
records[lkey] = {
'customer': line.consignee.name,
'mawb': line.mawb,
'hawb': line.hawb,
'sales': numbers,
'freight_forwader': line.freight_forwader.name,
'pieces': [line.pieces],
'plate': charge.vehicle.plate,
'driver': charge.driver.name,
'driver_id': charge.driver.id_number,
'driver_phone': charge.driver.mobile,
}
else:
records[lkey]['pieces'].append(line.pieces)
records[lkey]['sales'] = list(set(records[lkey]['sales'] + numbers))
report_context['records'] = records.values()
report_context['company'] = Company(data['company'])
return report_context