Subversion Repositories SmartDukaan

Rev

Rev 4341 | Rev 4373 | 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:
4319 rajveer 512
                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 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
 
3503 chandransh 658
    return [warehouse.logisticsLocation, warehouse_retid, total_availability, item.expectedDelay]
2341 chandransh 659
 
122 ashish 660
def get_warehouses_for_item(item_id):
643 chandransh 661
 
122 ashish 662
    if not item_id:
663
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 664
    item = get_item(item_id)
122 ashish 665
 
666
    if not item:
667
        raise InventoryServiceException(101, "bad item")
668
 
483 rajveer 669
    warehouses = item.currentInventory.warehouse
501 rajveer 670
    return warehouses
671
 
2404 chandransh 672
def get_child_categories(category):
673
    cm = CategoryManager()
2621 varun.gupt 674
    cat = cm.getCategory(category)
675
    return cat.children_category_ids if cat else None
2404 chandransh 676
 
626 chandransh 677
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 678
    '''
679
    Returns the Best Sellers between the start and the stop index in the given category
680
    '''
1926 rajveer 681
    query = get_best_sellers_query(category, None)
1098 chandransh 682
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 683
    return get_thrift_item_list(best_sellers)
684
 
2093 chandransh 685
def get_best_sellers_count(category=-1):
2404 chandransh 686
    '''
687
    Returns the number of best sellers in the given category
688
    '''
1926 rajveer 689
    count = get_best_sellers_query(category, None).count()
1120 rajveer 690
    if count is None:
691
        count = 0
766 rajveer 692
    return count
621 chandransh 693
 
1926 rajveer 694
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 695
    '''
696
    Returns the Best sellers for the given brand and category between the start and the stop index.
697
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
698
    '''
1926 rajveer 699
    query = get_best_sellers_query(category, brand)
1098 chandransh 700
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 701
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 702
 
1926 rajveer 703
def get_best_sellers_query(category, brand):
2404 chandransh 704
    '''
705
    Returns the query to be used for getting Best Sellers.
706
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
707
    '''
1098 chandransh 708
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 709
    if category != -1:
1970 rajveer 710
        all_categories = [category]
711
        child_categories = get_child_categories(category)
712
        if child_categories is not None:
713
            all_categories = all_categories + child_categories 
714
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 715
    if brand is not None:
716
        query = query.filter_by(brand=brand)
1098 chandransh 717
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 718
    return query
609 chandransh 719
 
1098 chandransh 720
def get_best_deals(category=-1):
2404 chandransh 721
    '''
722
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
723
    '''
724
    query = get_best_deals_query(Item, category, None)
1098 chandransh 725
    items = query.all()
609 chandransh 726
    return get_thrift_item_list(items)
727
 
1098 chandransh 728
def get_best_deals_count(category=-1):
2404 chandransh 729
    '''
730
    Returns the count of best deals in the given category.
731
    Ignores the category if it's -1.
732
    '''
733
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 734
    if count is None:
735
        count = 0
766 rajveer 736
    return count
501 rajveer 737
 
1926 rajveer 738
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 739
    '''
740
    Returns the catalog_item_ids of best deal items for 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 = get_best_deals_query(Item, category, brand)
1098 chandransh 744
    best_deal_items = query.all()[start_index:stop_index]
745
    return [item.catalog_item_id for item in best_deal_items]
746
 
2404 chandransh 747
def get_best_deals_counting_query(obj, category, brand):
748
    '''
749
    Returns the query to be used to select the best deals in the given brand and category.
750
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
751
    '''
752
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 753
    if category != -1:
1970 rajveer 754
        all_categories = [category]
755
        child_categories = get_child_categories(category)
756
        if child_categories is not None:
757
            all_categories = all_categories + child_categories 
758
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 759
    if brand is not None:
760
        query = query.filter_by(brand=brand)
2404 chandransh 761
    return query
762
 
763
def get_best_deals_query(obj, category, brand):
764
    '''
765
    Returns the query to be used to get the best deals in the given category and brand.
766
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
767
    '''
768
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 769
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
770
    return query
609 chandransh 771
 
1098 chandransh 772
def get_latest_arrivals(limit, category=-1):
2404 chandransh 773
    '''
774
    Returns up to limit number of Latest Arrivals in the given category.
775
    '''
2975 chandransh 776
    categories = []
777
    if category != -1:
778
        categories = [category]
779
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 780
    items = query.all()[0:limit]
609 chandransh 781
    return get_thrift_item_list(items)
598 chandransh 782
 
1098 chandransh 783
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 784
    '''
