Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
94 ashish 1
'''
2
Created on 23-Mar-2010
3
 
4
@author: ashish
5
'''
6
from elixir import *
7
from shop2020.model.v1.catalog.impl import DataService
122 ashish 8
from shop2020.model.v1.catalog.impl.DataService import Item, \
103 ashish 9
    Warehouse, ItemInventoryHistory, CurrentInventorySnapshot, ItemInfo,\
1368 chandransh 10
    ItemChangeLog, Category, EntityIDGenerator, VendorItemPricing,\
3557 rajveer 11
    VendorItemMapping, Vendor, SimilarItems, ProductNotification, Source, SourceItemPricing
122 ashish 12
from shop2020.thriftpy.model.v1.catalog.ttypes import \
2983 chandransh 13
    InventoryServiceException, status, ItemShippingInfo
2065 ankur.sing 14
from shop2020.model.v1.catalog.impl.Convertors import to_t_item,\
3557 rajveer 15
    to_t_vendor_item_pricing, to_t_source
94 ashish 16
import datetime
871 chandransh 17
import sys
2286 ankur.sing 18
from shop2020.utils.Utils import log_entry, to_py_date, log_risky_flag
621 chandransh 19
from sqlalchemy import desc, asc
3244 chandransh 20
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
1970 rajveer 21
from shop2020.model.v1.catalog.impl.CategoryManager import CategoryManager
3872 chandransh 22
from sqlalchemy.sql.expression import and_, or_, distinct, func
3086 rajveer 23
from string import Template
24
from shop2020.clients.HelperClient import HelperClient
3924 rajveer 25
import urllib2
26
from urllib2 import HTTPBasicAuthHandler
27
from shop2020.config.client.ConfigClient import ConfigClient
4318 rajveer 28
from shop2020.utils.EmailAttachmentSender import mail
4400 rajveer 29
from shop2020.clients.TransactionClient import TransactionClient
30
from shop2020.thriftpy.model.v1.order.ttypes import AlertType
94 ashish 31
 
32
def initialize():
33
    DataService.initialize()
34
 
3849 chandransh 35
def get_all_items_by_status(status, offset=0, limit=None):
36
    query = Item.query
37
    if status:
38
        query = query.filter_by(status=status)
39
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
40
    if limit:
41
        query = query.limit(limit)
42
    items = query.all()
43
    return items
44
 
45
def get_all_items(is_active, offset=0, limit=None):
103 ashish 46
    if is_active:
3849 chandransh 47
        items = get_all_items_by_status(status.ACTIVE, offset, limit)
103 ashish 48
    else:
3849 chandransh 49
        items = get_all_items_by_status(None, offset, limit)
766 rajveer 50
    return items
51
 
3849 chandransh 52
def get_item_count_by_status(use_status, status):
53
    if use_status:
54
        return Item.query.filter_by(status=status).count()
103 ashish 55
    else:
3849 chandransh 56
        return Item.query.count()
103 ashish 57
 
635 rajveer 58
def get_item(item_id):
766 rajveer 59
    item = Item.get_by(id=item_id)
60
    return item
94 ashish 61
 
635 rajveer 62
def get_items_by_catalog_id(catalog_id):
447 rajveer 63
    query = Item.query.filter_by(catalog_item_id=catalog_id)
437 rajveer 64
    try:
635 rajveer 65
        items = query.all()
66
        return get_thrift_item_list(items)
1399 rajveer 67
    except Exception as ex:
68
        print ex
437 rajveer 69
        raise InventoryServiceException(109, "Item not found")
70
 
576 chandransh 71
def is_active(item_id):
2983 chandransh 72
    t_item_shipping_info = ItemShippingInfo()
576 chandransh 73
    try:
635 rajveer 74
        item = get_item(item_id)
3281 chandransh 75
        t_item_shipping_info.isRisky = item.risky
4406 anupam.sin 76
        availability = __get_item_availability(item, None)
3281 chandransh 77
        if item.risky and availability <= 0 and item.status == status.ACTIVE:
78
            add_status_change_log(item, status.PAUSED_BY_RISK)
79
            item.status = status.PAUSED_BY_RISK
80
            item.status_description = "This item is currently out of stock"
81
            session.commit()
3924 rajveer 82
            #This will clear cache from tomcat
83
            __clear_homepage_cache()
2983 chandransh 84
        t_item_shipping_info.isActive = (item.status == status.ACTIVE)
3281 chandransh 85
        t_item_shipping_info.quantity = availability
576 chandransh 86
    except InventoryServiceException:
2983 chandransh 87
        print "[ERROR] Unexpected error:", sys.exc_info()[0]
88
    return t_item_shipping_info
89
 
2035 rajveer 90
def get_item_status_description(itemId):
91
    item = get_item(itemId)
92
    return item.status_description
563 chandransh 93
 
94 ashish 94
def get_Warehouse(warehouse_id):
95
    return Warehouse.get_by(id=warehouse_id)
96
 
4332 anupam.sin 97
def get_Vendor(vendorId):
98
    return Vendor.get_by(id=vendorId)
99
 
122 ashish 100
def get_all_warehouses_by_status(status):
101
    if not status:
766 rajveer 102
        warehouses = Warehouse.query.all()
122 ashish 103
    else:
851 chandransh 104
        warehouses = Warehouse.query.filter_by(status=status).all()
105
    return warehouses
122 ashish 106
 
94 ashish 107
def get_all_warehouses_for_item(item_id):
635 rajveer 108
    item = get_item(item_id)
94 ashish 109
    if not item:
122 ashish 110
        raise InventoryServiceException(108, "Some unforeseen error while obtaining item")
111
    return item.get_all_warehouses
94 ashish 112
 
122 ashish 113
def get_all_items_for_warehouse(warehouse_id):
114
    warehouse = get_Warehouse(warehouse_id)
115
    if not warehouse:
116
        raise InventoryServiceException(108, "bad warehouse")
117
    return warehouse.all_items
118
 
94 ashish 119
def add_warehouse(warehouse):
103 ashish 120
    if not warehouse:
122 ashish 121
        raise InventoryServiceException(108, "Bad warehouse")
103 ashish 122
    if get_Warehouse(warehouse.id):
123
        #warehouse is already present.
122 ashish 124
        raise InventoryServiceException(101, "Warehouse already present")
103 ashish 125
 
94 ashish 126
    ds_warehouse = Warehouse()
127
    ds_warehouse.id = warehouse.id
128
    ds_warehouse.location = warehouse.location
122 ashish 129
    ds_warehouse.status = status.ACTIVE
103 ashish 130
    ds_warehouse.addedOn = datetime.datetime.now()
483 rajveer 131
    ds_warehouse.lastCheckedOn = datetime.datetime.now()
132
    ds_warehouse.tinNumber = warehouse.tinNumber
133
    ds_warehouse.pincode = warehouse.pincode
134
    if warehouse.vendorString:
135
        ds_warehouse.vendorString = warehouse.vendorString
94 ashish 136
    session.commit()
103 ashish 137
    return ds_warehouse.id
94 ashish 138
 
122 ashish 139
def update_item(item):
140
    if not item:
141
        raise InventoryServiceException(108, "Bad item in request")
142
 
143
    if not item.id:
609 chandransh 144
        raise InventoryServiceException(101, "Missing id for update")
122 ashish 145
 
2120 ankur.sing 146
    validate_item_prices(item)
2065 ankur.sing 147
 
635 rajveer 148
    ds_item = get_item(item.id)
122 ashish 149
 
150
    if not ds_item:
609 chandransh 151
        raise InventoryServiceException(101, "Item missing in our database")
