Subversion Repositories SmartDukaan

Rev

Rev 23446 | Rev 23449 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
412 ashish 1
'''
2
Created on 05-Aug-2010
3
 
4
@author: ashish
5
'''
3133 rajveer 6
from shop2020.clients.CatalogClient import CatalogClient
5944 mandeep.dh 7
from shop2020.clients.InventoryClient import InventoryClient
494 rajveer 8
from shop2020.config.client.ConfigClient import ConfigClient
23218 amit.gupta 9
from shop2020.logistics.service.impl import DataAccessor, EcomExpressService
5944 mandeep.dh 10
from shop2020.logistics.service.impl.Converters import to_t_awbupdate, \
20745 kshitij.so 11
    to_t_provider, to_t_pickup_store, to_t_bluedart_attribute
5944 mandeep.dh 12
from shop2020.logistics.service.impl.DataAccessor import get_empty_AWB, \
13
    get_shipment_info, initialize, get_logistics_estimation, get_provider, \
14
    get_providers, close_session, get_free_awb_count, get_holidays, is_alive, \
15
    get_provider_for_pickup_type, get_pickup_store, get_all_pickup_stores, \
6322 amar.kumar 16
    get_pickup_store_by_hotspot_id, get_destination_code, update_pincode, \
9840 amit.gupta 17
    add_pincode, store_shipment_info, adjust_delivery_time, get_min_advance_amount, \
19413 amit.gupta 18
    add_new_awbs, run_Logistics_Location_Info_Update, \
19
    get_first_delivery_estimate_for_wh_location, \
20
    get_provider_limit_details_for_pincode, get_new_empty_awb, \
20745 kshitij.so 21
    get_logistics_locations, get_costing_and_delivery_estimate_for_pincode, \
22634 amit.gupta 22
    get_bluedart_attributes_for_logistics_txn_id, _DeliveryEstimateObject
9840 amit.gupta 23
from shop2020.logistics.service.impl.DataService import \
24
    ServiceableLocationDetails
19413 amit.gupta 25
from shop2020.thriftpy.logistics.ttypes import ItemText, LogisticsInfo, \
5944 mandeep.dh 26
    LogisticsServiceException, DeliveryType, PickUpType
27
from shop2020.thriftpy.model.v1.catalog.ttypes import status
9840 amit.gupta 28
from shop2020.utils.Utils import to_java_date, to_py_date
29
import collections
494 rajveer 30
import datetime
644 chandransh 31
import math
1687 vikas 32
import sys
23121 amit.gupta 33
from shop2020.utils.caching.SimpleCaching import memoized
9840 amit.gupta 34
#Start:- Added by Manish Sharma for Multiple Pincode Updation on 05-Jul-2013
35
#End:- Added by Manish Sharma for Multiple Pincode Updation on 05-Jul-2013
472 rajveer 36
 
412 ashish 37
class LogisticsServiceHandler:
38
 
3187 rajveer 39
    def __init__(self, dbname='logistics', db_hostname='localhost'):
40
        initialize(dbname, db_hostname)
746 rajveer 41
        try:
42
            config_client = ConfigClient()
5978 rajveer 43
            self.sourceId = int(config_client.get_property("sourceid"))
746 rajveer 44
            self.cutoff_time = int(config_client.get_property('delivery_cutoff_time'))
5843 mandeep.dh 45
            self.cod_cutoff_time = 24 #int(config_client.get_property('delivery_cutoff_time'))
776 rajveer 46
            self.default_pincode = int(config_client.get_property('default_pincode'))
1687 vikas 47
        except Exception as ex:
48
            print "[ERROR] Unexpected config error:", sys.exc_info()[0]
5978 rajveer 49
            self.sourceId = 1
746 rajveer 50
            self.cutoff_time = 15
5843 mandeep.dh 51
            self.cod_cutoff_time = 24
4866 rajveer 52
            self.default_pincode = "110001"
5978 rajveer 53
 
3064 chandransh 54
 
669 chandransh 55
    def getProvider(self, providerId):
