Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
94 ashish 1
'''
2
Created on 23-Mar-2010
3
 
4
@author: ashish
5
'''
6
from elixir import *
7
from shop2020.model.v1.catalog.impl import DataService
122 ashish 8
from shop2020.model.v1.catalog.impl.DataService import Item, \
103 ashish 9
    Warehouse, ItemInventoryHistory, CurrentInventorySnapshot, ItemInfo,\
1368 chandransh 10
    ItemChangeLog, Category, EntityIDGenerator, VendorItemPricing,\
3557 rajveer 11
    VendorItemMapping, Vendor, SimilarItems, ProductNotification, Source, SourceItemPricing
122 ashish 12
from shop2020.thriftpy.model.v1.catalog.ttypes import \
2983 chandransh 13
    InventoryServiceException, status, ItemShippingInfo
2065 ankur.sing 14
from shop2020.model.v1.catalog.impl.Convertors import to_t_item,\
3557 rajveer 15
    to_t_vendor_item_pricing, to_t_source
94 ashish 16
import datetime
871 chandransh 17
import sys
2286 ankur.sing 18
from shop2020.utils.Utils import log_entry, to_py_date, log_risky_flag
621 chandransh 19
from sqlalchemy import desc, asc
3244 chandransh 20
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
1970 rajveer 21
from shop2020.model.v1.catalog.impl.CategoryManager import CategoryManager
3872 chandransh 22
from sqlalchemy.sql.expression import and_, or_, distinct, func
3086 rajveer 23
from string import Template
24
from shop2020.clients.HelperClient import HelperClient
3924 rajveer 25
import urllib2
26
from urllib2 import HTTPBasicAuthHandler
27
from shop2020.config.client.ConfigClient import ConfigClient
4318 rajveer 28
from shop2020.utils.EmailAttachmentSender import mail
94 ashish 29
 
30
def initialize():
31
    DataService.initialize()
32
 
3849 chandransh 33
def get_all_items_by_status(status, offset=0, limit=None):
34
    query = Item.query
35
    if status:
36
        query = query.filter_by(status=status)
37
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
38
    if limit:
39
        query = query.limit(limit)
40
    items = query.all()
41
    return items
42
 
43
def get_all_items(is_active, offset=0, limit=None):
103 ashish 44
    if is_active:
3849 chandransh 45
        items = get_all_items_by_status(status.ACTIVE, offset, limit)
103 ashish 46
    else:
3849 chandransh 47
        items = get_all_items_by_status(None, offset, limit)
766 rajveer 48
    return items
49
 
3849 chandransh 50
def get_item_count_by_status(use_status, status):
51
    if use_status:
52
        return Item.query.filter_by(status=status).count()
103 ashish 53
    else:
3849 chandransh 54
        return Item.query.count()
103 ashish 55
 
635 rajveer 56
def get_item(item_id):
766 rajveer 57
    item = Item.get_by(id=item_id)
58
    return item
94 ashish 59
 
635 rajveer 60
def get_items_by_catalog_id(catalog_id):
447 rajveer 61
    query = Item.query.filter_by(catalog_item_id=catalog_id)
437 rajveer 62
    try:
635 rajveer 63
        items = query.all()
64
        return get_thrift_item_list(items)
1399 rajveer 65
    except Exception as ex:
66
        print ex
437 rajveer 67
        raise InventoryServiceException(109, "Item not found")
68
 
576 chandransh 69
def is_active(item_id):
2983 chandransh 70
    t_item_shipping_info = ItemShippingInfo()
576 chandransh 71
    try:
635 rajveer 72
        item = get_item(item_id)
3281 chandransh 73
        t_item_shipping_info.isRisky = item.risky
74
        availability = __get_item_availability(item)
75
        if item.risky and availability <= 0 and item.status == status.ACTIVE:
76
            add_status_change_log(item, status.PAUSED_BY_RISK)
77
            item.status = status.PAUSED_BY_RISK
78
            item.status_description = "This item is currently out of stock"
79
            session.commit()
3924 rajveer 80
            #This will clear cache from tomcat
81
            __clear_homepage_cache()
2983 chandransh 82
        t_item_shipping_info.isActive = (item.status == status.ACTIVE)
3281 chandransh 83
        t_item_shipping_info.quantity = availability
576 chandransh 84
    except InventoryServiceException:
2983 chandransh 85
        print "[ERROR] Unexpected error:", sys.exc_info()[0]
86
    return t_item_shipping_info
87
 
2035 rajveer 88
def get_item_status_description(itemId):
89
    item = get_item(itemId)
90
    return item.status_description
563 chandransh 91
 
94 ashish 92
def get_Warehouse(warehouse_id):
93
    return Warehouse.get_by(id=warehouse_id)
94
 
122 ashish 95
def get_all_warehouses_by_status(status):
96
    if not status:
766 rajveer 97
        warehouses = Warehouse.query.all()
122 ashish 98
    else:
851 chandransh 99
        warehouses = Warehouse.query.filter_by(status=status).all()
100
    return warehouses
122 ashish 101
 
94 ashish 102
def get_all_warehouses_for_item(item_id):
635 rajveer 103
    item = get_item(item_id)
94 ashish 104
    if not item:
122 ashish 105
        raise InventoryServiceException(108, "Some unforeseen error while obtaining item")
106
    return item.get_all_warehouses
94 ashish 107
 
122 ashish 108
def get_all_items_for_warehouse(warehouse_id):
109
    warehouse = get_Warehouse(warehouse_id)
110
    if not warehouse:
111
        raise InventoryServiceException(108, "bad warehouse")
112
    return warehouse.all_items
113
 
94 ashish 114
def add_warehouse(warehouse):
103 ashish 115
    if not warehouse:
122 ashish 116
        raise InventoryServiceException(108, "Bad warehouse")
103 ashish 117
    if get_Warehouse(warehouse.id):
118
        #warehouse is already present.
122 ashish 119
        raise InventoryServiceException(101, "Warehouse already present")
103 ashish 120
 
94 ashish 121
    ds_warehouse = Warehouse()
122
    ds_warehouse.id = warehouse.id
123
    ds_warehouse.location = warehouse.location
122 ashish 124
    ds_warehouse.status = status.ACTIVE
103 ashish 125
    ds_warehouse.addedOn = datetime.datetime.now()
483 rajveer 126
    ds_warehouse.lastCheckedOn = datetime.datetime.now()