122 ashish 152
 
963 chandransh 153
    if item.productGroup:
154
        ds_item.product_group = item.productGroup 
155
    if item.brand:
156
        ds_item.brand = item.brand
511 rajveer 157
    if item.modelNumber:
158
        ds_item.model_number = item.modelNumber
2497 ankur.sing 159
    ds_item.color = item.color
160
    ds_item.model_name = item.modelName
161
    ds_item.category = item.category
162
    ds_item.comments = item.comments
511 rajveer 163
 
2497 ankur.sing 164
    ds_item.catalog_item_id = item.catalogItemId
483 rajveer 165
 
2129 ankur.sing 166
    ds_item.mrp = item.mrp
167
    ds_item.sellingPrice = item.sellingPrice
2497 ankur.sing 168
 
2174 ankur.sing 169
    ds_item.weight = item.weight
2129 ankur.sing 170
 
2358 ankur.sing 171
    if ds_item.status != item.itemStatus:
2402 rajveer 172
        add_status_change_log(ds_item, item.itemStatus)
2358 ankur.sing 173
        ds_item.status = item.itemStatus
2035 rajveer 174
    if item.status_description:
175
        ds_item.status_description = item.status_description
122 ashish 176
 
511 rajveer 177
    if item.startDate:
2116 ankur.sing 178
        ds_item.startDate = to_py_date(item.startDate)
2497 ankur.sing 179
    else:
180
        ds_item.startDate = None
511 rajveer 181
    if item.retireDate:
2116 ankur.sing 182
        ds_item.retireDate = to_py_date(item.retireDate)
2497 ankur.sing 183
    else:
184
        ds_item.retireDate = None
511 rajveer 185
 
2497 ankur.sing 186
    ds_item.feature_id = item.featureId
187
    ds_item.feature_description = item.featureDescription
122 ashish 188
 
2129 ankur.sing 189
    ds_item.bestDealText = item.bestDealText
190
    ds_item.bestDealValue = item.bestDealValue
2065 ankur.sing 191
    ds_item.bestSellingRank = item.bestSellingRank
2497 ankur.sing 192
 
2065 ankur.sing 193
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 194
    ds_item.risky = item.risky
3359 chandransh 195
 
3459 chandransh 196
    if item.expectedDelay is not None:
3359 chandransh 197
        ds_item.expectedDelay = item.expectedDelay
198
 
199
    if item.preferredWarehouse:
200
        ds_item.preferredWarehouse = item.preferredWarehouse
4413 anupam.sin 201
 
202
    if item.defaultWarehouse:
203
        ds_item.defaultWarehouse = item.defaultWarehouse
204
 
205
    ds_item.isWarehousePreferenceSticky = item.isWarehousePreferenceSticky
3359 chandransh 206
 
2347 ankur.sing 207
    ds_item.updatedOn = datetime.datetime.now()
2065 ankur.sing 208
 
122 ashish 209
    session.commit();
210
    return ds_item.id
94 ashish 211
 
2116 ankur.sing 212
def check_vendor_item_mapping(product_group, brand, model_number, color, vendor_id, vendor_category):
213
    key = product_group.strip().lower() + '|' + brand.strip().lower() + '|' + model_number.strip().lower() + '|' + color.strip().lower()
214
    try:
215
        vim = VendorItemMapping.query.filter_by(vendor_id=vendor_id, item_key=key, vendor_category=vendor_category).one()
216
        return True
217
    except:
218
        return False
219
 
103 ashish 220
def add_item(item):
221
    if not item:
122 ashish 222
        raise InventoryServiceException(108, "Bad item in request")
635 rajveer 223
    if get_item(item.id):
122 ashish 224
        raise InventoryServiceException(101, "Item already exists")
2120 ankur.sing 225
 
226
    validate_item_prices(item)
227
 
103 ashish 228
    ds_item = Item()
963 chandransh 229
    if item.productGroup:
230
        ds_item.product_group = item.productGroup
231
    if item.brand:
232
        ds_item.brand = item.brand
515 rajveer 233
    if item.modelName:
234
        ds_item.model_name = item.modelName
235
    if item.modelNumber:
236
        ds_item.model_number = item.modelNumber
609 chandransh 237
    if item.color:
238
        ds_item.color = item.color
2116 ankur.sing 239
    if item.hotspotCategory:
240
        ds_item.hotspotCategory = item.hotspotCategory
241
        if item.hotspotCategory == 'Handsets':
2403 ankur.sing 242
            ds_item.preferredWarehouse = 1
2116 ankur.sing 243
        else:
2403 ankur.sing 244
            ds_item.preferredWarehouse = 2
2116 ankur.sing 245
 
483 rajveer 246
    if item.category:
247
        ds_item.category = item.category
248
    if item.comments:
249
        ds_item.comments = item.comments
250
 
103 ashish 251
    ds_item.addedOn = datetime.datetime.now()
609 chandransh 252
    ds_item.updatedOn = datetime.datetime.now()
2116 ankur.sing 253
    if item.startDate:
254
        ds_item.startDate = to_py_date(item.startDate)
255
    if item.retireDate:
256
        ds_item.retireDate = to_py_date(item.retireDate)
609 chandransh 257
 
483 rajveer 258
    if item.mrp:
259
        ds_item.mrp = item.mrp
260
    if item.sellingPrice:
261
        ds_item.sellingPrice = item.sellingPrice
122 ashish 262
    if item.weight:
263
        ds_item.weight = item.weight
264
 
265
    if item.featureId:
266
        ds_item.feature_id = item.featureId
267
    if item.featureDescription:
268
        ds_item.feature_description = item.featureDescription
269
 
103 ashish 270
    if item.otherInfo:
271
        for k,v in item.otherInfo.iteritems():
272
            info = ItemInfo()
273
            info.key = k
274
            info.value = v
275
            ds_item.iteminfo.append(info)
2116 ankur.sing 276
 
103 ashish 277
    #check if categories present. If yes, add them to system
122 ashish 278
 
609 chandransh 279
    if item.bestDealValue:
280
        ds_item.bestDealValue = item.bestDealValue
281
    if item.bestDealText:
282
        ds_item.bestDealText = item.bestDealText
2116 ankur.sing 283
    if item.bestSellingRank:
284
        ds_item.bestSellingRank = item.bestSellingRank
285
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 286
    ds_item.risky = item.risky
609 chandransh 287
 
3467 chandransh 288
    if item.expectedDelay is not None:
3359 chandransh 289
        ds_item.expectedDelay = item.expectedDelay
3467 chandransh 290
    else:
291
        ds_item.expectedDelay = 0
3359 chandransh 292
 
293
    if item.preferredWarehouse:
294
        ds_item.preferredWarehouse = item.preferredWarehouse
295
 
2116 ankur.sing 296
    # Check if a similar item already exists in our database
297
    similar_item = Item.query.filter_by(product_group=item.productGroup, brand = item.brand, model_number=item.modelNumber, hotspotCategory=item.hotspotCategory).first()
298
    print "[SIMILAR ITEM FOUND:] FOR {0} {1} {2} {3} {4}".format(item.productGroup, item.brand, item.modelNumber, item.hotspotCategory, item.color)
299
 
300
    if similar_item is None or similar_item.catalog_item_id is None:
301
        # If there is no similar item in the database from before,
302
        # use the entity_id_generator
303
        entity_id = EntityIDGenerator.query.first()
304
        ds_item.catalog_item_id = entity_id.id + 1
305
        ds_item.status = status.IN_PROCESS
306
        ds_item.status_description = "This item is in process."