675 chandransh 56
        """
57
        Returns a provider for a given provider ID. Throws an exception if none found.
58
 
59
        Parameters:
60
         - providerId
61
        """
796 rajveer 62
        try:
1137 chandransh 63
            provider = get_provider(providerId)
64
            if provider:
65
                return to_t_provider(provider)
66
            else:
67
                raise LogisticsServiceException(101, "No Provider found for the given id")
796 rajveer 68
        finally:
69
            close_session()
70
 
675 chandransh 71
    def getAllProviders(self, ):
72
        """
73
        Returns a list containing all the providers.
74
        """
796 rajveer 75
        try:
76
            return [to_t_provider(provider) for provider in get_providers()]
77
        finally:
78
            close_session()
79
 
23446 amit.gupta 80
    def getLogisticsInfo(self, destination_pincode, itemId, type, pickUp, stateId):
483 rajveer 81
        """
82
        Parameters:
83
         - destination_pincode
716 rajveer 84
         - item_id
3044 chandransh 85
         - type
483 rajveer 86
        """
796 rajveer 87
        try:
23446 amit.gupta 88
            logistics_info = self.get_logistics_estimation_with_type(itemId, destination_pincode, type, pickUp, stateId)
7946 manish.sha 89
            #logistics_info.airway_billno = get_empty_AWB(logistics_info.providerId, type)
796 rajveer 90
            return logistics_info
91
        finally:
92
            close_session()
93
 
20724 kshitij.so 94
    def getEmptyAWB(self, providerId, logisticsTransactionId):
412 ashish 95
        """
96
        Parameters:
97
         - provider_id
5247 rajveer 98
         - type
412 ashish 99
        """
796 rajveer 100
        try:
20724 kshitij.so 101
            return get_empty_AWB(providerId, logisticsTransactionId)
796 rajveer 102
        finally:
103
            close_session()
104
 
6643 rajveer 105
    def getShipmentInfo(self, awbNumber, providerId):
412 ashish 106
        """
107
        Parameters:
6643 rajveer 108
         - awbNumber
766 rajveer 109
         - providerId
412 ashish 110
        """
796 rajveer 111
        try:
6643 rajveer 112
            awb_updates = get_shipment_info(awbNumber, providerId)
796 rajveer 113
            t_updates = []
114
            for update in awb_updates:
115
                t_updates.append(to_t_awbupdate(update))
116
            return t_updates
117
        finally:
118
            close_session()
3044 chandransh 119
 
6643 rajveer 120
    def storeShipmentInfo(self, update):
121
        """
122
        Parameters:
123
         - update
124
        """
125
        try:
126
            store_shipment_info(update)
127
        finally:
128
            close_session()
129
 
130
 
4630 mandeep.dh 131
    def getLogisticsEstimation(self, itemId, destination_pin, type):
472 rajveer 132
        """
133
        Parameters:
134
         - itemId
135
         - destination_pin
4630 mandeep.dh 136
         - type
472 rajveer 137
        """
644 chandransh 138
        try:
23446 amit.gupta 139
            return self.get_logistics_estimation_with_type(itemId, destination_pin, type, -1)
796 rajveer 140
        finally:
141
            close_session()
3044 chandransh 142
 
7256 rajveer 143
 
144
    def getLogisticsEstimationForStore(self, itemId, destination_pin, type):
145
        """
146
        Parameters:
147
         - itemId
148
         - destination_pin
149
         - type
150
        """
151
        try:
152
            todate = datetime.datetime.now()
23446 amit.gupta 153
            logistics_info = self.get_logistics_estimation_with_type(itemId, destination_pin, type, -1)
7273 rajveer 154
            logistics_info.deliveryTime = to_java_date(todate +  datetime.timedelta(days = adjust_delivery_time(todate, logistics_info.deliveryTime)))
155
            logistics_info.shippingTime = to_java_date(todate +  datetime.timedelta(days = adjust_delivery_time(todate, logistics_info.shippingTime)))
7275 rajveer 156
            minAdvanceAmount, logistics_info.codAllowed = get_min_advance_amount(itemId, destination_pin, logistics_info.providerId, logistics_info.codAllowed)