785
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 786
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 787
    '''
2975 chandransh 788
    categories = []
789
    if category != -1:
790
        categories = [category]
791
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 792
    if count is None:
793
        count = 0
794
    count = min(count, limit)
766 rajveer 795
    return count
602 chandransh 796
 
2975 chandransh 797
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 798
    '''
799
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 800
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 801
    '''
2975 chandransh 802
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 803
    latest_arrivals = query.all()[start_index:stop_index]
804
    return [item.catalog_item_id for item in latest_arrivals]
805
 
2975 chandransh 806
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 807
    '''
808
    Returns the query to be used to count Latest arrivals.
3016 chandransh 809
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 810
    '''
811
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 812
 
813
    all_categories = []
814
    for category in categories:
815
        all_categories.append(category)
1970 rajveer 816
        child_categories = get_child_categories(category)
2975 chandransh 817
        if child_categories:
818
            all_categories = all_categories + child_categories
819
    if all_categories: 
1970 rajveer 820
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 821
 
1926 rajveer 822
    if brand is not None:
823
        query = query.filter_by(brand=brand)
2404 chandransh 824
    return query
825
 
2975 chandransh 826
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 827
    '''
828
    Returns the query to be used to retrieve Latest Arrivals.
829
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
830
    '''
2975 chandransh 831
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 832
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
833
    return query
609 chandransh 834
 
835
def get_thrift_item_list(items):
1098 chandransh 836
    return [to_t_item(item) for item in items if item != None]
635 rajveer 837
 
1155 rajveer 838
def generate_new_entity_id():
839
    generator =  EntityIDGenerator.query.one()
840
    id = generator.id + 1
841
    generator.id = id
842
    session.commit()
843
    return id
844
 
635 rajveer 845
def put_category_object(object):
846
    category = Category.get_by(id=1)
847
    if category is None:
848
        category = Category()
849
    category.object = object    
850
    session.commit()
851
    return True
852
 
853
def get_category_object():
766 rajveer 854
    object = Category.get_by(id=1).object
855
    return object
856
 
4283 anupam.sin 857
def get_item_pricing(item_id, vendorId):
1341 chandransh 858
    item = Item.query.filter_by(id=item_id).first()
859
    if item is None:
860
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 861
    '''
862
    if vendor id is -1 then we calculate an average transfer price to be populated
863
    at the time of order creation. This will be later updated with actual transfer price
864
    at the time of billing.
