Subversion Repositories SmartDukaan

Rev

Rev 4992 | Rev 5047 | 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:
5005 rajveer 859
                    holidayValue = str(holiday.holidayValue)
860
                    holidayDate = datetime.date(int(holidayValue[:4]), int(holidayValue[4:6]), int(holidayValue[6:8]))
4979 rajveer 861
                    if holidayDate >=  currentDate and holidayDate <= expectedDate:
862
                        holidayDelay = holidayDelay + 1                
863
    except Exception as e:
864
        print e
865
    return holidayDelay 
122 ashish 866
def get_warehouses_for_item(item_id):
643 chandransh 867
 
122 ashish 868
    if not item_id:
869
        raise InventoryServiceException(101, "bad item_id")
635 rajveer 870
    item = get_item(item_id)
122 ashish 871
 
872
    if not item:
873
        raise InventoryServiceException(101, "bad item")
874
 
483 rajveer 875
    warehouses = item.currentInventory.warehouse
501 rajveer 876
    return warehouses
877
 
2404 chandransh 878
def get_child_categories(category):
879
    cm = CategoryManager()
2621 varun.gupt 880
    cat = cm.getCategory(category)
881
    return cat.children_category_ids if cat else None
2404 chandransh 882
 
626 chandransh 883
def get_best_sellers(start_index, stop_index, category=-1):
2404 chandransh 884
    '''
885
    Returns the Best Sellers between the start and the stop index in the given category
886
    '''
1926 rajveer 887
    query = get_best_sellers_query(category, None)
1098 chandransh 888
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 889
    return get_thrift_item_list(best_sellers)
890
 
2093 chandransh 891
def get_best_sellers_count(category=-1):
2404 chandransh 892
    '''
893
    Returns the number of best sellers in the given category
894
    '''
1926 rajveer 895
    count = get_best_sellers_query(category, None).count()
1120 rajveer 896
    if count is None:
897
        count = 0
766 rajveer 898
    return count
621 chandransh 899
 
1926 rajveer 900
def get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 901
    '''
902
    Returns the Best sellers for the given brand and category between the start and the stop index.
903
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
904
    '''
1926 rajveer 905
    query = get_best_sellers_query(category, brand)
1098 chandransh 906
    best_sellers = query.all()[start_index:stop_index]
621 chandransh 907
    return [item.catalog_item_id for item in best_sellers]
1970 rajveer 908
 
1926 rajveer 909
def get_best_sellers_query(category, brand):
2404 chandransh 910
    '''
911
    Returns the query to be used for getting Best Sellers.
912
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
913
    '''
1098 chandransh 914
    query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)
626 chandransh 915
    if category != -1:
1970 rajveer 916
        all_categories = [category]
917
        child_categories = get_child_categories(category)
918
        if child_categories is not None:
919
            all_categories = all_categories + child_categories 
920
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 921
    if brand is not None:
922
        query = query.filter_by(brand=brand)
1098 chandransh 923
    query = query.order_by(asc(Item.bestSellingRank))
621 chandransh 924
    return query
609 chandransh 925
 
1098 chandransh 926
def get_best_deals(category=-1):
2404 chandransh 927
    '''
928
    Returns the Best deals in the given category. Ignores the category if it's passed as -1.
929
    '''
930
    query = get_best_deals_query(Item, category, None)
1098 chandransh 931
    items = query.all()
609 chandransh 932
    return get_thrift_item_list(items)
933
 
1098 chandransh 934
def get_best_deals_count(category=-1):
2404 chandransh 935
    '''
936
    Returns the count of best deals in the given category.
937
    Ignores the category if it's -1.
938
    '''
939
    count = get_best_deals_counting_query(func.count(distinct(Item.catalog_item_id)), category, None).scalar()
1120 rajveer 940
    if count is None:
941
        count = 0
766 rajveer 942
    return count
501 rajveer 943
 
1926 rajveer 944
def get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):
2404 chandransh 945
    '''
946
    Returns the catalog_item_ids of best deal items for the given brand and category.
947
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
948
    '''
949
    query = get_best_deals_query(Item, category, brand)
1098 chandransh 950
    best_deal_items = query.all()[start_index:stop_index]
951
    return [item.catalog_item_id for item in best_deal_items]
952
 
2404 chandransh 953
def get_best_deals_counting_query(obj, category, brand):
954
    '''
955
    Returns the query to be used to select the best deals in the given brand and category.
956
    Ignores the category if it's passed as -1 and the brand if it's passed as None. 
957
    '''
958
    query = session.query(obj).filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)
626 chandransh 959
    if category != -1:
1970 rajveer 960
        all_categories = [category]
961
        child_categories = get_child_categories(category)
962
        if child_categories is not None:
963
            all_categories = all_categories + child_categories 
