Subversion Repositories SmartDukaan

Rev

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