157
            ## Send minadvanceamount in providerId field 
158
            logistics_info.providerId = int(minAdvanceAmount)
7256 rajveer 159
            return logistics_info
160
        finally:
161
            close_session()
162
 
23447 amit.gupta 163
    def get_logistics_estimation_with_type(self, itemId, destination_pin, type, pickUp=PickUpType.COURIER, stateId=-1):
3044 chandransh 164
        try:
5295 rajveer 165
            #Get the id and location of actual warehouse that'll be used to fulfil this order.
5944 mandeep.dh 166
            client = InventoryClient().get_client()
23446 amit.gupta 167
            fulfilmentWarehouseId, expected_delay, billingWarehouseId, sellingPrice, totalAvailability, weight = client.getItemAvailabilityAtLocation(itemId, self.sourceId, stateId)
22724 amit.gupta 168
            #We assume that if totalAvailability 0 then its the case of hotspot billing where itemAvailabilityCache is sort of bypassed
169
            if totalAvailability <= 0:
170
                expected_delay = 0
171
 
3044 chandransh 172
        except Exception as ex:
173
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this item.")
5295 rajveer 174
 
22634 amit.gupta 175
        if pickUp == PickUpType.COURIER:
176
            delivery_estimate = get_logistics_estimation(destination_pin, sellingPrice, weight, type, billingWarehouseId)
177
        else:
22637 amit.gupta 178
            delivery_estimate = _DeliveryEstimateObject(0, 0, get_provider_for_pickup_type(pickUp), False, False)
3218 rajveer 179
        if delivery_estimate is None:
3044 chandransh 180
            raise LogisticsServiceException(104, "Unable to fetch delivery estimate for this pincode.")
5295 rajveer 181
 
3044 chandransh 182
 
5270 rajveer 183
        ## Commented below part as we have only Delhi as warehouse city. If we will add some more warehouses in different cities, this could be  useful. 
4009 chandransh 184
        # We are revising the estimates based on the actual warehouse that this order will be assigned to.
185
        # This warehouse may be located in a zone which is different from the one we allocated for this pincode.
5270 rajveer 186
        #delivery_estimate = get_logistics_estimation(destination_pin, item.sellingPrice, warehouse_loc, type)
187
        #if delivery_estimate is None:
188
        #    raise LogisticsServiceException(105, "Unable to fetch delivery estimate for pincode: " + destination_pin + " and revised location: " + str(warehouse_loc))
3044 chandransh 189
 
6537 rajveer 190
        delivery_time = 24 * (delivery_estimate.delivery_time + delivery_estimate.delivery_delay)
3044 chandransh 191
 
4009 chandransh 192
        '''
193
        We're now calculating the expected shipping delay which is independent of
194
        the courier agency and is completely within our control (well, almost).
195
        '''
3355 chandransh 196
        #Always add the expected delay
23183 amit.gupta 197
        #this is due to virtual inventory
4009 chandransh 198
        shipping_delay = 24 * expected_delay
3355 chandransh 199
 
4829 rajveer 200
        # Sometimes we set negative shipping delay just in case we know time to procure will be less than the default.
201
        # If we have received inventory and forgot to remove expected delay from item, it could lead to display negative shipping days. 
202
        if shipping_delay < 0:
203
            shipping_delay = 0
204
 
3044 chandransh 205
        #Further increase the estimate if it's late in the day
3064 chandransh 206
        current_hour = datetime.datetime.now().hour
207
        if type == DeliveryType.PREPAID and self.cutoff_time <= current_hour:
4009 chandransh 208
            shipping_delay = shipping_delay + 24
3044 chandransh 209
 
4426 rajveer 210
        #In case of COD,increase delay by one more day
22634 amit.gupta 211
        #As per deenanath why are doing this?
4426 rajveer 212
        if type == DeliveryType.COD:
213
            shipping_delay = shipping_delay + 24
6524 rajveer 214
            delivery_estimate.otgAvailable = False
4426 rajveer 215
 
4010 chandransh 216
        delivery_time = delivery_time + shipping_delay
