Subversion Repositories SmartDukaan

Rev

Rev 7256 | Rev 7275 | 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
5944 mandeep.dh 9
from shop2020.logistics.service.impl import DataAccessor
10
from shop2020.logistics.service.impl.Converters import to_t_awbupdate, \
11
    to_t_provider, to_t_pickup_store
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, \
7256 rajveer 17
    add_pincode, store_shipment_info, adjust_delivery_time
5944 mandeep.dh 18
from shop2020.thriftpy.logistics.ttypes import LogisticsInfo, \
19
    LogisticsServiceException, DeliveryType, PickUpType
20
from shop2020.thriftpy.model.v1.catalog.ttypes import status
494 rajveer 21
import datetime
644 chandransh 22
import math
1687 vikas 23
import sys
6322 amar.kumar 24
from shop2020.logistics.service.impl.DataService import ServiceableLocationDetails
7273 rajveer 25
from shop2020.utils.Utils import to_java_date
472 rajveer 26
 
412 ashish 27
class LogisticsServiceHandler:
28
 
3187 rajveer 29
    def __init__(self, dbname='logistics', db_hostname='localhost'):
30
        initialize(dbname, db_hostname)
746 rajveer 31
        try:
32
            config_client = ConfigClient()
5978 rajveer 33
            self.sourceId = int(config_client.get_property("sourceid"))
746 rajveer 34
            self.cutoff_time = int(config_client.get_property('delivery_cutoff_time'))
5843 mandeep.dh 35
            self.cod_cutoff_time = 24 #int(config_client.get_property('delivery_cutoff_time'))
776 rajveer 36
            self.default_pincode = int(config_client.get_property('default_pincode'))
1687 vikas 37
        except Exception as ex:
38
            print "[ERROR] Unexpected config error:", sys.exc_info()[0]
5978 rajveer 39
            self.sourceId = 1
746 rajveer 40
            self.cutoff_time = 15
5843 mandeep.dh 41
            self.cod_cutoff_time = 24
4866 rajveer 42
            self.default_pincode = "110001"
5978 rajveer 43
 
3064 chandransh 44
 
669 chandransh 45
    def getProvider(self, providerId):
675 chandransh 46
        """
47
        Returns a provider for a given provider ID. Throws an exception if none found.
48
 
49
        Parameters:
50
         - providerId
51
        """
796 rajveer 52
        try:
1137 chandransh 53
            provider = get_provider(providerId)
54
            if provider:
55
                return to_t_provider(provider)
56
            else:
57
                raise LogisticsServiceException(101, "No Provider found for the given id")
796 rajveer 58
        finally:
59
            close_session()
60
 
675 chandransh 61
    def getAllProviders(self, ):
62
        """
63
        Returns a list containing all the providers.
64
        """
796 rajveer 65
        try:
66
            return [to_t_provider(provider) for provider in get_providers()]
67
        finally:
68
            close_session()
69
 
5767 rajveer 70
    def getLogisticsInfo(self, destination_pincode, itemId, type, pickUp):
483 rajveer 71
        """
72
        Parameters:
73
         - destination_pincode
716 rajveer 74
         - item_id
3044 chandransh 75
         - type
483 rajveer 76
        """
796 rajveer 77
        try:
3044 chandransh 78
            logistics_info = self.get_logistics_estimation_with_type(itemId, destination_pincode, type)
5767 rajveer 79
            if pickUp == PickUpType.RUNNER or pickUp == PickUpType.SELF:
80
                logistics_info.providerId = get_provider_for_pickup_type(pickUp)
3044 chandransh 81
            logistics_info.airway_billno = get_empty_AWB(logistics_info.providerId, type)
796 rajveer 82
            return logistics_info
83
        finally:
84
            close_session()
85
 
5247 rajveer 86
    def getEmptyAWB(self, providerId, type):
412 ashish 87
        """
88
        Parameters:
89
         - provider_id
5247 rajveer 90
         - type
412 ashish 91
        """
796 rajveer 92
        try:
5247 rajveer 93
            return get_empty_AWB(providerId, type)
796 rajveer 94
        finally:
95
            close_session()
96
 
6643 rajveer 97
    def getShipmentInfo(self, awbNumber, providerId):
