Subversion Repositories SmartDukaan

Rev

Rev 3345 | Rev 3355 | 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,\
3079 rajveer 11
    VendorItemMapping, Vendor, SimilarItems, ProductNotification
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,\
15
    to_t_vendor_item_pricing
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
2404 chandransh 22
from sqlalchemy.sql.expression import and_, distinct, func
3086 rajveer 23
from string import Template
24
from shop2020.clients.HelperClient import HelperClient
94 ashish 25
 
26
def initialize():
27
    DataService.initialize()
28
 
29
 
103 ashish 30
def get_all_items(is_active):
31
    if is_active:
766 rajveer 32
        items = Item.query.filter_by(status= status.ACTIVE).all()
103 ashish 33
    else:
766 rajveer 34
        items = Item.query.all()
35
    return items
36
 
103 ashish 37
def get_all_items_by_status(status):
2174 ankur.sing 38
    if status == None:
103 ashish 39
        #return all items
766 rajveer 40
        items = get_all_items(False)
103 ashish 41
    else:
766 rajveer 42
        items = Item.query.filter_by(status=status).all()
43
    return items
103 ashish 44
 
635 rajveer 45
def get_item(item_id):
766 rajveer 46
    item = Item.get_by(id=item_id)
47
    return item
94 ashish 48
 
635 rajveer 49
def get_items_by_catalog_id(catalog_id):
447 rajveer 50
    query = Item.query.filter_by(catalog_item_id=catalog_id)
437 rajveer 51
    try:
635 rajveer 52
        items = query.all()
53
        return get_thrift_item_list(items)
1399 rajveer 54
    except Exception as ex:
55
        print ex
437 rajveer 56
        raise InventoryServiceException(109, "Item not found")
57
 
576 chandransh 58
def is_active(item_id):
2983 chandransh 59
    t_item_shipping_info = ItemShippingInfo()
576 chandransh 60
    try:
635 rajveer 61
        item = get_item(item_id)
3281 chandransh 62
        t_item_shipping_info.isRisky = item.risky
63
        availability = __get_item_availability(item)
64
        if item.risky and availability <= 0 and item.status == status.ACTIVE:
65
            add_status_change_log(item, status.PAUSED_BY_RISK)
66
            item.status = status.PAUSED_BY_RISK
67
            item.status_description = "This item is currently out of stock"
68
            session.commit()
2983 chandransh 69
        t_item_shipping_info.isActive = (item.status == status.ACTIVE)
3281 chandransh 70
        t_item_shipping_info.quantity = availability
576 chandransh 71
    except InventoryServiceException:
2983 chandransh 72
        print "[ERROR] Unexpected error:", sys.exc_info()[0]
73
    return t_item_shipping_info
74
 
2035 rajveer 75
def get_item_status_description(itemId):
76
    item = get_item(itemId)
77
    return item.status_description
563 chandransh 78
 
94 ashish 79
def get_Warehouse(warehouse_id):
80
    return Warehouse.get_by(id=warehouse_id)
81
 
122 ashish 82
def get_all_warehouses_by_status(status):
83
    if not status:
766 rajveer 84
        warehouses = Warehouse.query.all()
122 ashish 85
    else:
851 chandransh 86
        warehouses = Warehouse.query.filter_by(status=status).all()
87
    return warehouses
122 ashish 88
 
94 ashish 89
def get_all_warehouses_for_item(item_id):
635 rajveer 90
    item = get_item(item_id)
94 ashish 91
    if not item:
122 ashish 92
        raise InventoryServiceException(108, "Some unforeseen error while obtaining item")
93
    return item.get_all_warehouses
94 ashish 94
 
122 ashish 95
def get_all_items_for_warehouse(warehouse_id):
96
    warehouse = get_Warehouse(warehouse_id)
97
    if not warehouse:
98
        raise InventoryServiceException(108, "bad warehouse")
99
    return warehouse.all_items
100
 
94 ashish 101
def add_warehouse(warehouse):
103 ashish 102
    if not warehouse:
122 ashish 103
        raise InventoryServiceException(108, "Bad warehouse")
103 ashish 104
    if get_Warehouse(warehouse.id):
105
        #warehouse is already present.
122 ashish 106
        raise InventoryServiceException(101, "Warehouse already present")
103 ashish 107
 
94 ashish 108
    ds_warehouse = Warehouse()
109
    ds_warehouse.id = warehouse.id
110
    ds_warehouse.location = warehouse.location
122 ashish 111
    ds_warehouse.status = status.ACTIVE
103 ashish 112
    ds_warehouse.addedOn = datetime.datetime.now()
483 rajveer 113
    ds_warehouse.lastCheckedOn = datetime.datetime.now()
114
    ds_warehouse.tinNumber = warehouse.tinNumber
115
    ds_warehouse.pincode = warehouse.pincode
116
    if warehouse.vendorString:
117
        ds_warehouse.vendorString = warehouse.vendorString
94 ashish 118
    session.commit()
103 ashish 119
    return ds_warehouse.id
94 ashish 120
 
