Subversion Repositories SmartDukaan

Rev

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