307
        entity_id.id = entity_id.id  + 1
308
    else:
309
        #If a similar item already exists for a product group, brand and model_number, set it as same.
310
        ds_item.catalog_item_id = similar_item.catalog_item_id
311
        ds_item.category = similar_item.category
312
        ds_item.status = similar_item.status
313
        ds_item.status_description = similar_item.status_description
314
 
103 ashish 315
    session.commit();
3325 chandransh 316
    return ds_item.id
317
 
318
def update_inventory_history(warehouse_id, timestamp, availability):
319
    warehouse = get_Warehouse(warehouse_id)
320
    if not warehouse:
321
        raise InventoryServiceException(107, "Warehouse? Where?")
4368 rajveer 322
    vendors = get_vendors_for_warehouse(warehouse_id)
323
    if len(vendors) > 1:
324
        raise InventoryServiceException(110, "Multiple vendors found for warehouse !")
325
    vendor = vendors[0]
3325 chandransh 326
    time = datetime.datetime.now()
327
    for item_key, quantity in availability.iteritems():
328
        try:
329
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
330
            item = vendor_item_mapping.item
331
        except:
332
            continue  
333
        try:
334
            item_inventory_history = ItemInventoryHistory()
335
            item_inventory_history.warehouse = warehouse
336
            item_inventory_history.item = item
337
            item_inventory_history.timestamp = time
338
            item_inventory_history.availibility = quantity
339
        except:
340
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
341
    session.commit()
103 ashish 342
 
483 rajveer 343
def update_inventory(warehouse_id, timestamp, availability):
344
    warehouse = get_Warehouse(warehouse_id)
345
    if not warehouse:
346
        raise InventoryServiceException(107, "Warehouse? Where?")
347
 
348
    time = datetime.datetime.now()
349
    warehouse.lastCheckedOn = time
350
    warehouse.vendorString = timestamp
4368 rajveer 351
    vendors = get_vendors_for_warehouse(warehouse_id)
352
    if len(vendors) > 1:
353
        raise InventoryServiceException(110, "Multiple vendors found for warehouse !")
354
    vendor = vendors[0]
2368 ankur.sing 355
    session.commit()
1368 chandransh 356
    for item_key, quantity in availability.iteritems():
483 rajveer 357
        try:
1368 chandransh 358
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
359
            item = vendor_item_mapping.item
494 rajveer 360
        except:
361
            continue  
362
        try:
483 rajveer 363
            current_inventory_snapshot = CurrentInventorySnapshot.get_by(item=item, warehouse=warehouse)
364
            if not current_inventory_snapshot:
365
                current_inventory_snapshot = CurrentInventorySnapshot()
366
                current_inventory_snapshot.item = item
367
                current_inventory_snapshot.warehouse = warehouse
368
                current_inventory_snapshot.availibility = 0
871 chandransh 369
                current_inventory_snapshot.reserved = 0
483 rajveer 370
            # added the difference in the current inventory    
371
            current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
4400 rajveer 372
            try:
373
                if quantity > 0 and __get_item_reserved(item) > 0:
374
                    cl = TransactionClient().get_client()
375
                    cl.addAlert(AlertType.NEW_INVENTORY_ALERT, "Inventory received for item " + item.brand + item.model_name + item.model_number)
376
            except:
377
                print "Not able to raise alert for incoming inventory" 
483 rajveer 378
        except:
379
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
2368 ankur.sing 380
        session.commit() 
381
        check_risky_item(item)
483 rajveer 382
 
4320 rajveer 383
def add_inventory(itemId, warehouseId, quantity):
384
    current_inventory_snapshot = CurrentInventorySnapshot.get_by(item_id=itemId, warehouse_id=warehouseId)
385
    if not current_inventory_snapshot:
386
        current_inventory_snapshot = CurrentInventorySnapshot()
387
        current_inventory_snapshot.item_id = itemId
388
        current_inventory_snapshot.warehouse_id = warehouseId
389
        current_inventory_snapshot.availibility = 0
390
        current_inventory_snapshot.reserved = 0
391
    # added the difference in the current inventory    
392
    current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
393
    session.commit() 
394
 
4431 phani.kuma 395
'''
94 ashish 396
def get_item_inventoy(item_id):
397
 
398
    inventory = Item.get_by(id=item_id).currentInventory
399
    if not inventory:
122 ashish 400
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
94 ashish 401
    return inventory
4431 phani.kuma 402
'''
94 ashish 403
 
635 rajveer 404
def get_item_inventory_by_item_id(item_id):
405
    inventory = Item.get_by(id=item_id).currentInventory
379 ashish 406
    if not inventory:
407
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
408
    return inventory
409
 
103 ashish 410
 
411
def retire_warehouse(warehouse_id):
412
    if not warehouse_id:
122 ashish 413
        raise InventoryServiceException(101, "Bad warehouse id")
103 ashish 414
    warehouse = get_Warehouse(warehouse_id)
415
    if not warehouse:
122 ashish 416
        raise InventoryServiceException(108, "warehouse id not present")
417
    warehouse.status = status.DELETED;
103 ashish 418
    session.commit()
419
 
420
def retire_item(item_id):
421
    if not item_id:
122 ashish 422
        raise InventoryServiceException(101, "bad item id")
635 rajveer 423
    item = get_item(item_id)
103 ashish 424
    if not item:
122 ashish 425
        raise InventoryServiceException(108, "item id not present")
426
    item.status = status.PHASED_OUT
427
    item.retireDate = datetime.datetime.now()
103 ashish 428
    session.commit()
122 ashish 429
 
430
#need to implement threads based solution here
103 ashish 431
def start_item_on(item_id, timestamp):
432
    if not item_id:
122 ashish 433
        raise InventoryServiceException(101, "bad item id")
635 rajveer 434
    item = get_item(item_id)
103 ashish 435
    if not item:
122 ashish 436
        raise InventoryServiceException(108, "item id not present")
103 ashish 437
 
122 ashish 438
    item.status = status.ACTIVE
439
    item.startDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
440
    add_status_change_log(item, status.ACTIVE)
103 ashish 441
    session.commit()
442
 
122 ashish 443
#need to implement threads here
103 ashish 444
def retire_item_on(item_id, timestamp):
445
    if not item_id:
122 ashish 446
        raise InventoryServiceException(101, "bad item id")
635 rajveer 447
    item = get_item(item_id)
103 ashish 448
    if not item:
122 ashish 449
        raise InventoryServiceException(108, "item id not present")
103 ashish 450
 
122 ashish 451
    item.status = status.PHASED_OUT
452
    item.retireDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
453
    add_status_change_log(item, status.PHASED_OUT)
103 ashish 454
    session.commit()
455
 
456
def add_status_change_log(item, new_status):
457
    item_change_log = ItemChangeLog()
458
    item_change_log.new_status = new_status
459
    item_change_log.old_status = item.status
460
    item_change_log.timestamp = datetime.datetime.now()
461
    item_change_log.item = item
462
    session.commit()
463
 
464
def change_item_status(item_id, new_status):
465
    if not item_id:
122 ashish 466
        raise InventoryServiceException(101, "bad item id")
635 rajveer 467
    item = get_item(item_id)
103 ashish 468
    if not item:
122 ashish 469
        raise InventoryServiceException(108, "item id not present")
2116 ankur.sing 470
    add_status_change_log(item, new_status)
122 ashish 471
    item.status = new_status
2251 ankur.sing 472
    if item.status == status.PHASED_OUT:
473
        item.status_description = "This item has been phased out"
474
    elif item.status == status.DELETED:
475
        item.status_description = "This item has been deleted"
3924 rajveer 476
    elif item.status == status.PAUSED:
477
        item.status_description = "This item is currently out of stock"      
478
    elif item.status == status.PAUSED_BY_RISK:
479
        item.status_description = "This item is currently out of stock"
480
        #This will clear cache from tomcat
481
        __clear_homepage_cache()  
2251 ankur.sing 482
    elif item.status == status.ACTIVE:
483
        item.status_description = "This item is active"
484
    elif item.status == status.IN_PROCESS:
485
        item.status_description = "This item is in process"
486
    elif item.status == status.CONTENT_COMPLETE:
487
        item.status_description = "This item is in process"
103 ashish 488
    session.commit()
489
 
490
def get_item_availability_for_warehouse(warehouse_id, item_id):
491
    if not warehouse_id:
122 ashish 492
        raise InventoryServiceException(101, "bad warehouse_id")
103 ashish 493
    if not item_id:
122 ashish 494
        raise InventoryServiceException(101, "bad item_id")
103 ashish 495
 
496
    warehouse = get_Warehouse(warehouse_id)
497
    if not warehouse:
122 ashish 498
        raise InventoryServiceException(108, "warehouse does not exist")
635 rajveer 499
    item = get_item(item_id)
504 rajveer 500
 
103 ashish 501
    if not item:
766 rajveer 502
        raise InventoryServiceException(108, "item does not exist")
122 ashish 503
 
494 rajveer 504
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id)
504 rajveer 505
    query = query.filter_by(item_id = item.id)
494 rajveer 506
    try:
507
        current_inventory_snapshot = query.one()
871 chandransh 508
        return current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
494 rajveer 509
    except:
510
        return 0
511
    """
512
    current_inventory_snapshot = CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id == warehouse_id, CurrentInventorySnapshot.item_id == item_id).one()
103 ashish 513
    if not current_inventory_snapshot:
514
        return 0
515
    else:
516
        return current_inventory_snapshot.availibility
494 rajveer 517
    """
643 chandransh 518
 
2368 ankur.sing 519
def check_risky_item(item):
2251 ankur.sing 520
    if not item.risky:
521
        return
4406 anupam.sin 522
    availability = __get_item_availability(item, None)
2983 chandransh 523
    if availability <= 0:
2251 ankur.sing 524
        if item.status == status.ACTIVE:
2984 rajveer 525
            change_item_status(item.id, status.PAUSED_BY_RISK)
4318 rajveer 526
            try:
4374 rajveer 527
                mail("cnc.center@shop2020.in", "5h0p2o2o", ["chaitnaya.vats@shop2020.in", "abhishek.mathur@shop2020.in"], "Item is out of stock. ID: " + str(item.id)  + " " + item.brand +  " " + item.model_name + " " + item.model_number, " ", [])
4318 rajveer 528
            except:
529
                print "Unable to send the report"
2251 ankur.sing 530
    else:
2984 rajveer 531
        if item.status == status.PAUSED_BY_RISK:
2251 ankur.sing 532
            change_item_status(item.id, status.ACTIVE)
2368 ankur.sing 533
    session.commit()
2251 ankur.sing 534
 
4406 anupam.sin 535
'''
536
This method returns quantity of a particular item across all warehouses whose ids is provided
537
if warehouse_ids is null it checks for inventory in all warehouses.
538
'''
539
def __get_item_availability(item, warehouse_ids):
540
    if warehouse_ids is None:
541
        all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
542
        availability = 0
543
        reserved = 0
544
        for currInv in all_inventory:
545
            availability = availability + currInv.availibility
546
            reserved = reserved + currInv.reserved
547
        return availability - reserved
548
    else:
549
        total_availability = 0
550
        for warehouse_id in warehouse_ids:
551
            try:
552
                current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item.id).one()
553
                availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
554
            except Exception as e:
555
                print e
556
                availability = 0    
557
            total_availability = total_availability + availability
558
        return total_availability 
4400 rajveer 559
 
560
def __get_item_reserved(item):
561
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
562
    reserved = 0
563
    for currInv in all_inventory:
564
        reserved = reserved + currInv.reserved
565
    return reserved
2983 chandransh 566
 
871 chandransh 567
def reserve_item_in_warehouse(item_id, warehouse_id, quantity):    
568
    if not warehouse_id:
569
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 570
    item = get_item(item_id)
571
    if not item:
871 chandransh 572
        raise InventoryServiceException(101, "bad item_id")
573
 
574
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
575
    try:
576
        current_inventory_snapshot = query.one()
577
    except:
4103 chandransh 578
        current_inventory_snapshot = CurrentInventorySnapshot()
579
        current_inventory_snapshot.warehouse_id = warehouse_id
580
        current_inventory_snapshot.item_id = item_id
581
        current_inventory_snapshot.availibility = 0
582
        current_inventory_snapshot.reserved = 0
583
 
584
    current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
585
    session.commit()
586
    check_risky_item(item)
587
    return True
871 chandransh 588
 
589
def reduce_reservation_count(item_id, warehouse_id, quantity):
590
    if not warehouse_id:
591
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 592
    item = get_item(item_id)
593
    if not item:
871 chandransh 594
        raise InventoryServiceException(101, "bad item_id")
595
 
596
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
597
    try:
598
        current_inventory_snapshot = query.one()
599
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
4318 rajveer 600
        ##FIXME In case of our own warehouse reduce availability also
601
        if warehouse_id == 7:
4335 rajveer 602
            current_inventory_snapshot.availibility = current_inventory_snapshot.availibility - quantity
871 chandransh 603
        session.commit()
2368 ankur.sing 604
        check_risky_item(item)
871 chandransh 605
        return True
606
    except:
607
        print "Unexpected error:", sys.exc_info()[0]
608
        return False
609
 
2075 rajveer 610
def mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):
2828 rajveer 611
    '''
612
    Get all the items for this entityID and update category, brand, modelName and modelNumber for all.
613
    Update Status for only IN_PROCESS items to CONTENT_COMPLETE
614
    '''
723 chandransh 615
    content_complete_status = status.CONTENT_COMPLETE
2828 rajveer 616
    items = Item.query.filter_by(catalog_item_id=entity_id).all()
723 chandransh 617
    current_timestamp = datetime.datetime.now()
618
    for item in items:
2828 rajveer 619
        if item.status == status.IN_PROCESS:
620
            item.status = content_complete_status
621
            item_change_log = ItemChangeLog()
622
            item_change_log.old_status = item.status
623
            item_change_log.new_status = content_complete_status
624
            item_change_log.timestamp = current_timestamp
625
            item_change_log.item = item
723 chandransh 626
 
2075 rajveer 627
        item.category = category
628
        item.brand = brand
2081 rajveer 629
        item.model_name = modelName
630
        item.model_number = modelNumber
723 chandransh 631
        item.updatedOn = current_timestamp
632
    session.commit()
633
    return True
1294 chandransh 634
 
643 chandransh 635
def get_item_availability_for_location(warehouse_loc, item_id):
3355 chandransh 636
    """
637
    Determines the warehouse that should be used to fulfil an order for the given item.
4406 anupam.sin 638
    It first checks whether the preferred warehouse for that item is set or not. If set 
639
    and preference is sticky then that warehouse is used for fulfilment.
640
    If preference is not sticky then we see if item is available in the preferred WH,
641
    in which case that warehouse is used otherwise we use that warehouse which has the max
642
    availability. And if there is no inventory for that item in any warehouses then we use
643
    default warehouse.
644
    If preference is not set in that case we just find the warehouse with max availability
645
    and in case of zero inventory we use default warehouse
3355 chandransh 646
 
647
    Returns an ordered list of size 4 with following elements in the given order:
648
    1. Logistics location of the warehouse which was finally picked up to ship the order.
649
    2. Id of the warehouse which was finally picked up.
650
    3. Inventory size in the selected warehouse.
651
    4. Expected delay added by the category manager.
652
 
653
    Parameters:
654
     - warehouse_loc
655
     - item_id
656
    """
