Subversion Repositories SmartDukaan

Rev

Rev 4319 | Rev 4326 | 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
 
4320 rajveer 361
def add_inventory(itemId, warehouseId, quantity):
362
    current_inventory_snapshot = CurrentInventorySnapshot.get_by(item_id=itemId, warehouse_id=warehouseId)
363
    if not current_inventory_snapshot:
364
        current_inventory_snapshot = CurrentInventorySnapshot()
365
        current_inventory_snapshot.item_id = itemId
366
        current_inventory_snapshot.warehouse_id = warehouseId
367
        current_inventory_snapshot.availibility = 0
368
        current_inventory_snapshot.reserved = 0
369
    # added the difference in the current inventory    
370
    current_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantity
371
    session.commit() 
372
 
94 ashish 373
def get_item_inventoy(item_id):
374
 
375
    inventory = Item.get_by(id=item_id).currentInventory
376
    if not inventory:
122 ashish 377
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
94 ashish 378
    return inventory
379
 
635 rajveer 380
def get_item_inventory_by_item_id(item_id):
381
    inventory = Item.get_by(id=item_id).currentInventory
379 ashish 382
    if not inventory:
383
        raise InventoryServiceException(108, "Some unforeseen error while updating inventory")
384
    return inventory
385
 
103 ashish 386
 
387
def retire_warehouse(warehouse_id):
388
    if not warehouse_id:
122 ashish 389
        raise InventoryServiceException(101, "Bad warehouse id")
103 ashish 390
    warehouse = get_Warehouse(warehouse_id)
391
    if not warehouse:
122 ashish 392
        raise InventoryServiceException(108, "warehouse id not present")
393
    warehouse.status = status.DELETED;
103 ashish 394
    session.commit()
395
 
396
def retire_item(item_id):
397
    if not item_id:
122 ashish 398
        raise InventoryServiceException(101, "bad item id")
635 rajveer 399
    item = get_item(item_id)
103 ashish 400
    if not item:
122 ashish 401
        raise InventoryServiceException(108, "item id not present")
402
    item.status = status.PHASED_OUT
403
    item.retireDate = datetime.datetime.now()
103 ashish 404
    session.commit()
122 ashish 405
 
406
#need to implement threads based solution here
103 ashish 407
def start_item_on(item_id, timestamp):
408
    if not item_id:
122 ashish 409
        raise InventoryServiceException(101, "bad item id")
635 rajveer 410
    item = get_item(item_id)
103 ashish 411
    if not item:
122 ashish 412
        raise InventoryServiceException(108, "item id not present")
103 ashish 413
 
122 ashish 414
    item.status = status.ACTIVE
415
    item.startDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
416
    add_status_change_log(item, status.ACTIVE)
103 ashish 417
    session.commit()
418
 
122 ashish 419
#need to implement threads here
103 ashish 420
def retire_item_on(item_id, timestamp):
421
    if not item_id:
122 ashish 422
        raise InventoryServiceException(101, "bad item id")
635 rajveer 423
    item = get_item(item_id)
103 ashish 424
    if not item:
122 ashish 425
        raise InventoryServiceException(108, "item id not present")
103 ashish 426
 
122 ashish 427
    item.status = status.PHASED_OUT
428
    item.retireDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))
429
    add_status_change_log(item, status.PHASED_OUT)
103 ashish 430
    session.commit()
431
 
432
def add_status_change_log(item, new_status):
433
    item_change_log = ItemChangeLog()
434
    item_change_log.new_status = new_status
435
    item_change_log.old_status = item.status
436
    item_change_log.timestamp = datetime.datetime.now()
437
    item_change_log.item = item
438
    session.commit()
439
 
440
def change_item_status(item_id, new_status):
441
    if not item_id:
122 ashish 442
        raise InventoryServiceException(101, "bad item id")
635 rajveer 443
    item = get_item(item_id)
103 ashish 444
    if not item:
122 ashish 445
        raise InventoryServiceException(108, "item id not present")
2116 ankur.sing 446
    add_status_change_log(item, new_status)
122 ashish 447
    item.status = new_status
2251 ankur.sing 448
    if item.status == status.PHASED_OUT:
449
        item.status_description = "This item has been phased out"
450
    elif item.status == status.DELETED:
