Subversion Repositories SmartDukaan

Rev

Rev 4374 | Rev 4406 | 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
76
        availability = __get_item_availability(item)
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
2983 chandransh 515
    availability = __get_item_availability(item)
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
 
2983 chandransh 528
def __get_item_availability(item):
529
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
530
    availability = 0
531
    reserved = 0
532
    for currInv in all_inventory:
533
        availability = availability + currInv.availibility
534
        reserved = reserved + currInv.reserved
535
    return availability - reserved
4400 rajveer 536
 
537
def __get_item_reserved(item):
538
    all_inventory = CurrentInventorySnapshot.query.filter_by(item = item).all()
539
    reserved = 0
540
    for currInv in all_inventory:
541
        reserved = reserved + currInv.reserved
542
    return reserved
2983 chandransh 543
 
871 chandransh 544
def reserve_item_in_warehouse(item_id, warehouse_id, quantity):    
545
    if not warehouse_id:
546
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 547
    item = get_item(item_id)
548
    if not item:
871 chandransh 549
        raise InventoryServiceException(101, "bad item_id")
550
 
551
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
552
    try:
553
        current_inventory_snapshot = query.one()
554
    except:
4103 chandransh 555
        current_inventory_snapshot = CurrentInventorySnapshot()
556
        current_inventory_snapshot.warehouse_id = warehouse_id
557
        current_inventory_snapshot.item_id = item_id
558
        current_inventory_snapshot.availibility = 0
559
        current_inventory_snapshot.reserved = 0
560
 
561
    current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantity
562
    session.commit()
563
    check_risky_item(item)
564
    return True
871 chandransh 565
 
566
def reduce_reservation_count(item_id, warehouse_id, quantity):
567
    if not warehouse_id:
568
        raise InventoryServiceException(101, "bad warehouse_id")
2251 ankur.sing 569
    item = get_item(item_id)
570
    if not item:
871 chandransh 571
        raise InventoryServiceException(101, "bad item_id")
572
 
573
    query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)
574
    try:
575
        current_inventory_snapshot = query.one()
576
        current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantity
4318 rajveer 577
        ##FIXME In case of our own warehouse reduce availability also
578
        if warehouse_id == 7:
4335 rajveer 579
            current_inventory_snapshot.availibility = current_inventory_snapshot.availibility - quantity
871 chandransh 580
        session.commit()
2368 ankur.sing 581
        check_risky_item(item)
871 chandransh 582
        return True
583
    except:
584
        print "Unexpected error:", sys.exc_info()[0]
585
        return False
586
 
2075 rajveer 587
def mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):
2828 rajveer 588
    '''
589
    Get all the items for this entityID and update category, brand, modelName and modelNumber for all.
590
    Update Status for only IN_PROCESS items to CONTENT_COMPLETE
591
    '''
723 chandransh 592
    content_complete_status = status.CONTENT_COMPLETE
2828 rajveer 593
    items = Item.query.filter_by(catalog_item_id=entity_id).all()
723 chandransh 594
    current_timestamp = datetime.datetime.now()
595
    for item in items:
2828 rajveer 596
        if item.status == status.IN_PROCESS:
597
            item.status = content_complete_status
598
            item_change_log = ItemChangeLog()
599
            item_change_log.old_status = item.status
600
            item_change_log.new_status = content_complete_status
601
            item_change_log.timestamp = current_timestamp
602
            item_change_log.item = item
723 chandransh 603
 
2075 rajveer 604
        item.category = category
605
        item.brand = brand
2081 rajveer 606
        item.model_name = modelName
607
        item.model_number = modelNumber
723 chandransh 608
        item.updatedOn = current_timestamp
609
    session.commit()
610
    return True
1294 chandransh 611
 
643 chandransh 612
def get_item_availability_for_location(warehouse_loc, item_id):
3355 chandransh 613
    """
614
    Determines the warehouse that should be used to fulfil an order for the given item.
615
    It first checks all the warehouses which are in the logistics location given by the
616
    warehouse_loc parameter. If none of the warehouses there have any inventory, then the
617
    preferred warehouse for the item is used.
618
 
619
    Returns an ordered list of size 4 with following elements in the given order:
620
    1. Logistics location of the warehouse which was finally picked up to ship the order.
621
    2. Id of the warehouse which was finally picked up.
622
    3. Inventory size in the selected warehouse.
623
    4. Expected delay added by the category manager.
624
 
625
    Parameters:
626
     - warehouse_loc
627
     - item_id
628
    """