643 chandransh 657
    if warehouse_loc is None:
658
        raise InventoryServiceException(101, "Bad Warehouse Location")
659
    if not item_id:
1416 chandransh 660
        raise InventoryServiceException(101, "Bad Item id")
643 chandransh 661
 
1416 chandransh 662
    item = Item.get_by(id=item_id)
4406 anupam.sin 663
    logisticsLocation = warehouse_loc
664
    warehouses = Warehouse.query.filter_by(logisticsLocation=logisticsLocation).all()
643 chandransh 665
    warehouse_ids = [warehouse.id for warehouse in warehouses]
666
    warehouse_retid = -1
4406 anupam.sin 667
 
3503 chandransh 668
    total_availability = 0
4406 anupam.sin 669
    '''
670
    If warehouse preference is set and it is sticky then we should fulfil this order from this warehouse only.
671
    But we still need to calculate total availability across warehouses.
672
    '''
673
    if (item.isWarehousePreferenceSticky and item.preferredWarehouse is not None) :
674
        warehouse_retid = item.preferredWarehouse
675
        warehouse = Warehouse.get_by(id=warehouse_retid)
676
        logisticsLocation = warehouse.logisticsLocation
677
        total_availability = __get_item_availability(item, warehouse_ids)
678
 
679
    #If preference is not sticky then this order should be fulfilled from preferred WH if inventory available
680
    #otherwise we should check for its availability elsewhere and fulfil this order from there, but if it is not available anywhere
681
    #then we should fulfil this order from its default warehouse.
682
 
683
    elif (not item.isWarehousePreferenceSticky and item.preferredWarehouse is not None) :
785 rajveer 684
        try:
4406 anupam.sin 685
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = item.preferredWarehouse, item_id = item_id).one()
871 chandransh 686
            availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 687
        except Exception as e:
688
            print e
785 rajveer 689
            availability = 0    
4406 anupam.sin 690
        if availability > 0:
691
            warehouse_retid = item.preferredWarehouse
692
            total_availability = __get_item_availability(item, warehouse_ids)
693
        else :
694
            [logisticsLocation, warehouse_retid, total_availability] = \
695
                        __get_warehouse_with_max_availability(warehouse_loc = warehouse_loc, \
696
                                                            warehouse_ids = warehouse_ids, item = item)
697
 
698
    else :
699
        [logisticsLocation, warehouse_retid, total_availability] = \
700
                        __get_warehouse_with_max_availability(warehouse_loc = warehouse_loc, \
701
                                                            warehouse_ids = warehouse_ids, item = item)
2341 chandransh 702
 
4406 anupam.sin 703
    if item.expectedDelay is None:
704
        print 'expectedDelay field for this item was Null. Resetting it to 0'
705
        item.expectedDelay = 0
706
 
707
    ## FIXME Assign warehouse 5 (9D2) for all the hotspot products.
708
    #if warehouse_retid in [warehouse.id for warehouse in get_warehouses_for_vendor(1)]:
4433 anupam.sin 709
    if int(warehouse_retid) in [1,2,3,4,5]:
4406 anupam.sin 710
        warehouse_retid = 5
711
        warehouse = Warehouse.get_by(id=warehouse_retid)
712
        logisticsLocation = warehouse.logisticsLocation  
713
 
714
    return [logisticsLocation, int(warehouse_retid), total_availability, int(item.expectedDelay)]
715
 
716
def __get_warehouse_with_max_availability(warehouse_loc, warehouse_ids, item):
717
 
718
    warehouse_retid = -1
719
    max_availability = 0
720
    total_availability = 0
721
 
722
    for warehouse_id in warehouse_ids:
723
            try:
724
                current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item.id).one()
725
                availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
726
            except Exception as e:
727
                print e
728
                availability = 0    
729
            if availability > max_availability:
730
                warehouse_retid = warehouse_id
731
                max_availability = availability
732
            total_availability = total_availability + availability
733
 
734
    #If no warehouse could be found, use the default warehouse for this item
643 chandransh 735
    if warehouse_retid == -1:
759 chandransh 736
        # This is the case when all warehouses have exhausted their
737
        # inventory of this item or no warehouse is available in this
738
        # location.
4406 anupam.sin 739
        warehouse_retid = int(item.defaultWarehouse)
2344 chandransh 740
        warehouse = Warehouse.get_by(id=warehouse_retid)
4406 anupam.sin 741
        warehouse_loc = warehouse.logisticsLocation
2341 chandransh 742
        try:
4406 anupam.sin 743
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item.id).one()
3503 chandransh 744
            max_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 745
        except Exception as e:
746
            print e
3503 chandransh 747
            max_availability = 0
748
        total_availability = max_availability
643 chandransh 749
 
4406 anupam.sin 750
    return [warehouse_loc, warehouse_retid, total_availability]
751
'''    
752
def calculate_total_availability(warehouse_ids, item_id):
753
    total_availability = 0
754
    for warehouse_id in warehouse_ids:
755
            try:
756
                current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
757
                availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
758
            except Exception as e:
759
                print e
760
                availability = 0    
761
            total_availability = total_availability + availability
762
    return total_availability
763
'''
2341 chandransh 764
 
122 ashish 765
def get_warehouses_for_item(item_id):
643 chandransh 766
 
122 ashish 767
    if not item_id:
768
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 769
    item = get_item(item_id)
122 ashish 770
 
771
    if not item:
772
        raise InventoryServiceException(101, "bad item")
773
 
483 rajveer 774
    warehouses = item.currentInventory.warehouse
501 rajveer 775
    return warehouses
776
 
2404 chandransh 777
def get_child_categories(category):
778
    cm = CategoryManager()
2621 varun.gupt 779
    cat = cm.getCategory(category)
780
    return cat.children_category_ids if cat else None
2404 chandransh 781
 
626 chandransh 782
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 783
    '''
784
    Returns the Best Sellers between the start and the stop index in the given category
785
    '''
1926 rajveer 786
    query = get_best_sellers_query(category, None)
1098 chandransh 787
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 788
    return get_thrift_item_list(best_sellers)
789
 
2093 chandransh 790
def get_best_sellers_count(category=-1):
2404 chandransh 791
    '''
792
    Returns the number of best sellers in the given category
793
    '''
1926 rajveer 794
    count = get_best_sellers_query(category, None).count()
1120 rajveer 795
    if count is None:
796
        count = 0
766 rajveer 797
    return count
621 chandransh 798
 
1926 rajveer 799
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 800
    '''
801
    Returns the Best sellers for the given brand and category between the start and the stop index.
802
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
803
    '''
1926 rajveer 804
    query = get_best_sellers_query(category, brand)
1098 chandransh 805
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 806
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 807
 
1926 rajveer 808
def get_best_sellers_query(category, brand):
2404 chandransh 809
    '''
810
    Returns the query to be used for getting Best Sellers.
811
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
812
    '''
1098 chandransh 813
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 814
    if category != -1:
1970 rajveer 815
        all_categories = [category]
816
        child_categories = get_child_categories(category)
817
        if child_categories is not None:
818
            all_categories = all_categories + child_categories 
819
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 820
    if brand is not None:
821
        query = query.filter_by(brand=brand)
1098 chandransh 822
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 823
    return query
609 chandransh 824
 
1098 chandransh 825
def get_best_deals(category=-1):
2404 chandransh 826
    '''
827
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
828
    '''
829
    query = get_best_deals_query(Item, category, None)
1098 chandransh 830
    items = query.all()
609 chandransh 831
    return get_thrift_item_list(items)
832
 
1098 chandransh 833
def get_best_deals_count(category=-1):
2404 chandransh 834
    '''
835
    Returns the count of best deals in the given category.
836
    Ignores the category if it's -1.
837
    '''
838
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 839
    if count is None:
840
        count = 0
766 rajveer 841
    return count
501 rajveer 842
 
1926 rajveer 843
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 844
    '''
845
    Returns the catalog_item_ids of best deal items for the given brand and category.
846
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
847
    '''
848
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 849
    best_deal_items = query.all()[start_index:stop_index]
850
    return [item.catalog_item_id for item in best_deal_items]
851
 
2404 chandransh 852
def get_best_deals_counting_query(obj, category, brand):
853
    '''
854
    Returns the query to be used to select the best deals in the given brand and category.
855
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
856
    '''
857
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 858
    if category != -1:
1970 rajveer 859
        all_categories = [category]
860
        child_categories = get_child_categories(category)
861
        if child_categories is not None:
862
            all_categories = all_categories + child_categories 
863
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 864
    if brand is not None:
865
        query = query.filter_by(brand=brand)
2404 chandransh 866
    return query
867
 
868
def get_best_deals_query(obj, category, brand):
869
    '''
870
    Returns the query to be used to get the best deals in the given category and brand.
871
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
872
    '''
873
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 874
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
875
    return query
609 chandransh 876
 
1098 chandransh 877
def get_latest_arrivals(limit, category=-1):
2404 chandransh 878
    '''
879
    Returns up to limit number of Latest Arrivals in the given category.
880
    '''
2975 chandransh 881
    categories = []
882
    if category != -1:
883
        categories = [category]
884
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 885
    items = query.all()[0:limit]
609 chandransh 886
    return get_thrift_item_list(items)
598 chandransh 887
 
1098 chandransh 888
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 889
    '''
890
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 891
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 892
    '''
2975 chandransh 893
    categories = []
894
    if category != -1:
895
        categories = [category]
896
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 897
    if count is None:
898
        count = 0
899
    count = min(count, limit)
766 rajveer 900
    return count
602 chandransh 901
 
2975 chandransh 902
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 903
    '''
904
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 905
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 906
    '''
2975 chandransh 907
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 908
    latest_arrivals = query.all()[start_index:stop_index]
909
    return [item.catalog_item_id for item in latest_arrivals]
910
 
2975 chandransh 911
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 912
    '''
913
    Returns the query to be used to count Latest arrivals.
3016 chandransh 914
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 915
    '''
916
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 917
 
918
    all_categories = []
919
    for category in categories:
920
        all_categories.append(category)
1970 rajveer 921
        child_categories = get_child_categories(category)
2975 chandransh 922
        if child_categories:
923
            all_categories = all_categories + child_categories
924
    if all_categories: 
1970 rajveer 925
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 926
 
1926 rajveer 927
    if brand is not None:
928
        query = query.filter_by(brand=brand)
2404 chandransh 929
    return query
930
 
2975 chandransh 931
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 932
    '''
933
    Returns the query to be used to retrieve Latest Arrivals.
934
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
935
    '''
2975 chandransh 936
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 937
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
938
    return query
609 chandransh 939
 
940
def get_thrift_item_list(items):
1098 chandransh 941
    return [to_t_item(item) for item in items if item != None]
635 rajveer 942
 
1155 rajveer 943
def generate_new_entity_id():
944
    generator =  EntityIDGenerator.query.one()
945
    id = generator.id + 1
946
    generator.id = id
947
    session.commit()
948
    return id
949
 
635 rajveer 950
def put_category_object(object):
951
    category = Category.get_by(id=1)
952
    if category is None:
953
        category = Category()
954
    category.object = object    
955
    session.commit()
956
    return True
957
 
958
def get_category_object():
766 rajveer 959
    object = Category.get_by(id=1).object
960
    return object
961
 
4283 anupam.sin 962
def get_item_pricing(item_id, vendorId):
1341 chandransh 963
    item = Item.query.filter_by(id=item_id).first()
964
    if item is None:
965
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 966
    '''
967
    if vendor id is -1 then we calculate an average transfer price to be populated
968
    at the time of order creation. This will be later updated with actual transfer price
969
    at the time of billing.
970
    '''
971
    if(vendorId == -1):
972
        try:
973
            item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 974
            if item_pricings:
4307 anupam.sin 975
                for item_pricing in item_pricings:
4315 anupam.sin 976
                    total =+ item_pricing.transfer_price
977
                avg = total / len(item_pricings)
978
                item_pricing.transfer_price = avg
979
                return item_pricing
4307 anupam.sin 980
        except:
981
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 982
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 983
    try:
984
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 985
        return item_pricing
3244 chandransh 986
    except MultipleResultsFound:
1341 chandransh 987
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 988
    except NoResultFound:
1341 chandransh 989
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
990
 
1970 rajveer 991
def add_category(t_category):
992
    category = Category.get_by(id=t_category.id)
993
    if category is None:
994
        category = Category()
995
    category.id = t_category.id 
996
    category.label = t_category.label
997
    category.description = t_category.description
998
    category.parent_category_id = t_category.parent_category_id 
999
    session.commit()
1000
    return True
1001
 
1002
def get_category(id):
1003
    return Category.query.filter_by(id=id).first()
1004
 
1005
def get_all_categories():
1006
    return Category.query.all()
1007
 
1991 ankur.sing 1008
 
1009
def get_all_item_pricing(item_id):
1010
    item = Item.query.filter_by(id=item_id).first()
1011
    if item is None:
1012
        raise InventoryServiceException(101, "Bad Item")
1013
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
1014
    return item_pricing
1015
 
2116 ankur.sing 1016
def get_item_mappings(item_id):
1017
    item = Item.query.filter_by(id=item_id).first()
1018
    if item is None:
1019
        raise InventoryServiceException(101, "Bad Item")
1020
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
1021
    return item_mappings
1022
 
1023
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 1024
    if not vendorItemPricing:
1025
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
1026
    vendorId = vendorItemPricing.vendorId
1027
    itemId = vendorItemPricing.itemId
1028
 
1029
    try:
1030
        vendor = Vendor.query.filter_by(id=vendorId).one()
1031
    except:
1032
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
1033
 
1034
    try:
1035
        item = Item.query.filter_by(id=itemId).one()
1036
    except:
1037
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
1038
 
2120 ankur.sing 1039
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 1040
 
1991 ankur.sing 1041
    try:
1042
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
1043
    except:
2116 ankur.sing 1044
        ds_vendorItemPricing = VendorItemPricing()
1045
        ds_vendorItemPricing.vendor = vendor
1046
        ds_vendorItemPricing.item = item
1991 ankur.sing 1047
 
1048
    if vendorItemPricing.mop:
1049
        ds_vendorItemPricing.mop = vendorItemPricing.mop
1050
    if vendorItemPricing.dealerPrice:
1051
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
1052
    if vendorItemPricing.transferPrice:
2065 ankur.sing 1053
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 1054
 
1055
    session.commit()
1056
    return
1057
 
2358 ankur.sing 1058
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 1059
    if not vendorItemMapping:
1060
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
1061
    vendorId = vendorItemMapping.vendorId
