1
# -*- coding: utf-8 -*-
2
##############################################################################
4
# OpenERP, Open Source Management Solution
5
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU Affero General Public License as
9
# published by the Free Software Foundation, either version 3 of the
10
# License, or (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Affero General Public License for more details.
17
# You should have received a copy of the GNU Affero General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
##############################################################################
22
from osv import fields, osv
24
import decimal_precision as dp
27
from base64 import b64decode
29
import decimal_precision as dp
34
h = HTMLParser.HTMLParser()
36
import shippingservice
37
from miscellaneous import Address
39
from .xml_dict import dict_to_xml, xml_to_dict
41
from fedex.services.rate_service import FedexRateServiceRequest
42
from fedex.services.ship_service import FedexProcessShipmentRequest
43
from fedex.config import FedexConfig
45
from suds.client import Client
47
from tools.translate import _
49
logger = netsvc.Logger()
54
def get_partner_details(firm_name, partneradd_lnk, context=None):
57
result['name'] = partneradd_lnk.name
58
result['firm'] = firm_name or partneradd_lnk.name
59
result['add1'] = partneradd_lnk.street or ''
60
result['add2'] = partneradd_lnk.street2 or ''
61
result['city'] = partneradd_lnk.city or ''
62
result['state_code'] = partneradd_lnk.state_id.code or ''
65
print "zip: ",partneradd_lnk.zip
66
if len(partneradd_lnk.zip.strip()) == 5:
67
result['zip5'] = partneradd_lnk.zip
69
elif len(partneradd_lnk.zip.strip()) == 4:
70
result['zip4'] = partneradd_lnk.zip
72
elif str(partneradd_lnk.zip).find('-'):
73
zips = str(partneradd_lnk.zip).split('-')
74
if len(zips[0]) == 5 and len(zips[1]) == 4:
75
result['zip5'] = zips[0]
76
result['zip4'] = zips[1]
77
elif len(zips[0]) == 4 and len(zips[1]) == 5:
78
result['zip4'] = zips[0]
79
result['zip5'] = zips[1]
81
result['zip4'] = result['zip5'] = ''
83
result['email'] = partneradd_lnk.email or ''
84
result['country_code'] = partneradd_lnk.country_id.code or ''
85
result['phone'] = partneradd_lnk.phone or ''
88
class shipping_response(osv.osv):
89
_name = 'shipping.response'
91
def generate_tracking_no(self, cr, uid, ids, context={}, error=True):
92
print "generate_tracking_no ids: ",ids
93
# import subprocess as sp
94
# url = 'http://www.python.org'
95
# child = sp.Popen("firefox %s" % url, shell=True)
97
def get_usps_servicename(service):
98
if 'First-Class' in service:
100
elif 'Express Mail' in service:
101
return 'Express Mail'
102
elif 'Priority Mail' in service:
103
return 'Priority Mail'
104
elif 'Library Mail' in service:
105
return 'Library Mail'
106
elif 'Parcel Post' in service:
108
elif 'Media Mail' in service:
111
logger.notifyChannel('init', netsvc.LOG_WARNING, 'generate_tracking_no called')
112
saleorder_obj = self.pool.get('sale.order')
113
stockmove_obj = self.pool.get('stock.move')
114
stockpicking_obj = self.pool.get('stock.picking')
115
shippingresp_lnk = self.browse(cr,uid,ids[0])
117
move_ids = stockmove_obj.search(cr,uid,[('picking_id','=',shippingresp_lnk.picking_id.id)])
119
move_lines = stockmove_obj.browse(cr,uid,move_ids)
120
for move_line in move_lines:
121
real_stock = move_line.product_id.qty_available
122
print "real_stock: ",real_stock
123
res = self.pool.get('stock.location')._product_reserve(cr, uid, [move_line.location_id.id], move_line.product_id.id, move_line.product_qty, {'uom': move_line.product_uom.id}, lock=True)
125
# saleorder_obj.write(cr,uid,shippingresp_lnk.picking_id.sale_id.id,{'state':'shipping_except'})
127
# raise osv.except_osv(_('Error'), _('Not enough stock in inventory'))
129
partneradd_lnk = shippingresp_lnk.picking_id.sale_id.shop_id.cust_address
130
if not partneradd_lnk:
131
raise osv.except_osv(_('Error'), _('Shop Address not defined!'),)
132
result_from = get_partner_details(shippingresp_lnk.picking_id.sale_id.shop_id.name,partneradd_lnk,context)
134
partner_lnk = shippingresp_lnk.picking_id.partner_id
135
address = self.pool.get('res.partner').address_get(cr,uid,[partner_lnk.id])
136
partneradd_lnk = self.pool.get('res.partner.address').browse(cr,uid,address['default'])
137
result_to = get_partner_details(partner_lnk.name,partneradd_lnk,context)
139
cust_address = shippingresp_lnk.picking_id.sale_id.shop_id.cust_address
142
raise osv.except_osv(_('Error'), _('Shop Address not defined!'),)
145
shipper = Address(cust_address.name or cust_address.partner_id.name, cust_address.street, cust_address.city, cust_address.state_id.code or '', cust_address.zip, cust_address.country_id.code, cust_address.street2 or '', cust_address.phone or '', cust_address.email, cust_address.partner_id.name)
148
cust_address = shippingresp_lnk.picking_id.address_id
149
receipient = Address(cust_address.name or cust_address.partner_id.name, cust_address.street, cust_address.city, cust_address.state_id.code or '', cust_address.zip, cust_address.country_id.code, cust_address.street2 or '', cust_address.phone or '', cust_address.email, cust_address.partner_id.name)
151
weight = shippingresp_lnk.weight
152
rate = shippingresp_lnk.rate
155
if shippingresp_lnk.type.lower() == 'usps' and ('usps_active' in context.keys() and context.get('usps_active')):
157
shippingusps_obj = self.pool.get('shipping.usps')
158
shippingusps_id = shippingusps_obj.search(cr,uid,[('active','=',True)])
159
if not shippingusps_id:
161
raise osv.except_osv(_('Error'), _('Default USPS settings not defined'))
164
shippingusps_id = shippingusps_id[0]
165
shippingusps_ptr = shippingusps_obj.browse(cr,uid,shippingusps_id)
166
user_id = shippingusps_ptr.user_id
169
url = "https://testing.shippingapis.com/ShippingAPITest.dll?API=DeliveryConfirmationV3&" if shippingusps_ptr.test else "https://secure.shippingapis.com/ShippingAPI.dll?API=DeliveryConfirmationV3&"
171
weight = math.modf(weight)
172
pounds = int(weight[1])
173
ounces = round(weight[0],4) * 16
174
final_weight = pounds*16 + ounces
175
print "usps weight pounds: ",pounds
176
print "usps weight ounces: ",ounces
178
service_type = get_usps_servicename(shippingresp_lnk.name)
179
print "service_type: ",service_type
182
values['XML'] = '<DeliveryConfirmationV3.0Request USERID="' + user_id + '"><Option>1</Option><ImageParameters></ImageParameters><FromName>' + result_from['name'] + '</FromName><FromFirm>' + result_from['firm'] + '</FromFirm><FromAddress1>' + result_from['add2'] + '</FromAddress1><FromAddress2>' + result_from['add1'] + '</FromAddress2><FromCity>' + result_from['city'] + '</FromCity><FromState>' + result_from['state_code'] + '</FromState><FromZip5>' + result_from['zip5'] + '</FromZip5><FromZip4>' + result_from['zip4'] + '</FromZip4><ToName>' + result_to['name'] + '</ToName><ToFirm>' + result_to['firm'] + '</ToFirm><ToAddress1>' + result_to['add2'] + '</ToAddress1><ToAddress2>' + result_to['add1'] + '</ToAddress2><ToCity>' + result_to['city'] + '</ToCity><ToState>' + result_to['state_code'] + '</ToState><ToZip5>' + result_to['zip5'] + '</ToZip5><ToZip4>' + result_to['zip4'] + '</ToZip4><WeightInOunces>' + str(final_weight) + '</WeightInOunces><ServiceType>' + service_type + '</ServiceType><SeparateReceiptPage>TRUE</SeparateReceiptPage><POZipCode></POZipCode><ImageType>TIF</ImageType><LabelDate></LabelDate><CustomerRefNo></CustomerRefNo><AddressServiceRequested></AddressServiceRequested><SenderName></SenderName><SenderEMail></SenderEMail><RecipientName></RecipientName><RecipientEMail></RecipientEMail></DeliveryConfirmationV3.0Request>'
183
url = url + urllib.urlencode(values)
184
print "usps url: ",url
185
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'shipping url is %s'%(url,))
186
#req = urllib2.Request(url)
187
#opener = urllib2.build_opener()
188
#f = opener.open(req)
192
f = urllib2.urlopen(url)
194
print "usps response: ",response
198
raise osv.except_osv(_('Error'), _('%s' % (e)))
200
#print "after exception"
202
if response.find('<Error>') != -1:
203
sIndex = response.find('<Description>')
204
eIndex = response.find('</Description>')
206
raise osv.except_osv(_('Error'), _('%s') % (response[int(sIndex)+13:int(eIndex)],))
209
i = sIndex = eIndex = 0
210
sIndex = response.find('<DeliveryConfirmationNumber>',i)
211
eIndex = response.find('</DeliveryConfirmationNumber>',i)
212
tracking_no = response[int(sIndex) + 36:int(eIndex)]
214
sIndex = response.find('<DeliveryConfirmationLabel>',i)
215
eIndex = response.find('</DeliveryConfirmationLabel>',i)
216
s_label = response[int(sIndex) + 27:int(eIndex)]
218
s_label = s_label.replace('\n','')
219
s_label = s_label.replace('\r','')
220
#shipping_label = b64decode(s_label).encode('UTF-8')
221
#logger.notifyChannel('init', netsvc.LOG_WARNING, '!!!!!!shipping_label is %s'%(s_label,))
223
"""filename = "Label1.tif"
224
FILE = open(filename,"w")
225
FILE.write(b64decode(s_label))"""
227
attachment_pool = self.pool.get('ir.attachment')
229
'name': 'PackingList.tif',
230
'datas': binascii.b2a_base64(str(b64decode(s_label))),
231
'description': 'Packing List',
232
'res_name': shippingresp_lnk.picking_id.name,
233
'res_model': 'stock.picking',
234
'res_id': shippingresp_lnk.picking_id.id,
236
attach_id = attachment_pool.search(cr,uid,[('res_id','=',shippingresp_lnk.picking_id.id),('res_name','=',shippingresp_lnk.picking_id.name)])
238
attach_id = attachment_pool.create(cr, uid, data_attach)
239
print "attach_id: ",attach_id
241
attach_result = attachment_pool.write(cr, uid, attach_id, data_attach)
242
attach_id = attach_id[0]
243
print "attach_result: ",attach_result
244
context['attach_id'] = attach_id
247
stockpicking_obj.write(cr,uid,shippingresp_lnk.picking_id.id,{'carrier_tracking_ref':tracking_no, 'shipping_label':binascii.b2a_base64(str(b64decode(s_label))), 'shipping_rate': rate})
248
context['track_success'] = True
250
elif shippingresp_lnk.type.lower() == 'fedex':
251
print "Inside Fedex Shipping"
252
#raise osv.except_osv(_('Error'), _('FedEx shipment request under construction'))
254
shippingfedex_obj = self.pool.get('shipping.fedex')
255
shippingfedex_id = shippingfedex_obj.search(cr,uid,[('active','=',True)])
256
if not shippingfedex_id:
257
raise osv.except_osv(_('Error'), _('Default Fedex settings not defined'))
259
shippingfedex_id = shippingfedex_id[0]
261
shippingfedex_ptr = shippingfedex_obj.browse(cr,uid,shippingfedex_id)
262
account_no = shippingfedex_ptr.account_no
263
key = shippingfedex_ptr.key
264
password = shippingfedex_ptr.password
265
meter_no = shippingfedex_ptr.meter_no
266
is_test = shippingfedex_ptr.test
267
CONFIG_OBJ = FedexConfig(key=key, password=password, account_number=account_no, meter_number=meter_no, use_test_server=is_test)
269
# This is the object that will be handling our tracking request.
270
# We're using the FedexConfig object from example_config.py in this dir.
271
shipment = FedexProcessShipmentRequest(CONFIG_OBJ)
273
# This is very generalized, top-level information.
274
# REGULAR_PICKUP, REQUEST_COURIER, DROP_BOX, BUSINESS_SERVICE_CENTER or STATION
275
# print "DROPOFF TYPE: ",shippingresp_lnk.dropoff_type_fedex
276
fedex_servicedetails = stockpicking_obj.browse(cr,uid,shippingresp_lnk.picking_id.id)
278
shipment.RequestedShipment.DropoffType = fedex_servicedetails.dropoff_type_fedex #'REGULAR_PICKUP'
279
print "DROP OFF TYPE: ",fedex_servicedetails.dropoff_type_fedex
280
# See page 355 in WS_ShipService.pdf for a full list. Here are the common ones:
281
# STANDARD_OVERNIGHT, PRIORITY_OVERNIGHT, FEDEX_GROUND, FEDEX_EXPRESS_SAVER
282
shipment.RequestedShipment.ServiceType = fedex_servicedetails.service_type_fedex #'PRIORITY_OVERNIGHT'
284
# What kind of package this will be shipped in.
285
# FEDEX_BOX, FEDEX_PAK, FEDEX_TUBE, YOUR_PACKAGING
286
shipment.RequestedShipment.PackagingType = fedex_servicedetails.packaging_type_fedex #'FEDEX_PAK'
288
# No idea what this is.
289
# INDIVIDUAL_PACKAGES, PACKAGE_GROUPS, PACKAGE_SUMMARY
290
shipment.RequestedShipment.PackageDetail = fedex_servicedetails.package_detail_fedex #'INDIVIDUAL_PACKAGES'
292
# Shipper contact info.
293
shipment.RequestedShipment.Shipper.Contact.PersonName = shipper.name #'Sender Name'
294
shipment.RequestedShipment.Shipper.Contact.CompanyName = shipper.company_name #'Some Company'
295
shipment.RequestedShipment.Shipper.Contact.PhoneNumber = shipper.phone #'9012638716'
298
shipment.RequestedShipment.Shipper.Address.StreetLines = shipper.address1 #['Address Line 1']
299
shipment.RequestedShipment.Shipper.Address.City = shipper.city #'Herndon'
300
shipment.RequestedShipment.Shipper.Address.StateOrProvinceCode = shipper.state_code #'VA'
301
shipment.RequestedShipment.Shipper.Address.PostalCode = shipper.zip #'20171'
302
shipment.RequestedShipment.Shipper.Address.CountryCode = shipper.country_code #'US'
303
shipment.RequestedShipment.Shipper.Address.Residential = False
305
# Recipient contact info.
306
shipment.RequestedShipment.Recipient.Contact.PersonName = receipient.name #'Recipient Name'
307
shipment.RequestedShipment.Recipient.Contact.CompanyName = receipient.company_name #'Recipient Company'
308
shipment.RequestedShipment.Recipient.Contact.PhoneNumber = receipient.phone #'9012637906'
311
shipment.RequestedShipment.Recipient.Address.StreetLines = receipient.address1 #['Address Line 1']
312
shipment.RequestedShipment.Recipient.Address.City = receipient.city #'Herndon'
313
shipment.RequestedShipment.Recipient.Address.StateOrProvinceCode = receipient.state_code #'VA'
314
shipment.RequestedShipment.Recipient.Address.PostalCode = receipient.zip #'20171'
315
shipment.RequestedShipment.Recipient.Address.CountryCode = receipient.country_code #'US'
316
# This is needed to ensure an accurate rate quote with the response.
317
shipment.RequestedShipment.Recipient.Address.Residential = False
319
# Who pays for the shipment?
320
# RECIPIENT, SENDER or THIRD_PARTY
321
shipment.RequestedShipment.ShippingChargesPayment.PaymentType = fedex_servicedetails.payment_type_fedex #'SENDER'
323
# Specifies the label type to be returned.
324
# LABEL_DATA_ONLY or COMMON2D
325
shipment.RequestedShipment.LabelSpecification.LabelFormatType = 'COMMON2D'
327
# Specifies which format the label file will be sent to you in.
328
# DPL, EPL2, PDF, PNG, ZPLII
329
shipment.RequestedShipment.LabelSpecification.ImageType = 'PNG'
331
# To use doctab stocks, you must change ImageType above to one of the
332
# label printer formats (ZPLII, EPL2, DPL).
333
# See documentation for paper types, there quite a few.
334
shipment.RequestedShipment.LabelSpecification.LabelStockType = 'PAPER_4X6'
336
# This indicates if the top or bottom of the label comes out of the
338
# BOTTOM_EDGE_OF_TEXT_FIRST or TOP_EDGE_OF_TEXT_FIRST
339
shipment.RequestedShipment.LabelSpecification.LabelPrintingOrientation = 'BOTTOM_EDGE_OF_TEXT_FIRST'
341
package1_weight = shipment.create_wsdl_object_of_type('Weight')
343
package1_weight.Value = fedex_servicedetails.weight_package #1.0
344
package1_weight.Units = "LB"
346
package1 = shipment.create_wsdl_object_of_type('RequestedPackageLineItem')
347
package1.Weight = package1_weight
348
# Un-comment this to see the other variables you may set on a package.
351
# This adds the RequestedPackageLineItem WSDL object to the shipment. It
352
# increments the package count and total weight of the shipment for you.
353
shipment.add_package(package1)
355
# If you'd like to see some documentation on the ship service WSDL, un-comment
356
# this line. (Spammy).
357
#print shipment.client
359
# Un-comment this to see your complete, ready-to-send request as it stands
360
# before it is actually sent. This is useful for seeing what values you can
362
#print shipment.RequestedShipment
364
# If you want to make sure that all of your entered details are valid, you
365
# can call this and parse it just like you would via send_request(). If
366
# shipment.response.HighestSeverity == "SUCCESS", your shipment is valid.
367
#shipment.send_validation_request()
369
# Fires off the request, sets the 'response' attribute on the object.
371
shipment.send_request()
374
if e.reason.strerror == 'Name or service not known':
375
errormessage = "Connection Error: Please check your internet connection!"
379
print "EXception: ",errormessage
380
raise osv.except_osv(_('Error'), _('%s' % (errormessage,)))
382
# This will show the reply to your shipment being sent. You can access the
383
# attributes through the response attribute on the request object. This is
384
# good to un-comment to see the variables returned by the Fedex reply.
385
#print shipment.response
387
# Here is the overall end result of the query.
388
print "HighestSeverity:", shipment.response.HighestSeverity
389
# Getting the tracking number from the new shipment.
390
fedexTrackingNumber = shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber
391
print "Fedex Tracking#:",fedexTrackingNumber
392
# Net shipping costs.
393
fedexshippingrate = shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageRating.PackageRateDetails[0].NetCharge.Amount
394
print "Net Shipping Cost (US$):",fedexshippingrate
396
# Get the label image in ASCII format from the reply. Note the list indices
397
# we're using. You'll need to adjust or iterate through these if your shipment
398
# has multiple packages.
399
ascii_label_data = shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].Label.Parts[0].Image
400
# Convert the ASCII data to binary.
401
# label_binary_data = binascii.a2b_base64(ascii_label_data)
402
# print"LABEL: ",label_binary_data
404
#This is an example of how to dump a label to a PNG file.
406
# This will be the file we write the label out to.
407
# png_file = open('example_shipment_label.png', 'wb')
408
# png_file.write(b64decode(label_binary_data))
412
fedex_attachment_pool = self.pool.get('ir.attachment')
413
fedex_data_attach = {
414
'name': 'PackingList.png',
415
'datas': binascii.b2a_base64(str(b64decode(ascii_label_data))),
416
'description': 'Packing List',
417
'res_name': shippingresp_lnk.picking_id.name,
418
'res_model': 'stock.picking',
419
'res_id': shippingresp_lnk.picking_id.id,
422
fedex_attach_id = fedex_attachment_pool.search(cr,uid,[('res_id','=',shippingresp_lnk.picking_id.id),('res_name','=',shippingresp_lnk.picking_id.name)])
423
if not fedex_attach_id:
424
fedex_attach_id = fedex_attachment_pool.create(cr, uid, fedex_data_attach)
425
print "attach_id: ",fedex_attach_id
427
fedex_attach_result = fedex_attachment_pool.write(cr, uid, fedex_attach_id, fedex_data_attach)
428
fedex_attach_id = fedex_attach_id[0]
429
print "attach_result: ",fedex_attach_result
431
context['attach_id'] = fedex_attach_id
432
context['tracking_no'] = fedexTrackingNumber
434
#This is an example of how to print the label to a serial printer. This will not
435
#work for all label printers, consult your printer's documentation for more
436
#details on what formats it can accept.
438
# Pipe the binary directly to the label printer. Works under Linux
439
# without requiring PySerial. This WILL NOT work on other platforms.
440
#label_printer = open("/dev/ttyS0", "w")
441
#label_printer.write(label_binary_data)
442
#label_printer.close()
445
#This is a potential cross-platform solution using pySerial. This has not been
446
#tested in a long time and may or may not work. For Windows, Mac, and other
447
#platforms, you may want to go this route.
450
#label_printer = serial.Serial(0)
451
#print "SELECTED SERIAL PORT: "+ label_printer.portstr
452
#label_printer.write(label_binary_data)
453
#label_printer.close()
455
# if shipment.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber:
456
# track_success = True
457
if fedexTrackingNumber:
458
stockpickingwrite_result = stockpicking_obj.write(cr,uid,shippingresp_lnk.picking_id.id,{'carrier_tracking_ref':fedexTrackingNumber, 'shipping_label':binascii.b2a_base64(str(b64decode(ascii_label_data))), 'shipping_rate': fedexshippingrate})
459
context['track_success'] = True
461
elif shippingresp_lnk.type.lower() == 'ups':
462
ups_info = self.pool.get('shipping.ups').get_ups_info(cr,uid,context)
464
stockpicking_obj = self.pool.get('stock.picking')
465
pickup_type_ups = shippingresp_lnk.picking_id.pickup_type_ups
466
service_type_ups = shippingresp_lnk.picking_id.service_type_ups
467
packaging_type_ups = shippingresp_lnk.picking_id.packaging_type_ups
468
ups = shippingservice.UPSShipmentConfirmRequest(ups_info, pickup_type_ups, service_type_ups, packaging_type_ups, weight, shipper, receipient)
470
ups_response = ups.send()
473
if e.reason.strerror == 'Name or service not known':
474
errormessage = "Connection Error: Please check your internet connection!"
478
print "EXception: ",errormessage
479
raise osv.except_osv(_('Error'), _('%s' % (errormessage,)))
481
ups = shippingservice.UPSShipmentAcceptRequest(ups_info, ups_response.shipment_digest)
482
ups_response = ups.send()
484
context['attach_id'] = stockpicking_obj.create_attachment(cr,uid,[shippingresp_lnk.picking_id.id],ups_response,context)
485
stockpickingwrite_result = stockpicking_obj.write(cr,uid,shippingresp_lnk.picking_id.id,{'carrier_tracking_ref':ups_response.tracking_number, 'shipping_label':binascii.b2a_base64(str(b64decode(ups_response.graphic_image))), 'shipping_rate': rate})
486
context['track_success'] = True
487
context['tracking_no'] = ups_response.tracking_number
489
### Check Availability; Confirm; Validate : Automate Process Now step
490
if context.get('track_success',False):
491
### Assign Carrier to Delivery carrier if user has not chosen
492
# carrier_lnk = stockpicking_obj.browse(cr,uid,shippingresp_lnk.picking_id.id).carrier_id
493
# if not carrier_lnk:
495
if shippingresp_lnk.type.lower() == 'usps':
496
type_fieldname = 'is_usps'
497
elif shippingresp_lnk.type.lower() == 'ups':
498
type_fieldname = 'is_ups'
499
elif shippingresp_lnk.type.lower() == 'fedex':
500
type_fieldname = 'is_fedex'
502
carrier_ids = self.pool.get('delivery.carrier').search(cr,uid,[('service_output','=',shippingresp_lnk.name),(type_fieldname,'=',True)])
505
raise osv.except_osv(_('Error'), _('Shipping service output settings not defined'))
507
# print "selected carrier ids: ",carrier_ids
508
self.pool.get('stock.picking').write(cr,uid,shippingresp_lnk.picking_id.id,{'carrier_id':carrier_ids[0]})
510
### Check Availabiity
511
actionassign_result = stockpicking_obj.action_assign_new(cr,uid,[shippingresp_lnk.picking_id.id])
512
print "actionassign_result: ",actionassign_result
513
if not actionassign_result:
514
### Force Availability
515
# forceassign_result = stockpicking_obj.force_assign(cr,uid,[shippingresp_lnk.picking_id.id])
516
saleorder_obj.write(cr,uid,shippingresp_lnk.picking_id.sale_id.id,{'state':'shipping_except'})
519
current_time = time.strftime('%Y-%m-%d %H:%M:%S')
521
'delivery_date' : current_time
524
for move in move_lines:
525
if move.state in ('done', 'cancel'):
528
partial_datas['move%s' % (move.id)] = {
529
'product_id' : move.product_id.id,
530
'product_qty' : move.product_qty,
531
'product_uom' :move.product_uom.id,
532
'prodlot_id' : move.prodlot_id.id,
535
#print "partial_datas: ",partial_datas
536
res = stockpicking_obj.do_partial(cr,uid,[shippingresp_lnk.picking_id.id],partial_datas,context)
538
wf_service = netsvc.LocalService("workflow")
539
wf_service.trg_write(uid, 'stock.picking', shippingresp_lnk.picking_id.id, cr)
540
wf_service.trg_write(uid, 'sale.order', shippingresp_lnk.picking_id.sale_id.id, cr)
541
saleorder_obj.write(cr,uid,shippingresp_lnk.picking_id.sale_id.id,{'client_order_ref':context['tracking_no'], 'carrier_id':carrier_ids[0]})
543
### Write this shipping respnse is selected
544
self.write(cr,uid,ids[0],{'selected':True})
546
if context.get('batch_printing',False):
550
#serverip = socket.gethostbyname(socket.gethostname())
552
serverip = urllib2.urlopen('http://whatismyip.org').read()
555
raise osv.except_osv(_('Error'), _('%s' % (e)))
557
print "IP ADDRESS IS: ",serverip
559
return {'type': 'ir.actions.act_url',
560
'url': 'http://'+serverip+':8080/openerp/attachment/get?record=' + str(context['attach_id']),
563
# datas = {'ids': [shippingresp_lnk.picking_id.id],
564
# 'model': 'stock.picking'}
566
# return {'type': 'ir.actions.report.xml',
567
# 'report_name': 'webkitstock.picking.label',
575
'name': fields.char('Service Type', size=100, readonly=True),
576
'type': fields.char('Shipping Type', size=64, readonly=True),
577
'rate': fields.char('Rate', size=64, readonly=True),
578
#'tracking_no' : fields.char('Tracking No.', size=100),
579
'weight' : fields.float('Weight'),
580
'cust_default' : fields.boolean('Customer Default'),
581
'sys_default' : fields.boolean('System Default'),
582
'sr_no' : fields.integer('Sr. No'),
583
'selected' : fields.boolean('Selected'),
584
'picking_id' : fields.many2one('stock.picking','Picking')
592
def _get_shipping_type(self, cr, uid, context=None):
599
def _get_service_type_usps(self, cr, uid, context=None):
601
('First Class', 'First Class'),
602
('First Class HFP Commercial', 'First Class HFP Commercial'),
603
('FirstClassMailInternational', 'First Class Mail International'),
604
('Priority', 'Priority'),
605
('Priority Commercial', 'Priority Commercial'),
606
('Priority HFP Commercial', 'Priority HFP Commercial'),
607
('PriorityMailInternational', 'Priority Mail International'),
608
('Express', 'Express'),
609
('Express Commercial', 'Express Commercial'),
610
('Express SH', 'Express SH'),
611
('Express SH Commercial', 'Express SH Commercial'),
612
('Express HFP', 'Express HFP'),
613
('Express HFP Commercial', 'Express HFP Commercial'),
614
('ExpressMailInternational', 'Express Mail International'),
615
('ParcelPost', 'Parcel Post'),
616
('ParcelSelect', 'Parcel Select'),
617
('StandardMail', 'Standard Mail'),
618
('CriticalMail', 'Critical Mail'),
620
('Library', 'Library'),
622
('Online', 'Online'),
625
def _get_first_class_mail_type_usps(self, cr, uid, context=None):
627
('Letter', 'Letter'),
629
('Parcel', 'Parcel'),
630
('Postcard', 'Postcard'),
633
def _get_container_usps(self, cr, uid, context=None):
635
('Variable', 'Variable'),
637
('Letter', 'Letter'),
639
('Parcel', 'Parcel'),
640
('Large Parcel', 'Large Parcel'),
641
('Irregular Parcel', 'Irregular Parcel'),
642
('Oversized Parcel', 'Oversized Parcel'),
643
('Flat Rate Envelope', 'Flat Rate Envelope'),
644
('Padded Flat Rate Envelope', 'Padded Flat Rate Envelope'),
645
('Legal Flat Rate Envelope', 'Legal Flat Rate Envelope'),
646
('SM Flat Rate Envelope', 'SM Flat Rate Envelope'),
647
('Window Flat Rate Envelope', 'Window Flat Rate Envelope'),
648
('Gift Card Flat Rate Envelope', 'Gift Card Flat Rate Envelope'),
649
('Cardboard Flat Rate Envelope', 'Cardboard Flat Rate Envelope'),
650
('Flat Rate Box', 'Flat Rate Box'),
651
('SM Flat Rate Box', 'SM Flat Rate Box'),
652
('MD Flat Rate Box', 'MD Flat Rate Box'),
653
('LG Flat Rate Box', 'LG Flat Rate Box'),
654
('RegionalRateBoxA', 'RegionalRateBoxA'),
655
('RegionalRateBoxB', 'RegionalRateBoxB'),
656
('Rectangular', 'Rectangular'),
657
('Non-Rectangular', 'Non-Rectangular'),
660
def _get_size_usps(self, cr, uid, context=None):
662
('REGULAR', 'Regular'),
666
class stock_picking(osv.osv):
667
_name = "stock.picking"
668
_inherit = "stock.picking"
670
def action_assign_new(self, cr, uid, ids, *args):
671
""" Changes state of picking to available if all moves are confirmed.
674
for pick in self.browse(cr, uid, ids):
675
move_ids = [x.id for x in pick.move_lines if x.state == 'confirmed']
676
print "move_ids in action_assign_new: ",move_ids
679
self.pool.get('stock.move').action_assign(cr, uid, move_ids)
682
def get_ups_servicetype_name(self, cr, uid, ids, code, mag_code=False):
685
return 'Next Day Air'
687
return 'Second Day Air'
691
return 'Worldwide Express'
693
return 'Worldwide Expedited'
697
return 'Three-Day Select'
699
return 'Next Day Air Saver'
701
return 'Next Day Air Early AM'
703
return 'Worldwide Express Plus'
705
return 'Second Day Air AM'
711
if mag_code == 'ups_3DS':
712
return 'Three-Day Select'
713
elif mag_code == 'ups_GND':
715
elif mag_code == 'ups_2DA':
716
return 'Second Day Air'
717
elif mag_code == 'ups_1DP':
718
return 'Next Day Air Saver'
719
elif mag_code == 'ups_1DA':
720
return 'Next Day Air'
721
elif mag_code == 'ups_1DM':
722
return 'Next Day Air Early AM'
726
def generate_fedex_shipping(self, cr, uid, ids, dropoff_type_fedex, service_type_fedex, packaging_type_fedex, package_detail_fedex, payment_type_fedex, physical_packaging_fedex, weight, shipper_postal_code,shipper_country_code,customer_postal_code,customer_country_code, sys_default=False,cust_default=False, error=True, context=None):
727
if 'fedex_active' in context.keys() and context['fedex_active'] == False:
729
shippingfedex_obj = self.pool.get('shipping.fedex')
730
shippingfedex_id = shippingfedex_obj.search(cr,uid,[('active','=',True)])
731
if not shippingfedex_id:
733
raise osv.except_osv(_('Error'), _('Default FedEx settings not defined'))
737
shippingfedex_id = shippingfedex_id[0]
739
shippingfedex_ptr = shippingfedex_obj.browse(cr,uid,shippingfedex_id)
740
account_no = shippingfedex_ptr.account_no
741
key = shippingfedex_ptr.key
742
password = shippingfedex_ptr.password
743
meter_no = shippingfedex_ptr.meter_no
744
is_test = shippingfedex_ptr.test
745
CONFIG_OBJ = FedexConfig(key=key, password=password, account_number=account_no, meter_number=meter_no, use_test_server=is_test)
746
rate_request = FedexRateServiceRequest(CONFIG_OBJ)
748
stockpicking_lnk = self.browse(cr,uid,ids[0])
750
#print "dropoff_type_fedex: ",dropoff_type_fedex
751
#print "service_type_fedex: ",service_type_fedex
752
#print "packaging_type_fedex: ",packaging_type_fedex
753
# This is very generalized, top-level information.
754
# REGULAR_PICKUP, REQUEST_COURIER, DROP_BOX, BUSINESS_SERVICE_CENTER or STATION
755
rate_request.RequestedShipment.DropoffType = dropoff_type_fedex
757
# See page 355 in WS_ShipService.pdf for a full list. Here are the common ones:
758
# STANDARD_OVERNIGHT, PRIORITY_OVERNIGHT, FEDEX_GROUND, FEDEX_EXPRESS_SAVER
759
rate_request.RequestedShipment.ServiceType = service_type_fedex
761
# What kind of package this will be shipped in.
762
# FEDEX_BOX, FEDEX_PAK, FEDEX_TUBE, YOUR_PACKAGING
763
rate_request.RequestedShipment.PackagingType = packaging_type_fedex
765
# No idea what this is.
766
# INDIVIDUAL_PACKAGES, PACKAGE_GROUPS, PACKAGE_SUMMARY
767
rate_request.RequestedShipment.PackageDetail = package_detail_fedex
769
rate_request.RequestedShipment.Shipper.Address.PostalCode = shipper_postal_code
770
rate_request.RequestedShipment.Shipper.Address.CountryCode = shipper_country_code
771
rate_request.RequestedShipment.Shipper.Address.Residential = False
773
rate_request.RequestedShipment.Recipient.Address.PostalCode = customer_postal_code
774
rate_request.RequestedShipment.Recipient.Address.CountryCode = customer_country_code
775
# This is needed to ensure an accurate rate quote with the response.
776
#rate_request.RequestedShipment.Recipient.Address.Residential = True
777
#include estimated duties and taxes in rate quote, can be ALL or NONE
778
rate_request.RequestedShipment.EdtRequestType = 'NONE'
780
# Who pays for the rate_request?
781
# RECIPIENT, SENDER or THIRD_PARTY
782
rate_request.RequestedShipment.ShippingChargesPayment.PaymentType = payment_type_fedex
784
package1_weight = rate_request.create_wsdl_object_of_type('Weight')
785
package1_weight.Value = weight
786
package1_weight.Units = "LB"
788
package1 = rate_request.create_wsdl_object_of_type('RequestedPackageLineItem')
789
package1.Weight = package1_weight
790
#can be other values this is probably the most common
791
package1.PhysicalPackaging = physical_packaging_fedex
792
# Un-comment this to see the other variables you may set on a package.
795
# This adds the RequestedPackageLineItem WSDL object to the rate_request. It
796
# increments the package count and total weight of the rate_request for you.
797
rate_request.add_package(package1)
799
# If you'd like to see some documentation on the ship service WSDL, un-comment
800
# this line. (Spammy).
801
#print rate_request.client
803
# Un-comment this to see your complete, ready-to-send request as it stands
804
# before it is actually sent. This is useful for seeing what values you can
806
#print rate_request.RequestedShipment
808
# Fires off the request, sets the 'response' attribute on the object.
810
rate_request.send_request()
814
raise Exception('%s' % (e))
817
# This will show the reply to your rate_request being sent. You can access the
818
# attributes through the response attribute on the request object. This is
819
# good to un-comment to see the variables returned by the FedEx reply.
820
#print 'response: ', rate_request.response
822
# Here is the overall end result of the query.
823
#print "HighestSeverity:", rate_request.response.HighestSeverity
825
for detail in rate_request.response.RateReplyDetails[0].RatedShipmentDetails:
826
for surcharge in detail.ShipmentRateDetail.Surcharges:
827
if surcharge.SurchargeType == 'OUT_OF_DELIVERY_AREA':
828
print "ODA rate_request charge %s" % surcharge.Amount.Amount
830
for rate_detail in rate_request.response.RateReplyDetails[0].RatedShipmentDetails:
831
print "Net FedEx Charge %s %s" % (rate_detail.ShipmentRateDetail.TotalNetFedExCharge.Currency,rate_detail.ShipmentRateDetail.TotalNetFedExCharge.Amount)
834
sys_default_value = False
835
cust_default_value = False
837
sys_default_vals = sys_default.split('/')
838
#print "sys_default_vals: ",sys_default_vals
839
if sys_default_vals[0] == 'FedEx':
840
sys_default_value = True
844
cust_default_vals = cust_default.split('/')
845
#print "sys_default_vals: ",sys_default_vals
846
if cust_default_vals[0] == 'FedEx':
847
cust_default_value = True
851
'name' : service_type_fedex,
853
'rate' : rate_detail.ShipmentRateDetail.TotalNetFedExCharge.Amount,
854
'picking_id' : ids[0], #Change the ids[0] when switch to create
856
'sys_default' : sys_default_value,
857
'cust_default' : cust_default_value,
860
fedex_res_id = self.pool.get('shipping.response').create(cr,uid,fedex_res_vals)
861
#print "fedex_res_id: ",fedex_res_id
868
def generate_usps_shipping(self, cr, uid, ids,service_type_usps,first_class_mail_type_usps,container,size_usps,weight,zip_origination,zip_destination,sys_default=False,cust_default=False,error=True,context=None):
870
### Shift the code to def create
871
### Check if it is in delivery orders - Done
872
### Deleting all that exist if user is generating shipping again - Done
873
### Defaults values of types
874
### New link to do Generate Shipping
877
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'service_type_usps is %s'%(urllib.urlencode(service_type),))
878
if 'usps_active' in context.keys() and context['usps_active'] == False:
881
stockpicking_lnk = self.browse(cr,uid,ids[0])
884
shippingusps_obj = self.pool.get('shipping.usps')
885
shippingusps_id = shippingusps_obj.search(cr,uid,[('active','=',True)])
886
if not shippingusps_id:
887
### This is required because when picking is created when saleorder is confirmed and if the default parameter has some error then it should not stop as the order is getting imported from external sites
889
raise osv.except_osv(_('Error'), _('Active USPS settings not defined'))
893
shippingusps_id = shippingusps_id[0]
894
shippingusps_ptr = shippingusps_obj.browse(cr,uid,shippingusps_id)
895
user_id = shippingusps_ptr.user_id
897
url = "http://testing.shippingapis.com/ShippingAPITest.dll?API=RateV4&" if shippingusps_ptr.test else "http://production.shippingapis.com/ShippingAPI.dll?API=RateV4&"
899
## <Service></Service>
900
service_type = '<Service>' + service_type_usps + '</Service>'
902
if service_type_usps == 'First Class':
903
service_type += '<FirstClassMailType>' + first_class_mail_type_usps + '</FirstClassMailType>'
904
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'service_type is %s'%(service_type,))
906
container = container and '<Container>' + container + '</Container>' or '<Container/>'
907
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'container is %s'%(container,))
909
size = '<Size>' + size_usps + '</Size>'
910
if size_usps == 'LARGE':
911
size += '<Width>' + str(stockpicking_lnk.width_usps) + '</Width>'
912
size += '<Length>' + str(stockpicking_lnk.length_usps) + '</Length>'
913
size += '<Height>' + str(stockpicking_lnk.height_usps) + '</Height>'
915
if stockpicking_lnk.container_usps == 'Non-Rectangular' or stockpicking_lnk.container_usps == 'Variable' or stockpicking_lnk.container_usps == '':
916
size += '<Girth>' + str(stockpicking_lnk.height_usps) + '</Girth>'
917
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'size is %s'%(size,))
920
weight = math.modf(weight)
921
pounds = int(weight[1])
922
ounces = round(weight[0],2) * 16
924
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'pounds is %s'%(pounds,))
925
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'ounces is %s'%(ounces,))
928
values['XML'] = '<RateV4Request USERID="' + user_id + '"><Revision/><Package ID="1ST">' + service_type + '<ZipOrigination>' + zip_origination + '</ZipOrigination><ZipDestination>' + zip_destination + '</ZipDestination><Pounds>' + str(pounds) + '</Pounds><Ounces>' + str(ounces) + '</Ounces>' + container + size + '<Machinable>true</Machinable></Package></RateV4Request>'
929
logger.notifyChannel('init', netsvc.LOG_WARNING, 'values is %s'%(urllib.urlencode(values),))
930
url = url + urllib.urlencode(values)
931
logger.notifyChannel('init', netsvc.LOG_WARNING, 'shipping url is %s'%(url,))
933
f = urllib2.urlopen(url)
935
logger.notifyChannel('init', netsvc.LOG_WARNING, '!!!!!!shipping response is %s'%(response,))
937
raise Exception('%s' % (e))
941
if response.find('<Error>') != -1:
942
sIndex = response.find('<Description>')
943
eIndex = response.find('</Description>')
945
raise Exception('%s' % (response[int(sIndex)+13:int(eIndex)],))
951
i = sIndex = eIndex = 0
952
sIndex = response.find('<MailService>',i)
953
eIndex = response.find('</MailService>',i)
954
rsIndex = response.find('<Rate>',i)
955
reIndex = response.find('</Rate>',i)
956
while (sIndex != -1):
958
mail_service = response[int(sIndex) + 13:int(eIndex)]
960
# mail_service = mail_service.replace("&lt;sup&gt;&amp;reg;&lt;/sup&gt;",str(tm))
961
mail_service = mail_service.replace("&lt;sup&gt;&amp;reg;&lt;/sup&gt;","")
962
rate = response[int(rsIndex)+6:int(reIndex)]
963
sIndex = response.find('<MailService>',i)
964
eIndex = response.find('</MailService>',i)
965
rsIndex = response.find('<Rate>',i)
966
reIndex = response.find('</Rate>',i)
967
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'sIndex is %s'%(sIndex,))
968
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'eIndex is %s'%(eIndex,))
969
#logger.notifyChannel('init', netsvc.LOG_WARNING, '!!!!!!shipping mail_service is %s'%(mail_service,))
970
#logger.notifyChannel('init', netsvc.LOG_WARNING, '!!!!!!shipping rate is %s'%(h.unescape(rate),))
974
if mail_service.lower().find(def_service_type.lower()) != -1:
975
#print "Testng condition: ",mail_service.lower().find(def_service_type.lower())
976
if mail_service.lower().find(def_firstclass_type.lower()) != -1:
978
if mail_service.lower().find(def_container.lower()) != -1:
979
sys_default_value = True
982
sys_default_value = True
985
sys_default_value = False
986
cust_default_value = False
988
print "sys_default: ",sys_default
990
if cust_default and cust_default.split('/')[0] == 'USPS':
991
cust_default_value = True
994
elif sys_default and sys_default.split('/')[0] == 'USPS':
995
sys_default_value = True
999
'name' : mail_service,
1002
'picking_id' : ids[0], #Change the ids[0] when switch to create
1003
'weight' : weight_org,
1004
'sys_default' : sys_default_value,
1005
'cust_default' : cust_default_value,
1008
usps_res_id = self.pool.get('shipping.response').create(cr,uid,usps_res_vals)
1009
logger.notifyChannel('init', netsvc.LOG_WARNING, 'usps_res_id is %s'%(usps_res_id,))
1015
def create_quotes(self, cr, uid, ids, vals, context={}):
1017
'name' : vals.service_type,
1018
'type' : context['type'],
1020
'picking_id' : ids[0], #Change the ids[0] when switch to create
1021
'weight' : vals.weight,
1022
'sys_default' : False,
1023
'cust_default' : False,
1024
'sr_no' : vals.sr_no,
1026
res_id = self.pool.get('shipping.response').create(cr,uid,quotes_vals)
1027
logger.notifyChannel('init', netsvc.LOG_WARNING, 'res_id is %s'%(res_id,))
1033
def create_attachment(self, cr, uid, ids, vals, context={}):
1034
attachment_pool = self.pool.get('ir.attachment')
1036
'name': 'PackingList.' + vals.image_format.lower() ,
1037
'datas': binascii.b2a_base64(str(b64decode(vals.graphic_image))),
1038
'description': 'Packing List',
1039
'res_name': self.browse(cr,uid,ids[0]).name,
1040
'res_model': 'stock.picking',
1043
attach_id = attachment_pool.search(cr,uid,[('res_id','=',ids[0]),('res_name','=',self.browse(cr,uid,ids[0]).name)])
1045
attach_id = attachment_pool.create(cr, uid, data_attach)
1046
print "attach_id: ",attach_id
1048
attach_id = attach_id[0]
1049
attach_result = attachment_pool.write(cr, uid, attach_id, data_attach)
1050
print "attach_result: ",attach_result
1054
## This function is called when the button is clicked
1055
def generate_shipping(self, cr, uid, ids, context={}):
1057
print"rajivcontext",context
1060
# logger.notifyChannel('init', netsvc.LOG_WARNING, 'inside generate_shipping context: %s'%(context,))
1064
stockpicking = self.browse(cr,uid,id)
1065
shipping_type = stockpicking.shipping_type
1066
print"shipping_type@@@",shipping_type
1068
weight = stockpicking.weight_package if stockpicking.weight_package else stockpicking.weight_net
1070
if context.get('error',False):
1071
raise Exception('Package Weight Invalid!')
1074
shop_id = stockpicking.sale_id.shop_id
1075
print"shop_id@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",shop_id
1076
cust_address = stockpicking.sale_id.shop_id.cust_address
1077
print "CUST ADDRESS: ",cust_address
1078
if not cust_address:
1079
if context.get('error',False):
1080
raise Exception('Shop Address not defined!')
1084
shipper = Address(cust_address.name or cust_address.partner_id.name, cust_address.street, cust_address.city, cust_address.state_id.code or '', cust_address.zip, cust_address.country_id.code, cust_address.street2 or '', cust_address.phone or '', cust_address.email, cust_address.partner_id.name)
1087
cust_address = stockpicking.address_id
1090
stockpicking_lnk = self.browse(cr,uid,ids[0])
1091
receipient = Address(cust_address.name or cust_address.partner_id.name, cust_address.street, cust_address.city, cust_address.state_id.code or '', cust_address.zip, cust_address.country_id.code, cust_address.street2 or '', cust_address.phone or '', cust_address.email, cust_address.partner_id.name)
1093
# Deleting previous quotes
1094
shipping_res_obj = self.pool.get('shipping.response')
1095
shipping_res_ids = shipping_res_obj.search(cr,uid,[('picking_id','=',ids[0])])
1096
if shipping_res_ids:
1097
shipping_res_obj.unlink(cr,uid,shipping_res_ids)
1099
if 'usps_active' not in context.keys() and (shipping_type == 'USPS' or shipping_type == 'All'):
1100
print"Asif inside usps"
1101
usps_info = self.pool.get('shipping.usps').get_usps_info(cr,uid,context)
1102
service_type_usps = stockpicking.service_type_usps
1103
first_class_mail_type_usps = stockpicking.first_class_mail_type_usps or ''
1104
container_usps = stockpicking.container_usps or ''
1105
size_usps = stockpicking.size_usps
1106
width_usps = stockpicking.width_usps
1107
length_usps = stockpicking.length_usps
1108
height_usps = stockpicking.height_usps
1109
girth_usps = stockpicking.girth_usps
1110
usps = shippingservice.USPSRateRequest(usps_info, service_type_usps, first_class_mail_type_usps, container_usps, size_usps, width_usps, length_usps, height_usps, girth_usps, weight, shipper, receipient, cust_default, sys_default)
1111
usps_response = usps.send()
1112
context['type'] = 'USPS'
1113
self.create_quotes(cr,uid,ids,usps_response,context)
1114
# shipping_res = self.generate_usps_shipping(cr,uid,[id],service_type_usps,first_class_mail_type_usps,container_usps,size_usps,weight,shipper_postal_code,customer_postal_code,sys_default,cust_default,error_required,context)
1116
if 'ups_active' not in context.keys() or (shipping_type == 'UPS' or shipping_type == 'All'):
1117
print"Rajiv.S.Singh"
1118
ups_info = self.pool.get('shipping.ups').get_ups_info(cr,uid,context)
1119
pickup_type_ups = stockpicking.pickup_type_ups
1120
service_type_ups = stockpicking.service_type_ups
1121
packaging_type_ups = stockpicking.packaging_type_ups
1122
ups = shippingservice.UPSRateRequest(ups_info, pickup_type_ups, service_type_ups, packaging_type_ups, weight, shipper, receipient, cust_default, sys_default)
1123
ups_response = ups.send()
1124
context['type'] = 'UPS'
1125
self.create_quotes(cr,uid,ids,ups_response,context)
1126
# shipping_res = self.generate_ups_shipping(cr,uid,[id],pickup_type_ups,service_type_ups,packaging_type_ups,weight,shipper_postal_code,shipper_country_code,customer_postal_code,customer_country_code,sys_default,cust_default,error_required,context)
1128
if shipping_type == 'Fedex' or shipping_type == 'All':
1129
dropoff_type_fedex = stockpicking.dropoff_type_fedex
1130
service_type_fedex = stockpicking.service_type_fedex
1131
packaging_type_fedex = stockpicking.packaging_type_fedex
1132
package_detail_fedex = stockpicking.package_detail_fedex
1133
payment_type_fedex = stockpicking.payment_type_fedex
1134
physical_packaging_fedex = stockpicking.physical_packaging_fedex
1135
shipper_postal_code = shipper.zip
1136
shipper_country_code = shipper.country_code
1137
customer_postal_code = receipient.zip
1138
customer_country_code = receipient.country_code
1139
error_required = True
1140
shipping_res = self.generate_fedex_shipping(cr,uid,[id],dropoff_type_fedex,service_type_fedex,packaging_type_fedex,package_detail_fedex,payment_type_fedex,physical_packaging_fedex,weight,shipper_postal_code,shipper_country_code,customer_postal_code,customer_country_code,sys_default,cust_default,error_required,context)
1141
except Exception, exc:
1142
raise osv.except_osv(_('Error!'),_('%s' % (exc,)))
1145
def _get_cust_default_shipping(self,cr,uid,carrier_id,context={}):
1147
carrier_obj = self.pool.get('delivery.carrier')
1148
carrier_lnk = carrier_obj.browse(cr,uid,carrier_id)
1150
if carrier_lnk.is_ups:
1151
cust_default = 'UPS'
1152
service_type_ups = carrier_lnk.service_code or '03'
1153
cust_default += '/' + service_type_ups
1154
elif carrier_lnk.is_fedex:
1155
cust_default = 'FedEx'
1156
service_type_fedex = carrier_lnk.service_code or 'FEDEX_GROUND'
1157
cust_default += '/' + service_type_fedex
1158
elif carrier_lnk.is_usps:
1159
cust_default = 'USPS'
1160
service_type_usps = carrier_lnk.service_code or 'All'
1161
cust_default += '/' + service_type_usps
1163
cust_default = False
1166
def _get_sys_default_shipping(self,cr,uid,saleorderline_ids,weight,context={}):
1167
print "SIJO:inside _get_sys_default_shipping"
1169
if len(saleorderline_ids) <= 2:
1170
product_obj = self.pool.get('product.product')
1171
saleorderline_obj = self.pool.get('sale.order.line')
1172
product_shipping_obj = self.pool.get('product.product.shipping')
1173
product_categ_shipping_obj = self.pool.get('product.category.shipping')
1176
### Making sure product is not Shipping and Handling
1177
for line in saleorderline_obj.browse(cr,uid,saleorderline_ids):
1178
if line.product_id.type == 'service':
1180
product_id = line.product_id.id
1185
product_shipping_ids = product_shipping_obj.search(cr,uid,[('product_id','=',product_id)])
1187
if not product_shipping_ids:
1188
categ_id = product_obj.browse(cr,uid,product_id).product_tmpl_id.categ_id.id
1189
product_categ_shipping_ids = product_categ_shipping_obj.search(cr,uid,[('product_categ_id','=',categ_id)])
1190
if not product_categ_shipping_ids:
1191
### Assume the default
1192
if (weight*16) > 14.0:
1193
sys_default = 'USPS/Priority/Parcel/REGULAR'
1195
sys_default = 'USPS/First Class/Parcel/REGULAR'
1198
if product_shipping_ids:
1201
'FROM product_product_shipping '
1202
'WHERE weight <= %s ' +
1203
'and product_id=%s ' +
1204
'order by sequence desc limit 1',
1205
(weight,product_id))
1209
'FROM product_category_shipping '
1210
'WHERE weight <= %s '+
1211
'and product_categ_id=%s '+
1212
'order by sequence desc limit 1',
1214
res = cr.dictfetchall()
1216
## res: [{'create_uid': 1, 'create_date': '2011-06-28 01:43:49.017306', 'product_id': 187, 'weight': 3.0, 'sequence': 3, 'container_usps': u'Letter', 'service_type_usps': u'First Class', 'write_uid': None, 'first_class_mail_type_usps': u'Letter', 'size_usps': u'REGULAR', 'write_date': None, 'shipping_type': u'USPS', 'id': 14}]
1217
### Format- USPS/First Class/Letter
1218
sys_default = res[0]['shipping_type'] + '/' + res[0]['service_type_usps'] + '/' + res[0]['container_usps'] + '/' + res[0]['size_usps']
1222
def create(self, cr, uid, vals, context=None):
1223
#print "create vals: ",vals
1224
#create vals: {'origin': u'SO009', 'note': False, 'state': 'auto', 'name': u'OUT/00007', 'sale_id': 9, 'move_type': u'direct', 'type': 'out', 'address_id': 3, 'invoice_state': 'none', 'company_id': 1}
1227
if vals.get('type',False) and vals['type'] == 'out':
1229
vals['shipping_type'] = 'All'
1230
cust_default = False
1231
saleorder_lnk = self.pool.get('sale.order') .browse(cr,uid,vals['sale_id'])
1232
saleorderline_obj = self.pool.get('sale.order.line')
1233
saleorderline_ids = saleorderline_obj.search(cr,uid,[('order_id','=',vals['sale_id'])])
1234
#logger.notifyChannel('init', netsvc.LOG_WARNING, 'saleorderline_ids is %s'%(saleorderline_ids),)
1236
for saleorderline_id in saleorderline_ids:
1237
saleorderline_lnk = saleorderline_obj.browse(cr,uid,saleorderline_id)
1238
weight += (saleorderline_lnk.product_id.product_tmpl_id.weight_net * saleorderline_lnk.product_uom_qty)
1239
vals['weight_net'] = weight
1241
dropoff_type_fedex = 'REGULAR_PICKUP'
1242
service_type_fedex = 'FEDEX_GROUND'
1243
packaging_type_fedex = 'YOUR_PACKAGING'
1244
package_detail_fedex = 'INDIVIDUAL_PACKAGES'
1245
payment_type_fedex = 'SENDER'
1246
physical_packaging_fedex = 'BOX'
1247
vals['dropoff_type_fedex'] = dropoff_type_fedex
1248
vals['service_type_fedex'] = service_type_fedex
1249
vals['packaging_type_fedex'] = packaging_type_fedex
1250
vals['package_detail_fedex'] = package_detail_fedex
1251
vals['payment_type_fedex'] = payment_type_fedex
1252
vals['physical_packaging_fedex'] = physical_packaging_fedex
1254
pickup_type_ups = '01'
1255
service_type_ups = '03'
1256
packaging_type_ups = '02'
1257
vals['pickup_type_ups'] = pickup_type_ups
1258
vals['service_type_ups'] = service_type_ups
1259
vals['packaging_type_ups'] = packaging_type_ups
1261
carrier_id = saleorder_lnk.carrier_id and saleorder_lnk.carrier_id.id or False
1263
## Find which carrier has been selected :- cust_default
1264
vals['carrier_id'] = carrier_id
1265
cust_default = self._get_cust_default_shipping(cr,uid,carrier_id,context)
1266
carrier_obj = self.pool.get('delivery.carrier')
1267
carrier_lnk = carrier_obj.browse(cr,uid,carrier_id)
1268
if carrier_lnk.is_ups:
1269
service_type_ups = carrier_lnk.service_code or '03'
1270
vals['service_type_ups'] = service_type_ups
1271
elif carrier_lnk.is_fedex:
1272
service_type_fedex = carrier_lnk.service_code or 'FEDEX_GROUND'
1273
vals['service_type_fedex'] = service_type_fedex
1274
elif carrier_lnk.is_usps:
1275
service_type_usps = carrier_lnk.service_code or 'All'
1276
first_class_mail_type_usps = carrier_lnk.first_class_mail_type_usps or 'Parcel'
1277
container_usps = carrier_lnk.container_usps or 'Parcel'
1278
size_usps = carrier_lnk.size_usps or 'REGULAR'
1279
vals['service_type_usps'] = service_type_usps
1280
vals['first_class_mail_type_usps'] = first_class_mail_type_usps
1281
vals['container_usps'] = container_usps
1282
vals['size_usps'] = size_usps
1284
### Sys default applicable only for simple orders
1286
# if len(saleorderline_ids) <= 2:
1288
## We consider the Gross Weight
1290
sys_default = self._get_sys_default_shipping(cr,uid,saleorderline_ids,weight,context)
1291
print "sys_default in create: ",sys_default
1292
# Output: USPS/First Class/Letter/Reqular
1293
# If the customer default is not there, ONLY then it goes for system default
1294
if not (cust_default and cust_default.split("/")[0] == 'USPS') and sys_default and sys_default.split('/')[0] == 'USPS':
1295
vals['service_type_usps'] = sys_default.split('/')[1] or ''
1296
# vals['first_class_mail_type_usps'] = first_class_mail_type_usps
1297
vals['container_usps'] = sys_default.split('/')[2] or ''
1298
vals['size_usps'] = sys_default.split('/')[3] or ''
1300
# if not (cust_default or sys_default):
1301
# if (weight*16) > 14.0:
1302
# vals['service_type_usps'] = 'Priority'
1303
# vals['first_class_mail_type_usps'] = 'Parcel'
1304
# vals['container_usps'] = 'Parcel'
1305
# vals['size_usps'] = 'REGULAR'
1307
# vals['service_type_usps'] = 'First Class'
1308
# vals['first_class_mail_type_usps'] = 'Parcel'
1309
# vals['container_usps'] = 'Parcel'
1310
# vals['size_usps'] = 'REGULAR'
1313
new_id = super(stock_picking, self).create(cr, uid, vals, context)
1314
print "new_id: ",new_id
1315
# error_required = False
1317
context['cust_default'] = cust_default
1318
context['sys_default'] = sys_default
1319
context['error'] = False
1320
res = self.generate_shipping(cr,uid,[new_id],context)
1321
print "shipping response: ",res
1324
except Exception, e:
1325
print "Exception: ",e
1326
new_id = super(stock_picking, self).create(cr, uid, vals, context)
1328
new_id = super(stock_picking, self).create(cr, uid, vals, context)
1329
#print "new_id: ",new_id
1334
def _cal_weight_usps(self, cr, uid, ids, name, args, context=None):
1336
uom_obj = self.pool.get('product.uom')
1337
for picking in self.browse(cr, uid, ids, context=context):
1338
weight_net = picking.weight_net or 0.00
1339
weight_net_usps = weight_net / 2.2
1343
'weight_net_usps': weight_net_usps,
1347
def _get_picking_line(self, cr, uid, ids, context=None):
1349
for line in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
1350
result[line.picking_id.id] = True
1351
return result.keys()
1354
'use_shipping' : fields.boolean('Use Shipping'),
1355
'shipping_type' : fields.selection(_get_shipping_type,'Shipping Type'),
1356
'weight_package' : fields.float('Package Weight', digits_compute= dp.get_precision('Stock Weight'), help="Package weight which comes from weighinig machine in pounds"),
1357
'service_type_usps' : fields.selection(_get_service_type_usps, 'Service Type', size=100),
1358
'first_class_mail_type_usps' : fields.selection(_get_first_class_mail_type_usps, 'First Class Mail Type', size=50),
1359
'container_usps' : fields.selection(_get_container_usps,'Container', size=100),
1360
'size_usps' : fields.selection(_get_size_usps,'Size'),
1361
'width_usps' : fields.float('Width', digits_compute= dp.get_precision('Stock Weight')),
1362
'length_usps' : fields.float('Length', digits_compute= dp.get_precision('Stock Weight')),
1363
'height_usps' : fields.float('Height', digits_compute= dp.get_precision('Stock Weight')),
1364
'girth_usps' : fields.float('Girth', digits_compute= dp.get_precision('Stock Weight')),
1365
#'machinable_usps' : fields.boolean('Machinable', domain=[('service_type_usps', 'in', ('first_class','parcel','all','online')), '|', ('first_class_mail_type_usps', 'in', ('letter','flat'))]),
1366
#'ship_date_usps' : fields.date('Ship Date', help="Date Package Will Be Mailed. Ship date may be today plus 0 to 3 days in advance."),
1367
'dropoff_type_fedex' : fields.selection([
1368
('REGULAR_PICKUP','REGULAR PICKUP'),
1369
('REQUEST_COURIER','REQUEST COURIER'),
1370
('DROP_BOX','DROP BOX'),
1371
('BUSINESS_SERVICE_CENTER','BUSINESS SERVICE CENTER'),
1372
('STATION','STATION'),
1374
'service_type_fedex' : fields.selection([
1375
('EUROPE_FIRST_INTERNATIONAL_PRIORITY','EUROPE_FIRST_INTERNATIONAL_PRIORITY'),
1376
('FEDEX_1_DAY_FREIGHT','FEDEX_1_DAY_FREIGHT'),
1377
('FEDEX_2_DAY','FEDEX_2_DAY'),
1378
('FEDEX_2_DAY_FREIGHT','FEDEX_2_DAY_FREIGHT'),
1379
('FEDEX_3_DAY_FREIGHT','FEDEX_3_DAY_FREIGHT'),
1380
('FEDEX_EXPRESS_SAVER','FEDEX_EXPRESS_SAVER'),
1381
('STANDARD_OVERNIGHT','STANDARD_OVERNIGHT'),
1382
('PRIORITY_OVERNIGHT','PRIORITY_OVERNIGHT'),
1383
('FEDEX_GROUND','FEDEX_GROUND'),
1385
'packaging_type_fedex' : fields.selection([
1386
('FEDEX_BOX','FEDEX BOX'),
1387
('FEDEX_PAK','FEDEX PAK'),
1388
('FEDEX_TUBE','FEDEX_TUBE'),
1389
('YOUR_PACKAGING','YOUR_PACKAGING'),
1390
],'Packaging Type', help="What kind of package this will be shipped in"),
1391
'package_detail_fedex' : fields.selection([
1392
('INDIVIDUAL_PACKAGES','INDIVIDUAL_PACKAGES'),
1393
('PACKAGE_GROUPS','PACKAGE_GROUPS'),
1394
('PACKAGE_SUMMARY','PACKAGE_SUMMARY'),
1395
],'Package Detail'),
1396
'payment_type_fedex' : fields.selection([
1397
('RECIPIENT','RECIPIENT'),
1398
('SENDER','SENDER'),
1399
('THIRD_PARTY','THIRD_PARTY'),
1400
],'Payment Type', help="Who pays for the rate_request?"),
1401
'physical_packaging_fedex' : fields.selection([
1403
('BARREL','BARREL'),
1405
('BUCKET','BUCKET'),
1406
('BUNDLE','BUNDLE'),
1407
('CARTON','CARTON'),
1410
],'Physical Packaging'),
1411
'pickup_type_ups' : fields.selection([
1412
('01','Daily Pickup'),
1413
('03','Customer Counter'),
1414
('06','One Time Pickup'),
1415
('07','On Call Air'),
1416
('11','Suggested Retail Rates'),
1417
('19','Letter Center'),
1418
('20','Air Service Center'),
1420
'service_type_ups' : fields.selection([
1421
('01','Next Day Air'),
1422
('02','Second Day Air'),
1424
('07','Worldwide Express'),
1425
('08','Worldwide Expedited'),
1427
('12','Three-Day Select'),
1428
('13','Next Day Air Saver'),
1429
('14','Next Day Air Early AM'),
1430
('54','Worldwide Express Plus'),
1431
('59','Second Day Air AM'),
1434
'packaging_type_ups' : fields.selection([
1440
('21','Express Box'),
1444
('2a','Small Express Box'),
1445
('2b','Medium Express Box'),
1446
('2c','Large Express Box'),
1447
],'Packaging Type'),
1448
'shipping_label' : fields.binary('Logo'),
1449
'shipping_rate': fields.float('Shipping Rate'),
1450
'response_usps_ids' : fields.one2many('shipping.response','picking_id','Shipping Response')
1454
'use_shipping' : True,
1455
'shipping_type' : 'All',
1456
'service_type_usps' : 'All',
1457
'size_usps' : 'REGULAR',
1458
'dropoff_type_fedex' : 'REGULAR_PICKUP',
1459
'service_type_fedex' : 'FEDEX_GROUND',
1460
'packaging_type_fedex' : 'YOUR_PACKAGING',
1461
'package_detail_fedex' : 'INDIVIDUAL_PACKAGES',
1462
'payment_type_fedex' : 'SENDER',
1463
'physical_packaging_fedex' : 'BOX',
1464
'pickup_type_ups' : '01',
1465
'service_type_ups' : '03',
1466
'packaging_type_ups' : '02'
1471
class stock_move(osv.osv):
1472
_inherit = 'stock.move'
1474
def _cal_move_weight_new(self, cr, uid, ids, name, args, context=None):
1476
uom_obj = self.pool.get('product.uom')
1477
for move in self.browse(cr, uid, ids, context=context):
1478
weight = weight_net = 0.00
1480
converted_qty = move.product_qty
1481
if move.product_uom.id <> move.product_id.uom_id.id:
1482
converted_qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
1484
if move.product_id.weight > 0.00:
1485
weight = (converted_qty * move.product_id.weight)
1487
if move.product_id.weight_net > 0.00:
1488
weight_net = (converted_qty * move.product_id.weight_net)
1492
'weight_net': weight_net,
1497
'weight': fields.function(_cal_move_weight_new, method=True, type='float', string='Weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
1499
'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_qty', 'product_uom'], 20),
1501
'weight_net': fields.function(_cal_move_weight_new, method=True, type='float', string='Net weight', digits_compute= dp.get_precision('Stock Weight'), multi='_cal_move_weight',
1503
'stock.move': (lambda self, cr, uid, ids, c=None: ids, ['product_id', 'product_qty', 'product_uom'], 20),