122 ashish 121
def update_item(item):
122
    if not item:
123
        raise InventoryServiceException(108, "Bad item in request")
124
 
125
    if not item.id:
609 chandransh 126
        raise InventoryServiceException(101, "Missing id for update")
122 ashish 127
 
2120 ankur.sing 128
    validate_item_prices(item)
2065 ankur.sing 129
 
635 rajveer 130
    ds_item = get_item(item.id)
122 ashish 131
 
132
    if not ds_item:
609 chandransh 133
        raise InventoryServiceException(101, "Item missing in our database")
122 ashish 134
 
963 chandransh 135
    if item.productGroup:
136
        ds_item.product_group = item.productGroup 
137
    if item.brand:
138
        ds_item.brand = item.brand
511 rajveer 139
    if item.modelNumber:
140
        ds_item.model_number = item.modelNumber
2497 ankur.sing 141
    ds_item.color = item.color
142
    ds_item.model_name = item.modelName
143
    ds_item.category = item.category
144
    ds_item.comments = item.comments
511 rajveer 145
 
2497 ankur.sing 146
    ds_item.catalog_item_id = item.catalogItemId
483 rajveer 147
 
2129 ankur.sing 148
    ds_item.mrp = item.mrp
149
    ds_item.sellingPrice = item.sellingPrice
150
 
2497 ankur.sing 151
    ds_item.mop = item.mop
152
    ds_item.dealerPrice = item.dealerPrice
153
    ds_item.transfer_price = item.transferPrice
154
 
2174 ankur.sing 155
    ds_item.weight = item.weight
2129 ankur.sing 156
 
2358 ankur.sing 157
    if ds_item.status != item.itemStatus:
2402 rajveer 158
        add_status_change_log(ds_item, item.itemStatus)
2358 ankur.sing 159
        ds_item.status = item.itemStatus
2035 rajveer 160
    if item.status_description:
161
        ds_item.status_description = item.status_description
122 ashish 162
 
511 rajveer 163
    if item.startDate:
2116 ankur.sing 164
        ds_item.startDate = to_py_date(item.startDate)
2497 ankur.sing 165
    else:
166
        ds_item.startDate = None
511 rajveer 167
    if item.retireDate:
2116 ankur.sing 168
        ds_item.retireDate = to_py_date(item.retireDate)
2497 ankur.sing 169
    else:
170
        ds_item.retireDate = None
511 rajveer 171
 
2497 ankur.sing 172
    ds_item.feature_id = item.featureId
173
    ds_item.feature_description = item.featureDescription
122 ashish 174
 
2129 ankur.sing 175
    ds_item.bestDealText = item.bestDealText
176
    ds_item.bestDealValue = item.bestDealValue
2065 ankur.sing 177
    ds_item.bestSellingRank = item.bestSellingRank
2497 ankur.sing 178
 
2065 ankur.sing 179
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 180
    ds_item.risky = item.risky
2347 ankur.sing 181
    ds_item.updatedOn = datetime.datetime.now()
2065 ankur.sing 182
 
122 ashish 183
    session.commit();
184
    return ds_item.id
94 ashish 185
 
2116 ankur.sing 186
def check_vendor_item_mapping(product_group, brand, model_number, color, vendor_id, vendor_category):
187
    key = product_group.strip().lower() + '|' + brand.strip().lower() + '|' + model_number.strip().lower() + '|' + color.strip().lower()
188
    try:
189
        vim = VendorItemMapping.query.filter_by(vendor_id=vendor_id, item_key=key, vendor_category=vendor_category).one()
190
        return True
191
    except:
192
        return False
193
 
103 ashish 194
def add_item(item):
195
    if not item:
122 ashish 196
        raise InventoryServiceException(108, "Bad item in request")
635 rajveer 197
    if get_item(item.id):
122 ashish 198
        raise InventoryServiceException(101, "Item already exists")
2120 ankur.sing 199
 
200
    validate_item_prices(item)
201
 
103 ashish 202
    ds_item = Item()
963 chandransh 203
    if item.productGroup:
204
        ds_item.product_group = item.productGroup
205
    if item.brand:
206
        ds_item.brand = item.brand
515 rajveer 207
    if item.modelName:
208
        ds_item.model_name = item.modelName
209
    if item.modelNumber:
210
        ds_item.model_number = item.modelNumber
609 chandransh 211
    if item.color:
212
        ds_item.color = item.color
2116 ankur.sing 213
    if item.hotspotCategory:
214
        ds_item.hotspotCategory = item.hotspotCategory
215
        if item.hotspotCategory == 'Handsets':
2403 ankur.sing 216
            ds_item.preferredWarehouse = 1
2116 ankur.sing 217
        else:
2403 ankur.sing 218
            ds_item.preferredWarehouse = 2
2116 ankur.sing 219
 
483 rajveer 220
    if item.category:
221
        ds_item.category = item.category
222
    if item.comments:
223
        ds_item.comments = item.comments
224
 
103 ashish 225
    ds_item.addedOn = datetime.datetime.now()