1062
    itemId = vendorItemMapping.itemId
1063
 
1064
    try:
1065
        vendor = Vendor.query.filter_by(id=vendorId).one()
1066
    except:
1067
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
1068
 
1069
    try:
1070
        item = Item.query.filter_by(id=itemId).one()
1071
    except:
1072
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
1073
 
1074
    try:
2358 ankur.sing 1075
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 1076
    except:
1077
        ds_vendorItemMapping = VendorItemMapping()
1078
        ds_vendorItemMapping.vendor = vendor
1079
        ds_vendorItemMapping.item = item
2497 ankur.sing 1080
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 1081
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
1082
 
1083
    session.commit()
1084
    return
1085
 
2120 ankur.sing 1086
def validate_item_prices(item):
2129 ankur.sing 1087
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
1088
        return
1089
    if item.mrp < item.sellingPrice:
2120 ankur.sing 1090
        print "[BAD MRP and SP:] for {0} {1} {2} {3}. MRP={4}, SP={5}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(item.mrp), str(item.sellingPrice))
1091
        raise InventoryServiceException(101, "[BAD MRP and SP:] for {0} {1} {2} {3}. MRP={4}, SP={5}".format(item.productGroup, item.brand, item.modelNumber, item.color, str(item.mrp), str(item.sellingPrice)))
2065 ankur.sing 1092
    return
2120 ankur.sing 1093
 
1094
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 1095
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 1096
        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))
1097
        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)))
1098
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
1099
        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))
1100
        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)))
1101
    return
2065 ankur.sing 1102
 
1103
def get_all_vendors():
1104
    return Vendor.query.all()
1105
 
2116 ankur.sing 1106
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 1107
    query = Item.query
2428 ankur.sing 1108
    query = query.filter_by(product_group=product_group)
1109
    query = query.filter_by(brand=brand)
1110
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 1111
    if color:
1112
        query = query.filter_by(color=color)
1113
    item = query.first()
2116 ankur.sing 1114
    if item is None:
1115
        return 0
1116
    else:
1117
        return item.id
2286 ankur.sing 1118
 
1119
def change_risky_flag(item_id, risky):
1120
    item = get_item(item_id)
1121
    if not item:
1122
        raise InventoryServiceException(101, "Item missing in our database")
1123
    try:
1124
        log_risky_flag(item_id, risky)
1125
    except:
1126
        print "Not able to log risky flag change"
1127
    item.risky = risky
4295 varun.gupt 1128
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1129
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1130
    session.commit()
1131
 
2358 ankur.sing 1132
def get_items_by_vendor_category(vendor_category):
1133
    if not vendor_category:
1134
        raise InventoryServiceException(101, "Invalid vendor category in request")
1135
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
1136
    items = query.all()
1137
    return items
2116 ankur.sing 1138
 
2358 ankur.sing 1139
def get_risky_items():
1140
    items = Item.query.filter_by(risky=True).all()
1141
    return items
3008 rajveer 1142
 
2809 rajveer 1143
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1144
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1145
    similar_items = query.all()
3289 rajveer 1146
    return_list = []
1147
    for similar_item in similar_items:
1148
        isActive = False
1149
        try:
1150
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1151
        except:
1152
            continue
1153
        for item in all_items:
1154
            isActive = isActive or item.status == status.ACTIVE
1155
        if isActive:
1156
            return_list.append(similar_item.catalog_item_id)
1157
    return return_list
4423 phani.kuma 1158
 
1159
def get_all_similar_items_catalog_ids(itemId):
1160
    query = SimilarItems.query.filter_by(item_id=itemId)
1161
    similar_items = query.all()
1162
    return_list = []
1163
    for similar_item in similar_items:
1164
        item_query = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).limit(1)
1165
        item = item_query.one()
1166
        return_list.append(item)
2809 rajveer 1167
 
4423 phani.kuma 1168
    return get_thrift_item_list(return_list)
1169
 
1170
def add_similar_item_catalog_id(itemId, catalog_item_id):
1171
    if not itemId or not catalog_item_id:
1172
        raise InventoryServiceException(101, "Bad itemId or catalogItemId in request")
1173
    items_for_entity = get_items_by_catalog_id(catalog_item_id)
1174
    if not len(items_for_entity):
1175
        raise InventoryServiceException(101, "catalogItemId does not exists in database")
1176
 
1177
    s_items = SimilarItems.query.filter_by(item_id=itemId, catalog_item_id=catalog_item_id).all()
1178
    if not len(s_items):
1179
        s_item = SimilarItems()
1180
        s_item.item_id=itemId
1181
        s_item.catalog_item_id=catalog_item_id
1182
        session.commit()
1183
        return items_for_entity[0]
1184
    else:
1185
        raise InventoryServiceException(101, "Already exists")
1186
 
1187
def delete_similar_item_catalog_id(itemId, catalog_item_id):
1188
    if not itemId or not catalog_item_id:
1189
        raise InventoryServiceException(101, "Bad itemId or catalogItemId in request")
1190
 
1191
    similar_item = SimilarItems.query.filter_by(item_id=itemId, catalog_item_id=catalog_item_id).all()
1192
    if len(similar_item):
1193
        similar_item[0].delete()
1194
    session.commit()
1195
    return True
1196
 
3079 rajveer 1197
def add_product_notification(itemId, email):
1198
    try:
3470 rajveer 1199
        try:
1200
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1201
        except:
1202
            product_notification = ProductNotification()
1203
            product_notification.email = email
1204
            product_notification.item_id = itemId
3079 rajveer 1205
        product_notification.addedOn = datetime.datetime.now()
1206
        session.commit()
1207
        return True
1208
    except:
1209
        return False
3086 rajveer 1210
 
1211
 
1212
def send_product_notifications():
1213
    product_notifications = ProductNotification.query.all()
1214
    for product_notification in product_notifications:
1215
        item = product_notification.item
4406 anupam.sin 1216
        availability = __get_item_availability(item, None)
3309 rajveer 1217
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1218
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1219
            product_notification.delete()
1220
    session.commit()
1221
    return True
1222
 
1223
def __get_product_name(item):
1224
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1225
    color = item.color
1226
    if color is not None and color != 'NA':
1227
        product_name = product_name + " (" + color + ")"
3201 rajveer 1228
    product_name = product_name.replace("  "," ")
3086 rajveer 1229
    return product_name
1230
 
1231
 
1232
def __get_product_url(item):
1233
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1234
    product_url = product_url.replace("--","-")
1235
    product_url = product_url.replace(" ","")
1236
    return product_url
1237
 
3348 varun.gupt 1238
def get_all_brands_by_category(category_id):
1239
    catm = CategoryManager()
1240
    child_categories = catm.getCategory(category_id).children_category_ids
1241
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1242
 
1243
    return [brand[0] for brand in brands]
3086 rajveer 1244
 
1245
def __enque_product_notification_email(email, product, date, url, itemId):
1246
 
1247
    html = """
1248
        <html>
1249
        <body>
1250
        <div>
1251
        <p>
1252
            Hi,<br /><br />
1253
            The product requested by you on $date is now available on saholic.com.
1254
        </p>
1255
 
1256
        <p>    
1257
        <strong>Product: $product </strong>
1258
        </p>
1259
 
1260
        <p>
1261
        Click the link below to visit the product: 
1262
        <br/>
1263
        $url
1264
        </p>
1265
        <p>
1266
        Regards,<br/>
1267
        Saholic Customer Support Team<br/>
1268
        www.saholic.com<br/>
1269
        Email: help@saholic.com<br/>
1270
        </p>
1271
        </div>
1272
        </body>
1273
        </html>
1274
        """
