Subversion Repositories SmartDukaan

Rev

Rev 4400 | Rev 4413 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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