Subversion Repositories SmartDukaan

Rev

Rev 6832 | Rev 7149 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5944 mandeep.dh 1
'''
2
Created on 23-Mar-2010
3
 
4
@author: ashish
5
'''
6
from elixir import *
7
from functools import partial
6531 vikram.rag 8
from shop2020.clients.CatalogClient import CatalogClient
5944 mandeep.dh 9
from shop2020.clients.TransactionClient import TransactionClient
10
from shop2020.model.v1.inventory.impl import DataService
6531 vikram.rag 11
from shop2020.model.v1.inventory.impl.Convertors import to_t_warehouse, \
12
    to_t_itemidwarehouseid
5944 mandeep.dh 13
from shop2020.model.v1.inventory.impl.DataService import Warehouse, \
14
    ItemInventoryHistory, CurrentInventorySnapshot, VendorItemPricing, \
15
    VendorItemMapping, Vendor, MissedInventoryUpdate, BadInventorySnapshot, \
6531 vikram.rag 16
    VendorItemProcurementDelay, VendorHolidays, ItemAvailabilityCache, \
6821 amar.kumar 17
    CurrentReservationSnapshot, IgnoredInventoryUpdateItems, \
18
    ItemStockPurchaseParams, OOSStatus
6531 vikram.rag 19
from shop2020.thriftpy.model.v1.inventory.ttypes import \
20
    InventoryServiceException, HolidayType, InventoryType, WarehouseType
5944 mandeep.dh 21
from shop2020.thriftpy.model.v1.order.ttypes import AlertType
6531 vikram.rag 22
from shop2020.thriftpy.purchase.ttypes import PurchaseServiceException
5944 mandeep.dh 23
from shop2020.utils import EmailAttachmentSender
24
from shop2020.utils.EmailAttachmentSender import mail
6821 amar.kumar 25
from shop2020.utils.Utils import to_py_date, to_java_date
5944 mandeep.dh 26
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
6531 vikram.rag 27
from sqlalchemy.sql.expression import and_, func, distinct
28
from sqlalchemy.sql.functions import count
6857 amar.kumar 29
from sqlalchemy.sql import or_
5944 mandeep.dh 30
import calendar
31
import datetime
32
import sys
33
import threading
34
 
6550 rajveer 35
to_addresses = ["khushal.bhatia@shop2020.in", "chaitnaya.vats@shop2020.in", "chandan.kumar@shop2020.in"]
6029 rajveer 36
mail_user = "cnc.center@shop2020.in"
37
mail_password = "5h0p2o2o"
5944 mandeep.dh 38
skippedItems = { 175 : [27, 2160, 2175, 2163, 2158, 7128, 26, 2154],
39
                 193 : [5839] }
40
 
6821 amar.kumar 41
OOS_CALCULATION_TIME = 23
6498 vikram.rag 42
 
5944 mandeep.dh 43
def initialize(dbname='inventory', db_hostname="localhost"):
44
    DataService.initialize(dbname, db_hostname)
45
 
46
def get_Warehouse(warehouse_id):
47
    return Warehouse.get_by(id=warehouse_id)
48
 
49
def get_vendor(vendorId):
50
    return Vendor.get_by(id=vendorId)
51
 
52
def get_all_warehouses_by_status(status):
53
    return Warehouse.query.all()
54
 
55
def get_all_items_for_warehouse(warehouse_id):
56
    warehouse = get_Warehouse(warehouse_id)
57
    if not warehouse:
58
        raise InventoryServiceException(108, "bad warehouse")
59
    return warehouse.all_items
60
 
61
def add_warehouse(warehouse):
62
    if not warehouse:
63
        raise InventoryServiceException(108, "Bad warehouse")
64
    if get_Warehouse(warehouse.id):
65
        #warehouse is already present.
66
        raise InventoryServiceException(101, "Warehouse already present")
67
 
68
    ds_warehouse = Warehouse()
69
    ds_warehouse.location = warehouse.location
70
    ds_warehouse.status = 3
71
    ds_warehouse.addedOn = datetime.datetime.now()
72
    ds_warehouse.lastCheckedOn = datetime.datetime.now()
73
    ds_warehouse.tinNumber = warehouse.tinNumber
74
    ds_warehouse.pincode = warehouse.pincode
75
    ds_warehouse.billingType = warehouse.billingType
76
    ds_warehouse.billingWarehouseId = warehouse.billingWarehouseId
77
    ds_warehouse.displayName = warehouse.displayName
78
    ds_warehouse.inventoryType = InventoryType._VALUES_TO_NAMES[warehouse.inventoryType]
79
    ds_warehouse.isAvailabilityMonitored = warehouse.isAvailabilityMonitored
80
    ds_warehouse.logisticsLocation = warehouse.logisticsLocation
81
    ds_warehouse.shippingWarehouseId = warehouse.shippingWarehouseId
82
    ds_warehouse.transferDelayInHours = warehouse.transferDelayInHours
83
    ds_warehouse.vendor = get_vendor(warehouse.vendor.id)
84
    ds_warehouse.warehouseType = WarehouseType._VALUES_TO_NAMES[warehouse.warehouseType]    
85
    if warehouse.vendorString:
86
        ds_warehouse.vendorString = warehouse.vendorString
87
    session.commit()
88
    return ds_warehouse.id
89
 
6498 vikram.rag 90
def get_ignored_items(warehouse_id): 
6531 vikram.rag 91
    Ignored_inventory_items = IgnoredInventoryUpdateItems.query.filter_by(warehouse_id=warehouse_id).all()
6498 vikram.rag 92
    negativeItems = []
93
    for Ignored_inventory_item in Ignored_inventory_items:
94
        try:
95
            item_id = Ignored_inventory_item.item_id
96
            negativeItems.append(item_id)
97
        except:
98
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
99
    return negativeItems
100
 
6510 rajveer 101
def get_ignored_warehouses(item_id): 
6539 amit.gupta 102
    Ignored_inventory_items = IgnoredInventoryUpdateItems.query.filter_by(item_id=item_id).all()
6510 rajveer 103
    warehouses = []
104
    for Ignored_inventory_item in Ignored_inventory_items:
105
        warehouses.append(Ignored_inventory_item.warehouse_id)
106
    return warehouses
107
 
5944 mandeep.dh 108
def update_inventory_history(warehouse_id, timestamp, availability):
109
    warehouse = get_Warehouse(warehouse_id)
110
    if not warehouse:
111
        raise InventoryServiceException(107, "Warehouse? Where?")
112
    vendor = warehouse.vendor
113
    time = datetime.datetime.now()
114
    for item_key, quantity in availability.iteritems():
115
        try:
116
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
5960 mandeep.dh 117
            item_id = vendor_item_mapping.item_id
5944 mandeep.dh 118
        except:
6531 vikram.rag 119
            continue  
