Subversion Repositories SmartDukaan

Rev

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