964
        query = query.filter(Item.category.in_(all_categories))
1926 rajveer 965
    if brand is not None:
966
        query = query.filter_by(brand=brand)
2404 chandransh 967
    return query
968
 
969
def get_best_deals_query(obj, category, brand):
970
    '''
971
    Returns the query to be used to get the best deals in the given category and brand.
972
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
973
    '''
974
    query = get_best_deals_counting_query(obj, category, brand)
1098 chandransh 975
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))
976
    return query
609 chandransh 977
 
1098 chandransh 978
def get_latest_arrivals(limit, category=-1):
2404 chandransh 979
    '''
980
    Returns up to limit number of Latest Arrivals in the given category.
981
    '''
2975 chandransh 982
    categories = []
983
    if category != -1:
984
        categories = [category]
985
    query = get_latest_arrivals_query(Item, categories, None)
1098 chandransh 986
    items = query.all()[0:limit]
609 chandransh 987
    return get_thrift_item_list(items)
598 chandransh 988
 
1098 chandransh 989
def get_latest_arrivals_count(limit, category=-1):
2404 chandransh 990
    '''
991
    Returns the number of latest arrivals which will be displayed on the website.
3016 chandransh 992
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 993
    '''
2975 chandransh 994
    categories = []
995
    if category != -1:
996
        categories = [category]
997
    count = get_latest_arrivals_counting_query(func.count(distinct(Item.catalog_item_id)), categories, None).scalar()
1120 rajveer 998
    if count is None:
999
        count = 0
1000
    count = min(count, limit)
766 rajveer 1001
    return count
602 chandransh 1002
 
2975 chandransh 1003
def get_latest_arrivals_catalog_ids(start_index, stop_index, brand, categories=[]):
2404 chandransh 1004
    '''
1005
    Returns the catalog_item_ids of the latest arrivals between the start and the stop index
3016 chandransh 1006
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 1007
    '''
2975 chandransh 1008
    query = get_latest_arrivals_query(Item, categories, brand)
1098 chandransh 1009
    latest_arrivals = query.all()[start_index:stop_index]
1010
    return [item.catalog_item_id for item in latest_arrivals]
1011
 
2975 chandransh 1012
def get_latest_arrivals_counting_query(obj, categories, brand):
2404 chandransh 1013
    '''
1014
    Returns the query to be used to count Latest arrivals.
3016 chandransh 1015
    To ignore the categories, pass the list as empty. To ignore brand, pass it as null.
2404 chandransh 1016
    '''
1017
    query = session.query(obj).filter_by(status=status.ACTIVE)
2975 chandransh 1018
 
1019
    all_categories = []
1020
    for category in categories:
1021
        all_categories.append(category)
1970 rajveer 1022
        child_categories = get_child_categories(category)
2975 chandransh 1023
        if child_categories:
1024
            all_categories = all_categories + child_categories
1025
    if all_categories: 
1970 rajveer 1026
        query = query.filter(Item.category.in_(all_categories))
2975 chandransh 1027
 
1926 rajveer 1028
    if brand is not None:
1029
        query = query.filter_by(brand=brand)
2404 chandransh 1030
    return query
1031
 
2975 chandransh 1032
def get_latest_arrivals_query(obj, categories, brand):
2404 chandransh 1033
    '''
1034
    Returns the query to be used to retrieve Latest Arrivals.
1035
    Ignores the category if it's passed as -1 and the brand if it's passed as None.
1036
    '''
2975 chandransh 1037
    query = get_latest_arrivals_counting_query(obj, categories, brand)
1098 chandransh 1038
    query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))
1039
    return query
609 chandransh 1040
 
1041
def get_thrift_item_list(items):
1098 chandransh 1042
    return [to_t_item(item) for item in items if item != None]
635 rajveer 1043
 
1155 rajveer 1044
def generate_new_entity_id():
1045
    generator =  EntityIDGenerator.query.one()
1046
    id = generator.id + 1
1047
    generator.id = id
1048
    session.commit()
1049
    return id
1050
 
635 rajveer 1051
def put_category_object(object):
1052
    category = Category.get_by(id=1)
1053
    if category is None:
1054
        category = Category()
1055
    category.object = object    
1056
    session.commit()
1057
    return True
1058
 
1059
def get_category_object():
766 rajveer 1060
    object = Category.get_by(id=1).object
1061
    return object
1062
 
4283 anupam.sin 1063
def get_item_pricing(item_id, vendorId):
1341 chandransh 1064
    item = Item.query.filter_by(id=item_id).first()
1065
    if item is None:
1066
        raise InventoryServiceException(101, "Bad Item")
4307 anupam.sin 1067
    '''
1068
    if vendor id is -1 then we calculate an average transfer price to be populated
1069
    at the time of order creation. This will be later updated with actual transfer price
1070
    at the time of billing.
1071
    '''