5944 mandeep.dh 120
        try:
6510 rajveer 121
            item_inventory_history = ItemInventoryHistory()
122
            item_inventory_history.warehouse = warehouse
123
            item_inventory_history.item_id = item_id
124
            item_inventory_history.timestamp = time
125
            item_inventory_history.availability = quantity
5944 mandeep.dh 126
        except:
127
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
128
    session.commit()
129
 
130
def update_inventory(warehouse_id, timestamp, availability):
131
    warehouse = get_Warehouse(warehouse_id)
132
    if not warehouse:
133
        raise InventoryServiceException(107, "Warehouse? Where?")
6510 rajveer 134
 
5944 mandeep.dh 135
    time = datetime.datetime.now()
136
    warehouse.lastCheckedOn = time
137
    warehouse.vendorString = timestamp
138
    vendor = warehouse.vendor
139
    item_ids = []
140
    for item_key, quantity in availability.iteritems():
141
        try:
142
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
143
            item_id = vendor_item_mapping.item_id
6510 rajveer 144
            item_ids.append(item_id)
5944 mandeep.dh 145
        except:
146
            print 'Skipping update for ' + item_key + ' quantity ' + str(quantity) + ' warehouse id: ' + str(warehouse_id)
147
            __send_mail_for_missing_key(item_key, quantity, warehouse_id)
148
            continue
149
        try:
150
            current_inventory_snapshot = CurrentInventorySnapshot.get_by(item_id=item_id, warehouse=warehouse)
151
            if not current_inventory_snapshot:
152
                current_inventory_snapshot = CurrentInventorySnapshot()
153
                current_inventory_snapshot.item_id = item_id
154
                current_inventory_snapshot.warehouse = warehouse
155
                current_inventory_snapshot.availability = 0
156
                current_inventory_snapshot.reserved = 0
157
            # added the difference in the current inventory    
158
            current_inventory_snapshot.availability = current_inventory_snapshot.availability + quantity
159
            item = __get_item_from_master(item_id)
160
            try:
161
                if quantity > 0 and __get_item_reserved(item_id) > 0:
162
                    cl = TransactionClient().get_client()
163
                    #FIXME hardcoding for warehouse id 
164
                    cl.addAlert(AlertType.NEW_INVENTORY_ALERT, 5, "Inventory received for item " + item.brand + " " + item.modelName + " " + item.modelNumber + " " +  item.color)
165
            except:
166
                print "Not able to raise alert for incoming inventory" 
167
            if current_inventory_snapshot.availability < 0:
168
                __send_alert_for_negative_availability(item, current_inventory_snapshot.availability, warehouse)
169
        except:
170
            print "Some unforeseen error while updating inventory:", sys.exc_info()[0]
171
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
172
    session.commit()
173
 
174
    #**Update item availability cache**#
175
    for item_id in item_ids:
5978 rajveer 176
        clear_item_availability_cache(item_id)
5944 mandeep.dh 177
 
178
def __send_alert_for_negative_reserved(item, reserved, warehouse):
179
    itemName = " ".join([str(item.id), str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)])
6029 rajveer 180
    EmailAttachmentSender.mail(mail_user, mail_password, 'amar.kumar@shop2020.in', 'Negative reserved: ' + str(reserved) + ' for Item Id: ' + itemName + ' warehouse id: ' + str(warehouse.id), None)
5944 mandeep.dh 181
 
182
def __send_alert_for_negative_availability(item, availability, warehouse):
183
    itemName = " ".join([str(item.id), str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)])
5964 amar.kumar 184
    # EmailAttachmentSender.mail('cnc.center@shop2020.in', '5h0p2o2o', 'amar.kumar@shop2020.in', 'Negative availability ' + str(availability) + ' for Item id: ' + itemName + ' warehouse id: ' + str(warehouse.id), None)
5944 mandeep.dh 185
 
186
def __send_mail_for_missing_key(item_key, quantity, warehouse_id):
187
    missedInventoryUpdate = MissedInventoryUpdate.get_by(itemKey = item_key, warehouseId = warehouse_id)
188
    # One email per product key mismatch
189
    if not missedInventoryUpdate:
190
        missedInventoryUpdate = MissedInventoryUpdate()
191
        missedInventoryUpdate.itemKey = item_key
192
        missedInventoryUpdate.quantity = quantity
193
        missedInventoryUpdate.isIgnored = 1
194
        missedInventoryUpdate.timestamp = datetime.datetime.now()
195
        missedInventoryUpdate.warehouseId = warehouse_id
196
        session.commit()
6232 rajveer 197
        try:
6617 amar.kumar 198
            EmailAttachmentSender.mail(mail_user, mail_password, ['chaitnaya.vats@shop2020.in', 'chandan.kumar@shop2020.in', 'khushal.bhatia@shop2020.in'], 'Skipped inventory update for ' + item_key + ' quantity ' + str(quantity) + ' warehouse id: ' + str(warehouse_id), None)
6232 rajveer 199
        except:
200
            print "Not able to send email. No issues, we can continue with updates."
5944 mandeep.dh 201
    else:
202
        missedInventoryUpdate.quantity += quantity
203
        session.commit()
204
 
205
def add_inventory(itemId, warehouseId, quantity):
206
    current_inventory_snapshot = CurrentInventorySnapshot.get_by(item_id=itemId, warehouse_id=warehouseId)
207
    if not current_inventory_snapshot:
208
        current_inventory_snapshot = CurrentInventorySnapshot()
209
        current_inventory_snapshot.item_id = itemId
210
        current_inventory_snapshot.warehouse_id = warehouseId
211
        current_inventory_snapshot.availability = 0
212
        current_inventory_snapshot.reserved = 0
213
    # added the difference in the current inventory    
214
    current_inventory_snapshot.availability = current_inventory_snapshot.availability + quantity
215
    session.commit()
216
    #**Update item availability cache**#
5978 rajveer 217
    clear_item_availability_cache(itemId)
5944 mandeep.dh 218
    if current_inventory_snapshot.availability < 0:
219
        item = __get_item_from_master(itemId)
5978 rajveer 220
        __send_alert_for_negative_availability(item, current_inventory_snapshot.availability, get_Warehouse(warehouseId)) 
5944 mandeep.dh 221
 
222
def add_bad_inventory(itemId, warehouseId, quantity):
223
    bad_inventory_snapshot = BadInventorySnapshot.get_by(item_id=itemId, warehouse_id=warehouseId)
224
    if not bad_inventory_snapshot:
225
        bad_inventory_snapshot = BadInventorySnapshot()
226
        bad_inventory_snapshot.item_id = itemId
227
        bad_inventory_snapshot.warehouse_id = warehouseId
228
        bad_inventory_snapshot.availability = 0
229
    # added the difference in the current inventory    
230
    bad_inventory_snapshot.availability += quantity