609 chandransh 226
    ds_item.updatedOn = datetime.datetime.now()
2116 ankur.sing 227
    if item.startDate:
228
        ds_item.startDate = to_py_date(item.startDate)
229
    if item.retireDate:
230
        ds_item.retireDate = to_py_date(item.retireDate)
609 chandransh 231
 
483 rajveer 232
    if item.mrp:
233
        ds_item.mrp = item.mrp
234
    if item.mop:
235
        ds_item.mop = item.mop
236
    if item.sellingPrice:
237
        ds_item.sellingPrice = item.sellingPrice
609 chandransh 238
    if item.dealerPrice:
239
        ds_item.dealerPrice = item.dealerPrice
2116 ankur.sing 240
    if item.transferPrice:
241
        ds_item.transfer_price = item.transferPrice
122 ashish 242
    if item.weight:
243
        ds_item.weight = item.weight
244
 
245
    if item.featureId:
246
        ds_item.feature_id = item.featureId
247
    if item.featureDescription:
248
        ds_item.feature_description = item.featureDescription
249
 
103 ashish 250
    if item.otherInfo:
251
        for k,v in item.otherInfo.iteritems():
252
            info = ItemInfo()
253
            info.key = k
254
            info.value = v
255
            ds_item.iteminfo.append(info)
2116 ankur.sing 256
 
103 ashish 257
    #check if categories present. If yes, add them to system
122 ashish 258
 
609 chandransh 259
    if item.bestDealValue:
260
        ds_item.bestDealValue = item.bestDealValue
261
    if item.bestDealText:
262
        ds_item.bestDealText = item.bestDealText
2116 ankur.sing 263
    if item.bestSellingRank:
264
        ds_item.bestSellingRank = item.bestSellingRank
265
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 266
    ds_item.risky = item.risky
609 chandransh 267
 
2116 ankur.sing 268
    # Check if a similar item already exists in our database
269
    similar_item = Item.query.filter_by(product_group=item.productGroup, brand = item.brand, model_number=item.modelNumber, hotspotCategory=item.hotspotCategory).first()
270
    print "[SIMILAR ITEM FOUND:] FOR {0} {1} {2} {3} {4}".format(item.productGroup, item.brand, item.modelNumber, item.hotspotCategory, item.color)
271
 
272
    if similar_item is None or similar_item.catalog_item_id is None:
273
        # If there is no similar item in the database from before,
274
        # use the entity_id_generator
275
        entity_id = EntityIDGenerator.query.first()
276
        ds_item.catalog_item_id = entity_id.id + 1
277
        ds_item.status = status.IN_PROCESS
278
        ds_item.status_description = "This item is in process."
279
        entity_id.id = entity_id.id  + 1
280
    else:
281
        #If a similar item already exists for a product group, brand and model_number, set it as same.
282
        ds_item.catalog_item_id = similar_item.catalog_item_id
283
        ds_item.category = similar_item.category
284
        ds_item.status = similar_item.status
285
        ds_item.status_description = similar_item.status_description
286
 
103 ashish 287
    session.commit();
3325 chandransh 288
    return ds_item.id
289
 
290
def update_inventory_history(warehouse_id, timestamp, availability):
291
    warehouse = get_Warehouse(warehouse_id)
292
    if not warehouse:
293
        raise InventoryServiceException(107, "Warehouse? Where?")
294
    vendor = warehouse.vendor 
295
    time = datetime.datetime.now()
296
    for item_key, quantity in availability.iteritems():
297
        try:
298
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
299
            item = vendor_item_mapping.item
300
        except:
301
            continue  
302
        try:
303
            item_inventory_history = ItemInventoryHistory()
304
            item_inventory_history.warehouse = warehouse
305
            item_inventory_history.item = item
306
            item_inventory_history.timestamp = time
307
            item_inventory_history.availibility = quantity
308
        except:
309
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
310
    session.commit()
103 ashish 311
 
483 rajveer 312
def update_inventory(warehouse_id, timestamp, availability):
313
    warehouse = get_Warehouse(warehouse_id)
314
    if not warehouse:
315
        raise InventoryServiceException(107, "Warehouse? Where?")
316
 
317
    time = datetime.datetime.now()
318
    warehouse.lastCheckedOn = time
319
    warehouse.vendorString = timestamp
1368 chandransh 320
    vendor = warehouse.vendor
2368 ankur.sing 321
    session.commit()
1368 chandransh 322
    for item_key, quantity in availability.iteritems():
483 rajveer 323
        try:
1368 chandransh 324
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
325
            item = vendor_item_mapping.item
494 rajveer 326
        except:
327
            continue  
328
        try:
483 rajveer 329
            current_inventory_snapshot = CurrentInventorySnapshot.get_by(item=item, warehouse=warehouse)
330
            if not current_inventory_snapshot:
331
                current_inventory_snapshot = CurrentInventorySnapshot()
332
                current_inventory_snapshot.item = item
333
                current_inventory_snapshot.warehouse = warehouse
334
                current_inventory_snapshot.availibility = 0