1275
 
1276
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1277
 
3086 rajveer 1278
    try:
1279
        helper_client = HelperClient().get_client()
1280
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1281
    except Exception as e:
1282
        print e
1283
 
3557 rajveer 1284
def get_all_sources():
1285
    sources = Source.query.all()
1286
    return [to_t_source(source) for source in sources]
3086 rajveer 1287
 
3557 rajveer 1288
def get_item_pricing_by_source(itemId, sourceId):
1289
    item = Item.query.filter_by(id=itemId).first()
1290
    if item is None:
1291
        raise InventoryServiceException(101, "Bad Item")
1292
 
1293
    source = Source.query.filter_by(id=sourceId).first()
1294
    if source is None:
1295
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1296
 
1297
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1298
    if item_pricing is None:
1299
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1300
    return item_pricing
1301
 
1302
def add_source_item_pricing(sourceItemPricing):
1303
    if not sourceItemPricing:
1304
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1305
 
1306
    if not sourceItemPricing.sellingPrice:
4326 mandeep.dh 1307
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceItemPricing.sourceId))
3557 rajveer 1308
 
1309
    sourceId = sourceItemPricing.sourceId
1310
    itemId = sourceItemPricing.itemId
1311
 
1312
    item = Item.query.filter_by(id=itemId).first()
1313
    if item is None:
1314
        raise InventoryServiceException(101, "Bad Item")
1315
 
1316
    source = Source.query.filter_by(id=sourceId).first()
1317
    if source is None:
1318
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1319
 
3564 rajveer 1320
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1321
    if ds_sourceItemPricing is None:
1322
        ds_sourceItemPricing = SourceItemPricing()
1323
        ds_sourceItemPricing.source = source
1324
        ds_sourceItemPricing.item = item
1325
 
1326
    if sourceItemPricing.mrp:
1327
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1328
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1329
 
1330
    session.commit()
1331
    return
1332
 
1333
def get_all_source_pricing(itemId):
1334
    item = Item.query.filter_by(id=itemId).first()
1335
    if item is None:
1336
        raise InventoryServiceException(101, "Bad Item")
1337
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1338
    return source_pricing
1339
 
1340
 
1341
def get_item_for_source(item_id, sourceId):
1342
    item = get_item(item_id)
1343
    if sourceId == -1:
1344
        return item
1345
    try:
1346
        sip = get_item_pricing_by_source(item_id, sourceId)
1347
        item.sellingPrice = sip.sellingPrice
1348
        if sip.mrp:
1349
            item.mrp = sip.mrp
1350
    except:
1351
        print "No source pricing"
1352
    return item
1353
 
3872 chandransh 1354
def search_items(search_terms, offset, limit):
1355
    query = Item.query
1356
 
1357
    query_clause = []
1358
 
1359
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1360
 
1361
    for search_term in search_terms:
1362
        query_clause.append(Item.brand.like(search_term))
1363
        query_clause.append(Item.model_number.like(search_term))
1364
        query_clause.append(Item.model_name.like(search_term))
1365
 
1366
    query = query.filter(or_(*query_clause))
1367
 
1368
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1369
    if limit:
1370
        query = query.limit(limit)
1371
    items = query.all()
1372
    return items
1373
 
1374
def get_search_result_count(search_terms):
1375
    query = Item.query
1376
 
1377
    query_clause = []
1378
 
1379
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1380
 
1381
    for search_term in search_terms:
1382
        query_clause.append(Item.brand.like(search_term))
1383
        query_clause.append(Item.model_number.like(search_term))
1384
        query_clause.append(Item.model_name.like(search_term))
1385
 
1386
    query = query.filter(or_(*query_clause))
1387
 
1388
    return query.count()
1389
 
3924 rajveer 1390
def __clear_homepage_cache():
1391
    try:
1392
        # create a password manager
1393
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1394
        # Add the username and password.
1395
        configclient = ConfigClient()
4310 rajveer 1396
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1397
        ips = ips.split(" ")
1398
 
1399
        for ip in ips:
4310 rajveer 1400
            try:
1401
                top_level_url = "http://" + ip + ":8080/"
1402
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1403
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1404
 
4310 rajveer 1405
                opener = urllib2.build_opener(handler)
3924 rajveer 1406
 
4310 rajveer 1407
                # use the opener to fetch a URL
1408
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1409
                print "Successfully cleared home page cache" + res.read()
1410
            except:
1411
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1412
    except:
1413
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1414
 
4062 chandransh 1415
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1416
    """
1417
    Returns a list of inventory stock for items for which there are pending orders.
1418
    """
4341 rajveer 1419
 
4368 rajveer 1420
    warehouse_ids = [warehouse.id for warehouse in get_warehouses_for_vendor(vendor_id)]
4064 chandransh 1421
    pending_items_inventory = []
1422
    if warehouse_ids:
1423
        pending_items_inventory = session.query(CurrentInventorySnapshot.item_id, func.sum(CurrentInventorySnapshot.availibility), func.sum(CurrentInventorySnapshot.reserved)).filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).group_by(CurrentInventorySnapshot.item_id).having(func.sum(CurrentInventorySnapshot.reserved) > 0).all()
4024 chandransh 1424
    return pending_items_inventory
4295 varun.gupt 1425
 
1426
def get_product_notifications(start_datetime):
1427
    '''
1428
    Returns a list of Product Notification objects each representing user requests for notification
1429
    '''
1430
    query = ProductNotification.query
3924 rajveer 1431
 
4295 varun.gupt 1432
    if start_datetime:
1433
        query = query.filter(ProductNotification.addedOn > start_datetime)
1434
 
1435
    notifications = query.order_by(desc('addedOn')).all()
1436
    return notifications
1437
 
1438
def get_product_notification_request_count(start_datetime):
1439
    '''
1440
    Returns list of items and the counts of product notification requests
1441
    '''
1442
    print start_datetime
1443
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1444
 
1445
    if start_datetime:
1446
        query = query.filter(ProductNotification.addedOn > start_datetime)
1447
 
1448
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1449
    return counts
1450
 
766 rajveer 1451
def close_session():
1452
    if session.is_active:
1453
        print "session is active. closing it."
1399 rajveer 1454
        session.close()
3376 rajveer 1455
 
1456
def is_alive():
1457
    try:
1458
        session.query(Item.id).limit(1).one()
1459
        return True
1460
    except:
1461
        return False
4332 anupam.sin 1462
 
1463
def add_vendor(vendor):
1464
    if not vendor:
1465
        raise InventoryServiceException(108, "Bad vendor")
1466
    if get_Vendor(vendor.id):
1467
        #vendor is already present.
1468
        raise InventoryServiceException(101, "Vendor already present")
1469
 
1470
    ds_vendor = Vendor()
1471
    ds_vendor.id = vendor.id
1472
    ds_vendor.name = vendor.name
1473
    session.commit()
1474
    return ds_vendor.id
1475
 
1476
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
1477
    return True
1478
 
1479
def get_vendors_for_warehouse(warehouse_id):
1480
    try:
1481
        warehouse = Warehouse.get_by(id=warehouse_id)
1482
        return warehouse.vendors
1483
    except:
1484
        raise InventoryServiceException(108, "Bad Warehouse Id")
1485
 
1486
def get_warehouses_for_vendor(vendorId):
1487
    try:
1488
        vendor = get_Vendor(vendorId)
1489
        return vendor.warehouses
1490
    except:
1491
        raise InventoryServiceException(108, "Bad Vendor Id")