Subversion Repositories SmartDukaan

Rev

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