This commit is contained in:
2026-04-09 19:46:08 +02:00
parent 5ae8af84fb
commit a1ab7dec82
11 changed files with 669 additions and 118 deletions

View File

@@ -39,6 +39,98 @@ class Invoice(metaclass=PoolMeta):
]
return lines or list(self.lines or [])
@staticmethod
def _get_report_related_lots(line):
lots = []
seen = set()
def add_lot(lot):
if not lot:
return
lot_id = getattr(lot, 'id', None)
key = ('id', lot_id) if lot_id is not None else ('obj', id(lot))
if key in seen:
return
seen.add(key)
lots.append(lot)
add_lot(getattr(line, 'lot', None))
origin = getattr(line, 'origin', None)
for lot in getattr(origin, 'lots', []) or []:
add_lot(lot)
return lots
@classmethod
def _get_report_preferred_lots(cls, line):
lots = cls._get_report_related_lots(line)
physicals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'physic'
]
if physicals:
return physicals
virtuals = [
lot for lot in lots
if getattr(lot, 'lot_type', None) == 'virtual'
]
if len(virtuals) == 1:
return virtuals
return []
@staticmethod
def _get_report_line_sign(line):
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return Decimal(-1) if quantity < 0 else Decimal(1)
@staticmethod
def _get_report_lot_hist_weights(lot):
if not lot:
return None, None
if hasattr(lot, 'get_hist_quantity'):
net, gross = lot.get_hist_quantity()
return (
Decimal(str(net or 0)),
Decimal(str(gross if gross not in (None, '') else net or 0)),
)
hist = list(getattr(lot, 'lot_hist', []) or [])
state = getattr(lot, 'lot_state', None)
state_id = getattr(state, 'id', None)
if state_id is not None:
for entry in hist:
quantity_type = getattr(entry, 'quantity_type', None)
if getattr(quantity_type, 'id', None) == state_id:
net = Decimal(str(getattr(entry, 'quantity', 0) or 0))
gross = Decimal(str(
getattr(entry, 'gross_quantity', None)
if getattr(entry, 'gross_quantity', None) not in (None, '')
else net))
return net, gross
return None, None
def _get_report_invoice_line_weights(self, line):
lots = self._get_report_preferred_lots(line)
if lots:
sign = self._get_report_line_sign(line)
net_total = Decimal(0)
gross_total = Decimal(0)
for lot in lots:
net, gross = self._get_report_lot_hist_weights(lot)
if net is None:
continue
net_total += net
gross_total += gross
if net_total or gross_total:
return net_total * sign, gross_total * sign
quantity = Decimal(str(getattr(line, 'quantity', 0) or 0))
return quantity, quantity
@staticmethod
def _get_report_invoice_line_unit(line):
lots = Invoice._get_report_preferred_lots(line)
if lots and getattr(lots[0], 'lot_unit_line', None):
return lots[0].lot_unit_line
return getattr(line, 'unit', None)
@staticmethod
def _clean_report_description(value):
text = (value or '').strip()
@@ -81,6 +173,35 @@ class Invoice(metaclass=PoolMeta):
return lot
return line.lots[0]
@staticmethod
def _get_report_lot_shipment(lot):
if not lot:
return None
return (
getattr(lot, 'lot_shipment_in', None)
or getattr(lot, 'lot_shipment_out', None)
or getattr(lot, 'lot_shipment_internal', None)
)
def _get_report_invoice_shipments(self):
shipments = []
seen = set()
for line in self._get_report_invoice_lines():
for lot in self._get_report_preferred_lots(line):
shipment = self._get_report_lot_shipment(lot)
if not shipment:
continue
shipment_id = getattr(shipment, 'id', None)
key = (
getattr(shipment, '__name__', None),
shipment_id if shipment_id is not None else id(shipment),
)
if key in seen:
continue
seen.add(key)
shipments.append(shipment)
return shipments
def _get_report_invoice_lots(self):
invoice_lines = self._get_report_invoice_lines()
if not invoice_lines:
@@ -140,14 +261,13 @@ class Invoice(metaclass=PoolMeta):
return fees[0] if fees else None
def _get_report_shipment(self):
lot = self._get_report_lot()
if not lot:
shipments = self._get_report_invoice_shipments()
if len(shipments) == 1:
return shipments[0]
if len(shipments) > 1:
return None
return (
getattr(lot, 'lot_shipment_in', None)
or getattr(lot, 'lot_shipment_out', None)
or getattr(lot, 'lot_shipment_internal', None)
)
lot = self._get_report_lot()
return self._get_report_lot_shipment(lot)
@staticmethod
def _get_report_bank_account(party):
@@ -390,16 +510,14 @@ class Invoice(metaclass=PoolMeta):
def report_quantity_lines(self):
details = []
for line in self._get_report_invoice_lines():
quantity = getattr(line, 'report_net', '')
if quantity == '':
quantity = getattr(line, 'quantity', '')
quantity, _ = self._get_report_invoice_line_weights(line)
if quantity == '':
continue
quantity_text = self._format_report_number(
quantity, keep_trailing_decimal=True)
unit = getattr(line, 'unit', None)
unit = self._get_report_invoice_line_unit(line)
unit_name = unit.rec_name.upper() if unit and unit.rec_name else ''
lbs = getattr(line, 'report_lbs', '')
lbs = round(Decimal(quantity) * Decimal('2204.62'), 2)
parts = [quantity_text, unit_name]
if lbs != '':
parts.append(
@@ -586,11 +704,18 @@ class Invoice(metaclass=PoolMeta):
return 'NB BALES: ' + str(int(nb_bale))
return ''
@property
def report_cndn_nb_bale(self):
nb_bale = self.report_nb_bale
if nb_bale == 'NB BALES: 0':
return 'Unchanged'
return nb_bale
@property
def report_gross(self):
if self.lines:
return sum(
Decimal(str(getattr(line, 'quantity', 0) or 0))
self._get_report_invoice_line_weights(line)[1]
for line in self._get_report_invoice_lines())
line = self._get_report_trade_line()
if line and line.lots:
@@ -604,7 +729,7 @@ class Invoice(metaclass=PoolMeta):
def report_net(self):
if self.lines:
return sum(
Decimal(str(getattr(line, 'quantity', 0) or 0))
self._get_report_invoice_line_weights(line)[0]
for line in self._get_report_invoice_lines())
line = self._get_report_trade_line()
if line and line.lots:
@@ -625,8 +750,15 @@ class Invoice(metaclass=PoolMeta):
@property
def report_weight_unit_upper(self):
line = self._get_report_trade_line() or self._get_report_invoice_line()
unit = getattr(line, 'unit', None) if line else None
invoice_line = self._get_report_invoice_line()
unit = self._get_report_invoice_line_unit(invoice_line) if invoice_line else None
if not unit:
line = self._get_report_trade_line()
lot = self._get_report_lot()
unit = (
getattr(lot, 'lot_unit_line', None)
or getattr(line, 'unit', None) if line else None
)
if unit and unit.rec_name:
return unit.rec_name.upper()
return 'KGS'
@@ -634,6 +766,16 @@ class Invoice(metaclass=PoolMeta):
@property
def report_note_title(self):
total = Decimal(str(self.total_amount or 0))
invoice_type = getattr(self, 'type', None)
if not invoice_type:
if self.sales:
invoice_type = 'out'
elif self.purchases:
invoice_type = 'in'
if invoice_type == 'out':
if total < 0:
return 'Credit Note'
return 'Debit Note'
if total < 0:
return 'Debit Note'
return 'Credit Note'
@@ -721,6 +863,13 @@ class Invoice(metaclass=PoolMeta):
return shipment.number or ''
return ''
@property
def report_si_reference(self):
shipment = self._get_report_shipment()
if shipment:
return getattr(shipment, 'reference', None) or ''
return ''
@property
def report_freight_amount(self):
fee = self._get_report_freight_fee()
@@ -832,6 +981,13 @@ class InvoiceLine(metaclass=PoolMeta):
@property
def report_net(self):
if self.type == 'line':
lot = getattr(self, 'lot', None)
if lot:
net, _ = Invoice._get_report_lot_hist_weights(lot)
if net is None:
net = 0
sign = Invoice._get_report_line_sign(self)
return Decimal(str(net or 0)) * sign
return self.quantity
return ''