[IMP] Add stock valuation report
bzr revid: jco@openerp.com-20130516144844-ce7t4l53c0wksvhb
This commit is contained in:
@@ -39,7 +39,7 @@ class purchase_config_settings(osv.osv_memory):
|
||||
'group_uom':fields.boolean("Manage different units of measure for products",
|
||||
implied_group='product.group_uom',
|
||||
help="""Allows you to select and maintain different units of measure for products."""),
|
||||
'group_costing_method':fields.boolean("Compute product cost price based on average cost",
|
||||
'group_costing_method':fields.boolean("Compute product cost price based on average/FIFO/LIFO cost",
|
||||
implied_group='product.group_costing_method',
|
||||
help="""Allows you to compute product cost price based on average cost."""),
|
||||
'module_warning': fields.boolean("Alerts by products or supplier",
|
||||
|
||||
@@ -23,7 +23,6 @@ from openerp import tools
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
|
||||
|
||||
class report_stock_move(osv.osv):
|
||||
_name = "report.stock.move"
|
||||
_description = "Moves Statistics"
|
||||
@@ -228,4 +227,101 @@ CREATE OR REPLACE view report_stock_inventory AS (
|
||||
|
||||
|
||||
|
||||
|
||||
class report_stock_valuation(osv.osv):
|
||||
_name = "report.stock.valuation"
|
||||
_description = "Stock Valuation Statistics"
|
||||
_auto = False
|
||||
_order = 'date desc'
|
||||
_columns = {
|
||||
'date': fields.datetime('Date', readonly=True),
|
||||
'year': fields.char('Year', size=4, readonly=True),
|
||||
'month':fields.selection([('01','January'), ('02','February'), ('03','March'), ('04','April'),
|
||||
('05','May'), ('06','June'), ('07','July'), ('08','August'), ('09','September'),
|
||||
('10','October'), ('11','November'), ('12','December')], 'Month', readonly=True),
|
||||
'partner_id':fields.many2one('res.partner', 'Partner', readonly=True),
|
||||
'product_id':fields.many2one('product.product', 'Product', readonly=True),
|
||||
'product_categ_id':fields.many2one('product.category', 'Product Category', readonly=True),
|
||||
'location_id': fields.many2one('stock.location', 'Location', readonly=True),
|
||||
'prodlot_id': fields.many2one('stock.production.lot', 'Lot', readonly=True),
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'product_qty':fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), readonly=True),
|
||||
'value' : fields.float('Total Value', digits_compute=dp.get_precision('Account'), required=True),
|
||||
'move_value' : fields.float('Total Value', digits_compute=dp.get_precision('Account'), required=True),
|
||||
'state': fields.selection([('draft', 'Draft'), ('waiting', 'Waiting'), ('confirmed', 'Confirmed'), ('assigned', 'Available'), ('done', 'Done'), ('cancel', 'Cancelled')], 'Status', readonly=True, select=True,
|
||||
help='When the stock move is created it is in the \'Draft\' state.\n After that it is set to \'Confirmed\' state.\n If stock is available state is set to \'Avaiable\'.\n When the picking it done the state is \'Done\'.\
|
||||
\nThe state is \'Waiting\' if the move is waiting for another one.'),
|
||||
'location_type': fields.selection([('supplier', 'Supplier Location'), ('view', 'View'), ('internal', 'Internal Location'), ('customer', 'Customer Location'), ('inventory', 'Inventory'), ('procurement', 'Procurement'), ('production', 'Production'), ('transit', 'Transit Location for Inter-Companies Transfers')], 'Location Type', required=True),
|
||||
'scrap_location': fields.boolean('scrap'),
|
||||
'name': fields.text('Name', readonly=True),
|
||||
'price_unit': fields.float('Unit price', digits_compute=dp.get_precision('Account'))
|
||||
}
|
||||
|
||||
def init(self, cr):
|
||||
tools.drop_view_if_exists(cr, 'report_stock_valuation')
|
||||
cr.execute("""
|
||||
CREATE OR REPLACE view report_stock_valuation AS (
|
||||
(SELECT
|
||||
min(mm.id) as id, m.date as date,
|
||||
to_char(m.date, 'YYYY') as year,
|
||||
to_char(m.date, 'MM') as month,
|
||||
m.partner_id as partner_id, m.location_id as location_id,
|
||||
m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type, l.scrap_location as scrap_location,
|
||||
m.company_id,
|
||||
m.state as state, m.prodlot_id as prodlot_id,
|
||||
p.name as name,
|
||||
CASE WHEN ipcm.value_text in ('fifo','lifo') THEN coalesce(mm.price_unit_out * pu2.factor / pu.factor, 0.0)
|
||||
ELSE coalesce(m.price_unit * pu2.factor / pu.factor::decimal, 0.0) END AS price_unit,
|
||||
coalesce(sum(-ip.value_float * m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as value,
|
||||
CASE WHEN ipcm.value_text in ('fifo', 'lifo') THEN coalesce(sum(-mm.price_unit_out * mm.qty)::decimal, 0.0)
|
||||
ELSE coalesce(sum(-m.price_unit * mm.qty)::decimal, 0.0) END as move_value,
|
||||
coalesce(sum(-mm.qty * pu.factor / pu2.factor)::decimal, 0.0) as product_qty
|
||||
FROM
|
||||
stock_move_matching mm, stock_move m
|
||||
LEFT JOIN stock_picking p ON (m.picking_id=p.id)
|
||||
LEFT JOIN product_product pp ON (m.product_id=pp.id)
|
||||
LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
|
||||
LEFT JOIN ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.template,',pt.id) AND ip.company_id=m.company_id)
|
||||
LEFT JOIN ir_property ipcm ON (ipcm.name='cost_method' and ipcm.res_id=CONCAT('product.template,',pt.id) AND ipcm.company_id=m.company_id)
|
||||
LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
|
||||
LEFT JOIN product_uom pu2 ON (m.product_uom=pu2.id)
|
||||
LEFT JOIN product_uom u ON (m.product_uom=u.id)
|
||||
LEFT JOIN stock_location l ON (m.location_id=l.id)
|
||||
WHERE m.state != 'cancel' and mm.move_out_id=m.id
|
||||
GROUP BY
|
||||
p.name, mm.id, mm.move_out_id, m.id, m.product_id, m.product_uom, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
|
||||
m.prodlot_id, m.date, m.state, l.usage, l.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'),
|
||||
pu2.factor, pu.factor, ipcm.value_text
|
||||
) UNION ALL (
|
||||
SELECT
|
||||
-min(m.id) as id, m.date as date,
|
||||
to_char(m.date, 'YYYY') as year,
|
||||
to_char(m.date, 'MM') as month,
|
||||
m.partner_id as partner_id, m.location_dest_id as location_id,
|
||||
m.product_id as product_id, pt.categ_id as product_categ_id, l.usage as location_type, l.scrap_location as scrap_location,
|
||||
m.company_id,
|
||||
m.state as state, m.prodlot_id as prodlot_id,
|
||||
p.name as name, coalesce(m.price_unit * pu2.factor / pu.factor, 0.0) as price_unit,
|
||||
coalesce(sum(ip.value_float * m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as value,
|
||||
coalesce(sum(m.price_unit * m.product_qty)::decimal, 0.0) as move_value,
|
||||
coalesce(sum(m.product_qty * pu.factor / pu2.factor)::decimal, 0.0) as product_qty
|
||||
FROM
|
||||
stock_move m
|
||||
LEFT JOIN stock_picking p ON (m.picking_id=p.id)
|
||||
LEFT JOIN product_product pp ON (m.product_id=pp.id)
|
||||
LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
|
||||
LEFT JOIN ir_property ip ON (ip.name='standard_price' AND ip.res_id=CONCAT('product.template,',pt.id) AND ip.company_id=m.company_id)
|
||||
LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
|
||||
LEFT JOIN product_uom pu2 ON (m.product_uom=pu2.id)
|
||||
LEFT JOIN product_uom u ON (m.product_uom=u.id)
|
||||
LEFT JOIN stock_location l ON (m.location_dest_id=l.id)
|
||||
WHERE m.state != 'cancel'
|
||||
GROUP BY
|
||||
p.name, m.id, m.product_id, m.product_uom, pt.categ_id, m.partner_id, m.location_id, m.location_dest_id,
|
||||
m.prodlot_id, m.date, m.state, l.usage, l.scrap_location, m.company_id, pt.uom_id, to_char(m.date, 'YYYY'), to_char(m.date, 'MM'),
|
||||
pu2.factor, pu.factor
|
||||
)
|
||||
);
|
||||
""")
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -187,6 +187,101 @@
|
||||
id="menu_action_stock_inventory_report"
|
||||
parent="next_id_61" sequence="4"/>
|
||||
|
||||
<!-- Inventory: Stock Valuation report -->
|
||||
<record id="view_stock_valuation_tree" model="ir.ui.view">
|
||||
<field name="name">report.stock.valuation.tree</field>
|
||||
<field name="model">report.stock.valuation</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Valuation Analysis" create="false">
|
||||
<field name="date" invisible="1"/>
|
||||
<field name="year" invisible="1" />
|
||||
<field name="month" invisible="1"/>
|
||||
<field name="company_id" invisible="1"/>
|
||||
<field name="location_type" invisible="1"/>
|
||||
<field name="location_id" invisible="1"/>
|
||||
<field name="partner_id" invisible="1" context="{'contact_display':'partner'}"/>
|
||||
<field name="product_categ_id" invisible="1"/>
|
||||
<field name="product_id" invisible="1"/>
|
||||
<field name="prodlot_id" invisible="1"/>
|
||||
<field name="state" invisible="1"/>
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="product_qty" sum="Total quantity"/>
|
||||
<field name="move_value" sum="Total value"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_valuation_graph" model="ir.ui.view">
|
||||
<field name="name">report.stock.valuation.graph</field>
|
||||
<field name="model">report.stock.valuation</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Stock Valuation Analysis" type="bar">
|
||||
<field name="product_id"/>
|
||||
<field name="move_value"/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_valuation_search" model="ir.ui.view">
|
||||
<field name="name">report.stock.valuation.search</field>
|
||||
<field name="model">report.stock.valuation</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Stock Valuation Analysis">
|
||||
<filter string="Real" name="real" icon="terp-check" domain="[('state','=','done')]"
|
||||
help="Analysis of current inventory (only moves that have already been processed)"/>
|
||||
<filter string="Future" icon="terp-stock" domain="[('state','in',('assigned','done','waiting','confirmed'))]"
|
||||
help = "Analysis including future moves (similar to virtual stock)"/>
|
||||
<separator/>
|
||||
<filter icon="terp-go-home" name="location_type_internal" string="Internal" domain="[('location_type','=','internal')]"/>
|
||||
<field name="product_id" default_focus="1"/>
|
||||
<field name="location_id" filter_domain="[('location_id', 'child_of', self)]"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<group expand="0" string="Extended Filters...">
|
||||
<field name="partner_id" context="{'contact_display':'partner'}" filter_domain="[('partner_id', 'child_of', self)]"/>
|
||||
<field name="product_categ_id" />
|
||||
<field name="prodlot_id"/>
|
||||
<field name="state"/>
|
||||
<field name="location_type"/>
|
||||
<field name="date"/>
|
||||
<filter icon="terp-go-home" name="location_type_scrap" string="Scrap" domain="[('scrap_location','=','True')]"/>
|
||||
</group>
|
||||
<group expand="1" string="Group By..." >
|
||||
<filter string="Partner" name="group_partner" icon="terp-partner" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter name="group_product_categ_id" string="Product Category" icon="terp-stock_symbol-selection" context="{'group_by':'product_categ_id'}"/>
|
||||
<filter name="group_product" string="Product" icon="terp-accessories-archiver" context="{'group_by':'product_id'}"/>
|
||||
<filter name="group_lot" string="Lot" icon="terp-accessories-archiver" context="{'group_by':'prodlot_id'}"/>
|
||||
<filter name="group_company" string="Company" groups="base.group_multi_company" icon="terp-go-home" context="{'group_by':'company_id'}"/>
|
||||
<filter name="group_location" string="Location" icon="terp-go-home" context="{'group_by':'location_id'}"/>
|
||||
<filter string="Status" icon="terp-stock_effects-object-colorize" context="{'group_by':'state'}"/>
|
||||
<filter string="Date" icon="terp-go-today" context="{'group_by':'date'}"/>
|
||||
<filter string="Month" icon="terp-go-month" context="{'group_by':'month'}"/>
|
||||
<filter string="Year" icon="terp-go-year" context="{'group_by':'year'}"/>
|
||||
<filter string="Price" context="{'group_by': 'price_unit'}"/>
|
||||
</group>
|
||||
<group string="Extra group by">
|
||||
<filter string="Ref" context="{'group_by': 'name'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_stock_valuation_report" model="ir.actions.act_window">
|
||||
<field name="name">Stock Valuation Analysis</field>
|
||||
<field name="res_model">report.stock.valuation</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,graph</field>
|
||||
<field name="search_view_id" eval="False"/>
|
||||
<field name="context">{'contact_display': 'partner', 'search_default_real':1,
|
||||
'search_default_year':1,'search_default_month':1, 'search_default_location_type_internal':1,'search_default_group_product':1,'group_by':[], 'group_by_no_leaf':0}</field>
|
||||
<field name="help">Stock Valuation Analysis allows you to easily check and analyse your company stock levels. The difference with the Inventory Analysis, is that
|
||||
the stock is calculated based on the prices of the stock moves depending on the costing method of the product (FIFO/LIFO/Average/standard) and not just the standard price of the product.
|
||||
Sort and group by selection criteria in order to better analyse and manage your company activities. </field>
|
||||
</record>
|
||||
<menuitem action="action_stock_valuation_report"
|
||||
id="menu_action_stock_valuation_report"
|
||||
parent="next_id_61" sequence="4"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
||||
@@ -2306,7 +2306,7 @@ class stock_move(osv.osv):
|
||||
if context is None:
|
||||
context = {}
|
||||
src_company_ctx = dict(context,force_company=move.location_id.company_id.id)
|
||||
dest_company_ctx = dict(context,force_company=move.location_dest_id.company_id.id)
|
||||
dest_company_ctx = dict(context,force_company=move.location_dest_id.company_id.id) # pas besoin
|
||||
account_moves = []
|
||||
# Outgoing moves (or cross-company output part)
|
||||
if move.location_id.company_id \
|
||||
|
||||
Reference in New Issue
Block a user