451
        item.status_description = "This item has been deleted"
3924 rajveer 452
    elif item.status == status.PAUSED:
453
        item.status_description = "This item is currently out of stock"      
454
    elif item.status == status.PAUSED_BY_RISK:
455
        item.status_description = "This item is currently out of stock"
456
        #This will clear cache from tomcat
457
        __clear_homepage_cache()  
2251 ankur.sing 458
    elif item.status == status.ACTIVE:
459
        item.status_description = "This item is active"
460
    elif item.status == status.IN_PROCESS:
461
        item.status_description = "This item is in process"
462
    elif item.status == status.CONTENT_COMPLETE:
463
        item.status_description = "This item is in process"
103 ashish 464
    session.commit()
465
 
466
def get_item_availability_for_warehouse(warehouse_id, item_id):
467
    if not warehouse_id:
122 ashish 468
        raise InventoryServiceException(101, "bad warehouse_id")
103 ashish 469
    if not item_id:
122 ashish 470
        raise InventoryServiceException(101, "bad item_id")
103 ashish 471
 
472
    warehouse = get_Warehouse(warehouse_id)
473
    if not warehouse:
122 ashish 474
        raise InventoryServiceException(108, "warehouse does not exist")
635 rajveer 475
    item = get_item(item_id)
504 rajveer 476
 
103 ashish 477
    if not item:
766 rajveer 478
        raise InventoryServiceException(108, "item does not exist")
122 ashish 479
 
494 rajveer 480
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id)
504 rajveer 481
    query = query.filter_by(item_id = item.id)
494 rajveer 482
    try:
483
        current_inventory_snapshot = query.one()
871 chandransh 484
        return current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
494 rajveer 485
    except:
486
        return 0
487
    """
488
    current_inventory_snapshot = CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id == warehouse_id, CurrentInventorySnapshot.item_id == item_id).one()
103 ashish 489
    if not current_inventory_snapshot:
490
        return 0
491
    else:
492
        return current_inventory_snapshot.availibility
494 rajveer 493
    """
643 chandransh 494
 
2368 ankur.sing 495
def check_risky_item(item):
2251 ankur.sing 496
    if not item.risky:
497
        return
2983 chandransh 498
    availability = __get_item_availability(item)
499
    if availability <= 0:
2251 ankur.sing 500
        if item.status == status.ACTIVE:
2984 rajveer 501
            change_item_status(item.id, status.PAUSED_BY_RISK)
4318 rajveer 502
            try:
4319 rajveer 503
                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 504
            except:
505
                print "Unable to send the report"
2251 ankur.sing 506
    else:
2984 rajveer 507
        if item.status == status.PAUSED_BY_RISK:
2251 ankur.sing 508
            change_item_status(item.id, status.ACTIVE)
2368 ankur.sing 509
    session.commit()
2251 ankur.sing 510
 
2983 chandransh 511
def __get_item_availability(item):
512
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
513
    availability = 0
514
    reserved = 0
515
    for currInv in all_inventory:
516
        availability = availability + currInv.availibility
517
        reserved = reserved + currInv.reserved
518
    return availability - reserved
519
 
871 chandransh 520
def reserve_item_in_warehouse(item_id, warehouse_id, quantity):    
521
    if not warehouse_id:
522
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 523
    item = get_item(item_id)
524
    if not item:
871 chandransh 525
        raise InventoryServiceException(101, "bad item_id")
526
 
527
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
528
    try:
529
        current_inventory_snapshot = query.one()
530
    except:
4103 chandransh 531
        current_inventory_snapshot = CurrentInventorySnapshot()
532
        current_inventory_snapshot.warehouse_id = warehouse_id
533
        current_inventory_snapshot.item_id = item_id
534
        current_inventory_snapshot.availibility = 0
535
        current_inventory_snapshot.reserved = 0
536
 
537
    current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
538
    session.commit()
539
    check_risky_item(item)
540
    return True
871 chandransh 541
 
542
def reduce_reservation_count(item_id, warehouse_id, quantity):
543
    if not warehouse_id:
544
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 545
    item = get_item(item_id)
546
    if not item:
871 chandransh 547
        raise InventoryServiceException(101, "bad item_id")
548
 
549
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
550
    try:
551
        current_inventory_snapshot = query.one()