865
    '''
866
    if(vendorId == -1):
867
        try:
868
            item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 869
            if item_pricings:
4307 anupam.sin 870
                for item_pricing in item_pricings:
4315 anupam.sin 871
                    total =+ item_pricing.transfer_price
872
                avg = total / len(item_pricings)
873
                item_pricing.transfer_price = avg
874
                return item_pricing
4307 anupam.sin 875
        except:
876
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 877
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 878
    try:
879
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 880
        return item_pricing
3244 chandransh 881
    except MultipleResultsFound:
1341 chandransh 882
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 883
    except NoResultFound:
1341 chandransh 884
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
885
 
1970 rajveer 886
def add_category(t_category):
887
    category = Category.get_by(id=t_category.id)
888
    if category is None:
889
        category = Category()
890
    category.id = t_category.id 
891
    category.label = t_category.label
892
    category.description = t_category.description
893
    category.parent_category_id = t_category.parent_category_id 
894
    session.commit()
895
    return True
896
 
897
def get_category(id):
898
    return Category.query.filter_by(id=id).first()
899
 
900
def get_all_categories():
901
    return Category.query.all()
902
 
1991 ankur.sing 903
 
904
def get_all_item_pricing(item_id):
905
    item = Item.query.filter_by(id=item_id).first()
906
    if item is None:
907
        raise InventoryServiceException(101, "Bad Item")
908
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
909
    return item_pricing
910
 
2116 ankur.sing 911
def get_item_mappings(item_id):
912
    item = Item.query.filter_by(id=item_id).first()
913
    if item is None:
914
        raise InventoryServiceException(101, "Bad Item")
915
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
916
    return item_mappings
917
 
918
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 919
    if not vendorItemPricing:
920
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
921
    vendorId = vendorItemPricing.vendorId
922
    itemId = vendorItemPricing.itemId
923
 
924
    try:
925
        vendor = Vendor.query.filter_by(id=vendorId).one()
926
    except:
927
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
928
 
929
    try:
930
        item = Item.query.filter_by(id=itemId).one()
931
    except:
932
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
933
 
2120 ankur.sing 934
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 935
 
1991 ankur.sing 936
    try:
937
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
938
    except:
2116 ankur.sing 939
        ds_vendorItemPricing = VendorItemPricing()
940
        ds_vendorItemPricing.vendor = vendor
941
        ds_vendorItemPricing.item = item
1991 ankur.sing 942
 
943
    if vendorItemPricing.mop:
944
        ds_vendorItemPricing.mop = vendorItemPricing.mop
945
    if vendorItemPricing.dealerPrice:
946
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
947
    if vendorItemPricing.transferPrice:
2065 ankur.sing 948
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 949
 
950
    session.commit()
951
    return
952
 
2358 ankur.sing 953
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 954
    if not vendorItemMapping:
955
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
956
    vendorId = vendorItemMapping.vendorId
957
    itemId = vendorItemMapping.itemId
958
 
959
    try:
960
        vendor = Vendor.query.filter_by(id=vendorId).one()
961
    except:
962
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
963
 
964
    try:
965
        item = Item.query.filter_by(id=itemId).one()
966
    except:
967
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
968
 
969
    try:
2358 ankur.sing 970
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 971
    except:
972
        ds_vendorItemMapping = VendorItemMapping()
973
        ds_vendorItemMapping.vendor = vendor
974
        ds_vendorItemMapping.item = item
2497 ankur.sing 975
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 976
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
977
 
978
    session.commit()
979
    return
980
 
2120 ankur.sing 981
def validate_item_prices(item):
2129 ankur.sing 982
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
983
        return
984
    if item.mrp < item.sellingPrice:
2120 ankur.sing 985
        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))
986
        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 987
    return
2120 ankur.sing 988
 
989
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 990
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 991
        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))
992
        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)))
993
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
994
        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))
995
        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)))
996
    return
2065 ankur.sing 997
 
998
def get_all_vendors():
999
    return Vendor.query.all()
1000
 
2116 ankur.sing 1001
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 1002
    query = Item.query
2428 ankur.sing 1003
    query = query.filter_by(product_group=product_group)
1004
    query = query.filter_by(brand=brand)
1005
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 1006
    if color:
1007
        query = query.filter_by(color=color)
1008
    item = query.first()
2116 ankur.sing 1009
    if item is None:
1010
        return 0
1011
    else:
1012
        return item.id
2286 ankur.sing 1013
 
1014
def change_risky_flag(item_id, risky):
1015
    item = get_item(item_id)
1016
    if not item:
1017
        raise InventoryServiceException(101, "Item missing in our database")
1018
    try:
1019
        log_risky_flag(item_id, risky)
1020
    except:
1021
        print "Not able to log risky flag change"
1022
    item.risky = risky
4295 varun.gupt 1023
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1024
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1025
    session.commit()
1026
 
2358 ankur.sing 1027
def get_items_by_vendor_category(vendor_category):
1028
    if not vendor_category:
1029
        raise InventoryServiceException(101, "Invalid vendor category in request")
1030
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
1031
    items = query.all()
1032
    return items
2116 ankur.sing 1033
 
2358 ankur.sing 1034
def get_risky_items():
1035
    items = Item.query.filter_by(risky=True).all()
1036
    return items
3008 rajveer 1037
 
2809 rajveer 1038
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1039
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1040
    similar_items = query.all()
3289 rajveer 1041
    return_list = []
1042
    for similar_item in similar_items:
1043
        isActive = False
1044
        try:
1045
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1046
        except:
1047
            continue
1048
        for item in all_items:
1049
            isActive = isActive or item.status == status.ACTIVE
1050
        if isActive:
1051
            return_list.append(similar_item.catalog_item_id)
1052
    return return_list
2809 rajveer 1053
 
3079 rajveer 1054
def add_product_notification(itemId, email):
1055
    try:
3470 rajveer 1056
        try:
1057
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1058
        except:
1059
            product_notification = ProductNotification()
1060
            product_notification.email = email
1061
            product_notification.item_id = itemId
3079 rajveer 1062
        product_notification.addedOn = datetime.datetime.now()
1063
        session.commit()
1064
        return True
1065
    except:
1066
        return False
3086 rajveer 1067
 
1068
 
1069
def send_product_notifications():
1070
    product_notifications = ProductNotification.query.all()
1071
    for product_notification in product_notifications:
1072
        item = product_notification.item
1073
        availability = __get_item_availability(item)
3309 rajveer 1074
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1075
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1076
            product_notification.delete()
1077
    session.commit()
1078
    return True
1079
 
1080
def __get_product_name(item):
1081
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1082
    color = item.color
1083
    if color is not None and color != 'NA':
1084
        product_name = product_name + " (" + color + ")"
3201 rajveer 1085
    product_name = product_name.replace("  "," ")
3086 rajveer 1086
    return product_name
1087
 
1088
 
1089
def __get_product_url(item):
1090
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1091
    product_url = product_url.replace("--","-")
1092
    product_url = product_url.replace(" ","")
1093
    return product_url
1094
 
3348 varun.gupt 1095
def get_all_brands_by_category(category_id):
1096
    catm = CategoryManager()
1097
    child_categories = catm.getCategory(category_id).children_category_ids
1098
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1099
 
1100
    return [brand[0] for brand in brands]
3086 rajveer 1101
 
1102
def __enque_product_notification_email(email, product, date, url, itemId):
1103
 
1104
    html = """
1105
        <html>
1106
        <body>
1107
        <div>
1108
        <p>
1109
            Hi,<br /><br />
1110
            The product requested by you on $date is now available on saholic.com.
1111
        </p>
1112
 
1113
        <p>    
1114
        <strong>Product: $product </strong>
1115
        </p>
1116
 
1117
        <p>
1118
        Click the link below to visit the product: 
1119
        <br/>
1120
        $url
1121
        </p>
1122
        <p>
1123
        Regards,<br/>
1124
        Saholic Customer Support Team<br/>
1125
        www.saholic.com<br/>
1126
        Email: help@saholic.com<br/>
1127
        </p>
1128
        </div>
1129
        </body>
1130
        </html>
1131
        """
1132
 
1133
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1134
 
3086 rajveer 1135
    try:
1136
        helper_client = HelperClient().get_client()
1137
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1138
    except Exception as e:
1139
        print e
1140
 
3557 rajveer 1141
def get_all_sources():
1142
    sources = Source.query.all()
1143
    return [to_t_source(source) for source in sources]
3086 rajveer 1144
 
3557 rajveer 1145
def get_item_pricing_by_source(itemId, sourceId):
1146
    item = Item.query.filter_by(id=itemId).first()
1147
    if item is None:
1148
        raise InventoryServiceException(101, "Bad Item")
1149
 
1150
    source = Source.query.filter_by(id=sourceId).first()
1151
    if source is None:
1152
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1153
 
1154
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1155
    if item_pricing is None:
1156
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1157
    return item_pricing
1158
 
1159
def add_source_item_pricing(sourceItemPricing):
1160
    if not sourceItemPricing:
1161
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1162
 
1163
    if not sourceItemPricing.sellingPrice:
4326 mandeep.dh 1164
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceItemPricing.sourceId))
3557 rajveer 1165
 
1166
    sourceId = sourceItemPricing.sourceId
1167
    itemId = sourceItemPricing.itemId
1168
 
1169
    item = Item.query.filter_by(id=itemId).first()
1170
    if item is None:
1171
        raise InventoryServiceException(101, "Bad Item")
1172
 
1173
    source = Source.query.filter_by(id=sourceId).first()
1174
    if source is None:
1175
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1176
 
3564 rajveer 1177
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1178
    if ds_sourceItemPricing is None:
1179
        ds_sourceItemPricing = SourceItemPricing()
1180
        ds_sourceItemPricing.source = source
1181
        ds_sourceItemPricing.item = item
1182
 
1183
    if sourceItemPricing.mrp:
1184
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1185
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1186
 
1187
    session.commit()
1188
    return
1189
 
1190
def get_all_source_pricing(itemId):
1191
    item = Item.query.filter_by(id=itemId).first()
1192
    if item is None:
1193
        raise InventoryServiceException(101, "Bad Item")
1194
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1195
    return source_pricing
1196
 
1197
 
1198
def get_item_for_source(item_id, sourceId):
1199
    item = get_item(item_id)
1200
    if sourceId == -1:
1201
        return item
1202
    try:
1203
        sip = get_item_pricing_by_source(item_id, sourceId)
1204
        item.sellingPrice = sip.sellingPrice
1205
        if sip.mrp:
1206
            item.mrp = sip.mrp
1207
    except:
1208
        print "No source pricing"
1209
    return item
1210
 
3872 chandransh 1211
def search_items(search_terms, offset, limit):
1212
    query = Item.query
1213
 
1214
    query_clause = []
1215
 
1216
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1217
 
1218
    for search_term in search_terms:
1219
        query_clause.append(Item.brand.like(search_term))
1220
        query_clause.append(Item.model_number.like(search_term))
1221
        query_clause.append(Item.model_name.like(search_term))
1222
 
1223
    query = query.filter(or_(*query_clause))
1224
 
1225
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1226
    if limit:
1227
        query = query.limit(limit)
1228
    items = query.all()
1229
    return items
1230
 
1231
def get_search_result_count(search_terms):
1232
    query = Item.query
1233
 
1234
    query_clause = []
1235
 
1236
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1237
 
1238
    for search_term in search_terms:
1239
        query_clause.append(Item.brand.like(search_term))
1240
        query_clause.append(Item.model_number.like(search_term))
1241
        query_clause.append(Item.model_name.like(search_term))
1242
 
1243
    query = query.filter(or_(*query_clause))
1244
 
1245
    return query.count()
1246
 
3924 rajveer 1247
def __clear_homepage_cache():
1248
    try:
1249
        # create a password manager
1250
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1251
        # Add the username and password.
1252
        configclient = ConfigClient()
4310 rajveer 1253
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1254
        ips = ips.split(" ")
1255
 
1256
        for ip in ips:
4310 rajveer 1257
            try:
1258
                top_level_url = "http://" + ip + ":8080/"
1259
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1260
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1261
 
4310 rajveer 1262
                opener = urllib2.build_opener(handler)
3924 rajveer 1263
 
4310 rajveer 1264
                # use the opener to fetch a URL
1265
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1266
                print "Successfully cleared home page cache" + res.read()
1267
            except:
1268
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1269
    except:
1270
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1271
 
4062 chandransh 1272
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1273
    """
1274
    Returns a list of inventory stock for items for which there are pending orders.
1275
    """
4341 rajveer 1276
 
4368 rajveer 1277
    warehouse_ids = [warehouse.id for warehouse in get_warehouses_for_vendor(vendor_id)]
4064 chandransh 1278
    pending_items_inventory = []
1279
    if warehouse_ids:
1280
        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 1281
    return pending_items_inventory
4295 varun.gupt 1282
 
1283
def get_product_notifications(start_datetime):
1284
    '''
