stock_valuation_xlsx: restore past cost price support, using stock valuation layers
Don't replace the native menu entry any more. Code refactoring between the 2 wizards Improve multi-company support
This commit is contained in:
@@ -13,6 +13,8 @@
|
|||||||
Stock Valuation XLSX
|
Stock Valuation XLSX
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
This module is designed to work with *Cost Method* = **Average Cost (AVCO)**.
|
||||||
|
|
||||||
This module generate nice XLSX stock valuation reports either:
|
This module generate nice XLSX stock valuation reports either:
|
||||||
|
|
||||||
* from a physical inventory,
|
* from a physical inventory,
|
||||||
|
|||||||
@@ -137,33 +137,40 @@ class StockValuationXlsx(models.TransientModel):
|
|||||||
logger.debug('depreciation_rules=%s', rules)
|
logger.debug('depreciation_rules=%s', rules)
|
||||||
return rules
|
return rules
|
||||||
|
|
||||||
def compute_product_data(
|
@api.model
|
||||||
self, company_id, in_stock_product_ids, standard_price_past_date=False):
|
def compute_product_data(self, company_id, filter_product_ids, standard_price_dict):
|
||||||
self.ensure_one()
|
# standard_price_dict is a dictionnary with:
|
||||||
logger.debug('Start compute_product_data')
|
# keys = the keys that we expect in the result dict
|
||||||
ppo = self.env['product.product']
|
# values : a datetime object (for past date) or False (False means PRESENT)
|
||||||
|
logger.debug(
|
||||||
|
'Start compute_product_data standard_price_dict=%s', standard_price_dict)
|
||||||
|
ppo = self.env['product.product'].with_company(company_id)
|
||||||
|
svlo = self.env['stock.valuation.layer']
|
||||||
fields_list = self._prepare_product_fields()
|
fields_list = self._prepare_product_fields()
|
||||||
# if not standard_price_past_date: # TODO
|
# Do we need the present date?
|
||||||
if True:
|
if not all(standard_price_dict.values()):
|
||||||
fields_list.append('standard_price')
|
fields_list.append('standard_price')
|
||||||
products = ppo.search_read([('id', 'in', in_stock_product_ids)], fields_list)
|
products = ppo.search_read([('id', 'in', filter_product_ids)], fields_list)
|
||||||
product_id2data = {}
|
product_id2data = {}
|
||||||
for p in products:
|
for p in products:
|
||||||
logger.debug('p=%d', p['id'])
|
logger.debug('p=%d', p['id'])
|
||||||
if standard_price_past_date:
|
product_id2data[p['id']] = {}
|
||||||
# No more product.price.history on v14
|
for std_price_field_name, std_price_date in standard_price_dict.items():
|
||||||
# We are supposed to use stock.valuation.layer.revaluation
|
if not std_price_date: # present
|
||||||
# TODO migrate to stock.valuation.layer.revaluation
|
product_id2data[p['id']][std_price_field_name] = p['standard_price']
|
||||||
#history = ppho.search_read([
|
|
||||||
# ('company_id', '=', company_id),
|
|
||||||
# ('product_id', '=', p['id']),
|
|
||||||
# ('datetime', '<=', standard_price_past_date)],
|
|
||||||
# ['cost'], order='datetime desc, id desc', limit=1)
|
|
||||||
#standard_price = history and history[0]['cost'] or 0.0
|
|
||||||
standard_price = p['standard_price'] # TODO remove this tmp stuff
|
|
||||||
else:
|
else:
|
||||||
standard_price = p['standard_price']
|
layer_rg = svlo.read_group(
|
||||||
product_id2data[p['id']] = {'standard_price': standard_price}
|
[
|
||||||
|
('product_id', '=', p['id']),
|
||||||
|
('company_id', '=', company_id),
|
||||||
|
('create_date', '<=', std_price_date),
|
||||||
|
],
|
||||||
|
['value', 'quantity'],
|
||||||
|
[])
|
||||||
|
standard_price = 0
|
||||||
|
if layer_rg and layer_rg[0]['quantity']:
|
||||||
|
standard_price = layer_rg[0]['value'] / layer_rg[0]['quantity']
|
||||||
|
product_id2data[p['id']][std_price_field_name] = standard_price
|
||||||
for pfield in fields_list:
|
for pfield in fields_list:
|
||||||
if pfield.endswith('_id'):
|
if pfield.endswith('_id'):
|
||||||
product_id2data[p['id']][pfield] = p[pfield][0]
|
product_id2data[p['id']][pfield] = p[pfield][0]
|
||||||
@@ -381,9 +388,13 @@ class StockValuationXlsx(models.TransientModel):
|
|||||||
elif self.source == 'inventory':
|
elif self.source == 'inventory':
|
||||||
past_date = self.inventory_id.date
|
past_date = self.inventory_id.date
|
||||||
data, in_stock_products = self.compute_data_from_inventory(product_ids, prec_qty)
|
data, in_stock_products = self.compute_data_from_inventory(product_ids, prec_qty)
|
||||||
standard_price_past_date = past_date
|
if self.source == 'stock' and self.stock_date_type == 'present':
|
||||||
if not (self.source == 'stock' and self.stock_date_type == 'present') and self.standard_price_date == 'present':
|
|
||||||
standard_price_past_date = False
|
standard_price_past_date = False
|
||||||
|
else: # field standard_price_date is shown on screen
|
||||||
|
if self.standard_price_date == 'present':
|
||||||
|
standard_price_past_date = False
|
||||||
|
else:
|
||||||
|
standard_price_past_date = past_date
|
||||||
depreciation_rules = []
|
depreciation_rules = []
|
||||||
if apply_depreciation:
|
if apply_depreciation:
|
||||||
depreciation_rules = self._prepare_expiry_depreciation_rules(company_id, past_date)
|
depreciation_rules = self._prepare_expiry_depreciation_rules(company_id, past_date)
|
||||||
@@ -394,7 +405,7 @@ class StockValuationXlsx(models.TransientModel):
|
|||||||
in_stock_product_ids = list(in_stock_products.keys())
|
in_stock_product_ids = list(in_stock_products.keys())
|
||||||
product_id2data = self.compute_product_data(
|
product_id2data = self.compute_product_data(
|
||||||
company_id, in_stock_product_ids,
|
company_id, in_stock_product_ids,
|
||||||
standard_price_past_date=standard_price_past_date)
|
{'standard_price': standard_price_past_date})
|
||||||
data_res = self.group_result(data, split_by_lot, split_by_location)
|
data_res = self.group_result(data, split_by_lot, split_by_location)
|
||||||
categ_id2name = self.product_categ_id2name(self.categ_ids)
|
categ_id2name = self.product_categ_id2name(self.categ_ids)
|
||||||
uom_id2name = self.uom_id2name()
|
uom_id2name = self.uom_id2name()
|
||||||
|
|||||||
@@ -41,17 +41,14 @@
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="stock_valuation_xlsx_action" model="ir.actions.act_window">
|
<record id="stock_valuation_xlsx_action" model="ir.actions.act_window">
|
||||||
<field name="name">Stock Valuation XLSX</field>
|
<field name="name">Inventory Valuation XLSX</field>
|
||||||
<field name="res_model">stock.valuation.xlsx</field>
|
<field name="res_model">stock.valuation.xlsx</field>
|
||||||
<field name="view_mode">form</field>
|
<field name="view_mode">form</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Replace native menu, to avoid user confusion -->
|
<!-- in v14, I don't replace the native menu any more, because the native menu shows valuation layers,
|
||||||
<record id="stock_account.menu_valuation" model="ir.ui.menu">
|
which can be useful -->
|
||||||
<field name="action" ref="stock_valuation_xlsx.stock_valuation_xlsx_action"/>
|
<menuitem id="stock_valuation_xlsx_menu" action="stock_valuation_xlsx_action" sequence="115" parent="stock.menu_warehouse_report"/>
|
||||||
<field name="name">Stock Valuation XLSX</field>
|
|
||||||
<field name="sequence">0</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
@@ -106,59 +106,6 @@ class StockVariationXlsx(models.TransientModel):
|
|||||||
products = self.env['product.product'].search(domain)
|
products = self.env['product.product'].search(domain)
|
||||||
return products.ids
|
return products.ids
|
||||||
|
|
||||||
def _prepare_product_fields(self):
|
|
||||||
return ['uom_id', 'name', 'default_code', 'categ_id']
|
|
||||||
|
|
||||||
def compute_product_data(
|
|
||||||
self, company_id, filter_product_ids,
|
|
||||||
standard_price_start_date=False, standard_price_end_date=False):
|
|
||||||
self.ensure_one()
|
|
||||||
logger.debug('Start compute_product_data')
|
|
||||||
ppo = self.env['product.product']
|
|
||||||
fields_list = self._prepare_product_fields()
|
|
||||||
# if not standard_price_start_date or not standard_price_end_date: # TODO
|
|
||||||
if True:
|
|
||||||
fields_list.append('standard_price')
|
|
||||||
products = ppo.search_read([('id', 'in', filter_product_ids)], fields_list)
|
|
||||||
product_id2data = {}
|
|
||||||
for p in products:
|
|
||||||
logger.debug('p=%d', p['id'])
|
|
||||||
if standard_price_start_date:
|
|
||||||
# No more product.price.history on v14
|
|
||||||
# We are supposed to use stock.valuation.layer.revaluation
|
|
||||||
# TODO migrate to stock.valuation.layer.revaluation
|
|
||||||
#history = ppho.search_read([
|
|
||||||
# ('company_id', '=', company_id),
|
|
||||||
# ('product_id', '=', p['id']),
|
|
||||||
# ('datetime', '<=', standard_price_start_date)],
|
|
||||||
# ['cost'], order='datetime desc, id desc', limit=1)
|
|
||||||
#start_standard_price = history and history[0]['cost'] or 0.0
|
|
||||||
start_standard_price = p['standard_price'] # TODO remove this tmp stuff
|
|
||||||
else:
|
|
||||||
start_standard_price = p['standard_price']
|
|
||||||
if standard_price_end_date:
|
|
||||||
#history = ppho.search_read([
|
|
||||||
# ('company_id', '=', company_id),
|
|
||||||
# ('product_id', '=', p['id']),
|
|
||||||
# ('datetime', '<=', standard_price_end_date)],
|
|
||||||
# ['cost'], order='datetime desc, id desc', limit=1)
|
|
||||||
#end_standard_price = history and history[0]['cost'] or 0.0
|
|
||||||
end_standard_price = p['standard_price'] # TODO remove this tmp stuff
|
|
||||||
else:
|
|
||||||
end_standard_price = p['standard_price']
|
|
||||||
|
|
||||||
product_id2data[p['id']] = {
|
|
||||||
'start_standard_price': start_standard_price,
|
|
||||||
'end_standard_price': end_standard_price,
|
|
||||||
}
|
|
||||||
for pfield in fields_list:
|
|
||||||
if pfield.endswith('_id'):
|
|
||||||
product_id2data[p['id']][pfield] = p[pfield][0]
|
|
||||||
else:
|
|
||||||
product_id2data[p['id']][pfield] = p[pfield]
|
|
||||||
logger.debug('End compute_product_data')
|
|
||||||
return product_id2data
|
|
||||||
|
|
||||||
def compute_data_from_stock(self, product_ids, prec_qty, start_date, end_date_type, end_date, company_id):
|
def compute_data_from_stock(self, product_ids, prec_qty, start_date, end_date_type, end_date, company_id):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
logger.debug('Start compute_data_from_stock past_date=%s end_date_type=%s, end_date=%s', start_date, end_date_type, end_date)
|
logger.debug('Start compute_data_from_stock past_date=%s end_date_type=%s, end_date=%s', start_date, end_date_type, end_date)
|
||||||
@@ -273,12 +220,13 @@ class StockVariationXlsx(models.TransientModel):
|
|||||||
standard_price_start_date = standard_price_end_date = False
|
standard_price_start_date = standard_price_end_date = False
|
||||||
if self.standard_price_start_date_type == 'start':
|
if self.standard_price_start_date_type == 'start':
|
||||||
standard_price_start_date = self.start_date
|
standard_price_start_date = self.start_date
|
||||||
if self.standard_price_end_date_type == 'end':
|
if self.standard_price_end_date_type == 'end' and self.end_date_type == 'past':
|
||||||
standard_price_end_date = self.end_date
|
standard_price_end_date = self.end_date
|
||||||
|
|
||||||
product_id2data = self.compute_product_data(
|
product_id2data = svxo.compute_product_data(
|
||||||
company_id, list(product_data.keys()),
|
company_id, list(product_data.keys()), {
|
||||||
standard_price_start_date, standard_price_end_date)
|
'start_standard_price': standard_price_start_date,
|
||||||
|
'end_standard_price': standard_price_end_date})
|
||||||
categ_id2name = svxo.product_categ_id2name(self.categ_ids)
|
categ_id2name = svxo.product_categ_id2name(self.categ_ids)
|
||||||
uom_id2name = svxo.uom_id2name()
|
uom_id2name = svxo.uom_id2name()
|
||||||
res = self.stringify_and_sort_result(
|
res = self.stringify_and_sort_result(
|
||||||
|
|||||||
@@ -43,13 +43,13 @@
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="stock_variation_xlsx_action" model="ir.actions.act_window">
|
<record id="stock_variation_xlsx_action" model="ir.actions.act_window">
|
||||||
<field name="name">Stock Variation XLSX</field>
|
<field name="name">Inventory Variation XLSX</field>
|
||||||
<field name="res_model">stock.variation.xlsx</field>
|
<field name="res_model">stock.variation.xlsx</field>
|
||||||
<field name="view_mode">form</field>
|
<field name="view_mode">form</field>
|
||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<!-- Replace native menu, to avoid user confusion -->
|
<!-- Replace native menu, to avoid user confusion -->
|
||||||
<menuitem id="stock_variation_xlsx_menu" action="stock_variation_xlsx_action" parent="stock.menu_warehouse_report" sequence="1"/>
|
<menuitem id="stock_variation_xlsx_menu" action="stock_variation_xlsx_action" parent="stock.menu_warehouse_report" sequence="119"/>
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Reference in New Issue
Block a user