552
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
4318 rajveer 553
        ##FIXME In case of our own warehouse reduce availability also
554
        if warehouse_id == 7:
555
            current_inventory_snapshot.availability = current_inventory_snapshot.availability - quantity
871 chandransh 556
        session.commit()
2368 ankur.sing 557
        check_risky_item(item)
871 chandransh 558
        return True
559
    except:
560
        print "Unexpected error:", sys.exc_info()[0]
561
        return False
562
 
2075 rajveer 563
def mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):
2828 rajveer 564
    '''
565
    Get all the items for this entityID and update category, brand, modelName and modelNumber for all.
566
    Update Status for only IN_PROCESS items to CONTENT_COMPLETE
567
    '''
723 chandransh 568
    content_complete_status = status.CONTENT_COMPLETE
2828 rajveer 569
    items = Item.query.filter_by(catalog_item_id=entity_id).all()
723 chandransh 570
    current_timestamp = datetime.datetime.now()
571
    for item in items:
2828 rajveer 572
        if item.status == status.IN_PROCESS:
573
            item.status = content_complete_status
574
            item_change_log = ItemChangeLog()
575
            item_change_log.old_status = item.status
576
            item_change_log.new_status = content_complete_status
577
            item_change_log.timestamp = current_timestamp
578
            item_change_log.item = item
723 chandransh 579
 
2075 rajveer 580
        item.category = category
581
        item.brand = brand
2081 rajveer 582
        item.model_name = modelName
583
        item.model_number = modelNumber
723 chandransh 584
        item.updatedOn = current_timestamp
585
    session.commit()
586
    return True
1294 chandransh 587
 
643 chandransh 588
def get_item_availability_for_location(warehouse_loc, item_id):
3355 chandransh 589
    """
590
    Determines the warehouse that should be used to fulfil an order for the given item.
591
    It first checks all the warehouses which are in the logistics location given by the
592
    warehouse_loc parameter. If none of the warehouses there have any inventory, then the
593
    preferred warehouse for the item is used.
594
 
595
    Returns an ordered list of size 4 with following elements in the given order:
596
    1. Logistics location of the warehouse which was finally picked up to ship the order.
597
    2. Id of the warehouse which was finally picked up.
598
    3. Inventory size in the selected warehouse.
599
    4. Expected delay added by the category manager.
600
 
601
    Parameters:
602
     - warehouse_loc
603
     - item_id
604
    """
643 chandransh 605
    if warehouse_loc is None:
606
        raise InventoryServiceException(101, "Bad Warehouse Location")
607
    if not item_id:
1416 chandransh 608
        raise InventoryServiceException(101, "Bad Item id")
643 chandransh 609
 
1416 chandransh 610
    item = Item.get_by(id=item_id)
3355 chandransh 611
 
612
    #First try all warehouses in the suggested location.
643 chandransh 613
    warehouses = Warehouse.query.filter_by(logisticsLocation=warehouse_loc).all()
614
    warehouse_ids = [warehouse.id for warehouse in warehouses]
615
    warehouse_retid = -1
3503 chandransh 616
    max_availability = 0
617
    total_availability = 0
643 chandransh 618
    for warehouse_id in warehouse_ids:
785 rajveer 619
        try:
871 chandransh 620
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
621
            availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 622
        except Exception as e:
623
            print e
785 rajveer 624
            availability = 0    
3503 chandransh 625
        if availability > max_availability:
643 chandransh 626
            warehouse_retid = warehouse_id
3503 chandransh 627
            max_availability = availability
628
        total_availability = total_availability + availability
2341 chandransh 629
 
3355 chandransh 630
    #If no warehouse could be found, use the preferred warehouse for this item
643 chandransh 631
    if warehouse_retid == -1:
759 chandransh 632
        # This is the case when all warehouses have exhausted their
633
        # inventory of this item or no warehouse is available in this
634
        # location.
1416 chandransh 635
        warehouse_retid = int(item.preferredWarehouse)
2344 chandransh 636
        warehouse = Warehouse.get_by(id=warehouse_retid)
2341 chandransh 637
        try:
638
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item_id).one()
3503 chandransh 639
            max_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 640
        except Exception as e:
641
            print e
3503 chandransh 642
            max_availability = 0