1072
    if(vendorId == -1):
4543 anupam.sin 1073
        total = 0
4307 anupam.sin 1074
        try:
4858 anupam.sin 1075
            if item.preferredWarehouse is not None:
1076
                warehouse = Warehouse.query.filter_by(id=item.preferredWarehouse).first()
1077
                vendors = warehouse.vendors
1078
                item_pricings = []
1079
                for vendor in vendors :
1080
                    item_pricing = VendorItemPricing.query.filter_by(item=item, vendor=vendor).first()
1081
                    if item_pricing :
1082
                        item_pricings.append(item_pricing)
1083
            else :
1084
                item_pricings = VendorItemPricing.query.filter_by(item=item).all()
4315 anupam.sin 1085
            if item_pricings:
4307 anupam.sin 1086
                for item_pricing in item_pricings:
4543 anupam.sin 1087
                    total += item_pricing.transfer_price
4315 anupam.sin 1088
                avg = total / len(item_pricings)
1089
                item_pricing.transfer_price = avg
4543 anupam.sin 1090
            else:
1091
                item_pricing = VendorItemPricing()
1092
                item_pricing.transfer_price = item.sellingPrice
1093
                vendor = Vendor()
1094
                vendor.id = vendorId
1095
                item_pricing.vendor = vendor
1096
                item_pricing.item = item
1097
 
1098
            return item_pricing
4307 anupam.sin 1099
        except:
1100
            raise InventoryServiceException(101, "Item pricing not found ")
4283 anupam.sin 1101
    vendor = Vendor.get_by(id=vendorId)    
1341 chandransh 1102
    try:
1103
        item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()
1347 chandransh 1104
        return item_pricing
3244 chandransh 1105
    except MultipleResultsFound:
1341 chandransh 1106
        raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))
3244 chandransh 1107
    except NoResultFound:
1341 chandransh 1108
        raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))
1109
 
1970 rajveer 1110
def add_category(t_category):
1111
    category = Category.get_by(id=t_category.id)
1112
    if category is None:
1113
        category = Category()
1114
    category.id = t_category.id 
1115
    category.label = t_category.label
1116
    category.description = t_category.description
4762 phani.kuma 1117
    category.display_name = t_category.display_name
1970 rajveer 1118
    category.parent_category_id = t_category.parent_category_id 
1119
    session.commit()
1120
    return True
1121
 
1122
def get_category(id):
1123
    return Category.query.filter_by(id=id).first()
1124
 
1125
def get_all_categories():
1126
    return Category.query.all()
1127
 
1991 ankur.sing 1128
 
1129
def get_all_item_pricing(item_id):
1130
    item = Item.query.filter_by(id=item_id).first()
1131
    if item is None:
1132
        raise InventoryServiceException(101, "Bad Item")
1133
    item_pricing = VendorItemPricing.query.filter_by(item=item).all()
1134
    return item_pricing
1135
 
2116 ankur.sing 1136
def get_item_mappings(item_id):
1137
    item = Item.query.filter_by(id=item_id).first()
1138
    if item is None:
1139
        raise InventoryServiceException(101, "Bad Item")
1140
    item_mappings = VendorItemMapping.query.filter_by(item=item).all()
1141
    return item_mappings
1142
 
1143
def add_vendor_pricing(vendorItemPricing):
1991 ankur.sing 1144
    if not vendorItemPricing:
1145
        raise InventoryServiceException(108, "Bad vendorItemPricing in request")
1146
    vendorId = vendorItemPricing.vendorId
1147
    itemId = vendorItemPricing.itemId
1148
 
1149
    try:
1150
        vendor = Vendor.query.filter_by(id=vendorId).one()
1151
    except:
1152
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
1153
 
1154
    try:
1155
        item = Item.query.filter_by(id=itemId).one()
1156
    except:
1157
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
1158
 
2120 ankur.sing 1159
    validate_vendor_prices(to_t_item(item), vendorItemPricing)
2065 ankur.sing 1160
 
1991 ankur.sing 1161
    try:
1162
        ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()
1163
    except:
2116 ankur.sing 1164
        ds_vendorItemPricing = VendorItemPricing()
1165
        ds_vendorItemPricing.vendor = vendor
1166
        ds_vendorItemPricing.item = item
1991 ankur.sing 1167
 
1168
    if vendorItemPricing.mop:
1169
        ds_vendorItemPricing.mop = vendorItemPricing.mop
1170
    if vendorItemPricing.dealerPrice:
1171
        ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPrice
1172
    if vendorItemPricing.transferPrice:
2065 ankur.sing 1173
        ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPrice
1991 ankur.sing 1174
 
1175
    session.commit()
1176
    return