231
    session.commit()
232
    if bad_inventory_snapshot.availability < 0:
233
        item = __get_item_from_master(itemId)
234
        __send_alert_for_negative_availability(item, bad_inventory_snapshot.availability, get_Warehouse(warehouseId))
235
 
236
def get_item_inventory_by_item_id(item_id):
237
    return CurrentInventorySnapshot.query.filter_by(item_id=item_id).all()
238
 
239
def retire_warehouse(warehouse_id):
240
    if not warehouse_id:
241
        raise InventoryServiceException(101, "Bad warehouse id")
242
    warehouse = get_Warehouse(warehouse_id)
243
    if not warehouse:
244
        raise InventoryServiceException(108, "warehouse id not present")
245
    warehouse.status = 0;
246
    session.commit()
247
 
248
def get_item_availability_for_warehouse(warehouse_id, item_id):
6545 rajveer 249
    ignore = IgnoredInventoryUpdateItems.query.filter_by(item_id=item_id).filter_by(warehouse_id = warehouse_id).all()
6544 rajveer 250
    if ignore:
251
        return 0
5944 mandeep.dh 252
 
253
    try:
6544 rajveer 254
        current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id).filter_by(item_id = item_id).one()
5944 mandeep.dh 255
        return current_inventory_snapshot.availability - current_inventory_snapshot.reserved
256
    except:
257
        return 0
258
 
6484 amar.kumar 259
def get_item_availability_for_our_warehouses(item_ids):
260
    warehouses = Warehouse.query.filter_by(warehouseType = 'OURS', inventoryType = 'GOOD').all()
261
    warehouse_ids = []
262
    for warehouse in warehouses :
263
        warehouse_ids.append(warehouse.id)
264
 
265
    availability_map = dict()
266
 
267
    try :
268
        for item_id in item_ids :
269
            total_availability = 0
270
            for current_inventory_snapshot in CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).filter_by(item_id = item_id).all():
271
                total_availability += current_inventory_snapshot.availability
272
            if total_availability >0:
273
                availability_map[item_id] = total_availability
274
    except Exception as e:
275
        print e
276
        raise PurchaseServiceException(101, 'Exception while fetching availability of items in our warehouses')
277
 
278
    return availability_map
279
 
5944 mandeep.dh 280
'''
281
This method returns quantity of a particular item across all warehouses whose ids is provided
282
if warehouse_ids is null it checks for inventory in all warehouses.
283
'''
284
def __get_item_availability(item, warehouse_ids):
285
    if warehouse_ids is None:
286
        all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
287
        availability = 0
288
        reserved = 0
289
        for currInv in all_inventory:
290
            availability = availability + currInv.availability
291
            reserved = reserved + currInv.reserved
292
        return availability - reserved
293
    else:
294
        total_availability = 0
295
        for current_inventory_snapshot in CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).filter_by(item_id = item.id).all():
296
            total_availability += current_inventory_snapshot.availability - current_inventory_snapshot.reserved
297
        return total_availability 
298
 
299
def __get_item_reserved(item_id):
300
    all_inventory = CurrentInventorySnapshot.query.filter_by(item_id = item_id).all()
301
    reserved = 0
302
    for currInv in all_inventory:
303
        reserved = reserved + currInv.reserved
304
    return reserved
5966 rajveer 305
 
306
def __get_item_availability_at_warehouse(warehouse_id, item_id):
307
    inventory = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
308
    return inventory.availability
309
 
310
def is_order_billable(item_id, warehouse_id, source_id, order_id):
311
    reservations = CurrentReservationSnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).order_by(CurrentReservationSnapshot.promised_shipping_timestamp).order_by(CurrentReservationSnapshot.created_timestamp).all()
312
    availability = __get_item_availability_at_warehouse(warehouse_id, item_id)
313
    for reservation in reservations:
314
        availability = availability - reservation.reserved
315
        if reservation.order_id == order_id and reservation.source_id == source_id:
316
            break
317
    if availability < 0:
318
        return False
319
    return True
5944 mandeep.dh 320
 
5966 rajveer 321
def reserve_item_in_warehouse(item_id, warehouse_id, source_id, order_id, created_timestamp, promised_shipping_timestamp, quantity):    
5944 mandeep.dh 322
    if not warehouse_id:
323
        raise InventoryServiceException(101, "bad warehouse_id")
324
 
325
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
326
    try:
327
        current_inventory_snapshot = query.one()
328
    except:
329
        current_inventory_snapshot = CurrentInventorySnapshot()
330
        current_inventory_snapshot.warehouse_id = warehouse_id
331
        current_inventory_snapshot.item_id = item_id
332
        current_inventory_snapshot.availability = 0
333
        current_inventory_snapshot.reserved = 0
334
 
335
    current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
5966 rajveer 336
 
337
    reservation = CurrentReservationSnapshot()
338
    reservation.item_id = item_id
339
    reservation.warehouse_id = warehouse_id
340
    reservation.source_id = source_id
341
    reservation.order_id = order_id
5990 rajveer 342
    reservation.created_timestamp = to_py_date(created_timestamp)
343
    reservation.promised_shipping_timestamp = to_py_date(promised_shipping_timestamp)
5966 rajveer 344
    reservation.reserved = quantity
345
 
5944 mandeep.dh 346
    session.commit()
347
    #**Update item availability cache**#
5978 rajveer 348
    clear_item_availability_cache(item_id)
5944 mandeep.dh 349
    return True
350
 
5966 rajveer 351
def reduce_reservation_count(item_id, warehouse_id, source_id, order_id, quantity):
5944 mandeep.dh 352
    if not warehouse_id:
353
        raise InventoryServiceException(101, "bad warehouse_id")
354
 
355
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
356
    try:
357
        current_inventory_snapshot = query.one()
358
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
5966 rajveer 359
 
360
        reservation = CurrentReservationSnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id, source_id = source_id, order_id = order_id).one()
361
        if reservation.reserved == quantity:
362
            reservation.delete()
363
        else:
364
            reservation.reserved -= quantity
5944 mandeep.dh 365
        session.commit()
366
        #**Update item availability cache**#
5978 rajveer 367
        clear_item_availability_cache(item_id)
5944 mandeep.dh 368
        if current_inventory_snapshot.reserved < 0:
369
            item = __get_item_from_master(item_id)
370
            __send_alert_for_negative_reserved(item, current_inventory_snapshot.reserved, get_Warehouse(warehouse_id))
371
        return True
372
    except:
373
        print "Unexpected error:", sys.exc_info()[0]
374
        return False
375
 
5978 rajveer 376
def get_item_availability_for_location(item_id, source_id):
377
    item_availability = ItemAvailabilityCache.get_by(itemId=item_id, sourceId = source_id)
5944 mandeep.dh 378
    if item_availability:
379
        return [item_availability.warehouseId, item_availability.expectedDelay, item_availability.billingWarehouseId, item_availability.sellingPrice, item_availability.totalAvailability]
380
    else:
5978 rajveer 381
        __update_item_availability_cache(item_id, source_id)
382
            ##Check risky status for the source
383
        __check_risky_item(item_id, source_id)
384
        return get_item_availability_for_location(item_id, source_id)
5944 mandeep.dh 385
 
5978 rajveer 386
def clear_item_availability_cache(item_id = None):
387
    if item_id:
388
        ItemAvailabilityCache.query.filter_by(itemId = item_id).delete()
389
    else:
390
        ItemAvailabilityCache.query.delete()
5944 mandeep.dh 391
    session.commit()
392
 
5978 rajveer 393
def __update_item_availability_cache(item_id, source_id):
5944 mandeep.dh 394
    """
395
    Determines the warehouse that should be used to fulfil an order for the given item.
396
    Algorithm explained at https://sites.google.com/a/shop2020.in/virtual-w-h-and-inventory/technical-details
397
 
398
    It will be ensured that every item has either a preferred vendor specified or at least for one vendor its transfer price should be defined.
399
    This is needed to associate an item with at least one vendor so that in default case when its available no where, we know from where to procure it.
400
 
401
    if item available at any OUR-GOOD warehouse
402
        // OUR-GOOD warehouses have inventory risk; So, we empty them first! 
403
        // We can start with minimum transfer price criterion but down the line we can also bring in Inventory age 
404
        assign OUR-GOOD warehouse with minimum transfer price
405
    else
406
        if Preferred vendor is specified and marked Sticky
407
            // Always purchase from Preferred if its marked sticky
408
            assign preferred vendor's THIRDPARTY GOOD/VIRTUAL warehouse
409
        else 
410
            if item available in a THIRDPARTY GOOD/VIRTUAL warehouse
411
                assign THIRDPARTY GOOD/VIRTUAL warehouse where item is available with minimal transfer delay followed by minimum transfer price
412
            else 
413
                // Item not available at any warehouse, OURS or THIRDPARTY
414
                If Preferred vendor is specified
415
                    assign preferred vendor's THIRDPARTY GOOD/VIRTUAL warehouse
416
                else
417
                    assign THIRDPARTY GOOD/VIRTUAL warehouse with minimum transfer price
418
 
419
    Returns an ordered list of size 4 with following elements in the given order:
420
    1. Logistics location of the warehouse which was finally picked up to ship the order.
421
    2. Expected delay added by the category manager.
422
    3. Id of the warehouse which was finally picked up.
423
 
424
    Parameters:
425
     - itemId
426
    """
5978 rajveer 427
    item = __get_item_from_source(item_id, source_id)
5944 mandeep.dh 428
    item_pricing = {}
429
    for vendorItemPricing in VendorItemPricing.query.filter_by(item_id=item_id).all():
430
        item_pricing[vendorItemPricing.vendor_id] = vendorItemPricing
431
 
6510 rajveer 432
    ignoredWhs = get_ignored_warehouses(item_id)
433
 
5944 mandeep.dh 434
    warehouses = {}
435
    ourGoodWarehouses = {}
436
    thirdpartyWarehouses = {}
437
    preferredThirdpartyWarehouses = {}
438
    for warehouse in Warehouse.query.all():
439
        if (warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.BAD]):
440
            continue
441
        warehouses[warehouse.id] = warehouse
442
        if warehouse.warehouseType == WarehouseType._VALUES_TO_NAMES[WarehouseType.OURS]:
443
            if warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.GOOD]:
444
                ourGoodWarehouses[warehouse.id] = warehouse
445
        else:
446
            thirdpartyWarehouses[warehouse.id] = warehouse
447
            if item.preferredVendor == warehouse.vendor_id and warehouse.inventoryType == InventoryType._VALUES_TO_NAMES[InventoryType.GOOD]:
448
                preferredThirdpartyWarehouses[warehouse.id] = warehouse
449
 
450
    warehouse_retid = -1
451
    total_availability = 0
452
 
6540 rajveer 453
    [warehouse_retid, total_availability] = __get_warehouse_with_min_transfer_price(ourGoodWarehouses, ignoredWhs, item_id, item_pricing, False)
5944 mandeep.dh 454
    if warehouse_retid == -1:
455
        if item.preferredVendor and item.isWarehousePreferenceSticky:
6540 rajveer 456
            [warehouse_retid, total_availability] = __get_warehouse_with_min_transfer_delay(preferredThirdpartyWarehouses, ignoredWhs, item_id, item_pricing)
5944 mandeep.dh 457
            if warehouse_retid == -1:
458
                warehouse_retid = preferredThirdpartyWarehouses.keys()[0]
459
        else:
6540 rajveer 460
            [warehouse_retid, total_availability] = __get_warehouse_with_min_transfer_delay(thirdpartyWarehouses, ignoredWhs, item_id, item_pricing)
5944 mandeep.dh 461
            if warehouse_retid == -1:
462
                if item.preferredVendor:
463
                    warehouse_retid = preferredThirdpartyWarehouses.keys()[0]
464
                else:
6540 rajveer 465
                    [warehouse_retid, total_availability] = __get_warehouse_with_min_transfer_price(thirdpartyWarehouses, ignoredWhs, item_id, item_pricing, True)
5944 mandeep.dh 466
 
467
    warehouse = warehouses[warehouse_retid]
468
    billingWarehouseId = warehouse.billingWarehouseId
469
 
470
    # Fetching billing warehouse of a Good billable warehouse corresponding to the virtual one
471
    if not warehouse.billingWarehouseId:
472
        for w in Warehouse.query.filter_by(vendor_id = warehouse.vendor_id, inventoryType = InventoryType._VALUES_TO_NAMES[InventoryType.GOOD]).all():
473
            if w.billingWarehouseId:
474
                billingWarehouseId = w.billingWarehouseId
475
                break
476
 
477
    expectedDelay = item.expectedDelay 
478
    if expectedDelay is None:
479
        print 'expectedDelay field for this item was Null. Resetting it to 0'
480
        expectedDelay = 0
481
    else:
482
        expectedDelay = int(item.expectedDelay)
483
 
484
    if total_availability <= 0:
6562 rajveer 485
        if item.preferredVendor in [1, 5]:
486
            expectedDelay = expectedDelay + 3
487
        else:
488
            expectedDelay = expectedDelay + 2
6643 rajveer 489
    else:
490
        if warehouse.transferDelayInHours:
491
            expectedDelay = expectedDelay + warehouse.transferDelayInHours / 24
5944 mandeep.dh 492
 
5963 mandeep.dh 493
    total_availability = 0
494
    for entry in CurrentInventorySnapshot.query.filter_by(item_id = item_id).all():
6545 rajveer 495
        if entry.warehouse_id not in ignoredWhs:
496
            total_availability += entry.availability - entry.reserved
5963 mandeep.dh 497
 
5978 rajveer 498
    item_availability_cache = ItemAvailabilityCache.get_by(itemId=item_id, sourceId=source_id)
5944 mandeep.dh 499
    if item_availability_cache is None:
500
        item_availability_cache = ItemAvailabilityCache()
501
        item_availability_cache.itemId = item_id
5978 rajveer 502
        item_availability_cache.sourceId = source_id
5944 mandeep.dh 503
    item_availability_cache.warehouseId = int(warehouse_retid)
504
    item_availability_cache.expectedDelay = expectedDelay
505
    item_availability_cache.billingWarehouseId = billingWarehouseId
506
    item_availability_cache.sellingPrice = item.sellingPrice
507
    item_availability_cache.totalAvailability = total_availability
508
    session.commit()
509
 
6540 rajveer 510
def __get_warehouse_with_min_transfer_price(warehouses, ignoredWhs, item_id, item_pricing, ignoreAvailability):
5944 mandeep.dh 511
    warehouse_retid = -1
512
    minTransferPrice = None
513
    total_availability = 0
6013 amar.kumar 514
    availabilityForBillingWarehouses = {}
515
    warehousesAvailability = {}
516
    availability = 0
517
    billing_warehouse_retid = None
5944 mandeep.dh 518
 
519
    if not ignoreAvailability:
520
        for entry in CurrentInventorySnapshot.query.filter_by(item_id = item_id).all():
6013 amar.kumar 521
            #if entry.availability > entry.reserved:
6542 rajveer 522
            warehousesAvailability[entry.warehouse_id] = [entry.availability, entry.reserved] 
5944 mandeep.dh 523
 
6540 rajveer 524
    if len(ignoredWhs) > 0:
525
        for whid in ignoredWhs:
526
            if warehousesAvailability.has_key(whid):
6542 rajveer 527
                warehousesAvailability[whid][0] = 0
6683 rajveer 528
                warehousesAvailability[whid][1] = 0
6540 rajveer 529
 
5944 mandeep.dh 530
    for warehouse in warehouses.values():
531
        if not ignoreAvailability:
6013 amar.kumar 532
            #TODO Mistake no entry for this warehouse.id in warehouseswithAvailab
533
            if warehouse.id not in warehousesAvailability:
534
                continue
535
            entry = warehousesAvailability[warehouse.id]
536
            if warehouse.billingWarehouseId in availabilityForBillingWarehouses:
537
                if warehouse.billingWarehouseId is not None or warehouse.billingWarehouseId != 0: 
6544 rajveer 538
                    availabilityForBillingWarehouses[warehouse.billingWarehouseId] = availabilityForBillingWarehouses[warehouse.billingWarehouseId] + entry[0] - entry[1]  
5944 mandeep.dh 539
            else:
6013 amar.kumar 540
                if warehouse.billingWarehouseId is not None or warehouse.billingWarehouseId != 0: 
6542 rajveer 541
                    availabilityForBillingWarehouses[warehouse.billingWarehouseId] = entry[0] - entry[1]
542
            if entry[0] <= entry[1]:
5944 mandeep.dh 543
                continue
6542 rajveer 544
            total_availability += entry[0] - entry[1]
5944 mandeep.dh 545
 
546
        # Missing transfer price cases should not impact warehouse assignment
547
        transferPrice = None
548
        if item_pricing.has_key(warehouse.vendor_id):
6778 rajveer 549
            transferPrice = item_pricing[warehouse.vendor_id].nlc
5944 mandeep.dh 550
        if minTransferPrice is None or (transferPrice and minTransferPrice > transferPrice):
551
            warehouse_retid = warehouse.id
6013 amar.kumar 552
            billing_warehouse_retid = warehouse.billingWarehouseId
5944 mandeep.dh 553
            minTransferPrice = transferPrice
6013 amar.kumar 554
 
555
 
556
    if billing_warehouse_retid in availabilityForBillingWarehouses: 
557
        availability = availabilityForBillingWarehouses[billing_warehouse_retid]
558
    else:
559
        availability = total_availability
560
 
561
    return [warehouse_retid, availability]
5944 mandeep.dh 562
 
6540 rajveer 563
def __get_warehouse_with_min_transfer_delay(warehouses, ignoredWhs, item_id, item_pricing):
5944 mandeep.dh 564
    minTransferDelay = None
565
    minTransferDelayWarehouses = {}
566
    total_availability = 0
567
 
568
    for entry in CurrentInventorySnapshot.query.filter_by(item_id = item_id).all():
569
        if warehouses.has_key(entry.warehouse_id):
570
            warehouse = warehouses[entry.warehouse_id]
6013 amar.kumar 571
            #if entry.availability > entry.reserved:
6683 rajveer 572
            if entry.warehouse_id not in ignoredWhs:
573
                total_availability += entry.availability - entry.reserved
6780 amar.kumar 574
            if entry.availability - entry.reserved <= 0:
575
                continue
6013 amar.kumar 576
            transferDelay = warehouse.transferDelayInHours
577
            if minTransferDelay is None or minTransferDelay >= transferDelay:
578
                if minTransferDelay != transferDelay:
579
                    minTransferDelayWarehouses = {}
580
                minTransferDelayWarehouses[warehouse.id] = warehouse
581
                minTransferDelay = transferDelay
5944 mandeep.dh 582
 
6540 rajveer 583
    return [__get_warehouse_with_min_transfer_price(minTransferDelayWarehouses, ignoredWhs, item_id, item_pricing, False)[0], total_availability]
5944 mandeep.dh 584
 
585
def __get_warehouse_with_max_availability(warehouse_ids, item_id):
586
    warehouse_retid = -1
587
    max_availability = 0
588
    total_availability = 0
589
 
590
    for entry in CurrentInventorySnapshot.query.filter_by(item_id = item_id).all():
591
        if entry.warehouse_id in warehouse_ids:
592
            availability = entry.availability - entry.reserved
593
            if availability > max_availability:
594
                warehouse_retid = entry.warehouse_id
595
                max_availability = availability
596
            total_availability += availability
597
 
598
    return [warehouse_retid, total_availability]
599
 
5978 rajveer 600
def __get_expected_procurement_delay(item_id, preferredVendor):
5944 mandeep.dh 601
    procurementDelay = 2
602
    try:
5978 rajveer 603
        if preferredVendor:
604
            delays = VendorItemProcurementDelay.query.filter_by(vendor_id = preferredVendor, item_id = item_id).all()
5944 mandeep.dh 605
        else:
5978 rajveer 606
            delays = VendorItemProcurementDelay.query.filter_by(item_id = item_id).all()
5944 mandeep.dh 607
 
608
        procurementDelay= min([delay.procurementDelay for delay in delays])