643
        total_availability = max_availability
643 chandransh 644
 
4317 varun.gupt 645
    if item.expectedDelay is None:
646
        print 'expectedDelay field for this item was Null. Resetting it to 0'
647
        item.expectedDelay = 0
648
 
3503 chandransh 649
    return [warehouse.logisticsLocation, warehouse_retid, total_availability, item.expectedDelay]
2341 chandransh 650
 
122 ashish 651
def get_warehouses_for_item(item_id):
643 chandransh 652
 
122 ashish 653
    if not item_id:
654
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 655
    item = get_item(item_id)
122 ashish 656
 
657
    if not item:
658
        raise InventoryServiceException(101, "bad item")
659
 
483 rajveer 660
    warehouses = item.currentInventory.warehouse
501 rajveer 661
    return warehouses
662
 
2404 chandransh 663
def get_child_categories(category):
664
    cm = CategoryManager()
2621 varun.gupt 665
    cat = cm.getCategory(category)
666
    return cat.children_category_ids if cat else None
2404 chandransh 667
 
626 chandransh 668
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 669
    '''
670
    Returns the Best Sellers between the start and the stop index in the given category
671
    '''
1926 rajveer 672
    query = get_best_sellers_query(category, None)
1098 chandransh 673
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 674
    return get_thrift_item_list(best_sellers)
675
 
2093 chandransh 676
def get_best_sellers_count(category=-1):
2404 chandransh 677
    '''
678
    Returns the number of best sellers in the given category
679
    '''
1926 rajveer 680
    count = get_best_sellers_query(category, None).count()
1120 rajveer 681
    if count is None:
682
        count = 0
766 rajveer 683
    return count
621 chandransh 684
 
1926 rajveer 685
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 686
    '''
687
    Returns the Best sellers for the given brand and category between the start and the stop index.
688
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
689
    '''
1926 rajveer 690
    query = get_best_sellers_query(category, brand)
1098 chandransh 691
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 692
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 693
 
1926 rajveer 694
def get_best_sellers_query(category, brand):
2404 chandransh 695
    '''
696
    Returns the query to be used for getting Best Sellers.
697
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
698
    '''
1098 chandransh 699
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 700
    if category != -1:
1970 rajveer 701
        all_categories = [category]
702
        child_categories = get_child_categories(category)
703
        if child_categories is not None:
704
            all_categories = all_categories + child_categories 
705
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 706
    if brand is not None:
707
        query = query.filter_by(brand=brand)
1098 chandransh 708
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 709
    return query
609 chandransh 710
 
1098 chandransh 711
def get_best_deals(category=-1):
2404 chandransh 712
    '''
713
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
714
    '''
715
    query = get_best_deals_query(Item, category, None)
1098 chandransh 716
    items = query.all()
609 chandransh 717
    return get_thrift_item_list(items)
718
 
1098 chandransh 719
def get_best_deals_count(category=-1):
2404 chandransh 720
    '''
721
    Returns the count of best deals in the given category.
722
    Ignores the category if it's -1.
723
    '''
724
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 725
    if count is None:
726
        count = 0
766 rajveer 727
    return count
501 rajveer 728
 
1926 rajveer 729
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 730
    '''
731
    Returns the catalog_item_ids of best deal items for the given brand and category.
732
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
733
    '''
734
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 735
    best_deal_items = query.all()[start_index:stop_index]
736
    return [item.catalog_item_id for item in best_deal_items]
737
 
2404 chandransh 738
def get_best_deals_counting_query(obj, category, brand):
739
    '''
740
    Returns the query to be used to select the best deals in the given brand and category.
741
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
742
    '''
743
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 744
    if category != -1:
1970 rajveer 745
        all_categories = [category]
746
        child_categories = get_child_categories(category)
747
        if child_categories is not None:
748
            all_categories = all_categories + child_categories 
749
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 750
    if brand is not None:
751
        query = query.filter_by(brand=brand)
2404 chandransh 752
    return query
753
 
754
def get_best_deals_query(obj, category, brand):
755
    '''
756
    Returns the query to be used to get the best deals in the given category and brand.
757
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
758
    '''
759
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 760
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
761
    return query
609 chandransh 762
 