127
    ds_warehouse.tinNumber = warehouse.tinNumber
128
    ds_warehouse.pincode = warehouse.pincode
129
    if warehouse.vendorString:
130
        ds_warehouse.vendorString = warehouse.vendorString
94 ashish 131
    session.commit()
103 ashish 132
    return ds_warehouse.id
94 ashish 133
 
122 ashish 134
def update_item(item):
135
    if not item:
136
        raise InventoryServiceException(108, "Bad item in request")
137
 
138
    if not item.id:
609 chandransh 139
        raise InventoryServiceException(101, "Missing id for update")
122 ashish 140
 
2120 ankur.sing 141
    validate_item_prices(item)
2065 ankur.sing 142
 
635 rajveer 143
    ds_item = get_item(item.id)
122 ashish 144
 
145
    if not ds_item:
609 chandransh 146
        raise InventoryServiceException(101, "Item missing in our database")
122 ashish 147
 
963 chandransh 148
    if item.productGroup:
149
        ds_item.product_group = item.productGroup 
150
    if item.brand:
151
        ds_item.brand = item.brand
511 rajveer 152
    if item.modelNumber:
153
        ds_item.model_number = item.modelNumber
2497 ankur.sing 154
    ds_item.color = item.color
155
    ds_item.model_name = item.modelName
156
    ds_item.category = item.category
157
    ds_item.comments = item.comments
511 rajveer 158
 
2497 ankur.sing 159
    ds_item.catalog_item_id = item.catalogItemId
483 rajveer 160
 
2129 ankur.sing 161
    ds_item.mrp = item.mrp
162
    ds_item.sellingPrice = item.sellingPrice
2497 ankur.sing 163
 
2174 ankur.sing 164
    ds_item.weight = item.weight
2129 ankur.sing 165
 
2358 ankur.sing 166
    if ds_item.status != item.itemStatus:
2402 rajveer 167
        add_status_change_log(ds_item, item.itemStatus)
2358 ankur.sing 168
        ds_item.status = item.itemStatus
2035 rajveer 169
    if item.status_description:
170
        ds_item.status_description = item.status_description
122 ashish 171
 
511 rajveer 172
    if item.startDate:
2116 ankur.sing 173
        ds_item.startDate = to_py_date(item.startDate)
2497 ankur.sing 174
    else:
175
        ds_item.startDate = None
511 rajveer 176
    if item.retireDate:
2116 ankur.sing 177
        ds_item.retireDate = to_py_date(item.retireDate)
2497 ankur.sing 178
    else:
179
        ds_item.retireDate = None
511 rajveer 180
 
2497 ankur.sing 181
    ds_item.feature_id = item.featureId
182
    ds_item.feature_description = item.featureDescription
122 ashish 183
 
2129 ankur.sing 184
    ds_item.bestDealText = item.bestDealText
185
    ds_item.bestDealValue = item.bestDealValue
2065 ankur.sing 186
    ds_item.bestSellingRank = item.bestSellingRank
2497 ankur.sing 187
 
2065 ankur.sing 188
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 189
    ds_item.risky = item.risky
3359 chandransh 190
 
3459 chandransh 191
    if item.expectedDelay is not None:
3359 chandransh 192
        ds_item.expectedDelay = item.expectedDelay
193
 
194
    if item.preferredWarehouse:
195
        ds_item.preferredWarehouse = item.preferredWarehouse
196
 
2347 ankur.sing 197
    ds_item.updatedOn = datetime.datetime.now()
2065 ankur.sing 198
 
122 ashish 199
    session.commit();
200
    return ds_item.id
94 ashish 201
 
2116 ankur.sing 202
def check_vendor_item_mapping(product_group, brand, model_number, color, vendor_id, vendor_category):
203
    key = product_group.strip().lower() + '|' + brand.strip().lower() + '|' + model_number.strip().lower() + '|' + color.strip().lower()
204
    try:
205
        vim = VendorItemMapping.query.filter_by(vendor_id=vendor_id, item_key=key, vendor_category=vendor_category).one()
206
        return True
207
    except:
208
        return False
209
 
103 ashish 210
def add_item(item):
211
    if not item:
122 ashish 212
        raise InventoryServiceException(108, "Bad item in request")
635 rajveer 213
    if get_item(item.id):
122 ashish 214
        raise InventoryServiceException(101, "Item already exists")
2120 ankur.sing 215
 
216
    validate_item_prices(item)
217
 
103 ashish 218
    ds_item = Item()
963 chandransh 219
    if item.productGroup:
220
        ds_item.product_group = item.productGroup
221
    if item.brand:
222
        ds_item.brand = item.brand
515 rajveer 223
    if item.modelName:
224
        ds_item.model_name = item.modelName
225
    if item.modelNumber:
226
        ds_item.model_number = item.modelNumber
609 chandransh 227
    if item.color:
228
        ds_item.color = item.color
2116 ankur.sing 229
    if item.hotspotCategory:
230
        ds_item.hotspotCategory = item.hotspotCategory
231
        if item.hotspotCategory == 'Handsets':
2403 ankur.sing 232
            ds_item.preferredWarehouse = 1
2116 ankur.sing 233
        else:
2403 ankur.sing 234
            ds_item.preferredWarehouse = 2
2116 ankur.sing 235
 
483 rajveer 236
    if item.category:
237
        ds_item.category = item.category
238
    if item.comments:
239
        ds_item.comments = item.comments
240
 
103 ashish 241
    ds_item.addedOn = datetime.datetime.now()
609 chandransh 242
    ds_item.updatedOn = datetime.datetime.now()
2116 ankur.sing 243
    if item.startDate:
244
        ds_item.startDate = to_py_date(item.startDate)
245
    if item.retireDate:
246
        ds_item.retireDate = to_py_date(item.retireDate)
609 chandransh 247
 
483 rajveer 248
    if item.mrp:
249
        ds_item.mrp = item.mrp
250
    if item.sellingPrice:
251
        ds_item.sellingPrice = item.sellingPrice
122 ashish 252
    if item.weight:
253
        ds_item.weight = item.weight
254
 
255
    if item.featureId:
256
        ds_item.feature_id = item.featureId
257
    if item.featureDescription:
258
        ds_item.feature_description = item.featureDescription
259
 
103 ashish 260
    if item.otherInfo:
261
        for k,v in item.otherInfo.iteritems():