609
    except Exception as e:
610
        print e
611
    return procurementDelay
612
 
5978 rajveer 613
def __get_vendor_holiday_delay(preferredVendor, expectedDelay):
5944 mandeep.dh 614
    holidayDelay = 0
615
    try:
5978 rajveer 616
        if preferredVendor:
617
            holidays = VendorHolidays.query.filter_by(vendor_id = preferredVendor).all()
5944 mandeep.dh 618
            currentDate = datetime.date.today()
619
            expectedDate = currentDate + datetime.timedelta(days = expectedDelay)
620
            for holiday in holidays:
621
                if holiday.holidayType == HolidayType.WEEKLY and holiday.holidayValue != calendar.SUNDAY:
622
                    if currentDate.weekday() > holiday.holidayValue:
623
                        holidayDate = currentDate + datetime.timedelta(days=holiday.holidayValue-currentDate.weekday(), weeks=1)
624
                    else:
625
                        holidayDate = currentDate + datetime.timedelta(days=holiday.holidayValue-currentDate.weekday())
626
                    if holidayDate >=  currentDate and holidayDate <= expectedDate:
627
                        holidayDelay = holidayDelay + 1
628
                elif holiday.holidayType == HolidayType.MONTHLY:
629
                    holidayDate = datetime.date(currentDate.year, currentDate.month, holiday.holidayValue)
630
                    if holidayDate >=  currentDate and holidayDate <= expectedDate:
631
                        holidayDelay = holidayDelay + 1    
632
                elif holiday.holidayType == HolidayType.SPECIFIC:
633
                    holidayValue = str(holiday.holidayValue)
634
                    holidayDate = datetime.date(int(holidayValue[:4]), int(holidayValue[4:6]), int(holidayValue[6:8]))
635
                    if holidayDate >=  currentDate and holidayDate <= expectedDate:
636
                        holidayDelay = holidayDelay + 1                
637
    except Exception as e:
638
        print e
639
    return holidayDelay 
640
 
641
def get_item_pricing(item_id, vendorId):
642
    '''
643
    if vendor id is -1 then we calculate an average transfer price to be populated
644
    at the time of order creation. This will be later updated with actual transfer price
645
    at the time of billing.
646
    '''
647
    if(vendorId == -1):
6778 rajveer 648
        tp_total = 0
649
        nlc_total = 0
5944 mandeep.dh 650
        try:
651
            item_pricings = []
652
            item = __get_item_from_master(item_id)
653
            if item.preferredVendor is not None:
654
                item_pricing = VendorItemPricing.query.filter_by(item_id=item_id, vendor_id=item.preferredVendor).first()
655
                if item_pricing:
656
                    item_pricings.append(item_pricing)                    
657
            else :
658
                item_pricings = VendorItemPricing.query.filter_by(item_id=item_id).all()
659
            if item_pricings:
660
                for item_pricing in item_pricings:
6778 rajveer 661
                    tp_total += item_pricing.transfer_price
662
                    nlc_total += item_pricing.nlc
663
                tp_avg = tp_total / len(item_pricings)
664
                nlc_avg = nlc_total / len(item_pricings)
665
                item_pricing.transfer_price = tp_avg
666
                item_pricing.nlc = nlc_avg
5944 mandeep.dh 667
            else:
668
                item_pricing = VendorItemPricing()
669
                item_pricing.transfer_price = item.sellingPrice
6778 rajveer 670
                item_pricing.nlc = item.sellingPrice
5944 mandeep.dh 671
                vendor = Vendor()
672
                vendor.id = vendorId
673
                item_pricing.vendor = vendor
674
                item_pricing.item_id = item_id
675
 
676
            return item_pricing
677
        except:
678
            raise InventoryServiceException(101, "Item pricing not found ")
679
    vendor = Vendor.get_by(id=vendorId)    
680
    try:
681
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item_id=item_id).one()
682
        return item_pricing
683
    except MultipleResultsFound:
684
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
685
    except NoResultFound:
686
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
687
 
688
def get_all_item_pricing(item_id):
689
    item_pricing = VendorItemPricing.query.filter_by(item_id=item_id).all()
690
    return item_pricing
691
 
692
def get_item_mappings(item_id):
693
    item_mappings = VendorItemMapping.query.filter_by(item_id=item_id).all()
694
    return item_mappings
695
 
696
def add_vendor_pricing(vendorItemPricing):
697
    if not vendorItemPricing:
698
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
699
    vendorId = vendorItemPricing.vendorId
700
    itemId = vendorItemPricing.itemId
701
 
702
    try:
703
        vendor = Vendor.query.filter_by(id=vendorId).one()
704
    except:
705
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
706
 
707
    try:
708
        item = __get_item_from_master(itemId)
709
    except:
710
        raise InventoryServiceException(101, "Item not found for itemId " + str(itemId))
711
 
712
    validate_vendor_prices(item, vendorItemPricing)
713
 
714
    try:
715
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item_id==itemId)).one()
716
    except:
717
        ds_vendorItemPricing = VendorItemPricing()
718
        ds_vendorItemPricing.vendor = vendor
719
        ds_vendorItemPricing.item_id = itemId
720
 
721
    subject = ""
722
    message = ""
723
    if vendorItemPricing.mop:
724
        ds_vendorItemPricing.mop = vendorItemPricing.mop
725
    if vendorItemPricing.dealerPrice:
726
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
727
    if vendorItemPricing.transferPrice:
728
        if vendorItemPricing.transferPrice != ds_vendorItemPricing.transfer_price:
6617 amar.kumar 729
            client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
730
            item = client.getItem(itemId)
731
            message = "Transfer price for Item {0} {1} {2} {3} \nand Vendor:{4} is changed from {5} to {6}.".format(item.brand, item.modelName, item.modelNumber, item.color, vendor.name, ds_vendorItemPricing.transfer_price, vendorItemPricing.transferPrice)
6651 amar.kumar 732
            subject = "Alert:Change in Transfer Price {0} {1} {2} {3} {4}".format(item.brand, item.modelName, item.modelNumber, item.color, itemId)
5944 mandeep.dh 733
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
6751 amar.kumar 734
    if vendorItemPricing.nlc:
735
        if vendorItemPricing.nlc != ds_vendorItemPricing.nlc:
736
            client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
737
            item = client.getItem(itemId)
738
            message = "NLC for Item {0} {1} {2} {3} \nand Vendor:{4} is changed from {5} to {6}.".format(item.brand, item.modelName, item.modelNumber, item.color, vendor.name, ds_vendorItemPricing.nlc, vendorItemPricing.nlc)
739
            subject = "Alert:Change in NLC {0} {1} {2} {3} {4}".format(item.brand, item.modelName, item.modelNumber, item.color, itemId)
740
        ds_vendorItemPricing.nlc = vendorItemPricing.nlc
