Subversion Repositories SmartDukaan

Rev

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