@@ -45,7 +45,7 @@ def _compute_date_planned(self):
4545    def  _get_invoiced (self ):
4646        precision  =  self .env ['decimal.precision' ].precision_get ('Product Unit of Measure' )
4747        for  order  in  self :
48-             if  order .state  !=   'purchase' :
48+             if  order .state  not   in  ( 'purchase' ,  'done' ) :
4949                order .invoice_status  =  'no' 
5050                continue 
5151
@@ -122,16 +122,16 @@ def _compute_is_shipped(self):
122122        ('done' , 'Locked' ),
123123        ('cancel' , 'Cancelled' )
124124        ], string = 'Status' , readonly = True , select = True , copy = False , default = 'draft' , track_visibility = 'onchange' )
125-     order_line  =  fields .One2many ('purchase.order.line' , 'order_id' , string = 'Order Lines' , states = READONLY_STATES , copy = True )
125+     order_line  =  fields .One2many ('purchase.order.line' , 'order_id' , string = 'Order Lines' , states = { 'cancel' : [( 'readonly' ,  True )],  'done' : [( 'readonly' ,  True )]} , copy = True )
126126    notes  =  fields .Text ('Terms and Conditions' )
127127
128-     invoice_count  =  fields .Integer (compute = "_compute_invoice" , string = '# of Invoices ' , copy = False , default = 0 )
129-     invoice_ids  =  fields .Many2many ('account.invoice' , compute = "_compute_invoice" , string = 'Invoices ' , copy = False )
128+     invoice_count  =  fields .Integer (compute = "_compute_invoice" , string = '# of Bills ' , copy = False , default = 0 )
129+     invoice_ids  =  fields .Many2many ('account.invoice' , compute = "_compute_invoice" , string = 'Bills ' , copy = False )
130130    invoice_status  =  fields .Selection ([
131-         ('no' , 'Not purchased ' ),
132-         ('to invoice' , 'Waiting Invoices ' ),
133-         ('invoiced' , 'Invoice  Received' ),
134-         ], string = 'Invoice  Status' , compute = '_get_invoiced' , store = True , readonly = True , copy = False , default = 'no' )
131+         ('no' , 'Nothing to Bill ' ),
132+         ('to invoice' , 'Waiting Bills ' ),
133+         ('invoiced' , 'Bills  Received' ),
134+         ], string = 'Billing  Status' , compute = '_get_invoiced' , store = True , readonly = True , copy = False , default = 'no' )
135135
136136    picking_count  =  fields .Integer (compute = '_compute_picking' , string = 'Receptions' , default = 0 )
137137    picking_ids  =  fields .Many2many ('stock.picking' , compute = '_compute_picking' , string = 'Receptions' , copy = False )
@@ -145,7 +145,7 @@ def _compute_is_shipped(self):
145145
146146    fiscal_position_id  =  fields .Many2one ('account.fiscal.position' , string = 'Fiscal Position' , oldname = 'fiscal_position' )
147147    payment_term_id  =  fields .Many2one ('account.payment.term' , 'Payment Term' )
148-     incoterm_id  =  fields .Many2one ('stock.incoterms' , 'Incoterm' , help = "International Commercial Terms are a series of predefined commercial terms used in international transactions." )
148+     incoterm_id  =  fields .Many2one ('stock.incoterms' , 'Incoterm' , states = { 'done' : [( 'readonly' ,  True )]},  help = "International Commercial Terms are a series of predefined commercial terms used in international transactions." )
149149
150150    product_id  =  fields .Many2one ('product.product' , related = 'order_line.product_id' , string = 'Product' )
151151    create_uid  =  fields .Many2one ('res.users' , 'Responsible' )
@@ -304,9 +304,15 @@ def print_quotation(self):
304304        return  self .env ['report' ].get_action (self , 'purchase.report_purchasequotation' )
305305
306306    @api .multi  
307-     def  button_approve (self ):
307+     def  button_approve (self , force = False ):
308+         if  self .company_id .po_double_validation  ==  'two_step' \
309+           and  self .amount_total  >=  self .env .user .company_id .currency_id .compute (self .company_id .po_double_validation_amount , self .currency_id )\
310+           and  not  self .user_has_groups ('purchase.group_purchase_manager' ):
311+             raise  UserError (_ ('You need purchase manager access rights to validate an order above %.2f %s.' ) %  (self .company_id .po_double_validation_amount , self .company_id .currency_id .name ))
308312        self .write ({'state' : 'purchase' })
309313        self ._create_picking ()
314+         if  self .company_id .po_lock  ==  'lock' :
315+             self .write ({'state' : 'done' })
310316        return  {}
311317
312318    @api .multi  
@@ -319,14 +325,11 @@ def button_confirm(self):
319325        for  order  in  self :
320326            order ._add_supplier_to_product ()
321327            # Deal with double validation process 
322-             if  order .company_id .po_double_validation  ==  'one_step' \
323-                     or  (order .company_id .po_double_validation  ==  'two_step' \
324-                         and  order .amount_total  <  self .env .user .company_id .currency_id .compute (order .company_id .po_double_validation_amount , order .currency_id ))\
325-                     or  order .user_has_groups ('purchase.group_purchase_manager' ):
326-                 order .button_approve ()
328+             if  order .company_id .po_double_validation  ==  'one_step' :
329+                 order .button_approve (force = True )
327330            else :
328331                order .write ({'state' : 'to approve' })
329-         return  {} 
332+         return  True 
330333
331334    @api .multi  
332335    def  button_cancel (self ):
@@ -381,13 +384,18 @@ def _prepare_picking(self):
381384
382385    @api .multi  
383386    def  _create_picking (self ):
387+         StockPicking  =  self .env ['stock.picking' ]
384388        for  order  in  self :
385389            if  any ([ptype  in  ['product' , 'consu' ] for  ptype  in  order .order_line .mapped ('product_id.type' )]):
386-                 res  =  order ._prepare_picking ()
387-                 picking  =  self .env ['stock.picking' ].create (res )
388-                 moves  =  order .order_line .filtered (lambda  r : r .product_id .type  in  ['product' , 'consu' ])._create_stock_moves (picking )
389-                 moves .action_confirm ()
390-                 order .order_line .mapped ('move_ids' ).force_assign ()
390+                 pickings  =  order .picking_ids .filtered (lambda  x : x .state  not  in 'done' ,'cancel' ))
391+                 if  not  pickings :
392+                     res  =  order ._prepare_picking ()
393+                     picking  =  StockPicking .create (res )
394+                 else :
395+                     picking  =  pickings [0 ]
396+                 moves  =  order .order_line ._create_stock_moves (picking )
397+                 moves  =  moves .action_confirm ()
398+                 moves .force_assign ()
391399                picking .message_post_with_view ('mail.message_origin_link' ,
392400                    values = {'self' : picking , 'origin' : order },
393401                    subtype_id = self .env .ref ('mail.mt_note' ).id )
@@ -523,7 +531,22 @@ def _compute_qty_received(self):
523531                        total  +=  move .product_uom_qty 
524532            line .qty_received  =  total 
525533
534+     @api .model  
535+     def  create (self , values ):
536+         line  =  super (PurchaseOrderLine , self ).create (values )
537+         if  line .order_id .state  ==  'purchase' :
538+             line .order_id ._create_picking ()
539+         return  line 
540+ 
541+     @api .multi  
542+     def  write (self , values ):
543+         result  =  super (PurchaseOrderLine , self ).write (values )
544+         orders  =  self .filtered (lambda  x : x .order_id .state  ==  'purchase' ).mapped ('order_id' )
545+         orders ._create_picking ()
546+         return  result 
547+ 
526548    name  =  fields .Text (string = 'Description' , required = True )
549+     sequence  =  fields .Integer (string = 'Sequence' , default = 10 )
527550    product_qty  =  fields .Float (string = 'Quantity' , digits = dp .get_precision ('Product Unit of Measure' ), required = True )
528551    date_planned  =  fields .Datetime (string = 'Scheduled Date' , required = True , select = True )
529552    taxes_id  =  fields .Many2many ('account.tax' , string = 'Taxes' , domain = ['|' , ('active' , '=' , False ), ('active' , '=' , True )])
@@ -542,7 +565,7 @@ def _compute_qty_received(self):
542565    company_id  =  fields .Many2one ('res.company' , related = 'order_id.company_id' , string = 'Company' , store = True , readonly = True )
543566    state  =  fields .Selection (related = 'order_id.state' , store = True )
544567
545-     invoice_lines  =  fields .One2many ('account.invoice.line' , 'purchase_line_id' , string = "Invoice  Lines" , readonly = True , copy = False )
568+     invoice_lines  =  fields .One2many ('account.invoice.line' , 'purchase_line_id' , string = "Bill  Lines" , readonly = True , copy = False )
546569
547570    # Replace by invoiced Qty 
548571    qty_invoiced  =  fields .Float (compute = '_compute_qty_invoiced' , string = "Billed Qty" , store = True )
@@ -572,8 +595,12 @@ def _create_stock_moves(self, picking):
572595        moves  =  self .env ['stock.move' ]
573596        done  =  self .env ['stock.move' ].browse ()
574597        for  line  in  self :
598+             if  line .product_id .type  not  in 'product' , 'consu' ]:
599+                 continue 
600+             qty  =  0.0 
575601            price_unit  =  line ._get_stock_move_price_unit ()
576- 
602+             for  move  in  line .move_ids .filtered (lambda  x : x .state  !=  'cancel' ):
603+                 qty  +=  move .product_qty 
577604            template  =  {
578605                'name' : line .name  or  '' ,
579606                'product_id' : line .product_id .id ,
@@ -596,9 +623,8 @@ def _create_stock_moves(self, picking):
596623                'route_ids' : line .order_id .picking_type_id .warehouse_id  and  [(6 , 0 , [x .id  for  x  in  line .order_id .picking_type_id .warehouse_id .route_ids ])] or  [],
597624                'warehouse_id' :line .order_id .picking_type_id .warehouse_id .id ,
598625            }
599- 
600626            # Fullfill all related procurements with this po line 
601-             diff_quantity  =  line .product_qty 
627+             diff_quantity  =  line .product_qty   -   qty 
602628            for  procurement  in  line .procurement_ids :
603629                procurement_qty  =  procurement .product_uom ._compute_quantity (procurement .product_qty , line .product_uom )
604630                tmp  =  template .copy ()
@@ -618,7 +644,7 @@ def _create_stock_moves(self, picking):
618644    @api .multi  
619645    def  unlink (self ):
620646        for  line  in  self :
621-             if  line .order_id .state  in  ['approved ' , 'done' ]:
647+             if  line .order_id .state  in  ['purchase ' , 'done' ]:
622648                raise  UserError (_ ('Cannot delete a purchase order line which is in state \' %s\' .' ) % (line .state ,))
623649            for  proc  in  line .procurement_ids :
624650                proc .message_post (body = _ ('Purchase order line deleted.' ))
@@ -722,6 +748,15 @@ def _onchange_quantity(self):
722748
723749        self .price_unit  =  price_unit 
724750
751+     @api .onchange ('product_qty' ) 
752+     def  _onchange_product_qty (self ):
753+         if  (self .state  ==  'purchase'  or  self .state  ==  'to approve' ) and  self .product_id .type  in  ['product' , 'consu' ] and  self .product_qty  <  self ._origin .product_qty :
754+             warning_mess  =  {
755+                 'title' : _ ('Ordered quantity decreased!' ),
756+                 'message'  : _ ('You are decreasing the ordered quantity!\n You must update the quantities on the reception and/or bills.' ),
757+             }
758+             return  {'warning' : warning_mess }
759+ 
725760    def  _suggest_quantity (self ):
726761        ''' 
727762        Suggest a minimal quantity based on the seller 
@@ -991,8 +1026,8 @@ def _purchase_count(self):
9911026        ('purchase' , 'On ordered quantities' ),
9921027        ('receive' , 'On received quantities' ),
9931028        ], string = "Control Purchase Bills" ,
994-         help = "On ordered quantities: Invoice this product  based on ordered quantities.\n " 
995-         "On received quantities: Invoice this product  based on received quantity." , default = "receive" )
1029+         help = "On ordered quantities: control bills  based on ordered quantities.\n " 
1030+         "On received quantities: control bills  based on received quantity." , default = "receive" )
9961031    route_ids  =  fields .Many2many (default = lambda  self : self ._get_buy_route ())
9971032    purchase_line_warn  =  fields .Selection (WARNING_MESSAGE , 'Purchase Order Line' , help = WARNING_HELP , required = True , default = "no-message" )
9981033    purchase_line_warn_msg  =  fields .Text ('Message for Purchase Order Line' )
0 commit comments