1177
 
2358 ankur.sing 1178
def add_vendor_item_mapping(key, vendorItemMapping):
2116 ankur.sing 1179
    if not vendorItemMapping:
1180
        raise InventoryServiceException(108, "Bad vendorItemMapping in request")
1181
    vendorId = vendorItemMapping.vendorId
1182
    itemId = vendorItemMapping.itemId
1183
 
1184
    try:
1185
        vendor = Vendor.query.filter_by(id=vendorId).one()
1186
    except:
1187
        raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))
1188
 
1189
    try:
1190
        item = Item.query.filter_by(id=itemId).one()
1191
    except:
1192
        raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))
1193
 
1194
    try:
2358 ankur.sing 1195
        ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==key)).one()
2116 ankur.sing 1196
    except:
1197
        ds_vendorItemMapping = VendorItemMapping()
1198
        ds_vendorItemMapping.vendor = vendor
1199
        ds_vendorItemMapping.item = item
1200
    ds_vendorItemMapping.item_key = vendorItemMapping.itemKey
4985 mandeep.dh 1201
 
2116 ankur.sing 1202
    session.commit()
4985 mandeep.dh 1203
 
1204
    # Marking the missed inventory as not ignored as the catalog dashboard user has updated their key
1205
    for missedInventoryUpdate in MissedInventoryUpdate.query.filter_by(itemKey = vendorItemMapping.itemKey).all():
1206
        missedInventoryUpdate.isIgnored = 0
1207
    session.commit()
1208
 
2116 ankur.sing 1209
    return
1210
 
2120 ankur.sing 1211
def validate_item_prices(item):
2129 ankur.sing 1212
    if item.mrp == None or item.sellingPrice == None or item.mrp == "" or item.sellingPrice == "":
1213
        return
1214
    if item.mrp < item.sellingPrice:
2120 ankur.sing 1215
        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))
1216
        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 1217
    return
2120 ankur.sing 1218
 
1219
def validate_vendor_prices(item, vendorPrices):
2129 ankur.sing 1220
    if item.mrp != None and item.mrp != "" and vendorPrices.mop != "" and item.mrp <  vendorPrices.mop:
2120 ankur.sing 1221
        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))
1222
        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)))
1223
    if vendorPrices.mop != "" and vendorPrices.transferPrice != "" and vendorPrices.transferPrice > vendorPrices.mop:
1224
        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))
1225
        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)))
1226
    return
2065 ankur.sing 1227
 
1228
def get_all_vendors():
1229
    return Vendor.query.all()
1230
 
4725 phani.kuma 1231
def check_color_valid(color):
1232
    if color is not None:
1233
        color = color.strip().lower()
1234
        if color != '' and color != 'na' and color != 'blank' and color != '(blank)':
1235
            return True
1236
    return False
1237
 
1238
def check_similar_item(brand, model_number, model_name, color):
2129 ankur.sing 1239
    query = Item.query
2428 ankur.sing 1240
    query = query.filter_by(brand=brand)
1241
    query = query.filter_by(model_number=model_number)
4725 phani.kuma 1242
    query = query.filter_by(model_name=model_name)
1243
    similar_items = query.all()
1244
    item = None
1245
    # Check if a similar item already exists in our database
1246
    for old_item in similar_items:
1247
        if old_item.color != None and old_item.color.strip().lower() == color.strip().lower():
1248
            item = old_item
1249
            break
1250
 
1251
    # 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 1252
    if item is None:
4725 phani.kuma 1253
        for old_item in similar_items:
1254
            if not check_color_valid(old_item.color):
1255
                item = old_item
1256
                break
1257
    i = 0
1258
    color_of_similar_item = None
1259
    # Check if a similar item already exists in our database to be used to get catalog_item_id
1260
    for old_item in similar_items:
1261
        # get a similar item already existing in our database with valid color
1262
        if check_color_valid(old_item.color):
1263
            similar_item = old_item
1264
            color_of_similar_item = similar_item.color
1265
            break
1266
        i = i + 1
1267
        # get a similar item already existing in our database if similar item with valid color is not found
1268
        if i == len(similar_items):
1269
            similar_item = old_item
1270
            color_of_similar_item = similar_item.color
1271
 
1272
    # Check if a similar item that is obtained above is having a valid color
1273
    if check_color_valid(color_of_similar_item):
1274
        # 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.
1275
        # 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.
1276
        if item is None and not check_color_valid(color):
1277
            return similar_item.id
1278
 
1279
    if item is None:
2116 ankur.sing 1280
        return 0
1281
    else:
1282
        return item.id
2286 ankur.sing 1283
 
1284
def change_risky_flag(item_id, risky):
1285
    item = get_item(item_id)
1286
    if not item:
1287
        raise InventoryServiceException(101, "Item missing in our database")
1288
    try:
1289
        log_risky_flag(item_id, risky)
1290
    except:
1291
        print "Not able to log risky flag change"
1292
    item.risky = risky
4295 varun.gupt 1293
    if not risky and item.status == status.PAUSED_BY_RISK:
2368 ankur.sing 1294
        change_item_status(item.id, status.ACTIVE)
2286 ankur.sing 1295
    session.commit()
1296
 
4957 phani.kuma 1297
def get_items_for_mastersheet(categoryName, brand):
1298
    if not categoryName or not brand:
1299
        raise InventoryServiceException(101, "Invalid category or brand in request")
1300
 
4762 phani.kuma 1301
    categories = ["Handsets", "Tablets", "Laptops"]
4957 phani.kuma 1302
    query = Item.query.filter(Item.status != status.PHASED_OUT)
1303
    if categoryName == "ALL":
1304
        pass
1305
    elif categoryName == "ALL Accessories":
1306
        query = query.filter(~Item.product_group.in_(categories))
1307
    elif categoryName == "ALL Handsets":
1308
        query = query.filter(Item.product_group.in_(categories))
1309
    elif categoryName == "Mobile Accessories":
1310
        child_categories = get_child_categories(10011)
1311
        if child_categories is not None:
1312
            child_categories.append(0)
1313
            query = query.filter(Item.category.in_(child_categories))
1314
    elif categoryName == "Laptop Accessories":
1315
        child_categories = get_child_categories(10070)
1316
        if child_categories is not None:
1317
            child_categories.append(0)
1318
            query = query.filter(Item.category.in_(child_categories))
1319
    else:
1320
        query = query.filter(Item.product_group == categoryName)
1321
 
1322
    if brand == "ALL":
1323
        pass
1324
    else:
1325
        query = query.filter(Item.brand == brand)
2358 ankur.sing 1326
    items = query.all()
1327
    return items
2116 ankur.sing 1328
 
2358 ankur.sing 1329
def get_risky_items():
1330
    items = Item.query.filter_by(risky=True).all()
1331
    return items
3008 rajveer 1332
 
2809 rajveer 1333
def get_similar_items_catalog_ids(start_index, stop_index, itemId):
3008 rajveer 1334
    query = SimilarItems.query.filter_by(item_id=itemId).limit(stop_index-start_index)
1335
    similar_items = query.all()
3289 rajveer 1336
    return_list = []
1337
    for similar_item in similar_items:
1338
        isActive = False
1339
        try:
1340
            all_items = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).all()
1341
        except:
1342
            continue
1343
        for item in all_items:
1344
            isActive = isActive or item.status == status.ACTIVE
1345
        if isActive:
1346
            return_list.append(similar_item.catalog_item_id)
1347
    return return_list
4423 phani.kuma 1348
 
1349
def get_all_similar_items_catalog_ids(itemId):
1350
    query = SimilarItems.query.filter_by(item_id=itemId)
1351
    similar_items = query.all()
1352
    return_list = []
1353
    for similar_item in similar_items:
1354
        item_query = Item.query.filter_by(catalog_item_id=similar_item.catalog_item_id).limit(1)
1355
        item = item_query.one()
1356
        return_list.append(item)
2809 rajveer 1357
 
4423 phani.kuma 1358
    return get_thrift_item_list(return_list)
1359
 
1360
def add_similar_item_catalog_id(itemId, catalog_item_id):
1361
    if not itemId or not catalog_item_id:
1362
        raise InventoryServiceException(101, "Bad itemId or catalogItemId in request")
1363
    items_for_entity = get_items_by_catalog_id(catalog_item_id)
1364
    if not len(items_for_entity):
1365
        raise InventoryServiceException(101, "catalogItemId does not exists in database")
1366
 
1367
    s_items = SimilarItems.query.filter_by(item_id=itemId, catalog_item_id=catalog_item_id).all()
1368
    if not len(s_items):
1369
        s_item = SimilarItems()
1370
        s_item.item_id=itemId
1371
        s_item.catalog_item_id=catalog_item_id
1372
        session.commit()
1373
        return items_for_entity[0]
1374
    else:
1375
        raise InventoryServiceException(101, "Already exists")
1376
 
1377
def delete_similar_item_catalog_id(itemId, catalog_item_id):
1378
    if not itemId or not catalog_item_id:
1379
        raise InventoryServiceException(101, "Bad itemId or catalogItemId in request")
1380
 
1381
    similar_item = SimilarItems.query.filter_by(item_id=itemId, catalog_item_id=catalog_item_id).all()
1382
    if len(similar_item):
1383
        similar_item[0].delete()
1384
    session.commit()
1385
    return True
1386
 
3079 rajveer 1387
def add_product_notification(itemId, email):
1388
    try:
3470 rajveer 1389
        try:
1390
            product_notification = ProductNotification.query.filter_by(item_id=itemId, email=email).one()
1391
        except:
1392
            product_notification = ProductNotification()
1393
            product_notification.email = email
1394
            product_notification.item_id = itemId
3079 rajveer 1395
        product_notification.addedOn = datetime.datetime.now()
1396
        session.commit()
1397
        return True
1398
    except:
1399
        return False
3086 rajveer 1400
 
1401
 
1402
def send_product_notifications():
1403
    product_notifications = ProductNotification.query.all()
1404
    for product_notification in product_notifications:
1405
        item = product_notification.item
4406 anupam.sin 1406
        availability = __get_item_availability(item, None)
3309 rajveer 1407
        if availability > 0 and item.status == status.ACTIVE:
3086 rajveer 1408
            __enque_product_notification_email(product_notification.email, __get_product_name(item) , product_notification.addedOn, __get_product_url(item), item.id)
1409
            product_notification.delete()
1410
    session.commit()
1411
    return True
1412
 
1413
def __get_product_name(item):
1414
    product_name = item.brand + " " + item.model_name + " " + item.model_number
1415
    color = item.color
1416
    if color is not None and color != 'NA':
1417
        product_name = product_name + " (" + color + ")"
3201 rajveer 1418
    product_name = product_name.replace("  "," ")
3086 rajveer 1419
    return product_name
1420
 
1421
 
1422
def __get_product_url(item):
1423
    product_url = "http://www.saholic.com/mobile-phones/" + item.brand + "-" + item.model_name + "-" + item.model_number + "-" + str(item.catalog_item_id)
1424
    product_url = product_url.replace("--","-")
1425
    product_url = product_url.replace(" ","")
1426
    return product_url
1427
 
3348 varun.gupt 1428
def get_all_brands_by_category(category_id):
1429
    catm = CategoryManager()
1430
    child_categories = catm.getCategory(category_id).children_category_ids
1431
    brands = session.query(distinct(Item.brand)).filter(Item.category.in_(child_categories)).all()
1432
 
1433
    return [brand[0] for brand in brands]
3086 rajveer 1434
 
4957 phani.kuma 1435
def get_all_brands():
1436
    brands = session.query(distinct(Item.brand)).order_by(Item.brand).all()
1437
 
1438
    return [brand[0] for brand in brands]
1439
 
3086 rajveer 1440
def __enque_product_notification_email(email, product, date, url, itemId):
1441
 
1442
    html = """
1443
        <html>
1444
        <body>
1445
        <div>
1446
        <p>
1447
            Hi,<br /><br />
1448
            The product requested by you on $date is now available on saholic.com.
1449
        </p>
1450
 
1451
        <p>    
1452
        <strong>Product: $product </strong>
1453
        </p>
1454
 
1455
        <p>
1456
        Click the link below to visit the product: 
1457
        <br/>
1458
        $url
1459
        </p>
1460
        <p>
1461
        Regards,<br/>
1462
        Saholic Customer Support Team<br/>
1463
        www.saholic.com<br/>
1464
        Email: help@saholic.com<br/>
1465
        </p>
1466
        </div>
1467
        </body>
1468
        </html>
1469
        """
1470
 
1471
    html = Template(html).substitute(dict(product=product,date=date,url=url))
3079 rajveer 1472
 
3086 rajveer 1473
    try:
1474
        helper_client = HelperClient().get_client()
1475
        helper_client.saveUserEmailForSending(email, "", "Product requested by you is available now.", html, str(itemId), "ProductNotification")
1476
    except Exception as e:
1477
        print e
1478
 
3557 rajveer 1479
def get_all_sources():
1480
    sources = Source.query.all()
1481
    return [to_t_source(source) for source in sources]
3086 rajveer 1482
 
3557 rajveer 1483
def get_item_pricing_by_source(itemId, sourceId):
1484
    item = Item.query.filter_by(id=itemId).first()
1485
    if item is None:
1486
        raise InventoryServiceException(101, "Bad Item")
1487
 
1488
    source = Source.query.filter_by(id=sourceId).first()
1489
    if source is None:
1490
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1491
 
1492
    item_pricing = SourceItemPricing.query.filter_by(source=source, item=item).first()
1493
    if item_pricing is None:
1494
        raise InventoryServiceException(101, "Pricing information not found for sourceId " + str(sourceId))
1495
    return item_pricing
1496
 
1497
def add_source_item_pricing(sourceItemPricing):
1498
    if not sourceItemPricing:
1499
        raise InventoryServiceException(108, "Bad sourceItemPricing in request")
1500
 
1501
    if not sourceItemPricing.sellingPrice:
4326 mandeep.dh 1502
        raise InventoryServiceException(101, "Selling Price is not defined for sourceId " + str(sourceItemPricing.sourceId))
3557 rajveer 1503
 
1504
    sourceId = sourceItemPricing.sourceId
1505
    itemId = sourceItemPricing.itemId
1506
 
1507
    item = Item.query.filter_by(id=itemId).first()
1508
    if item is None:
1509
        raise InventoryServiceException(101, "Bad Item")
1510
 
1511
    source = Source.query.filter_by(id=sourceId).first()
1512
    if source is None:
1513
        raise InventoryServiceException(101, "Source not found for sourceId " + str(sourceId))
1514
 
3564 rajveer 1515
    ds_sourceItemPricing = SourceItemPricing.get_by(source=source, item=item)
3557 rajveer 1516
    if ds_sourceItemPricing is None:
1517
        ds_sourceItemPricing = SourceItemPricing()
1518
        ds_sourceItemPricing.source = source
1519
        ds_sourceItemPricing.item = item
1520
 
1521
    if sourceItemPricing.mrp:
1522
        ds_sourceItemPricing.mrp = sourceItemPricing.mrp
1523
    ds_sourceItemPricing.sellingPrice = sourceItemPricing.sellingPrice
1524
 
1525
    session.commit()
1526
    return
1527
 
1528
def get_all_source_pricing(itemId):
1529
    item = Item.query.filter_by(id=itemId).first()
1530
    if item is None:
1531
        raise InventoryServiceException(101, "Bad Item")
1532
    source_pricing = SourceItemPricing.query.filter_by(item=item).all()
1533
    return source_pricing
1534
 
1535
 
1536
def get_item_for_source(item_id, sourceId):
1537
    item = get_item(item_id)
1538
    if sourceId == -1:
1539
        return item
1540
    try:
1541
        sip = get_item_pricing_by_source(item_id, sourceId)
1542
        item.sellingPrice = sip.sellingPrice
1543
        if sip.mrp:
1544
            item.mrp = sip.mrp
1545
    except:
1546
        print "No source pricing"
1547
    return item
1548
 
3872 chandransh 1549
def search_items(search_terms, offset, limit):
1550
    query = Item.query
1551
 
1552
    query_clause = []
1553
 
1554
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1555
 
1556
    for search_term in search_terms:
1557
        query_clause.append(Item.brand.like(search_term))
1558
        query_clause.append(Item.model_number.like(search_term))
1559
        query_clause.append(Item.model_name.like(search_term))
1560
 
1561
    query = query.filter(or_(*query_clause))
1562
 
1563
    query = query.order_by(Item.product_group, Item.brand, Item.model_number, Item.model_name).offset(offset)
1564
    if limit:
1565
        query = query.limit(limit)
1566
    items = query.all()
1567
    return items
1568
 
1569
def get_search_result_count(search_terms):
1570
    query = Item.query
1571
 
1572
    query_clause = []
1573
 
1574
    search_terms = ['%' + search_term + '%' for search_term in search_terms]
1575
 
1576
    for search_term in search_terms:
1577
        query_clause.append(Item.brand.like(search_term))
1578
        query_clause.append(Item.model_number.like(search_term))
1579
        query_clause.append(Item.model_name.like(search_term))
1580
 
1581
    query = query.filter(or_(*query_clause))
1582
 
1583
    return query.count()
1584
 
3924 rajveer 1585
def __clear_homepage_cache():
1586
    try:
1587
        # create a password manager
1588
        password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
1589
        # Add the username and password.
1590
        configclient = ConfigClient()
4310 rajveer 1591
        ips = configclient.get_property("production_servers_private_ips");
3924 rajveer 1592
        ips = ips.split(" ")
1593
 
1594
        for ip in ips:
4310 rajveer 1595
            try:
1596
                top_level_url = "http://" + ip + ":8080/"
1597
                password_mgr.add_password(None, top_level_url, "saholic", "shop2020")
1598
                handler = urllib2.HTTPBasicAuthHandler(password_mgr)
3924 rajveer 1599
 
4310 rajveer 1600
                opener = urllib2.build_opener(handler)
3924 rajveer 1601
 
4310 rajveer 1602
                # use the opener to fetch a URL
1603
                res = opener.open(top_level_url + "cache-admin/HomePageSnippets?_method=delete")
1604
                print "Successfully cleared home page cache" + res.read()
1605
            except:
1606
                print "Unable to clear home page cache" + res.read()
3924 rajveer 1607
    except:
1608
        print "Unable to clear cache, still should continue with other operations"
4024 chandransh 1609
 
4062 chandransh 1610
def get_pending_orders_inventory(vendor_id=1):
4024 chandransh 1611
    """
1612
    Returns a list of inventory stock for items for which there are pending orders.
1613
    """
