Sale design
This commit is contained in:
@@ -15,6 +15,7 @@ from sql.functions import CurrentTimestamp, DateTrunc
|
||||
import datetime
|
||||
import logging
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from trytond.exceptions import UserWarning, UserError
|
||||
from trytond.modules.purchase_trade.numbers_to_words import quantity_to_words, amount_to_currency_words, format_date_en
|
||||
|
||||
@@ -279,6 +280,8 @@ class Sale(metaclass=PoolMeta):
|
||||
association = fields.Many2One('purchase.association',"Association", required=True,states={'invisible': Eval('company_visible'),})
|
||||
crop = fields.Many2One('purchase.crop',"Crop",states={'invisible': Eval('company_visible'),})
|
||||
viewer = fields.Function(fields.Text(""),'get_viewer')
|
||||
execution_summary_viewer = fields.Function(
|
||||
fields.Text(""), 'get_execution_summary_viewer')
|
||||
doc_template = fields.Many2One('doc.template',"Template")
|
||||
required_documents = fields.Many2Many(
|
||||
'contract.document.type', 'sale', 'doc_type', 'Required Documents')
|
||||
@@ -1186,6 +1189,122 @@ class Sale(metaclass=PoolMeta):
|
||||
def on_change_with_viewer(self):
|
||||
return self.get_viewer()
|
||||
|
||||
def _execution_summary_quantity(self, value):
|
||||
if value is None:
|
||||
return 0.0
|
||||
try:
|
||||
return float(value)
|
||||
except (TypeError, ValueError):
|
||||
return 0.0
|
||||
|
||||
def get_execution_summary_viewer(self, name=None):
|
||||
LotQt = Pool().get('lot.qt')
|
||||
rows = []
|
||||
totals = defaultdict(float)
|
||||
|
||||
for line in (self.lines or []):
|
||||
if getattr(line, 'type', 'line') != 'line':
|
||||
continue
|
||||
|
||||
quantity = self._execution_summary_quantity(
|
||||
getattr(line, 'quantity_theorical', None)
|
||||
or getattr(line, 'quantity', None))
|
||||
matched = 0.0
|
||||
shipped = 0.0
|
||||
lots_count = 0
|
||||
shipped_routes = []
|
||||
line_lots = list(getattr(line, 'lots', None) or [])
|
||||
lot_ids = [lot.id for lot in line_lots if getattr(lot, 'id', None)]
|
||||
lot_qts = LotQt.search([('lot_s', 'in', lot_ids)]) if lot_ids else []
|
||||
|
||||
for lqt in lot_qts:
|
||||
lots_count += 1
|
||||
lot_quantity = self._execution_summary_quantity(
|
||||
getattr(lqt, 'lot_quantity', None)
|
||||
or getattr(lqt, 'lot_qt', None))
|
||||
if getattr(lqt, 'lot_p', None):
|
||||
matched += lot_quantity
|
||||
shipment = (
|
||||
getattr(lqt, 'lot_shipment_in', None)
|
||||
or getattr(lqt, 'lot_shipment_internal', None)
|
||||
or getattr(lqt, 'lot_shipment_out', None))
|
||||
if shipment:
|
||||
shipped += lot_quantity
|
||||
route_from = getattr(
|
||||
getattr(shipment, 'from_location', None),
|
||||
'rec_name', None)
|
||||
route_to = getattr(
|
||||
getattr(shipment, 'to_location', None),
|
||||
'rec_name', None)
|
||||
route_from = route_from or getattr(
|
||||
getattr(self, 'from_location', None), 'rec_name', None)
|
||||
route_to = route_to or getattr(
|
||||
getattr(self, 'to_location', None), 'rec_name', None)
|
||||
if route_from or route_to:
|
||||
shipped_routes.append(
|
||||
'%s > %s' % (route_from or '-', route_to or '-'))
|
||||
|
||||
if not lot_qts:
|
||||
for lot in line_lots:
|
||||
lots_count += 1
|
||||
lot_quantity = self._execution_summary_quantity(
|
||||
getattr(lot, 'lot_qt', None))
|
||||
if getattr(lot, 'lot_p', None) or getattr(lot, 'line', None):
|
||||
matched += lot_quantity
|
||||
shipment = (
|
||||
getattr(lot, 'lot_shipment_in', None)
|
||||
or getattr(lot, 'lot_shipment_internal', None)
|
||||
or getattr(lot, 'lot_shipment_out', None))
|
||||
if shipment:
|
||||
shipped += lot_quantity
|
||||
route_from = getattr(
|
||||
getattr(shipment, 'from_location', None),
|
||||
'rec_name', None)
|
||||
route_to = getattr(
|
||||
getattr(shipment, 'to_location', None),
|
||||
'rec_name', None)
|
||||
route_from = route_from or getattr(
|
||||
getattr(self, 'from_location', None),
|
||||
'rec_name', None)
|
||||
route_to = route_to or getattr(
|
||||
getattr(self, 'to_location', None),
|
||||
'rec_name', None)
|
||||
if route_from or route_to:
|
||||
shipped_routes.append(
|
||||
'%s > %s' % (route_from or '-', route_to or '-'))
|
||||
|
||||
unit = getattr(getattr(line, 'unit', None), 'rec_name', '') or ''
|
||||
product = getattr(getattr(line, 'product', None), 'rec_name', '') or ''
|
||||
route = (shipped_routes[0] if shipped_routes else '%s > %s' % (
|
||||
getattr(getattr(self, 'from_location', None), 'rec_name', None)
|
||||
or '-',
|
||||
getattr(getattr(self, 'to_location', None), 'rec_name', None)
|
||||
or '-'))
|
||||
|
||||
rows.append({
|
||||
'product': product,
|
||||
'quantity': quantity,
|
||||
'matched': matched,
|
||||
'shipped': shipped,
|
||||
'open': max(quantity - shipped, 0.0),
|
||||
'unit': unit,
|
||||
'lots': lots_count,
|
||||
'route': route,
|
||||
})
|
||||
totals['quantity'] += quantity
|
||||
totals['matched'] += matched
|
||||
totals['shipped'] += shipped
|
||||
totals['open'] += max(quantity - shipped, 0.0)
|
||||
totals['lines'] += 1
|
||||
|
||||
data = {
|
||||
'type': 'execution-summary',
|
||||
'unit': rows[0]['unit'] if rows else '',
|
||||
'totals': dict(totals),
|
||||
'rows': rows[:4],
|
||||
}
|
||||
return "d3:" + json.dumps(data)
|
||||
|
||||
def getLots(self):
|
||||
if self.lines:
|
||||
if self.lines.lots:
|
||||
|
||||
@@ -2,57 +2,112 @@
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<data>
|
||||
<xpath expr="/form/group/field[@name='currency']" position="after">
|
||||
<newline/>
|
||||
<label name="lc_date"/>
|
||||
<field name="lc_date"/>
|
||||
<label name="wb"/>
|
||||
<field name="wb"/>
|
||||
<newline/>
|
||||
<label name="certif"/>
|
||||
<field name="certif"/>
|
||||
<newline/>
|
||||
<label name="agent"/>
|
||||
<field name="agent"/>
|
||||
<label name="operator"/>
|
||||
<field name="operator"/>
|
||||
<newline/>
|
||||
<label name="trader"/>
|
||||
<field name="trader"/>
|
||||
<label name="our_reference"/>
|
||||
<field name="our_reference"/>
|
||||
<newline/>
|
||||
<label name="association"/>
|
||||
<field name="association"/>
|
||||
<label name="crop"/>
|
||||
<field name="crop"/>
|
||||
<newline/>
|
||||
<label name="tol_min"/>
|
||||
<field name="tol_min"/>
|
||||
<label name="tol_max"/>
|
||||
<field name="tol_max"/>
|
||||
<newline/>
|
||||
<label name="tolerance_used"/>
|
||||
<field name="tolerance_used" widget="tolerance_gauge"
|
||||
min_field="tolerance_min" max_field="tolerance_max"
|
||||
xexpand="1" xfill="1"/>
|
||||
<label name="tolerance_option"/>
|
||||
<field name="tolerance_option"/>
|
||||
<field name="tolerance_min" invisible="1"/>
|
||||
<field name="tolerance_max" invisible="1"/>
|
||||
<newline/>
|
||||
<label name="from_location"/>
|
||||
<field name="from_location"/>
|
||||
<label name="to_location"/>
|
||||
<field name="to_location"/>
|
||||
<newline/>
|
||||
<label name="incoterm"/>
|
||||
<field name="incoterm"/>
|
||||
<label name="incoterm_location"/>
|
||||
<field name="incoterm_location"/>
|
||||
<newline/>
|
||||
<label name="product_origin"/>
|
||||
<field name="product_origin"/>
|
||||
<xpath expr="/form/group[@id='hd'][2]" position="replace"/>
|
||||
<xpath expr="/form/group[@id='hd'][1]" position="replace">
|
||||
<group id="sale_header_summary" colspan="6" col="10"
|
||||
panel="summary" xalign="0" yalign="0"
|
||||
col_widths="min-content,2fr,min-content,130px,min-content,1.2fr,min-content,130px,min-content,1fr">
|
||||
<label name="party"/>
|
||||
<field name="party"/>
|
||||
<label name="number"/>
|
||||
<field name="number"/>
|
||||
<label name="reference"/>
|
||||
<field name="reference"/>
|
||||
<label name="sale_date"/>
|
||||
<field name="sale_date"/>
|
||||
<label name="currency"/>
|
||||
<field name="currency"/>
|
||||
</group>
|
||||
|
||||
<group id="sale_header_left" colspan="4" col="1"
|
||||
xalign="0" yalign="0" col_widths="1fr">
|
||||
<group id="sale_commercial_terms" string="Commercial Terms"
|
||||
colspan="1" col="1" panel="card" icon="tryton-public"
|
||||
xalign="0" yalign="0"
|
||||
col_widths="1fr">
|
||||
<group id="sale_commercial_terms_top"
|
||||
colspan="1" col="6" xalign="0" yalign="0"
|
||||
col_widths="min-content,1fr,min-content,1fr,min-content,130px">
|
||||
<label name="payment_term"/>
|
||||
<field name="payment_term"/>
|
||||
<label name="wb"/>
|
||||
<field name="wb"/>
|
||||
<label name="lc_date"/>
|
||||
<field name="lc_date"/>
|
||||
</group>
|
||||
<group id="sale_commercial_terms_incoterm"
|
||||
colspan="1" col="4" xalign="0" yalign="0"
|
||||
col_widths="min-content,1fr,min-content,1fr">
|
||||
<label name="incoterm"/>
|
||||
<field name="incoterm"/>
|
||||
<label name="incoterm_location"/>
|
||||
<field name="incoterm_location"/>
|
||||
</group>
|
||||
<group id="sale_commercial_terms_origin"
|
||||
colspan="1" col="4" xalign="0" yalign="0"
|
||||
col_widths="min-content,1fr,min-content,1fr">
|
||||
<label name="product_origin"/>
|
||||
<field name="product_origin"/>
|
||||
<label name="tolerance_option"/>
|
||||
<field name="tolerance_option"/>
|
||||
</group>
|
||||
<field name="certif" invisible="1"/>
|
||||
</group>
|
||||
|
||||
<group id="sale_execution" string="People & Execution"
|
||||
colspan="1" col="4" panel="card" icon="tryton-link"
|
||||
xalign="0" yalign="0"
|
||||
col_widths="min-content,1fr,min-content,1fr">
|
||||
<label name="broker"/>
|
||||
<field name="broker"/>
|
||||
<label name="operator"/>
|
||||
<field name="operator"/>
|
||||
<label name="trader"/>
|
||||
<field name="trader"/>
|
||||
<label name="our_reference"/>
|
||||
<field name="our_reference"/>
|
||||
<label name="from_location"/>
|
||||
<field name="from_location"/>
|
||||
<label name="to_location"/>
|
||||
<field name="to_location"/>
|
||||
<label name="association"/>
|
||||
<field name="association"/>
|
||||
<label name="crop"/>
|
||||
<field name="crop"/>
|
||||
</group>
|
||||
|
||||
<group id="sale_tolerance" string="Tolerance"
|
||||
colspan="1" col="6" panel="card" icon="tryton-switch"
|
||||
xalign="0" yalign="0"
|
||||
col_widths="min-content,1fr,min-content,1fr,min-content,200px">
|
||||
<label name="tol_min"/>
|
||||
<field name="tol_min"/>
|
||||
<label name="tol_max"/>
|
||||
<field name="tol_max"/>
|
||||
<label name="tolerance_used"/>
|
||||
<field name="tolerance_used" widget="tolerance_gauge"
|
||||
min_field="tolerance_min" max_field="tolerance_max"
|
||||
width="190" xexpand="0" xfill="0"/>
|
||||
</group>
|
||||
<field name="tolerance_min" invisible="1"/>
|
||||
<field name="tolerance_max" invisible="1"/>
|
||||
</group>
|
||||
|
||||
<group id="sale_header_right" colspan="2" col="1"
|
||||
xalign="0" yalign="0" col_widths="1fr">
|
||||
<group id="sale_map" string="Map" colspan="1" col="1"
|
||||
panel="card" icon="tryton-public" xalign="0" yalign="0"
|
||||
col_widths="1fr">
|
||||
<field name="viewer" widget="html_viewer" height="220"/>
|
||||
</group>
|
||||
<group id="sale_recap" string="Execution summary"
|
||||
colspan="1" col="1" panel="sidebar" icon="tryton-note"
|
||||
xalign="0" yalign="0"
|
||||
col_widths="1fr">
|
||||
<field name="execution_summary_viewer" widget="html_viewer"
|
||||
height="142"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="/form/notebook/page[@id='sale']" position="after">
|
||||
<page string="Contract Clauses" col="4" id="contract_clauses">
|
||||
|
||||
Reference in New Issue
Block a user