[MERGE] module to manage the landed costs
bzr revid: qdp-launchpad@openerp.com-20140424133710-fjrgyx32xt6d4kfw
This commit is contained in:
commit
387e6fbb0e
|
@ -34,6 +34,8 @@ class stock_config_settings(osv.osv_memory):
|
|||
help='This allows to automatically launch the invoicing wizard if the delivery is '
|
||||
'to be invoiced when you send or deliver goods.\n'
|
||||
'-This installs the module stock_invoice_directly.'),
|
||||
'module_stock_landed_costs': fields.boolean("Calculate landed costs on products",
|
||||
help="""Install the module that allows to affect landed costs on pickings, and split them onto the different products."""),
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
<field name="module_stock_invoice_directly" class="oe_inline"/>
|
||||
<label for="module_stock_invoice_directly"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="module_stock_landed_costs" class="oe_inline"/>
|
||||
<label for="module_stock_landed_costs"/>
|
||||
</div>
|
||||
</div>
|
||||
</group>
|
||||
</xpath>
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import product
|
||||
import stock_landed_costs
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,52 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'WMS Landed Costs',
|
||||
'version': '1.1',
|
||||
'author': 'OpenERP SA',
|
||||
'summary': 'Landed Costs',
|
||||
'description': """
|
||||
#TODO
|
||||
======================
|
||||
#TODO
|
||||
""",
|
||||
'website': 'http://www.openerp.com',
|
||||
'images': [],
|
||||
'depends': ['stock_account'],
|
||||
'category': 'Warehouse Management',
|
||||
'sequence': 16,
|
||||
'demo': [
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
'product_view.xml',
|
||||
'stock_landed_costs_view.xml',
|
||||
'stock_landed_costs_data.xml',
|
||||
],
|
||||
'test': [
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
'auto_install': False,
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
SPLIT_METHOD = [
|
||||
('equal', 'Equal'),
|
||||
('by_quantity', 'By Quantity'),
|
||||
('by_current_cost_price', 'By Current Cost Price'),
|
||||
('by_weight', 'By Weight'),
|
||||
('by_volume', 'By Volume'),
|
||||
]
|
||||
|
||||
class product_product(osv.osv):
|
||||
_inherit = "product.product"
|
||||
|
||||
_columns = {
|
||||
'landed_cost_ok': fields.boolean('Can constitute a landed cost'),
|
||||
'split_method': fields.selection(SPLIT_METHOD, 'Split Method'),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'landed_cost_ok': False,
|
||||
'split_method': 'equal',
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<record id="view_product_landed_cost_form" model="ir.ui.view">
|
||||
<field name="name">product.product.landed.cost.form</field>
|
||||
<field name="model">product.product</field>
|
||||
<field name="inherit_id" ref="product.product_normal_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<div name="options" position="after">
|
||||
<field name="landed_cost_ok"/>
|
||||
<label for="landed_cost_ok"/>
|
||||
</div>
|
||||
<xpath expr="//group[@name='properties']" position="before">
|
||||
<group>
|
||||
<separator string="Split Method" colspan="4"/>
|
||||
<group colspan="2" col="2">
|
||||
<field name="split_method"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,4 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
"access_stock_landed_cost","stock.landed.cost","model_stock_landed_cost","stock.group_stock_manager",1,1,1,1
|
||||
"access_stock_landed_cost_lines","stock.landed.cost.lines","model_stock_landed_cost_lines","stock.group_stock_manager",1,1,1,1
|
||||
"access_stock_valuation_adjustment_lines","stock.valuation.adjustment.lines","model_stock_valuation_adjustment_lines","stock.group_stock_manager",1,1,1,1
|
|
|
@ -0,0 +1,320 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import time
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
import openerp.addons.decimal_precision as dp
|
||||
from openerp.tools.translate import _
|
||||
import product
|
||||
|
||||
|
||||
class stock_landed_cost(osv.osv):
|
||||
_name = 'stock.landed.cost'
|
||||
_description = 'Stock Landed Cost'
|
||||
_inherit = 'mail.thread'
|
||||
|
||||
_track = {
|
||||
'state': {
|
||||
'stock_landed_costs.mt_stock_landed_cost_open': lambda self, cr, uid, obj, ctx=None: obj['state'] == 'done',
|
||||
},
|
||||
}
|
||||
|
||||
def _total_amount(self, cr, uid, ids, name, args, context=None):
|
||||
result = {}
|
||||
for cost in self.browse(cr, uid, ids, context=context):
|
||||
total = 0.0
|
||||
for line in cost.cost_lines:
|
||||
total += line.price_unit
|
||||
result[cost.id] = total
|
||||
return result
|
||||
|
||||
def _get_cost_line(self, cr, uid, ids, context=None):
|
||||
cost_to_recompute = []
|
||||
for line in self.pool.get('stock.landed.cost.lines').browse(cr, uid, ids, context=context):
|
||||
cost_to_recompute.append(line.cost_id.id)
|
||||
return cost_to_recompute
|
||||
|
||||
def onchange_pickings(self, cr, uid, ids, picking_ids=None, context=None):
|
||||
result = {'valuation_adjustment_lines': []}
|
||||
line_obj = self.pool.get('stock.valuation.adjustment.lines')
|
||||
picking_obj = self.pool.get('stock.picking')
|
||||
lines = []
|
||||
for cost in self.browse(cr, uid, ids, context=context):
|
||||
line_ids = [line.id for line in cost.valuation_adjustment_lines]
|
||||
line_obj.unlink(cr, uid, line_ids, context=context)
|
||||
picking_ids = picking_ids and picking_ids[0][2] or False
|
||||
if not picking_ids:
|
||||
return {'value': result}
|
||||
|
||||
for picking in picking_obj.browse(cr, uid, picking_ids):
|
||||
for move in picking.move_lines:
|
||||
#it doesn't make sense to make a landed cost for a product that isn't set as being valuated in real time at real cost
|
||||
if move.product_id.valuation != 'real_time' or move.product_id.cost_method != 'real':
|
||||
continue
|
||||
total_cost = 0.0
|
||||
total_qty = move.product_qty
|
||||
weight = move.product_id and move.product_id.weight * move.product_qty
|
||||
volume = move.product_id and move.product_id.volume * move.product_qty
|
||||
for quant in move.quant_ids:
|
||||
total_cost += quant.cost
|
||||
vals = dict(product_id=move.product_id.id, move_id=move.id, quantity=move.product_uom_qty, former_cost=total_cost * total_qty, weight=weight, volume=volume, flag='original')
|
||||
lines.append(vals)
|
||||
result['valuation_adjustment_lines'] = lines
|
||||
return {'value': result}
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=256, required=True, states={'done': [('readonly', True)]}, track_visibility='always'),
|
||||
'date': fields.date('Date', required=True, states={'done': [('readonly', True)]}, track_visibility='onchange'),
|
||||
'picking_ids': fields.many2many('stock.picking', string='Pickings', states={'done': [('readonly', True)]}),
|
||||
'cost_lines': fields.one2many('stock.landed.cost.lines', 'cost_id', 'Cost Lines', states={'done': [('readonly', True)]}),
|
||||
'valuation_adjustment_lines': fields.one2many('stock.valuation.adjustment.lines', 'cost_id', 'Valuation Adjustments', states={'done': [('readonly', True)]}),
|
||||
'description': fields.text('Item Description', states={'done': [('readonly', True)]}),
|
||||
'amount_total': fields.function(_total_amount, type='float', string='Total', digits_compute=dp.get_precision('Account'),
|
||||
store={
|
||||
'stock.landed.cost': (lambda self, cr, uid, ids, c={}: ids, ['cost_lines'], 20),
|
||||
'stock.landed.cost.lines': (_get_cost_line, ['price_unit', 'quantity', 'cost_id'], 20),
|
||||
}, track_visibility='always'
|
||||
),
|
||||
'state': fields.selection([('draft', 'Draft'), ('done', 'Posted'), ('cancel', 'Cancelled')], 'State', readonly=True, track_visibility='onchange'),
|
||||
'account_move_id': fields.many2one('account.move', 'Journal Entry', readonly=True),
|
||||
'account_journal_id': fields.many2one('account.journal', 'Account Journal', required=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'state': 'draft',
|
||||
'date': fields.date.context_today,
|
||||
}
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
default = {} if default is None else default.copy()
|
||||
default.update({
|
||||
'account_move_id': False,
|
||||
})
|
||||
return super(stock_landed_cost, self).copy(cr, uid, id, default=default, context=context)
|
||||
|
||||
def _create_accounting_entries(self, cr, uid, line, move_id, context=None):
|
||||
product_obj = self.pool.get('product.product')
|
||||
cost_product = line.cost_line_id and line.cost_line_id.product_id
|
||||
if not cost_product:
|
||||
return False
|
||||
accounts = product_obj.get_product_accounts(cr, uid, line.product_id.id, context=context)
|
||||
credit_account_id = accounts['stock_account_input']
|
||||
debit_account_id = cost_product.property_account_expense and cost_product.property_account_expense.id or cost_product.categ_id.property_account_expense_categ.id
|
||||
if not credit_account_id:
|
||||
raise osv.except_osv(_('Error!'), _('Please configure Stock Input Account for product: %s.') % (line.product_id.name))
|
||||
if not debit_account_id:
|
||||
raise osv.except_osv(_('Error!'), _('Please configure Stock Expense Account for product: %s.') % (cost_product.name))
|
||||
return self._create_account_move_line(cr, uid, line, move_id, credit_account_id, debit_account_id, context=context)
|
||||
|
||||
def _create_account_move_line(self, cr, uid, line, move_id, credit_account_id, debit_account_id, context=None):
|
||||
"""
|
||||
Generate the account.move.line values to track the landed cost.
|
||||
"""
|
||||
aml_obj = self.pool.get('account.move.line')
|
||||
aml_obj.create(cr, uid, {
|
||||
'name': line.name,
|
||||
'move_id': move_id,
|
||||
'product_id': line.product_id.id,
|
||||
'quantity': line.quantity,
|
||||
'debit': line.additional_landed_cost,
|
||||
'account_id': debit_account_id
|
||||
}, context=context)
|
||||
aml_obj.create(cr, uid, {
|
||||
'name': line.name,
|
||||
'move_id': move_id,
|
||||
'product_id': line.product_id.id,
|
||||
'quantity': line.quantity,
|
||||
'credit': line.additional_landed_cost,
|
||||
'account_id': credit_account_id
|
||||
}, context=context)
|
||||
return True
|
||||
|
||||
def _create_account_move(self, cr, uid, cost, context=None):
|
||||
vals = {
|
||||
'journal_id': cost.account_journal_id.id,
|
||||
'period_id': self.pool.get('account.period').find(cr, uid, cost.date, context=context)[0],
|
||||
'date': cost.date,
|
||||
'ref': cost.name
|
||||
}
|
||||
return self.pool.get('account.move').create(cr, uid, vals, context=context)
|
||||
|
||||
def button_validate(self, cr, uid, ids, context=None):
|
||||
quant_obj = self.pool.get('stock.quant')
|
||||
for cost in self.browse(cr, uid, ids, context=context):
|
||||
if not cost.valuation_adjustment_lines:
|
||||
raise osv.except_osv(_('Error!'), _('You cannot validate a landed cost which has no valuation line.'))
|
||||
move_id = self._create_account_move(cr, uid, cost, context=context)
|
||||
quant_dict = {}
|
||||
for line in cost.valuation_adjustment_lines:
|
||||
if not line.move_id:
|
||||
continue
|
||||
per_unit = line.final_cost / line.quantity
|
||||
diff = per_unit - line.former_cost_per_unit
|
||||
quants = [quant for quant in line.move_id.quant_ids]
|
||||
for quant in quants:
|
||||
if quant.id not in quant_dict:
|
||||
quant_dict[quant.id] = quant.cost + diff
|
||||
else:
|
||||
quant_dict[quant.id] += diff
|
||||
for key, value in quant_dict.items():
|
||||
quant_obj.write(cr, uid, quant.id, {'cost': value}, context=context)
|
||||
self._create_accounting_entries(cr, uid, line, move_id, context=context)
|
||||
self.write(cr, uid, cost.id, {'state': 'done', 'account_move_id': move_id}, context=context)
|
||||
return True
|
||||
|
||||
def button_cancel(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
|
||||
return True
|
||||
|
||||
def compute_landed_cost(self, cr, uid, ids, context=None):
|
||||
line_obj = self.pool.get('stock.valuation.adjustment.lines')
|
||||
for cost in self.browse(cr, uid, ids, context=None):
|
||||
total_qty = 0.0
|
||||
total_cost = 0.0
|
||||
total_weight = 0.0
|
||||
total_volume = 0.0
|
||||
total_line = 0.0
|
||||
for line in cost.valuation_adjustment_lines:
|
||||
if line.flag == 'original':
|
||||
total_qty += line.quantity
|
||||
total_cost += line.former_cost
|
||||
total_weight += line.weight
|
||||
total_volume += line.volume
|
||||
total_line += 1
|
||||
|
||||
unlink_ids = line_obj.search(cr, uid, [('cost_id', 'in', ids), ('flag', '=', 'duplicate')], context=context)
|
||||
line_obj.unlink(cr, uid, unlink_ids, context=context)
|
||||
for cost in self.browse(cr, uid, ids, context=None):
|
||||
count = 0.0
|
||||
for line in cost.cost_lines:
|
||||
count += 1
|
||||
for valuation in cost.valuation_adjustment_lines:
|
||||
if count == 1:
|
||||
line_obj.write(cr, uid, valuation.id, {'cost_line_id': line.id}, context=context)
|
||||
continue
|
||||
line_obj.copy(cr, uid, valuation.id, default={'cost_line_id': line.id, 'flag': 'duplicate'}, context=context)
|
||||
|
||||
for cost in self.browse(cr, uid, ids, context=None):
|
||||
dict = {}
|
||||
for line in cost.cost_lines:
|
||||
for valuation in cost.valuation_adjustment_lines:
|
||||
value = 0.0
|
||||
if valuation.cost_line_id and valuation.cost_line_id.id == line.id:
|
||||
if line.split_method == 'by_quantity' and total_qty:
|
||||
per_unit = (line.price_unit / total_qty)
|
||||
value = valuation.quantity * per_unit
|
||||
elif line.split_method == 'by_weight' and total_weight:
|
||||
per_unit = (line.price_unit / total_weight)
|
||||
value = valuation.weight * per_unit
|
||||
elif line.split_method == 'by_volume' and total_volume:
|
||||
per_unit = (line.price_unit / total_volume)
|
||||
value = valuation.volume * per_unit
|
||||
elif line.split_method == 'equal':
|
||||
value = (line.price_unit / total_line)
|
||||
elif line.split_method == 'by_current_cost_price' and total_cost:
|
||||
per_unit = (line.price_unit / total_cost)
|
||||
value = valuation.former_cost * per_unit
|
||||
else:
|
||||
value = (line.price_unit / total_line)
|
||||
|
||||
if valuation.id not in dict:
|
||||
dict[valuation.id] = value
|
||||
else:
|
||||
dict[valuation.id] += value
|
||||
|
||||
for key, value in dict.items():
|
||||
line_obj.write(cr, uid, key, {'additional_landed_cost': value}, context=context)
|
||||
return True
|
||||
|
||||
|
||||
class stock_landed_cost_lines(osv.osv):
|
||||
_name = 'stock.landed.cost.lines'
|
||||
_description = 'Stock Landed Cost Lines'
|
||||
|
||||
def onchange_product_id(self, cr, uid, ids, product_id=False, context=None):
|
||||
result = {}
|
||||
if not product_id:
|
||||
return {'value': {'quantity': 0.0, 'price_unit': 0.0}}
|
||||
|
||||
product = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
|
||||
result['name'] = product.name
|
||||
result['split_method'] = product.split_method
|
||||
result['price_unit'] = product.standard_price
|
||||
result['account_id'] = product.property_account_expense and cost_product.property_account_expense.id or cost_product.categ_id.property_account_expense_categ.id
|
||||
return {'value': result}
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Description', size=256),
|
||||
'cost_id': fields.many2one('stock.landed.cost', 'Landed Cost', required=True, ondelete='cascade'),
|
||||
'product_id': fields.many2one('product.product', 'Product', required=True),
|
||||
'price_unit': fields.float('Unit Price', required=True, digits_compute=dp.get_precision('Product Price')),
|
||||
'split_method': fields.selection(product.SPLIT_METHOD, string='Split Method', required=True),
|
||||
'account_id': fields.many2one('account.account', 'Account', domain=[('type', '<>', 'view'), ('type', '<>', 'closed')]),
|
||||
}
|
||||
|
||||
class stock_valuation_adjustment_lines(osv.osv):
|
||||
_name = 'stock.valuation.adjustment.lines'
|
||||
_description = 'Stock Valuation Adjustment Lines'
|
||||
|
||||
def _amount_final(self, cr, uid, ids, name, args, context=None):
|
||||
result = {}
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
result[line.id] = {
|
||||
'former_cost_per_unit': 0.0,
|
||||
'final_cost': 0.0,
|
||||
}
|
||||
result[line.id]['former_cost_per_unit'] = (line.former_cost / line.quantity if line.quantity else 1.0)
|
||||
result[line.id]['final_cost'] = (line.former_cost + line.additional_landed_cost)
|
||||
return result
|
||||
|
||||
def _get_name(self, cr, uid, ids, name, arg, context=None):
|
||||
res = {}
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
res[line.id] = line.product_id.code or line.product_id.name or ''
|
||||
if line.cost_line_id:
|
||||
res[line.id] += ' - ' + line.cost_line_id.name
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
'name': fields.function(_get_name, type='char', string='Description', store=True),
|
||||
'cost_id': fields.many2one('stock.landed.cost', 'Landed Cost', required=True, ondelete='cascade'),
|
||||
'cost_line_id': fields.many2one('stock.landed.cost.lines', 'Cost Line', readonly=True),
|
||||
'move_id': fields.many2one('stock.move', 'Stock Move', readonly=True),
|
||||
'product_id': fields.many2one('product.product', 'Product', required=True),
|
||||
'quantity': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'), required=True),
|
||||
'weight': fields.float('Weight', digits_compute=dp.get_precision('Product Unit of Measure')),
|
||||
'volume': fields.float('Volume', digits_compute=dp.get_precision('Product Unit of Measure')),
|
||||
'former_cost': fields.float('Former Cost', digits_compute=dp.get_precision('Product Price')),
|
||||
'former_cost_per_unit': fields.function(_amount_final, multi='cost', string='Former Cost(Per Unit)', type='float', digits_compute=dp.get_precision('Account'), store=True),
|
||||
'additional_landed_cost': fields.float('Additional Landed Cost', digits_compute=dp.get_precision('Product Price')),
|
||||
'final_cost': fields.function(_amount_final, multi='cost', string='Final Cost', type='float', digits_compute=dp.get_precision('Account'), store=True),
|
||||
'flag': fields.selection([('original', 'Original'), ('duplicate', 'Duplicate')], 'Flag', readonly=True),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
'quantity': 1.0,
|
||||
'weight': 1.0,
|
||||
'volume': 1.0,
|
||||
'flag': 'original',
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- Stock landed costs - related subtypes for messaging / Chatter -->
|
||||
<record id="mt_stock_landed_cost_open" model="mail.message.subtype">
|
||||
<field name="name">Open</field>
|
||||
<field name="res_model">stock.landed.cost</field>
|
||||
<field name="description">Landed cost is opened</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
|
@ -0,0 +1,162 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<!-- Stock Landed Cost Form View -->
|
||||
<record id='view_stock_landed_cost_form' model='ir.ui.view'>
|
||||
<field name="name">stock.landed.cost.form</field>
|
||||
<field name="model">stock.landed.cost</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Landed Costs" version="7.0">
|
||||
<header>
|
||||
<button name="button_validate" string="Validate" states="draft" class="oe_highlight" type="object"/>
|
||||
<button name="button_cancel" string="Cancel" states="draft" type="object"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="draft,done"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1>
|
||||
<field name="name" class="oe_inline"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date"/>
|
||||
<field name="picking_ids" widget="many2many_tags" domain="[('state', '=', 'done')]"
|
||||
on_change="onchange_pickings(picking_ids, context)"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="account_journal_id"/>
|
||||
<field name="account_move_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<separator string="Cost Lines" colspan="4"/>
|
||||
<group>
|
||||
<field name="cost_lines" nolabel="1">
|
||||
<form string="Cost Lines" version="7.0">
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id"
|
||||
on_change="onchange_product_id(product_id)" domain="[('landed_cost_ok', '=', True)]" context="{'default_landed_cost_ok': True}"/>
|
||||
<field name="price_unit"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="split_method"/>
|
||||
<field name="account_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<label for="name"/>
|
||||
<field name="name"/>
|
||||
</form>
|
||||
<tree string="Cost Lines" editable="bottom">
|
||||
<field name="product_id" on_change="onchange_product_id(product_id)" domain="[('landed_cost_ok', '=', True)]" context="{'default_landed_cost_ok': True}"/>
|
||||
<field name="name"/>
|
||||
<field name="account_id"/>
|
||||
<field name="split_method"/>
|
||||
<field name="price_unit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
<group class="oe_subtotal_footer oe_right">
|
||||
<field name="amount_total"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<separator string="Valuation Adjustments"/>
|
||||
</group>
|
||||
<group>
|
||||
<button name="compute_landed_cost" string="Compute" type="object" class="oe_right"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="valuation_adjustment_lines" nolabel="1">
|
||||
<form string="Valuation Adjustments" version="7.0">
|
||||
<group>
|
||||
<group>
|
||||
<field name="product_id"/>
|
||||
<field name="quantity"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="former_cost"/>
|
||||
<field name="additional_landed_cost"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
<tree string="Valuation Adjustments" editable="bottom">
|
||||
<field name="cost_line_id" readonly="1"/>
|
||||
<field name="product_id" readonly="1"/>
|
||||
<field name="weight"/>
|
||||
<field name="volume"/>
|
||||
<field name="quantity" readonly="1"/>
|
||||
<field name="former_cost_per_unit" readonly="1"/>
|
||||
<field name="former_cost" readonly="1"/>
|
||||
<field name="additional_landed_cost"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Landed Cost Tree View -->
|
||||
<record id='view_stock_landed_cost_tree' model='ir.ui.view'>
|
||||
<field name="name">stock.landed.cost.tree</field>
|
||||
<field name="model">stock.landed.cost</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Landed Costs">
|
||||
<field name="name"/>
|
||||
<field name="date"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Landed Cost Search View -->
|
||||
<record id="view_stock_landed_cost_search" model="ir.ui.view">
|
||||
<field name="name">stock.landed.cost.search</field>
|
||||
<field name="model">stock.landed.cost</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Landed Costs">
|
||||
<field name="name" string="Name"/>
|
||||
<field name="date"/>
|
||||
<separator/>
|
||||
<filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
|
||||
<filter string="Done" name="done" domain="[('state','=','done')]"/>
|
||||
<group expand="0" string="Group By...">
|
||||
<filter string="Month" context="{'group_by': 'date'}"/>
|
||||
<filter string="Status" context="{'group_by': 'state'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Landed Cost Action -->
|
||||
<record id='action_stock_landed_cost' model='ir.actions.act_window'>
|
||||
<field name="name">Landed Costs</field>
|
||||
<field name="res_model">stock.landed.cost</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to create a new landed cost.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Stock Landed Cost Menu -->
|
||||
<menuitem name="Landed Costs" parent="stock.menu_stock_root" id="menu_stock_landed_cost_main" sequence="1"/>
|
||||
<menuitem action="action_stock_landed_cost" name="Landed Costs" parent="menu_stock_landed_cost_main" id="menu_stock_landed_cost" sequence="1"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
Loading…
Reference in New Issue