Rev 5361 | Rev 5443 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
'''Created on 29-Jul-2011@author: Chandranshu'''from elixir import metadata, setup_all, sessionfrom shop2020.clients.CatalogClient import CatalogClientfrom shop2020.clients.TransactionClient import TransactionClientfrom shop2020.purchase.main.model.LineItem import LineItemfrom shop2020.purchase.main.model.Purchase import Purchasefrom shop2020.purchase.main.model.PurchaseOrder import PurchaseOrderfrom shop2020.purchase.main.model.RevisionedPurchaseOrder import \RevisionedPurchaseOrderfrom shop2020.purchase.main.model.Supplier import Supplierfrom shop2020.thriftpy.model.v1.catalog.ttypes import WarehouseType, \InventoryTypefrom shop2020.thriftpy.model.v1.order.ttypes import OrderStatusfrom shop2020.thriftpy.purchase.ttypes import PurchaseServiceException, POStatus, \PurchaseOrder as TPurchaseOrder, LineItem as TLineItemfrom sqlalchemy import create_enginefrom sqlalchemy.sql.expression import or_import datetimeimport loggingimport syslogging.basicConfig(level=logging.DEBUG)class PurchaseServiceHandler:'''classdocs'''def __init__(self, dbname='warehouse', db_hostname='localhost', echoOn=True):'''Constructor'''engine = create_engine('mysql://root:shop2020@' + db_hostname + '/' + dbname, pool_recycle=7200)metadata.bind = enginemetadata.bind.echo = echoOnsetup_all(True)def createPurchaseOrder(self, tPurchaseOrder):"""Creates a purchase order based on the data in the given purchase order object.This method populates a number of missing fieldsParameters:- purchaseOrder"""try:purchaseOrder = PurchaseOrder(tPurchaseOrder)session.commit()purchaseOrder.set_po_number()session.commit()return purchaseOrder.idfinally:self.close_session()def getAllPurchaseOrders(self, status):"""Returns a list of all the purchase orders in the given stateParameters:- status"""try:pos = PurchaseOrder.query.filter_by(status=status).all()return [po.to_thrift_object() for po in pos ]finally:self.close_session()def getPurchaseOrder(self, id):"""Returns the purchase order with the given id. Throws an exception if there is no such purchase order.Parameters:- id"""try:purchaseOrder = PurchaseOrder.get_by(id=id)if not purchaseOrder:raise PurchaseServiceException(101, "No purchase order can be found with id:" + str(id))return purchaseOrder.to_thrift_object()finally:self.close_session()def getSupplier(self, id):"""Returns the supplier with the given order id. Throws an exception if there is no such supplier.Parameters:- id"""try:return Supplier.get_by(id=id).to_thrift_object()finally:self.close_session()def startPurchase(self, purchaseOrderId, invoiceNumber, freightCharges):"""Creates a purchase for the given purchase order.Throws an exception if no more purchases are allowed against the given purchase order.Parameters:- purchaseOrderId- invoiceNumber- freightCharges"""try:purchase_order = PurchaseOrder.get_by(id = purchaseOrderId)purchase = Purchase(purchase_order, invoiceNumber, freightCharges)session.commit()return purchase.idfinally:self.close_session()def closePurchase(self, purchaseId):"""Marks a purchase as complete and updates the receivedOn time.Throws an exception if no such purchase exists.Parameters:- purchaseId"""try:purchase = Purchase.get_by(id=purchaseId)purchase.receivedOn = datetime.datetime.now()session.commit()finally:self.close_session()def getAllPurchases(self, purchaseOrderId, open):"""Returns all open or closed purchases for the given purchase order. Throws an exception if no such purchase order existsParameters:- purchaseOrderId- open"""try:if open:purchases = Purchase.query.filter_by(purchaseOrder_id = purchaseOrderId, receivedOn = None).all()else:purchases = Purchase.query.filter_by(purchaseOrder_id = purchaseOrderId).filter(Purchase.receivedOn != None).all()return [purchase.to_thrift_object() for purchase in purchases]finally:self.close_session()def getPurchaseOrderForPurchase(self, purchaseId):"""Returns the purchase order for a given purchaseParameters:- purchaseId"""try:return self.getPurchaseOrder(Purchase.query.filter_by(id = purchaseId).one().purchaseOrder_id)finally:self.close_session()def getPendingPurchaseOrders(self, warehouseId):"""Creates purchase order objects from pending ordersParameters:- warehouseId"""try:purchaseOrders = []if not warehouseId:raise PurchaseServiceException(101, "bad warehouse id")transactionClient = TransactionClient().get_client()pending_orders = transactionClient.getOrdersInBatch([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.ACCEPTED], 0, 0, warehouseId)if not pending_orders:return purchaseOrderscatalog_client = CatalogClient().get_client()availability = {}warehouses = catalog_client.getWarehouses(WarehouseType.OURS, InventoryType.GOOD, 0, None, warehouseId)for warehouse in warehouses:goodWarehouseId = warehouse.idfor item in catalog_client.getAllItemsForWarehouse(goodWarehouseId):itemInventory = catalog_client.getItemInventoryByItemId(item.id)if availability.has_key(item.id):availability[item.id] = [availability[item.id][0] + itemInventory.availability[goodWarehouseId], item]else:availability[item.id] = [itemInventory.availability[goodWarehouseId], item]unfulfilledPurchaseOrders = PurchaseOrder.query.filter(or_(PurchaseOrder.status == POStatus.PARTIALLY_FULFILLED, PurchaseOrder.status == POStatus.READY)).all()for purchaseOrder in unfulfilledPurchaseOrders:for lineitem in purchaseOrder.lineitems:if availability.has_key(lineitem.itemId):availability[lineitem.itemId] = [availability[lineitem.itemId][0] + lineitem.unfulfilledQuantity, availability[lineitem.itemId][1]]else:item = catalog_client.getItem(lineitem.itemId)availability[item.id] = [lineitem.unfulfilledQuantity, item]codRequirements = {}requirements = {}for order in pending_orders:if order.purchaseOrderId:continuefor lineitem in order.lineitems:if (requirements.has_key(lineitem.item_id)):requirements[lineitem.item_id] += lineitem.quantityelse:requirements[lineitem.item_id] = lineitem.quantityif order.cod:if (codRequirements.has_key(lineitem.item_id)):codRequirements[lineitem.item_id] += lineitem.quantityelse:codRequirements[lineitem.item_id] = lineitem.quantitynetRequirements = {}for itemId in requirements.keys():requirementsCount = requirements.get(itemId)if availability.has_key(itemId):availabilityCount = availability.get(itemId)[0]item = availability.get(itemId)[1]if requirementsCount > availabilityCount:if item.preferredVendor is None:raise PurchaseServiceException(101, 'Preferred Vendor missing for ' + " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)]))if (netRequirements.has_key(item.preferredVendor)):netRequirements[item.preferredVendor].append([item, requirementsCount - availabilityCount])else:netRequirements[item.preferredVendor] = [[item, requirementsCount - availabilityCount]];else:item = catalog_client.getItem(itemId);if item.preferredVendor is None:raise PurchaseServiceException(101, 'Preferred Vendor missing for ' + " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)]))if (netRequirements.has_key(item.preferredVendor)):netRequirements[item.preferredVendor].append([item, requirementsCount])else:netRequirements[item.preferredVendor] = [[item, requirementsCount]];if not netRequirements:return purchaseOrdersfor vendorId in netRequirements.keys():t_purchase_order = TPurchaseOrder()t_purchase_order.supplierId = vendorIdt_purchase_order.warehouseId = warehouseIdt_purchase_order.lineitems = []for key in netRequirements.get(vendorId):item = key[0]quantity = key[1]t_po_lineitem = TLineItem()t_po_lineitem.productGroup = item.productGroupt_po_lineitem.brand = item.brandt_po_lineitem.modelNumber = item.modelNumbert_po_lineitem.modelName = item.modelNamet_po_lineitem.color = item.colort_po_lineitem.itemId = item.idt_po_lineitem.quantity = quantityif codRequirements.has_key(item.id):t_po_lineitem.codCount = min(codRequirements[item.id], quantity)try:item_pricing = catalog_client.getItemPricing(item.id, vendorId)except Exception as e:vendor = self.getSupplier(vendorId)print 'Could not find transfer price for Item id: ' + str(item.id) + ' and vendor id: ' + str(vendorId)print eraise PurchaseServiceException(101, 'Transfer price missing for ' + vendor.name + ' and ' + " ".join([item.brand, item.modelName, item.modelNumber, item.color]))t_po_lineitem.unitPrice = item_pricing.transferPricet_purchase_order.lineitems.append(t_po_lineitem)purchaseOrders.append(t_purchase_order)return purchaseOrdersfinally:self.close_session()def getSuppliers(self, ):"""Returns all the valid suppliers"""try:return [Supplier.to_thrift_object(supplier) for supplier in Supplier.query.all()]finally:self.close_session()def unFulfillPO(self, purchaseId, itemId, quantity):"""Unfulfills a given purchase id and an item with its quantity.Parameters:- purchaseId- itemId- quantity"""try:purchaseOrderId = Purchase.query.filter_by(id = purchaseId).one().purchaseOrder_idlineitems = LineItem.query.filter_by(purchaseOrder_id = purchaseOrderId, itemId = itemId).all()if lineitems:fulfilledQuantity = lineitems[0].quantity - lineitems[0].unfulfilledQuantityif fulfilledQuantity < quantity:raise PurchaseServiceException(101, 'Can UnFulfill only ' + str(fulfilledQuantity) + 'quantity')else:lineitems[0].unfulfilledQuantity = lineitems[0].unfulfilledQuantity + quantitylineitems[0].fulfilled = 0purchaseOrder = PurchaseOrder.get_by(id=purchaseOrderId)purchaseOrder.status = POStatus.PARTIALLY_FULFILLEDsession.commit()returnraise PurchaseServiceException(101, 'No lineitem found with this itemId: ' + str(itemId) + ' in PO Id: ' + str(purchaseOrderId))finally:self.close_session()def fulfillPO(self, purchaseOrderId, itemId, quantity):"""Fulfills a given purchase order with an item.Parameters:- purchaseOrderId- itemId- quantity"""try:lineitems = LineItem.query.filter_by(purchaseOrder_id = purchaseOrderId, itemId = itemId).all()if lineitems:if lineitems[0].unfulfilledQuantity < quantity:raise PurchaseServiceException(101, 'Can fulfill only ' + str(lineitems[0].unfulfilledQuantity) + ' quantity')else:lineitems[0].unfulfilledQuantity = lineitems[0].unfulfilledQuantity - quantityif not lineitems[0].unfulfilledQuantity:lineitems[0].fulfilled = 1session.commit()if not LineItem.query.filter_by(purchaseOrder_id = purchaseOrderId, fulfilled = 0).all():purchaseOrder = PurchaseOrder.get_by(id=purchaseOrderId)purchaseOrder.status = POStatus.CLOSEDsession.commit()returnraise PurchaseServiceException(101, 'No lineitem found with this itemId: ' + str(itemId) + ' in PO Id: ' + str(purchaseOrderId) )finally:self.close_session()def updatePurchaseOrder(self, purchaseOrder):"""Amends a PO sa per the new lineitems passedParameters:- purchaseOrder"""try:existingPurchaseOrder = PurchaseOrder.get_by(id = purchaseOrder.id)maxRevision = 0existingRevisions = RevisionedPurchaseOrder.query.filter_by(purchaseOrderId = purchaseOrder.id).all()if existingRevisions:maxRevision = max([a.revision for a in existingRevisions]) + 1newPOItems = {}for t_lineitem in purchaseOrder.lineitems:newPOItems[t_lineitem.itemId] = t_lineitemfor lineitem in existingPurchaseOrder.lineitems:fulfilledQuantity = lineitem.quantity - lineitem.unfulfilledQuantityif fulfilledQuantity:if not newPOItems.has_key(lineitem.itemId):raise PurchaseServiceException(101, 'Cannot remove fulfilled item id: ' + str(lineitem.itemId) + ' from PO')else:if newPOItems[lineitem.itemId].quantity < fulfilledQuantity:raise PurchaseServiceException(101, 'More quantity already fulfilled for item id: ' + str(lineitem.itemId))else:newPOItems[lineitem.itemId].unfulfilledQuantity = newPOItems[lineitem.itemId].unfulfilledQuantity - fulfilledQuantityrevisionedPurchaseOrder = RevisionedPurchaseOrder()revisionedPurchaseOrder.purchaseOrderId = purchaseOrder.idrevisionedPurchaseOrder.revision = maxRevisionrevisionedPurchaseOrder.itemId = lineitem.itemIdrevisionedPurchaseOrder.unfulfilledQuantity = lineitem.unfulfilledQuantityrevisionedPurchaseOrder.unitPrice = lineitem.unitPricerevisionedPurchaseOrder.createdAt = lineitem.createdAtrevisionedPurchaseOrder.quantity = lineitem.quantitylineitem.delete()existingPurchaseOrder.lineitems = [LineItem(existingPurchaseOrder, t_lineitem) for t_lineitem in purchaseOrder.lineitems]existingPurchaseOrder.totalCost = sum([t_lineitem.quantity * t_lineitem.unitPrice for t_lineitem in purchaseOrder.lineitems])session.commit()finally:self.close_session()def close_session(self):if session.is_active:print "session is active. closing it."session.close()def isAlive(self, ):"""For checking weather service is active alive or not. It also checks connectivity with database"""try:session.query(Supplier.id).limit(1).all()return Trueexcept:return Falsefinally:self.close_session()