Subversion Repositories SmartDukaan

Rev

Rev 4870 | Rev 4979 | 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
'''
644 chandransh 6
from shop2020.thriftpy.logistics.ttypes import LogisticsInfo,\
3044 chandransh 7
    LogisticsServiceException, DeliveryType
644 chandransh 8
from shop2020.logistics.service.impl.DataAccessor import get_empty_AWB,\
675 chandransh 9
    get_shipment_info, initialize, get_logistics_estimation, get_provider,\
3064 chandransh 10
    get_providers, close_session, get_free_awb_count, get_holidays,\
4866 rajveer 11
    is_alive
669 chandransh 12
from shop2020.logistics.service.impl.Converters import to_t_awbupdate,\
4410 rajveer 13
    to_t_provider
3133 rajveer 14
from shop2020.clients.CatalogClient import CatalogClient
494 rajveer 15
from shop2020.config.client.ConfigClient import ConfigClient
16
import datetime
644 chandransh 17
import math
1687 vikas 18
import sys
3217 rajveer 19
from shop2020.logistics.service.impl import DataAccessor
4934 amit.gupta 20
from shop2020.thriftpy.model.v1.catalog.ttypes import status
472 rajveer 21
 
412 ashish 22
class LogisticsServiceHandler:
23
 
3187 rajveer 24
    def __init__(self, dbname='logistics', db_hostname='localhost'):
25
        initialize(dbname, db_hostname)
746 rajveer 26
        try:
27
            config_client = ConfigClient()
28
            self.cutoff_time = int(config_client.get_property('delivery_cutoff_time'))
3064 chandransh 29
            self.cod_cutoff_time = 0 #int(config_client.get_property('delivery_cutoff_time'))
746 rajveer 30
            self.stock_threshold = int(config_client.get_property('inventory_stock_threshold'))
3064 chandransh 31
            self.time_to_procure = int(config_client.get_property('inventory_time_to_procure'))
776 rajveer 32
            self.default_pincode = int(config_client.get_property('default_pincode'))
1687 vikas 33
        except Exception as ex:
34
            print "[ERROR] Unexpected config error:", sys.exc_info()[0]
746 rajveer 35
            self.cutoff_time = 15
3064 chandransh 36
            self.cod_cutoff_time = 0
746 rajveer 37
            self.stock_threshold = 2
3064 chandransh 38
            self.time_to_procure = 48
4866 rajveer 39
            self.default_pincode = "110001"
3064 chandransh 40
 
669 chandransh 41
    def getProvider(self, providerId):
675 chandransh 42
        """
43
        Returns a provider for a given provider ID. Throws an exception if none found.
44
 
45
        Parameters:
46
         - providerId
47
        """
796 rajveer 48
        try:
1137 chandransh 49
            provider = get_provider(providerId)
50
            if provider:
51
                return to_t_provider(provider)
52
            else:
53
                raise LogisticsServiceException(101, "No Provider found for the given id")
796 rajveer 54
        finally:
55
            close_session()
56
 
675 chandransh 57
    def getAllProviders(self, ):
58
        """
59
        Returns a list containing all the providers.
60
        """
796 rajveer 61
        try:
62
            return [to_t_provider(provider) for provider in get_providers()]
63
        finally:
64
            close_session()
65
 
3044 chandransh 66
    def getLogisticsInfo(self, destination_pincode, itemId, type):
483 rajveer 67
        """
68
        Parameters:
69
         - destination_pincode
716 rajveer 70
         - item_id
3044 chandransh 71
         - type
483 rajveer 72
        """
796 rajveer 73
        try:
3044 chandransh 74
            logistics_info = self.get_logistics_estimation_with_type(itemId, destination_pincode, type)
75
            logistics_info.airway_billno = get_empty_AWB(logistics_info.providerId, type)
796 rajveer 76
            return logistics_info
77
        finally:
78
            close_session()
79
 
412 ashish 80
    def getEmptyAWB(self, provider_id):
81
        """
82
        Parameters:
83
         - provider_id
84
        """
796 rajveer 85
        try:
86
            return get_empty_AWB(provider_id)
87
        finally:
88
            close_session()
89
 
644 chandransh 90
    def getShipmentInfo(self, awb, providerId):
412 ashish 91
        """
92
        Parameters:
93
         - awb
766 rajveer 94
         - providerId
412 ashish 95
        """
796 rajveer 96
        try:
97
            awb_updates = get_shipment_info(awb, providerId)
98
            t_updates = []
99
            for update in awb_updates:
100
                t_updates.append(to_t_awbupdate(update))
101
            return t_updates
102
        finally:
103
            close_session()
3044 chandransh 104
 
4630 mandeep.dh 105
    def getLogisticsEstimation(self, itemId, destination_pin, type):
472 rajveer 106
        """
107
        Parameters:
108
         - itemId
109
         - destination_pin
4630 mandeep.dh 110
         - type
472 rajveer 111
        """
644 chandransh 112
        try:
4630 mandeep.dh 113
            return self.get_logistics_estimation_with_type(itemId, destination_pin, type)
796 rajveer 114
        finally:
115
            close_session()
3044 chandransh 116
 
4630 mandeep.dh 117
    def get_logistics_estimation_with_type(self, itemId, destination_pin, type):
3044 chandransh 118
        if not destination_pin:
119
            destination_pin = self.default_pincode
120
        try:
3133 rajveer 121
            client = CatalogClient().get_client()
3044 chandransh 122
            item = client.getItem(itemId)
123
        except Exception as ex:
124
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this item.")
125
 
3218 rajveer 126
        delivery_estimate = get_logistics_estimation(destination_pin, item.sellingPrice, None, type)
127
        if delivery_estimate is None:
3044 chandransh 128
            raise LogisticsServiceException(104, "Unable to fetch delivery estimate for this pincode.")
129
 
3218 rajveer 130
        warehouse_loc = delivery_estimate.warehouse_location
3044 chandransh 131
        try:
3355 chandransh 132
            #Get the id and location of actual warehouse that'll be used to fulfil this order.
133
            warehouse_loc, warehouse_id, items_in_inventory, expected_delay = client.getItemAvailabilityAtLocation(warehouse_loc, itemId)
3044 chandransh 134
        except Exception as ex:
135
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this item.")
136
 
4009 chandransh 137
        # We are revising the estimates based on the actual warehouse that this order will be assigned to.
138
        # This warehouse may be located in a zone which is different from the one we allocated for this pincode.
3218 rajveer 139
        delivery_estimate = get_logistics_estimation(destination_pin, item.sellingPrice, warehouse_loc, type)
140
        if delivery_estimate is None:
3044 chandransh 141
            raise LogisticsServiceException(105, "Unable to fetch delivery estimate for pincode: " + destination_pin + " and revised location: " + str(warehouse_loc))
142
 
4009 chandransh 143
        delivery_time = 24 * delivery_estimate.delivery_time
3044 chandransh 144
 
4009 chandransh 145
        '''