5944 mandeep.dh 741
 
742
    session.commit()
743
    if subject:
744
        __send_mail(subject, message)
745
    return
746
 
747
def add_vendor_item_mapping(key, vendorItemMapping):
748
    if not vendorItemMapping:
749
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
750
    vendorId = vendorItemMapping.vendorId
751
    itemId = vendorItemMapping.itemId
752
 
753
    try:
754
        vendor = Vendor.query.filter_by(id=vendorId).one()
755
    except:
756
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
757
 
758
    try:
759
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item_id==itemId, VendorItemMapping.item_key==key)).one()
760
    except:
761
        ds_vendorItemMapping = VendorItemMapping()
762
        ds_vendorItemMapping.vendor = vendor
763
        ds_vendorItemMapping.item_id = itemId
764
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
765
 
766
    session.commit()
767
 
768
    # Marking the missed inventory as not ignored as the catalog dashboard user has updated their key
769
    for missedInventoryUpdate in MissedInventoryUpdate.query.filter_by(itemKey = vendorItemMapping.itemKey).all():
770
        missedInventoryUpdate.isIgnored = 0
771
    session.commit()
772
 
773
    return
774
 
775
def validate_vendor_prices(item, vendorPrices):
776
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
777
        print "[BAD MRP and MOP:] for {0} {1} {2} {3}. MRP={4}. MOP={5}, Vendor={6}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(item.mrp), str(vendorPrices.mop), str(vendorPrices.vendorId))
