[IMP] stock: change cost price and partial wizard

bzr revid: hmo@tinyerp.com-20100326092502-3f4jfnr6wjjrbayf
This commit is contained in:
Harry (Open ERP) 2010-03-26 14:55:02 +05:30
parent 137c640c50
commit f688de89c1
12 changed files with 381 additions and 390 deletions

View File

@ -43,6 +43,7 @@ Thanks to the double entry management, the inventory controlling is powerful and
"update_xml" : [
"stock_data.xml",
"wizard/stock_move_view.xml",
"wizard/stock_partial_picking_view.xml",
"wizard/stock_inventory_set_stock_zero_view.xml",
"wizard/stock_fill_inventory_view.xml",
"wizard/stock_invoice_onshipping_view.xml",

View File

@ -24,7 +24,7 @@ from tools.translate import _
class product_product(osv.osv):
_inherit = "product.product"
_inherit = "product.product"
def do_change_standard_price(self, cr, uid, ids, datas, context={}):
"""
@ -43,16 +43,16 @@ class product_product(osv.osv):
"""
location_obj = self.pool.get('stock.location')
move_obj = self.pool.get('account.move')
move_line_obj = self.pool.get('account.move.line')
loc_ids = location_obj.search(cr, uid, [('account_id','<>',False),('usage','=','internal')])
move_line_obj = self.pool.get('account.move.line')
new_price = datas.get('new_price', 0.0)
stock_output_acc = datas.get('stock_output_account', False)
stock_input_acc = datas.get('stock_input_account', False)
journal_id = datas.get('stock_journal', False)
move_ids = []
move_ids = []
for rec_id in ids:
loc_ids = location_obj.search(cr, uid, [('account_id','<>',False),('usage','=','internal')])
for location in location_obj.browse(cr, uid, loc_ids):
c = context.copy()
c.update({
@ -62,20 +62,45 @@ class product_product(osv.osv):
product = self.browse(cr, uid, rec_id, context=c)
qty = product.qty_available
diff = product.standard_price - new_price
diff = product.standard_price - new_price
assert diff, _("Could not find any difference between standard price and new price!")
if qty:
location_account = location.account_id and location.account_id.id or False
company_id = location.company_id and location.company_id.id or False
company_id = location.company_id and location.company_id.id or False
assert location_account, _('Inventory Account is not specified for Location: %s' % (location.name))
assert company_id, _('Company is not specified in Location')
#
# Accounting Entries
#
if not journal_id:
journal_id = product.categ_id.property_stock_journal and product.categ_id.property_stock_journal.id or False
if not journal_id:
raise osv.except_osv(_('Error!'),
_('There is no journal defined '\
'on the product category: "%s" (id: %d)') % \
(product.categ_id.name,
product.categ_id.id,))
move_id = move_obj.create(cr, uid, {
'journal_id': journal_id,
'company_id': company_id
})
move_ids.append(move_id)
if diff > 0:
if diff > 0:
if not stock_input_acc:
stock_input_acc = product.product_tmpl_id.\
property_stock_account_input.id
if not stock_input_acc:
stock_input_acc = product.categ_id.\
property_stock_account_input_categ.id
if not stock_input_acc:
raise osv.except_osv(_('Error!'),
_('There is no stock input account defined ' \
'for this product: "%s" (id: %d)') % \
(product.name,
product.id,))
amount_diff = qty * diff
move_line_obj.create(cr, uid, {
'name': product.name,
@ -90,6 +115,18 @@ class product_product(osv.osv):
'move_id': move_id
})
elif diff < 0:
if not stock_output_acc:
stock_output_acc = product.product_tmpl_id.\
property_stock_account_output.id
if not stock_output_acc:
stock_output_acc = product.categ_id.\
property_stock_account_output_categ.id
if not stock_output_acc:
raise osv.except_osv(_('Error!'),
_('There is no stock output account defined ' \
'for this product: "%s" (id: %d)') % \
(product.name,
product.id,))
amount_diff = qty * -diff
move_line_obj.create(cr, uid, {
'name': product.name,
@ -106,7 +143,7 @@ class product_product(osv.osv):
self.write(cr, uid, rec_id, {'standard_price': new_price})
return True
return move_ids
def view_header_get(self, cr, user, view_id, view_type, context):
res = super(product_product, self).view_header_get(cr, user, view_id, view_type, context)

View File

@ -486,6 +486,7 @@ class stock_picking(osv.osv):
'max_date': fields.function(get_min_max_date, fnct_inv=_set_maximum_date, multi="min_max_date",
method=True, store=True, type='datetime', string='Max. Expected Date', select=2),
'move_lines': fields.one2many('stock.move', 'picking_id', 'Entry lines', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}),
'delivery_line':fields.one2many('stock.delivery', 'picking_id', 'Delivery lines', readonly=True),
'auto_picking': fields.boolean('Auto-Picking'),
'address_id': fields.many2one('res.partner.address', 'Partner', help="Address of partner"),
'invoice_state': fields.selection([
@ -856,7 +857,7 @@ class stock_picking(osv.osv):
continue
return super(stock_picking, self).unlink(cr, uid, ids, context=context)
def do_partial(self, cr, uid, ids, partial_datas, context):
def do_partial(self, cr, uid, ids, partial_datas, context={}):
"""
@ partial_datas : dict. contain details of partial picking
like partner_id, address_id, delivery_date, delivery moves with product_id, product_qty, uom
@ -869,6 +870,7 @@ class stock_picking(osv.osv):
users_obj = self.pool.get('res.users')
uom_obj = self.pool.get('product.uom')
price_type_obj = self.pool.get('product.price.type')
sequence_obj = self.pool.get('ir.sequence')
wf_service = netsvc.LocalService("workflow")
partner_id = partial_datas.get('partner_id', False)
address_id = partial_datas.get('address_id', False)
@ -877,11 +879,13 @@ class stock_picking(osv.osv):
new_picking = None
new_moves = []
complete, too_many, too_few = [], [], []
complete, too_many, too_few = [], [], []
move_product_qty = {}
for move in pick.move_lines:
partial_data = partial_datas.get('move%s'%(move.id), False)
partial_data = partial_datas.get('move%s'%(move.id), False)
assert partial_data, _('Do not Found Partial data of Stock Move Line :%s' %(move.id))
product_qty = partial_data.get('product_qty',0.0)
move_product_qty[move.id] = product_qty
product_uom = partial_data.get('product_uom',False)
product_price = partial_data.get('product_price',0.0)
product_currency = partial_data.get('product_currency',False)
@ -919,20 +923,14 @@ class stock_picking(osv.osv):
{pricetype.field: new_std_price})
move_obj.write(cr, uid, [move.id], {'price_unit': new_price})
delivery_id = delivery_obj.create(cr, uid, {
'name': pick.name,
'partner_id': partner_id,
'address_id': address_id,
'date': delivery_date,
'picking_id':pick.id
}, context=context)
for move in too_few:
product_qty = move_product_qty[move.id]
if not new_picking:
new_picking = self.copy(cr, uid, pick.id,
{
'name': pool.get('ir.sequence').get(cr, uid, 'stock.picking.%s'%(pick.type)),
'name': sequence_obj.get(cr, uid, 'stock.picking.%s'%(pick.type)),
'move_lines' : [],
'state':'draft',
})
@ -942,8 +940,7 @@ class stock_picking(osv.osv):
{
'product_qty' : product_qty,
'product_uos_qty': product_qty, #TODO: put correct uos_qty
'picking_id' : new_picking,
'delivery_id' : delivery_id,
'picking_id' : new_picking,
'state': 'assigned',
'move_dest_id': False,
'price_unit': move.price_unit,
@ -959,6 +956,7 @@ class stock_picking(osv.osv):
if new_picking:
move_obj.write(cr, uid, [c.id for c in complete], {'picking_id': new_picking})
for move in too_many:
product_qty = move_product_qty[move.id]
move_obj.write(cr, uid, [move.id],
{
'product_qty' : product_qty,
@ -967,10 +965,11 @@ class stock_picking(osv.osv):
})
else:
for move in too_many:
product_qty = move_product_qty[move.id]
move_obj.write(cr, uid, [move.id],
{
'product_qty': product_qty,
'product_uos_qty': product_qty
'product_uos_qty': product_qty #TODO: put correct uos_qty
})
# At first we confirm the new picking (if necessary)
@ -982,13 +981,22 @@ class stock_picking(osv.osv):
self.action_move(cr, uid, [new_picking])
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr)
wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
delivered_pack_id = new_picking
else:
self.action_move(cr, uid, [pick.id])
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
bo_name = ''
if new_picking:
bo_name = pick_obj.read(cr, uid, [new_picking], ['name'])[0]['name']
res[pick.id] = {'new_picking': new_picking or False, 'back_order':bo_name}
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
delivered_pack_id = pick.id
delivered_pack = self.browse(cr, uid, delivered_pack_id, context=context)
delivery_id = delivery_obj.create(cr, uid, {
'name': delivered_pack.name,
'partner_id': partner_id,
'address_id': address_id,
'date': delivery_date,
'picking_id' : pick.id,
'move_delivered' : [(6,0, map(lambda x:x.id, delivered_pack.move_lines))]
}, context=context)
res[pick.id] = {'delivered_picking': delivered_pack.id or False}
return res
stock_picking()
@ -1090,7 +1098,21 @@ class stock_production_lot_revision(osv.osv):
stock_production_lot_revision()
class stock_delivery(osv.osv):
""" Tracability of partialdeliveries """
_name = "stock.delivery"
_description = "Delivery"
_columns = {
'name': fields.char('Name', size=60, required=True),
'date': fields.datetime('Date', required=True),
'partner_id': fields.many2one('res.partner', 'Partner', required=True),
'address_id': fields.many2one('res.partner.address', 'Address', required=True),
'move_delivered':fields.one2many('stock.move', 'delivered_id', 'Move Delivered'),
'picking_id': fields.many2one('stock.picking', 'Picking list', required=True),
}
stock_delivery()
# ----------------------------------------------------
# Move
@ -1892,26 +1914,8 @@ class stock_warehouse(osv.osv):
_defaults = {
'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'stock.inventory', context=c),
}
stock_warehouse()
class stock_delivery(osv.osv):
""" Tracability of partialdeliveries """
_name = "stock.delivery"
_description = "Delivery"
_columns = {
'name': fields.char('Name', size=60, required=True),
'date': fields.datetime('Date'),
'partner_id': fields.many2one('res.partner', 'Partner'),
'address_id': fields.many2one('res.partner.address', 'Address'),
'product_delivered':fields.one2many('stock.move', 'delivered_id', 'Product Delivered', domain=[('picking_id.type','=','in')]),
'picking_id': fields.many2one('stock.picking', 'Picking list'),
}
stock_warehouse()
stock_delivery()
# Move wizard :
# get confirm or assign stock move lines of partner and put in current picking.

View File

@ -20,6 +20,11 @@
<field name="code">stock.picking.internal</field>
</record>
<record id="seq_type_picking_delivery" model="ir.sequence.type">
<field name="name">Picking Delivery</field>
<field name="code">stock.picking.delivery</field>
</record>
<!--
Sequences for pickings
-->
@ -45,6 +50,13 @@
<field name="padding">5</field>
</record>
<record id="seq_picking_delivery" model="ir.sequence">
<field name="name">Picking DLV</field>
<field name="code">stock.picking.delivery</field>
<field name="prefix">DLV/</field>
<field name="padding">5</field>
</record>
<!--
Sequences from tracking numbers
-->

View File

@ -565,7 +565,7 @@
<field name="date"/>
<field name="min_date"/>
<field name="state"/>
<button name="%(partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Picking"/>
<button name="%(action_partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Picking"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel" help="Cancel" confirm="This operation will cancel the picking. Do you want to continue?"/>
</tree>
</field>
@ -672,7 +672,7 @@
<button name="draft_validate" states="draft" string="Process Now" type="object" icon="gtk-media-play"/>
<button name="action_assign" states="confirmed" string="Check Availability" type="object" icon="gtk-find"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="%(partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-apply"/>
<button name="%(action_partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-apply"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel"/>
</group>
</page>
@ -732,7 +732,7 @@
<field name="date" select="1"/>
<field name="min_date" select="1"/>
<field name="state" select="1"/>
<button name="%(partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Delivery"/>
<button name="%(action_partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Delivery"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel" help="Cancel" confirm="This operation will cancel the delivery. Do you want to continue?"/>
</tree>
</field>
@ -833,7 +833,7 @@
<button name="draft_validate" states="draft" string="Process Now" type="object" icon="gtk-media-play"/>
<button name="action_assign" states="confirmed" string="Check Availability" type="object" icon="gtk-find"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="%(partial_picking)d" states="assigned" string="Products Sent" type="action" icon="gtk-go-forward"/>
<button name="%(action_partial_picking)d" states="assigned" string="Products Sent" type="action" icon="gtk-go-forward"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel"/>
</group>
</page>
@ -926,7 +926,7 @@
<field name="min_date"/>
<field name="invoice_state"/>
<field name="state"/>
<button name="%(partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Picking"/>
<button name="%(action_partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-go-forward" help="Validate Picking"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel" help="Cancel" confirm="This operation will cancel the picking. Do you want to continue?"/>
</tree>
</field>
@ -1030,10 +1030,13 @@
<button name="draft_validate" states="draft" string="Process Now" type="object" icon="gtk-yes"/>
<button name="action_assign" states="confirmed" string="Check Availability" type="object" groups="base.group_extended" icon="gtk-apply"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" icon="gtk-jump-to"/>
<button name="%(partial_picking)d" states="assigned" string="Picking Done" type="action" icon="gtk-execute"/>
<button name="%(action_partial_picking)d" states="assigned" string="Picking Done" type="action" icon="gtk-execute"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel"/>
</group>
</page>
<page string="Delivery Info">
<field colspan="4" name="delivery_line" nolabel="1"/>
</page>
<page string="Notes">
<field colspan="4" name="note" nolabel="1"/>
</page>
@ -1101,7 +1104,7 @@
<field name="view_mode">calendar</field>
<field name="act_window_id" ref="action_picking_tree"/>
</record>
<!-- <menuitem action="action_picking_tree" id="menu_action_picking_tree" parent="menu_stock_root" sequence="19"/>-->
<menuitem action="action_picking_tree" id="menu_action_picking_tree" parent="menu_stock_warehouse_mgmt" sequence="5"/>
<record id="view_picking_in_tree" model="ir.ui.view">
<field name="name">stock.picking.in.tree</field>
@ -1117,7 +1120,7 @@
<field name="min_date"/>
<field name="invoice_state"/>
<field name="state"/>
<button name="%(partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-ok" help="Receive products"/>
<button name="%(action_partial_picking)d" states="assigned" string="Validate" type="action" icon="gtk-ok" help="Receive products"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel" help="Cancel" confirm="This operation will cancel the shipment. Do you want to continue?" />
</tree>
</field>
@ -1220,10 +1223,13 @@
<button name="draft_validate" states="draft" string="Process Now" type="object" icon="gtk-media-play"/>
<button name="action_assign" states="confirmed" string="Check Availability" type="object" icon="gtk-find"/>
<button name="force_assign" states="confirmed" string="Force Availability" type="object" groups="base.group_extended" icon="gtk-jump-to"/>
<button name="%(partial_picking)d" states="assigned" string="Products Received" type="action" icon="gtk-ok"/>
<button name="%(action_partial_picking)d" states="assigned" string="Products Received" type="action" icon="gtk-ok"/>
<button name="button_cancel" states="assigned,confirmed,draft" string="Cancel" icon="gtk-cancel"/>
</group>
</page>
<page string="Delivery Info">
<field colspan="4" name="delivery_line" nolabel="1"/>
</page>
<page string="Notes">
<field colspan="4" name="note" nolabel="1"/>
</page>
@ -1760,7 +1766,7 @@
<field name="address_id"/>
<field name="picking_id"/>
<separator string="Product Delivered Information" colspan="4" />
<field name="product_delivered" colspan="4" nolabel="1" widget="one2many" mode="tree,form">
<field name="move_delivered" colspan="4" nolabel="1" widget="one2many" mode="tree,form">
<tree string="Stock Moves" editable="top">
<field name="picking_id" string="Reference"/>
<field name="origin" string="Latest Requisition"/>
@ -1783,7 +1789,7 @@
<field name="name"/>
<field name="date"/>
<field name="partner_id"/>
<field name="product_delivered"/>
<field name="address_id"/>
</tree>
</field>
</record>
@ -1792,8 +1798,7 @@
<field name="name">Delivered Products</field>
<field name="res_model">stock.delivery</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<!-- <field name="target">new</field> -->
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="view_stock_delivery_tree"/>
</record>

View File

@ -13,14 +13,7 @@
multi="True"
name="stock.move.split"
string="Split move line"/>
<wizard
id="partial_picking"
model="stock.picking"
menu="False"
keyword="client_action_multi"
name="stock.partial_picking"
string="Partial picking"/>
<wizard
id="make_picking"
@ -61,4 +54,4 @@
id="wizard_merge_inventory"/>
</data>
</openerp>
</openerp>

View File

@ -21,7 +21,7 @@
import stock_traceability
import stock_move
import wizard_partial_picking
import stock_partial_picking
import wizard_partial_move
import wizard_picking_make
import wizard_replacement

View File

@ -79,9 +79,9 @@ class change_standard_price(osv.osv_memory):
price = product_obj.standard_price
diff = price - new_price
if diff > 0 :
return {'value' : {'enable_stock_in_out_acc':False}}
else :
return {'value' : {'enable_stock_in_out_acc':True}}
else :
return {'value' : {'enable_stock_in_out_acc':False}}
def change_price(self, cr, uid, ids, context):
"""

View File

@ -7,17 +7,12 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Change Standard Price">
<field name="new_price" on_change="onchange_price(new_price, context)" context="{'active_id': active_id}"/>
<newline/>
<field name="stock_account_input" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]" attrs="{'readonly':[('enable_stock_in_out_acc','=',False)],'required': [('enable_stock_in_out_acc','=',True)]}"/>
<newline/>
<field name="stock_account_output" domain="[('type','&lt;&gt;','view'),('type','&lt;&gt;','consolidation')]" attrs="{'readonly':[('enable_stock_in_out_acc','=',True)],'required': [('enable_stock_in_out_acc','=',False)]}"/>
<newline/>
<field name="stock_journal"/>
<field name="enable_stock_in_out_acc" invisible="1"/>
<group col="2" colspan="4">
<button special="cancel" string="Cancel" icon="gtk-cancel"/>
<button name="change_price" string="Change" type="object" icon="gtk-ok"/>
<field name="new_price"/>
<separator string="" colspan="4" />
<label string="" colspan="2"/>
<group col="2" colspan="2">
<button special="cancel" string="_Cancel" icon="gtk-cancel"/>
<button name="change_price" string="_Apply" type="object" icon="gtk-apply"/>
</group>
</form>
</field>

View File

@ -0,0 +1,237 @@
# -*- 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 osv import fields, osv
from service import web_services
from tools.translate import _
import netsvc
import pooler
import time
class stock_partial_picking(osv.osv_memory):
_name = "stock.partial.picking"
_description = "Partial Picking"
_columns = {
'date': fields.datetime('Date', required=True),
'partner_id': fields.many2one('res.partner',string="Partner", required=True),
'address_id': fields.many2one('res.partner.address', 'Delivery Address', help="Address where goods are to be delivered", required=True),
}
def view_init(self, cr, uid, fields_list, context=None):
res = super(stock_partial_picking, self).view_init(cr, uid, fields_list, context=context)
pick_obj = self.pool.get('stock.picking')
if not context:
context={}
moveids = []
for pick in pick_obj.browse(cr, uid, context.get('active_ids', [])):
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
if 'move%s_product_id'%(m.id) not in self._columns:
self._columns['move%s_product_id'%(m.id)] = fields.many2one('product.product',string="Product")
if 'move%s_product_qty'%(m.id) not in self._columns:
self._columns['move%s_product_qty'%(m.id)] = fields.float("Quantity")
if 'move%s_product_uom'%(m.id) not in self._columns:
self._columns['move%s_product_uom'%(m.id)] = fields.many2one('product.uom',string="Product UOM")
if (pick.type == 'in') and (m.product_id.cost_method == 'average'):
if 'move%s_product_price'%(m.id) not in self._columns:
self._columns['move%s_product_price'%(m.id)] = fields.float("Price")
if 'move%s_product_currency'%(m.id) not in self._columns:
self._columns['move%s_product_currency'%(m.id)] = fields.many2one('res.currency',string="Currency")
return res
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False,submenu=False):
result = super(stock_partial_picking, self).fields_view_get(cr, uid, view_id, view_type, context, toolbar,submenu)
pick_obj = self.pool.get('stock.picking')
picking_ids = context.get('active_ids', False)
if not picking_ids:
return result
if view_type in ['form']:
_moves_arch_lst = """<form string="Deliver Products">
<separator colspan="4" string="Delivery Information"/>
<field name="date" colspan="4" />
<field name="partner_id"/>
<field name="address_id"/>
<newline/>
<separator colspan="4" string="Move Detail"/>
"""
_moves_fields = result['fields']
for pick in pick_obj.browse(cr, uid, picking_ids, context):
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
_moves_fields.update({
'move%s_product_id'%(m.id) : {
'string': _('Product'),
'type' : 'many2one',
'relation': 'product.product',
'required' : True,
'readonly' : True,
},
'move%s_product_qty'%(m.id) : {
'string': _('Quantity'),
'type' : 'float',
'required': True,
},
'move%s_product_uom'%(m.id) : {
'string': _('Product UOM'),
'type' : 'many2one',
'relation': 'product.uom',
'required' : True,
'readonly' : True,
}
})
_moves_arch_lst += """
<group colspan="4" col="10">
<field name="move%s_product_id" />
<field name="move%s_product_qty" />
<field name="move%s_product_uom" />
"""%(m.id, m.id, m.id)
if (pick.type == 'in') and (m.product_id.cost_method == 'average'):
_moves_fields.update({
'move%s_product_price'%(m.id) : {
'string': _('Price'),
'type' : 'float',
},
'move%s_product_currency'%(m.id): {
'string': _('Currency'),
'type' : 'float',
'type' : 'many2one',
'relation': 'res.currency',
}
})
_moves_arch_lst += """
<field name="move%s_product_price" />
<field name="move%s_product_currency" />
"""%(m.id, m.id)
_moves_arch_lst += """
</group>
"""
_moves_arch_lst += """
<separator string="" colspan="4" />
<label string="" colspan="2"/>
<group col="2" colspan="2">
<button icon='gtk-cancel' special="cancel"
string="_Cancel" />
<button name="do_partial" string="_Deliver"
colspan="1" type="object" icon="gtk-apply" />
</group>
</form>"""
result['arch'] = _moves_arch_lst
result['fields'] = _moves_fields
return result
def default_get(self, cr, uid, fields, context=None):
"""
To get default values for the object.
@param self: The object pointer.
@param cr: A database cursor
@param uid: ID of the user currently logged in
@param fields: List of fields for which we want default values
@param context: A standard dictionary
@return: A dictionary which of fields with values.
"""
res = super(stock_partial_picking, self).default_get(cr, uid, fields, context=context)
pick_obj = self.pool.get('stock.picking')
if not context:
context={}
moveids = []
for pick in pick_obj.browse(cr, uid, context.get('active_ids', [])):
if 'partner_id' in fields:
res.update({'partner_id': pick.address_id.partner_id.id})
if 'address_id' in fields:
res.update({'address_id': pick.address_id.id})
if 'date' in fields:
res.update({'date': pick.date})
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
if 'move%s_product_id'%(m.id) in fields:
res['move%s_product_id'%(m.id)] = m.product_id.id
if 'move%s_product_qty'%(m.id) in fields:
res['move%s_product_qty'%(m.id)] = m.product_qty
if 'move%s_product_uom'%(m.id) in fields:
res['move%s_product_uom'%(m.id)] = m.product_uom.id
if (pick.type == 'in') and (m.product_id.cost_method == 'average'):
price = 0
if hasattr(m, 'purchase_line_id') and m.purchase_line_id:
price = m.purchase_line_id.price_unit
currency = False
if hasattr(pick, 'purchase_id') and pick.purchase_id:
currency = pick.purchase_id.pricelist_id.currency_id.id
if 'move%s_product_price'%(m.id) in fields:
res['move%s_product_price'%(m.id)] = price
if 'move%s_product_currency'%(m.id) in fields:
res['move%s_product_currency'%(m.id)] = currency
return res
def do_partial(self, cr, uid, ids, context):
pick_obj = self.pool.get('stock.picking')
picking_ids = context.get('active_ids', False)
partial = self.browse(cr, uid, ids[0], context)
partial_datas = {
'partner_id' : partial.partner_id and partial.partner_id.id or False,
'address_id' : partial.address_id and partial.address_id.id or False,
'delivery_date' : partial.date
}
for pick in pick_obj.browse(cr, uid, picking_ids):
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
partial_datas['move%s'%(m.id)] = {
'product_id' : getattr(partial, 'move%s_product_id'%(m.id)),
'product_qty' : getattr(partial, 'move%s_product_qty'%(m.id)),
'product_uom' : getattr(partial, 'move%s_product_uom'%(m.id))
}
if (pick.type == 'in') and (m.product_id.cost_method == 'average'):
partial_datas['move%s'%(m.id)].update({
'product_price' : getattr(partial, 'move%s_product_price'%(m.id)),
'product_currency': getattr(partial, 'move%s_product_currency'%(m.id))
})
res = pick_obj.do_partial(cr, uid, picking_ids, partial_datas, context=context)
return {}
stock_partial_picking()
#_moves_arch_end = '''<?xml version="1.0"?>
#<form string="Picking result">
# <label string="The picking has been successfully made !" colspan="4"/>
# <field name="back_order_notification" colspan="4" nolabel="1"/>
#</form>'''
#_moves_fields_end = {
# 'back_order_notification': {'string':'Back Order' ,'type':'text', 'readonly':True}
# }
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="action_partial_picking" model="ir.actions.act_window">
<field name="name">Making Picking</field>
<field name="res_model">stock.partial.picking</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

View File

@ -1,306 +0,0 @@
# -*- 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
import netsvc
from tools.misc import UpdateableStr, UpdateableDict
import pooler
import wizard
from osv import osv
import tools
from tools.translate import _
_moves_arch = UpdateableStr()
_moves_fields = UpdateableDict()
_moves_arch_end = '''<?xml version="1.0"?>
<form string="Picking result">
<label string="The picking has been successfully made !" colspan="4"/>
<field name="back_order_notification" colspan="4" nolabel="1"/>
</form>'''
_moves_fields_end = {
'back_order_notification': {'string':'Back Order' ,'type':'text', 'readonly':True}
}
def make_default(val):
def fct(uid, data, state):
return val
return fct
def _to_xml(s):
return (s or '').replace('&','&amp;').replace('<','&lt;').replace('>','&gt;')
def _get_moves(self, cr, uid, data, context):
pick_obj = pooler.get_pool(cr.dbname).get('stock.picking')
pick = pick_obj.browse(cr, uid, [data['id']], context)[0]
res = {}
_moves_fields.clear()
#TODO: cleanup and this code..
_moves_arch_lst = ['<?xml version="1.0"?>', '<form string="Make picking">']
_moves_arch_lst.append('<field name="partner_id%d"/>' % (pick.id,))
_moves_fields['partner_id%s' % pick.id] ={'string':'Partner',
'type':'many2one', 'relation':'res.partner', 'required' : '1','default': make_default(pick.address_id.partner_id.id)}
_moves_arch_lst.append('<field name="address_id%d"/>' % (pick.id))
_moves_fields['address_id%s' % pick.id] ={'string':'Delivery Address',
'type':'many2one', 'relation':'res.partner.address', 'required' : '1','default': make_default(pick.address_id.id)}
_moves_arch_lst.append('<newline/>')
_moves_arch_lst.append('<field name="date%d"/>' % (pick.id))
_moves_fields['date%s' % pick.id] ={'string':'Date',
'type':'date', 'required' : '1','default': make_default(pick.date)}
_moves_arch_lst.append('<newline/>')
_moves_arch_lst.append('<separator string="Delivery Detail" colspan="4"/>')
_moves_arch_lst.append('<label string="Product" align="0.0" />')
_moves_arch_lst.append('<label string="Quantity" align="10.0" />')
_moves_arch_lst.append('<label string="UOM" align="10.0" />')
for m in pick.move_lines:
if m.state in ('done', 'cancel'):
continue
quantity = m.product_qty
if m.state!='assigned':
quantity = 0
_moves_fields
_moves_arch_lst.append('<group colspan="6" col="3">')
_moves_arch_lst.append('<field name="name%s" nolabel="1" />' % (m.id,))
_moves_fields['name%s' % m.id] = {
'string': 'Product',
'type' : 'many2one', 'relation': 'product.product', 'required' : True, 'default' : make_default(m.product_id.id)}
_moves_arch_lst.append('<field name="move%s" nolabel="1" />' % (m.id,))
_moves_fields['move%s' % m.id] = {
'string': 'Quantity',
'type' : 'float', 'required' : True, 'default' : make_default(quantity)}
_moves_arch_lst.append('<field name="uom%s" nolabel="1"/>'% (m.id,))
_moves_fields['uom%s' % m.id] = {'string': 'UOM', 'type': 'many2one',
'relation': 'product.uom', 'readonly':True,'required': True,
'default': make_default(m.product_uom.id)}
_moves_arch_lst.append('</group>')
if (pick.type == 'in') and (m.product_id.cost_method == 'average'):
price=0
if hasattr(m, 'purchase_line_id') and m.purchase_line_id:
price=m.purchase_line_id.price_unit
currency=0
if hasattr(pick, 'purchase_id') and pick.purchase_id:
currency=pick.purchase_id.pricelist_id.currency_id.id
_moves_arch_lst.append('<group col="6"><field name="uom%s" nolabel="1"/>\
<field name="price%s"/>' % (m.id,m.id,))
_moves_fields['price%s' % m.id] = {'string': 'Unit Price',
'type': 'float', 'required': True, 'default': make_default(price)}
_moves_fields['uom%s' % m.id] = {'string': 'UOM', 'type': 'many2one',
'relation': 'product.uom', 'required': True,
'default': make_default(m.product_uom.id)}
_moves_arch_lst.append('<field name="currency%d" nolabel="1"/></group>' % (m.id,))
_moves_fields['currency%s' % m.id] = {'string': 'Currency',
'type': 'many2one', 'relation': 'res.currency',
'required': True, 'default': make_default(currency)}
_moves_arch_lst.append('<newline/>')
_moves_arch_lst.append('<newline/>')
res.setdefault('moves', []).append(m.id)
_moves_arch_lst.append('</form>')
_moves_arch.string = '\n'.join(_moves_arch_lst)
return res
def _do_split(self, cr, uid, data, context):
move_obj = pooler.get_pool(cr.dbname).get('stock.move')
pick_obj = pooler.get_pool(cr.dbname).get('stock.picking')
delivery_obj = pooler.get_pool(cr.dbname).get('stock.delivery')
pick = pick_obj.browse(cr, uid, [data['id']])[0]
new_picking = None
new_moves = []
complete, too_many, too_few = [], [], []
pool = pooler.get_pool(cr.dbname)
for move in move_obj.browse(cr, uid, data['form'].get('moves',[])):
if move.product_qty == data['form']['move%s' % move.id]:
complete.append(move)
elif move.product_qty > data['form']['move%s' % move.id]:
too_few.append(move)
else:
too_many.append(move)
# Average price computation
if (pick.type == 'in') and (move.product_id.cost_method == 'average'):
product_obj = pool.get('product.product')
currency_obj = pool.get('res.currency')
users_obj = pool.get('res.users')
uom_obj = pool.get('product.uom')
product = product_obj.browse(cr, uid, [move.product_id.id])[0]
user = users_obj.browse(cr, uid, [uid])[0]
qty = data['form']['move%s' % move.id]
uom = data['form']['uom%s' % move.id]
price = data['form']['price%s' % move.id]
currency = data['form']['currency%s' % move.id]
qty = uom_obj._compute_qty(cr, uid, uom, qty, product.uom_id.id)
pricetype=pool.get('product.price.type').browse(cr,uid,user.company_id.property_valuation_price_type.id)
if (qty > 0):
new_price = currency_obj.compute(cr, uid, currency,
user.company_id.currency_id.id, price)
new_price = uom_obj._compute_price(cr, uid, uom, new_price,
product.uom_id.id)
if product.qty_available<=0:
new_std_price = new_price
else:
# Get the standard price
amount_unit=product.price_get(pricetype.field, context)[product.id]
new_std_price = ((amount_unit * product.qty_available)\
+ (new_price * qty))/(product.qty_available + qty)
# Write the field according to price type field
product_obj.write(cr, uid, [product.id],
{pricetype.field: new_std_price})
move_obj.write(cr, uid, [move.id], {'price_unit': new_price})
for move in too_few:
if not new_picking:
new_picking = pick_obj.copy(cr, uid, pick.id,
{
'name': pool.get('ir.sequence').get(cr, uid, 'stock.picking.in'),
'move_lines' : [],
'state':'draft',
})
if data['form']['move%s' % move.id] != 0:
new_obj = move_obj.copy(cr, uid, move.id,
{
'product_qty' : data['form']['move%s' % move.id],
'product_uos_qty':data['form']['move%s' % move.id],
'picking_id' : new_picking,
'state': 'assigned',
'move_dest_id': False,
'partner_id': data['form']['partner_id%s' % pick.id],
'address_id': data['form']['address_id%s' % pick.id],
'price_unit': move.price_unit,
})
delivery_id = delivery_obj.search(cr,uid, [('name','=',pick.name)])
if not delivery_id :
delivery_id = delivery_obj.create(cr, uid, {
'name': pick.name,
'partner_id': data['form']['partner_id%s' % pick.id],
'address_id': data['form']['address_id%s' % pick.id],
'date': move.date,
'product_delivered':[(6,0, [new_obj])],
'picking_id':move.picking_id.id
}, context=context)
if not isinstance(delivery_id, (int, long)):
delivery_id=delivery_id[0]
delivery_obj.write(cr, uid, [delivery_id], {'product_delivered': [(4, new_obj)]})
move_obj.write(cr, uid, [move.id],
{
'product_qty' : move.product_qty - data['form']['move%s' % move.id],
'product_uos_qty':move.product_qty - data['form']['move%s' % move.id],
# 'delivered_id':delivery_id
})
if new_picking:
move_obj.write(cr, uid, [c.id for c in complete], {'picking_id': new_picking})
for move in too_many:
move_obj.write(cr, uid, [move.id],
{
'product_qty' : data['form']['move%s' % move.id],
'product_uos_qty': data['form']['move%s' % move.id],
'picking_id': new_picking,
})
else:
for move in too_many:
move_obj.write(cr, uid, [move.id],
{
'product_qty': data['form']['move%s' % move.id],
'product_uos_qty': data['form']['move%s' % move.id]
})
# At first we confirm the new picking (if necessary)
wf_service = netsvc.LocalService("workflow")
if new_picking:
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_confirm', cr)
# Then we finish the good picking
if new_picking:
pick_obj.write(cr, uid, [pick.id], {'backorder_id': new_picking})
pick_obj.action_move(cr, uid, [new_picking])
wf_service.trg_validate(uid, 'stock.picking', new_picking, 'button_done', cr)
wf_service.trg_write(uid, 'stock.picking', pick.id, cr)
else:
pick_obj.action_move(cr, uid, [pick.id])
wf_service.trg_validate(uid, 'stock.picking', pick.id, 'button_done', cr)
bo_name = ''
if new_picking:
bo_name = pick_obj.read(cr, uid, [new_picking], ['name'])[0]['name']
return {'new_picking':new_picking or False, 'back_order':bo_name}
def _get_default(self, cr, uid, data, context):
if data['form']['back_order']:
data['form']['back_order_notification'] = _('Back Order %s Assigned to this Picking.') % (tools.ustr(data['form']['back_order']),)
return data['form']
class partial_picking(wizard.interface):
states = {
'init': {
'actions': [ _get_moves ],
'result': {'type': 'form', 'arch': _moves_arch, 'fields': _moves_fields,
'state' : (
('end', 'Cancel', 'gtk-cancel'),
('split', 'Make Picking', 'gtk-apply', True)
)
},
},
'split': {
'actions': [ _do_split ],
'result': {'type': 'state', 'state': 'end2'},
},
'end2': {
'actions': [ _get_default ],
'result': {'type': 'form', 'arch': _moves_arch_end,
'fields': _moves_fields_end,
'state': (
('end', 'Close'),
)
},
},
}
partial_picking('stock.partial_picking')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: