Subversion Repositories SmartDukaan

Rev

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