262
            info = ItemInfo()
263
            info.key = k
264
            info.value = v
265
            ds_item.iteminfo.append(info)
2116 ankur.sing 266
 
103 ashish 267
    #check if categories present. If yes, add them to system
122 ashish 268
 
609 chandransh 269
    if item.bestDealValue:
270
        ds_item.bestDealValue = item.bestDealValue
271
    if item.bestDealText:
272
        ds_item.bestDealText = item.bestDealText
2116 ankur.sing 273
    if item.bestSellingRank:
274
        ds_item.bestSellingRank = item.bestSellingRank
275
    ds_item.defaultForEntity = item.defaultForEntity
2251 ankur.sing 276
    ds_item.risky = item.risky
609 chandransh 277
 
3467 chandransh 278
    if item.expectedDelay is not None:
3359 chandransh 279
        ds_item.expectedDelay = item.expectedDelay
3467 chandransh 280
    else:
281
        ds_item.expectedDelay = 0
3359 chandransh 282
 
283
    if item.preferredWarehouse:
284
        ds_item.preferredWarehouse = item.preferredWarehouse
285
 
2116 ankur.sing 286
    # Check if a similar item already exists in our database
287
    similar_item = Item.query.filter_by(product_group=item.productGroup, brand = item.brand, model_number=item.modelNumber, hotspotCategory=item.hotspotCategory).first()
288
    print "[SIMILAR ITEM FOUND:] FOR {0} {1} {2} {3} {4}".format(item.productGroup, item.brand, item.modelNumber, item.hotspotCategory, item.color)
289
 
290
    if similar_item is None or similar_item.catalog_item_id is None:
291
        # If there is no similar item in the database from before,
292
        # use the entity_id_generator
293
        entity_id = EntityIDGenerator.query.first()
294
        ds_item.catalog_item_id = entity_id.id + 1
295
        ds_item.status = status.IN_PROCESS
296
        ds_item.status_description = "This item is in process."
297
        entity_id.id = entity_id.id  + 1
298
    else:
299
        #If a similar item already exists for a product group, brand and model_number, set it as same.
300
        ds_item.catalog_item_id = similar_item.catalog_item_id
301
        ds_item.category = similar_item.category
302
        ds_item.status = similar_item.status
303
        ds_item.status_description = similar_item.status_description
304
 
103 ashish 305
    session.commit();
3325 chandransh 306
    return ds_item.id
307
 
308
def update_inventory_history(warehouse_id, timestamp, availability):
309
    warehouse = get_Warehouse(warehouse_id)
310
    if not warehouse:
311
        raise InventoryServiceException(107, "Warehouse? Where?")
312
    vendor = warehouse.vendor 
313
    time = datetime.datetime.now()
314
    for item_key, quantity in availability.iteritems():
315
        try:
316
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
317
            item = vendor_item_mapping.item
318
        except:
319
            continue  
320
        try:
321
            item_inventory_history = ItemInventoryHistory()
322
            item_inventory_history.warehouse = warehouse
323
            item_inventory_history.item = item
324
            item_inventory_history.timestamp = time
325
            item_inventory_history.availibility = quantity
326
        except:
327
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
328
    session.commit()
103 ashish 329
 
483 rajveer 330
def update_inventory(warehouse_id, timestamp, availability):
331
    warehouse = get_Warehouse(warehouse_id)
332
    if not warehouse:
333
        raise InventoryServiceException(107, "Warehouse? Where?")
334
 
335
    time = datetime.datetime.now()
336
    warehouse.lastCheckedOn = time
337
    warehouse.vendorString = timestamp
1368 chandransh 338
    vendor = warehouse.vendor
2368 ankur.sing 339
    session.commit()
1368 chandransh 340
    for item_key, quantity in availability.iteritems():
483 rajveer 341
        try:
1368 chandransh 342
            vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();
343
            item = vendor_item_mapping.item
494 rajveer 344
        except:
345
            continue  
346
        try:
483 rajveer 347
            current_inventory_snapshot = CurrentInventorySnapshot.get_by(item=item, warehouse=warehouse)
348
            if not current_inventory_snapshot:
349
                current_inventory_snapshot = CurrentInventorySnapshot()
350
                current_inventory_snapshot.item = item
351
                current_inventory_snapshot.warehouse = warehouse
352
                current_inventory_snapshot.availibility = 0
871 chandransh 353
                current_inventory_snapshot.reserved = 0
483 rajveer 354
            # added the difference in the current inventory    
355
            current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
356
        except:
357
            raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
2368 ankur.sing 358
        session.commit() 
359
        check_risky_item(item)
483 rajveer 360
 
94 ashish 361
def get_item_inventoy(item_id):
362
 
363
    inventory = Item.get_by(id=item_id).currentInventory
364
    if not inventory:
122 ashish 365
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
94 ashish 366
    return inventory
367
 
635 rajveer 368
def get_item_inventory_by_item_id(item_id):
369
    inventory = Item.get_by(id=item_id).currentInventory
379 ashish 370
    if not inventory:
371
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
372
    return inventory
373
 
103 ashish 374
 
375
def retire_warehouse(warehouse_id):
376
    if not warehouse_id:
122 ashish 377
        raise InventoryServiceException(101, "Bad warehouse id")
103 ashish 378
    warehouse = get_Warehouse(warehouse_id)
379
    if not warehouse:
122 ashish 380
        raise InventoryServiceException(108, "warehouse id not present")
381
    warehouse.status = status.DELETED;
103 ashish 382
    session.commit()
383
 
384
def retire_item(item_id):
385
    if not item_id:
122 ashish 386
        raise InventoryServiceException(101, "bad item id")
635 rajveer 387
    item = get_item(item_id)
103 ashish 388
    if not item:
122 ashish 389
        raise InventoryServiceException(108, "item id not present")
390
    item.status = status.PHASED_OUT
391
    item.retireDate = datetime.datetime.now()
103 ashish 392
    session.commit()
122 ashish 393
 
394
#need to implement threads based solution here
103 ashish 395
def start_item_on(item_id, timestamp):
396
    if not item_id:
122 ashish 397
        raise InventoryServiceException(101, "bad item id")
635 rajveer 398
    item = get_item(item_id)
103 ashish 399
    if not item:
122 ashish 400
        raise InventoryServiceException(108, "item id not present")
103 ashish 401
 
