← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~openerp-dev/openobject-addons/ksa-addons2 into lp:~openerp-dev/openobject-addons/trunk-dev-addons2

 

ksa(OpenERP) has proposed merging lp:~openerp-dev/openobject-addons/ksa-addons2 into lp:~openerp-dev/openobject-addons/trunk-dev-addons2.

Requested reviews:
  OpenERP R&D Team (openerp-dev)
Related bugs:
  #500931 No analytic entry is generated finishing one production order
  https://bugs.launchpad.net/bugs/500931
  #543979 product: check uos not necessary
  https://bugs.launchpad.net/bugs/543979
  #674551 "qunatity" in MRP
  https://bugs.launchpad.net/bugs/674551
  #675418 account moves with same account in debit and credit
  https://bugs.launchpad.net/bugs/675418


Task- 1847
* Add m2m function field on orderpoint for draft procurement of the product and location of that orderpoint
* change the logic when compute scheduler with automatic orderpoint such that it considers all draft procurement for that orderpoint and create MO/PO accordingly
-- 
https://code.launchpad.net/~openerp-dev/openobject-addons/ksa-addons2/+merge/42823
Your team OpenERP R&D Team is requested to review the proposed merge of lp:~openerp-dev/openobject-addons/ksa-addons2 into lp:~openerp-dev/openobject-addons/trunk-dev-addons2.
=== modified file 'mrp/mrp.py'
--- mrp/mrp.py	2010-11-22 13:47:16 +0000
+++ mrp/mrp.py	2010-12-06 11:00:31 +0000
@@ -53,11 +53,23 @@
         'costs_journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal'),
         'costs_general_account_id': fields.many2one('account.account', 'General Account', domain=[('type','<>','view')]),
         'resource_id': fields.many2one('resource.resource','Resource', ondelete='cascade', required=True),
+        'product_id': fields.many2one('product.product','Product'),
     }
     _defaults = {
         'capacity_per_cycle': 1.0,
         'resource_type': 'material',
      }
+
+    def on_change_product_cost(self, cr, uid, ids, product_id, context=None):
+        if context is None:
+            context = {}
+        res = {'value':{}}
+
+        if product_id:
+            cost = self.pool.get('product.product').browse(cr, uid, product_id, context=context)
+            res = {'value' : {'costs_hour' :cost.standard_price }}
+        return res
+
 mrp_workcenter()
 
 
@@ -737,7 +749,10 @@
                         'account_id': account,
                         'general_account_id': wc.costs_general_account_id.id,
                         'journal_id': wc.costs_journal_id.id,
-                        'code': wc.code
+                        'ref': wc.code,
+                        'product_id': wc.product_id.id,
+                        'unit_amount': wc.costs_hour * wc.time_cycle,
+                        'product_uom_id': wc.product_id.uom_id.id
                     } )
             if wc.costs_journal_id and wc.costs_general_account_id:
                 value = wc_line.cycle * wc.costs_cycle
@@ -750,7 +765,10 @@
                         'account_id': account,
                         'general_account_id': wc.costs_general_account_id.id,
                         'journal_id': wc.costs_journal_id.id,
-                        'code': wc.code,
+                        'ref': wc.code,
+                        'product_id': wc.product_id.id,
+                        'unit_amount': wc.costs_hour * wc.time_cycle,
+                        'product_uom_id': wc.product_id.uom_id.id
                     } )
         return amount
 

=== modified file 'mrp/mrp_view.xml'
--- mrp/mrp_view.xml	2010-11-22 18:13:26 +0000
+++ mrp/mrp_view.xml	2010-12-06 11:00:31 +0000
@@ -160,12 +160,13 @@
                             </group>
                             <group col="2" colspan="2">
                             <separator colspan="2" string="Costing Information"/>
+                            <field name="product_id" on_change="on_change_product_cost(product_id)"/>
                             <field name="costs_hour"/>
                             <field name="costs_hour_account_id" groups="analytic.group_analytic_accounting"/>
                             <field name="costs_cycle"/>
                             <field name="costs_cycle_account_id" groups="analytic.group_analytic_accounting"/>
-                            <field name="costs_journal_id" groups="analytic.group_analytic_accounting"/>
-                            <field name="costs_general_account_id" groups="analytic.group_analytic_accounting"/>
+                             <field name="costs_journal_id" attrs="{'required':['|',('costs_hour_account_id', '=', True),('costs_cycle_account_id', '=', True)]}" groups="analytic.group_analytic_accounting"/>
+                            <field name="costs_general_account_id" attrs="{ 'required':['|',('costs_cycle_account_id', '=', True),('costs_hour_account_id', '=', True)]}" groups="analytic.group_analytic_accounting"/>
                             </group>
                             <separator colspan="4" string="Description"/>
                             <field colspan="4" name="note" nolabel="1"/>
