Subversion Repositories SmartDukaan

Rev

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

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