Subversion Repositories SmartDukaan

Rev

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