146
        We're now calculating the expected shipping delay which is independent of
147
        the courier agency and is completely within our control (well, almost).
148
        '''
3355 chandransh 149
        #Always add the expected delay
4009 chandransh 150
        shipping_delay = 24 * expected_delay
3355 chandransh 151
 
3044 chandransh 152
        # Increase the estimate if the actual stock is less than the threshold 
153
        if items_in_inventory < self.stock_threshold :
4009 chandransh 154
            shipping_delay = shipping_delay + self.time_to_procure
3044 chandransh 155
 
4829 rajveer 156
        # Sometimes we set negative shipping delay just in case we know time to procure will be less than the default.
157
        # If we have received inventory and forgot to remove expected delay from item, it could lead to display negative shipping days. 
158
        if shipping_delay < 0:
159
            shipping_delay = 0
160
 
3044 chandransh 161
        #Further increase the estimate if it's late in the day
3064 chandransh 162
        current_hour = datetime.datetime.now().hour
163
        if type == DeliveryType.PREPAID and self.cutoff_time <= current_hour:
4009 chandransh 164
            shipping_delay = shipping_delay + 24
3064 chandransh 165
        elif type == DeliveryType.COD and self.cod_cutoff_time <= current_hour:
4009 chandransh 166
            shipping_delay = shipping_delay + 24
3044 chandransh 167
 
4426 rajveer 168
        #In case of COD,increase delay by one more day
169
        if type == DeliveryType.COD:
170
            shipping_delay = shipping_delay + 24
171
 
4010 chandransh 172
        delivery_time = delivery_time + shipping_delay
173
 
4009 chandransh 174
        shipping_delay = int(math.ceil(shipping_delay/24.0))
4010 chandransh 175
        delivery_time = int(math.ceil(delivery_time/24.0))
3044 chandransh 176
 
177
        logistics_info = LogisticsInfo()
178
        logistics_info.deliveryTime = delivery_time
3218 rajveer 179
        logistics_info.providerId = delivery_estimate.provider_id
3044 chandransh 180
        logistics_info.warehouseId = warehouse_id
4009 chandransh 181
        logistics_info.shippingTime = shipping_delay
4870 rajveer 182
        logistics_info.codAllowed = delivery_estimate.codAllowed 
3044 chandransh 183
 
184
        return logistics_info
185
 
731 chandransh 186
    def getDestinationCode(self, providerId, pinCode):
187
        """
188
        Returns the short three letter code of a pincode for the given provider.
189
        Raises an exception if the pin code is not serviced by the given provider.
190
 
191
        Parameters:
192
         - providerId
193
         - pinCode
194
        """
796 rajveer 195
        try:
3217 rajveer 196
            try:
3218 rajveer 197
                dest_code = DataAccessor.serviceable_location_cache[providerId][pinCode][0]
3217 rajveer 198
                return dest_code
199
            except:
796 rajveer 200
                raise LogisticsServiceException(101, "The pincode " + pinCode + " is not serviced by this provider: " + str(providerId))
201
        finally:
202
            close_session()
1137 chandransh 203
 
3103 chandransh 204
    def getFreeAwbCount(self, providerId, type):
1137 chandransh 205
        """
3103 chandransh 206
        Returns the number of unused AWB numbers for the given provider of the given type
796 rajveer 207
 
1137 chandransh 208
        Parameters:
209
         - providerId
3103 chandransh 210
         - type
1137 chandransh 211
        """
212
        try:
3103 chandransh 213
            return get_free_awb_count(providerId, type)
1137 chandransh 214
        finally:
215
            close_session()
1730 ankur.sing 216
 
217
    def getHolidays(self, fromDate, toDate):
218
        """
219
        Returns list of Holiday dates between fromDate and toDate (both inclusive)
220
        fromDate should be passed as milliseconds corresponding to the start of the day.
221
        If fromDate is passed as -1, fromDate is not considered for filtering
222
        If toDate is passed as -1, toDate is not considered for filtering
1137 chandransh 223
 
1730 ankur.sing 224
        Parameters:
225
         - fromDate
226
         - toDate
227
        """
228
        try:
229
            return get_holidays(fromDate, toDate)
230
        finally:
231
            close_session()
3064 chandransh 232
 
766 rajveer 233
    def closeSession(self, ):
234
        close_session()
3376 rajveer 235
 
236
    def isAlive(self, ):
237
        """
238
        For checking weather service is active alive or not. It also checks connectivity with database
239
        """
240
        try:
241
            return is_alive()
242
        finally:
243
            close_session()
4934 amit.gupta 244
 
245
    def getEntityLogisticsEstimation(self, catalogItemId, destination_pin, type):
246
        """
247
        Returns a LogisticsInfo structure w/o an airway bill number. Use this method during the estimation phase.
248
        Raises an exception if this pincode is not allocated to any warehouse zone or provider. Also, if the pincode
249
        is allocated to a warehouse zone but there are no actual warehouses in that zone, an exception is raised.
250
 
251
        Parameters:
252
         - catalogItemId
253
         - destination_pin
254
         - type
255
        """
256
        try:
257
            return self.get_entity_logistics_estimation_with_type(catalogItemId, destination_pin, type)
258
        finally:
259
            close_session()
260
 
261
    def get_entity_logistics_estimation_with_type(self, catalog_item_id, destination_pin, type):
262
        try:
263
            client = CatalogClient().get_client()
264
            items = client.getValidItemsByCatalogId(catalog_item_id)
265
        except Exception as ex:
266
            raise LogisticsServiceException(103, "Unable to fetch inventory information about this entity.")
267
 
268
        estimateList = []
269
 
270
        for item in items:
271
            estimationInfo = self.get_logistics_estimation_with_type(item.id, destination_pin, type)
272
            if item.itemStatus == status.ACTIVE:
273
                estimateList.append((0, estimationInfo.deliveryTime, item.id))
274
            elif item.itemStatus == status.PAUSED:
275
                estimateList.append((1, estimationInfo.deliveryTime, item.id))
276
            elif item.itemStatus == status.PAUSED_BY_RISK:
277
                estimateList.append((2, estimationInfo.deliveryTime, item.id))
278
 
279
        estimateList.sort()
280
 
281
        return [estimate[-1] for estimate in estimateList]