From 54309a198031e71adc50ca41f3270454f16c0b3d Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sun, 24 May 2026 19:32:03 +0200 Subject: [PATCH] GR --- modules/purchase_trade/__init__.py | 8 + modules/purchase_trade/ctrm_reporting.py | 439 ++++++++++++++++++ modules/purchase_trade/ctrm_reporting.xml | 84 ++++ .../view/ctrm_accruals_context_form.xml | 18 + .../view/ctrm_accruals_list.xml | 15 + .../view/ctrm_cashflow_context_form.xml | 12 + .../view/ctrm_cashflow_list.xml | 17 + .../ctrm_gl_reconciliation_context_form.xml | 16 + .../view/ctrm_gl_reconciliation_list.xml | 21 + .../view/ctrm_settlements_context_form.xml | 16 + .../view/ctrm_settlements_list.xml | 16 + 11 files changed, 662 insertions(+) create mode 100644 modules/purchase_trade/view/ctrm_accruals_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_accruals_list.xml create mode 100644 modules/purchase_trade/view/ctrm_cashflow_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_cashflow_list.xml create mode 100644 modules/purchase_trade/view/ctrm_gl_reconciliation_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_gl_reconciliation_list.xml create mode 100644 modules/purchase_trade/view/ctrm_settlements_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_settlements_list.xml diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py index 73c378d..2d4749b 100755 --- a/modules/purchase_trade/__init__.py +++ b/modules/purchase_trade/__init__.py @@ -82,6 +82,14 @@ def register(): ctrm_reporting.CTRMContractPerformanceContext, ctrm_reporting.CTRMScheduling, ctrm_reporting.CTRMSchedulingContext, + ctrm_reporting.CTRMAccruals, + ctrm_reporting.CTRMAccrualsContext, + ctrm_reporting.CTRMSettlements, + ctrm_reporting.CTRMSettlementsContext, + ctrm_reporting.CTRMCashFlow, + ctrm_reporting.CTRMCashFlowContext, + ctrm_reporting.CTRMGLReconciliation, + ctrm_reporting.CTRMGLReconciliationContext, configuration.Configuration, pricing.ImportPricesStart, pricing.ImportPricesResult, diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py index 44e7005..12f2f1c 100644 --- a/modules/purchase_trade/ctrm_reporting.py +++ b/modules/purchase_trade/ctrm_reporting.py @@ -1545,3 +1545,442 @@ class CTRMScheduling(ModelSQL, ModelView): Coalesce(lot.lot_qt, 0).as_('quantity'), lot.lot_unit_line.as_('unit'), where=where)) + + +class CTRMFinanceDateContextMixin: + from_date = fields.Date("From Date") + to_date = fields.Date("To Date") + party = fields.Many2One('party.party', "Party") + currency = fields.Many2One('currency.currency', "Currency") + + @classmethod + def default_to_date(cls): + Date = Pool().get('ir.date') + return Date.today() + + +class CTRMAccrualsContext(CTRMFinanceDateContextMixin, ModelView): + "CTRM Accruals Context" + __name__ = 'ctrm.reporting.finance.accruals.context' + + product = fields.Many2One('product.product', "Product") + purchase = fields.Many2One('purchase.purchase', "Purchase") + sale = fields.Many2One('sale.sale', "Sale") + type = fields.Selection([ + (None, ''), + ('physical', 'Physical'), + ('fee', 'Fee'), + ('derivative', 'Derivative'), + ], "Accrual Type") + + +class CTRMAccruals(ModelSQL, ModelView): + "CTRM Accruals" + __name__ = 'ctrm.reporting.finance.accruals' + + valuation_date = fields.Date("Valuation Date") + accrual_type = fields.Selection([ + ('physical', 'Physical'), + ('fee', 'Fee'), + ('derivative', 'Derivative'), + ], "Accrual Type") + lot = fields.Many2One('lot.lot', "Lot") + product = fields.Many2One('product.product', "Product") + party = fields.Many2One('party.party', "Party") + purchase = fields.Many2One('purchase.purchase', "Purchase") + purchase_line = fields.Many2One('purchase.line', "Purchase Line") + sale = fields.Many2One('sale.sale', "Sale") + sale_line = fields.Many2One('sale.line', "Sale Line") + reference = fields.Char("Reference") + quantity = fields.Numeric("Quantity", digits=(16, 5)) + unit = fields.Many2One('product.uom', "Unit") + amount = fields.Numeric("Amount", digits=(16, 2)) + currency = fields.Many2One('currency.currency', "Currency") + state = fields.Char("State") + + @classmethod + def table_query(cls): + pool = Pool() + ValuationLine = pool.get('valuation.valuation.line') + Lot = pool.get('lot.lot') + val = ValuationLine.__table__() + lot = Lot.__table__() + + accrual_type = Case( + (val.type == 'derivative', 'derivative'), + (val.type.in_(['line fee', 'pur. fee', 'sale fee', + 'shipment fee']), 'fee'), + else_='physical') + context = Transaction().context + where = ( + val.type.in_(ALL_VALUATION_TYPES) + & ((val.lot == Null) + | ((lot.invoice_line == Null) + & (lot.sale_invoice_line == Null)))) + if context.get('from_date'): + where &= val.date >= context['from_date'] + if context.get('to_date'): + where &= val.date <= context['to_date'] + if context.get('party'): + where &= val.counterparty == context['party'] + if context.get('currency'): + where &= val.currency == context['currency'] + if context.get('product'): + where &= val.product == context['product'] + if context.get('purchase'): + where &= val.purchase == context['purchase'] + if context.get('sale'): + where &= val.sale == context['sale'] + if context.get('type'): + where &= accrual_type == context['type'] + + return ( + val + .join(lot, 'LEFT', condition=val.lot == lot.id) + .select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + val.id.as_('id'), + val.date.as_('valuation_date'), + accrual_type.as_('accrual_type'), + val.lot.as_('lot'), + val.product.as_('product'), + val.counterparty.as_('party'), + val.purchase.as_('purchase'), + val.line.as_('purchase_line'), + val.sale.as_('sale'), + val.sale_line.as_('sale_line'), + val.reference.as_('reference'), + val.quantity.as_('quantity'), + val.unit.as_('unit'), + val.amount.as_('amount'), + val.currency.as_('currency'), + val.state.as_('state'), + where=where)) + + +class CTRMSettlementsContext(CTRMFinanceDateContextMixin, ModelView): + "CTRM Settlements Context" + __name__ = 'ctrm.reporting.finance.settlements.context' + + invoice_type = fields.Selection([ + (None, ''), + ('in', 'Supplier'), + ('out', 'Customer'), + ], "Invoice Type") + state = fields.Selection([ + (None, ''), + ('draft', 'Draft'), + ('validated', 'Validated'), + ('posted', 'Posted'), + ('paid', 'Paid'), + ('cancelled', 'Cancelled'), + ], "State") + payment_status = fields.Selection([ + (None, ''), + ('not', 'Not Paid'), + ('partial', 'Partially Paid'), + ('paid', 'Paid'), + ], "Payment Status") + + +class CTRMSettlements(ModelSQL, ModelView): + "CTRM Settlements and Invoicing" + __name__ = 'ctrm.reporting.finance.settlements' + + invoice = fields.Many2One('account.invoice', "Invoice") + invoice_type = fields.Selection([ + ('in', 'Supplier'), + ('out', 'Customer'), + ], "Invoice Type") + number = fields.Char("Number") + reference = fields.Char("Reference") + invoice_date = fields.Date("Invoice Date") + party = fields.Many2One('party.party', "Party") + state = fields.Char("State") + currency = fields.Many2One('currency.currency', "Currency") + invoice_amount = fields.Numeric("Invoice Amount", digits=(16, 2)) + paid_amount = fields.Numeric("Paid Amount", digits=(16, 2)) + open_amount = fields.Numeric("Open Amount", digits=(16, 2)) + payment_status = fields.Selection([ + ('not', 'Not Paid'), + ('partial', 'Partially Paid'), + ('paid', 'Paid'), + ], "Payment Status") + move = fields.Many2One('account.move', "Move") + reconciliation = fields.Integer("Reconciliation") + + @classmethod + def table_query(cls): + pool = Pool() + Invoice = pool.get('account.invoice') + InvoicePayment = pool.get('account.invoice-account.move.line') + MoveLine = pool.get('account.move.line') + + invoice = Invoice.__table__() + invoice_payment = InvoicePayment.__table__() + line = MoveLine.__table__() + + amount = Coalesce(invoice.total_amount_cache, 0) + paid = Coalesce(Sum(line.amount_second_currency), 0) + open_amount = amount - paid + payment_status = Case( + (open_amount == 0, 'paid'), + (paid != 0, 'partial'), + else_='not') + + context = Transaction().context + where = invoice.id != Null + if context.get('from_date'): + where &= invoice.invoice_date >= context['from_date'] + if context.get('to_date'): + where &= invoice.invoice_date <= context['to_date'] + if context.get('party'): + where &= invoice.party == context['party'] + if context.get('currency'): + where &= invoice.currency == context['currency'] + if context.get('invoice_type'): + where &= invoice.type == context['invoice_type'] + if context.get('state'): + where &= invoice.state == context['state'] + + grouped = ( + invoice + .join(invoice_payment, 'LEFT', + condition=invoice_payment.invoice == invoice.id) + .join(line, 'LEFT', + condition=line.id == invoice_payment.line) + .select( + invoice.id.as_('id'), + invoice.id.as_('invoice'), + invoice.type.as_('invoice_type'), + invoice.number.as_('number'), + invoice.reference.as_('reference'), + invoice.invoice_date.as_('invoice_date'), + invoice.party.as_('party'), + invoice.state.as_('state'), + invoice.currency.as_('currency'), + amount.as_('invoice_amount'), + paid.as_('paid_amount'), + open_amount.as_('open_amount'), + payment_status.as_('payment_status'), + invoice.move.as_('move'), + Max(line.reconciliation).as_('reconciliation'), + where=where, + group_by=[ + invoice.id, invoice.type, invoice.number, + invoice.reference, invoice.invoice_date, invoice.party, + invoice.state, invoice.currency, + invoice.total_amount_cache, invoice.move, + ])) + outer_where = grouped.id != Null + if context.get('payment_status'): + outer_where &= grouped.payment_status == context['payment_status'] + + return grouped.select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + grouped.id.as_('id'), + grouped.invoice.as_('invoice'), + grouped.invoice_type.as_('invoice_type'), + grouped.number.as_('number'), + grouped.reference.as_('reference'), + grouped.invoice_date.as_('invoice_date'), + grouped.party.as_('party'), + grouped.state.as_('state'), + grouped.currency.as_('currency'), + grouped.invoice_amount.as_('invoice_amount'), + grouped.paid_amount.as_('paid_amount'), + grouped.open_amount.as_('open_amount'), + grouped.payment_status.as_('payment_status'), + grouped.move.as_('move'), + grouped.reconciliation.as_('reconciliation'), + where=outer_where) + + +class CTRMCashFlowContext(CTRMFinanceDateContextMixin, ModelView): + "CTRM Cash Flow Context" + __name__ = 'ctrm.reporting.finance.cashflow.context' + + overdue_only = fields.Boolean("Overdue Only") + + +class CTRMCashFlow(ModelSQL, ModelView): + "CTRM Cash Flow Forecast" + __name__ = 'ctrm.reporting.finance.cashflow' + + move_line = fields.Many2One('account.move.line', "Move Line") + move = fields.Many2One('account.move', "Move") + due_date = fields.Date("Due Date") + posting_date = fields.Date("Posting Date") + party = fields.Many2One('party.party', "Party") + account = fields.Many2One('account.account', "Account") + currency = fields.Many2One('currency.currency', "Currency") + amount = fields.Numeric("Amount", digits=(16, 2)) + debit = fields.Numeric("Debit", digits=(16, 2)) + credit = fields.Numeric("Credit", digits=(16, 2)) + second_currency = fields.Many2One('currency.currency', "Second Currency") + amount_second_currency = fields.Numeric( + "Amount Second Currency", digits=(16, 2)) + description = fields.Char("Description") + reference = fields.Char("Reference") + journal = fields.Many2One('account.journal', "Journal") + + @classmethod + def table_query(cls): + pool = Pool() + MoveLine = pool.get('account.move.line') + Move = pool.get('account.move') + Company = pool.get('company.company') + + line = MoveLine.__table__() + move = Move.__table__() + company = Company.__table__() + currency = Coalesce(line.second_currency, company.currency) + amount = Coalesce(line.debit, 0) - Coalesce(line.credit, 0) + + context = Transaction().context + where = ( + (line.reconciliation == Null) + & (line.maturity_date != Null)) + if context.get('from_date'): + where &= line.maturity_date >= context['from_date'] + if context.get('to_date'): + where &= line.maturity_date <= context['to_date'] + if context.get('party'): + where &= line.party == context['party'] + if context.get('currency'): + where &= currency == context['currency'] + if context.get('overdue_only'): + Date = Pool().get('ir.date') + where &= line.maturity_date < Date.today() + + return ( + line + .join(move, condition=line.move == move.id) + .join(company, condition=move.company == company.id) + .select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + line.id.as_('id'), + line.id.as_('move_line'), + line.move.as_('move'), + line.maturity_date.as_('due_date'), + move.date.as_('posting_date'), + line.party.as_('party'), + line.account.as_('account'), + currency.as_('currency'), + amount.as_('amount'), + line.debit.as_('debit'), + line.credit.as_('credit'), + line.second_currency.as_('second_currency'), + line.amount_second_currency.as_('amount_second_currency'), + line.description.as_('description'), + Coalesce(line.ext_ref, move.ext_ref).as_('reference'), + move.journal.as_('journal'), + where=where)) + + +class CTRMGLReconciliationContext(CTRMFinanceDateContextMixin, ModelView): + "CTRM GL Reconciliation Context" + __name__ = 'ctrm.reporting.finance.gl.context' + + account = fields.Many2One('account.account', "Account") + lot = fields.Many2One('lot.lot', "Lot") + unreconciled_only = fields.Boolean("Unreconciled Only") + + +class CTRMGLReconciliation(ModelSQL, ModelView): + "CTRM GL Reconciliation" + __name__ = 'ctrm.reporting.finance.gl' + + move_line = fields.Many2One('account.move.line', "Move Line") + move = fields.Many2One('account.move', "Move") + posting_date = fields.Date("Posting Date") + journal = fields.Many2One('account.journal', "Journal") + account = fields.Many2One('account.account', "Account") + party = fields.Many2One('party.party', "Party") + lot = fields.Many2One('lot.lot', "Lot") + fee = fields.Many2One('fee.fee', "Fee") + invoice = fields.Many2One('account.invoice', "Invoice") + currency = fields.Many2One('currency.currency', "Currency") + debit = fields.Numeric("Debit", digits=(16, 2)) + credit = fields.Numeric("Credit", digits=(16, 2)) + balance = fields.Numeric("Balance", digits=(16, 2)) + second_currency = fields.Many2One('currency.currency', "Second Currency") + amount_second_currency = fields.Numeric( + "Amount Second Currency", digits=(16, 2)) + reconciliation = fields.Integer("Reconciliation") + move_state = fields.Char("Move State") + description = fields.Char("Description") + reference = fields.Char("Reference") + + @classmethod + def table_query(cls): + pool = Pool() + MoveLine = pool.get('account.move.line') + Move = pool.get('account.move') + Invoice = pool.get('account.invoice') + Company = pool.get('company.company') + + line = MoveLine.__table__() + move = Move.__table__() + invoice = Invoice.__table__() + company = Company.__table__() + currency = Coalesce(line.second_currency, company.currency) + balance = Coalesce(line.debit, 0) - Coalesce(line.credit, 0) + + context = Transaction().context + where = (line.lot != Null) | (line.fee != Null) | (invoice.id != Null) + if context.get('from_date'): + where &= move.date >= context['from_date'] + if context.get('to_date'): + where &= move.date <= context['to_date'] + if context.get('party'): + where &= line.party == context['party'] + if context.get('currency'): + where &= currency == context['currency'] + if context.get('account'): + where &= line.account == context['account'] + if context.get('lot'): + where &= line.lot == context['lot'] + if context.get('unreconciled_only'): + where &= line.reconciliation == Null + + return ( + line + .join(move, condition=line.move == move.id) + .join(company, condition=move.company == company.id) + .join(invoice, 'LEFT', condition=invoice.move == move.id) + .select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + line.id.as_('id'), + line.id.as_('move_line'), + line.move.as_('move'), + move.date.as_('posting_date'), + move.journal.as_('journal'), + line.account.as_('account'), + line.party.as_('party'), + line.lot.as_('lot'), + line.fee.as_('fee'), + invoice.id.as_('invoice'), + currency.as_('currency'), + line.debit.as_('debit'), + line.credit.as_('credit'), + balance.as_('balance'), + line.second_currency.as_('second_currency'), + line.amount_second_currency.as_('amount_second_currency'), + line.reconciliation.as_('reconciliation'), + move.state.as_('move_state'), + line.description.as_('description'), + Coalesce(line.ext_ref, move.ext_ref).as_('reference'), + where=where)) diff --git a/modules/purchase_trade/ctrm_reporting.xml b/modules/purchase_trade/ctrm_reporting.xml index 1d3482f..e78941b 100644 --- a/modules/purchase_trade/ctrm_reporting.xml +++ b/modules/purchase_trade/ctrm_reporting.xml @@ -240,6 +240,86 @@ + + ctrm.reporting.finance.accruals.context + form + ctrm_accruals_context_form + + + ctrm.reporting.finance.accruals + tree + ctrm_accruals_list + + + Accruals + ctrm.reporting.finance.accruals + ctrm.reporting.finance.accruals.context + + + + + + + + ctrm.reporting.finance.settlements.context + form + ctrm_settlements_context_form + + + ctrm.reporting.finance.settlements + tree + ctrm_settlements_list + + + Settlements and Invoicing + ctrm.reporting.finance.settlements + ctrm.reporting.finance.settlements.context + + + + + + + + ctrm.reporting.finance.cashflow.context + form + ctrm_cashflow_context_form + + + ctrm.reporting.finance.cashflow + tree + ctrm_cashflow_list + + + Cash Flow Forecast + ctrm.reporting.finance.cashflow + ctrm.reporting.finance.cashflow.context + + + + + + + + ctrm.reporting.finance.gl.context + form + ctrm_gl_reconciliation_context_form + + + ctrm.reporting.finance.gl + tree + ctrm_gl_reconciliation_list + + + GL Reconciliation + ctrm.reporting.finance.gl + ctrm.reporting.finance.gl.context + + + + + + diff --git a/modules/purchase_trade/view/ctrm_accruals_context_form.xml b/modules/purchase_trade/view/ctrm_accruals_context_form.xml new file mode 100644 index 0000000..ab1dbc6 --- /dev/null +++ b/modules/purchase_trade/view/ctrm_accruals_context_form.xml @@ -0,0 +1,18 @@ +
+