Rev 2093 | Rev 2120 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
'''Created on 23-Mar-2010@author: ashish'''from elixir import *from shop2020.model.v1.catalog.impl import DataServicefrom shop2020.model.v1.catalog.impl.DataService import Item, \Warehouse, ItemInventoryHistory, CurrentInventorySnapshot, ItemInfo,\ItemChangeLog, Category, EntityIDGenerator, VendorItemPricing,\VendorItemMapping, Vendorfrom shop2020.thriftpy.model.v1.catalog.ttypes import \InventoryServiceException, statusfrom shop2020.model.v1.catalog.impl.Convertors import to_t_item,\to_t_vendor_item_pricingimport datetimeimport sysfrom shop2020.utils.Utils import log_entry, to_py_datefrom sqlalchemy import desc, ascfrom shop2020.model.v1.catalog.impl.CategoryManager import CategoryManagerfrom sqlalchemy.sql.expression import and_def initialize():DataService.initialize()def get_all_items(is_active):if is_active:items = Item.query.filter_by(status= status.ACTIVE).all()else:items = Item.query.all()return itemsdef get_all_items_by_status(status):if not status:#return all itemsitems = get_all_items(False)else:items = Item.query.filter_by(status=status).all()return itemsdef get_item(item_id):item = Item.get_by(id=item_id)return itemdef get_items_by_catalog_id(catalog_id):query = Item.query.filter_by(catalog_item_id=catalog_id)try:items = query.all()return get_thrift_item_list(items)except Exception as ex:print exraise InventoryServiceException(109, "Item not found")def is_active(item_id):try:item = get_item(item_id)return item.status == status.ACTIVEexcept InventoryServiceException:return Falsedef get_item_status_description(itemId):item = get_item(itemId)return item.status_descriptiondef get_Warehouse(warehouse_id):return Warehouse.get_by(id=warehouse_id)def get_all_warehouses_by_status(status):if not status:warehouses = Warehouse.query.all()else:warehouses = Warehouse.query.filter_by(status=status).all()return warehousesdef get_all_warehouses_for_item(item_id):item = get_item(item_id)if not item:raise InventoryServiceException(108, "Some unforeseen error while obtaining item")return item.get_all_warehousesdef get_all_items_for_warehouse(warehouse_id):warehouse = get_Warehouse(warehouse_id)if not warehouse:raise InventoryServiceException(108, "bad warehouse")return warehouse.all_itemsdef add_warehouse(warehouse):if not warehouse:raise InventoryServiceException(108, "Bad warehouse")if get_Warehouse(warehouse.id):#warehouse is already present.raise InventoryServiceException(101, "Warehouse already present")ds_warehouse = Warehouse()ds_warehouse.id = warehouse.idds_warehouse.location = warehouse.locationds_warehouse.status = status.ACTIVEds_warehouse.addedOn = datetime.datetime.now()ds_warehouse.lastCheckedOn = datetime.datetime.now()ds_warehouse.tinNumber = warehouse.tinNumberds_warehouse.pincode = warehouse.pincodeif warehouse.vendorString:ds_warehouse.vendorString = warehouse.vendorStringsession.commit()return ds_warehouse.iddef update_item(item):if not item:raise InventoryServiceException(108, "Bad item in request")if not item.id:raise InventoryServiceException(101, "Missing id for update")validate_prices(item)ds_item = get_item(item.id)if not ds_item:raise InventoryServiceException(101, "Item missing in our database")if item.productGroup:ds_item.product_group = item.productGroupif item.brand:ds_item.brand = item.brandif item.modelName:ds_item.model_name = item.modelNameif item.modelNumber:ds_item.model_number = item.modelNumberif item.color:ds_item.color = item.colorif item.category:ds_item.category = item.categoryif item.comments:ds_item.comments = item.commentsif item.catalogItemId:ds_item.catalog_item_id = item.catalogItemIdif item.mrp:ds_item.mrp = item.mrpif item.mop:ds_item.mop = item.mopif item.sellingPrice:ds_item.sellingPrice = item.sellingPriceif item.dealerPrice:ds_item.dealerPrice = item.dealerPriceif item.transferPrice:ds_item.transfer_price = item.transferPriceif item.weight:ds_item.weight = item.weightif item.itemStatus:ds_item.status = item.itemStatusif item.status_description:ds_item.status_description = item.status_descriptionif item.startDate:ds_item.startDate = to_py_date(item.startDate)if item.retireDate:ds_item.retireDate = to_py_date(item.retireDate)if item.featureId:ds_item.feature_id = item.featureIdif item.featureDescription:ds_item.feature_description = item.featureDescriptionif item.bestDealText:ds_item.bestDealText = item.bestDealTextif item.bestDealValue:ds_item.bestDealValue = item.bestDealValueds_item.bestSellingRank = item.bestSellingRankds_item.defaultForEntity = item.defaultForEntityds_item.updated_on = datetime.datetime.now()session.commit();return ds_item.iddef check_vendor_item_mapping(product_group, brand, model_number, color, vendor_id, vendor_category):key = product_group.strip().lower() + '|' + brand.strip().lower() + '|' + model_number.strip().lower() + '|' + color.strip().lower()try:vim = VendorItemMapping.query.filter_by(vendor_id=vendor_id, item_key=key, vendor_category=vendor_category).one()return Trueexcept:return Falsedef add_item(item):if not item:raise InventoryServiceException(108, "Bad item in request")if get_item(item.id):raise InventoryServiceException(101, "Item already exists")ds_item = Item()if item.productGroup:ds_item.product_group = item.productGroupif item.brand:ds_item.brand = item.brandif item.modelName:ds_item.model_name = item.modelNameif item.modelNumber:ds_item.model_number = item.modelNumberif item.color:ds_item.color = item.colorif item.hotspotCategory:ds_item.hotspotCategory = item.hotspotCategoryif item.hotspotCategory == 'Handsets':item.preferredWarehouse = 1else:item.preferredWarehouse = 2if item.category:ds_item.category = item.categoryif item.comments:ds_item.comments = item.commentsds_item.addedOn = datetime.datetime.now()ds_item.updatedOn = datetime.datetime.now()if item.startDate:ds_item.startDate = to_py_date(item.startDate)if item.retireDate:ds_item.retireDate = to_py_date(item.retireDate)if item.mrp:ds_item.mrp = item.mrpif item.mop:ds_item.mop = item.mopif item.sellingPrice:ds_item.sellingPrice = item.sellingPriceif item.dealerPrice:ds_item.dealerPrice = item.dealerPriceif item.transferPrice:ds_item.transfer_price = item.transferPriceif item.weight:ds_item.weight = item.weightif item.featureId:ds_item.feature_id = item.featureIdif item.featureDescription:ds_item.feature_description = item.featureDescriptionif item.otherInfo:for k,v in item.otherInfo.iteritems():info = ItemInfo()info.key = kinfo.value = vds_item.iteminfo.append(info)#check if categories present. If yes, add them to systemif item.bestDealValue:ds_item.bestDealValue = item.bestDealValueif item.bestDealText:ds_item.bestDealText = item.bestDealTextif item.bestSellingRank:ds_item.bestSellingRank = item.bestSellingRankds_item.defaultForEntity = item.defaultForEntity# Check if a similar item already exists in our databasesimilar_item = Item.query.filter_by(product_group=item.productGroup, brand = item.brand, model_number=item.modelNumber, hotspotCategory=item.hotspotCategory).first()print "[SIMILAR ITEM FOUND:] FOR {0} {1} {2} {3} {4}".format(item.productGroup, item.brand, item.modelNumber, item.hotspotCategory, item.color)if similar_item is None or similar_item.catalog_item_id is None:# If there is no similar item in the database from before,# use the entity_id_generatorentity_id = EntityIDGenerator.query.first()ds_item.catalog_item_id = entity_id.id + 1ds_item.status = status.IN_PROCESSds_item.status_description = "This item is in process."entity_id.id = entity_id.id + 1else:#If a similar item already exists for a product group, brand and model_number, set it as same.ds_item.catalog_item_id = similar_item.catalog_item_idds_item.category = similar_item.categoryds_item.status = similar_item.statusds_item.status_description = similar_item.status_descriptionsession.commit();return ds_item.iddef update_inventory(warehouse_id, timestamp, availability):warehouse = get_Warehouse(warehouse_id)if not warehouse:raise InventoryServiceException(107, "Warehouse? Where?")time = datetime.datetime.now()warehouse.lastCheckedOn = timewarehouse.vendorString = timestampvendor = warehouse.vendorfor item_key, quantity in availability.iteritems():try:vendor_item_mapping = VendorItemMapping.query.filter_by(vendor=vendor, item_key=item_key).one();item = vendor_item_mapping.itemexcept:continuetry:item_inventory_history = ItemInventoryHistory()item_inventory_history.warehouse = warehouseitem_inventory_history.item = itemitem_inventory_history.timestamp = timeitem_inventory_history.availibility = quantitycurrent_inventory_snapshot = CurrentInventorySnapshot.get_by(item=item, warehouse=warehouse)if not current_inventory_snapshot:current_inventory_snapshot = CurrentInventorySnapshot()current_inventory_snapshot.item = itemcurrent_inventory_snapshot.warehouse = warehousecurrent_inventory_snapshot.availibility = 0current_inventory_snapshot.reserved = 0# added the difference in the current inventorycurrent_inventory_snapshot.availibility = current_inventory_snapshot.availibility + quantityexcept:raise InventoryServiceException(108, "Some unforeseen error while updating inventory")session.commit()def get_item_inventoy(item_id):inventory = Item.get_by(id=item_id).currentInventoryif not inventory:raise InventoryServiceException(108, "Some unforeseen error while updating inventory")return inventorydef get_item_inventory_by_item_id(item_id):inventory = Item.get_by(id=item_id).currentInventoryif not inventory:raise InventoryServiceException(108, "Some unforeseen error while updating inventory")return inventorydef retire_warehouse(warehouse_id):if not warehouse_id:raise InventoryServiceException(101, "Bad warehouse id")warehouse = get_Warehouse(warehouse_id)if not warehouse:raise InventoryServiceException(108, "warehouse id not present")warehouse.status = status.DELETED;session.commit()def retire_item(item_id):if not item_id:raise InventoryServiceException(101, "bad item id")item = get_item(item_id)if not item:raise InventoryServiceException(108, "item id not present")item.status = status.PHASED_OUTitem.retireDate = datetime.datetime.now()session.commit()#need to implement threads based solution heredef start_item_on(item_id, timestamp):if not item_id:raise InventoryServiceException(101, "bad item id")item = get_item(item_id)if not item:raise InventoryServiceException(108, "item id not present")item.status = status.ACTIVEitem.startDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))add_status_change_log(item, status.ACTIVE)session.commit()#need to implement threads heredef retire_item_on(item_id, timestamp):if not item_id:raise InventoryServiceException(101, "bad item id")item = get_item(item_id)if not item:raise InventoryServiceException(108, "item id not present")item.status = status.PHASED_OUTitem.retireDate = datetime.datetime.fromtimestamp(to_py_date(timestamp))add_status_change_log(item, status.PHASED_OUT)session.commit()def add_status_change_log(item, new_status):item_change_log = ItemChangeLog()item_change_log.new_status = new_statusitem_change_log.old_status = item.statusitem_change_log.timestamp = datetime.datetime.now()item_change_log.item = itemsession.commit()def change_item_status(item_id, new_status):if not item_id:raise InventoryServiceException(101, "bad item id")item = get_item(item_id)if not item:raise InventoryServiceException(108, "item id not present")add_status_change_log(item, new_status)item.status = new_statussession.commit()def get_item_availability_for_warehouse(warehouse_id, item_id):if not warehouse_id:raise InventoryServiceException(101, "bad warehouse_id")if not item_id:raise InventoryServiceException(101, "bad item_id")warehouse = get_Warehouse(warehouse_id)if not warehouse:raise InventoryServiceException(108, "warehouse does not exist")item = get_item(item_id)if not item:raise InventoryServiceException(108, "item does not exist")query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id)query = query.filter_by(item_id = item.id)try:current_inventory_snapshot = query.one()return current_inventory_snapshot.availibility - current_inventory_snapshot.reservedexcept:return 0"""current_inventory_snapshot = CurrentInventorySnapshot.query.filter(CurrentInventorySnapshot.warehouse_id == warehouse_id, CurrentInventorySnapshot.item_id == item_id).one()if not current_inventory_snapshot:return 0else:return current_inventory_snapshot.availibility"""def reserve_item_in_warehouse(item_id, warehouse_id, quantity):if not warehouse_id:raise InventoryServiceException(101, "bad warehouse_id")if not item_id:raise InventoryServiceException(101, "bad item_id")query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)try:current_inventory_snapshot = query.one()current_inventory_snapshot.reserved = current_inventory_snapshot.reserved + quantitysession.commit()return Trueexcept:print "Unexpected error:", sys.exc_info()[0]return Falsedef reduce_reservation_count(item_id, warehouse_id, quantity):if not warehouse_id:raise InventoryServiceException(101, "bad warehouse_id")if not item_id:raise InventoryServiceException(101, "bad item_id")query = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id)try:current_inventory_snapshot = query.one()current_inventory_snapshot.reserved = current_inventory_snapshot.reserved - quantitysession.commit()return Trueexcept:print "Unexpected error:", sys.exc_info()[0]return Falsedef mark_item_as_content_complete(entity_id, category, brand, modelName, modelNumber):content_complete_status = status.CONTENT_COMPLETEitems = Item.query.filter_by(catalog_item_id=entity_id, status=status.IN_PROCESS).all()current_timestamp = datetime.datetime.now()for item in items:item_change_log = ItemChangeLog()item_change_log.old_status = item.statusitem_change_log.new_status = content_complete_statusitem_change_log.timestamp = current_timestampitem_change_log.item = itemitem.status = content_complete_statusitem.category = categoryitem.brand = branditem.model_name = modelNameitem.model_number = modelNumberitem.updatedOn = current_timestampsession.commit()return Truedef get_item_availability_for_location(warehouse_loc, item_id):if warehouse_loc is None:raise InventoryServiceException(101, "Bad Warehouse Location")if not item_id:raise InventoryServiceException(101, "Bad Item id")item = Item.get_by(id=item_id)warehouses = Warehouse.query.filter_by(logisticsLocation=warehouse_loc).all()warehouse_ids = [warehouse.id for warehouse in warehouses]warehouse_retid = -1global_availability = 0for warehouse_id in warehouse_ids:try:current_inventory_snapshot = CurrentInventorySnapshot.query.filter_by(warehouse_id = warehouse_id, item_id = item_id).one()availability = current_inventory_snapshot.availibility - current_inventory_snapshot.reservedexcept:availability = 0if availability > global_availability:warehouse_retid = warehouse_idglobal_availability = availabilityif warehouse_retid == -1:# This is the case when all warehouses have exhausted their# inventory of this item or no warehouse is available in this# location.warehouse_retid = int(item.preferredWarehouse)return [warehouse_retid, global_availability]def get_warehouses_for_item(item_id):if not item_id:raise InventoryServiceException(101, "bad item_id")item = get_item(item_id)if not item:raise InventoryServiceException(101, "bad item")warehouses = item.currentInventory.warehousereturn warehousesdef get_best_sellers(start_index, stop_index, category=-1):query = get_best_sellers_query(category, None)best_sellers = query.all()[start_index:stop_index]return get_thrift_item_list(best_sellers)def get_best_sellers_count(category=-1):count = get_best_sellers_query(category, None).count()if count is None:count = 0return countdef get_best_sellers_catalog_ids(start_index, stop_index, brand, category=-1):query = get_best_sellers_query(category, brand)best_sellers = query.all()[start_index:stop_index]return [item.catalog_item_id for item in best_sellers]def get_child_categories(category):cm = CategoryManager()return cm.getCategory(category).children_category_idsdef get_best_sellers_query(category, brand):query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestSellingRank != None)if category != -1:all_categories = [category]child_categories = get_child_categories(category)if child_categories is not None:all_categories = all_categories + child_categoriesquery = query.filter(Item.category.in_(all_categories))if brand is not None:query = query.filter_by(brand=brand)query = query.order_by(asc(Item.bestSellingRank))return querydef get_best_deals(category=-1):query = get_best_deals_query(category, None)items = query.all()return get_thrift_item_list(items)def get_best_deals_count(category=-1):count = get_best_deals_query(category, None).count()if count is None:count = 0return countdef get_best_deals_catalog_ids(start_index, stop_index, brand, category=-1):query = get_best_deals_query(category, brand)best_deal_items = query.all()[start_index:stop_index]return [item.catalog_item_id for item in best_deal_items]def get_best_deals_query(category, brand):query = Item.query.filter_by(status=status.ACTIVE).filter(Item.bestDealValue != None)if category != -1:all_categories = [category]child_categories = get_child_categories(category)if child_categories is not None:all_categories = all_categories + child_categoriesquery = query.filter(Item.category.in_(all_categories))if brand is not None:query = query.filter_by(brand=brand)query = query.group_by(Item.catalog_item_id).order_by(desc(Item.bestDealValue))return querydef get_latest_arrivals(limit, category=-1):query = get_latest_arrivals_query(category, None)items = query.all()[0:limit]return get_thrift_item_list(items)def get_latest_arrivals_count(limit, category=-1):count = get_latest_arrivals_query(category, None).count()if count is None:count = 0count = min(count, limit)return countdef get_latest_arrivals_catalog_ids(start_index, stop_index, brand, category=-1):query = get_latest_arrivals_query(category, brand)latest_arrivals = query.all()[start_index:stop_index]return [item.catalog_item_id for item in latest_arrivals]def get_latest_arrivals_query(category, brand):query = Item.query.filter_by(status=status.ACTIVE)if category != -1:all_categories = [category]child_categories = get_child_categories(category)if child_categories is not None:all_categories = all_categories + child_categoriesquery = query.filter(Item.category.in_(all_categories))if brand is not None:query = query.filter_by(brand=brand)query = query.group_by(Item.catalog_item_id).order_by(desc(Item.startDate))return querydef get_thrift_item_list(items):return [to_t_item(item) for item in items if item != None]def generate_new_entity_id():generator = EntityIDGenerator.query.one()id = generator.id + 1generator.id = idsession.commit()return iddef put_category_object(object):category = Category.get_by(id=1)if category is None:category = Category()category.object = objectsession.commit()return Truedef get_category_object():object = Category.get_by(id=1).objectreturn objectdef get_item_pricing(item_id, warehouse_id):item = Item.query.filter_by(id=item_id).first()if item is None:raise InventoryServiceException(101, "Bad Item")warehouse = get_Warehouse(warehouse_id)if not warehouse:raise InventoryServiceException(108, "Bad Warehouse")vendor = warehouse.vendortry:item_pricing = VendorItemPricing.query.filter_by(vendor=vendor, item=item).one()return item_pricingexcept sqlalchemy.orm.exc.MultipleResultsFound:raise InventoryServiceException(110, "Multiple pricing information present for Vendor: " + vendor.name + " and Item: " + str(item_id))except sqlalchemy.orm.exc.NoResultFound:raise InventoryServiceException(111, "Missing pricing information for Vendor: " + vendor.name + " and Item: " + str(item_id))def add_category(t_category):category = Category.get_by(id=t_category.id)if category is None:category = Category()category.id = t_category.idcategory.label = t_category.labelcategory.description = t_category.descriptioncategory.parent_category_id = t_category.parent_category_idsession.commit()return Truedef get_category(id):return Category.query.filter_by(id=id).first()def get_all_categories():return Category.query.all()def get_all_item_pricing(item_id):item = Item.query.filter_by(id=item_id).first()if item is None:raise InventoryServiceException(101, "Bad Item")item_pricing = VendorItemPricing.query.filter_by(item=item).all()return item_pricingdef get_item_mappings(item_id):item = Item.query.filter_by(id=item_id).first()if item is None:raise InventoryServiceException(101, "Bad Item")item_mappings = VendorItemMapping.query.filter_by(item=item).all()return item_mappingsdef add_vendor_pricing(vendorItemPricing):if not vendorItemPricing:raise InventoryServiceException(108, "Bad vendorItemPricing in request")vendorId = vendorItemPricing.vendorIditemId = vendorItemPricing.itemIdtry:vendor = Vendor.query.filter_by(id=vendorId).one()except:raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))try:item = Item.query.filter_by(id=itemId).one()except:raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))validate_prices(to_t_item(item), vendorItemPricing)try:ds_vendorItemPricing = VendorItemPricing.query.filter(and_(VendorItemPricing.vendor==vendor, VendorItemPricing.item==item)).one()except:ds_vendorItemPricing = VendorItemPricing()ds_vendorItemPricing.vendor = vendords_vendorItemPricing.item = itemif vendorItemPricing.mop:ds_vendorItemPricing.mop = vendorItemPricing.mopif vendorItemPricing.dealerPrice:ds_vendorItemPricing.dealerPrice = vendorItemPricing.dealerPriceif vendorItemPricing.transferPrice:ds_vendorItemPricing.transfer_price = vendorItemPricing.transferPricesession.commit()returndef add_vendor_item_mapping(vendorItemMapping):if not vendorItemMapping:raise InventoryServiceException(108, "Bad vendorItemMapping in request")vendorId = vendorItemMapping.vendorIditemId = vendorItemMapping.itemIdtry:vendor = Vendor.query.filter_by(id=vendorId).one()except:raise InventoryServiceException(101, "Vendor not found for vendorId " + str(vendorId))try:item = Item.query.filter_by(id=itemId).one()except:raise InventoryServiceException(101, "Item not found for vendorId " + str(itemId))try:ds_vendorItemMapping = VendorItemMapping.query.filter(and_(VendorItemMapping.vendor==vendor, VendorItemMapping.item==item, VendorItemMapping.item_key==vendorItemMapping.itemKey)).one()except:ds_vendorItemMapping = VendorItemMapping()ds_vendorItemMapping.vendor = vendords_vendorItemMapping.item = itemds_vendorItemMapping.vendor_category = vendorItemMapping.vendorCategoryds_vendorItemMapping.item_key = vendorItemMapping.itemKeysession.commit()returndef validate_prices(item, vendorPrices = None):if item.mrp != "" and item.sellingPrice != "" and item.mrp < item.sellingPrice:raise InventoryServiceException("[BAD MRP and SP:] for {0} {1} {2} {3}. MRP={4}, SP={5}".format(item.productGroup, item.brand, item.modelNumber, item.color, item.mrp, item.sellingPrice))if not vendorPrices:vendorPricesList = [to_t_vendor_item_pricing(vip) for vip in get_all_item_pricing(item.id)]else:vendorPricesList = [vendorPrices]for vp in vendorPricesList:if item.mrp != "" and vp.mop != "" and item.mrp < vp.mop: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, item.mrp, vp.mop, vp.vendorId))if vp.mop != "" and vp.transferPrice != "" and vp.transferPrice > vp.mop:raise InventoryServiceException("[BAD MOP and TP:] for {0} {1} {2} {3}. TP={4}. MOP={5}, Vendor={6}".format(item.productGroup, item.brand, item.modelNumber, item.color, vp.transferPrice, vp.mop, vp.vendorId))returndef get_all_vendors():return Vendor.query.all()def check_similar_item(product_group, brand, model_number, color):item = Item.query.filter_by(product_group=product_group,brand=brand,model_number=model_number,color=color).first()if item is None:return 0else:return item.iddef close_session():if session.is_active:print "session is active. closing it."session.close()