Lot invoicing + Fee invoicing

This commit is contained in:
2026-06-22 17:44:55 +02:00
parent 703868001b
commit ed818c2287
6 changed files with 224 additions and 54 deletions

View File

@@ -25,7 +25,16 @@ from trytond.modules.purchase_trade.service import ContractFactory
from trytond.modules.purchase_trade.company_defaults import (
default_itsa_unit, is_itsa_company)
logger = logging.getLogger(__name__)
logger = logging.getLogger(__name__)
def _fee_invoice_action(fee, invoice_action):
invoice = fee.get_invoice('inv') if fee else None
if invoice_action == 'final' and invoice:
return 'dn_cn'
if invoice:
return 'already_invoiced'
return 'standard'
class LotAccountingGraph(ModelSQL,ModelView):
"Lot accounting graph"
@@ -4667,7 +4676,7 @@ class LotInvoice(Wizard):
def transition_start(self):
return 'inv'
def default_inv(self, fields):
def default_inv(self, fields):
lot_p = []
lot_s = []
fee_pur = []
@@ -4675,8 +4684,10 @@ class LotInvoice(Wizard):
fee_sale = []
pp_sale = []
act = 'prov'
line = None
sale_line = None
line = None
sale_line = None
purchase_lines = []
sale_lines = []
val = {}
Lot = Pool().get('lot.lot')
LotQt = Pool().get('lot.qt')
@@ -4690,7 +4701,9 @@ class LotInvoice(Wizard):
lot = lqts[0].lot_p
else:
lot = Lot(i)
line = lot.line
line = lot.line
if line and line not in purchase_lines:
purchase_lines.append(line)
if lot.line.purchase:
if lot.line.purchase.wb:
if lot.line.purchase.wb.qt_type in [e.quantity_type for e in lot.lot_hist]:
@@ -4715,7 +4728,9 @@ class LotInvoice(Wizard):
unit = val['lot_unit']
val['lot_currency'] = lot.lot_price_ct_symbol
lot_p.append(val)
sale_line = lot.sale_line
sale_line = lot.sale_line
if sale_line and sale_line not in sale_lines:
sale_lines.append(sale_line)
val_s = val.copy() # ou utiliser deepcopy si certains champs sont des objets imbriqués
val_s['lot_price'] = lot.lot_price_sale
val_s['lot_amount'] = lot.get_current_quantity_converted() * lot.lot_price_sale if lot.lot_price_sale else Decimal(0)
@@ -4737,22 +4752,28 @@ class LotInvoice(Wizard):
val_s['lot_currency'] = lot.lot_price_ct_symbol_sale
val_s['lot_unit'] = sale_line.unit.id if sale_line else None
lot_s.append(val_s)
if line:
if line.fees:
for f in line.fees:
if f.type == 'ordered':
val = {}
val['fee'] = f.id
val['fee_type'] = f.product.id
val['fee_quantity'] = f.quantity
val['fee_price'] = f.price
val['fee_unit'] = line.unit.id
val['fee_amount'] = f.amount
val['fee_landed_cost'] = f.fee_landed_cost
fee_pur.append(val)
if line.purchase:
Prep = Pool().get('account.invoice')
prep = Prep.search([('description','=','Prepayment'),('party','=',line.purchase.party.id),('state','!=','draft')])
seen_fees = set()
for purchase_line in purchase_lines:
if purchase_line.fees:
for f in purchase_line.fees:
if f.type == 'ordered':
fee_key = getattr(f, 'id', None) or id(f)
if fee_key in seen_fees:
continue
seen_fees.add(fee_key)
val = {}
val['fee'] = f.id
val['fee_type'] = f.product.id
val['fee_quantity'] = f.quantity
val['fee_price'] = f.price
val['fee_unit'] = purchase_line.unit.id
val['fee_amount'] = f.amount
val['fee_landed_cost'] = f.fee_landed_cost
fee_pur.append(val)
if line:
if line.purchase:
Prep = Pool().get('account.invoice')
prep = Prep.search([('description','=','Prepayment'),('party','=',line.purchase.party.id),('state','!=','draft')])
if prep:
for p in prep:
for li in p.lines:
@@ -4760,21 +4781,27 @@ class LotInvoice(Wizard):
val['inv'] = li.id
val['inv_amount'] = li.amount
pp_pur.append(val)
if sale_line:
if sale_line.fees:
for f in sale_line.fees:
if f.type == 'ordered':
val = {}
val['fee'] = f.id
val['fee_type'] = f.product.id
val['fee_quantity'] = f.quantity
val['fee_price'] = f.price
val['fee_unit'] = sale_line.unit.id
val['fee_amount'] = f.amount
val['fee_landed_cost'] = f.fee_landed_cost
fee_sale.append(val)
if sale_line.sale:
Prep = Pool().get('account.invoice')
seen_fees = set()
for current_sale_line in sale_lines:
if current_sale_line.fees:
for f in current_sale_line.fees:
if f.type == 'ordered':
fee_key = getattr(f, 'id', None) or id(f)
if fee_key in seen_fees:
continue
seen_fees.add(fee_key)
val = {}
val['fee'] = f.id
val['fee_type'] = f.product.id
val['fee_quantity'] = f.quantity
val['fee_price'] = f.price
val['fee_unit'] = current_sale_line.unit.id
val['fee_amount'] = f.amount
val['fee_landed_cost'] = f.fee_landed_cost
fee_sale.append(val)
if sale_line:
if sale_line.sale:
Prep = Pool().get('account.invoice')
prep = Prep.search([('description','=','Prepayment'),('party','=',sale_line.sale.party.id),('state','!=','draft')])
if prep:
for p in prep:
@@ -4842,10 +4869,33 @@ class LotInvoice(Wizard):
break
if not invoice_line:
raise UserError("No invoice line was generated from the selected lots.")
self._invoice_selected_fees()
self.message.invoice = invoice_line.invoice
return 'message'
def _invoice_selected_fees(self):
Fee = Pool().get('fee.fee')
fee_lines = (
self.inv.fee_pur
if self.inv.type == 'purchase' else self.inv.fee_sale)
fees = []
seen = set()
for line in fee_lines or []:
fee = getattr(line, 'fee', None)
if not getattr(line, 'to_invoice', False) or not fee:
continue
fee_key = getattr(fee, 'id', None) or id(fee)
if fee_key in seen:
continue
seen.add(fee_key)
action = _fee_invoice_action(fee, self.inv.action)
if action == 'already_invoiced':
continue
fees.append(fee)
if fees:
Fee.invoice(fees)
@classmethod
def _split_sale_padding(cls, padding, lots):
padding = Decimal(str(padding or 0))
@@ -4983,19 +5033,31 @@ class LotInvoiceStart(ModelView):
def default_type(cls):
return 'purchase'
class LotInvoicingFee(ModelView):
class LotInvoicingFee(ModelView):
"Fees"
__name__ = "lot.invoicing.fee"
lfs = fields.Many2One('lot.invoice.start',"Invoicing")
fee = fields.Many2One('fee.fee',"Fee")
fee_type = fields.Many2One('product.product',"Fee type")
to_invoice = fields.Boolean("To invoice")
fee_type = fields.Many2One('product.product',"Fee type")
invoice_action = fields.Function(fields.Selection([
('standard', 'Standard invoice'),
('dn_cn', 'DN/CN'),
('already_invoiced', 'Already invoiced'),
], "Invoice action"), 'on_change_with_invoice_action')
to_invoice = fields.Boolean("To invoice", states={
'readonly': Eval('invoice_action') == 'already_invoiced',
}, depends=['invoice_action'])
fee_unit = fields.Many2One('product.uom',"Unit",readonly=True)
fee_quantity = fields.Numeric("Qt",digits=(1,5),readonly=True)
fee_price = fields.Numeric("Price",digits=(1,4),readonly=True)
fee_amount = fields.Numeric("Amount",digits=(1,2),readonly=True)
fee_landed_cost = fields.Boolean("To inventory",readonly=True)
fee_landed_cost = fields.Boolean("To inventory",readonly=True)
@fields.depends('fee', '_parent_lfs.action')
def on_change_with_invoice_action(self, name=None):
action = self.lfs.action if self.lfs else None
return _fee_invoice_action(self.fee, action)
class LotInvoicingInv(ModelView):
"Fees"