217
 
4009 chandransh 218
        shipping_delay = int(math.ceil(shipping_delay/24.0))
4010 chandransh 219
        delivery_time = int(math.ceil(delivery_time/24.0))
3044 chandransh 220
 
221
        logistics_info = LogisticsInfo()
222
        logistics_info.deliveryTime = delivery_time
3218 rajveer 223
        logistics_info.providerId = delivery_estimate.provider_id
5110 mandeep.dh 224
        logistics_info.warehouseId = billingWarehouseId
225
        logistics_info.fulfilmentWarehouseId = fulfilmentWarehouseId
4009 chandransh 226
        logistics_info.shippingTime = shipping_delay
4870 rajveer 227
        logistics_info.codAllowed = delivery_estimate.codAllowed 
6524 rajveer 228
        logistics_info.otgAvailable = delivery_estimate.otgAvailable
6726 rajveer 229
        logistics_info.deliveryDelay = delivery_estimate.delivery_delay
3044 chandransh 230
 
5595 anupam.sin 231
        try:
232
            return logistics_info
233
        finally:
234
            close_session()
3044 chandransh 235
 
731 chandransh 236
    def getDestinationCode(self, providerId, pinCode):
237
        """
238
        Returns the short three letter code of a pincode for the given provider.
239
        Raises an exception if the pin code is not serviced by the given provider.
240
 
241
        Parameters:
242
         - providerId
243
         - pinCode
244
        """
796 rajveer 245
        try:
3217 rajveer 246
            try:
3218 rajveer 247
                dest_code = DataAccessor.serviceable_location_cache[providerId][pinCode][0]
3217 rajveer 248
                return dest_code
249
            except:
6017 amar.kumar 250
                try:
251
                    dest_code = get_destination_code(providerId, pinCode) 
252
                    return dest_code
253
                except:
8182 amar.kumar 254
                    if providerId >7:
255
                        return ""
6017 amar.kumar 256
                    raise LogisticsServiceException(101, "The pincode " + pinCode + " is not serviced by this provider: " + str(providerId))
796 rajveer 257
        finally:
258
            close_session()
1137 chandransh 259
 
3103 chandransh 260
    def getFreeAwbCount(self, providerId, type):
1137 chandransh 261
        """
3103 chandransh 262
        Returns the number of unused AWB numbers for the given provider of the given type
796 rajveer 263
 
1137 chandransh 264
        Parameters:
265
         - providerId
3103 chandransh 266
         - type
1137 chandransh 267
        """
268
        try:
3103 chandransh 269
            return get_free_awb_count(providerId, type)
1137 chandransh 270
        finally:
271
            close_session()
1730 ankur.sing 272
 
273
    def getHolidays(self, fromDate, toDate):
274
        """
275
        Returns list of Holiday dates between fromDate and toDate (both inclusive)
276
        fromDate should be passed as milliseconds corresponding to the start of the day.
277
        If fromDate is passed as -1, fromDate is not considered for filtering
278
        If toDate is passed as -1, toDate is not considered for filtering
1137 chandransh 279
 
1730 ankur.sing 280
        Parameters:
281
         - fromDate
282
         - toDate
283
        """
284
        try:
285
            return get_holidays(fromDate, toDate)
286
        finally:
287
            close_session()
5527 anupam.sin 288
 
289
    def getProviderForPickupType(self, pickUp):
290
        try:
291
            return get_provider_for_pickup_type(pickUp)
292
        finally:
293
            close_session()
3064 chandransh 294
 
766 rajveer 295
    def closeSession(self, ):
296
        close_session()
3376 rajveer 297
 
298
    def isAlive(self, ):
299
        """
300
        For checking weather service is active alive or not. It also checks connectivity with database
301
        """
302
        try:
303
            return is_alive()
304
        finally:
305
            close_session()
4934 amit.gupta 306
 
307
    def getEntityLogisticsEstimation(self, catalogItemId, destination_pin, type):