412 ashish 98
        """
99
        Parameters:
6643 rajveer 100
         - awbNumber
766 rajveer 101
         - providerId
412 ashish 102
        """
796 rajveer 103
        try:
6643 rajveer 104
            awb_updates = get_shipment_info(awbNumber, providerId)
796 rajveer 105
            t_updates = []
106
            for update in awb_updates:
107
                t_updates.append(to_t_awbupdate(update))
108
            return t_updates
109
        finally:
110
            close_session()
3044 chandransh 111
 
6643 rajveer 112
    def storeShipmentInfo(self, update):
113
        """
114
        Parameters:
115
         - update
116
        """
117
        try:
118
            store_shipment_info(update)
119
        finally:
120
            close_session()
121
 
122
 
4630 mandeep.dh 123
    def getLogisticsEstimation(self, itemId, destination_pin, type):
472 rajveer 124
        """
125
        Parameters:
126
         - itemId
127
         - destination_pin
4630 mandeep.dh 128
         - type
472 rajveer 129
        """
644 chandransh 130
        try:
4630 mandeep.dh 131
            return self.get_logistics_estimation_with_type(itemId, destination_pin, type)
796 rajveer 132
        finally:
133
            close_session()
3044 chandransh 134
 
7256 rajveer 135
 
136
    def getLogisticsEstimationForStore(self, itemId, destination_pin, type):
137
        """
138
        Parameters:
139
         - itemId
140
         - destination_pin
141
         - type
142
        """
143
        try:
144
            todate = datetime.datetime.now()
145
            logistics_info = self.get_logistics_estimation_with_type(itemId, destination_pin, type)
7273 rajveer 146
            logistics_info.deliveryTime = to_java_date(todate +  datetime.timedelta(days = adjust_delivery_time(todate, logistics_info.deliveryTime)))
147
            logistics_info.shippingTime = to_java_date(todate +  datetime.timedelta(days = adjust_delivery_time(todate, logistics_info.shippingTime)))
7256 rajveer 148
            return logistics_info
149
        finally:
150
            close_session()
151
 
4630 mandeep.dh 152
    def get_logistics_estimation_with_type(self, itemId, destination_pin, type):
3044 chandransh 153
        try:
5295 rajveer 154
            #Get the id and location of actual warehouse that'll be used to fulfil this order.
5944 mandeep.dh 155
            client = InventoryClient().get_client()
5983 rajveer 156
            fulfilmentWarehouseId, expected_delay, billingWarehouseId, sellingPrice, totalAvailability = client.getItemAvailabilityAtLocation(itemId, self.sourceId)
3044 chandransh 157
        except Exception as ex:
158
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this item.")
5295 rajveer 159
 
6524 rajveer 160
        delivery_estimate = get_logistics_estimation(destination_pin, sellingPrice)
3218 rajveer 161
        if delivery_estimate is None:
3044 chandransh 162
            raise LogisticsServiceException(104, "Unable to fetch delivery estimate for this pincode.")
5295 rajveer 163
 
3044 chandransh 164
 
5270 rajveer 165
        ## 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 166
        # We are revising the estimates based on the actual warehouse that this order will be assigned to.
167
        # This warehouse may be located in a zone which is different from the one we allocated for this pincode.
5270 rajveer 168
        #delivery_estimate = get_logistics_estimation(destination_pin, item.sellingPrice, warehouse_loc, type)
169
        #if delivery_estimate is None:
170
        #    raise LogisticsServiceException(105, "Unable to fetch delivery estimate for pincode: " + destination_pin + " and revised location: " + str(warehouse_loc))
3044 chandransh 171
 
6537 rajveer 172
        delivery_time = 24 * (delivery_estimate.delivery_time + delivery_estimate.delivery_delay)
3044 chandransh 173
 
4009 chandransh 174
        '''
175
        We're now calculating the expected shipping delay which is independent of
176
        the courier agency and is completely within our control (well, almost).
177
        '''
3355 chandransh 178
        #Always add the expected delay
4009 chandransh 179
        shipping_delay = 24 * expected_delay
3355 chandransh 180
 