871 chandransh 335
                current_inventory_snapshot.reserved = 0
483 rajveer 336
            # added the difference in the current inventory    
337
            current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
338
        except:
339
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
2368 ankur.sing 340
        session.commit() 
341
        check_risky_item(item)
483 rajveer 342
 
94 ashish 343
def get_item_inventoy(item_id):
344
 
345
    inventory = Item.get_by(id=item_id).currentInventory
346
    if not inventory:
122 ashish 347
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
94 ashish 348
    return inventory
349
 
635 rajveer 350
def get_item_inventory_by_item_id(item_id):
351
    inventory = Item.get_by(id=item_id).currentInventory
379 ashish 352
    if not inventory:
353
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
354
    return inventory
355
 
103 ashish 356
 
357
def retire_warehouse(warehouse_id):
358
    if not warehouse_id:
122 ashish 359
        raise InventoryServiceException(101, "Bad warehouse id")
103 ashish 360
    warehouse = get_Warehouse(warehouse_id)
361
    if not warehouse:
122 ashish 362
        raise InventoryServiceException(108, "warehouse id not present")
363
    warehouse.status = status.DELETED;
103 ashish 364
    session.commit()
365
 
366
def retire_item(item_id):
367
    if not item_id:
122 ashish 368
        raise InventoryServiceException(101, "bad item id")
635 rajveer 369
    item = get_item(item_id)
103 ashish 370
    if not item:
122 ashish 371
        raise InventoryServiceException(108, "item id not present")
372
    item.status = status.PHASED_OUT
373
    item.retireDate = datetime.datetime.now()
103 ashish 374
    session.commit()
122 ashish 375
 
376
#need to implement threads based solution here
103 ashish 377
def start_item_on(item_id, timestamp):
378
    if not item_id:
122 ashish 379
        raise InventoryServiceException(101, "bad item id")
635 rajveer 380
    item = get_item(item_id)
103 ashish 381
    if not item:
122 ashish 382
        raise InventoryServiceException(108, "item id not present")
103 ashish 383
 
122 ashish 384
    item.status = status.ACTIVE
385
    item.startDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
386
    add_status_change_log(item, status.ACTIVE)
103 ashish 387
    session.commit()
388
 
122 ashish 389
#need to implement threads here
103 ashish 390
def retire_item_on(item_id, timestamp):
391
    if not item_id:
122 ashish 392
        raise InventoryServiceException(101, "bad item id")
635 rajveer 393
    item = get_item(item_id)
103 ashish 394
    if not item:
122 ashish 395
        raise InventoryServiceException(108, "item id not present")
103 ashish 396
 
122 ashish 397
    item.status = status.PHASED_OUT
398
    item.retireDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
399
    add_status_change_log(item, status.PHASED_OUT)
103 ashish 400
    session.commit()
401
 
402
def add_status_change_log(item, new_status):
403
    item_change_log = ItemChangeLog()
404
    item_change_log.new_status = new_status
405
    item_change_log.old_status = item.status
406
    item_change_log.timestamp = datetime.datetime.now()
407
    item_change_log.item = item
408
    session.commit()
409
 
410
def change_item_status(item_id, new_status):
411
    if not item_id:
122 ashish 412
        raise InventoryServiceException(101, "bad item id")
635 rajveer 413
    item = get_item(item_id)
103 ashish 414
    if not item:
122 ashish 415
        raise InventoryServiceException(108, "item id not present")
2116 ankur.sing 416
    add_status_change_log(item, new_status)
122 ashish 417
    item.status = new_status
2251 ankur.sing 418
    if item.status == status.PHASED_OUT:
419
        item.status_description = "This item has been phased out"
420
    elif item.status == status.DELETED:
421
        item.status_description = "This item has been deleted"
2984 rajveer 422
    elif item.status == status.PAUSED or item.status == status.PAUSED_BY_RISK:
2251 ankur.sing 423
        item.status_description = "This item is currently out of stock"        
424
    elif item.status == status.ACTIVE:
425
        item.status_description = "This item is active"
426
    elif item.status == status.IN_PROCESS:
427
        item.status_description = "This item is in process"
428
    elif item.status == status.CONTENT_COMPLETE:
429
        item.status_description = "This item is in process"
103 ashish 430
    session.commit()
431
 
432
def get_item_availability_for_warehouse(warehouse_id, item_id):
433
    if not warehouse_id:
122 ashish 434
        raise InventoryServiceException(101, "bad warehouse_id")
103 ashish 435
    if not item_id:
122 ashish 436
        raise InventoryServiceException(101, "bad item_id")
103 ashish 437
 
438
    warehouse = get_Warehouse(warehouse_id)
439
    if not warehouse:
122 ashish 440
        raise InventoryServiceException(108, "warehouse does not exist")
635 rajveer 441
    item = get_item(item_id)
504 rajveer 442
 
103 ashish 443
    if not item:
766 rajveer 444
        raise InventoryServiceException(108, "item does not exist")
122 ashish 445
 
