Fee report

This commit is contained in:
2026-06-17 11:25:33 +02:00
parent 02e5c43f3d
commit 8441bf98e7
5 changed files with 85 additions and 27 deletions

View File

@@ -9,7 +9,7 @@ from trytond.transaction import Transaction, inactive_records
from decimal import getcontext, Decimal, ROUND_UP, ROUND_HALF_UP
from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr
from sql.conditionals import Case
from sql import Column, Literal
from sql import Column, Literal, Null
from sql.functions import CurrentTimestamp, DateTrunc
from trytond.wizard import Button, StateTransition, StateView, Wizard
from itertools import chain, groupby
@@ -1513,8 +1513,8 @@ class FeeLots(ModelSQL,ModelView):
Fee._regenerate_fee_pnl(
fees=Fee.browse(list(fee_ids)), lots=lots)
class FeeReport(
ModelSQL, ModelView):
class FeeReport(
ModelSQL, ModelView):
"Fee Report"
__name__ = 'fee.report'
r_purchase_line = fields.Many2One('purchase.line', "Purchase line")
@@ -1543,12 +1543,14 @@ class FeeReport(
r_fee_quantity = fields.Function(fields.Numeric("Qt",digits=(1,4)),'get_quantity')
r_fee_unit = fields.Function(fields.Many2One('product.uom',"Unit"),'get_unit')
r_purchase = fields.Many2One('purchase.purchase',"Purchase", ondelete='CASCADE')
r_fee_amount = fields.Function(fields.Numeric("Amount", digits=(1,4)),'get_amount')
r_inv = fields.Function(fields.Many2One('account.invoice',"Invoice"),'get_invoice')
r_state = fields.Selection([
('not invoiced', 'Not invoiced'),
('invoiced', 'Invoiced'),
], string='State', readonly=True)
r_fee_amount = fields.Function(fields.Numeric("Amount", digits=(1,4)),'get_amount')
r_inv = fields.Function(fields.Many2One('account.invoice',"Invoice"),'get_invoice')
r_dn_cn = fields.Function(fields.Many2One('account.invoice',"DN/CN"),
'get_dn_cn')
r_state = fields.Selection([
('not invoiced', 'Not invoiced'),
('invoiced', 'Invoiced'),
], string='State', readonly=True)
#r_fee_lots = fields.Function(fields.Many2Many('lot.lot', None, None, "Lots"),'get_lots')#, searcher='search_lots')
#r_lots = fields.Many2Many('fee.lots', 'fee', 'lot',"Lots",domain=[('id', 'in', Eval('r_fee_lots',[]))] )
@@ -1566,10 +1568,17 @@ class FeeReport(
"get_shipment_origin",
)
def get_invoice(self,name):
if self.r_purchase:
if self.r_purchase.invoices:
return self.r_purchase.invoices[0]
def get_invoice(self,name):
Fee = Pool().get('fee.fee')
fee = Fee(self.id)
invoice = fee.get_invoice(name)
return getattr(invoice, 'id', invoice)
def get_dn_cn(self, name):
Fee = Pool().get('fee.fee')
fee = Fee(self.id)
dn_cn = getattr(fee, 'dn_cn', None)
return getattr(dn_cn, 'id', dn_cn)
def get_shipment_origin(self, name):
if self.r_shipment_in:
@@ -1595,10 +1604,16 @@ class FeeReport(
fee = Fee(self.id)
return fee.get_quantity()
def get_amount(self,name=None):
Fee = Pool().get('fee.fee')
fee = Fee(self.id)
return fee.get_amount()
def get_amount(self,name=None):
Fee = Pool().get('fee.fee')
fee = Fee(self.id)
return fee.get_amount()
@classmethod
@ModelView.button
def invoice(cls, reports):
Fee = Pool().get('fee.fee')
Fee.invoice(Fee.browse([report.id for report in reports]))
@classmethod
def table_query(cls):
@@ -1620,10 +1635,11 @@ class FeeReport(
sale = context.get('sale')
shipment_in = context.get('shipment_in')
shipment_out = context.get('shipment_out')
shipment_internal = context.get('shipment_internal')
asof = context.get('asof')
todate = context.get('todate')
wh = ((fr.create_date >= asof) & ((fr.create_date-datetime.timedelta(1)) <= todate))
shipment_internal = context.get('shipment_internal')
invoice_status = context.get('invoice_status')
asof = context.get('asof')
todate = context.get('todate')
wh = ((fr.create_date >= asof) & ((fr.create_date-datetime.timedelta(1)) <= todate))
if party:
wh &= (fr.fee_counterparty == party)
if fee_type:
@@ -1632,8 +1648,14 @@ class FeeReport(
wh &= (pu.id == purchase)
if sale:
wh &= (sa.id == sale)
if shipment_in:
wh &= (fr.shipment_in == shipment_in)
if shipment_in:
wh &= (fr.shipment_in == shipment_in)
if invoice_status == 'not_invoiced':
wh &= (fr.state == 'not invoiced')
elif invoice_status == 'invoiced_without_dn_cn':
wh &= ((fr.state == 'invoiced') & (fr.dn_cn == Null))
elif invoice_status == 'invoiced_with_dn_cn':
wh &= ((fr.state == 'invoiced') & (fr.dn_cn != Null))
# if shipment_out:
# wh &= (fr.shipment_out == shipment_out)
@@ -1679,15 +1701,21 @@ class FeeReport(
('r_fee_counterparty', operator, operand, *extra),
]
class FeeContext(ModelView):
class FeeContext(ModelView):
"Fee Context"
__name__ = 'fee.context'
asof = fields.Date("As of")
todate = fields.Date("To")
party = fields.Many2One('party.party', "Counterparty")
fee_type = fields.Many2One('product.product', 'Fee type')
purchase = fields.Many2One('purchase.purchase', "Purchase")
fee_type = fields.Many2One('product.product', 'Fee type')
invoice_status = fields.Selection([
(None, ''),
('not_invoiced', 'Not invoiced'),
('invoiced_without_dn_cn', 'Invoiced without DN/CN'),
('invoiced_with_dn_cn', 'Invoiced with DN/CN'),
], "Invoice status")
purchase = fields.Many2One('purchase.purchase', "Purchase")
sale = fields.Many2One('sale.sale', "Sale")
shipment_in = fields.Many2One('stock.shipment.in',"Shipment In")
shipment_out = fields.Many2One('stock.shipment.out',"Shipment Out")

View File

@@ -80,6 +80,15 @@ this repository contains the full copyright notices and license terms. -->
<field name="button" ref="fee_invoice_button"/>
<field name="group" ref="purchase.group_purchase"/>
</record>
<record model="ir.model.button" id="fee_report_invoice_button">
<field name="model">fee.report</field>
<field name="name">invoice</field>
<field name="string">Invoice</field>
</record>
<record model="ir.model.button-res.group" id="fee_report_invoice_button_group_admin">
<field name="button" ref="fee_report_invoice_button"/>
<field name="group" ref="purchase.group_purchase"/>
</record>
<record model="ir.model.button" id="purchase_line_apply_default_fees_button">
<field name="model">purchase.line</field>
<field name="name">apply_default_fees</field>

View File

@@ -5537,6 +5537,23 @@ class PurchaseTradeTestCase(ModuleTestCase):
self.assertEqual(Fee._get_generated_purchases_to_delete([fee]), [])
def test_fee_report_invoice_delegates_to_fee_invoice(self):
'fee report invoice button invoices the underlying fees'
FeeReport = Pool().get('fee.report')
report = FeeReport()
report.id = 10
fee_model = Mock()
fees = [Mock(id=10)]
fee_model.browse.return_value = fees
with patch('trytond.modules.purchase_trade.fee.Pool') as PoolMock:
PoolMock.return_value.get.return_value = fee_model
FeeReport.invoice([report])
fee_model.browse.assert_called_once_with([10])
fee_model.invoice.assert_called_once_with(fees)
def test_sale_report_converts_mixed_units_for_total_and_words(self):
'sale report totals prefer the virtual lot unit as common unit'
Sale = Pool().get('sale.sale')

View File

@@ -7,6 +7,8 @@
<field name="party"/>
<label name="fee_type"/>
<field name="fee_type"/>
<label name="invoice_status"/>
<field name="invoice_status"/>
<label name="purchase"/>
<field name="purchase"/>
<label name="sale"/>

View File

@@ -1,4 +1,5 @@
<tree>
<button name="invoice" string="Invoice"/>
<field name="r_purchase_line" width="90"/>
<field name="r_shipment_origin" width="120"/>
<field name="r_fee_type" width="120"/>
@@ -9,5 +10,6 @@
<field name="r_fee_currency" width="60"/>
<field name="r_fee_amount" width="100" sum="1"/>
<field name="r_state" width="80"/>
<field name="r_inv" width="80"/>
<field name="r_inv" width="90"/>
<field name="r_dn_cn" width="90"/>
</tree>