1098 chandransh 763
def get_latest_arrivals(limit, category=-1):
2404 chandransh 764
    '''
765
    Returns up to limit number of Latest Arrivals in the given category.
766
    '''
2975 chandransh 767
    categories = []
768
    if category != -1:
769
        categories = [category]
770
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 771
    items = query.all()[0:limit]
609 chandransh 772
    return get_thrift_item_list(items)
598 chandransh 773
 
1098 chandransh 774
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 775
    '''
776
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 777
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 778
    '''
2975 chandransh 779
    categories = []
780
    if category != -1:
781
        categories = [category]
782
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 783
    if count is None:
784
        count = 0
785
    count = min(count, limit)
766 rajveer 786
    return count
602 chandransh 787
 
2975 chandransh 788
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 789
    '''
790
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 791
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 792
    '''
2975 chandransh 793
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 794
    latest_arrivals = query.all()[start_index:stop_index]
795
    return [item.catalog_item_id for item in latest_arrivals]
796
 
2975 chandransh 797
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 798
    '''
799
    Returns the query to be used to count Latest arrivals.
3016 chandransh 800
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 801
    '''
802
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 803
 
804
    all_categories = []
805
    for category in categories:
806
        all_categories.append(category)
1970 rajveer 807
        child_categories = get_child_categories(category)
2975 chandransh 808
        if child_categories:
809
            all_categories = all_categories + child_categories
810
    if all_categories: 
1970 rajveer 811
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 812
 
1926 rajveer 813
    if brand is not None:
814
        query = query.filter_by(brand=brand)
2404 chandransh 815
    return query
816
 
2975 chandransh 817
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 818
    '''
819
    Returns the query to be used to retrieve Latest Arrivals.
820
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
821
    '''
2975 chandransh 822
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 823
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
824
    return query
609 chandransh 825
 
826
def get_thrift_item_list(items):
1098 chandransh 827
    return [to_t_item(item) for item in items if item != None]
635 rajveer 828
 
1155 rajveer 829
def generate_new_entity_id():
830
    generator =  EntityIDGenerator.query.one()
831
    id = generator.id + 1
832
    generator.id = id
833
    session.commit()
834
    return id
835
 
635 rajveer 836
def put_category_object(object):
837
    category = Category.get_by(id=1)
838
    if category is None:
839
        category = Category()
840
    category.object = object    
841
    session.commit()
842
    return True
843
 
844
def get_category_object():
766 rajveer 845
    object = Category.get_by(id=1).object
846
    return object
847
 
4283 anupam.sin 848
def get_item_pricing(item_id, vendorId):
1341 chandransh 849
    item = Item.query.filter_by(id=item_id).first()
850
    if item is None:
851
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 852
    '''
853
    if vendor id is -1 then we calculate an average transfer price to be populated
854
    at the time of order creation. This will be later updated with actual transfer price
855
    at the time of billing.
856
    '''
857
    if(vendorId == -1):
858
        try:
859
            item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 860
            if item_pricings:
4307 anupam.sin 861
                for item_pricing in item_pricings:
4315 anupam.sin 862
                    total =+ item_pricing.transfer_price
863
                avg = total / len(item_pricings)
864
                item_pricing.transfer_price = avg
865
                return item_pricing
4307 anupam.sin 866
        except:
867
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 868
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 869
    try:
870
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 871
        return item_pricing
3244 chandransh 872
    except MultipleResultsFound:
1341 chandransh 873
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 874
    except NoResultFound:
1341 chandransh 875
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
876
 
1970 rajveer 877
def add_category(t_category):
878
    category = Category.get_by(id=t_category.id)
879
    if category is None:
880
        category = Category()
881
    category.id = t_category.id 
882
    category.label = t_category.label
883
    category.description = t_category.description
884
    category.parent_category_id = t_category.parent_category_id 
885
    session.commit()
886
    return True
887
 
888
def get_category(id):
889
    return Category.query.filter_by(id=id).first()
890
 
891
def get_all_categories():
892
    return Category.query.all()
893
 
1991 ankur.sing 894
 
895
def get_all_item_pricing(item_id):
896
    item = Item.query.filter_by(id=item_id).first()
897
    if item is None:
898
        raise InventoryServiceException(101, "Bad Item")
899
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
900
    return item_pricing
901
 
