Subversion Repositories SmartDukaan

Rev

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