mirror of
https://github.com/NaN-tic/trytond-sale_opportunity_purchase_relation_margin.git
synced 2023-12-14 04:02:56 +01:00
update cost of sale_line depending on purchase state
This commit is contained in:
parent
7c41bc26c7
commit
9c8674cd62
2 changed files with 103 additions and 37 deletions
|
@ -7,5 +7,6 @@ from .sale import *
|
|||
def register():
|
||||
Pool.register(
|
||||
SaleLine,
|
||||
Purchase,
|
||||
PurchaseLine,
|
||||
module='sale_opportunity_purchase_relation_margin', type_='model')
|
||||
|
|
139
sale.py
139
sale.py
|
@ -1,54 +1,119 @@
|
|||
#The COPYRIGHT file at the top level of this repository contains
|
||||
#the full copyright notices and license terms.
|
||||
from trytond.model import fields
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
# The COPYRIGHT file at the top level of this repository contains the full
|
||||
# copyright notices and license terms.
|
||||
from decimal import Decimal
|
||||
|
||||
__all__ = ['SaleLine', 'PurchaseLine']
|
||||
from trytond.config import config
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
DIGITS = int(config.get('digits', 'unit_price_digits', 4))
|
||||
|
||||
__all__ = ['SaleLine', 'Purchase', 'PurchaseLine']
|
||||
__metaclass__ = PoolMeta
|
||||
|
||||
_QUANTIZE = Decimal(str(10 ** -DIGITS))
|
||||
_CONFIRMED_STATES = ('confirmed', 'processing', 'done')
|
||||
|
||||
|
||||
class SaleLine:
|
||||
__name__ = 'sale.line'
|
||||
|
||||
@fields.depends('purchase_lines')
|
||||
def on_change_purchase_lines(self):
|
||||
changes = {}
|
||||
if self.purchase_lines:
|
||||
changes['cost_price'] = self.purchase_lines[0].unit_price
|
||||
return changes
|
||||
@classmethod
|
||||
def update_cost_price(cls, lines):
|
||||
pool = Pool()
|
||||
Sale = pool.get('sale.sale')
|
||||
|
||||
to_write = []
|
||||
sales = set()
|
||||
for line in lines:
|
||||
new_cost_price = line.calc_cost_price_from_purchase_lines()
|
||||
if new_cost_price != line.cost_price:
|
||||
to_write.extend(([line], {
|
||||
'cost_price': new_cost_price,
|
||||
}))
|
||||
if line.sale.state not in ('draft', 'quotation'):
|
||||
sales.add(line.sale)
|
||||
|
||||
if to_write:
|
||||
cls.write(*to_write)
|
||||
|
||||
# Ensure that the margin cache is valid
|
||||
if sales:
|
||||
sales = list(sales)
|
||||
Sale.write(sales, {'margin_cache': None})
|
||||
Sale.store_cache(sales)
|
||||
|
||||
def calc_cost_price_from_purchase_lines(self):
|
||||
if not self.purchase_lines:
|
||||
return self.product.cost_price
|
||||
|
||||
confirmed_purchase_lines = any(l.purchase.state in _CONFIRMED_STATES
|
||||
for l in self.purchase_lines)
|
||||
cost_price = Decimal('0.0')
|
||||
quantity = 0
|
||||
for purchase_line in self.purchase_lines:
|
||||
if purchase_line.purchase.state == 'cancel':
|
||||
continue
|
||||
if (not confirmed_purchase_lines
|
||||
or purchase_line.purchase.state in _CONFIRMED_STATES):
|
||||
cost_price += purchase_line.amount
|
||||
quantity += purchase_line.quantity
|
||||
if quantity:
|
||||
return (cost_price / Decimal(str(quantity))).quantize(_QUANTIZE)
|
||||
return self.product.cost_price
|
||||
|
||||
|
||||
class Purchase:
|
||||
__name__ = 'purchase.purchase'
|
||||
|
||||
@classmethod
|
||||
def cancel(cls, purchases):
|
||||
super(Purchase, cls).cancel(purchases)
|
||||
PurchaseLine.update_sale_lines_cost_price([l for p in purchases
|
||||
for l in p.lines])
|
||||
|
||||
@classmethod
|
||||
def draft(cls, purchases):
|
||||
super(Purchase, cls).draft(purchases)
|
||||
PurchaseLine.update_sale_lines_cost_price([l for p in purchases
|
||||
for l in p.lines])
|
||||
|
||||
@classmethod
|
||||
def confirm(cls, purchases):
|
||||
super(Purchase, cls).confirm(purchases)
|
||||
PurchaseLine.update_sale_lines_cost_price([l for p in purchases
|
||||
for l in p.lines])
|
||||
|
||||
|
||||
class PurchaseLine:
|
||||
__name__ = 'purchase.line'
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
purchase_lines = super(PurchaseLine, cls).create(vlist)
|
||||
cls.update_sale_lines_cost_price(purchase_lines)
|
||||
return purchase_lines
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
actions = iter(args)
|
||||
modified_lines = []
|
||||
for lines, values in zip(actions, actions):
|
||||
if 'unit_price' in values or 'sale_lines' in values:
|
||||
modified_lines.extend(lines)
|
||||
|
||||
super(PurchaseLine, cls).write(*args)
|
||||
|
||||
cls.update_sale_lines_cost_price(modified_lines)
|
||||
|
||||
@classmethod
|
||||
def update_sale_lines_cost_price(cls, lines):
|
||||
pool = Pool()
|
||||
SaleLine = pool.get('sale.line')
|
||||
Sale = pool.get('sale.sale')
|
||||
actions = iter(args)
|
||||
to_check = []
|
||||
for lines, values in zip(actions, actions):
|
||||
if 'unit_price' in values:
|
||||
to_check.extend(lines)
|
||||
super(PurchaseLine, cls).write(*args)
|
||||
to_write = []
|
||||
lines = SaleLine.search([
|
||||
('purchase_lines', 'in', [l.id for l in to_check]),
|
||||
|
||||
if not lines:
|
||||
return
|
||||
|
||||
sale_lines = SaleLine.search([
|
||||
('purchase_lines', 'in', [l.id for l in lines]),
|
||||
])
|
||||
sales = set()
|
||||
for line in lines:
|
||||
if (line.purchase_lines and
|
||||
line.cost_price != line.purchase_lines[0].unit_price):
|
||||
to_write.extend(([line], {
|
||||
'cost_price': line.purchase_lines[0].unit_price,
|
||||
}))
|
||||
if line.sale.state not in ('draft', 'quotation'):
|
||||
sales.add(line.sale)
|
||||
if to_write:
|
||||
SaleLine.write(*to_write)
|
||||
# Ensure that the margin cache is valid
|
||||
if sales:
|
||||
sales = list(sales)
|
||||
Sale.write(sales, {'margin_cache': None})
|
||||
Sale.store_cache(sales)
|
||||
if sale_lines:
|
||||
SaleLine.update_cost_price(sale_lines)
|
||||
|
|
Loading…
Reference in a new issue