4829 rajveer 181
        # Sometimes we set negative shipping delay just in case we know time to procure will be less than the default.
182
        # If we have received inventory and forgot to remove expected delay from item, it could lead to display negative shipping days. 
183
        if shipping_delay < 0:
184
            shipping_delay = 0
185
 
3044 chandransh 186
        #Further increase the estimate if it's late in the day
3064 chandransh 187
        current_hour = datetime.datetime.now().hour
188
        if type == DeliveryType.PREPAID and self.cutoff_time <= current_hour:
4009 chandransh 189
            shipping_delay = shipping_delay + 24
3044 chandransh 190
 
4426 rajveer 191
        #In case of COD,increase delay by one more day
192
        if type == DeliveryType.COD:
193
            shipping_delay = shipping_delay + 24
6524 rajveer 194
            delivery_estimate.otgAvailable = False
4426 rajveer 195
 
4010 chandransh 196
        delivery_time = delivery_time + shipping_delay
197
 
4009 chandransh 198
        shipping_delay = int(math.ceil(shipping_delay/24.0))
4010 chandransh 199
        delivery_time = int(math.ceil(delivery_time/24.0))
3044 chandransh 200
 
7187 rajveer 201
        if itemId in (7943,8195):
6987 rajveer 202
            delivery_estimate.codAllowed = False
3044 chandransh 203
        logistics_info = LogisticsInfo()
204
        logistics_info.deliveryTime = delivery_time
3218 rajveer 205
        logistics_info.providerId = delivery_estimate.provider_id
5110 mandeep.dh 206
        logistics_info.warehouseId = billingWarehouseId
207
        logistics_info.fulfilmentWarehouseId = fulfilmentWarehouseId
4009 chandransh 208
        logistics_info.shippingTime = shipping_delay
4870 rajveer 209
        logistics_info.codAllowed = delivery_estimate.codAllowed 
6524 rajveer 210
        logistics_info.otgAvailable = delivery_estimate.otgAvailable
6726 rajveer 211
        logistics_info.deliveryDelay = delivery_estimate.delivery_delay
3044 chandransh 212
 
5595 anupam.sin 213
        try:
214
            return logistics_info
215
        finally:
216
            close_session()
3044 chandransh 217
 
731 chandransh 218
    def getDestinationCode(self, providerId, pinCode):
219
        """
220
        Returns the short three letter code of a pincode for the given provider.
221
        Raises an exception if the pin code is not serviced by the given provider.
222
 
223
        Parameters:
224
         - providerId
225
         - pinCode
226
        """
796 rajveer 227
        try:
3217 rajveer 228
            try:
3218 rajveer 229
                dest_code = DataAccessor.serviceable_location_cache[providerId][pinCode][0]
3217 rajveer 230
                return dest_code
231
            except:
6017 amar.kumar 232
                try:
233
                    dest_code = get_destination_code(providerId, pinCode) 
234
                    return dest_code
235
                except:
236
                    raise LogisticsServiceException(101, "The pincode " + pinCode + " is not serviced by this provider: " + str(providerId))
796 rajveer 237
        finally:
238
            close_session()
1137 chandransh 239
 
3103 chandransh 240
    def getFreeAwbCount(self, providerId, type):
1137 chandransh 241
        """
3103 chandransh 242
        Returns the number of unused AWB numbers for the given provider of the given type
796 rajveer 243
 
1137 chandransh 244
        Parameters:
245
         - providerId
3103 chandransh 246
         - type
1137 chandransh 247
        """
248
        try:
3103 chandransh 249
            return get_free_awb_count(providerId, type)
1137 chandransh 250
        finally:
251
            close_session()
1730 ankur.sing 252
 
253
    def getHolidays(self, fromDate, toDate):
254
        """
255
        Returns list of Holiday dates between fromDate and toDate (both inclusive)
256
        fromDate should be passed as milliseconds corresponding to the start of the day.
257
        If fromDate is passed as -1, fromDate is not considered for filtering
258
        If toDate is passed as -1, toDate is not considered for filtering
1137 chandransh 259
 
1730 ankur.sing 260
        Parameters:
261
         - fromDate
262
         - toDate
263
        """
264
        try:
265
            return get_holidays(fromDate, toDate)
