Subversion Repositories SmartDukaan

Rev

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