643 chandransh 629
    if warehouse_loc is None:
630
        raise InventoryServiceException(101, "Bad Warehouse Location")
631
    if not item_id:
1416 chandransh 632
        raise InventoryServiceException(101, "Bad Item id")
643 chandransh 633
 
1416 chandransh 634
    item = Item.get_by(id=item_id)
3355 chandransh 635
 
636
    #First try all warehouses in the suggested location.
643 chandransh 637
    warehouses = Warehouse.query.filter_by(logisticsLocation=warehouse_loc).all()
638
    warehouse_ids = [warehouse.id for warehouse in warehouses]
639
    warehouse_retid = -1
3503 chandransh 640
    max_availability = 0
641
    total_availability = 0
643 chandransh 642
    for warehouse_id in warehouse_ids:
785 rajveer 643
        try:
871 chandransh 644
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()
645
            availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 646
        except Exception as e:
647
            print e
785 rajveer 648
            availability = 0    
3503 chandransh 649
        if availability > max_availability:
643 chandransh 650
            warehouse_retid = warehouse_id
3503 chandransh 651
            max_availability = availability
652
        total_availability = total_availability + availability
2341 chandransh 653
 
3355 chandransh 654
    #If no warehouse could be found, use the preferred warehouse for this item
643 chandransh 655
    if warehouse_retid == -1:
759 chandransh 656
        # This is the case when all warehouses have exhausted their
657
        # inventory of this item or no warehouse is available in this
658
        # location.
1416 chandransh 659
        warehouse_retid = int(item.preferredWarehouse)
2344 chandransh 660
        warehouse = Warehouse.get_by(id=warehouse_retid)
2341 chandransh 661
        try:
662
            current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_retid, item_id = item_id).one()
3503 chandransh 663
            max_availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reserved
4317 varun.gupt 664
        except Exception as e:
665
            print e
3503 chandransh 666
            max_availability = 0
667
        total_availability = max_availability
643 chandransh 668
 
4317 varun.gupt 669
    if item.expectedDelay is None:
670
        print 'expectedDelay field for this item was Null. Resetting it to 0'
671
        item.expectedDelay = 0
672
 
4373 rajveer 673
    ## FIXME Assign warehouse 5 (9D2) for all the hotspot products.
674
    #if warehouse_retid in [warehouse.id for warehouse in get_warehouses_for_vendor(1)]:
675
    if warehouse_retid in [1,2,3,4,5]:
676
        warehouse_retid = 5
677
        warehouse = Warehouse.get_by(id=warehouse_retid)
678
 
3503 chandransh 679
    return [warehouse.logisticsLocation, warehouse_retid, total_availability, item.expectedDelay]
2341 chandransh 680
 
122 ashish 681
def get_warehouses_for_item(item_id):
643 chandransh 682
 
122 ashish 683
    if not item_id:
684
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 685
    item = get_item(item_id)
122 ashish 686
 
687
    if not item:
688
        raise InventoryServiceException(101, "bad item")
689
 
483 rajveer 690
    warehouses = item.currentInventory.warehouse
501 rajveer 691
    return warehouses
692
 
2404 chandransh 693
def get_child_categories(category):
694
    cm = CategoryManager()
2621 varun.gupt 695
    cat = cm.getCategory(category)
696
    return cat.children_category_ids if cat else None
2404 chandransh 697
 
626 chandransh 698
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 699
    '''
700
    Returns the Best Sellers between the start and the stop index in the given category
701
    '''
1926 rajveer 702
    query = get_best_sellers_query(category, None)
1098 chandransh 703
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 704
    return get_thrift_item_list(best_sellers)
705
 
2093 chandransh 706
def get_best_sellers_count(category=-1):
2404 chandransh 707
    '''
708
    Returns the number of best sellers in the given category
709
    '''
1926 rajveer 710
    count = get_best_sellers_query(category, None).count()
1120 rajveer 711
    if count is None:
712
        count = 0
766 rajveer 713
    return count
621 chandransh 714
 
1926 rajveer 715
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 716
    '''
717
    Returns the Best sellers for the given brand and category between the start and the stop index.
718
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
719
    '''
1926 rajveer 720
    query = get_best_sellers_query(category, brand)
1098 chandransh 721
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 722
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 723
 
1926 rajveer 724
def get_best_sellers_query(category, brand):
2404 chandransh 725
    '''
726
    Returns the query to be used for getting Best Sellers.
727
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
728
    '''
1098 chandransh 729
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 730
    if category != -1:
1970 rajveer 731
        all_categories = [category]
732
        child_categories = get_child_categories(category)
733
        if child_categories is not None:
734
            all_categories = all_categories + child_categories 
735
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 736
    if brand is not None:
737
        query = query.filter_by(brand=brand)
1098 chandransh 738
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 739
    return query
609 chandransh 740
 
1098 chandransh 741
def get_best_deals(category=-1):
2404 chandransh 742
    '''
743
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
744
    '''
745
    query = get_best_deals_query(Item, category, None)
1098 chandransh 746
    items = query.all()
609 chandransh 747
    return get_thrift_item_list(items)
748
 
1098 chandransh 749
def get_best_deals_count(category=-1):
2404 chandransh 750
    '''
751
    Returns the count of best deals in the given category.
752
    Ignores the category if it's -1.
753
    '''
754
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 755
    if count is None:
756
        count = 0
766 rajveer 757
    return count
501 rajveer 758
 
1926 rajveer 759
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 760
    '''
761
    Returns the catalog_item_ids of best deal items for the given brand and category.
762
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
763
    '''
764
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 765
    best_deal_items = query.all()[start_index:stop_index]
766
    return [item.catalog_item_id for item in best_deal_items]
767
 
2404 chandransh 768
def get_best_deals_counting_query(obj, category, brand):
769
    '''
770
    Returns the query to be used to select the best deals in the given brand and category.
771
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
772
    '''
773
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 774
    if category != -1:
1970 rajveer 775
        all_categories = [category]
776
        child_categories = get_child_categories(category)
777
        if child_categories is not None:
778
            all_categories = all_categories + child_categories 
779
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 780
    if brand is not None:
781
        query = query.filter_by(brand=brand)
2404 chandransh 782
    return query
783
 
784
def get_best_deals_query(obj, category, brand):
785
    '''
786
    Returns the query to be used to get the best deals in the given category and brand.
787
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
788
    '''
789
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 790
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
791
    return query
609 chandransh 792
 
1098 chandransh 793
def get_latest_arrivals(limit, category=-1):
2404 chandransh 794
    '''
795
    Returns up to limit number of Latest Arrivals in the given category.
796
    '''
2975 chandransh 797
    categories = []
798
    if category != -1:
799
        categories = [category]
800
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 801
    items = query.all()[0:limit]
609 chandransh 802
    return get_thrift_item_list(items)
598 chandransh 803
 
1098 chandransh 804
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 805
    '''
806
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 807
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 808
    '''
2975 chandransh 809
    categories = []
810
    if category != -1:
811
        categories = [category]
812
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 813
    if count is None:
814
        count = 0
815
    count = min(count, limit)
766 rajveer 816
    return count
602 chandransh 817
 
2975 chandransh 818
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 819
    '''
820
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 821
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 822
    '''
2975 chandransh 823
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 824
    latest_arrivals = query.all()[start_index:stop_index]
825
    return [item.catalog_item_id for item in latest_arrivals]
826
 
2975 chandransh 827
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 828
    '''
829
    Returns the query to be used to count Latest arrivals.
3016 chandransh 830
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 831
    '''
832
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 833
 
834
    all_categories = []
835
    for category in categories:
836
        all_categories.append(category)
1970 rajveer 837
        child_categories = get_child_categories(category)
2975 chandransh 838
        if child_categories:
839
            all_categories = all_categories + child_categories
840
    if all_categories: 
1970 rajveer 841
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 842
 
1926 rajveer 843
    if brand is not None:
844
        query = query.filter_by(brand=brand)
2404 chandransh 845
    return query
846
 
2975 chandransh 847
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 848
    '''
849
    Returns the query to be used to retrieve Latest Arrivals.
850
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
851
    '''
