mirror of
https://bitbucket.org/presik/trytonpsk-purchase_discount.git
synced 2023-12-14 05:03:01 +01:00
236 lines
8.9 KiB
Python
236 lines
8.9 KiB
Python
# This file is part of purchase_discount module for Tryton.
|
|
# The COPYRIGHT file at the top level of this repository contains
|
|
# the full copyright notices and license terms.
|
|
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
from trytond.exceptions import UserError
|
|
from trytond.model import ModelView, fields
|
|
from trytond.wizard import Wizard, StateTransition, StateView, Button
|
|
from trytond.pool import PoolMeta, Pool
|
|
from trytond.pyson import Eval
|
|
from trytond.modules.purchase.purchase import PurchaseReport
|
|
from trytond.config import config as config_
|
|
from trytond.transaction import Transaction
|
|
|
|
from trytond.modules.product import price_digits, round_price
|
|
|
|
STATES = {
|
|
'invisible': Eval('type') != 'line',
|
|
'required': Eval('type') == 'line',
|
|
}
|
|
DIGITS = config_.getint('product', 'price_decimal', default=4)
|
|
DISCOUNT_DIGITS = 6
|
|
|
|
|
|
class Configuration(metaclass=PoolMeta):
|
|
__name__ = 'purchase.configuration'
|
|
description = fields.Char('Default Description')
|
|
|
|
|
|
class Purchase(metaclass=PoolMeta):
|
|
__name__ = 'purchase.purchase'
|
|
|
|
@staticmethod
|
|
def default_description():
|
|
config = Pool().get('purchase.configuration')(1)
|
|
if config.description:
|
|
return config.description
|
|
|
|
|
|
class PurchaseLine(metaclass=PoolMeta):
|
|
__name__ = 'purchase.line'
|
|
|
|
base_price = fields.Numeric('Base Price', digits=(16, DIGITS))
|
|
# gross_unit_price_wo_round = fields.Numeric('Gross Price without rounding',
|
|
# digits=(16, DIGITS + DISCOUNT_DIGITS), readonly=True)
|
|
discount_amount = fields.Function(fields.Numeric(
|
|
"Discount Amount", digits=price_digits,
|
|
states={
|
|
'invisible': Eval('type') != 'line',
|
|
'readonly': Eval('purchase_state') != 'draft',
|
|
},
|
|
depends=['type', 'purchase_state']),
|
|
'on_change_with_discount_amount', setter='set_discount_amount')
|
|
discount_rate = fields.Function(fields.Numeric(
|
|
"Discount Rate", digits=(16, 4),
|
|
states={
|
|
'invisible': Eval('type') != 'line',
|
|
'readonly': Eval('purchase_state') != 'draft',
|
|
},
|
|
depends=['type', 'purchase_state']),
|
|
'on_change_with_discount_rate', setter='set_discount_rate')
|
|
discount = fields.Function(fields.Char(
|
|
"Discount",
|
|
states={
|
|
'invisible': ~Eval('discount'),
|
|
}),
|
|
'on_change_with_discount')
|
|
|
|
stock_quantity = fields.Function(fields.Float('Stock Quantity',
|
|
digits=(16, 2), depends=['product'], states=STATES),
|
|
'on_change_with_stock_quantity')
|
|
# product_description = fields.Text('Application')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(PurchaseLine, cls).__setup__()
|
|
|
|
@classmethod
|
|
def __register__(cls, module_name):
|
|
table_h = cls.__table_handler__(module_name)
|
|
if table_h.column_exist('gross_unit_price'):
|
|
table_h.column_rename('gross_unit_price', 'base_price')
|
|
if table_h.column_exist('discount'):
|
|
table_h.column_rename('discount', 'discount_old')
|
|
super(PurchaseLine, cls).__register__(module_name)
|
|
|
|
def get_invoice_line(self):
|
|
'Return a list of invoice lines for sale line'
|
|
line = super(PurchaseLine, self).get_invoice_line()
|
|
if line and isinstance(line, list):
|
|
for l in line:
|
|
l.base_price = self.base_price
|
|
return line
|
|
|
|
@fields.depends(
|
|
methods=[
|
|
'compute_base_price', 'on_change_with_discount_rate',
|
|
'on_change_with_discount_amount', 'on_change_with_discount'])
|
|
def on_change_product(self):
|
|
super().on_change_product()
|
|
if self.product:
|
|
self.base_price = self.compute_base_price()
|
|
self.discount_rate = self.on_change_with_discount_rate()
|
|
self.discount_amount = self.on_change_with_discount_amount()
|
|
self.discount = self.on_change_with_discount()
|
|
|
|
@fields.depends('product', 'unit')
|
|
def compute_base_price(self):
|
|
pool = Pool()
|
|
Uom = pool.get('product.uom')
|
|
if self.product:
|
|
price = self.product.cost_price
|
|
if self.unit:
|
|
price = Uom.compute_price(
|
|
self.product.default_uom, price, self.unit)
|
|
return round_price(price)
|
|
|
|
@fields.depends('unit_price', 'base_price')
|
|
def on_change_with_discount_rate(self, name=None):
|
|
if self.unit_price is None or not self.base_price:
|
|
return
|
|
rate = 1 - self.unit_price / self.base_price
|
|
return rate.quantize(
|
|
Decimal(1) / 10 ** self.__class__.discount_rate.digits[1])
|
|
|
|
@classmethod
|
|
def set_discount_rate(cls, lines, name, value):
|
|
pass
|
|
|
|
@fields.depends('unit_price', 'base_price')
|
|
def on_change_with_discount_amount(self, name=None):
|
|
if self.unit_price is None or self.base_price is None:
|
|
return
|
|
return round_price(self.base_price - self.unit_price)
|
|
|
|
@fields.depends(
|
|
'base_price', 'discount_rate',
|
|
methods=['on_change_with_discount_amount', 'on_change_with_discount',
|
|
'on_change_with_amount'])
|
|
def on_change_discount_rate(self):
|
|
if self.base_price is not None and self.discount_rate is not None:
|
|
self.unit_price = round_price(
|
|
self.base_price * (1 - self.discount_rate))
|
|
self.discount_amount = self.on_change_with_discount_amount()
|
|
self.discount = self.on_change_with_discount()
|
|
self.amount = self.on_change_with_amount()
|
|
|
|
@fields.depends(
|
|
'base_price', 'discount_amount',
|
|
methods=['on_change_with_discount_rate', 'on_change_with_discount',
|
|
'on_change_with_amount'])
|
|
def on_change_discount_amount(self):
|
|
if self.base_price is not None and self.discount_amount is not None:
|
|
self.unit_price = round_price(
|
|
self.base_price - self.discount_amount)
|
|
self.discount_rate = self.on_change_with_discount_rate()
|
|
self.discount = self.on_change_with_discount()
|
|
self.amount = self.on_change_with_amount()
|
|
|
|
@fields.depends(
|
|
'purchase', '_parent_purchase.currency',
|
|
methods=[
|
|
'on_change_with_discount_rate', 'on_change_with_discount_amount'])
|
|
def on_change_with_discount(self, name=None):
|
|
pool = Pool()
|
|
Lang = pool.get('ir.lang')
|
|
lang = Lang.get()
|
|
rate = self.on_change_with_discount_rate()
|
|
if not rate or rate % Decimal('0.01'):
|
|
amount = self.on_change_with_discount_amount()
|
|
if amount:
|
|
return lang.currency(
|
|
amount, self.purchase.currency, digits=price_digits[1])
|
|
else:
|
|
return lang.format('%i', rate * 100) + '%'
|
|
|
|
@fields.depends('product', 'purchase')
|
|
def on_change_with_stock_quantity(self, name=None):
|
|
res = 0
|
|
if not self.purchase.warehouse:
|
|
raise UserError('purchase_without_warehouse')
|
|
location_id = self.purchase.warehouse.id
|
|
if self.product:
|
|
stock_context = {
|
|
'stock_date_end': date.today(),
|
|
'locations': [location_id],
|
|
}
|
|
with Transaction().set_context(stock_context):
|
|
try:
|
|
res_dict = self.product._get_quantity([self.product], 'quantity', [location_id], grouping_filter=([self.product.id],))
|
|
if res_dict.get(self.product.id):
|
|
res += res_dict[self.product.id]
|
|
except AttributeError as error:
|
|
print(error)
|
|
return res
|
|
|
|
@classmethod
|
|
def set_discount_amount(cls, lines, name, value):
|
|
pass
|
|
|
|
|
|
class PurchaseDiscountWizardStart(ModelView):
|
|
'Purchase Discount Wizard Start'
|
|
__name__ = 'purchase.discount_wizard.start'
|
|
discount = fields.Float('Discount', digits=(2, 2))
|
|
|
|
|
|
class PurchaseDiscountWizard(Wizard):
|
|
'Purchase Discount Wizard'
|
|
__name__ = 'purchase.discount_wizard'
|
|
start = StateView('purchase.discount_wizard.start',
|
|
'purchase_discount.purchase_wizard_start_view_form', [
|
|
Button('Cancel', 'end', 'tryton-cancel'),
|
|
Button('Ok', 'accept', 'tryton-ok', default=True),
|
|
])
|
|
accept = StateTransition()
|
|
|
|
def transition_accept(self):
|
|
Purchase = Pool().get('purchase.purchase')
|
|
purchases = Purchase.browse(Transaction().context['active_ids'])
|
|
purchases = [i for i in purchases if i.state == 'draft']
|
|
for purchase in purchases:
|
|
for line in purchase.lines:
|
|
if line.type != 'line':
|
|
continue
|
|
value = self.start.discount / 100
|
|
line.write([line], {'discount': Decimal(value).quantize(Decimal(100) ** -2)})
|
|
line.update_prices()
|
|
line.save()
|
|
# Purchase.update_taxes(purchases)
|
|
return 'end'
|
|
|
|
|
|
class PurchaseDiscountReport(PurchaseReport):
|
|
__name__ = 'purchase.purchase.discount'
|