1285
    Returns a list of Product Notification objects each representing user requests for notification
1286
    '''
1287
    query = ProductNotification.query
3924 rajveer 1288
 
4295 varun.gupt 1289
    if start_datetime:
1290
        query = query.filter(ProductNotification.addedOn > start_datetime)
1291
 
1292
    notifications = query.order_by(desc('addedOn')).all()
1293
    return notifications
1294
 
1295
def get_product_notification_request_count(start_datetime):
1296
    '''
1297
    Returns list of items and the counts of product notification requests
1298
    '''
1299
    print start_datetime
1300
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1301
 
1302
    if start_datetime:
1303
        query = query.filter(ProductNotification.addedOn > start_datetime)
1304
 
1305
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1306
    return counts
1307
 
766 rajveer 1308
def close_session():
1309
    if session.is_active:
1310
        print "session is active. closing it."
1399 rajveer 1311
        session.close()
3376 rajveer 1312
 
1313
def is_alive():
1314
    try:
1315
        session.query(Item.id).limit(1).one()
1316
        return True
1317
    except:
1318
        return False
4332 anupam.sin 1319
 
1320
def add_vendor(vendor):
1321
    if not vendor:
1322
        raise InventoryServiceException(108, "Bad vendor")
1323
    if get_Vendor(vendor.id):
1324
        #vendor is already present.
1325
        raise InventoryServiceException(101, "Vendor already present")
1326
 
1327
    ds_vendor = Vendor()
1328
    ds_vendor.id = vendor.id
1329
    ds_vendor.name = vendor.name
1330
    session.commit()
1331
    return ds_vendor.id
1332
 
1333
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
1334
    return True
1335
 
1336
def get_vendors_for_warehouse(warehouse_id):
1337
    try:
1338
        warehouse = Warehouse.get_by(id=warehouse_id)
1339
        return warehouse.vendors
1340
    except:
1341
        raise InventoryServiceException(108, "Bad Warehouse Id")
1342
 
1343
def get_warehouses_for_vendor(vendorId):
1344
    try:
1345
        vendor = get_Vendor(vendorId)
1346
        return vendor.warehouses
1347
    except:
1348
        raise InventoryServiceException(108, "Bad Vendor Id")