Subversion Repositories SmartDukaan

Rev

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