2975 chandransh 852
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 853
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
854
    return query
609 chandransh 855
 
856
def get_thrift_item_list(items):
1098 chandransh 857
    return [to_t_item(item) for item in items if item != None]
635 rajveer 858
 
1155 rajveer 859
def generate_new_entity_id():
860
    generator =  EntityIDGenerator.query.one()
861
    id = generator.id + 1
862
    generator.id = id
863
    session.commit()
864
    return id
865
 
635 rajveer 866
def put_category_object(object):
867
    category = Category.get_by(id=1)
868
    if category is None:
869
        category = Category()
870
    category.object = object    
871
    session.commit()
872
    return True
873
 
874
def get_category_object():
766 rajveer 875
    object = Category.get_by(id=1).object
876
    return object
877
 
4283 anupam.sin 878
def get_item_pricing(item_id, vendorId):
1341 chandransh 879
    item = Item.query.filter_by(id=item_id).first()
880
    if item is None:
881
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 882
    '''
883
    if vendor id is -1 then we calculate an average transfer price to be populated
884
    at the time of order creation. This will be later updated with actual transfer price
885
    at the time of billing.
886
    '''
887
    if(vendorId == -1):
888
        try:
889
            item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 890
            if item_pricings:
4307 anupam.sin 891
                for item_pricing in item_pricings:
4315 anupam.sin 892
                    total =+ item_pricing.transfer_price
893
                avg = total / len(item_pricings)
894
                item_pricing.transfer_price = avg
895
                return item_pricing
4307 anupam.sin 896
        except:
897
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 898
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 899
    try:
900
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 901
        return item_pricing
3244 chandransh 902
    except MultipleResultsFound:
1341 chandransh 903
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 904
    except NoResultFound:
1341 chandransh 905
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
906
 
1970 rajveer 907
def add_category(t_category):
908
    category = Category.get_by(id=t_category.id)
909
    if category is None:
910
        category = Category()
911
    category.id = t_category.id 
912
    category.label = t_category.label
913
    category.description = t_category.description
914
    category.parent_category_id = t_category.parent_category_id 
915
    session.commit()
916
    return True
917
 
918
def get_category(id):
919
    return Category.query.filter_by(id=id).first()
920
 
921
def get_all_categories():
922
    return Category.query.all()
923
 
1991 ankur.sing 924
 
925
def get_all_item_pricing(item_id):
926
    item = Item.query.filter_by(id=item_id).first()
927
    if item is None:
928
        raise InventoryServiceException(101, "Bad Item")
929
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
930
    return item_pricing
931
 
2116 ankur.sing 932
def get_item_mappings(item_id):
933
    item = Item.query.filter_by(id=item_id).first()
934
    if item is None:
935
        raise InventoryServiceException(101, "Bad Item")
936
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
937
    return item_mappings
938
 
939
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 940
    if not vendorItemPricing:
941
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
942
    vendorId = vendorItemPricing.vendorId
943
    itemId = vendorItemPricing.itemId
944
 
945
    try:
946
        vendor = Vendor.query.filter_by(id=vendorId).one()
947
    except:
948
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
949
 
950
    try:
951
        item = Item.query.filter_by(id=itemId).one()
952
    except:
953
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
954
 
2120 ankur.sing 955
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 956
 
1991 ankur.sing 957
    try:
958
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
959
    except:
2116 ankur.sing 960
        ds_vendorItemPricing = VendorItemPricing()
961
        ds_vendorItemPricing.vendor = vendor
962
        ds_vendorItemPricing.item = item
1991 ankur.sing 963
 
964
    if vendorItemPricing.mop:
965
        ds_vendorItemPricing.mop = vendorItemPricing.mop
966
    if vendorItemPricing.dealerPrice:
967
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
968
    if vendorItemPricing.transferPrice:
2065 ankur.sing 969
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 970
 
971
    session.commit()
972
    return
973
 
2358 ankur.sing 974
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 975
    if not vendorItemMapping:
976
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
977
    vendorId = vendorItemMapping.vendorId
978
    itemId = vendorItemMapping.itemId
979
 
980
    try:
981
        vendor = Vendor.query.filter_by(id=vendorId).one()
982
    except:
983
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
984
 
985
    try:
986
        item = Item.query.filter_by(id=itemId).one()
987
    except:
988
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
989
 
990
    try:
2358 ankur.sing 991
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 992
    except:
993
        ds_vendorItemMapping = VendorItemMapping()
994
        ds_vendorItemMapping.vendor = vendor
995
        ds_vendorItemMapping.item = item
2497 ankur.sing 996
    ds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategory
2116 ankur.sing 997
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
998
 
999
    session.commit()
1000
    return
1001
 
2120 ankur.sing 1002
def validate_item_prices(item):
2129 ankur.sing 1003
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
1004
        return
1005
    if item.mrp < item.sellingPrice:
2120 ankur.sing 1006
        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))
1007
        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 1008
    return
2120 ankur.sing 1009
 
1010
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 1011
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 1012
        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))
1013
        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)))
1014
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
1015
        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))
1016
        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)))
1017
    return
2065 ankur.sing 1018
 
1019
def get_all_vendors():
1020
    return Vendor.query.all()
1021
 
2116 ankur.sing 1022
def check_similar_item(product_group, brand, model_number, color):
2129 ankur.sing 1023
    query = Item.query
2428 ankur.sing 1024
    query = query.filter_by(product_group=product_group)
1025
    query = query.filter_by(brand=brand)
1026
    query = query.filter_by(model_number=model_number)
2129 ankur.sing 1027
    if color:
1028
        query = query.filter_by(color=color)
1029
    item = query.first()
2116 ankur.sing 1030
    if item is None:
1031
        return 0
1032
    else:
1033
        return item.id
2286 ankur.sing 1034
 
1035
def change_risky_flag(item_id, risky):
1036
    item = get_item(item_id)
1037
    if not item:
1038
        raise InventoryServiceException(101, "Item missing in our database")
1039
    try:
1040
        log_risky_flag(item_id, risky)
1041
    except:
1042
        print "Not able to log risky flag change"
1043
    item.risky = risky
4295 varun.gupt 1044
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1045
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1046
    session.commit()
1047
 
2358 ankur.sing 1048
def get_items_by_vendor_category(vendor_category):
1049
    if not vendor_category:
1050
        raise InventoryServiceException(101, "Invalid vendor category in request")
1051
    query = Item.query.filter(and_(Item.hotspotCategory==vendor_category, Item.status != status.PHASED_OUT))
1052
    items = query.all()
1053
    return items
2116 ankur.sing 1054
 
2358 ankur.sing 1055
def get_risky_items():
1056
    items = Item.query.filter_by(risky=True).all()
1057
    return items
3008 rajveer 1058
 
2809 rajveer 1059
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1060
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1061
    similar_items = query.all()
3289 rajveer 1062
    return_list = []
1063
    for similar_item in similar_items:
1064
        isActive = False
1065
        try:
1066
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1067
        except:
1068
            continue
1069
        for item in all_items:
1070
            isActive = isActive or item.status == status.ACTIVE
1071
        if isActive:
1072
            return_list.append(similar_item.catalog_item_id)
1073
    return return_list
2809 rajveer 1074
 
3079 rajveer 1075
def add_product_notification(itemId, email):
1076
    try:
3470 rajveer 1077
        try:
1078
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1079
        except:
1080
            product_notification = ProductNotification()
1081
            product_notification.email = email
1082
            product_notification.item_id = itemId
3079 rajveer 1083
        product_notification.addedOn = datetime.datetime.now()
1084
        session.commit()
1085
        return True
1086
    except:
1087
        return False
3086 rajveer 1088
 
1089
 
1090
def send_product_notifications():
1091
    product_notifications = ProductNotification.query.all()
1092
    for product_notification in product_notifications:
1093
        item = product_notification.item
1094
        availability = __get_item_availability(item)
3309 rajveer 1095
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1096
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1097
            product_notification.delete()
1098
    session.commit()
1099
    return True
1100
 
1101
def __get_product_name(item):
1102
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1103
    color = item.color
1104
    if color is not None and color != 'NA':
1105
        product_name = product_name + " (" + color + ")"
3201 rajveer 1106
    product_name = product_name.replace("  "," ")
3086 rajveer 1107
    return product_name
1108
 
1109
 
