Subversion Repositories SmartDukaan

Rev

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