Subversion Repositories SmartDukaan

Rev

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