1110
def __get_product_url(item):
1111
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1112
    product_url = product_url.replace("--","-")
1113
    product_url = product_url.replace(" ","")
1114
    return product_url
1115
 
3348 varun.gupt 1116
def get_all_brands_by_category(category_id):
1117
    catm = CategoryManager()
1118
    child_categories = catm.getCategory(category_id).children_category_ids
1119
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1120
 
1121
    return [brand[0] for brand in brands]
3086 rajveer 1122
 
1123
def __enque_product_notification_email(email, product, date, url, itemId):
1124
 
1125
    html = """
1126
        <html>
1127
        <body>
1128
        <div>
1129
        <p>
1130
            Hi,<br /><br />
1131
            The product requested by you on $date is now available on saholic.com.
1132
        </p>
1133
 
1134
        <p>    
1135
        <strong>Product: $product </strong>
1136
        </p>
1137
 
1138
        <p>
1139
        Click the link below to visit the product: 
1140
        <br/>
1141
        $url
1142
        </p>
1143
        <p>
1144
        Regards,<br/>
1145
        Saholic Customer Support Team<br/>
1146
        www.saholic.com<br/>
1147
        Email: help@saholic.com<br/>
1148
        </p>
1149
        </div>
1150
        </body>
1151
        </html>
1152
        """
1153
 
1154
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1155
 
3086 rajveer 1156
    try:
1157
        helper_client = HelperClient().get_client()
1158
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1159
    except Exception as e:
1160
        print e
1161
 
3557 rajveer 1162
def get_all_sources():
1163
    sources = Source.query.all()
1164
    return [to_t_source(source) for source in sources]
3086 rajveer 1165
 
3557 rajveer 1166
def get_item_pricing_by_source(itemId, sourceId):
1167
    item = Item.query.filter_by(id=itemId).first()
1168
    if item is None:
1169
        raise InventoryServiceException(101, "Bad Item")
1170
 
1171
    source = Source.query.filter_by(id=sourceId).first()
1172
    if source is None:
1173
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1174
 
1175
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1176
    if item_pricing is None:
1177
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1178
    return item_pricing
1179
 
1180
def add_source_item_pricing(sourceItemPricing):
1181
    if not sourceItemPricing:
1182
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1183
 
1184
    if not sourceItemPricing.sellingPrice:
4326 mandeep.dh 1185
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceItemPricing.sourceId))
3557 rajveer 1186
 
1187
    sourceId = sourceItemPricing.sourceId
1188
    itemId = sourceItemPricing.itemId
1189
 
1190
    item = Item.query.filter_by(id=itemId).first()
1191
    if item is None:
1192
        raise InventoryServiceException(101, "Bad Item")
1193
 
1194
    source = Source.query.filter_by(id=sourceId).first()
1195
    if source is None:
1196
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1197
 
3564 rajveer 1198
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1199
    if ds_sourceItemPricing is None:
1200
        ds_sourceItemPricing = SourceItemPricing()
1201
        ds_sourceItemPricing.source = source
1202
        ds_sourceItemPricing.item = item
1203
 
1204
    if sourceItemPricing.mrp:
1205
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1206
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1207
 
1208
    session.commit()
1209
    return
1210
 
1211
def get_all_source_pricing(itemId):
1212
    item = Item.query.filter_by(id=itemId).first()
1213
    if item is None:
1214
        raise InventoryServiceException(101, "Bad Item")
1215
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1216
    return source_pricing
1217
 
1218
 
1219
def get_item_for_source(item_id, sourceId):
1220
    item = get_item(item_id)
1221
    if sourceId == -1:
1222
        return item
1223
    try:
1224
        sip = get_item_pricing_by_source(item_id, sourceId)
1225
        item.sellingPrice = sip.sellingPrice
1226
        if sip.mrp:
1227
            item.mrp = sip.mrp
1228
    except:
1229
        print "No source pricing"
1230
    return item
1231
 
3872 chandransh 1232
def search_items(search_terms, offset, limit):
1233
    query = Item.query
1234
 
1235
    query_clause = []
1236
 
1237
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1238
 
1239
    for search_term in search_terms:
1240
        query_clause.append(Item.brand.like(search_term))
1241
        query_clause.append(Item.model_number.like(search_term))
