Subversion Repositories SmartDukaan

Rev

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

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