Subversion Repositories SmartDukaan

Rev

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