1242
        query_clause.append(Item.model_name.like(search_term))
1243
 
1244
    query = query.filter(or_(*query_clause))
1245
 
1246
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1247
    if limit:
1248
        query = query.limit(limit)
1249
    items = query.all()
1250
    return items
1251
 
1252
def get_search_result_count(search_terms):
1253
    query = Item.query
1254
 
1255
    query_clause = []
1256
 
1257
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1258
 
1259
    for search_term in search_terms:
1260
        query_clause.append(Item.brand.like(search_term))
1261
        query_clause.append(Item.model_number.like(search_term))
1262
        query_clause.append(Item.model_name.like(search_term))
1263
 
1264
    query = query.filter(or_(*query_clause))
1265
 
1266
    return query.count()
1267
 
3924 rajveer 1268
def __clear_homepage_cache():
1269
    try:
1270
        # create a password manager
1271
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1272
        # Add the username and password.
1273
        configclient = ConfigClient()
4310 rajveer 1274
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1275
        ips = ips.split(" ")
1276
 
1277
        for ip in ips:
4310 rajveer 1278
            try:
1279
                top_level_url = "http://" + ip + ":8080/"
1280
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1281
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1282
 
4310 rajveer 1283
                opener = urllib2.build_opener(handler)
3924 rajveer 1284
 
4310 rajveer 1285
                # use the opener to fetch a URL
1286
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1287
                print "Successfully cleared home page cache" + res.read()
1288
            except:
1289
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1290
    except:
1291
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1292
 
4062 chandransh 1293
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1294
    """
1295
    Returns a list of inventory stock for items for which there are pending orders.
1296
    """
4341 rajveer 1297
 
4368 rajveer 1298
    warehouse_ids = [warehouse.id for warehouse in get_warehouses_for_vendor(vendor_id)]
4064 chandransh 1299
    pending_items_inventory = []
1300
    if warehouse_ids:
1301
        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 1302
    return pending_items_inventory
4295 varun.gupt 1303
 
1304
def get_product_notifications(start_datetime):
1305
    '''
1306
    Returns a list of Product Notification objects each representing user requests for notification
1307
    '''
1308
    query = ProductNotification.query
3924 rajveer 1309
 
4295 varun.gupt 1310
    if start_datetime:
1311
        query = query.filter(ProductNotification.addedOn > start_datetime)
1312
 
1313
    notifications = query.order_by(desc('addedOn')).all()
1314
    return notifications
1315
 
1316
def get_product_notification_request_count(start_datetime):
1317
    '''
1318
    Returns list of items and the counts of product notification requests
1319
    '''
1320
    print start_datetime
1321
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1322
 
1323
    if start_datetime:
1324
        query = query.filter(ProductNotification.addedOn > start_datetime)
1325
 
1326
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1327
    return counts
1328
 
766 rajveer 1329
def close_session():
1330
    if session.is_active:
1331
        print "session is active. closing it."
1399 rajveer 1332
        session.close()
3376 rajveer 1333
 
1334
def is_alive():
1335
    try:
1336
        session.query(Item.id).limit(1).one()
1337
        return True
1338
    except:
1339
        return False
4332 anupam.sin 1340
 
1341
def add_vendor(vendor):
1342
    if not vendor:
1343
        raise InventoryServiceException(108, "Bad vendor")
1344
    if get_Vendor(vendor.id):
1345
        #vendor is already present.
1346
        raise InventoryServiceException(101, "Vendor already present")
1347
 
1348
    ds_vendor = Vendor()
1349
    ds_vendor.id = vendor.id
1350
    ds_vendor.name = vendor.name
1351
    session.commit()
1352
    return ds_vendor.id
1353
 
1354
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
1355
    return True
1356
 
1357
def get_vendors_for_warehouse(warehouse_id):
1358
    try:
1359
        warehouse = Warehouse.get_by(id=warehouse_id)
1360
        return warehouse.vendors
1361
    except:
1362
        raise InventoryServiceException(108, "Bad Warehouse Id")
1363
 
1364
def get_warehouses_for_vendor(vendorId):
1365
    try:
1366
        vendor = get_Vendor(vendorId)
1367
        return vendor.warehouses
1368
    except:
1369
        raise InventoryServiceException(108, "Bad Vendor Id")