@@ -649,9 +650,9 @@
                                     <field name="product_uom"  string="UOM" widget="selection"/>
                                     <field name="location_id"  string="Source Loc." />
                                     <field name="state" invisible="1"/>
-                                    <button name="%(stock.action_partial_move)d" 
-                                        string="Partial" 
-                                        type="action" states="confirmed,assigned" 
+                                    <button name="%(stock.action_partial_move)d"
+                                        string="Partial"
+                                        type="action" states="confirmed,assigned"
                                         icon="gtk-justify-fill"/>
                                     <button name="%(stock.move_scrap)d"
                                         string="Scrap Products" type="action"
@@ -926,9 +927,9 @@
         <menuitem action="mrp_workcenter_action" id="menu_view_resource_search_mrp" parent="menu_pm_resources_config" sequence="1"/>
         <menuitem action="resource.action_resource_calendar_form" id="menu_view_resource_calendar_search_mrp" parent="menu_pm_resources_config" sequence="1"/>
         <menuitem action="resource.action_resource_calendar_leave_tree" id="menu_view_resource_calendar_leaves_search_mrp" parent="menu_pm_resources_config" sequence="1"/>
-        
+
         <!-- Planning -->
-        
+
         <menuitem id="menu_mrp_planning" name="Planning"
 		        parent="base.menu_mrp_root" sequence="2"
 		        groups="base.group_extended"/>

