diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py index 515cfa3..896bffa 100755 --- a/modules/purchase_trade/__init__.py +++ b/modules/purchase_trade/__init__.py @@ -94,7 +94,8 @@ def register(): fee.Fee, fee.FeeLots, purchase.FeeLots, - valuation.Valuation, + valuation.Valuation, + valuation.ValuationLine, valuation.ValuationDyn, derivative.Derivative, derivative.DerivativeMatch, diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index 24f529d..643e31d 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -252,21 +252,12 @@ class Purchase(metaclass=PoolMeta): broker = fields.Many2One('party.party',"Broker",domain=[('categories.parent', 'child_of', [4])]) tol_min = fields.Numeric("Tol - in %") tol_max = fields.Numeric("Tol + in %") - # certification = fields.Selection([ - # (None, ''), - # ('bci', 'BCI'), - # ],"Certification") certif = fields.Many2One('purchase.certification',"Certification") wb = fields.Many2One('purchase.weight.basis',"Weight basis") association = fields.Many2One('purchase.association',"Association") crop = fields.Many2One('purchase.crop',"Crop") - # weight_basis = fields.Selection([ - # (None, ''), - # ('ncsw', 'NCSW'), - # ('nlw', 'NLW'), - # ], 'Weight basis') pnl = fields.One2Many('valuation.valuation.dyn', 'r_purchase', 'Pnl',states={'invisible': ~Eval('group_pnl'),}) - pnl_ = fields.One2Many('valuation.valuation', '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) @@ -647,358 +638,6 @@ class Line(metaclass=PoolMeta): f.purchase = line.purchase Fee.save([f]) - def get_pnl_der_lines(self): - der_lines = [] - if self.derivatives: - Pnl = Pool().get('valuation.valuation') - Date = Pool().get('ir.date') - for d in self.derivatives: - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.line = self.id - pnl.type = 'derivative' - pnl.date = Date.today() - pnl.reference = d.price_index.price_index - pnl.price = round(Decimal(d.price_index.get_price_per_qt(d.price,self.unit,self.purchase.currency)),4) - pnl.counterparty = d.party - pnl.product = d.product - pnl.state = 'fixed' - pnl.amount = round(pnl.price * (d.quantity) * Decimal(-1),4) - mtm = round(Decimal(d.price_index.get_price(Date.today(),self.unit,self.purchase.currency,True)) * d.quantity * Decimal(-1),4) - pnl.mtm = pnl.amount - mtm - pnl.quantity = round(d.quantity,5) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - der_lines.append(pnl) - return der_lines - - def get_pnl_price_lines(self): - price_lines = [] - Pnl = Pool().get('valuation.valuation') - LotQt = Pool().get('lot.qt') - Date = Pool().get('ir.date') - for lot in self.lots: - logger.info("FROM_VALUATION_TYPE:%s",self.price_type) - if self.price_type == 'basis' and self.price_summary: - for pc in self.price_summary: - #pnl management - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.line = self.id - pnl.type = 'pur. priced' - pnl.date = Date.today() - pnl.lot = lot.id - if lot.sale_line: - pnl.sale = lot.sale_line.sale.id - pnl.reference = pc.get_name() + ' / ' + str(pc.ratio) + '%' - pnl.price = round(pc.price,4) - pnl.counterparty = self.purchase.party - pnl.product = self.product - if pc.unfixed_qt == 0: - pnl.state = 'fixed' - elif pc.fixed_qt == 0: - pnl.state = 'unfixed' - else: - pnl.state = 'part. fixed' + ' ' + str(round(pc.fixed_qt / Decimal(self.quantity_theorical) * 100,0)) + '%' - if pc.price and pc.ratio: - #pnl.amount = round(pc.price * (pc.unfixed_qt + pc.fixed_qt) * Decimal(-1) * pc.ratio / 100,2) - pnl.amount = round(pc.price * lot.get_current_quantity_converted() * Decimal(-1) * pc.ratio / 100,4) - last_price = pc.get_last_price() - mtm = Decimal(0) - if last_price: - mtm = round(Decimal(last_price) * lot.get_current_quantity_converted() * Decimal(-1),4) - pnl.mtm = round(pnl.amount - (mtm * pc.ratio / 100),4) - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - elif self.price_type == 'priced': - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.line = self.id - pnl.type = 'pur. priced' - pnl.date = Date.today() - pnl.lot = lot.id - if lot.sale_line: - pnl.sale = lot.sale_line.sale.id - if lot.lot_type == 'physic': - pnl.reference = 'Purchase/Physic' - else: - pnl.reference = 'Purchase/Open' - if lot.lot_price: - pnl.price = round(lot.lot_price,4) - pnl.counterparty = self.purchase.party - pnl.product = self.product - pnl.state = 'fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity * Decimal(-1),4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - elif self.price_type == 'efp': - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.line = self.id - pnl.type = 'pur. efp' - pnl.date = Date.today() - pnl.lot = lot.id - if lot.sale_line: - pnl.sale = lot.sale_line.sale.id - if lot.lot_type == 'physic': - pnl.reference = 'Purchase/Physic' - else: - pnl.reference = 'Purchase/Open' - if lot.lot_price: - pnl.price = round(lot.lot_price,4) - pnl.counterparty = self.purchase.party - pnl.product = self.product - pnl.state = 'not fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity * Decimal(-1),4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - if lot.sale_line: - sl = lot - if sl.sale_line.price_type == 'basis' and sl.sale_line.price_summary: - for pc in sl.sale_line.price_summary: - #pnl management - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.type = 'sale priced' - pnl.date = Date.today() - pnl.lot = lot.id - pnl.reference = pc.get_name() + ' / ' + str(pc.ratio) + '%' - pnl.price = round(pc.price,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = sl.sale_line.product - if pc.unfixed_qt == 0: - pnl.state = 'fixed' - elif pc.fixed_qt == 0: - pnl.state = 'unfixed' - else: - pnl.state = 'part. fixed' + ' ' + str(round(pc.fixed_qt / Decimal(sl.sale_line.quantity_theorical) * 100,0)) + '%' - if pc.price and pc.ratio: - #pnl.amount = round(pc.price * (pc.unfixed_qt + pc.fixed_qt) * Decimal(-1) * pc.ratio / 100,2) - pnl.amount = round(pc.price * sl.get_current_quantity_converted() * pc.ratio / 100,4) - last_price = pc.get_last_price() - mtm = Decimal(0) - if last_price: - mtm = round(Decimal(last_price) * sl.get_current_quantity_converted(),4) - pnl.mtm = round(pnl.amount - (mtm * pc.ratio / 100),4) - pnl.quantity = round(sl.get_current_quantity_converted(),5) - pnl.unit = sl.sale_line.unit - pnl.currency = sl.sale_line.sale.currency - price_lines.append(pnl) - elif sl.sale_line.price_type == 'priced': - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.type = 'sale priced' - pnl.date = Date.today() - pnl.lot = lot.id - if lot.lot_type == 'physic': - pnl.reference = 'Sale/Physic' - else: - pnl.reference = 'Sale/Open' - pnl.price = round(lot.lot_price_sale,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = self.product - pnl.state = 'fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity,4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - elif sl.sale_line.price_type == 'efp': - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.type = 'sale efp' - pnl.date = Date.today() - pnl.lot = lot.id - if lot.lot_type == 'physic': - pnl.reference = 'Sale/Physic' - else: - pnl.reference = 'Sale/Open' - pnl.price = round(lot.lot_price_sale,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = self.product - pnl.state = 'not fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity,4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - lqts = LotQt.search([('lot_p','=',lot.id),('lot_s','>',0),('lot_quantity','>',0)]) - logger.info("FROM_VALUATION:%s",lqts) - logger.info("FROM_VALUATION2:%s",lot.sale_line) - if lqts and not lot.sale_line: - for lqt in lqts: - sl = lqt.lot_s - if sl.sale_line.price_type == 'basis' and sl.sale_line.price_summary: - for pc in sl.sale_line.price_summary: - #pnl management - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.lot = sl.id - pnl.type = 'sale priced' - pnl.date = Date.today() - pnl.reference = pc.get_name() + ' / ' + str(pc.ratio) + '%' - pnl.price = round(pc.price,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = sl.sale_line.product - if pc.unfixed_qt == 0: - pnl.state = 'fixed' - elif pc.fixed_qt == 0: - pnl.state = 'unfixed' - else: - pnl.state = 'part. fixed' + ' ' + str(round(pc.fixed_qt / Decimal(sl.sale_line.quantity_theorical) * 100,0)) + '%' - if pc.price and pc.ratio: - #pnl.amount = round(pc.price * (pc.unfixed_qt + pc.fixed_qt) * Decimal(-1) * pc.ratio / 100,2) - pnl.amount = round(pc.price * sl.get_current_quantity_converted() * pc.ratio / 100,4) - last_price = pc.get_last_price() - mtm = Decimal(0) - if last_price: - mtm = round(Decimal(last_price) * sl.get_current_quantity_converted(),4) - pnl.mtm = round(pnl.amount - (mtm * pc.ratio / 100),4) - pnl.quantity = round(sl.get_current_quantity_converted(),5) - pnl.unit = sl.sale_line.unit - pnl.currency = sl.sale_line.sale.currency - price_lines.append(pnl) - elif sl.sale_line.price_type == 'priced': - logger.info("FROM_VALUATION3:%s",sl) - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.type = 'sale priced' - pnl.date = Date.today() - pnl.lot = sl.id - if sl.lot_type == 'physic': - pnl.reference = 'Sale/Physic' - else: - pnl.reference = 'Sale/Open' - pnl.price = round(sl.lot_price_sale,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = self.product - pnl.state = 'fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(sl.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity,4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - elif sl.sale_line.price_type == 'efp': - logger.info("FROM_VALUATION3:%s",sl) - pnl = Pnl() - pnl.purchase = self.purchase.id - pnl.sale = sl.sale_line.sale.id - pnl.line = self.id - pnl.type = 'sale efp' - pnl.date = Date.today() - pnl.lot = sl.id - if sl.lot_type == 'physic': - pnl.reference = 'Sale/Physic' - else: - pnl.reference = 'Sale/Open' - pnl.price = round(sl.lot_price_sale,4) - pnl.counterparty = sl.sale_line.sale.party - pnl.product = self.product - pnl.state = 'not fixed' - mtm = Decimal(0) - pnl.mtm = mtm - pnl.quantity = round(sl.get_current_quantity_converted(),5) - pnl.amount = round(pnl.price * pnl.quantity,4) - pnl.unit = self.unit - pnl.currency = self.purchase.currency - price_lines.append(pnl) - return price_lines - - def group_fees_by_type_supplier(self,fees): - grouped = defaultdict(list) - - # Regrouper par (type, supplier) - for fee in fees: - key = (fee.product, fee.supplier) - grouped[key].append(fee) - result = [] - for key, fee_list in grouped.items(): - ordered_fees = [f for f in fee_list if f.type == 'ordered'] - if ordered_fees: - result.extend(ordered_fees) - else: - budgeted_fees = [f for f in fee_list if f.type == 'budgeted'] - result.extend(budgeted_fees) - return result - - def get_pnl_fee_lines(self): - fee_lines = [] - #pnl management - Pnl = Pool().get('valuation.valuation') - Date = Pool().get('ir.date') - Currency = Pool().get('currency.currency') - FeeLots = Pool().get('fee.lots') - if self.lots: - for lot in self.lots: - fl = FeeLots.search(['lot','=',lot.id]) - if fl: - fees = [e.fee for e in fl] - sorted_fees = self.group_fees_by_type_supplier(fees) - if sorted_fees: - for sf in sorted_fees: - pnl = Pnl() - pnl.lot = lot.id - if lot.sale_line: - pnl.sale = lot.sale_line.sale.id - pnl.purchase = self.purchase.id - pnl.line = self.id - if sf.line: - pnl.type = 'pur. fee' - if sf.sale_line: - pnl.type = 'sale fee' - if sf.shipment_in: - pnl.type = 'shipment fee' - pnl.date = Date.today() - pnl.price = Decimal(sf.get_price_per_qt()) - if sf.currency != self.purchase.currency: - with Transaction().set_context(date=Date.today()): - pnl.price = Currency.compute(sf.currency,pnl.price, self.purchase.currency) - pnl.counterparty = sf.supplier - str_op = '' - if lot.lot_type == 'physic': - str_op = '/Physic' - else: - str_op = '/Open' - pnl.reference = sf.product.name + str_op - pnl.product = sf.product - pnl.state = sf.type - if sf.p_r == 'pay': - sign = -1 - pnl.amount = round(pnl.price * lot.get_current_quantity_converted() * sign,2) - pnl.mtm = 0 - pnl.quantity = round(lot.get_current_quantity_converted(),5) - pnl.unit = sf.unit if sf.unit else self.unit - pnl.currency = sf.currency - fee_lines.append(pnl) - - return fee_lines - def check_from_to(self,tr): if tr.pricing_period: date_from,date_to, d, include, dates = tr.getDateWithEstTrigger(1) diff --git a/modules/purchase_trade/sale.py b/modules/purchase_trade/sale.py index 42ecc1b..fe413fd 100755 --- a/modules/purchase_trade/sale.py +++ b/modules/purchase_trade/sale.py @@ -324,14 +324,7 @@ class Sale(metaclass=PoolMeta): if line_p: #compute pnl Pnl = Pool().get('valuation.valuation') - pnl = Pnl.search([('line','=',line_p.id)]) - if pnl: - Pnl.delete(pnl) - pnl_lines = [] - pnl_lines.extend(line_p.get_pnl_fee_lines()) - pnl_lines.extend(line_p.get_pnl_price_lines()) - pnl_lines.extend(line_p.get_pnl_der_lines()) - Pnl.save(pnl_lines) + Pnl.generate(line_p) if line.quantity_theorical: OpenPosition = Pool().get('open.position') @@ -733,14 +726,7 @@ class SaleLine(metaclass=PoolMeta): if purchase_lines: for pl in purchase_lines: Pnl = Pool().get('valuation.valuation') - pnl = Pnl.search([('line','=',pl.id)]) - if pnl: - Pnl.delete(pnl) - pnl_lines = [] - pnl_lines.extend(pl.get_pnl_fee_lines()) - pnl_lines.extend(pl.get_pnl_price_lines()) - pnl_lines.extend(pl.get_pnl_der_lines()) - Pnl.save(pnl_lines) + Pnl.generate(pl) class SaleCreatePurchase(Wizard): "Create mirror purchase" diff --git a/modules/purchase_trade/valuation.py b/modules/purchase_trade/valuation.py index 8f3f00c..8173b7e 100644 --- a/modules/purchase_trade/valuation.py +++ b/modules/purchase_trade/valuation.py @@ -34,10 +34,7 @@ VALTYPE = [ ('derivative', 'Derivative'), ] -class Valuation(ModelSQL,ModelView): - "Valuation" - __name__ = 'valuation.valuation' - +class ValuationBase(ModelSQL): purchase = fields.Many2One('purchase.purchase',"Purchase") line = fields.Many2One('purchase.line',"Purch. Line") date = fields.Date("Date") @@ -299,11 +296,24 @@ class Valuation(ModelSQL,ModelView): pnl = Pnl.search([('line','=',line.id),('date','=',Date.today())]) if pnl: Pnl.delete(pnl) + PnlLine = Pool().get('valuation.valuation.line') + pnlline = PnlLine.search(['line','=',line.id]) + if pnlline: + PnlLine.delete(pnlline) pnl_lines = [] pnl_lines.extend(cls.create_pnl_fee_from_line(line)) pnl_lines.extend(cls.create_pnl_price_from_line(line)) pnl_lines.extend(cls.create_pnl_der_from_line(line)) Pnl.save(pnl_lines) + PnlLine.save(pnl_lines) + +class Valuation(ValuationBase, ModelView): + "Valuation" + __name__ = 'valuation.valuation' + +class ValuationLine(ValuationBase, ModelView): + "Last Valuation" + __name__ = 'valuation.valuation.line' class ValuationDyn(ModelSQL,ModelView): "Valuation" @@ -327,35 +337,12 @@ class ValuationDyn(ModelSQL,ModelView): @classmethod def table_query(cls): - Valuation = Pool().get('valuation.valuation') + Valuation = Pool().get('valuation.valuation.line') val = Valuation.__table__() context = Transaction().context group_pnl = context.get('group_pnl') wh = (val.id > 0) - # query = val.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.purchase.as_('r_purchase'), - # val.line.as_('r_line'), - # val.date.as_('r_date'), - # val.type.as_('r_type'), - # val.reference.as_('r_reference'), - # val.counterparty.as_('r_counterparty'), - # val.product.as_('r_product'), - # val.state.as_('r_state'), - # val.price.as_('r_price'), - # val.currency.as_('r_currency'), - # val.quantity.as_('r_quantity'), - # val.unit.as_('r_unit'), - # val.amount.as_('r_amount'), - # val.mtm.as_('r_mtm'), - # val.lot.as_('r_lot'), - # where=wh) - - #if group_pnl==True: + query = val.select( Literal(0).as_('create_uid'), CurrentTimestamp().as_('create_date'),