494 rajveer 446
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id)
504 rajveer 447
    query = query.filter_by(item_id = item.id)
494 rajveer 448
    try:
449
        current_inventory_snapshot = query.one()
871 chandransh 450
        return current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
494 rajveer 451
    except:
452
        return 0
453
    """
454
    current_inventory_snapshot = CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id == warehouse_id, CurrentInventorySnapshot.item_id == item_id).one()
103 ashish 455
    if not current_inventory_snapshot:
456
        return 0
457
    else:
458
        return current_inventory_snapshot.availibility
494 rajveer 459
    """
643 chandransh 460
 
2368 ankur.sing 461
def check_risky_item(item):
2251 ankur.sing 462
    if not item.risky:
463
        return
2983 chandransh 464
    availability = __get_item_availability(item)
465
    if availability <= 0:
2251 ankur.sing 466
        if item.status == status.ACTIVE:
2984 rajveer 467
            change_item_status(item.id, status.PAUSED_BY_RISK)
2251 ankur.sing 468
    else:
2984 rajveer 469
        if item.status == status.PAUSED_BY_RISK:
2251 ankur.sing 470
            change_item_status(item.id, status.ACTIVE)
2368 ankur.sing 471
    session.commit()
2251 ankur.sing 472
 
2983 chandransh 473
def __get_item_availability(item):
474
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
475
    availability = 0
476
    reserved = 0
477
    for currInv in all_inventory:
478
        availability = availability + currInv.availibility
479
        reserved = reserved + currInv.reserved
480
    return availability - reserved
481
 
871 chandransh 482
def reserve_item_in_warehouse(item_id, warehouse_id, quantity):    
483
    if not warehouse_id:
484
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 485
    item = get_item(item_id)
486
    if not item:
871 chandransh 487
        raise InventoryServiceException(101, "bad item_id")
488
 
489
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
490
    try:
491
        current_inventory_snapshot = query.one()
492
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
493
        session.commit()
2368 ankur.sing 494
        check_risky_item(item)
871 chandransh 495
        return True
496
    except:
497
        print "Unexpected error:", sys.exc_info()[0]
498
        return False
499
 
500
def reduce_reservation_count(item_id, warehouse_id, quantity):
501
    if not warehouse_id:
502
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 503
    item = get_item(item_id)
504
    if not item:
871 chandransh 505
        raise InventoryServiceException(101, "bad item_id")
506
 
507
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
508
    try:
509
        current_inventory_snapshot = query.one()
510
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
511
        session.commit()
2368 ankur.sing 512
        check_risky_item(item)
871 chandransh 513
        return True
514
    except:
515
        print "Unexpected error:", sys.exc_info()[0]
516
        return False
517
 
2075 rajveer 518
def mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):
2828 rajveer 519
    '''
520
    Get all the items for this entityID and update category, brand, modelName and modelNumber for all.
521
    Update Status for only IN_PROCESS items to CONTENT_COMPLETE
522
    '''
723 chandransh 523
    content_complete_status = status.CONTENT_COMPLETE
2828 rajveer 524
    items = Item.query.filter_by(catalog_item_id=entity_id).all()
723 chandransh 525
    current_timestamp = datetime.datetime.now()
526
    for item in items:
2828 rajveer 527
        if item.status == status.IN_PROCESS:
528
            item.status = content_complete_status
529
            item_change_log = ItemChangeLog()
530
            item_change_log.old_status = item.status
531
            item_change_log.new_status = content_complete_status
532
            item_change_log.timestamp = current_timestamp
533
            item_change_log.item = item
723 chandransh 534
 
2075 rajveer 535
        item.category = category
536
        item.brand = brand
2081 rajveer 537
        item.model_name = modelName
538
        item.model_number = modelNumber
723 chandransh 539
        item.updatedOn = current_timestamp
540
    session.commit()
541
    return True
1294 chandransh 542
 
643 chandransh 543
def get_item_availability_for_location(warehouse_loc, item_id):
544
    if warehouse_loc is None:
545
        raise InventoryServiceException(101, "Bad Warehouse Location")
546
    if not item_id:
1416 chandransh 547
        raise InventoryServiceException(101, "Bad Item id")
643 chandransh 548
 
1416 chandransh 549
    item = Item.get_by(id=item_id)
643 chandransh 550
    warehouses = Warehouse.query.filter_by(logisticsLocation=warehouse_loc).all()
551
    warehouse_ids = [warehouse.id for warehouse in warehouses]
552
    warehouse_retid = -1
553
    global_availability = 0
554
    for warehouse_id in warehouse_ids:
785 rajveer 555
        try:
871 chandransh 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
785 rajveer 558
        except:
559
            availability = 0    
643 chandransh 560
        if availability > global_availability:
561
            warehouse_retid = warehouse_id
562
            global_availability = availability
2341 chandransh 563
 
643 chandransh 564
    if warehouse_retid == -1:
759 chandransh 565
        # This is the case when all warehouses have exhausted their
566
        # inventory of this item or no warehouse is available in this
567
        # location.