4341 rajveer 1614
 
4368 rajveer 1615
    warehouse_ids = [warehouse.id for warehouse in get_warehouses_for_vendor(vendor_id)]
4064 chandransh 1616
    pending_items_inventory = []
1617
    if warehouse_ids:
1618
        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 1619
    return pending_items_inventory
4295 varun.gupt 1620
 
1621
def get_product_notifications(start_datetime):
1622
    '''
1623
    Returns a list of Product Notification objects each representing user requests for notification
1624
    '''
1625
    query = ProductNotification.query
3924 rajveer 1626
 
4295 varun.gupt 1627
    if start_datetime:
1628
        query = query.filter(ProductNotification.addedOn > start_datetime)
1629
 
1630
    notifications = query.order_by(desc('addedOn')).all()
1631
    return notifications
1632
 
1633
def get_product_notification_request_count(start_datetime):
1634
    '''
1635
    Returns list of items and the counts of product notification requests
1636
    '''
1637
    print start_datetime
1638
    query = session.query(ProductNotification, func.count(ProductNotification.email).label('count'))
1639
 
1640
    if start_datetime:
1641
        query = query.filter(ProductNotification.addedOn > start_datetime)
1642
 
1643
    counts = query.group_by(ProductNotification.item_id).order_by(desc('count')).all()
1644
    return counts
1645
 
766 rajveer 1646
def close_session():
1647
    if session.is_active:
1648
        print "session is active. closing it."
1399 rajveer 1649
        session.close()
3376 rajveer 1650
 
1651
def is_alive():
1652
    try:
1653
        session.query(Item.id).limit(1).one()
1654
        return True
1655
    except:
1656
        return False
4332 anupam.sin 1657
 
1658
def add_vendor(vendor):
1659
    if not vendor:
1660
        raise InventoryServiceException(108, "Bad vendor")
1661
    if get_Vendor(vendor.id):
1662
        #vendor is already present.
1663
        raise InventoryServiceException(101, "Vendor already present")
1664
 
1665
    ds_vendor = Vendor()
1666
    ds_vendor.id = vendor.id
1667
    ds_vendor.name = vendor.name
1668
    session.commit()
1669
    return ds_vendor.id
1670
 
1671
def add_warehouse_vendor_mapping(warehouse_id, VendorId):
1672
    return True
1673
 
1674
def get_vendors_for_warehouse(warehouse_id):
1675
    try:
1676
        warehouse = Warehouse.get_by(id=warehouse_id)
1677
        return warehouse.vendors
1678
    except:
1679
        raise InventoryServiceException(108, "Bad Warehouse Id")
1680
 
1681
def get_warehouses_for_vendor(vendorId):
1682
    try:
1683
        vendor = get_Vendor(vendorId)
1684
        return vendor.warehouses
1685
    except:
4649 phani.kuma 1686
        raise InventoryServiceException(108, "Bad Vendor Id")
1687
 
1688
def add_authorization_log_for_item(itemId, username, reason):
1689
    if not itemId or not username:
1690
        raise InventoryServiceException(101, "Bad itemId or Invalid username in request")
1691
    authorize_log = AuthorizationLog()
1692
    authorize_log.item_id = itemId
1693
    authorize_log.username = username
1694
    authorize_log.reason = reason
1695
    session.commit()
4797 rajveer 1696
    return True
1697
 
1698
def __send_mail_for_oos_item(item): 
1699
    try:
4930 rajveer 1700
        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 1701
    except Exception as e:
1702
        print e
4985 mandeep.dh 1703
 
1704
def mark_missed_inventory_updates_as_processed(itemKey, warehouseId):
1705
    MissedInventoryUpdate.query.filter_by(itemKey = itemKey, warehouseId = warehouseId).delete()
1706
    session.commit()
1707
 
1708
def get_item_keys_to_be_processed(warehouseId):
1709
    return [i.itemKey for i in MissedInventoryUpdate.query.filter_by(warehouseId = warehouseId, isIgnored = 0)]
1710
 
1711
def reset_availability(itemKey, vendorId, quantity, warehouseId):
1712
    vendorItemMapping = VendorItemMapping.get_by(vendor_id = vendorId, item_key = itemKey)
1713
    if vendorItemMapping:
1714
        itemId = vendorItemMapping.item_id
1715
        currentInventorySnapshot = CurrentInventorySnapshot.get_by(item_id = itemId, warehouse_id = warehouseId)
1716
        if currentInventorySnapshot:
1717
            currentInventorySnapshot.availibility = quantity
1718
        else:
1719
            add_inventory(itemId, warehouseId, quantity)
1720
    else:
1721
        raise InventoryServiceException(101, 'VendorMapping not found for: ' + itemKey)
1722
    session.commit()