Subversion Repositories SmartDukaan

Rev

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