778
        raise InventoryServiceException(101, "[BAD MRP and MOP:] for {0} {1} {2} {3}. MRP={4}. MOP={5}, Vendor={6}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(item.mrp), str(vendorPrices.mop), str(vendorPrices.vendorId)))
779
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
780
        print "[BAD MOP and TP:] for {0} {1} {2} {3}. TP={4}. MOP={5}, Vendor={6}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(vendorPrices.transferPrice), str(vendorPrices.mop), str(vendorPrices.vendorId))
781
        raise InventoryServiceException(101, "[BAD MOP and TP:] for {0} {1} {2} {3}. TP={4}. MOP={5}, Vendor={6}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(vendorPrices.transferPrice), str(vendorPrices.mop), str(vendorPrices.vendorId)))
782
    return
783
 
784
def get_all_vendors():
785
    return Vendor.query.all()
786
 
787
def get_pending_orders_inventory(vendor_id=1):
788
    """
789
    Returns a list of inventory stock for items for which there are pending orders.
790
    """
791
 
792
    warehouse_ids = [warehouse.id for warehouse in Warehouse.query.filter_by(vendor_id = vendor_id)]
793
    pending_items_inventory = []
794
    if warehouse_ids:
795
        pending_items_inventory = session.query(CurrentInventorySnapshot.item_id, func.sum(CurrentInventorySnapshot.availability), func.sum(CurrentInventorySnapshot.reserved)).filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).group_by(CurrentInventorySnapshot.item_id).having(func.sum(CurrentInventorySnapshot.reserved) > 0).all()
796
    return pending_items_inventory
797
 
798
def close_session():
799
    if session.is_active:
800
        print "session is active. closing it."
801
        session.close()
802
 
803
def is_alive():
804
    try:
805
        session.query(Vendor.id).limit(1).one()
806
        return True
807
    except:
808
        return False
809
 
810
def add_vendor(vendor):
811
    if not vendor:
812
        raise InventoryServiceException(108, "Bad vendor")
813
    if get_vendor(vendor.id):
814
        #vendor is already present.
815
        raise InventoryServiceException(101, "Vendor already present")
816
 
817
    ds_vendor = Vendor()
818
    ds_vendor.id = vendor.id
819
    ds_vendor.name = vendor.name
820
    session.commit()
821
    return ds_vendor.id
822
 
823
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
824
    return True
825
 
826
def mark_missed_inventory_updates_as_processed(itemKey, warehouseId):
827
    MissedInventoryUpdate.query.filter_by(itemKey = itemKey, warehouseId = warehouseId).delete()
828
    session.commit()
829
 
830
def get_item_keys_to_be_processed(warehouseId):
831
    return [i.itemKey for i in MissedInventoryUpdate.query.filter_by(warehouseId = warehouseId, isIgnored = 0)]
832
 
833
def reset_availability(itemKey, vendorId, quantity, warehouseId):
834
    vendorItemMapping = VendorItemMapping.get_by(vendor_id = vendorId, item_key = itemKey)
835
    if vendorItemMapping:
836
        itemId = vendorItemMapping.item_id
837
 
838
        if skippedItems.has_key(warehouseId) and itemId in skippedItems[warehouseId]:
839
            quantity = 0
840
 
841
        currentInventorySnapshot = CurrentInventorySnapshot.get_by(item_id = itemId, warehouse_id = warehouseId)
842
        if currentInventorySnapshot:
843
            currentInventorySnapshot.availability = quantity
5978 rajveer 844
            clear_item_availability_cache(itemId) 
5944 mandeep.dh 845
        else:
846
            add_inventory(itemId, warehouseId, quantity)
847
 
848
    else:
849
        raise InventoryServiceException(101, 'VendorMapping not found for: ' + itemKey)
850
    session.commit()
851
 
852
def reset_availability_for_warehouse(warehouseId):
853
    for currentInventorySnapshot in CurrentInventorySnapshot.query.filter_by(warehouse_id=warehouseId).all():
854
        currentInventorySnapshot.availability = 0
5978 rajveer 855
        clear_item_availability_cache(currentInventorySnapshot.item_id) 
5944 mandeep.dh 856
    session.commit()
857
 
6467 amar.kumar 858
def get_our_warehouse_id_for_vendor(vendor_id):
859
    try:
860
        warehouse = Warehouse.query.filter_by(vendor_id = vendor_id, warehouseType = 'OURS', inventoryType = 'GOOD').first()
861
        return warehouse.id
862
    except Exception as e:
863
        print e;
864
        raise InventoryServiceException(101, 'No our warehouse found for vendorId: ' + vendor_id)
5944 mandeep.dh 865
 
866
def __send_mail(subject, message):
867
    try:
6029 rajveer 868
        thread = threading.Thread(target=partial(mail, mail_user, mail_password, to_addresses, subject, message))
5944 mandeep.dh 869
        thread.start()
870
    except Exception as ex:
871
        print ex    
872
 
873
def get_shipping_locations():
874
    shippingLocationIds = {}
875
    warehouses = Warehouse.query.all()
876
    for warehouse in warehouses:
877
        if warehouse.shippingWarehouseId:
878
            shippingLocationIds[warehouse.shippingWarehouseId] = 1
879
 
880
    shippingLocations = []
881
    for shippingLocationId in shippingLocationIds:
882
        shippingLocations.append(get_Warehouse(shippingLocationId))
883
 
884
    return shippingLocations
885
 
886
def get_inventory_snapshot(warehouseId):
887
    query = CurrentInventorySnapshot.query
888
 
889
    if warehouseId:
890
        query = query.filter_by(warehouse_id = warehouseId)
891
 
892
    itemInventoryMap = {}
893
    for row in query.all():
894
        if not itemInventoryMap.has_key(row.item_id):
895
            itemInventoryMap[row.item_id] = []
896
 
897
        itemInventoryMap[row.item_id].append(row)
898
 
899
    return itemInventoryMap
900
 
901
def update_vendor_string(warehouseId, vendorString):
902
    warehouse = get_Warehouse(warehouseId)
903
    warehouse.vendorString = vendorString
904
    session.commit()
905
 
906
def __get_item_from_master(item_id):
907
    client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
5978 rajveer 908
    return client.getItem(item_id)
909
 
910
def __check_risky_item(item_id, source_id):
911
    ## We should get the list of strings which will identify to the catalog servers
912
    if source_id == 1:
913
        client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
914
        client.validateRiskyStatus(item_id)
915
    if source_id == 2:
916
        client = CatalogClient("catalog_service_server_host_hotspot", "catalog_service_server_port").get_client()
917
        client.validateRiskyStatus(item_id)
918
 
919
def __get_item_from_source(item_id, source_id):
920
    if source_id == 1:
921
        client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
922
        return client.getItem(item_id)
923
    if source_id == 2:
924
        client = CatalogClient("catalog_service_server_host_hotspot", "catalog_service_server_port").get_client()
6531 vikram.rag 925
        return client.getItem(item_id)
926
 
927
def get_monitored_warehouses_for_vendors(vendorIds):
928
    w = []
929
    for wh in Warehouse.query.filter_by(isAvailabilityMonitored = 1).all():
930
        if wh.vendor.id in (vendorIds):
931
            w.append(to_t_warehouse(wh).id)
932
    return w
933
def get_ignored_warehouseids_and_itemids():
934
    iw = []
935
    for i in IgnoredInventoryUpdateItems.query.all():
936
        iw.append(to_t_itemidwarehouseid(i)) 
937
    return iw
938
def insert_item_to_ignore_inventory_update_list(item_id,warehouse_id):
939
    try:
940
        ds_warehouse=IgnoredInventoryUpdateItems()
941
        ds_warehouse.item_id=item_id
942
        ds_warehouse.warehouse_id=warehouse_id
6532 amit.gupta 943
        clear_item_availability_cache(item_id)
6531 vikram.rag 944
        session.commit()
945
        return True
946
    except:
947
        return False       
948
def delete_item_from_ignore_inventory_update_list(item_id,warehouse_id):
949
    try:
950
        session.query(IgnoredInventoryUpdateItems).filter_by(item_id=item_id,warehouse_id=warehouse_id).delete()
6532 amit.gupta 951
        clear_item_availability_cache(item_id)
6531 vikram.rag 952
        session.commit()
953
        return True
954
    except:
955
        return False           
956
 
957
def get_all_ignored_inventoryupdate_items_count():
958
    return  session.query(func.count(distinct(IgnoredInventoryUpdateItems.item_id))).scalar()
959
 
960
def get_ignored_inventoryupdate_itemids(offset=0,limit=None):
961
    itemIds = session.query(distinct(IgnoredInventoryUpdateItems.item_id))
962
    '''if limit is not None:
963
        itemIds = itemIds.limit(limit)'''
964
    print itemIds.all()
965
    return [id for (id, ) in itemIds.all()]
6821 amar.kumar 966
 
967
def update_item_stock_purchase_params(item_id, numOfDaysStock, minStockLevel):
968
    if numOfDaysStock is None or minStockLevel is None:
969
        raise InventoryServiceException(108, "Bad params : numOfDaysStock = " + str(numOfDaysStock) + "minStockLevel = " + str(minStockLevel))
970
    itemStockPurchaseParams = ItemStockPurchaseParams.query.filter_by(item_id = item_id).first()
971
    if itemStockPurchaseParams is None:
972
        itemStockPurchaseParams = ItemStockPurchaseParams()
973
    itemStockPurchaseParams.item_id = item_id
974
    itemStockPurchaseParams.numOfDaysStock = numOfDaysStock
975
    itemStockPurchaseParams.minStockLevel = minStockLevel
976
    session.commit()
977
 
978
def get_item_stock_purchase_params(item_id):
979
    return ItemStockPurchaseParams.query.filter_by(item_id = item_id).first()
980
 
981
def add_oos_status_for_item(oosStatusMap, date):
982
 
983
    oosDate = to_py_date(date)
984
    oosDate.replace(second=0, microsecond=0)
985
 
986
    cartAdditionStartDate = oosDate - datetime.timedelta(days = 1)
987
 
988
    client = TransactionClient().get_client()
989
 
990
    #Gets physical orders in the last day
991
    orders = client.getPhysicalOrders(to_java_date(cartAdditionStartDate), to_java_date(oosDate))
992
 
993
    orderCountByItemId = {}
994
    for order in orders:
995
        if orderCountByItemId.has_key(order.lineitems[0].item_id):
996
            orderCountByItemId[order.lineitems[0].item_id] = orderCountByItemId[order.lineitems[0].item_id] + 1 
997
        else:
998
            orderCountByItemId[order.lineitems[0].item_id] = 1
999
 
1000
    for itemId, status in oosStatusMap.iteritems():
1001
        if OOSStatus.query.filter_by(item_id = itemId, date = oosDate).first() is None: 
1002
            oosStatus = OOSStatus()
1003
            oosStatus.item_id = itemId
1004
            oosStatus.date = oosDate
6832 amar.kumar 1005
            oosStatus.is_oos = status
6857 amar.kumar 1006
            order_count = 0
6821 amar.kumar 1007
            if status == False:
1008
                if orderCountByItemId.has_key(itemId):
1009
                    order_count = orderCountByItemId[itemId]
1010
            oosStatus.num_orders = order_count
1011
            session.commit()
1012
        else:
1013
            print "OOS Status already exists for ItemID:"+str(itemId)
1014
            """raise InventoryServiceException(101, "OOS Status already exists for ItemID:"+str(itemId) + " & Date:"+oosDate)"""
1015
 
6832 amar.kumar 1016
def get_oos_statuses_for_x_days_for_item(itemId, days):
1017
    timestamp = datetime.datetime.now()
1018
    timestamp = timestamp - datetime.timedelta(days = 6)
6857 amar.kumar 1019
    return OOSStatus.query.filter_by(item_id = itemId).filter(OOSStatus.date > timestamp).all()
1020
 
1021
def get_non_zero_item_stock_purchase_params():
1022
    return ItemStockPurchaseParams.query.filter(or_("numOfDaysStock!=0","minStockLevel!=0"))