Subversion Repositories SmartDukaan

Rev

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