1416 chandransh 568
        warehouse_retid = int(item.preferredWarehouse)
2344 chandransh 569
        warehouse = Warehouse.get_by(id=warehouse_retid)
2341 chandransh 570
        try:
571
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item_id).one()
572
            global_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
573
        except:
574
            global_availability = 0
643 chandransh 575
 
2341 chandransh 576
    return [warehouse.logisticsLocation, warehouse_retid, global_availability]
577
 
122 ashish 578
def get_warehouses_for_item(item_id):
643 chandransh 579
 
122 ashish 580
    if not item_id:
581
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 582
    item = get_item(item_id)
122 ashish 583
 
584
    if not item:
585
        raise InventoryServiceException(101, "bad item")
586
 
483 rajveer 587
    warehouses = item.currentInventory.warehouse
501 rajveer 588
    return warehouses
589
 
2404 chandransh 590
def get_child_categories(category):
591
    cm = CategoryManager()
2621 varun.gupt 592
    cat = cm.getCategory(category)
593
    return cat.children_category_ids if cat else None
2404 chandransh 594
 
626 chandransh 595
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 596
    '''
597
    Returns the Best Sellers between the start and the stop index in the given category
598
    '''
1926 rajveer 599
    query = get_best_sellers_query(category, None)
1098 chandransh 600
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 601
    return get_thrift_item_list(best_sellers)
602
 
2093 chandransh 603
def get_best_sellers_count(category=-1):
2404 chandransh 604
    '''
605
    Returns the number of best sellers in the given category
606
    '''
1926 rajveer 607
    count = get_best_sellers_query(category, None).count()
1120 rajveer 608
    if count is None:
609
        count = 0
766 rajveer 610
    return count
621 chandransh 611
 
1926 rajveer 612
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 613
    '''
614
    Returns the Best sellers for the given brand and category between the start and the stop index.
615
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
616
    '''
1926 rajveer 617
    query = get_best_sellers_query(category, brand)
1098 chandransh 618
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 619
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 620
 
1926 rajveer 621
def get_best_sellers_query(category, brand):
2404 chandransh 622
    '''
623
    Returns the query to be used for getting Best Sellers.
624
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
625
    '''
1098 chandransh 626
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 627
    if category != -1:
1970 rajveer 628
        all_categories = [category]
629
        child_categories = get_child_categories(category)
630
        if child_categories is not None:
631
            all_categories = all_categories + child_categories 
632
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 633
    if brand is not None:
634
        query = query.filter_by(brand=brand)
1098 chandransh 635
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 636
    return query
609 chandransh 637
 
1098 chandransh 638
def get_best_deals(category=-1):
2404 chandransh 639
    '''
640
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
641
    '''
642
    query = get_best_deals_query(Item, category, None)
1098 chandransh 643
    items = query.all()
609 chandransh 644
    return get_thrift_item_list(items)
645
 
1098 chandransh 646
def get_best_deals_count(category=-1):
2404 chandransh 647
    '''
648
    Returns the count of best deals in the given category.
649
    Ignores the category if it's -1.
650
    '''
651
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 652
    if count is None:
653
        count = 0
766 rajveer 654
    return count
501 rajveer 655
 
1926 rajveer 656
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 657
    '''
658
    Returns the catalog_item_ids of best deal items for the given brand and category.
659
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
660
    '''
661
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 662
    best_deal_items = query.all()[start_index:stop_index]
663
    return [item.catalog_item_id for item in best_deal_items]
664
 
2404 chandransh 665
def get_best_deals_counting_query(obj, category, brand):
666
    '''
667
    Returns the query to be used to select the best deals in the given brand and category.
668
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
669
    '''
670
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 671
    if category != -1:
1970 rajveer 672
        all_categories = [category]
673
        child_categories = get_child_categories(category)
674
        if child_categories is not None:
675
            all_categories = all_categories + child_categories 
676
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 677
    if brand is not None:
678
        query = query.filter_by(brand=brand)
2404 chandransh 679
    return query
680
 
681
def get_best_deals_query(obj, category, brand):
682
    '''
683
    Returns the query to be used to get the best deals in the given category and brand.
684
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
685
    '''
686
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 687
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
688
    return query
609 chandransh 689
 
1098 chandransh 690
def get_latest_arrivals(limit, category=-1):
2404 chandransh 691
    '''
692
    Returns up to limit number of Latest Arrivals in the given category.
693
    '''
2975 chandransh 694
    categories = []
695
    if category != -1:
696
        categories = [category]
697
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 698
    items = query.all()[0:limit]
609 chandransh 699
    return get_thrift_item_list(items)
598 chandransh 700
 
1098 chandransh 701
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 702
    '''
703
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 704
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 705
    '''
2975 chandransh 706
    categories = []
707
    if category != -1:
708
        categories = [category]
709
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 710
    if count is None:
711
        count = 0
712
    count = min(count, limit)
766 rajveer 713
    return count
602 chandransh 714
 
2975 chandransh 715
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 716
    '''
717
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 718
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 719
    '''
