Subversion Repositories SmartDukaan

Rev

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