Subversion Repositories SmartDukaan

Rev

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