~unifield-team/unifield-wm/us-826

« back to all changes in this revision

Viewing changes to msf_outgoing/msf_outgoing.py

  • Committer: Olivier DOSSMANN
  • Date: 2012-09-10 12:47:41 UTC
  • mfrom: (1122 unifield-wm)
  • mto: This revision was merged to the branch mainline in revision 1133.
  • Revision ID: olivier@tempo-laptop-20120910124741-jwl0z433kaszn1ob
UF-1285 [MERGE] Last trunk lp:unifield-wm

Show diffs side-by-side

added added

removed removed

Lines of Context:
271
271
                'backshipment_id': fields.function(_vals_get, method=True, type='many2one', relation='shipment', string='Draft Shipment', multi='get_vals',),
272
272
                # added by Quentin https://bazaar.launchpad.net/~unifield-team/unifield-wm/trunk/revision/426.20.14
273
273
                'parent_id': fields.many2one('shipment', string='Parent shipment'),
 
274
                'invoice_id': fields.many2one('account.invoice', string='Related invoice'),
274
275
                }
275
276
    _defaults = {'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),}
276
277
    
873
874
            
874
875
            # all draft packing are validated (done state) - the state of shipment is automatically updated -> function
875
876
        return True
 
877
    
 
878
    def shipment_create_invoice(self, cr, uid, ids, context=None):
 
879
        '''
 
880
        Create invoices for validated shipment
 
881
        '''
 
882
        invoice_obj = self.pool.get('account.invoice')
 
883
        line_obj = self.pool.get('account.invoice.line')
 
884
        partner_obj = self.pool.get('res.partner')
 
885
        distrib_obj = self.pool.get('analytic.distribution')
 
886
        sale_line_obj = self.pool.get('sale.order.line')
 
887
        sale_obj = self.pool.get('sale.order')
 
888
        company = self.pool.get('res.users').browse(cr, uid, uid, context).company_id
 
889
        
 
890
        if not context:
 
891
            context = {}
 
892
            
 
893
        if isinstance(ids, (int, long)):
 
894
            ids = [ids]
 
895
            
 
896
        for shipment in self.browse(cr, uid, ids, context=context):
 
897
            make_invoice = False
 
898
            for pack in shipment.pack_family_memory_ids:
 
899
                for move in pack.move_lines:
 
900
                    if move.state != 'cancel' and (not move.sale_line_id or move.sale_line_id.order_id.order_policy == 'picking'):
 
901
                        make_invoice = True
 
902
                    
 
903
            if not make_invoice:
 
904
                continue
 
905
                    
 
906
            payment_term_id = False
 
907
            partner =  shipment.partner_id2
 
908
            if not partner:
 
909
                raise osv.except_osv(_('Error, no partner !'),
 
910
                    _('Please put a partner on the shipment if you want to generate invoice.'))
 
911
            
 
912
            inv_type = 'out_invoice'
 
913
            
 
914
            if inv_type in ('out_invoice', 'out_refund'):
 
915
                account_id = partner.property_account_receivable.id
 
916
                payment_term_id = partner.property_payment_term and partner.property_payment_term.id or False
 
917
            else:
 
918
                account_id = partner.property_account_payable.id
 
919
            
 
920
            addresses = partner_obj.address_get(cr, uid, [partner.id], ['contact', 'invoice'])
 
921
            
 
922
            invoice_vals = {
 
923
                    'name': shipment.name,
 
924
                    'origin': shipment.name or '',
 
925
                    'type': inv_type,
 
926
                    'account_id': account_id,
 
927
                    'partner_id': partner.id,
 
928
                    'address_invoice_id': addresses['invoice'],
 
929
                    'address_contact_id': addresses['contact'],
 
930
                    'payment_term': payment_term_id,
 
931
                    'fiscal_position': partner.property_account_position.id,
 
932
                    'date_invoice': context.get('date_inv',False),
 
933
                    'user_id':uid
 
934
                }
 
935
            cur_id = shipment.pack_family_memory_ids[0].currency_id.id
 
936
            if cur_id:
 
937
                invoice_vals['currency_id'] = cur_id
 
938
            # Journal type
 
939
            journal_type = 'sale'
 
940
            # Disturb journal for invoice only on intermission partner type
 
941
            if shipment.partner_id2.partner_type == 'intermission':
 
942
                if not company.intermission_default_counterpart or not company.intermission_default_counterpart.id:
 
943
                    raise osv.except_osv(_('Error'), _('Please configure a default intermission account in Company configuration.'))
 
944
                invoice_vals['is_intermission'] = True
 
945
                invoice_vals['account_id'] = company.intermission_default_counterpart.id
 
946
                journal_type = 'intermission'
 
947
            journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', journal_type)])
 
948
            if not journal_ids:
 
949
                raise osv.except_osv(_('Warning'), _('No %s journal found!' % (journal_type,)))
 
950
            invoice_vals['journal_id'] = journal_ids[0]
 
951
                
 
952
            invoice_id = invoice_obj.create(cr, uid, invoice_vals,
 
953
                        context=context)
 
954
            
 
955
            # Change currency for the intermission invoice
 
956
            if shipment.partner_id2.partner_type == 'intermission':
 
957
                company_currency = company.currency_id and company.currency_id.id or False
 
958
                if not company_currency:
 
959
                    raise osv.except_osv(_('Warning'), _('No company currency found!'))
 
960
                wiz_account_change = self.pool.get('account.change.currency').create(cr, uid, {'currency_id': company_currency})
 
961
                self.pool.get('account.change.currency').change_currency(cr, uid, [wiz_account_change], context={'active_id': invoice_id})
 
962
            
 
963
            # Link the invoice to the shipment
 
964
            self.write(cr, uid, [shipment.id], {'invoice_id': invoice_id}, context=context)
 
965
            
 
966
            # For each stock moves, create an invoice line
 
967
            for pack in shipment.pack_family_memory_ids:
 
968
                for move in pack.move_lines:
 
969
                    if move.state == 'cancel':
 
970
                        continue
 
971
                    
 
972
                    if move.sale_line_id and move.sale_line_id.order_id.order_policy != 'picking':
 
973
                        continue
 
974
                    
 
975
                    origin = move.picking_id.name or ''
 
976
                    if move.picking_id.origin:
 
977
                        origin += ':' + move.picking_id.origin
 
978
                        
 
979
                    if inv_type in ('out_invoice', 'out_refund'):
 
980
                        account_id = move.product_id.product_tmpl_id.\
 
981
                                property_account_income.id
 
982
                        if not account_id:
 
983
                            account_id = move.product_id.categ_id.\
 
984
                                    property_account_income_categ.id
 
985
                    else:
 
986
                        account_id = move.product_id.product_tmpl_id.\
 
987
                                property_account_expense.id
 
988
                        if not account_id:
 
989
                            account_id = move.product_id.categ_id.\
 
990
                                    property_account_expense_categ.id
 
991
                                    
 
992
                    # Compute unit price from FO line if the move is linked to
 
993
                    price_unit = move.product_id.list_price
 
994
                    if move.sale_line_id and move.sale_line_id.product_id.id == move.product_id.id:
 
995
                        uom_id = move.product_id.uom_id.id
 
996
                        uos_id = move.product_id.uos_id and move.product_id.uos_id.id or False
 
997
                        price = move.sale_line_id.price_unit
 
998
                        coeff = move.product_id.uos_coeff
 
999
                        if uom_id != uos_id and coeff != 0:
 
1000
                            price_unit = price / coeff
 
1001
                        else:
 
1002
                            price_unit = move.sale_line_id.price_unit
 
1003
                            
 
1004
                    # Get discount from FO line
 
1005
                    discount = 0.00
 
1006
                    if move.sale_line_id and move.sale_line_id.product_id.id == move.product_id.id:
 
1007
                        discount = move.sale_line_id.discount
 
1008
                        
 
1009
                    # Get taxes from FO line
 
1010
                    taxes = move.product_id.taxes_id
 
1011
                    if move.sale_line_id and move.sale_line_id.product_id.id == move.product_id.id:
 
1012
                        taxes = [x.id for x in move.sale_line_id.tax_id]
 
1013
                        
 
1014
                    if shipment.partner_id2:
 
1015
                        tax_ids = self.pool.get('account.fiscal.position').map_tax(cr, uid, shipment.partner_id2.property_account_position, taxes)
 
1016
                    else:
 
1017
                        tax_ids = map(lambda x: x.id, taxes)
 
1018
                        
 
1019
                    distrib_id = False
 
1020
                    if move.sale_line_id:
 
1021
                        sol_ana_dist_id = move.sale_line_id.analytic_distribution_id or move.sale_line_id.order_id.analytic_distribution_id
 
1022
                        if sol_ana_dist_id:
 
1023
                            distrib_id = distrib_obj.copy(cr, uid, sol_ana_dist_id.id, context=context)
 
1024
                        
 
1025
                    #set UoS if it's a sale and the picking doesn't have one
 
1026
                    uos_id = move.product_uos and move.product_uos.id or False
 
1027
                    if not uos_id and inv_type in ('out_invoice', 'out_refund'):
 
1028
                        uos_id = move.product_uom.id
 
1029
                    account_id = self.pool.get('account.fiscal.position').map_account(cr, uid, partner.property_account_position, account_id)
 
1030
                        
 
1031
                    line_id = line_obj.create(cr, uid, {'name': move.name,
 
1032
                                                        'origin': origin,
 
1033
                                                        'invoice_id': invoice_id,
 
1034
                                                        'uos_id': uos_id,
 
1035
                                                        'product_id': move.product_id.id,
 
1036
                                                        'account_id': account_id,
 
1037
                                                        'price_unit': price_unit,
 
1038
                                                        'discount': discount,
 
1039
                                                        'quantity': move.product_qty or move.product_uos_qty,
 
1040
                                                        'invoice_line_tax_id': [(6, 0, tax_ids)],
 
1041
                                                        'analytic_distribution_id': distrib_id,
 
1042
                                                       }, context=context)
 
1043
 
 
1044
                    self.pool.get('stock.move').write(cr, uid, [shipment.id], {'invoice_id': invoice_id}, context=context)
 
1045
                    if move.sale_line_id:
 
1046
                        sale_obj.write(cr, uid, [move.sale_line_id.order_id.id], {'invoice_ids': [(4, invoice_id)],})
 
1047
                        sale_line_obj.write(cr, uid, [move.sale_line_id.id], {'invoiced': True,
 
1048
                                                                              'invoice_lines': [(4, line_id)],})
 
1049
            
 
1050
        return True
876
1051
        
877
1052
    def validate(self, cr, uid, ids, context=None):
878
1053
        '''
899
1074
                # trigger standard workflow
900
1075
                pick_obj.action_move(cr, uid, [packing.id])
901
1076
                wf_service.trg_validate(uid, 'stock.picking', packing.id, 'button_done', cr)
 
1077
            
 
1078
            # Create automatically the invoice
 
1079
            self.shipment_create_invoice(cr, uid, shipment.id, context=context)
902
1080
                
903
1081
            # log validate action
904
1082
            self.log(cr, uid, shipment.id, _('The Shipment %s has been validated.')%(shipment.name,))
1142
1320
        '''
1143
1321
        unlink test for draft
1144
1322
        '''
1145
 
        datas = self.read(cr, uid, ids, ['state'], context=context)
 
1323
        datas = self.read(cr, uid, ids, ['state','type','subtype'], context=context)
1146
1324
        if [data for data in datas if data['state'] != 'draft']:
1147
1325
            raise osv.except_osv(_('Warning !'), _('Only draft picking tickets can be deleted.'))
1148
 
        data = self.has_picking_ticket_in_progress(cr, uid, ids, context=context)
1149
 
        if [x for x in data.values() if x]:
1150
 
            raise osv.except_osv(_('Warning !'), _('Some Picking Tickets are in progress. Return products to stock from ppl and shipment and try again.'))
 
1326
        ids_picking_draft = [data['id'] for data in datas if data['subtype'] == 'picking' and data['type'] == 'out' and data['state'] == 'draft']
 
1327
        if ids_picking_draft:
 
1328
            data = self.has_picking_ticket_in_progress(cr, uid, ids, context=context)
 
1329
            if [x for x in data.values() if x]:
 
1330
                raise osv.except_osv(_('Warning !'), _('Some Picking Tickets are in progress. Return products to stock from ppl and shipment and try again.'))
1151
1331
        
1152
1332
        return super(stock_picking, self).unlink(cr, uid, ids, context=context)
1153
1333
   
1266
1446
            # by default, nothing is in progress
1267
1447
            res[obj.id] = False
1268
1448
            # treat only draft picking
1269
 
            assert obj.subtype == 'picking' and obj.state == 'draft', 'the validate function should only be called on draft picking ticket objects'
 
1449
            assert obj.subtype in 'picking' and obj.state == 'draft', 'the validate function should only be called on draft picking ticket objects'
1270
1450
            for picking in obj.backorder_ids:
1271
1451
                # take care, is_completed returns a dictionary
1272
1452
                if not picking.is_completed()[picking.id]:
1763
1943
        special behavior :
1764
1944
         - creation of corresponding shipment
1765
1945
        '''
 
1946
        # For picking ticket from scratch, invoice it !
 
1947
        if not vals.get('sale_id') and not vals.get('purchase_id') and not vals.get('invoice_state') and 'type' in vals and vals['type'] == 'out':
 
1948
            vals['invoice_state'] = '2binvoiced'
1766
1949
        # objects
1767
1950
        date_tools = self.pool.get('date.tools')
1768
1951
        fields_tools = self.pool.get('fields.tools')
1980
2163
        date_tools = self.pool.get('date.tools')
1981
2164
        fields_tools = self.pool.get('fields.tools')
1982
2165
        db_date_format = date_tools.get_db_date_format(cr, uid, context=context)
1983
 
        
1984
2166
        for obj in self.browse(cr, uid, ids, context=context):
1985
2167
            # the convert function should only be called on draft picking ticket
1986
2168
            assert obj.subtype == 'picking' and obj.state == 'draft', 'the convert function should only be called on draft picking ticket objects'
2002
2184
                # using draft_force_assign, the moves are not treated because not in draft
2003
2185
                # and the corresponding chain location on location_dest_id was not computed
2004
2186
                # we therefore set them back in draft state before treatment
2005
 
                vals = {'state': 'draft'}
 
2187
                if move.product_qty == 0.0:
 
2188
                    vals = {'state': 'done'}
 
2189
                else:
 
2190
                    vals = {'state': 'draft'}
2006
2191
                # If the move comes from a DPO, don't change the destination location
2007
2192
                if not move.dpo_id:
2008
2193
                    vals.update({'location_dest_id': obj.warehouse_id.lot_output_id.id})
2811
2996
            loc_packing_id = self.pool.get('stock.warehouse').browse(cr, uid, warehouse_id, context=context).lot_packing_id.id
2812
2997
            res.update({'location_dest_id': loc_packing_id})
2813
2998
        elif 'subtype' in context and context.get('subtype', False) == 'standard':
2814
 
            loc_packing_id = self.pool.get('stock.warehouse').browse(cr, uid, warehouse_id, context=context).lot_output_id.id
2815
 
            res.update({'location_dest_id': loc_packing_id})
 
2999
            loc_output_id = self.pool.get('stock.warehouse').browse(cr, uid, warehouse_id, context=context).lot_output_id.id
 
3000
            res.update({'location_dest_id': loc_output_id})
2816
3001
        
2817
3002
        return res
2818
3003
    
2843
3028
                # Fields used for domain
2844
3029
                'location_virtual_id': fields.many2one('stock.location', string='Virtual location'),
2845
3030
                'location_output_id': fields.many2one('stock.location', string='Output location'),
 
3031
                'invoice_line_id': fields.many2one('account.invoice.line', string='Invoice line'),
2846
3032
                }
2847
3033
 
2848
3034
stock_move()