Rev 23277 | Blame | Compare with Previous | Last modification | View Log | RSS feed
from datetime import date, datetime, timedeltafrom elixir import metadata, setup_all, sessionfrom email import encodersfrom email.mime.base import MIMEBasefrom email.mime.multipart import MIMEMultipartfrom email.mime.text import MIMETextfrom shop2020.clients.CatalogClient import CatalogClientfrom shop2020.clients.InventoryClient import InventoryClientfrom shop2020.clients.TransactionClient import TransactionClientfrom shop2020.purchase.main.model.Invoice import Invoicefrom 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.PurchaseReturn import PurchaseReturnfrom shop2020.purchase.main.model.PurchaseReturnSettlement import \PurchaseReturnSettlementfrom shop2020.purchase.main.model.RevisionedPurchaseOrder import \RevisionedPurchaseOrderfrom shop2020.purchase.main.model.Supplier import Supplierfrom shop2020.thriftpy.generic.ttypes import ExceptionTypefrom shop2020.thriftpy.model.v1.inventory.ttypes import WarehouseType, \InventoryType, ItemStockPurchaseParamsfrom shop2020.thriftpy.model.v1.order.ttypes import OrderStatusfrom shop2020.thriftpy.purchase.ttypes import PurchaseServiceException, POStatus, \PurchaseOrder as TPurchaseOrder, LineItem as TLineItem, POType, \PurchaseReturnType, PurchaseReturnInventoryTypefrom shop2020.utils.Utils import to_py_datefrom sqlalchemy import create_enginefrom sqlalchemy.sql.expression import or_from xlrd import open_workbookfrom xlwt.Workbook import Workbookimport loggingimport smtplibimport sysimport timeimport tracebackimport xlwtXLS_O_FILENAME = "allPendingPOs.xls"SENDER = "adwords@shop2020.in"PASSWORD = "adwords_shop2020"SUBJECT = "Pending Purchase Order " + date.today().isoformat()SMTP_SERVER = "smtp.gmail.com"SMTP_PORT = 587boldStyle = xlwt.XFStyle()f = xlwt.Font()f.bold = TrueboldStyle.font = fi = -1datetime_format = xlwt.XFStyle()datetime_format.num_format_str = 'dd/mm/yyyy HH:MM AM/PM'class PurchaseHandler:'''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 getSuppliers(self,):"""Returns all the valid suppliers"""return [Supplier.to_thrift_object(supplier) for supplier in Supplier.query.all()]def getPendingPurchaseOrders(self, warehouseId):"""Creates purchase order objects from pending ordersParameters:- warehouseId"""errorsMap={}try:purchaseOrders = []transactionClient = TransactionClient().get_client()pending_orders = transactionClient.getOrdersInBatch([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.ACCEPTED, OrderStatus.COD_VERIFICATION_PENDING], 0, 0, warehouseId, 0)if not pending_orders:print "pendingOrders empty"return purchaseOrders, errorsMapinventory_client = InventoryClient().get_client()availability = {}virtualInventory = {}ourGoodWarehouseIds = [w.id for w in inventory_client.getWarehouses(WarehouseType.OURS, InventoryType.GOOD, 0, None, warehouseId)]ourVirtualWarehouseIds = [w.id for w in inventory_client.getWarehouses(WarehouseType.THIRD_PARTY, InventoryType.GOOD, 0, None, None)]itemInventorySnapshot = inventory_client.getInventorySnapshot(0)for itemId, itemInventory in itemInventorySnapshot.iteritems():'''item = self.__get_item_from_master(itemId)'''for warehouseId, quantity in itemInventory.availability.iteritems():if warehouseId in ourGoodWarehouseIds:if availability.has_key(itemId):availability[itemId] = [availability[itemId][0] + quantity]else:availability[itemId] = [quantity]if warehouseId in ourVirtualWarehouseIds:if virtualInventory.has_key(itemId):virtualInventory[itemId] = [virtualInventory[itemId][0] + quantity]else:virtualInventory[itemId] = [quantity]previouslyOrderedQty = {}unfulfilledPurchaseOrders = PurchaseOrder.query.filter(or_(PurchaseOrder.status == POStatus.PARTIALLY_FULFILLED, PurchaseOrder.status == POStatus.READY)).filter(PurchaseOrder.type == POType.REAL).all()for purchaseOrder in unfulfilledPurchaseOrders:for lineitem in purchaseOrder.lineitems:if previouslyOrderedQty.has_key(lineitem.itemId):previouslyOrderedQty[lineitem.itemId] = previouslyOrderedQty[lineitem.itemId] + lineitem.unfulfilledQuantityelse:previouslyOrderedQty[lineitem.itemId] = lineitem.unfulfilledQuantityif availability.has_key(lineitem.itemId):availability[lineitem.itemId] = [availability[lineitem.itemId][0] + lineitem.unfulfilledQuantity]else:'''item = self.__get_item_from_master(lineitem.itemId)'''availability[lineitem.itemId] = [lineitem.unfulfilledQuantity]codRequirements = {}requirements = {}verificationPendingOrders = {}for order in pending_orders:if order.purchaseOrderId:continuefor lineitem in order.lineitems:if (requirements.has_key(lineitem.item_id)):requirements[lineitem.item_id] = requirements.get(lineitem.item_id) + lineitem.quantityelse:requirements[lineitem.item_id] = lineitem.quantityif order.cod:if (codRequirements.has_key(lineitem.item_id)):codRequirements[lineitem.item_id] = codRequirements.get(lineitem.item_id) + lineitem.quantityelse:codRequirements[lineitem.item_id] = lineitem.quantityif order.status == OrderStatus.COD_VERIFICATION_PENDING:if (verificationPendingOrders.has_key(lineitem.item_id)):verificationPendingOrders[lineitem.item_id] = verificationPendingOrders.get(lineitem.item_id) + lineitem.quantityelse:verificationPendingOrders[lineitem.item_id] = lineitem.quantityadvancedPOParameters = {}SKUListForPO = []inventory_client = InventoryClient().get_client()itemStockPurchaseParams = inventory_client.getNonZeroItemStockPurchaseParams()for itemStockPurchaseParam in itemStockPurchaseParams:inventory_client = InventoryClient().get_client()oosStatuses = inventory_client.getOosStatusesForXDaysForItem(itemStockPurchaseParam.item_id, 0, 3)salesCount = 0numDaysInStock = 0rtoCount = 0avgSales = 0.0lastXdaysSale =""oosStatus = Nonefor oosStatus in oosStatuses:if oosStatus.is_oos == False:salesCount = salesCount + oosStatus.num_ordersnumDaysInStock = numDaysInStock + 1lastXdaysSale = lastXdaysSale + str(oosStatus.num_orders) + "-"else:lastXdaysSale = lastXdaysSale + "X-"if oosStatus and oosStatus.rto_orders is not None:rtoCount = oosStatus.rto_orderslastXdaysSale = lastXdaysSale[:-1]if numDaysInStock>0:avgSales = float(salesCount)/numDaysInStockadvancedPOParameters[itemStockPurchaseParam.item_id] = [round(avgSales * itemStockPurchaseParam.numOfDaysStock), round(avgSales,2) , numDaysInStock, itemStockPurchaseParam.minStockLevel, itemStockPurchaseParam.numOfDaysStock, lastXdaysSale, rtoCount]if itemInventorySnapshot.has_key(itemStockPurchaseParam.item_id):itemAvailability = itemInventorySnapshot.get(itemStockPurchaseParam.item_id)currentAvailability = 0currentReserved = 0for wId, rQty in itemAvailability.reserved.iteritems():if wId in ourGoodWarehouseIds:currentReserved = currentReserved + rQty#Key Condition Added By Manish Sharmaif availability.has_key(itemStockPurchaseParam.item_id):if availability[itemStockPurchaseParam.item_id] is None:availability[itemStockPurchaseParam.item_id] = [0]else:availability[itemStockPurchaseParam.item_id] = [0]if (availability[itemStockPurchaseParam.item_id][0] - currentReserved) < max(advancedPOParameters[itemStockPurchaseParam.item_id][0], advancedPOParameters[itemStockPurchaseParam.item_id][3]):SKUListForPO.append(itemStockPurchaseParam.item_id)else:SKUListForPO.append(itemStockPurchaseParam.item_id)for key in requirements:if advancedPOParameters.has_key(key):continueprint "Item Id ---", keyinventory_client = InventoryClient().get_client()oosStatuses = inventory_client.getOosStatusesForXDaysForItem(key, 0, 3)salesCount = 0numDaysInStock = 0rtoCount = 0avgSales = 0.0lastXdaysSale = ""oosStatus = Nonefor oosStatus in oosStatuses:if oosStatus.is_oos == False:salesCount = salesCount + oosStatus.num_ordersnumDaysInStock = numDaysInStock + 1lastXdaysSale = lastXdaysSale + str(oosStatus.num_orders) + "-"else:lastXdaysSale = lastXdaysSale + "X-"lastXdaysSale = lastXdaysSale[:-1]if oosStatus and oosStatus.rto_orders:rtoCount = oosStatus.rto_ordersif numDaysInStock>0:avgSales = float(salesCount)/float(numDaysInStock)itemStockPurchaseParam = Nonetry:itemStockPurchaseParam = inventory_client.getItemStockPurchaseParams(key)except Exception as e:if errorsMap.has_key(key):errorsMap[key] = errorsMap.get(key) + "| Item Stock Purchase Param Missing"else:errorsMap[key] = "Item Stock Purchase Param Missing "continueinventory_client.updateItemStockPurchaseParams(key, 0, 0)itemStockPurchaseParam = inventory_client.getItemStockPurchaseParams(key)if itemStockPurchaseParam.numOfDaysStock is None:itemStockPurchaseParam.minStockLevel = 0itemStockPurchaseParam.numOfDaysStock = 0itemStockPurchaseParam.item_id = keyadvancedPOParameters[key] = [round(avgSales * itemStockPurchaseParam.numOfDaysStock), round(avgSales,2), numDaysInStock, itemStockPurchaseParam.minStockLevel, itemStockPurchaseParam.numOfDaysStock, lastXdaysSale, rtoCount]cumulativeRequirementsItemIds = list(set(requirements.keys()+SKUListForPO))netRequirements = {}for itemId in cumulativeRequirementsItemIds:print "Item Id for Preferred Vendor", itemIdrequirementsCount = requirements.get(itemId)if requirementsCount is None:requirementsCount = 0.0if availability.has_key(itemId):availabilityCount = availability.get(itemId)[0]item = self.get_item_from_master(itemId)if requirementsCount > availabilityCount or itemId in SKUListForPO:if item.preferredVendor is None:if errorsMap.has_key(itemId):errorsMap[itemId] = errorsMap.get(itemId) + "| Preferred Vendor is Missing"else:errorsMap[itemId] = "Preferred Vendor is Missing "continueif (netRequirements.has_key(item.preferredVendor)):netRequirements[item.preferredVendor].append([item, requirementsCount - availabilityCount])else:netRequirements[item.preferredVendor] = [[item, requirementsCount - availabilityCount]];else:item = self.get_item_from_master(itemId)if item.preferredVendor is None:if errorsMap.has_key(itemId):errorsMap[itemId] = errorsMap.get(itemId) + "| Preferred Vendor is Missing"else:errorsMap[itemId] = "Preferred Vendor is Missing "continueif (netRequirements.has_key(item.preferredVendor)):netRequirements[item.preferredVendor].append([item, requirementsCount])else:netRequirements[item.preferredVendor] = [[item, requirementsCount]];if not netRequirements:return purchaseOrders, errorsMapsuppliersMap = {}for supplier in self.getSuppliers():suppliersMap[supplier.id] = supplierfor vendorId in netRequirements.keys():t_purchase_order = {}supplier = suppliersMap.get(vendorId)t_purchase_order['SupplierName'] = supplier.namet_purchase_order['lineitems']= []for key in netRequirements.get(vendorId):item = key[0]quantity = key[1]t_po_lineitem = {}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['packQuantity'] = item.packQuantityif quantity <0: #TODO Check this logicquantity=0t_po_lineitem['quantity'] = quantityt_po_lineitem['availableQuantity'] = 0if availability.has_key(item.id):if previouslyOrderedQty.has_key(item.id):t_po_lineitem['availableQuantity'] = availability[item.id][0] - previouslyOrderedQty[item.id]else:t_po_lineitem['availableQuantity'] = availability[item.id][0]if requirements.has_key(item.id):t_po_lineitem['reservedQuantity'] = requirements[item.id]additionalQty = max(advancedPOParameters[item.id][0], advancedPOParameters[item.id][3])additionalQty = max(0,(additionalQty - (advancedPOParameters[item.id][6]/2)))suggestedQuantity = additionalQty +key[1]t_po_lineitem['suggestedQuantity'] = max(0,suggestedQuantity)#t_po_lineitem.suggestedQuantity = max(advancedPOParameters[item.id][0], advancedPOParameters[item.id][3]) + key[1]t_po_lineitem['avgSales'] = advancedPOParameters[item.id][1]t_po_lineitem['numberOfDaysInStock'] = advancedPOParameters[item.id][2]t_po_lineitem['minStockLevel'] = advancedPOParameters[item.id][3]t_po_lineitem['numberOfDaysStock'] = advancedPOParameters[item.id][4]t_po_lineitem['lastXdaysSale'] = advancedPOParameters[item.id][5]t_po_lineitem['rtoOrders'] = advancedPOParameters[item.id][6]if verificationPendingOrders.has_key(item.id):t_po_lineitem['verificationPending'] = verificationPendingOrders[item.id]else:t_po_lineitem['verificationPending'] = 0if virtualInventory.has_key(item.id):t_po_lineitem['virtualStock'] = virtualInventory[item.id][0]else:t_po_lineitem['virtualStock'] = 0if previouslyOrderedQty.has_key(item.id):t_po_lineitem['previouslyOrderedQty'] = previouslyOrderedQty[item.id]else:t_po_lineitem['previouslyOrderedQty'] = 0if codRequirements.has_key(item.id):t_po_lineitem['codCount'] = min(codRequirements[item.id], quantity)try:item_pricing = inventory_client.getItemPricing(item.id, vendorId)except Exception as e:if errorsMap.has_key(item.id):errorsMap[item.id] = errorsMap.get(item.id) + "| Could not find transfer price for vendor id: " + str(vendorId) +" "else:errorsMap[item.id] = "Could not find transfer price for vendor id: " + str(vendorId) +" "print 'Could not find transfer price for Item id: ' + str(item.id) + ' and vendor id: ' + str(vendorId)print et_po_lineitem['unitPrice'] = item_pricing.transferPricet_po_lineitem['nlc'] = item_pricing.nlct_po_lineitem['mrp'] = item.mrpt_purchase_order['lineitems'].append(t_po_lineitem)purchaseOrders.append(t_purchase_order)continuet_po_lineitem['unitPrice'] = item_pricing.transferPricet_po_lineitem['nlc'] = item_pricing.nlct_po_lineitem['mrp'] = item.mrpt_purchase_order['lineitems'].append(t_po_lineitem)purchaseOrders.append(t_purchase_order)print "errorMap : ", errorsMapreturn purchaseOrders, errorsMapexcept Exception as e:traceback.print_exc()finally:self.close_session()def close_session(self):if session.is_active:print "session is active. closing it."session.close()def get_item_from_master(self, item_id):client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()return client.getItem(item_id)def inc():global ii+=1return idef sendmail(email, message, title, *varargs):if email == "":returnmailServer = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)mailServer.ehlo()mailServer.starttls()mailServer.ehlo()# Create the container (outer) email message.msg = MIMEMultipart()msg['Subject'] = titlemsg.preamble = titlehtml_msg = MIMEText(message, 'html')msg.attach(html_msg)#snapdeal more to be added herefor fileName in varargs:snapdeal = MIMEBase('application', 'vnd.ms-excel')snapdeal.set_payload(file(fileName).read())encoders.encode_base64(snapdeal)snapdeal.add_header('Content-Disposition', 'attachment;filename=' + fileName)msg.attach(snapdeal)MAILTO = emailmailServer.login(SENDER, PASSWORD)mailServer.sendmail(SENDER, MAILTO, msg.as_string())def main():global ii = -1row = 0wb = xlwt.Workbook()worksheet = wb.add_sheet("All Pending Purchase Orders")worksheet.write(row, inc(), 'Supplier Name', boldStyle)worksheet.write(row, inc(), 'Item Id', boldStyle)worksheet.write(row, inc(), 'Product Name', boldStyle)worksheet.write(row, inc(), 'Quantity', boldStyle)worksheet.write(row, inc(), 'COD', boldStyle)worksheet.write(row, inc(), 'Prepaid', boldStyle)worksheet.write(row, inc(), 'Transfer price', boldStyle)worksheet.write(row, inc(), 'Nlc', boldStyle)worksheet.write(row, inc(), 'Total amount', boldStyle)worksheet.write(row, inc(), 'Pack Quantity', boldStyle)worksheet.write(row, inc(), 'Available Quantity', boldStyle)worksheet.write(row, inc(), 'Reserved Quantity', boldStyle)worksheet.write(row, inc(), 'Virtual Stock', boldStyle)worksheet.write(row, inc(), 'NetPendingOrderQty', boldStyle)worksheet.write(row, inc(), 'PreviouslyOrderedQty', boldStyle)worksheet.write(row, inc(), 'AverageSale', boldStyle)worksheet.write(row, inc(), 'Pending RTOs', boldStyle)worksheet.write(row, inc(), 'COD Pending Orders', boldStyle)worksheet.write(row, inc(), 'NumDaysStock', boldStyle)worksheet.write(row, inc(), 'MinStockReq', boldStyle)worksheet.write(row, inc(), 'Additional Qty', boldStyle)worksheet.write(row, inc(), 'Errors', boldStyle)purchaseHandler = PurchaseHandler()pendingPurchaseOrders, errorsMap = purchaseHandler.getPendingPurchaseOrders(7573)print errorsMapprint pendingPurchaseOrdersfor itemId, error in errorsMap.items():row += 1i=-1worksheet.write(row, inc(), "Not_defined")worksheet.write(row, inc(), str(itemId))item = purchaseHandler.get_item_from_master(itemId)worksheet.write(row, inc(), item.brand+" "+item.modelName+" "+item.modelNumber+" "+item.color)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), "Not_defined")worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), 0)worksheet.write(row, inc(), error)for purchaseOrder in pendingPurchaseOrders:for lineitem in purchaseOrder.get('lineitems'):row += 1i=-1worksheet.write(row, inc(), purchaseOrder.get('SupplierName'))worksheet.write(row, inc(), lineitem.get('itemId'))worksheet.write(row, inc(), lineitem.get('brand')+" "+lineitem.get('modelName')+" "+lineitem.get('modelNumber')+" "+lineitem.get('color'))worksheet.write(row, inc(), lineitem.get('suggestedQuantity'))codCount =0;if lineitem.get('codCount') is not None:codCount = lineitem.get('codCount')worksheet.write(row, inc(), codCount)worksheet.write(row, inc(), long(lineitem.get('quantity'))-long(codCount))worksheet.write(row, inc(), lineitem.get('unitPrice'))worksheet.write(row, inc(), lineitem.get('nlc'))worksheet.write(row, inc(), float(lineitem.get('suggestedQuantity')) * float(lineitem.get('unitPrice')))worksheet.write(row, inc(), lineitem.get('packQuantity'))reservedCount = 0if lineitem.get('reservedQuantity') is not None:reservedCount = lineitem.get('reservedQuantity')worksheet.write(row, inc(), long(lineitem.get('availableQuantity')))worksheet.write(row, inc(), long(reservedCount))worksheet.write(row, inc(), lineitem.get('virtualStock'))worksheet.write(row, inc(), long(reservedCount)-long(lineitem.get('availableQuantity')))worksheet.write(row, inc(), lineitem.get('previouslyOrderedQty'))worksheet.write(row, inc(), "("+lineitem.get('lastXdaysSale')+")"+str(lineitem.get('avgSales')))worksheet.write(row, inc(), lineitem.get('rtoOrders'))worksheet.write(row, inc(), lineitem.get('verificationPending'))worksheet.write(row, inc(), lineitem.get('numberOfDaysStock'))worksheet.write(row, inc(), lineitem.get('minStockLevel'))stockThroughAvgSales = float(lineitem.get('avgSales')) * float(lineitem.get('numberOfDaysStock'))additionalQty = 0if stockThroughAvgSales > float(lineitem.get('minStockLevel')):additionalQty = stockThroughAvgSaleselse:additionalQty = float(lineitem.get('minStockLevel'))if float(lineitem.get('rtoOrders')) >1:additionalQty = additionalQty - (float(lineitem.get('rtoOrders'))/2)if additionalQty<0:additionalQty = 0worksheet.write(row, inc(), additionalQty)error = "NA"if errorsMap.has_key(lineitem.get('itemId')):error = errorsMap.get(lineitem.get('itemId'))worksheet.write(row, inc(), error)wb.save(XLS_O_FILENAME)sendmail(["amit.gupta@shop2020.in", "ritesh.chauhan@shop2020.in", "rahul.kandpal@smartdukaan.com"], "", "All Pending Purchase Orders", XLS_O_FILENAME)#sendmail(["manish.sharma@shop2020.in"], "", "All Pending Purchase Orders", XLS_O_FILENAME)if __name__ == '__main__':main()