308
        """
309
        Returns a LogisticsInfo structure w/o an airway bill number. Use this method during the estimation phase.
310
        Raises an exception if this pincode is not allocated to any warehouse zone or provider. Also, if the pincode
311
        is allocated to a warehouse zone but there are no actual warehouses in that zone, an exception is raised.
312
 
313
        Parameters:
314
         - catalogItemId
315
         - destination_pin
316
         - type
317
        """
318
        try:
319
            return self.get_entity_logistics_estimation_with_type(catalogItemId, destination_pin, type)
320
        finally:
321
            close_session()
322
 
323
    def get_entity_logistics_estimation_with_type(self, catalog_item_id, destination_pin, type):
324
        try:
325
            client = CatalogClient().get_client()
326
            items = client.getValidItemsByCatalogId(catalog_item_id)
327
        except Exception as ex:
328
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this entity.")
329
 
330
        estimateList = []
331
 
332
        for item in items:
11254 amit.gupta 333
            try:
23446 amit.gupta 334
                estimationInfo = self.get_logistics_estimation_with_type(item.id, destination_pin, type, -1)
11254 amit.gupta 335
            except Exception as ex:
336
                estimationInfo = LogisticsInfo()
337
                estimationInfo.deliveryTime = 0
4934 amit.gupta 338
            if item.itemStatus == status.ACTIVE:
9840 amit.gupta 339
                estimateList.append((0, estimationInfo.deliveryTime, "BUY NOW", item.id))
4934 amit.gupta 340
            elif item.itemStatus == status.PAUSED:
9840 amit.gupta 341
                estimateList.append((1, estimationInfo.deliveryTime, "NOTIFY ME", item.id))
4934 amit.gupta 342
            elif item.itemStatus == status.PAUSED_BY_RISK:
9840 amit.gupta 343
                estimateList.append((2, estimationInfo.deliveryTime, "NOTIFY ME", item.id))
6074 amit.gupta 344
            elif item.itemStatus == status.COMING_SOON:
10688 amit.gupta 345
                estimateList.append((3, estimationInfo.deliveryTime, "NOTIFY ME", item.id))
4934 amit.gupta 346
 
347
        estimateList.sort()
5595 anupam.sin 348
        try:
9840 amit.gupta 349
            return [ ItemText(estimate[-1], estimate[-2]) for estimate in estimateList]
5595 anupam.sin 350
        finally:
351
            close_session()
5555 rajveer 352
 
5595 anupam.sin 353
    def getAllPickupStores(self):
354
        try:
355
            return [to_t_pickup_store(pickup_store) for pickup_store in get_all_pickup_stores()]
356
        finally:
357
            close_session()
5555 rajveer 358
 
359
    def getPickupStore(self, storeId):
360
        """
361
        Parameters:
362
         - storeId
363
        """
5595 anupam.sin 364
        try:
365
            storeToReturn = to_t_pickup_store(get_pickup_store(storeId))
366
            return storeToReturn
367
        finally:
5719 rajveer 368
            close_session()
369
 
370
    def getPickupStoreByHotspotId(self, hotspotId):
371
        """
372
        Parameters:
373
         - hotspotId
374
        """
375
        try:
376
            storeToReturn = to_t_pickup_store(get_pickup_store_by_hotspot_id(hotspotId))
377
            return storeToReturn
378
        finally:
6322 amar.kumar 379
            close_session()
6524 rajveer 380
    def addPincode(self, providerId, pincode, destCode, exp, cod, stationType, otgAvailable):
6322 amar.kumar 381
        try:
6524 rajveer 382
            add_pincode(providerId, pincode, destCode, exp, cod, stationType, otgAvailable)
6322 amar.kumar 383
        finally:
384
            close_session()
6524 rajveer 385
    def updatePincode(self, providerId, pincode, exp, cod, otgAvailable):
6322 amar.kumar 386
        try:
6524 rajveer 387
            update_pincode(providerId, pincode, exp, cod, otgAvailable)
6322 amar.kumar 388
        finally:
7567 rajveer 389
            close_session()
390
 
13146 manish.sha 391
    def addNewAwbs(self, providerId, isCod, awbs, awbUsedFor):
7567 rajveer 392
        try:
13146 manish.sha 393
            return add_new_awbs(providerId, isCod, awbs, awbUsedFor)
7567 rajveer 394
        finally:
7733 manish.sha 395
            close_session()
7786 manish.sha 396
 
397
 
23121 amit.gupta 398
    def runLogisticsLocationInfoUpdate(self, logisticsLocationInfoList, runCompleteUpdate, providerId):
7733 manish.sha 399
        try:
23121 amit.gupta 400
            run_Logistics_Location_Info_Update(logisticsLocationInfoList, runCompleteUpdate, providerId)
7733 manish.sha 401
        finally:
402
            close_session()
7888 rajveer 403
 
404
    def adjustDeliveryDays(self, startDate, days):
405
        try:
406
            return adjust_delivery_time(to_py_date(startDate), days)
407
        finally:
12895 manish.sha 408
            close_session()
409
 
410
    def getFirstDeliveryEstimateForWhLocation(self, pincode, whLocation):
411
        try:
412
            return get_first_delivery_estimate_for_wh_location(pincode, whLocation)
413
        finally:
13146 manish.sha 414
            close_session()
415
 
416
    def getProviderLimitDetailsForPincode(self, providerId, pincode):
417
        try:
418
            return get_provider_limit_details_for_pincode(providerId, pincode)
419
        finally:
420
            close_session()
421
 
422
    def getNewEmptyAwb(self, providerId, type, orderQuantity):
423
        try:
424
            return get_new_empty_awb(providerId, type, orderQuantity)
425
        finally:
426
            close_session()
19421 manish.sha 427
 
19413 amit.gupta 428
    def getLocationInfoMap(self, destinationPin, sellingPriceList):
429
        try:
430
            return get_logistics_locations(destinationPin, sellingPriceList)
431
        finally:
19421 manish.sha 432
            close_session()
433
 
19474 manish.sha 434
    def getCostingAndDeliveryEstimateForPincode(self, pincode, transactionAmount, isCod, weight, billingWarehouseId, isCompleteTxn):
19421 manish.sha 435
        try:
19474 manish.sha 436
            costingAndDeliveryEstimateObj = get_costing_and_delivery_estimate_for_pincode(pincode, transactionAmount, isCod, weight, billingWarehouseId, isCompleteTxn)
19421 manish.sha 437
            delivery_time = 24 * (costingAndDeliveryEstimateObj.deliveryTime + costingAndDeliveryEstimateObj.delivery_delay)
438
            shipping_delay = 0
439
 
440
            #Further increase the estimate if it's late in the day
441
            current_hour = datetime.datetime.now().hour
442
            if not isCod and self.cutoff_time <= current_hour:
443
                shipping_delay = shipping_delay + 24
444
 
445
            #In case of COD,increase delay by one more day
446
            if isCod:
447
                shipping_delay = shipping_delay + 24
448
                costingAndDeliveryEstimateObj.otgAvailable = False
449
 
450
            delivery_time = delivery_time + shipping_delay
451
 
452
            shipping_delay = int(math.ceil(shipping_delay/24.0))
453
            delivery_time = int(math.ceil(delivery_time/24.0))
454
 
455
            costingAndDeliveryEstimateObj.deliveryTime = delivery_time
456
            costingAndDeliveryEstimateObj.shippingTime = shipping_delay
457
            return costingAndDeliveryEstimateObj
458
        finally:
459
            close_session()
20745 kshitij.so 460
 
461
    def getBluedartAttributesForLogisticsTxnId(self, logisticsTxnId, name):
462
        try:
463
            return to_t_bluedart_attribute(get_bluedart_attributes_for_logistics_txn_id(logisticsTxnId, name))
464
        finally:
23218 amit.gupta 465
            close_session()
466
 
467
 
468
    def pushCourierDetailsForEcomExpress(self, logisticsTransactionIds):
469
        try:
470
            for logisticsTransactionId in logisticsTransactionIds:
471
                EcomExpressService.forward_request(logisticsTransactionId)
472
            return True
473
        finally:
474
            close_session()
475
 
476
        return False