2975 chandransh 720
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 721
    latest_arrivals = query.all()[start_index:stop_index]
722
    return [item.catalog_item_id for item in latest_arrivals]
723
 
2975 chandransh 724
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 725
    '''
726
    Returns the query to be used to count Latest arrivals.
3016 chandransh 727
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 728
    '''
729
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 730
 
731
    all_categories = []
732
    for category in categories:
733
        all_categories.append(category)
1970 rajveer 734
        child_categories = get_child_categories(category)
2975 chandransh 735
        if child_categories:
736
            all_categories = all_categories + child_categories
737
    if all_categories: 
1970 rajveer 738
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 739
 
1926 rajveer 740
    if brand is not None:
741
        query = query.filter_by(brand=brand)
2404 chandransh 742
    return query
743
 
2975 chandransh 744
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 745
    '''
746
    Returns the query to be used to retrieve Latest Arrivals.
747
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
748
    '''
2975 chandransh 749
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 750
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
751
    return query
609 chandransh 752
 
753
def get_thrift_item_list(items):
1098 chandransh 754
    return [to_t_item(item) for item in items if item != None]
635 rajveer 755
 
1155 rajveer 756
def generate_new_entity_id():
757
    generator =  EntityIDGenerator.query.one()
758
    id = generator.id + 1
759
    generator.id = id
760
    session.commit()
761
    return id
762
 
635 rajveer 763
def put_category_object(object):
764
    category = Category.get_by(id=1)
765
    if category is None:
766
        category = Category()
767
    category.object = object    
768
    session.commit()
769
    return True
770
 
771
def get_category_object():
766 rajveer 772
    object = Category.get_by(id=1).object
773
    return object
774
 
1341 chandransh 775
def get_item_pricing(item_id, warehouse_id):
776
    item = Item.query.filter_by(id=item_id).first()
777
    if item is None:
778
        raise InventoryServiceException(101, "Bad Item")
779
 
780
    warehouse = get_Warehouse(warehouse_id)
781
    if not warehouse:
782
        raise InventoryServiceException(108, "Bad Warehouse")
783
    vendor = warehouse.vendor
784
 
785
    try:
786
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 787
        return item_pricing
3244 chandransh 788
    except MultipleResultsFound:
1341 chandransh 789
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 790
    except NoResultFound:
1341 chandransh 791
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
792
 
1970 rajveer 793
def add_category(t_category):
794
    category = Category.get_by(id=t_category.id)
795
    if category is None:
796
        category = Category()
797
    category.id = t_category.id 
798
    category.label = t_category.label
799
    category.description = t_category.description
800
    category.parent_category_id = t_category.parent_category_id 
801
    session.commit()
802
    return True
803
 
804
def get_category(id):
805
    return Category.query.filter_by(id=id).first()
806
 
807
def get_all_categories():
808
    return Category.query.all()
809
 
1991 ankur.sing 810
 
811
def get_all_item_pricing(item_id):
812
    item = Item.query.filter_by(id=item_id).first()
813
    if item is None:
814
        raise InventoryServiceException(101, "Bad Item")
815
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
816
    return item_pricing
817
 
2116 ankur.sing 818
def get_item_mappings(item_id):
819
    item = Item.query.filter_by(id=item_id).first()
820
    if item is None:
821
        raise InventoryServiceException(101, "Bad Item")
822
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
823
    return item_mappings
824
 
825
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 826
    if not vendorItemPricing:
827
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
828
    vendorId = vendorItemPricing.vendorId
829
    itemId = vendorItemPricing.itemId
830
 
831
    try:
832
        vendor = Vendor.query.filter_by(id=vendorId).one()
833
    except:
834
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
835
 
836
    try:
837
        item = Item.query.filter_by(id=itemId).one()
838
    except:
839
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
840
 
2120 ankur.sing 841
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 842
 
1991 ankur.sing 843
    try:
844
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
845
    except:
2116 ankur.sing 846
        ds_vendorItemPricing = VendorItemPricing()
847
        ds_vendorItemPricing.vendor = vendor
848
        ds_vendorItemPricing.item = item
1991 ankur.sing 849
 
850
    if vendorItemPricing.mop:
851
        ds_vendorItemPricing.mop = vendorItemPricing.mop
852
    if vendorItemPricing.dealerPrice:
853
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
854
    if vendorItemPricing.transferPrice:
2065 ankur.sing 855
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 856
 
857
    session.commit()
858
    return
859
 
2358 ankur.sing 860
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 861
    if not vendorItemMapping:
862
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
863
    vendorId = vendorItemMapping.vendorId
864
    itemId = vendorItemMapping.itemId
865
 
866
    try:
867
        vendor = Vendor.query.filter_by(id=vendorId).one()
868
    except:
869
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
870
 
871
    try:
872
        item = Item.query.filter_by(id=itemId).one()
873
    except:
874
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
875
 
876
    try:
2358 ankur.sing 877
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 878
    except:
879
        ds_vendorItemMapping = VendorItemMapping()
880
        ds_vendorItemMapping.vendor = vendor
