Subversion Repositories SmartDukaan

Rev

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