122 ashish 402
    item.status = status.ACTIVE
403
    item.startDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
404
    add_status_change_log(item, status.ACTIVE)
103 ashish 405
    session.commit()
406
 
122 ashish 407
#need to implement threads here
103 ashish 408
def retire_item_on(item_id, timestamp):
409
    if not item_id:
122 ashish 410
        raise InventoryServiceException(101, "bad item id")
635 rajveer 411
    item = get_item(item_id)
103 ashish 412
    if not item:
122 ashish 413
        raise InventoryServiceException(108, "item id not present")
103 ashish 414
 
122 ashish 415
    item.status = status.PHASED_OUT
416
    item.retireDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
417
    add_status_change_log(item, status.PHASED_OUT)
103 ashish 418
    session.commit()
419
 
420
def add_status_change_log(item, new_status):
421
    item_change_log = ItemChangeLog()
422
    item_change_log.new_status = new_status
423
    item_change_log.old_status = item.status
424
    item_change_log.timestamp = datetime.datetime.now()
425
    item_change_log.item = item
426
    session.commit()
427
 
428
def change_item_status(item_id, new_status):
429
    if not item_id:
122 ashish 430
        raise InventoryServiceException(101, "bad item id")
635 rajveer 431
    item = get_item(item_id)
103 ashish 432
    if not item:
122 ashish 433
        raise InventoryServiceException(108, "item id not present")
2116 ankur.sing 434
    add_status_change_log(item, new_status)
122 ashish 435
    item.status = new_status
2251 ankur.sing 436
    if item.status == status.PHASED_OUT:
437
        item.status_description = "This item has been phased out"
438
    elif item.status == status.DELETED:
439
        item.status_description = "This item has been deleted"
3924 rajveer 440
    elif item.status == status.PAUSED:
441
        item.status_description = "This item is currently out of stock"      
442
    elif item.status == status.PAUSED_BY_RISK:
443
        item.status_description = "This item is currently out of stock"
444
        #This will clear cache from tomcat
445
        __clear_homepage_cache()  
2251 ankur.sing 446
    elif item.status == status.ACTIVE:
447
        item.status_description = "This item is active"
448
    elif item.status == status.IN_PROCESS:
449
        item.status_description = "This item is in process"
450
    elif item.status == status.CONTENT_COMPLETE:
451
        item.status_description = "This item is in process"
103 ashish 452
    session.commit()
453
 
454
def get_item_availability_for_warehouse(warehouse_id, item_id):
455
    if not warehouse_id:
122 ashish 456
        raise InventoryServiceException(101, "bad warehouse_id")
103 ashish 457
    if not item_id:
122 ashish 458
        raise InventoryServiceException(101, "bad item_id")
103 ashish 459
 
460
    warehouse = get_Warehouse(warehouse_id)
461
    if not warehouse:
122 ashish 462
        raise InventoryServiceException(108, "warehouse does not exist")
635 rajveer 463
    item = get_item(item_id)
504 rajveer 464
 
103 ashish 465
    if not item:
766 rajveer 466
        raise InventoryServiceException(108, "item does not exist")
122 ashish 467
 
494 rajveer 468
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id)
504 rajveer 469
    query = query.filter_by(item_id = item.id)
494 rajveer 470
    try:
471
        current_inventory_snapshot = query.one()
871 chandransh 472
        return current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
494 rajveer 473
    except:
474
        return 0
475
    """
476
    current_inventory_snapshot = CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id == warehouse_id, CurrentInventorySnapshot.item_id == item_id).one()
103 ashish 477
    if not current_inventory_snapshot:
478
        return 0
479
    else:
480
        return current_inventory_snapshot.availibility
494 rajveer 481
    """
643 chandransh 482
 
2368 ankur.sing 483
def check_risky_item(item):
2251 ankur.sing 484
    if not item.risky:
485
        return
2983 chandransh 486
    availability = __get_item_availability(item)
487
    if availability <= 0:
2251 ankur.sing 488
        if item.status == status.ACTIVE:
2984 rajveer 489
            change_item_status(item.id, status.PAUSED_BY_RISK)
4318 rajveer 490
            try:
4319 rajveer 491
                mail("cnc.center@shop2020.in", "5h0p2o2o", "chaitnaya.vats@shop2020.in", "Item is out of stock. " + item.brand +  " " + item.model_name + " " + item.model_number, "", [])
4318 rajveer 492
            except:
493
                print "Unable to send the report"
2251 ankur.sing 494
    else:
2984 rajveer 495
        if item.status == status.PAUSED_BY_RISK:
2251 ankur.sing 496
            change_item_status(item.id, status.ACTIVE)
2368 ankur.sing 497
    session.commit()
2251 ankur.sing 498
 
2983 chandransh 499
def __get_item_availability(item):
500
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
501
    availability = 0
502
    reserved = 0
503
    for currInv in all_inventory:
504
        availability = availability + currInv.availibility
505
        reserved = reserved + currInv.reserved
506
    return availability - reserved
507
 
871 chandransh 508
def reserve_item_in_warehouse(item_id, warehouse_id, quantity):    
509
    if not warehouse_id:
510
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 511
    item = get_item(item_id)
512
    if not item:
871 chandransh 513
        raise InventoryServiceException(101, "bad item_id")
514
 
515
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
516
    try:
517
        current_inventory_snapshot = query.one()
518
    except:
4103 chandransh 519
        current_inventory_snapshot = CurrentInventorySnapshot()
520
        current_inventory_snapshot.warehouse_id = warehouse_id
521
        current_inventory_snapshot.item_id = item_id
522
        current_inventory_snapshot.availibility = 0
523
        current_inventory_snapshot.reserved = 0
524
 
525
    current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
526
    session.commit()
527
    check_risky_item(item)
528
    return True
871 chandransh 529
 
530
def reduce_reservation_count(item_id, warehouse_id, quantity):
531
    if not warehouse_id:
532
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 533
    item = get_item(item_id)
534
    if not item:
871 chandransh 535
        raise InventoryServiceException(101, "bad item_id")
536
 
537
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
538
    try:
539
        current_inventory_snapshot = query.one()
540
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
4318 rajveer 541
        ##FIXME In case of our own warehouse reduce availability also
542
        if warehouse_id == 7:
543
            current_inventory_snapshot.availability = current_inventory_snapshot.availability - quantity
871 chandransh 544
        session.commit()