881
        ds_vendorItemMapping.item = item
2497 ankur.sing 882
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 883
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
884
 
885
    session.commit()
886
    return
887
 
2120 ankur.sing 888
def validate_item_prices(item):
2129 ankur.sing 889
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
890
        return
891
    if item.mrp < item.sellingPrice:
2120 ankur.sing 892
        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))
893
        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 894
    return
2120 ankur.sing 895
 
896
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 897
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 898
        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))
899
        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)))
900
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
901
        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))
902
        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)))
903
    return
2065 ankur.sing 904
 
905
def get_all_vendors():
906
    return Vendor.query.all()
907
 
2116 ankur.sing 908
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 909
    query = Item.query
2428 ankur.sing 910
    query = query.filter_by(product_group=product_group)
911
    query = query.filter_by(brand=brand)
912
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 913
    if color:
914
        query = query.filter_by(color=color)
915
    item = query.first()
2116 ankur.sing 916
    if item is None:
917
        return 0
918
    else:
919
        return item.id
2286 ankur.sing 920
 
921
def change_risky_flag(item_id, risky):
922
    item = get_item(item_id)
923
    if not item:
924
        raise InventoryServiceException(101, "Item missing in our database")
925
    try:
926
        log_risky_flag(item_id, risky)
927
    except:
928
        print "Not able to log risky flag change"
929
    item.risky = risky
2368 ankur.sing 930
    if not risky and item.status == status.PAUSED:
931
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 932
    session.commit()
933
 
2358 ankur.sing 934
def get_items_by_vendor_category(vendor_category):
935
    if not vendor_category:
936
        raise InventoryServiceException(101, "Invalid vendor category in request")
937
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
938
    items = query.all()
939
    return items
2116 ankur.sing 940
 
2358 ankur.sing 941
def get_risky_items():
942
    items = Item.query.filter_by(risky=True).all()
943
    return items
3008 rajveer 944
 
2809 rajveer 945
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 946
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
947
    similar_items = query.all()
3289 rajveer 948
    return_list = []
949
    for similar_item in similar_items:
950
        isActive = False
951
        try:
952
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
953
        except:
954
            continue
955
        for item in all_items:
956
            isActive = isActive or item.status == status.ACTIVE
957
        if isActive:
958
            return_list.append(similar_item.catalog_item_id)
959
    return return_list
2809 rajveer 960
 
3079 rajveer 961
def add_product_notification(itemId, email):
962
    try:
963
        product_notification = ProductNotification()
964
        product_notification.email = email
965
        product_notification.item_id = itemId
966
        product_notification.addedOn = datetime.datetime.now()
967
        session.commit()
968
        return True
969
    except:
970
        return False
3086 rajveer 971
 
972
 
973
def send_product_notifications():
974
    product_notifications = ProductNotification.query.all()
975
    for product_notification in product_notifications:
976
        item = product_notification.item
977
        availability = __get_item_availability(item)
3309 rajveer 978
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 979
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
980
            product_notification.delete()
981
    session.commit()
982
    return True
983
 
984
def __get_product_name(item):
985
    product_name = item.brand + " " + item.model_name + " " + item.model_number
986
    color = item.color
987
    if color is not None and color != 'NA':
988
        product_name = product_name + " (" + color + ")"
3201 rajveer 989
    product_name = product_name.replace("  "," ")
3086 rajveer 990
    return product_name
991
 
992
 
993
def __get_product_url(item):
994
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
995
    product_url = product_url.replace("--","-")
996
    product_url = product_url.replace(" ","")
997
    return product_url
998
 
3348 varun.gupt 999
def get_all_brands_by_category(category_id):
1000
    catm = CategoryManager()
1001
    child_categories = catm.getCategory(category_id).children_category_ids
1002
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1003
 
1004
    return [brand[0] for brand in brands]
3086 rajveer 1005
 
1006
def __enque_product_notification_email(email, product, date, url, itemId):
1007
 
1008
    html = """
1009
        <html>
1010
        <body>
1011
        <div>
1012
        <p>
1013
            Hi,<br /><br />
1014
            The product requested by you on $date is now available on saholic.com.
1015
        </p>
1016
 
1017
        <p>    
1018
        <strong>Product: $product </strong>
1019
        </p>
1020
 
1021
        <p>
1022
        Click the link below to visit the product: 
1023
        <br/>
1024
        $url
1025
        </p>
1026
        <p>
1027
        Regards,<br/>
1028
        Saholic Customer Support Team<br/>
1029
        www.saholic.com<br/>
1030
        Email: help@saholic.com<br/>
1031
        </p>
1032
        </div>
1033
        </body>
1034
        </html>
1035
        """
1036
 
1037
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1038
 
3086 rajveer 1039
    try:
1040
        helper_client = HelperClient().get_client()
1041
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1042
    except Exception as e:
1043
        print e
1044
 
1045
 
766 rajveer 1046
def close_session():
1047
    if session.is_active:
1048
        print "session is active. closing it."
1399 rajveer 1049
        session.close()