Subversion Repositories SmartDukaan

Rev

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