266
        finally:
267
            close_session()
5527 anupam.sin 268
 
269
    def getProviderForPickupType(self, pickUp):
270
        try:
271
            return get_provider_for_pickup_type(pickUp)
272
        finally:
273
            close_session()
3064 chandransh 274
 
766 rajveer 275
    def closeSession(self, ):
276
        close_session()
3376 rajveer 277
 
278
    def isAlive(self, ):
279
        """
280
        For checking weather service is active alive or not. It also checks connectivity with database
281
        """
282
        try:
283
            return is_alive()
284
        finally:
285
            close_session()
4934 amit.gupta 286
 
287
    def getEntityLogisticsEstimation(self, catalogItemId, destination_pin, type):
288
        """
289
        Returns a LogisticsInfo structure w/o an airway bill number. Use this method during the estimation phase.
290
        Raises an exception if this pincode is not allocated to any warehouse zone or provider. Also, if the pincode
291
        is allocated to a warehouse zone but there are no actual warehouses in that zone, an exception is raised.
292
 
293
        Parameters:
294
         - catalogItemId
295
         - destination_pin
296
         - type
297
        """
298
        try:
299
            return self.get_entity_logistics_estimation_with_type(catalogItemId, destination_pin, type)
300
        finally:
301
            close_session()
302
 
303
    def get_entity_logistics_estimation_with_type(self, catalog_item_id, destination_pin, type):
304
        try:
305
            client = CatalogClient().get_client()
306
            items = client.getValidItemsByCatalogId(catalog_item_id)
307
        except Exception as ex:
308
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this entity.")
309
 
310
        estimateList = []
311
 
312
        for item in items:
313
            estimationInfo = self.get_logistics_estimation_with_type(item.id, destination_pin, type)
314
            if item.itemStatus == status.ACTIVE:
315
                estimateList.append((0, estimationInfo.deliveryTime, item.id))
316
            elif item.itemStatus == status.PAUSED:
317
                estimateList.append((1, estimationInfo.deliveryTime, item.id))
318
            elif item.itemStatus == status.PAUSED_BY_RISK:
319
                estimateList.append((2, estimationInfo.deliveryTime, item.id))
6074 amit.gupta 320
            elif item.itemStatus == status.COMING_SOON:
321
                estimateList.append((3, estimationInfo.deliveryTime, item.id))
4934 amit.gupta 322
 
323
        estimateList.sort()
5595 anupam.sin 324
        try:
325
            return [estimate[-1] for estimate in estimateList]
326
        finally:
327
            close_session()
5555 rajveer 328
 
5595 anupam.sin 329
    def getAllPickupStores(self):
330
        try:
331
            return [to_t_pickup_store(pickup_store) for pickup_store in get_all_pickup_stores()]
332
        finally:
333
            close_session()
5555 rajveer 334
 
335
    def getPickupStore(self, storeId):
336
        """
337
        Parameters:
338
         - storeId
339
        """
5595 anupam.sin 340
        try:
341
            storeToReturn = to_t_pickup_store(get_pickup_store(storeId))
342
            return storeToReturn
343
        finally:
5719 rajveer 344
            close_session()
345
 
346
    def getPickupStoreByHotspotId(self, hotspotId):
347
        """
348
        Parameters:
349
         - hotspotId
350
        """
351
        try:
352
            storeToReturn = to_t_pickup_store(get_pickup_store_by_hotspot_id(hotspotId))
353
            return storeToReturn
354
        finally:
6322 amar.kumar 355
            close_session()
6524 rajveer 356
    def addPincode(self, providerId, pincode, destCode, exp, cod, stationType, otgAvailable):
6322 amar.kumar 357
        try:
6524 rajveer 358
            add_pincode(providerId, pincode, destCode, exp, cod, stationType, otgAvailable)
6322 amar.kumar 359
        finally:
360
            close_session()
6524 rajveer 361
    def updatePincode(self, providerId, pincode, exp, cod, otgAvailable):
6322 amar.kumar 362
        try:
6524 rajveer 363
            update_pincode(providerId, pincode, exp, cod, otgAvailable)
6322 amar.kumar 364
        finally:
5595 anupam.sin 365
            close_session()