2368 ankur.sing 545
        check_risky_item(item)
871 chandransh 546
        return True
547
    except:
548
        print "Unexpected error:", sys.exc_info()[0]
549
        return False
550
 
2075 rajveer 551
def mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):
2828 rajveer 552
    '''
553
    Get all the items for this entityID and update category, brand, modelName and modelNumber for all.
554
    Update Status for only IN_PROCESS items to CONTENT_COMPLETE
555
    '''
723 chandransh 556
    content_complete_status = status.CONTENT_COMPLETE
2828 rajveer 557
    items = Item.query.filter_by(catalog_item_id=entity_id).all()
723 chandransh 558
    current_timestamp = datetime.datetime.now()
559
    for item in items:
2828 rajveer 560
        if item.status == status.IN_PROCESS:
561
            item.status = content_complete_status
562
            item_change_log = ItemChangeLog()
563
            item_change_log.old_status = item.status
564
            item_change_log.new_status = content_complete_status
565
            item_change_log.timestamp = current_timestamp
566
            item_change_log.item = item
723 chandransh 567
 
2075 rajveer 568
        item.category = category
569
        item.brand = brand
2081 rajveer 570
        item.model_name = modelName
571
        item.model_number = modelNumber
723 chandransh 572
        item.updatedOn = current_timestamp
573
    session.commit()
574
    return True
1294 chandransh 575
 
643 chandransh 576
def get_item_availability_for_location(warehouse_loc, item_id):
3355 chandransh 577
    """
578
    Determines the warehouse that should be used to fulfil an order for the given item.
579
    It first checks all the warehouses which are in the logistics location given by the
580
    warehouse_loc parameter. If none of the warehouses there have any inventory, then the
581
    preferred warehouse for the item is used.
582
 
583
    Returns an ordered list of size 4 with following elements in the given order:
584
    1. Logistics location of the warehouse which was finally picked up to ship the order.
585
    2. Id of the warehouse which was finally picked up.
586
    3. Inventory size in the selected warehouse.
587
    4. Expected delay added by the category manager.
588
 
589
    Parameters:
590
     - warehouse_loc
591
     - item_id
592
    """
643 chandransh 593
    if warehouse_loc is None:
594
        raise InventoryServiceException(101, "Bad Warehouse Location")
595
    if not item_id:
1416 chandransh 596
        raise InventoryServiceException(101, "Bad Item id")
643 chandransh 597
 
1416 chandransh 598
    item = Item.get_by(id=item_id)
3355 chandransh 599
 
600
    #First try all warehouses in the suggested location.
643 chandransh 601
    warehouses = Warehouse.query.filter_by(logisticsLocation=warehouse_loc).all()
602
    warehouse_ids = [warehouse.id for warehouse in warehouses]
603
    warehouse_retid = -1
3503 chandransh 604
    max_availability = 0
605
    total_availability = 0
643 chandransh 606
    for warehouse_id in warehouse_ids:
785 rajveer 607
        try:
871 chandransh 608
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
609
            availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 610
        except Exception as e:
611
            print e
785 rajveer 612
            availability = 0    
3503 chandransh 613
        if availability > max_availability:
643 chandransh 614
            warehouse_retid = warehouse_id
3503 chandransh 615
            max_availability = availability
616
        total_availability = total_availability + availability
2341 chandransh 617
 
3355 chandransh 618
    #If no warehouse could be found, use the preferred warehouse for this item
643 chandransh 619
    if warehouse_retid == -1:
759 chandransh 620
        # This is the case when all warehouses have exhausted their
621
        # inventory of this item or no warehouse is available in this
622
        # location.
1416 chandransh 623
        warehouse_retid = int(item.preferredWarehouse)
2344 chandransh 624
        warehouse = Warehouse.get_by(id=warehouse_retid)
2341 chandransh 625
        try:
626
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item_id).one()
3503 chandransh 627
            max_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 628
        except Exception as e:
629
            print e
3503 chandransh 630
            max_availability = 0
631
        total_availability = max_availability
643 chandransh 632
 
4317 varun.gupt 633
    if item.expectedDelay is None:
634
        print 'expectedDelay field for this item was Null. Resetting it to 0'
635
        item.expectedDelay = 0
636
 
3503 chandransh 637
    return [warehouse.logisticsLocation, warehouse_retid, total_availability, item.expectedDelay]
2341 chandransh 638
 
122 ashish 639
def get_warehouses_for_item(item_id):
643 chandransh 640
 
122 ashish 641
    if not item_id:
642
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 643
    item = get_item(item_id)
122 ashish 644
 
645
    if not item:
646
        raise InventoryServiceException(101, "bad item")
647
 
483 rajveer 648
    warehouses = item.currentInventory.warehouse
501 rajveer 649
    return warehouses
650
 
2404 chandransh 651
def get_child_categories(category):
652
    cm = CategoryManager()
2621 varun.gupt 653
    cat = cm.getCategory(category)
654
    return cat.children_category_ids if cat else None
2404 chandransh 655
 
626 chandransh 656
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 657
    '''
658
    Returns the Best Sellers between the start and the stop index in the given category
659
    '''
1926 rajveer 660
    query = get_best_sellers_query(category, None)
1098 chandransh 661
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 662
    return get_thrift_item_list(best_sellers)
663
 
2093 chandransh 664
def get_best_sellers_count(category=-1):
2404 chandransh 665
    '''
666
    Returns the number of best sellers in the given category
667
    '''
1926 rajveer 668
    count = get_best_sellers_query(category, None).count()
1120 rajveer 669
    if count is None:
670
        count = 0
766 rajveer 671
    return count
621 chandransh 672
 
1926 rajveer 673
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 674
    '''
675
    Returns the Best sellers for the given brand and category between the start and the stop index.
676
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
677
    '''
1926 rajveer 678
    query = get_best_sellers_query(category, brand)
1098 chandransh 679
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 680
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 681
 
1926 rajveer 682
def get_best_sellers_query(category, brand):
2404 chandransh 683
    '''
684
    Returns the query to be used for getting Best Sellers.
685
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
686
    '''
1098 chandransh 687
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 688
    if category != -1:
1970 rajveer 689
        all_categories = [category]
690
        child_categories = get_child_categories(category)
691
        if child_categories is not None:
692
            all_categories = all_categories + child_categories 
693
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 694
    if brand is not None:
695
        query = query.filter_by(brand=brand)
1098 chandransh 696
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 697
    return query
609 chandransh 698
 
1098 chandransh 699
def get_best_deals(category=-1):
2404 chandransh 700
    '''
701
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
702
    '''
703
    query = get_best_deals_query(Item, category, None)
1098 chandransh 704
    items = query.all()
609 chandransh 705
    return get_thrift_item_list(items)
706
 
1098 chandransh 707
def get_best_deals_count(category=-1):
2404 chandransh 708
    '''
709
    Returns the count of best deals in the given category.
710
    Ignores the category if it's -1.
711
    '''
712
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 713
    if count is None:
714
        count = 0
766 rajveer 715
    return count
501 rajveer 716
 
1926 rajveer 717
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 718
    '''
719
    Returns the catalog_item_ids of best deal items for the given brand and category.
720
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
721
    '''
722
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 723
    best_deal_items = query.all()[start_index:stop_index]
724
    return [item.catalog_item_id for item in best_deal_items]
725
 
2404 chandransh 726
def get_best_deals_counting_query(obj, category, brand):
727
    '''
728
    Returns the query to be used to select the best deals in the given brand and category.
729
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
730
    '''
731
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 732
    if category != -1:
1970 rajveer 733
        all_categories = [category]
734
        child_categories = get_child_categories(category)
735
        if child_categories is not None:
736
            all_categories = all_categories + child_categories 
737
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 738
    if brand is not None:
739
        query = query.filter_by(brand=brand)
2404 chandransh 740
    return query
741
 
742
def get_best_deals_query(obj, category, brand):
743
    '''
744
    Returns the query to be used to get the best deals in the given category and brand.
745
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
746
    '''
747
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 748
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
749
    return query
609 chandransh 750
 
1098 chandransh 751
def get_latest_arrivals(limit, category=-1):
2404 chandransh 752
    '''
753
    Returns up to limit number of Latest Arrivals in the given category.
754
    '''
2975 chandransh 755
    categories = []
756
    if category != -1:
757
        categories = [category]
758
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 759
    items = query.all()[0:limit]
609 chandransh 760
    return get_thrift_item_list(items)
598 chandransh 761
 
1098 chandransh 762
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 763
    '''
764
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 765
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 766
    '''
2975 chandransh 767
    categories = []
768
    if category != -1:
769
        categories = [category]
770
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 771
    if count is None:
772
        count = 0
773
    count = min(count, limit)
766 rajveer 774
    return count
602 chandransh 775
 
2975 chandransh 776
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 777
    '''
778
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 779
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 780
    '''
2975 chandransh 781
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 782
    latest_arrivals = query.all()[start_index:stop_index]
783
    return [item.catalog_item_id for item in latest_arrivals]
784
 
2975 chandransh 785
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 786
    '''
787
    Returns the query to be used to count Latest arrivals.
3016 chandransh 788
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 789
    '''
790
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 791
 
792
    all_categories = []
793
    for category in categories:
794
        all_categories.append(category)
1970 rajveer 795
        child_categories = get_child_categories(category)
2975 chandransh 796
        if child_categories:
797
            all_categories = all_categories + child_categories
798
    if all_categories: 
1970 rajveer 799
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 800
 
1926 rajveer 801
    if brand is not None:
802
        query = query.filter_by(brand=brand)
2404 chandransh 803
    return query
804
 
2975 chandransh 805
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 806
    '''
807
    Returns the query to be used to retrieve Latest Arrivals.
808
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
809
    '''
2975 chandransh 810
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 811
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
812
    return query
609 chandransh 813
 
814
def get_thrift_item_list(items):
1098 chandransh 815
    return [to_t_item(item) for item in items if item != None]
635 rajveer 816
 
1155 rajveer 817
def generate_new_entity_id():
818
    generator =  EntityIDGenerator.query.one()
819
    id = generator.id + 1
820
    generator.id = id
821
    session.commit()
822
    return id
823
 
635 rajveer 824
def put_category_object(object):
825
    category = Category.get_by(id=1)
826
    if category is None:
827
        category = Category()
828
    category.object = object    
829
    session.commit()
830
    return True
831
 
832
def get_category_object():
766 rajveer 833
    object = Category.get_by(id=1).object
834
    return object
835
 
4283 anupam.sin 836
def get_item_pricing(item_id, vendorId):
1341 chandransh 837
    item = Item.query.filter_by(id=item_id).first()
838
    if item is None:
839
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 840
    '''
841
    if vendor id is -1 then we calculate an average transfer price to be populated
842
    at the time of order creation. This will be later updated with actual transfer price
843
    at the time of billing.
844
    '''
845
    if(vendorId == -1):
846
        try:
847
            item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 848
            if item_pricings:
4307 anupam.sin 849
                for item_pricing in item_pricings:
4315 anupam.sin 850
                    total =+ item_pricing.transfer_price
851
                avg = total / len(item_pricings)
852
                item_pricing.transfer_price = avg
853
                return item_pricing
4307 anupam.sin 854
        except:
855
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 856
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 857
    try:
858
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 859
        return item_pricing
3244 chandransh 860
    except MultipleResultsFound:
1341 chandransh 861
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 862
    except NoResultFound:
1341 chandransh 863
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
864
 
1970 rajveer 865
def add_category(t_category):
866
    category = Category.get_by(id=t_category.id)
867
    if category is None:
868
        category = Category()
869
    category.id = t_category.id 
870
    category.label = t_category.label
871
    category.description = t_category.description
872
    category.parent_category_id = t_category.parent_category_id 
873
    session.commit()
874
    return True
875
 
876
def get_category(id):
877
    return Category.query.filter_by(id=id).first()
878
 
879
def get_all_categories():
880
    return Category.query.all()
881
 
1991 ankur.sing 882
 
883
def get_all_item_pricing(item_id):
884
    item = Item.query.filter_by(id=item_id).first()
885
    if item is None:
886
        raise InventoryServiceException(101, "Bad Item")
887
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
888
    return item_pricing
889
 
2116 ankur.sing 890
def get_item_mappings(item_id):
891
    item = Item.query.filter_by(id=item_id).first()
892
    if item is None:
893
        raise InventoryServiceException(101, "Bad Item")
894
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
895
    return item_mappings
896
 
897
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 898
    if not vendorItemPricing:
899
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
900
    vendorId = vendorItemPricing.vendorId
