Padding report

This commit is contained in:
2026-04-27 20:09:36 +02:00
parent 308252215f
commit 384c1285b1
6 changed files with 234 additions and 1 deletions

View File

@@ -165,7 +165,9 @@ de negoce physique:
`docs/template-rules.md`. `docs/template-rules.md`.
6. Pour les vues XML Tryton de ce module, utiliser `editable="1"` sur les 6. Pour les vues XML Tryton de ce module, utiliser `editable="1"` sur les
`<tree>` editables; ne pas utiliser `editable="bottom"`. `<tree>` editables; ne pas utiliser `editable="bottom"`.
7. Si une regle de texte par defaut durable est demandee sur achat/vente, 7. Ne pas ajouter `keyword_open` / `open_keyword` sur les vues `<tree>`:
ces attributs ne sont pas supportes par Tryton.
8. Si une regle de texte par defaut durable est demandee sur achat/vente,
preferer un singleton de configuration expose dans un menu fonctionnel preferer un singleton de configuration expose dans un menu fonctionnel
existant plutot qu'un menu technique `purchase_trade`. existant plutot qu'un menu technique `purchase_trade`.

View File

@@ -196,6 +196,8 @@ def register():
Pool.register( Pool.register(
configuration.AccountConfiguration, configuration.AccountConfiguration,
configuration.AccountConfigurationDefaultAccount, configuration.AccountConfigurationDefaultAccount,
invoice.InvoicePaddingReport,
invoice.InvoicePaddingContext,
module='purchase_trade', type_='model') module='purchase_trade', type_='model')
Pool.register( Pool.register(
invoice.Invoice, invoice.Invoice,

View File

@@ -1,6 +1,11 @@
from decimal import Decimal, ROUND_HALF_UP from decimal import Decimal, ROUND_HALF_UP
from datetime import date as dt_date from datetime import date as dt_date
from sql import Literal
from sql.conditionals import Case
from sql.functions import CurrentTimestamp
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool, PoolMeta from trytond.pool import Pool, PoolMeta
from trytond.modules.purchase_trade.numbers_to_words import amount_to_currency_words from trytond.modules.purchase_trade.numbers_to_words import amount_to_currency_words
from trytond.exceptions import UserError from trytond.exceptions import UserError
@@ -123,6 +128,7 @@ class Invoice(metaclass=PoolMeta):
for move_line in (sale_line, accrual_line): for move_line in (sale_line, accrual_line):
move_line.lot = lot move_line.lot = lot
move_line.origin = invoice_line move_line.origin = invoice_line
move_line.description = 'Padding'
if not reversal: if not reversal:
sale_line.account = sale_account sale_line.account = sale_account
@@ -187,6 +193,7 @@ class Invoice(metaclass=PoolMeta):
self.additional_moves = tuple(self.additional_moves or ()) + (move,) self.additional_moves = tuple(self.additional_moves or ()) + (move,)
return [move] return [move]
@staticmethod @staticmethod
def _format_report_number(value, digits='0.0000', keep_trailing_decimal=False, def _format_report_number(value, digits='0.0000', keep_trailing_decimal=False,
strip_trailing_zeros=True): strip_trailing_zeros=True):
@@ -1261,6 +1268,167 @@ class Invoice(metaclass=PoolMeta):
return 'USD' return 'USD'
class InvoicePaddingReport(ModelSQL, ModelView):
"Invoice with padding"
__name__ = 'invoice.padding.report'
party = fields.Many2One('party.party', "Party")
sale = fields.Many2One('sale.sale', "Sale")
sale_line = fields.Many2One('sale.line', "Sale Line")
lot = fields.Many2One('lot.lot', "Lot")
product = fields.Many2One('product.product', "Product")
currency = fields.Many2One('currency.currency', "Currency")
unit = fields.Many2One('product.uom', "Unit")
padding_quantity = fields.Numeric("Padding Quantity", digits='unit')
unit_price = fields.Numeric("Unit Price", digits=(16, 6))
padding_amount = fields.Numeric("Padding Amount", digits=(16, 2))
provisional_invoice = fields.Many2One(
'account.invoice', "Provisional Invoice")
provisional_date = fields.Date("Provisional Date")
provisional_state = fields.Selection([
('draft', "Draft"),
('validated', "Validated"),
('posted', "Posted"),
('paid', "Paid"),
('cancelled', "Cancelled"),
], "Provisional State")
final_invoice = fields.Many2One('account.invoice', "Final Invoice")
final_date = fields.Date("Final Date")
final_state = fields.Selection([
(None, ''),
('draft', "Draft"),
('validated', "Validated"),
('posted', "Posted"),
('paid', "Paid"),
('cancelled', "Cancelled"),
], "Final State")
padding_status = fields.Selection([
('active', "Active"),
('reversed', "Reversed"),
], "Padding Status")
@classmethod
def table_query(cls):
pool = Pool()
Lot = pool.get('lot.lot')
SaleLine = pool.get('sale.line')
Sale = pool.get('sale.sale')
InvoiceLine = pool.get('account.invoice.line')
Invoice = pool.get('account.invoice')
lot = Lot.__table__()
sale_line = SaleLine.__table__()
sale = Sale.__table__()
prov_line = InvoiceLine.__table__()
prov_invoice = Invoice.__table__()
final_line = InvoiceLine.__table__()
final_invoice = Invoice.__table__()
context = Transaction().context
party = context.get('party')
currency = context.get('currency')
status_filter = context.get('status')
from_date = context.get('from_date')
to_date = context.get('to_date')
sale_filter = context.get('sale')
lot_filter = context.get('lot')
reversed_condition = (
(final_invoice.id > 0)
& ~final_invoice.state.in_(['draft', 'cancelled']))
padding_status = Case(
(reversed_condition, 'reversed'),
else_='active')
where = Literal(True)
where &= lot.sale_invoice_padding > 0
where &= prov_invoice.id > 0
if party:
where &= prov_invoice.party == party
if currency:
where &= prov_invoice.currency == currency
if status_filter and status_filter != 'all':
where &= padding_status == status_filter
if from_date:
where &= prov_invoice.invoice_date >= from_date
if to_date:
where &= prov_invoice.invoice_date <= to_date
if sale_filter:
where &= sale.id == sale_filter
if lot_filter:
where &= lot.id == lot_filter
return (
lot
.join(sale_line, 'LEFT', condition=lot.sale_line == sale_line.id)
.join(sale, 'LEFT', condition=sale_line.sale == sale.id)
.join(prov_line, 'LEFT',
condition=lot.sale_invoice_line_prov == prov_line.id)
.join(prov_invoice, 'LEFT',
condition=prov_line.invoice == prov_invoice.id)
.join(final_line, 'LEFT',
condition=lot.sale_invoice_line == final_line.id)
.join(final_invoice, 'LEFT',
condition=final_line.invoice == final_invoice.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(0).as_('write_uid'),
Literal(None).as_('write_date'),
lot.id.as_('id'),
prov_invoice.party.as_('party'),
sale.id.as_('sale'),
sale_line.id.as_('sale_line'),
lot.id.as_('lot'),
prov_line.product.as_('product'),
prov_invoice.currency.as_('currency'),
prov_line.unit.as_('unit'),
lot.sale_invoice_padding.as_('padding_quantity'),
prov_line.unit_price.as_('unit_price'),
(lot.sale_invoice_padding * prov_line.unit_price).as_(
'padding_amount'),
prov_invoice.id.as_('provisional_invoice'),
prov_invoice.invoice_date.as_('provisional_date'),
prov_invoice.state.as_('provisional_state'),
final_invoice.id.as_('final_invoice'),
final_invoice.invoice_date.as_('final_date'),
final_invoice.state.as_('final_state'),
padding_status.as_('padding_status'),
where=where,
))
class InvoicePaddingContext(ModelView):
"Invoice with padding context"
__name__ = 'invoice.padding.context'
from_date = fields.Date("From")
to_date = fields.Date("To")
party = fields.Many2One('party.party', "Party")
currency = fields.Many2One('currency.currency', "Currency")
status = fields.Selection([
('all', "All"),
('active', "Active"),
('reversed', "Reversed"),
], "Status")
sale = fields.Many2One('sale.sale', "Sale")
lot = fields.Many2One('lot.lot', "Lot")
@classmethod
def default_from_date(cls):
Date = Pool().get('ir.date')
return Date.today().replace(day=1, month=1, year=1999)
@classmethod
def default_to_date(cls):
Date = Pool().get('ir.date')
return Date.today()
@classmethod
def default_status(cls):
return 'active'
class InvoiceLine(metaclass=PoolMeta): class InvoiceLine(metaclass=PoolMeta):
__name__ = 'account.invoice.line' __name__ = 'account.invoice.line'

View File

@@ -36,5 +36,31 @@
<field name="model">account.invoice,-1</field> <field name="model">account.invoice,-1</field>
<field name="action" ref="report_payment_order"/> <field name="action" ref="report_payment_order"/>
</record> </record>
<record model="ir.ui.view" id="invoice_padding_context_view_form">
<field name="model">invoice.padding.context</field>
<field name="type">form</field>
<field name="name">invoice_padding_context_form</field>
</record>
<record model="ir.ui.view" id="invoice_padding_report_view_list">
<field name="model">invoice.padding.report</field>
<field name="type">tree</field>
<field name="name">invoice_padding_report_list</field>
</record>
<record model="ir.action.act_window" id="act_invoice_padding_report_form">
<field name="name">Invoice with padding</field>
<field name="res_model">invoice.padding.report</field>
<field name="context_model">invoice.padding.context</field>
</record>
<record model="ir.action.act_window.view" id="act_invoice_padding_report_form_view">
<field name="sequence" eval="70"/>
<field name="view" ref="invoice_padding_report_view_list"/>
<field name="act_window" ref="act_invoice_padding_report_form"/>
</record>
<menuitem
parent="purchase_trade.menu_global_reporting"
sequence="101"
action="act_invoice_padding_report_form"
id="menu_invoice_padding_report_form"/>
</data> </data>
</tryton> </tryton>

View File

@@ -0,0 +1,16 @@
<form>
<label name="from_date"/>
<field name="from_date"/>
<label name="to_date"/>
<field name="to_date"/>
<label name="party"/>
<field name="party"/>
<label name="currency"/>
<field name="currency"/>
<label name="status"/>
<field name="status"/>
<label name="sale"/>
<field name="sale"/>
<label name="lot"/>
<field name="lot"/>
</form>

View File

@@ -0,0 +1,19 @@
<tree>
<field name="party" width="140"/>
<field name="currency" width="60"/>
<field name="sale" width="100"/>
<field name="sale_line" width="100"/>
<field name="lot" width="120"/>
<field name="product" width="140"/>
<field name="padding_status" width="80"/>
<field name="padding_quantity" width="110" sum="1"/>
<field name="unit" width="60"/>
<field name="unit_price" width="90"/>
<field name="padding_amount" width="110" sum="1"/>
<field name="provisional_invoice" width="130"/>
<field name="provisional_date" width="90"/>
<field name="provisional_state" width="90"/>
<field name="final_invoice" width="130"/>
<field name="final_date" width="90"/>
<field name="final_state" width="90"/>
</tree>