Subversion Repositories SmartDukaan

Rev

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