2116 ankur.sing 902
def get_item_mappings(item_id):
903
    item = Item.query.filter_by(id=item_id).first()
904
    if item is None:
905
        raise InventoryServiceException(101, "Bad Item")
906
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
907
    return item_mappings
908
 
909
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 910
    if not vendorItemPricing:
911
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
912
    vendorId = vendorItemPricing.vendorId
913
    itemId = vendorItemPricing.itemId
914
 
915
    try:
916
        vendor = Vendor.query.filter_by(id=vendorId).one()
917
    except:
918
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
919
 
920
    try:
921
        item = Item.query.filter_by(id=itemId).one()
922
    except:
923
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
924
 
2120 ankur.sing 925
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 926
 
1991 ankur.sing 927
    try:
928
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
929
    except:
2116 ankur.sing 930
        ds_vendorItemPricing = VendorItemPricing()
931
        ds_vendorItemPricing.vendor = vendor
932
        ds_vendorItemPricing.item = item
1991 ankur.sing 933
 
934
    if vendorItemPricing.mop:
935
        ds_vendorItemPricing.mop = vendorItemPricing.mop
936
    if vendorItemPricing.dealerPrice:
937
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
938
    if vendorItemPricing.transferPrice:
2065 ankur.sing 939
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 940
 
941
    session.commit()
942
    return
943
 
2358 ankur.sing 944
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 945
    if not vendorItemMapping:
946
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
947
    vendorId = vendorItemMapping.vendorId
948
    itemId = vendorItemMapping.itemId
949
 
950
    try:
951
        vendor = Vendor.query.filter_by(id=vendorId).one()
952
    except:
953
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
954
 
955
    try:
956
        item = Item.query.filter_by(id=itemId).one()
957
    except:
958
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
959
 
960
    try:
2358 ankur.sing 961
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 962
    except:
963
        ds_vendorItemMapping = VendorItemMapping()
964
        ds_vendorItemMapping.vendor = vendor
965
        ds_vendorItemMapping.item = item
2497 ankur.sing 966
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 967
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
968
 
969
    session.commit()
970
    return
971
 
2120 ankur.sing 972
def validate_item_prices(item):
2129 ankur.sing 973
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
974
        return
975
    if item.mrp < item.sellingPrice:
2120 ankur.sing 976
        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))
977
        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 978
    return
2120 ankur.sing 979
 
980
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 981
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 982
        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))
983
        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)))
984
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
985
        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))
986
        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)))
987
    return
2065 ankur.sing 988
 
989
def get_all_vendors():
990
    return Vendor.query.all()
991
 
2116 ankur.sing 992
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 993
    query = Item.query
2428 ankur.sing 994
    query = query.filter_by(product_group=product_group)
995
    query = query.filter_by(brand=brand)
996
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 997
    if color:
998
        query = query.filter_by(color=color)
999
    item = query.first()
2116 ankur.sing 1000
    if item is None:
1001
        return 0
1002
    else:
1003
        return item.id
2286 ankur.sing 1004
 
1005
def change_risky_flag(item_id, risky):
1006
    item = get_item(item_id)
1007
    if not item:
1008
        raise InventoryServiceException(101, "Item missing in our database")
1009
    try:
1010
        log_risky_flag(item_id, risky)
1011
    except:
1012
        print "Not able to log risky flag change"
1013
    item.risky = risky
4295 varun.gupt 1014
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1015
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1016
    session.commit()
1017
 
2358 ankur.sing 1018
def get_items_by_vendor_category(vendor_category):
1019
    if not vendor_category:
1020
        raise InventoryServiceException(101, "Invalid vendor category in request")
1021
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
1022
    items = query.all()
1023
    return items
2116 ankur.sing 1024
 
2358 ankur.sing 1025
def get_risky_items():
1026
    items = Item.query.filter_by(risky=True).all()
1027
    return items
3008 rajveer 1028
 
2809 rajveer 1029
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1030
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1031
    similar_items = query.all()
3289 rajveer 1032
    return_list = []
1033
    for similar_item in similar_items:
1034
        isActive = False
1035
        try:
1036
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1037
        except:
1038
            continue
1039
        for item in all_items:
1040
            isActive = isActive or item.status == status.ACTIVE
1041
        if isActive:
1042
            return_list.append(similar_item.catalog_item_id)
