Pnl graph
This commit is contained in:
@@ -185,12 +185,13 @@ def register():
|
||||
derivative.DerivativeReportContext,
|
||||
fee.FeeReport,
|
||||
fee.FeeContext,
|
||||
forex.ForexCoverPhysicalContract,
|
||||
forex.PForex,
|
||||
forex.ForexBI,
|
||||
purchase.PnlBI,
|
||||
purchase.PositionBI,
|
||||
stock.Move,
|
||||
forex.ForexCoverPhysicalContract,
|
||||
forex.PForex,
|
||||
forex.ForexBI,
|
||||
purchase.PurchasePnlGraph,
|
||||
purchase.PnlBI,
|
||||
purchase.PositionBI,
|
||||
stock.Move,
|
||||
stock.Location,
|
||||
stock.InvoiceLine,
|
||||
stock.ShipmentIn,
|
||||
|
||||
@@ -11,7 +11,7 @@ from trytond.tools import (cursor_dict, is_full_text, lstrip_wildcard)
|
||||
from trytond.transaction import Transaction, inactive_records
|
||||
from decimal import getcontext, Decimal, ROUND_HALF_UP
|
||||
from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr
|
||||
from sql.conditionals import Case
|
||||
from sql.conditionals import Case, Coalesce
|
||||
from sql import Column, Literal
|
||||
from sql.functions import CurrentTimestamp, DateTrunc, Abs
|
||||
from trytond.wizard import Button, StateTransition, StateView, Wizard, StateAction
|
||||
@@ -370,11 +370,13 @@ class Purchase(metaclass=PoolMeta):
|
||||
wb = fields.Many2One('purchase.weight.basis',"Weight basis", required=True)
|
||||
association = fields.Many2One('purchase.association',"Association", required=True,states={'invisible': Eval('company_visible'),})
|
||||
crop = fields.Many2One('purchase.crop',"Crop",states={'invisible': Eval('company_visible'),})
|
||||
pnl = fields.One2Many('valuation.valuation.dyn', 'r_purchase', 'Pnl',states={'invisible': ~Eval('group_pnl'),})
|
||||
pnl_ = fields.One2Many('valuation.valuation.line', 'purchase', 'Pnl',states={'invisible': Eval('group_pnl'),})
|
||||
derivatives = fields.One2Many('derivative.derivative', 'purchase', 'Derivative')
|
||||
plans = fields.One2Many('workflow.plan','purchase',"Execution plans")
|
||||
forex = fields.One2Many('forex.cover.physical.contract','contract',"Forex",readonly=True)
|
||||
pnl = fields.One2Many('valuation.valuation.dyn', 'r_purchase', 'Pnl',states={'invisible': ~Eval('group_pnl'),})
|
||||
pnl_ = fields.One2Many('valuation.valuation.line', 'purchase', 'Pnl',states={'invisible': Eval('group_pnl'),})
|
||||
pnl_graph = fields.One2Many(
|
||||
'purchase.pnl.graph', 'purchase', 'Pnl graph')
|
||||
derivatives = fields.One2Many('derivative.derivative', 'purchase', 'Derivative')
|
||||
plans = fields.One2Many('workflow.plan','purchase',"Execution plans")
|
||||
forex = fields.One2Many('forex.cover.physical.contract','contract',"Forex",readonly=True)
|
||||
plan = fields.Many2One('workflow.plan',"Name")
|
||||
estimated_date = fields.One2Many('pricing.estimated','purchase',"Estimated date")
|
||||
group_pnl = fields.Boolean("Group Pnl")
|
||||
@@ -3319,9 +3321,9 @@ class GoToBi(Wizard):
|
||||
action['url'] = config.bi + '/dashboard/6-pnl?lot=&product=&purchase='+ ct_number + '&sale='
|
||||
return action, {}
|
||||
|
||||
class PurchaseAllocationsWizard(Wizard):
|
||||
'Open Allocations report from Purchase without modal'
|
||||
__name__ = 'purchase.allocations.wizard'
|
||||
class PurchaseAllocationsWizard(Wizard):
|
||||
'Open Allocations report from Purchase without modal'
|
||||
__name__ = 'purchase.allocations.wizard'
|
||||
|
||||
start_state = 'open_report'
|
||||
|
||||
@@ -3334,11 +3336,45 @@ class PurchaseAllocationsWizard(Wizard):
|
||||
action['context_model'] = 'lot.context'
|
||||
action['pyson_context'] = PYSONEncoder().encode({
|
||||
'purchase': purchase_id,
|
||||
})
|
||||
return action, {}
|
||||
|
||||
class PurchaseInvoiceReport(
|
||||
ModelSQL, ModelView):
|
||||
})
|
||||
return action, {}
|
||||
|
||||
|
||||
class PurchasePnlGraph(ModelSQL, ModelView):
|
||||
"Purchase Pnl graph"
|
||||
__name__ = 'purchase.pnl.graph'
|
||||
|
||||
purchase = fields.Many2One('purchase.purchase', "Purchase")
|
||||
valuation_date = fields.Date("Valuation Date")
|
||||
pnl = fields.Numeric("Pnl", digits=(16, 2))
|
||||
mtm = fields.Numeric("Mtm", digits=(16, 2))
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls._order.insert(0, ('valuation_date', 'ASC'))
|
||||
|
||||
@classmethod
|
||||
def table_query(cls):
|
||||
Valuation = Pool().get('valuation.valuation')
|
||||
val = Valuation.__table__()
|
||||
return val.select(
|
||||
Literal(0).as_('create_uid'),
|
||||
CurrentTimestamp().as_('create_date'),
|
||||
Literal(None).as_('write_uid'),
|
||||
Literal(None).as_('write_date'),
|
||||
Max(val.id).as_('id'),
|
||||
val.purchase.as_('purchase'),
|
||||
val.date.as_('valuation_date'),
|
||||
Sum(Coalesce(val.pnl, 0)).as_('pnl'),
|
||||
Sum(Coalesce(val.mtm, 0)).as_('mtm'),
|
||||
where=(val.purchase != None),
|
||||
group_by=[val.purchase, val.date],
|
||||
order_by=[val.date.asc])
|
||||
|
||||
|
||||
class PurchaseInvoiceReport(
|
||||
ModelSQL, ModelView):
|
||||
"Purchase invoices"
|
||||
__name__ = 'purchase.invoice.report'
|
||||
r_supplier = fields.Many2One('party.party',"Supplier")
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from contextlib import nullcontext
|
||||
from decimal import Decimal
|
||||
from types import SimpleNamespace
|
||||
@@ -5252,6 +5253,24 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
self.assertEqual(
|
||||
ShipmentIn.operator.domain, [('categories.name', '=', 'OPERATOR')])
|
||||
|
||||
def test_purchase_form_has_pnl_graph_tab_after_pnl(self):
|
||||
'purchase form exposes a rich graph for historical PnL and MTM'
|
||||
path = Path('modules/purchase_trade/view/purchase_form.xml')
|
||||
root = ElementTree.parse(path).getroot()
|
||||
pages = root.findall(".//xpath[@expr=\"/form/notebook/page[@id='info']\"]//page")
|
||||
page_ids = [page.get('id') for page in pages]
|
||||
pnl_index = page_ids.index('pnl')
|
||||
|
||||
self.assertEqual(page_ids[pnl_index + 1], 'pnl_graph')
|
||||
|
||||
graph_field = pages[pnl_index + 1].find("field[@name='pnl_graph']")
|
||||
self.assertIsNotNone(graph_field)
|
||||
self.assertEqual(graph_field.get('widget'), 'rich_graph')
|
||||
self.assertEqual(graph_field.get('date_field'), 'valuation_date')
|
||||
self.assertEqual(graph_field.get('series'), 'pnl,mtm')
|
||||
self.assertEqual(graph_field.get('labels'), 'pnl:Pnl,mtm:Mtm')
|
||||
self.assertIsNone(graph_field.get('hidden_series'))
|
||||
|
||||
def test_shipment_in_pnl_lines_use_physical_and_open_lots(self):
|
||||
'shipment PnL uses valuation lines from physical and open lot links'
|
||||
ShipmentIn = Pool().get('stock.shipment.in')
|
||||
|
||||
@@ -149,13 +149,23 @@ this repository contains the full copyright notices and license terms. -->
|
||||
<page string="Forex" col="4" id="fo">
|
||||
<field name="forex" mode="tree" view_ids="purchase_trade.view_forex_cover_physical_contract_tree2"/>
|
||||
</page>
|
||||
<page string="Pnl" col="4" >
|
||||
<page string="Pnl" col="4" id="pnl">
|
||||
<label name="group_pnl"/>
|
||||
<field name="group_pnl" colspan="1"/>
|
||||
<newline/>
|
||||
<field name="pnl_" mode="tree,graph,graph" view_ids="purchase_trade.valuation_view_tree_sequence3,purchase_trade.valuation_view_graph,purchase_trade.valuation_view_graph2" height="450" colspan="4"/>
|
||||
<field name="pnl" mode="tree" view_ids="purchase_trade.valuation_view_tree_sequence4" height="450" colspan="4"/>
|
||||
</page>
|
||||
<page string="Pnl graph" col="4" id="pnl_graph">
|
||||
<field name="pnl_graph"
|
||||
widget="rich_graph"
|
||||
date_field="valuation_date"
|
||||
series="pnl,mtm"
|
||||
labels="pnl:Pnl,mtm:Mtm"
|
||||
colors="pnl:#00b894,mtm:#8b5cf6"
|
||||
height="360"
|
||||
colspan="4"/>
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="/form/notebook/page[@id='info']/label[@name='invoice_party']" position="before">
|
||||
<field name="bank_accounts" colspan="4" invisible="1"/>
|
||||
|
||||
Reference in New Issue
Block a user