=== modified file 'mrp/wizard/mrp_price.py'
--- mrp/wizard/mrp_price.py	2010-11-22 13:47:16 +0000
+++ mrp/wizard/mrp_price.py	2010-12-06 11:00:31 +0000
@@ -25,7 +25,7 @@
     _name = 'mrp.product_price'
     _description = 'Product Price'
     _columns = {
-        'number': fields.integer('Quantity', required=True, help="Specify quantity of products to produce or buy. Report of Cost structure will be displayed base on this qunatity."),
+        'number': fields.integer('Quantity', required=True, help="Specify quantity of products to produce or buy. Report of Cost structure will be displayed base on this quantity."),
     }
     _defaults = {
         'number': 1,

=== modified file 'procurement/procurement.py'
--- procurement/procurement.py	2010-11-22 12:38:00 +0000
+++ procurement/procurement.py	2010-12-06 11:00:31 +0000
@@ -490,6 +490,17 @@
     _name = "stock.warehouse.orderpoint"
     _description = "Minimum Inventory Rule"
 
+    def procurement_draft(self, cr, uid, ids, field_name, arg, context=None):
+        if context is None:
+            context = {}
+        result = {}
+        procurement_obj = self.pool.get('procurement.order')
+        for data in self.browse(cr, uid, ids, context=context):
+
+            procurement_ids = procurement_obj.search(cr, uid , [('state','=','draft'),('product_id','=',data.product_id.id),('location_id','=',data.location_id.id)])
+            result[data.id] = procurement_ids
+        return result
+
     _columns = {
         'name': fields.char('Name', size=32, required=True),
         'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the orderpoint without removing it."),
@@ -508,6 +519,8 @@
             help="The procurement quantity will by rounded up to this multiple."),
         'procurement_id': fields.many2one('procurement.order', 'Latest procurement', ondelete="set null"),
         'company_id': fields.many2one('res.company','Company',required=True),
+        'procurement_draft_ids': fields.function(procurement_draft, method=True, type='many2many', relation="procurement.order", \
+                                string="Related Procurement Orders",help="Draft procurement of the product and location of that orderpoint"),
     }
     _defaults = {
         'active': lambda *a: 1,

=== modified file 'procurement/procurement_view.xml'
--- procurement/procurement_view.xml	2010-11-15 09:43:30 +0000
+++ procurement/procurement_view.xml	2010-12-06 11:00:31 +0000
@@ -4,7 +4,7 @@
 		<!--
         Procurement
         -->
-		
+
 
         <record id="procurement_tree_view" model="ir.ui.view">
             <field name="name">procurement.order.tree</field>
@@ -145,7 +145,7 @@
             <field name="search_view_id" ref="view_procurement_filter"/>
             <field name="help">Procurement Orders represent the need for a certain quantity of products, at a given time, in a given location. Sale Orders are one typical source of Procurement Orders (but these are distinct documents). Depending on the procurement parameters and the products configuration, the procurement engine will attempt to satisfy the need by reserving products from stock, or ordering products from a supplier, or passing a manufacturing order, etc. A Procurement Exception occurs when the system cannot find a way to fulfill a procurement. Some exceptions will resolve themselves automatically, but others require manual intervention (those are identified by a specific error message)</field>
         </record>
-        
+
         <record id="procurement_action5" model="ir.actions.act_window">
             <field name="name">Procurement Exceptions</field>
             <field name="type">ir.actions.act_window</field>
@@ -224,6 +224,10 @@
                         <field name="procurement_id" readonly="1"/>
                         <field name="active" />
                     </group>
+                    <group col="4" colspan="4" groups="base.group_extended">
+                        <separator string="Related Procurement Orders" colspan="4" />
+                        <field name="procurement_draft_ids" colspan="4" nolabel="1"/>
+                    </group>
                 </form>
             </field>
         </record>
@@ -238,11 +242,11 @@
             <field name="help">You can define your minimum stock rules, so that OpenERP will trigger automatically the propositions of manufacturing or purchase orders according to the stock level. Once the virtual stock of a product (=stock on hand minus all confirmed orders and reservations) is bellow the minimum quantity, OpenERP will generate a procurement request in order to fullfil the stock up to the maximum quantity.</field>
         </record>
 
-        <act_window 
+        <act_window
         context="{'search_default_warehouse_id': active_id}"
         id="act_stock_warehouse_2_stock_warehouse_orderpoint"
-        name="Minimum Stock Rules" 
-        res_model="stock.warehouse.orderpoint" 
+        name="Minimum Stock Rules"
+        res_model="stock.warehouse.orderpoint"
         src_model="stock.warehouse"/>
 
         <!-- add product_uom to context to be the default value when adding new orderpoints -->

=== modified file 'procurement/schedulers.py'
--- procurement/schedulers.py	2010-11-12 12:54:47 +0000
+++ procurement/schedulers.py	2010-12-06 11:00:31 +0000
@@ -34,14 +34,14 @@
     def _procure_confirm(self, cr, uid, ids=None, use_new_cursor=False, context=None):
         '''
         Call the scheduler to check the procurement order
-        
+
         @param self: The object pointer
         @param cr: The current row, from the database cursor,
         @param uid: The current user ID for security checks
         @param ids: List of selected IDs
         @param use_new_cursor: False or the dbname
         @param context: A standard dictionary for contextual values
-        @return:  Dictionary of values        
+        @return:  Dictionary of values
         '''
         if not context:
             context = {}
@@ -50,7 +50,7 @@
             if use_new_cursor:
                 cr = pooler.get_db(use_new_cursor).cursor()
             wf_service = netsvc.LocalService("workflow")
-    
+
             procurement_obj = self.pool.get('procurement.order')
             if not ids:
                 ids = procurement_obj.search(cr, uid, [], order="date_planned")
@@ -112,13 +112,13 @@
             if uid:
                 request = self.pool.get('res.request')
                 summary = '''Here is the procurement scheduling report.
-    
+
         Start Time: %s
         End Time: %s
         Total Procurements processed: %d
         Procurements with exceptions: %d
         Skipped Procurements (scheduled date outside of scheduler range) %d
-    
+
         Exceptions:\n'''% (start_date, end_date, report_total, report_except, report_later)
                 summary += '\n'.join(report)
                 request.create(cr, uid,
@@ -141,7 +141,7 @@
     def create_automatic_op(self, cr, uid, context=None):
         """
         Create procurement of  virtual stock < 0
-        
+
         @param self: The object pointer
         @param cr: The current row, from the database cursor,
         @param uid: The current user ID for security checks
@@ -191,14 +191,14 @@
         '''
         Create procurement based on Orderpoint
         use_new_cursor: False or the dbname
-        
+
         @param self: The object pointer
         @param cr: The current row, from the database cursor,
         @param user_id: The current user ID for security checks
         @param context: A standard dictionary for contextual values
         @param param: False or the dbname
         @return:  Dictionary of values
-        """        
+        """
         '''
         if not context:
             context = {}
@@ -212,27 +212,53 @@
         report = []
         offset = 0
         ids = [1]
+        newdate = datetime.today()
         if automatic:
             self.create_automatic_op(cr, uid, context=context)
         while ids:
             ids = orderpoint_obj.search(cr, uid, [], offset=offset, limit=100)
-            for op in orderpoint_obj.browse(cr, uid, ids):
+            for op in orderpoint_obj.browse(cr, uid, ids, context=context):
                 if op.procurement_id.state != 'exception':
                     if op.procurement_id and op.procurement_id.purchase_id and op.procurement_id.purchase_id.state in ('draft', 'confirmed'):
                         continue
                 prods = location_obj._product_virtual_get(cr, uid,
                         op.location_id.id, [op.product_id.id],
                         {'uom': op.product_uom.id})[op.product_id.id]
+
                 if prods < op.product_min_qty:
                     qty = max(op.product_min_qty, op.product_max_qty)-prods
+
                     reste = qty % op.qty_multiple
                     if reste > 0:
                         qty += op.qty_multiple - reste
+
                     newdate = datetime.today() + relativedelta(
                             days = int(op.product_id.seller_delay))
                     if qty <= 0:
                         continue
                     if op.product_id.type not in ('consu'):
+                        # Check draft procurement related to this order point
+                        if op.procurement_draft_ids:
+                            procure_qty = {}
+                            #Compute list of draft procurement attached to Orderpoint
+                            for pro_data in op.procurement_draft_ids:
+                                procure_qty.update({pro_data.product_qty: pro_data.id })
+                            procure_list = procure_qty.keys()
+                            procure_list.sort()
+                            procure_list.reverse()
+
+                            to_generate = qty
+                            for proc in procure_list:
+                                if to_generate >= proc:
+                                    wf_service.trg_validate(uid, 'procurement.order', procure_qty[proc], 'button_confirm', cr)
+                                    wf_service.trg_validate(uid, 'procurement.order', procure_qty[proc], 'button_check', cr)
+                                    procurement_obj.write(cr, uid, [procure_qty[proc]],  {'origin': op.name}, context=context)
+                                    to_generate -= proc
+                                if not to_generate:
+                                    break
+                            qty = to_generate
+
+                    if qty:
                         proc_id = procurement_obj.create(cr, uid, {
                             'name': op.name,
                             'date_planned': newdate.strftime('%Y-%m-%d'),
@@ -248,7 +274,7 @@
                         wf_service.trg_validate(uid, 'procurement.order', proc_id,
                                 'button_check', cr)
                         orderpoint_obj.write(cr, uid, [op.id],
-                                {'procurement_id': proc_id})
+                                {'procurement_id': proc_id}, context=context)
             offset += len(ids)
             if use_new_cursor:
                 cr.commit()

=== modified file 'product/product.py'
--- product/product.py	2010-11-24 17:09:41 +0000
+++ product/product.py	2010-12-06 11:00:31 +0000
@@ -355,7 +355,8 @@
         return True
 
     _constraints = [
-        (_check_uos, 'Error: UOS must be in a different category than the UOM', ['uos_id']),
+         # As Per do changes given by lp bug : 543979
+#        (_check_uos, 'Error: UOS must be in a different category than the UOM', ['uos_id']),
         (_check_uom, 'Error: The default UOM and the purchase UOM must be in the same category.', ['uom_id']),
     ]
 

=== modified file 'stock/stock.py'
--- stock/stock.py	2010-11-24 17:21:57 +0000
+++ stock/stock.py	2010-12-06 11:00:31 +0000
@@ -1904,6 +1904,12 @@
         acc_variation = accounts.get('property_stock_variation', False)
         journal_id = accounts['stock_journal']
 
+        if acc_dest == acc_variation:
+            raise osv.except_osv(_('Error!'),  _('Can not create Journal Entry, Output Account on defined on this product and Variant account on category of this product is same.'))
+
+        if acc_src == acc_variation:
+            raise osv.except_osv(_('Error!'),  _('Can not create Journal Entry, Input Account on defined on this product and Variant account on category of this product is same.'))
+
         if not acc_src:
             raise osv.except_osv(_('Error!'),  _('There is no stock input account defined for this product or its category: "%s" (id: %d)') % \
                                     (move.product_id.name, move.product_id.id,))
@@ -2416,6 +2422,12 @@
         return self.pool.get('stock.move').create(cr, uid, move_vals)
 
     def action_done(self, cr, uid, ids, context=None):
+        """ Finished the inventory
+        @return: True
+        """
+
+        if context is None:
+            context = {}
         move_obj = self.pool.get('stock.move')
         for inv in self.browse(cr, uid, ids, context=context):
             move_obj.action_done(cr, uid, [x.id for x in inv.move_ids], context=context)
@@ -2423,7 +2435,7 @@
         return True
 
     def action_confirm(self, cr, uid, ids, context=None):
-        """ Finishes the inventory and writes its finished date
+        """ Confirm the inventory and writes its finished date
         @return: True
         """
         if context is None:
@@ -2434,7 +2446,7 @@
         product_context = dict(context, compute_child=False)
 
         location_obj = self.pool.get('stock.location')
-        for inv in self.browse(cr, uid, ids):
+        for inv in self.browse(cr, uid, ids, context=context):
             move_ids = []
             for line in inv.inventory_line_id:
                 pid = line.product_id.id

=== modified file 'stock/wizard/stock_splitinto.py'
--- stock/wizard/stock_splitinto.py	2010-11-24 11:27:43 +0000
+++ stock/wizard/stock_splitinto.py	2010-12-06 11:00:31 +0000
@@ -64,7 +64,7 @@
             if quantity_rest>0:
                 quantity_rest = move.product_qty - quantity
                 tracking_id = track_obj.create(cr, uid, {}, context=context)
-                if quantity==0.0:
+                if quantity == 0.0:
                     move_obj.write(cr, uid, [move.id], {'tracking_id': tracking_id}, context=context)
                 else:
                     default_val = {


Follow ups