901
    itemId = vendorItemPricing.itemId
902
 
903
    try:
904
        vendor = Vendor.query.filter_by(id=vendorId).one()
905
    except:
906
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
907
 
908
    try:
909
        item = Item.query.filter_by(id=itemId).one()
910
    except:
911
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
912
 
2120 ankur.sing 913
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 914
 
1991 ankur.sing 915
    try:
916
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
917
    except:
2116 ankur.sing 918
        ds_vendorItemPricing = VendorItemPricing()
919
        ds_vendorItemPricing.vendor = vendor
920
        ds_vendorItemPricing.item = item
1991 ankur.sing 921
 
922
    if vendorItemPricing.mop:
923
        ds_vendorItemPricing.mop = vendorItemPricing.mop
924
    if vendorItemPricing.dealerPrice:
925
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
926
    if vendorItemPricing.transferPrice:
2065 ankur.sing 927
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 928
 
929
    session.commit()
930
    return
931
 
2358 ankur.sing 932
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 933
    if not vendorItemMapping:
934
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
935
    vendorId = vendorItemMapping.vendorId
936
    itemId = vendorItemMapping.itemId
937
 
938
    try:
939
        vendor = Vendor.query.filter_by(id=vendorId).one()
940
    except:
941
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
942
 
943
    try:
944
        item = Item.query.filter_by(id=itemId).one()
945
    except:
946
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
947
 
948
    try:
2358 ankur.sing 949
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 950
    except:
951
        ds_vendorItemMapping = VendorItemMapping()
952
        ds_vendorItemMapping.vendor = vendor
953
        ds_vendorItemMapping.item = item
2497 ankur.sing 954
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 955
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
956
 
957
    session.commit()
958
    return
959
 
2120 ankur.sing 960
def validate_item_prices(item):
2129 ankur.sing 961
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
962
        return
963
    if item.mrp < item.sellingPrice:
2120 ankur.sing 964
        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))
965
        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 966
    return
2120 ankur.sing 967
 
968
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 969
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 970
        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))
971
        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)))
972
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
973
        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))
974
        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)))
975
    return
2065 ankur.sing 976
 
977
def get_all_vendors():
978
    return Vendor.query.all()
979
 
2116 ankur.sing 980
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 981
    query = Item.query
2428 ankur.sing 982
    query = query.filter_by(product_group=product_group)
983
    query = query.filter_by(brand=brand)
984
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 985
    if color:
986
        query = query.filter_by(color=color)
987
    item = query.first()
2116 ankur.sing 988
    if item is None:
989
        return 0
990
    else:
991
        return item.id
2286 ankur.sing 992
 
993
def change_risky_flag(item_id, risky):
994
    item = get_item(item_id)
995
    if not item:
996
        raise InventoryServiceException(101, "Item missing in our database")
997
    try:
998
        log_risky_flag(item_id, risky)
999
    except:
1000
        print "Not able to log risky flag change"
1001
    item.risky = risky
4295 varun.gupt 1002
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1003
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1004
    session.commit()
1005
 
2358 ankur.sing 1006
def get_items_by_vendor_category(vendor_category):
1007
    if not vendor_category:
1008
        raise InventoryServiceException(101, "Invalid vendor category in request")
1009
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
1010
    items = query.all()
1011
    return items
2116 ankur.sing 1012
 
2358 ankur.sing 1013
def get_risky_items():
1014
    items = Item.query.filter_by(risky=True).all()
1015
    return items
3008 rajveer 1016
 
2809 rajveer 1017
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1018
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1019
    similar_items = query.all()
3289 rajveer 1020
    return_list = []
1021
    for similar_item in similar_items:
1022
        isActive = False
1023
        try:
1024
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1025
        except:
1026
            continue
1027
        for item in all_items:
1028
            isActive = isActive or item.status == status.ACTIVE
1029
        if isActive:
1030
            return_list.append(similar_item.catalog_item_id)
1031
    return return_list
2809 rajveer 1032
 
3079 rajveer 1033
def add_product_notification(itemId, email):
1034
    try:
3470 rajveer 1035
        try:
1036
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1037
        except:
1038
            product_notification = ProductNotification()
1039
            product_notification.email = email
1040
            product_notification.item_id = itemId
3079 rajveer 1041
        product_notification.addedOn = datetime.datetime.now()
1042
        session.commit()
1043
        return True
1044
    except:
1045
        return False
3086 rajveer 1046
 
1047
 
1048
def send_product_notifications():
1049
    product_notifications = ProductNotification.query.all()
1050
    for product_notification in product_notifications:
1051
        item = product_notification.item
1052
        availability = __get_item_availability(item)
3309 rajveer 1053
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1054
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1055
            product_notification.delete()
1056
    session.commit()
1057
    return True
1058
 
1059
def __get_product_name(item):
1060
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1061
    color = item.color
1062
    if color is not None and color != 'NA':
1063
        product_name = product_name + " (" + color + ")"
3201 rajveer 1064
    product_name = product_name.replace("  "," ")
3086 rajveer 1065
    return product_name
1066
 
1067
 
1068
def __get_product_url(item):
1069
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1070
    product_url = product_url.replace("--","-")
1071
    product_url = product_url.replace(" ","")
1072
    return product_url
1073
 
3348 varun.gupt 1074
def get_all_brands_by_category(category_id):
1075
    catm = CategoryManager()
1076
    child_categories = catm.getCategory(category_id).children_category_ids
1077
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1078
 
1079
    return [brand[0] for brand in brands]
3086 rajveer 1080
 
1081
def __enque_product_notification_email(email, product, date, url, itemId):
1082
 
1083
    html = """
1084
        <html>
1085
        <body>
1086
        <div>
1087
        <p>
1088
            Hi,<br /><br />
1089
            The product requested by you on $date is now available on saholic.com.
1090
        </p>
1091
 
1092
        <p>    
1093
        <strong>Product: $product </strong>
1094
        </p>
1095
 
1096
        <p>
1097
        Click the link below to visit the product: 
1098
        <br/>
1099
        $url
1100
        </p>
1101
        <p>
1102
        Regards,<br/>
1103
        Saholic Customer Support Team<br/>
1104
        www.saholic.com<br/>
1105
        Email: help@saholic.com<br/>
1106
        </p>
1107
        </div>
1108
        </body>
1109
        </html>
1110
        """
1111
 
