[ADD] product_update_price_last_purchase
This commit is contained in:
parent
27f0791503
commit
5f4bb24894
18 changed files with 942 additions and 0 deletions
8
product_update_price_last_purchase/models/__init__.py
Normal file
8
product_update_price_last_purchase/models/__init__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from . import product_template
|
||||
from . import product_product
|
||||
from . import res_company
|
||||
from . import res_config
|
||||
from . import ir_actions_report
|
||||
from . import stock_move
|
||||
from . import product_pricelist
|
||||
from . import product_pricelist_item
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import logging
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class IrActionsReport(models.Model):
|
||||
_inherit = 'ir.actions.report'
|
||||
|
||||
@api.multi
|
||||
def render_qweb_pdf(self, res_ids=None, data=None):
|
||||
_logger.debug("render_qweb_pdf : %s -- %s" %(res_ids, data))
|
||||
if res_ids:
|
||||
Model = self.env[self.model]
|
||||
record_ids = Model.browse(res_ids)
|
||||
wk_record_ids = Model
|
||||
for record_id in record_ids:
|
||||
if self.report_name == "product.report_producttemplatelabel":
|
||||
record_id.to_print = False
|
||||
return super(IrActionsReport, self).render_qweb_pdf(res_ids, data)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# Copyright (C) 2020: Criptomart (https://criptomart.net)
|
||||
# @author Santi Noreña (<santi@criptomart.net>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
_inherit = 'product.pricelist'
|
||||
|
||||
@api.multi
|
||||
def _compute_price_rule(self, products_qty_partner, date=False, uom_id=False):
|
||||
ProductPricelistItem = self.env['product.pricelist.item']
|
||||
ProductProduct = self.env['product.product']
|
||||
res = super()._compute_price_rule(products_qty_partner, date=date, uom_id=uom_id)
|
||||
new_res = res.copy()
|
||||
for product_id, values in res.items():
|
||||
if values[1]:
|
||||
item_id = values[1]
|
||||
if item_id:
|
||||
item = ProductPricelistItem.browse(item_id)
|
||||
if item.base == 'last_purchase_price':
|
||||
product = ProductProduct.browse(product_id)
|
||||
new_res[product_id] = (product.last_purchase_price, item_id)
|
||||
return new_res
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# Copyright (C) 2020: Criptomart (https://criptomart.net)
|
||||
# @author Santi Noreña (<santi@criptomart.net>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ProductPricelistItem(models.Model):
|
||||
_inherit = 'product.pricelist.item'
|
||||
|
||||
base = fields.Selection(selection_add=[
|
||||
('last_purchase_price', 'Last purchase price')])
|
||||
26
product_update_price_last_purchase/models/product_product.py
Normal file
26
product_update_price_last_purchase/models/product_product.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Copyright (C) 2020: Criptomart (https://criptomart.net)
|
||||
# @author Santi Noreña (<santi@criptomart.net>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = "product.product"
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if vals.get('last_purchase_price'):
|
||||
vals['list_price_updated'] = True
|
||||
return super(ProductProduct, self).write(vals)
|
||||
|
||||
|
||||
class ProductPackaging(models.Model):
|
||||
_inherit = "product.packaging"
|
||||
|
||||
qty = fields.Float('Contained Quantity', help="The total number of products you can have per pallet or box.", digits=dp.get_precision('Product Unit of Measure'))
|
||||
|
||||
144
product_update_price_last_purchase/models/product_template.py
Normal file
144
product_update_price_last_purchase/models/product_template.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# Copyright (C) 2020: Criptomart (https://criptomart.net)
|
||||
# @author Santi Noreña (<santi@criptomart.net>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
import math
|
||||
|
||||
from odoo import exceptions, models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
@api.multi
|
||||
def _compute_theoritical_price(self):
|
||||
partner = self.env['res.users'].browse(self.env.uid).partner_id
|
||||
pricelist_obj = self.env['product.pricelist']
|
||||
pricelist_id = self.env['ir.config_parameter'].sudo().get_param('product_laosa.product_pricelist_automatic') or False
|
||||
pricelist = pricelist_obj.browse(int(pricelist_id))
|
||||
_logger.debug("Calculating price with PriceList : %s" %pricelist.name)
|
||||
if pricelist:
|
||||
for template in self:
|
||||
if template.name and template.id and template.last_purchase_price_compute_type != 'manual_update':
|
||||
partial_price = pricelist.get_product_price(template.product_variant_id, "1", partner)
|
||||
_logger.debug("partial_price : %s" %partial_price)
|
||||
# Suma el IVA
|
||||
for tax in template.taxes_id:
|
||||
partial_price = partial_price * ( 1 + ( tax.amount / 100) )
|
||||
_logger.debug("partial_price after taxes : %s" %partial_price)
|
||||
# Redondea a 0,05 de precisión
|
||||
template.list_price = round(round(partial_price / 0.05) * 0.05, -int(math.floor(math.log10(0.05))))
|
||||
_logger.debug("final price : %s" %template.list_price)
|
||||
template.list_price_updated = False
|
||||
else:
|
||||
raise UserError(_('Not found a valid pricelist to compute sale price. Check configuration in General Settings.'))
|
||||
return False
|
||||
|
||||
list_price = fields.Float(
|
||||
string="Sale price with VAT",
|
||||
help="Price calculated according to the configured pricelist, including VAT.",
|
||||
compute="_compute_theoritical_price",
|
||||
store=True,
|
||||
readonly=False,
|
||||
digits=dp.get_precision('Product Price')
|
||||
)
|
||||
|
||||
list_price_updated = fields.Boolean(
|
||||
string="Last purchase price updated",
|
||||
help="The last cost price has been updated and you need to update the selling price in the database, shelves and scales.",
|
||||
default=False,
|
||||
readonly=True
|
||||
)
|
||||
|
||||
list_price_automatic = fields.Boolean(
|
||||
string="Automatic Sale Price",
|
||||
help="Automatic computation of the PVP from the cost price and the rate defined in the configuration.",
|
||||
default=True
|
||||
)
|
||||
|
||||
to_print = fields.Boolean(
|
||||
string="To print label",
|
||||
help="The sale price has been updated on this product and needs to be updated on the shelf.",
|
||||
default=False,
|
||||
readonly=True
|
||||
)
|
||||
|
||||
last_purchase_price = fields.Float(
|
||||
string="Last purchase price",
|
||||
help="The last price at which the product was purchased. It is used as the base price field for calculating the product sale price.",
|
||||
#readonly=True,
|
||||
digits=dp.get_precision('Product Price')
|
||||
)
|
||||
|
||||
last_purchase_price_compute_type = fields.Selection([
|
||||
('without_discounts', 'Without discounts'),
|
||||
('with_discount', 'First discount'),
|
||||
('with_three_discounts', 'Triple discount'),
|
||||
('manual_update', 'Manual update')],
|
||||
string="Last purchase price calculation type",
|
||||
help='Choose whether discounts should influence the calculation of the last purchase price. Select Never update for manual configuration of cost and sale prices.\n'
|
||||
'\n* Without discounts: does not take into account discounts when updating the last purchase price.\n'
|
||||
'* First discount: take into account only first discount when updating the last purchase price.\n'
|
||||
'* Triple discount: take into account all discounts when updating the last purchase price. Needs "Purchase Triple Discount" OCA module.\n'
|
||||
'* Manual update: Select this for manual configuration of cost and sale price. The sales price will not be calculated automatically.',
|
||||
default='without_discounts',
|
||||
required=True
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# Set supplier tax same than customer tax
|
||||
if vals.get('taxes_id'):
|
||||
tax = self.get_supplier_tax(vals.get('taxes_id'))
|
||||
vals['supplier_taxes_id'] = tax
|
||||
vals['list_price_updated'] = True
|
||||
return super(ProductTemplate, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
# Set supplier tax same than customer tax
|
||||
if vals.get('taxes_id'):
|
||||
tax = self.get_supplier_tax(vals.get('taxes_id'))
|
||||
vals['supplier_taxes_id'] = tax
|
||||
# Mark if product needs list price update
|
||||
if vals.get('last_purchase_price'):
|
||||
vals['list_price_updated'] = True
|
||||
# Mark if product needs update the shelf tag
|
||||
if vals.get('list_price'):
|
||||
vals['to_print'] = True
|
||||
return super(ProductTemplate, self).write(vals)
|
||||
|
||||
def get_supplier_tax(self, taxes_id):
|
||||
tax_obj = self.env['account.tax']
|
||||
tax_res = []
|
||||
if taxes_id:
|
||||
if "6, False, []" not in taxes_id:
|
||||
for tupla in taxes_id:
|
||||
a, b, c = tupla
|
||||
if c:
|
||||
for i in c:
|
||||
tax = tax_obj.browse(i)
|
||||
val = tax.amount
|
||||
if val == 21:
|
||||
record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva21_bc').id
|
||||
elif val == 10:
|
||||
record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva10_bc').id
|
||||
elif val == 4:
|
||||
record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva4_bc').id
|
||||
else:
|
||||
record_id = self.env['account.tax'].search([
|
||||
('amount','=', val),
|
||||
('active','=', True),
|
||||
('type_tax_use','=','purchase')
|
||||
],
|
||||
limit=1).id
|
||||
tax_res.append(record_id)
|
||||
|
||||
return [(6, 0, tax_res)]
|
||||
|
||||
|
||||
|
||||
17
product_update_price_last_purchase/models/res_company.py
Normal file
17
product_update_price_last_purchase/models/res_company.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#import logging
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
#_logger = logging.getLogger(__name__)
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
product_pricelist_automatic = fields.Many2one(
|
||||
comodel_name='product.pricelist',
|
||||
string='Pricelist applied to the automatic selling price',
|
||||
help='Rate that applies to all products that update the selling price automatically.',
|
||||
)
|
||||
|
||||
|
||||
|
||||
35
product_update_price_last_purchase/models/res_config.py
Normal file
35
product_update_price_last_purchase/models/res_config.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#import logging
|
||||
|
||||
from odoo import models, fields, api
|
||||
|
||||
#_logger = logging.getLogger(__name__)
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
product_pricelist_automatic = fields.Many2one(
|
||||
related='company_id.product_pricelist_automatic',
|
||||
comodel_name='product.pricelist',
|
||||
string='Pricelist applied to automatic calculation of sales price',
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
res = super(ResConfigSettings, self).get_values()
|
||||
config_obj = self.env["ir.config_parameter"]
|
||||
product_pricelist_automatic = config_obj.sudo().get_param(
|
||||
"product_laosa.product_pricelist_automatic", default=0)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def set_values(self):
|
||||
super(ResConfigSettings, self).set_values()
|
||||
config_obj = self.env["ir.config_parameter"]
|
||||
config_obj.sudo().set_param(
|
||||
"product_laosa.product_pricelist_automatic",
|
||||
int(self.product_pricelist_automatic.id)
|
||||
)
|
||||
|
||||
|
||||
|
||||
33
product_update_price_last_purchase/models/stock_move.py
Normal file
33
product_update_price_last_purchase/models/stock_move.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Copyright 2016-2019 Akretion (http://www.akretion.com/)
|
||||
# Copyright 2020 Criptomart <tech@criptomart.net>
|
||||
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
|
||||
# @author Santi Noreña (<santi@criptomart.net>)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
import math
|
||||
|
||||
from odoo import exceptions, models, fields, api, _
|
||||
from odoo.tools import float_is_zero, float_round, float_compare
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class StockMove(models.Model):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
@api.multi
|
||||
def product_price_update_before_done(self):
|
||||
super(StockMove, self).product_price_update_before_done()
|
||||
for move in self.filtered(lambda move: move.location_id.usage == 'supplier'):
|
||||
if move.product_id.last_purchase_price_compute_type == 'with_three_discounts':
|
||||
price_updated = float_round(move.purchase_line_id.price_subtotal / move.purchase_line_id.product_qty, precision_digits=2)
|
||||
elif move.product_id.last_purchase_price_compute_type == 'with_discount':
|
||||
price_updated = float_round(move.purchase_line_id.price_unit * (1 - move.purchase_line_id.discount / 100), precision_digits=2)
|
||||
else:
|
||||
price_updated = move.purchase_line_id.price_unit
|
||||
|
||||
if float_compare(move.product_id.last_purchase_price, price_updated, precision_digits=2) and not float_is_zero(move.quantity_done, precision_digits=3):
|
||||
_logger.info("Update last_purchase_price: %s for product %s Previous price: %s" % (price_updated, move.product_id.default_code, move.product_id.last_purchase_price))
|
||||
# Write the last purchase price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
|
||||
move.product_id.with_context(force_company=move.company_id.id).sudo().write({'last_purchase_price': price_updated})
|
||||
Loading…
Add table
Add a link
Reference in a new issue