Subversion Repositories SmartDukaan

Rev

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