Subversion Repositories SmartDukaan

Rev

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