1112
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1113
 
3086 rajveer 1114
    try:
1115
        helper_client = HelperClient().get_client()
1116
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1117
    except Exception as e:
1118
        print e
1119
 
3557 rajveer 1120
def get_all_sources():
1121
    sources = Source.query.all()
1122
    return [to_t_source(source) for source in sources]
3086 rajveer 1123
 
3557 rajveer 1124
def get_item_pricing_by_source(itemId, sourceId):
1125
    item = Item.query.filter_by(id=itemId).first()
1126
    if item is None:
1127
        raise InventoryServiceException(101, "Bad Item")
1128
 
1129
    source = Source.query.filter_by(id=sourceId).first()
1130
    if source is None:
1131
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1132
 
1133
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1134
    if item_pricing is None:
1135
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1136
    return item_pricing
1137
 
1138
def add_source_item_pricing(sourceItemPricing):
1139
    if not sourceItemPricing:
1140
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1141
 
1142
    if not sourceItemPricing.sellingPrice:
1143
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceId))
1144
 
1145
    sourceId = sourceItemPricing.sourceId
1146
    itemId = sourceItemPricing.itemId
1147
 
1148
    item = Item.query.filter_by(id=itemId).first()
1149
    if item is None:
1150
        raise InventoryServiceException(101, "Bad Item")
1151
 
1152
    source = Source.query.filter_by(id=sourceId).first()
1153
    if source is None:
1154
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1155
 
3564 rajveer 1156
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1157
    if ds_sourceItemPricing is None:
1158
        ds_sourceItemPricing = SourceItemPricing()
1159
        ds_sourceItemPricing.source = source
1160
        ds_sourceItemPricing.item = item
1161
 
1162
    if sourceItemPricing.mrp:
1163
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1164
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1165
 
1166
    session.commit()
1167
    return
1168
 
1169
def get_all_source_pricing(itemId):
1170
    item = Item.query.filter_by(id=itemId).first()
1171
    if item is None:
1172
        raise InventoryServiceException(101, "Bad Item")
1173
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1174
    return source_pricing
1175
 
1176
 
1177
def get_item_for_source(item_id, sourceId):
1178
    item = get_item(item_id)
1179
    if sourceId == -1:
1180
        return item
1181
    try:
1182
        sip = get_item_pricing_by_source(item_id, sourceId)
1183
        item.sellingPrice = sip.sellingPrice
1184
        if sip.mrp:
1185
            item.mrp = sip.mrp
1186
    except:
1187
        print "No source pricing"
1188
    return item
1189
 
3872 chandransh 1190
def search_items(search_terms, offset, limit):
1191
    query = Item.query
1192
 
1193
    query_clause = []
1194
 
1195
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1196
 
1197
    for search_term in search_terms:
1198
        query_clause.append(Item.brand.like(search_term))
1199
        query_clause.append(Item.model_number.like(search_term))
1200
        query_clause.append(Item.model_name.like(search_term))
1201
 
1202
    query = query.filter(or_(*query_clause))
1203
 
1204
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1205
    if limit:
1206
        query = query.limit(limit)
1207
    items = query.all()
1208
    return items
1209
 
1210
def get_search_result_count(search_terms):
1211
    query = Item.query
1212
 
1213
    query_clause = []
1214
 
1215
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1216
 
1217
    for search_term in search_terms:
1218
        query_clause.append(Item.brand.like(search_term))
1219
        query_clause.append(Item.model_number.like(search_term))
1220
        query_clause.append(Item.model_name.like(search_term))
1221
 
1222
    query = query.filter(or_(*query_clause))
1223
 
1224
    return query.count()
1225
 
3924 rajveer 1226
def __clear_homepage_cache():
1227
    try:
1228
        # create a password manager
1229
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1230
        # Add the username and password.
1231
        configclient = ConfigClient()
4310 rajveer 1232
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1233
        ips = ips.split(" ")
1234
 
1235
        for ip in ips:
4310 rajveer 1236
            try:
1237
                top_level_url = "http://" + ip + ":8080/"
1238
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1239
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1240
 
4310 rajveer 1241
                opener = urllib2.build_opener(handler)
3924 rajveer 1242
 
4310 rajveer 1243
                # use the opener to fetch a URL
1244
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1245
                print "Successfully cleared home page cache" + res.read()
1246
            except:
1247
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1248
    except:
1249
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1250
 
4062 chandransh 1251
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1252
    """
1253
    Returns a list of inventory stock for items for which there are pending orders.
1254
    """
4062 chandransh 1255
    warehouse_ids = [warehouse.id for warehouse in Warehouse.query.filter_by(vendor_id=vendor_id).all()]
4064 chandransh 1256
    pending_items_inventory = []
1257
    if warehouse_ids:
1258
        pending_items_inventory = session.query(CurrentInventorySnapshot.item_id, func.sum(CurrentInventorySnapshot.availibility), func.sum(CurrentInventorySnapshot.reserved)).filter(CurrentInventorySnapshot.warehouse_id.in_(warehouse_ids)).group_by(CurrentInventorySnapshot.item_id).having(func.sum(CurrentInventorySnapshot.reserved) > 0).all()
4024 chandransh 1259
    return pending_items_inventory
4295 varun.gupt 1260
 
1261
def get_product_notifications(start_datetime):
1262
    '''
1263
    Returns a list of Product Notification objects each representing user requests for notification
1264
    '''
1265
    query = ProductNotification.query
3924 rajveer 1266
 
4295 varun.gupt 1267
    if start_datetime:
1268
        query = query.filter(ProductNotification.addedOn > start_datetime)
1269
 
1270
    notifications = query.order_by(desc('addedOn')).all()
1271
    return notifications
1272
 
1273
def get_product_notification_request_count(start_datetime):
1274
    '''
1275
    Returns list of items and the counts of product notification requests
1276
    '''
1277
    print start_datetime
1278
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1279
 
1280
    if start_datetime:
1281
        query = query.filter(ProductNotification.addedOn > start_datetime)
1282
 
1283
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1284
    return counts
1285
 
766 rajveer 1286
def close_session():
1287
    if session.is_active:
1288
        print "session is active. closing it."
1399 rajveer 1289
        session.close()
3376 rajveer 1290
 
1291
def is_alive():
1292
    try:
1293
        session.query(Item.id).limit(1).one()
1294
        return True
1295
    except:
1296
        return False