Subversion Repositories SmartDukaan

Rev

Rev 5052 | Rev 5110 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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