[IMP] stock: change cost price and partial wizard
authorHarry (Open ERP) <hmo@tinyerp.com>
Fri, 26 Mar 2010 09:25:02 +0000 (14:55 +0530)
committerHarry (Open ERP) <hmo@tinyerp.com>
Fri, 26 Mar 2010 09:25:02 +0000 (14:55 +0530)
bzr revid: hmo@tinyerp.com-20100326092502-3f4jfnr6wjjrbayf

12 files changed:
addons/stock/__terp__.py
addons/stock/product.py
addons/stock/stock.py
addons/stock/stock_sequence.xml
addons/stock/stock_view.xml
addons/stock/stock_wizard.xml
addons/stock/wizard/__init__.py
addons/stock/wizard/stock_change_standard_price.py
addons/stock/wizard/stock_change_standard_price_view.xml
addons/stock/wizard/stock_partial_picking.py [new file with mode: 0644]
addons/stock/wizard/stock_partial_picking_view.xml [new file with mode: 0644]
addons/stock/wizard/wizard_partial_picking.py [deleted file]

index 52c27c7..07cfecc 100644 (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",
index ef7bfb1..d771815 100644 (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)
index 5e684d9..229ea20 100644 (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.
index d65c3df..9c5083d 100644 (file)
             <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
        -->
             <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
     -->
index 67fefcd..ec07a2f 100644 (file)
                     <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>
                                 <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>
                     <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>
                                 <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>
                     <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>
                                 <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>
             <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>
                     <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>
                                 <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>
                            <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"/>
                        <field name="name"/>
                     <field name="date"/>
                     <field name="partner_id"/>
-                    <field name="product_delivered"/>
+                    <field name="address_id"/>
                 </tree>
             </field>
         </record>
             <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>        
index 86b91e4..7e727eb 100644 (file)
             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>
\ No newline at end of file
+</openerp>
index fabee37..2d085ed 100644 (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
index 337a59f..8e2ec5f 100644 (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):
         """ 
index 4382a35..ffca108 100644 (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>
diff --git a/addons/stock/wizard/stock_partial_picking.py b/addons/stock/wizard/stock_partial_picking.py
new file mode 100644 (file)
index 0000000..bc23d03
--- /dev/null
@@ -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:
+
diff --git a/addons/stock/wizard/stock_partial_picking_view.xml b/addons/stock/wizard/stock_partial_picking_view.xml
new file mode 100644 (file)
index 0000000..2f901b9
--- /dev/null
@@ -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>
diff --git a/addons/stock/wizard/wizard_partial_picking.py b/addons/stock/wizard/wizard_partial_picking.py
deleted file mode 100644 (file)
index f602553..0000000
+++ /dev/null
@@ -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:
-