1043
    return return_list
2809 rajveer 1044
 
3079 rajveer 1045
def add_product_notification(itemId, email):
1046
    try:
3470 rajveer 1047
        try:
1048
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1049
        except:
1050
            product_notification = ProductNotification()
1051
            product_notification.email = email
1052
            product_notification.item_id = itemId
3079 rajveer 1053
        product_notification.addedOn = datetime.datetime.now()
1054
        session.commit()
1055
        return True
1056
    except:
1057
        return False
3086 rajveer 1058
 
1059
 
1060
def send_product_notifications():
1061
    product_notifications = ProductNotification.query.all()
1062
    for product_notification in product_notifications:
1063
        item = product_notification.item
1064
        availability = __get_item_availability(item)
3309 rajveer 1065
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1066
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1067
            product_notification.delete()
1068
    session.commit()
1069
    return True
1070
 
1071
def __get_product_name(item):
1072
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1073
    color = item.color
1074
    if color is not None and color != 'NA':
1075
        product_name = product_name + " (" + color + ")"
3201 rajveer 1076
    product_name = product_name.replace("  "," ")
3086 rajveer 1077
    return product_name
1078
 
1079
 
1080
def __get_product_url(item):
1081
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1082
    product_url = product_url.replace("--","-")
1083
    product_url = product_url.replace(" ","")
1084
    return product_url
1085
 
3348 varun.gupt 1086
def get_all_brands_by_category(category_id):
1087
    catm = CategoryManager()
1088
    child_categories = catm.getCategory(category_id).children_category_ids
1089
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1090
 
1091
    return [brand[0] for brand in brands]
3086 rajveer 1092
 
1093
def __enque_product_notification_email(email, product, date, url, itemId):
1094
 
1095
    html = """
1096
        <html>
1097
        <body>
1098
        <div>
1099
        <p>
1100
            Hi,<br /><br />
1101
            The product requested by you on $date is now available on saholic.com.
1102
        </p>
1103
 
1104
        <p>    
1105
        <strong>Product: $product </strong>
1106
        </p>
1107
 
1108
        <p>
1109
        Click the link below to visit the product: 
1110
        <br/>
1111
        $url
1112
        </p>
1113
        <p>
1114
        Regards,<br/>
1115
        Saholic Customer Support Team<br/>
1116
        www.saholic.com<br/>
1117
        Email: help@saholic.com<br/>
1118
        </p>
1119
        </div>
1120
        </body>
1121
        </html>
1122
        """
1123
 
1124
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1125
 
3086 rajveer 1126
    try:
1127
        helper_client = HelperClient().get_client()
1128
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1129
    except Exception as e:
1130
        print e
1131
 
3557 rajveer 1132
def get_all_sources():
1133
    sources = Source.query.all()
1134
    return [to_t_source(source) for source in sources]
3086 rajveer 1135
 
3557 rajveer 1136
def get_item_pricing_by_source(itemId, sourceId):
1137
    item = Item.query.filter_by(id=itemId).first()
1138
    if item is None:
1139
        raise InventoryServiceException(101, "Bad Item")
1140
 
1141
    source = Source.query.filter_by(id=sourceId).first()
1142
    if source is None:
1143
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1144
 
1145
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1146
    if item_pricing is None:
1147
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1148
    return item_pricing
1149
 
1150
def add_source_item_pricing(sourceItemPricing):
1151
    if not sourceItemPricing:
1152
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1153
 
1154
    if not sourceItemPricing.sellingPrice:
1155
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceId))
1156
 
1157
    sourceId = sourceItemPricing.sourceId
1158
    itemId = sourceItemPricing.itemId
1159
 
1160
    item = Item.query.filter_by(id=itemId).first()
1161
    if item is None:
1162
        raise InventoryServiceException(101, "Bad Item")
1163
 
1164
    source = Source.query.filter_by(id=sourceId).first()
1165
    if source is None:
1166
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1167
 
3564 rajveer 1168
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1169
    if ds_sourceItemPricing is None:
1170
        ds_sourceItemPricing = SourceItemPricing()
1171
        ds_sourceItemPricing.source = source
1172
        ds_sourceItemPricing.item = item
1173
 
1174
    if sourceItemPricing.mrp:
1175
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1176
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1177
 
1178
    session.commit()
1179
    return
1180
 
1181
def get_all_source_pricing(itemId):
1182
    item = Item.query.filter_by(id=itemId).first()
1183
    if item is None:
1184
        raise InventoryServiceException(101, "Bad Item")
1185
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1186
    return source_pricing
1187
 
1188
 
1189
def get_item_for_source(item_id, sourceId):
1190
    item = get_item(item_id)
1191
    if sourceId == -1:
1192
        return item
1193
    try:
1194
        sip = get_item_pricing_by_source(item_id, sourceId)
1195
        item.sellingPrice = sip.sellingPrice
1196
        if sip.mrp:
1197
            item.mrp = sip.mrp
1198
    except:
1199
        print "No source pricing"
1200
    return item
1201
 
3872 chandransh 1202
def search_items(search_terms, offset, limit):
1203
    query = Item.query
1204
 
1205
    query_clause = []
1206
 
1207
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1208
 
1209
    for search_term in search_terms:
1210
        query_clause.append(Item.brand.like(search_term))
1211
        query_clause.append(Item.model_number.like(search_term))
1212
        query_clause.append(Item.model_name.like(search_term))
1213
 
1214
    query = query.filter(or_(*query_clause))
1215
 
1216
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1217
    if limit:
1218
        query = query.limit(limit)
1219
    items = query.all()
1220
    return items
1221
 
1222
def get_search_result_count(search_terms):
1223
    query = Item.query
1224
 
1225
    query_clause = []
1226
 
1227
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1228
 
1229
    for search_term in search_terms:
1230
        query_clause.append(Item.brand.like(search_term))
1231
        query_clause.append(Item.model_number.like(search_term))
1232
        query_clause.append(Item.model_name.like(search_term))
1233
 
1234
    query = query.filter(or_(*query_clause))
1235
 
1236
    return query.count()
1237
 
3924 rajveer 1238
def __clear_homepage_cache():
1239
    try:
1240
        # create a password manager
1241
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1242
        # Add the username and password.
1243
        configclient = ConfigClient()
4310 rajveer 1244
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1245
        ips = ips.split(" ")
1246
 
1247
        for ip in ips:
4310 rajveer 1248
            try:
1249
                top_level_url = "http://" + ip + ":8080/"
1250
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1251
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1252
 
4310 rajveer 1253
                opener = urllib2.build_opener(handler)
3924 rajveer 1254
 
4310 rajveer 1255
                # use the opener to fetch a URL
1256
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1257
                print "Successfully cleared home page cache" + res.read()
1258
            except:
1259
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1260
    except:
1261
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1262
 
4062 chandransh 1263
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1264
    """
1265
    Returns a list of inventory stock for items for which there are pending orders.
1266
    """
4062 chandransh 1267
    warehouse_ids = [warehouse.id for warehouse in Warehouse.query.filter_by(vendor_id=vendor_id).all()]
4064 chandransh 1268
    pending_items_inventory = []
1269
    if warehouse_ids:
1270
        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 1271
    return pending_items_inventory
4295 varun.gupt 1272
 
1273
def get_product_notifications(start_datetime):
1274
    '''
1275
    Returns a list of Product Notification objects each representing user requests for notification
1276
    '''
1277
    query = ProductNotification.query
3924 rajveer 1278
 
4295 varun.gupt 1279
    if start_datetime:
1280
        query = query.filter(ProductNotification.addedOn > start_datetime)
1281
 
1282
    notifications = query.order_by(desc('addedOn')).all()
1283
    return notifications
1284
 
1285
def get_product_notification_request_count(start_datetime):
1286
    '''
1287
    Returns list of items and the counts of product notification requests
1288
    '''
1289
    print start_datetime
1290
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1291
 
1292
    if start_datetime:
1293
        query = query.filter(ProductNotification.addedOn > start_datetime)
1294
 
1295
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1296
    return counts
1297
 
766 rajveer 1298
def close_session():
1299
    if session.is_active:
1300
        print "session is active. closing it."
1399 rajveer 1301
        session.close()
3376 rajveer 1302
 
1303
def is_alive():
1304
    try:
1305
        session.query(Item.id).limit(1).one()
1306
        return True
1307
    except:
1308
        return False