Subversion Repositories SmartDukaan

Rev

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