Subversion Repositories SmartDukaan

Rev

Rev 18016 | Rev 18425 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18010 manish.sha 1
from elixir import metadata, setup_all, session
2
from shop2020.clients.CatalogClient import CatalogClient
3
from shop2020.clients.InventoryClient import InventoryClient
4
from shop2020.clients.TransactionClient import TransactionClient
5
from shop2020.purchase.main.model.Invoice import Invoice
6
from shop2020.purchase.main.model.LineItem import LineItem
7
from shop2020.purchase.main.model.Purchase import Purchase
8
from shop2020.purchase.main.model.PurchaseReturn import PurchaseReturn
9
from shop2020.purchase.main.model.PurchaseReturnSettlement import PurchaseReturnSettlement
10
from shop2020.purchase.main.model.RevisionedPurchaseOrder import \
11
    RevisionedPurchaseOrder
12
from shop2020.purchase.main.model.Supplier import Supplier
13
from shop2020.purchase.main.model.PurchaseOrder import PurchaseOrder
14
from shop2020.thriftpy.generic.ttypes import ExceptionType
15
from shop2020.thriftpy.model.v1.inventory.ttypes import WarehouseType, \
16
    InventoryType, ItemStockPurchaseParams
17
from shop2020.thriftpy.model.v1.order.ttypes import OrderStatus
18
from shop2020.thriftpy.purchase.ttypes import PurchaseServiceException, POStatus, \
19
    PurchaseOrder as TPurchaseOrder, LineItem as TLineItem, POType,\
20
    PurchaseReturnType, PurchaseReturnInventoryType
21
from shop2020.utils.Utils import to_py_date
22
from sqlalchemy import create_engine
23
from sqlalchemy.sql.expression import or_
24
from datetime import date, datetime, timedelta
25
import logging
26
import sys
27
from xlrd import open_workbook
28
from xlwt.Workbook import Workbook
29
import smtplib
30
import time
31
import xlwt
32
from email import encoders
33
from email.mime.base import MIMEBase
34
from email.mime.multipart import MIMEMultipart
35
from email.mime.text import MIMEText
36
 
37
 
38
XLS_O_FILENAME = "allPendingPOs.xls"
39
SENDER = "adwords@shop2020.in"
40
PASSWORD = "adwords_shop2020"
41
SUBJECT = "Pending Purchase Order " + date.today().isoformat()
42
SMTP_SERVER = "smtp.gmail.com"
43
SMTP_PORT = 587
44
boldStyle = xlwt.XFStyle()
45
f = xlwt.Font()
46
f.bold = True
47
boldStyle.font = f
48
i = -1
49
 
50
datetime_format = xlwt.XFStyle()
51
datetime_format.num_format_str = 'dd/mm/yyyy HH:MM AM/PM'
52
 
53
class PurchaseHandler:
54
    '''
55
    classdocs
56
    '''
57
 
58
    def __init__(self, dbname='warehouse', db_hostname='localhost',  echoOn=True):
59
        '''
60
        Constructor
61
        '''
62
        engine = create_engine('mysql://root:shop2020@' + db_hostname + '/' + dbname, pool_recycle=7200)
63
        metadata.bind = engine
64
        metadata.bind.echo = echoOn
65
        setup_all(True)
66
 
67
    def getSuppliers(self,):
68
        """
69
        Returns all the valid suppliers
70
        """
71
        return [Supplier.to_thrift_object(supplier) for supplier in Supplier.query.all()]
72
 
73
    def getPendingPurchaseOrders(self, warehouseId):
74
        """
75
        Creates purchase order objects from pending orders
76
 
77
        Parameters:
78
         - warehouseId
79
        """
80
        try:
81
            purchaseOrders = []
82
 
83
            transactionClient = TransactionClient().get_client()
84
            pending_orders = transactionClient.getOrdersInBatch([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.ACCEPTED], 0, 0, warehouseId, 0)
85
 
86
            if not pending_orders:
87
                return purchaseOrders
88
 
89
            inventory_client = InventoryClient().get_client()
90
            availability = {}
91
 
92
            ourGoodWarehouseIds = [w.id for w in inventory_client.getWarehouses(WarehouseType.OURS, InventoryType.GOOD, 0, None, warehouseId)]
93
            itemInventorySnapshot = inventory_client.getInventorySnapshot(0)
94
            for itemId, itemInventory in itemInventorySnapshot.iteritems():
95
                '''item = self.__get_item_from_master(itemId)'''
96
                for warehouseId, quantity in itemInventory.availability.iteritems():
97
                    if warehouseId in ourGoodWarehouseIds:
98
                        if availability.has_key(itemId):
99
                            availability[itemId] = [availability[itemId][0] + quantity]
100
                        else:
101
                            availability[itemId] = [quantity]
102
 
103
            previouslyOrderedQty = {}
104
            unfulfilledPurchaseOrders = PurchaseOrder.query.filter(or_(PurchaseOrder.status == POStatus.PARTIALLY_FULFILLED, PurchaseOrder.status == POStatus.READY)).filter(PurchaseOrder.type == POType.REAL).all()
105
            for purchaseOrder in unfulfilledPurchaseOrders:
106
                for lineitem in purchaseOrder.lineitems:
107
                    if previouslyOrderedQty.has_key(lineitem.itemId):
108
                        previouslyOrderedQty[lineitem.itemId] = previouslyOrderedQty[lineitem.itemId] + lineitem.unfulfilledQuantity
109
                    else:
110
                        previouslyOrderedQty[lineitem.itemId] = lineitem.unfulfilledQuantity
111
 
112
                    if availability.has_key(lineitem.itemId):
113
                        availability[lineitem.itemId] = [availability[lineitem.itemId][0] + lineitem.unfulfilledQuantity]
114
                    else:
115
                        '''item = self.__get_item_from_master(lineitem.itemId)'''
116
                        availability[lineitem.itemId] = [lineitem.unfulfilledQuantity]
117
 
118
            codRequirements = {}
119
            requirements = {}
120
            for order in pending_orders:
121
                if order.purchaseOrderId:
122
                    continue
123
                for lineitem in order.lineitems:
124
                    if (requirements.has_key(lineitem.item_id)):
125
                        requirements[lineitem.item_id] += lineitem.quantity
126
                    else:
127
                        requirements[lineitem.item_id] = lineitem.quantity
128
 
129
                    if order.cod:
130
                        if (codRequirements.has_key(lineitem.item_id)):
131
                            codRequirements[lineitem.item_id] += lineitem.quantity
132
                        else:
133
                            codRequirements[lineitem.item_id] = lineitem.quantity
134
 
135
            advancedPOParameters = {}
136
            SKUListForPO = []
137
            inventory_client = InventoryClient().get_client()
138
            itemStockPurchaseParams = inventory_client.getNonZeroItemStockPurchaseParams()
139
            for itemStockPurchaseParam in itemStockPurchaseParams:
140
                inventory_client = InventoryClient().get_client()
141
                oosStatuses = inventory_client.getOosStatusesForXDaysForItem(itemStockPurchaseParam.item_id, 0, 3)
142
                salesCount = 0
143
                numDaysInStock = 0
144
                rtoCount = 0
145
                avgSales = 0.0
146
                lastXdaysSale ="" 
147
                for oosStatus in oosStatuses:
148
                    if oosStatus.is_oos == False:
149
                        salesCount = salesCount + oosStatus.num_orders
150
                        numDaysInStock = numDaysInStock + 1
151
                        lastXdaysSale = lastXdaysSale + str(oosStatus.num_orders) + "-" 
152
                    else:
153
                        lastXdaysSale = lastXdaysSale + "X-"
154
                if oosStatus.rto_orders is not None:
155
                    rtoCount = oosStatus.rto_orders
156
                lastXdaysSale = lastXdaysSale[:-1]
157
                if numDaysInStock>0:
158
                    avgSales = float(salesCount)/numDaysInStock
159
                advancedPOParameters[itemStockPurchaseParam.item_id] = [round(avgSales * itemStockPurchaseParam.numOfDaysStock), round(avgSales,2) , numDaysInStock, itemStockPurchaseParam.minStockLevel, itemStockPurchaseParam.numOfDaysStock, lastXdaysSale, rtoCount]
160
                if itemInventorySnapshot.has_key(itemStockPurchaseParam.item_id):
161
                    itemAvailability = itemInventorySnapshot.get(itemStockPurchaseParam.item_id)
162
                    currentAvailability = 0
163
                    currentReserved = 0
164
                    for wId, rQty in itemAvailability.reserved.iteritems():
165
                        if wId in ourGoodWarehouseIds:
166
                            currentReserved = currentReserved + rQty
167
                    #Key Condition Added By Manish Sharma        
168
                    if availability.has_key(itemStockPurchaseParam.item_id):
169
                        if availability[itemStockPurchaseParam.item_id] is None:
170
                                availability[itemStockPurchaseParam.item_id] = [0]
171
                    else:
172
                        availability[itemStockPurchaseParam.item_id] = [0]
173
                    if (availability[itemStockPurchaseParam.item_id][0] - currentReserved) < max(advancedPOParameters[itemStockPurchaseParam.item_id][0], advancedPOParameters[itemStockPurchaseParam.item_id][3]):
174
                        SKUListForPO.append(itemStockPurchaseParam.item_id)
175
                else:
176
                    SKUListForPO.append(itemStockPurchaseParam.item_id)
177
 
178
            for key in requirements:
179
                if advancedPOParameters.has_key(key):
180
                    continue
181
                print "Item Id ---", key
182
                inventory_client = InventoryClient().get_client()
183
                oosStatuses = inventory_client.getOosStatusesForXDaysForItem(key, 0, 3)
184
                salesCount = 0
185
                numDaysInStock = 0
186
                rtoCount = 0
187
                avgSales = 0.0
188
                lastXdaysSale = ""
189
                for oosStatus in oosStatuses:
190
                    if oosStatus.is_oos == False:
191
                        salesCount = salesCount + oosStatus.num_orders
192
                        numDaysInStock = numDaysInStock + 1
193
                        lastXdaysSale = lastXdaysSale + str(oosStatus.num_orders) + "-" 
194
                    else:
195
                        lastXdaysSale = lastXdaysSale + "X-"
196
                lastXdaysSale = lastXdaysSale[:-1]
197
                if oosStatus.rto_orders:
198
                    rtoCount = oosStatus.rto_orders
199
                if numDaysInStock>0:
200
                    avgSales = float(salesCount)/float(numDaysInStock)
201
                itemStockPurchaseParam = ItemStockPurchaseParams()
202
                try:
203
                    itemStockPurchaseParam = inventory_client.getItemStockPurchaseParams(key)
204
                except Exception as e:
205
                    inventory_client.updateItemStockPurchaseParams(key, 0, 0)
206
                    itemStockPurchaseParam = inventory_client.getItemStockPurchaseParams(key)
207
                advancedPOParameters[key] = [round(avgSales * itemStockPurchaseParam.numOfDaysStock), round(avgSales,2), numDaysInStock, itemStockPurchaseParam.minStockLevel, itemStockPurchaseParam.numOfDaysStock, lastXdaysSale, rtoCount]
208
 
209
            cumulativeRequirementsItemIds = list(set(requirements.keys()+SKUListForPO))
210
            netRequirements = {}
211
            for itemId in cumulativeRequirementsItemIds:
212
                print "Item Id for Preferred Vendor", itemId
213
                requirementsCount = requirements.get(itemId)
214
                if requirementsCount is None:
215
                    requirementsCount = 0.0
216
                if  availability.has_key(itemId):
217
                    availabilityCount = availability.get(itemId)[0]
218
                    item = self.__get_item_from_master(itemId)
219
                    if requirementsCount > availabilityCount or itemId in SKUListForPO:
220
                        if item.preferredVendor is None:
221
                            raise PurchaseServiceException(101, 'Preferred Vendor missing for ' + " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)]))
222
                        if (netRequirements.has_key(item.preferredVendor)):
223
                            netRequirements[item.preferredVendor].append([item, requirementsCount - availabilityCount])
224
                        else:
225
                            netRequirements[item.preferredVendor] = [[item, requirementsCount - availabilityCount]];
226
                else:
227
                    item = self.__get_item_from_master(itemId)
228
                    if item.preferredVendor is None:
229
                        raise PurchaseServiceException(101, 'Preferred Vendor missing for ' + " ".join([str(item.brand), str(item.modelName), str(item.modelNumber), str(item.color)]))
230
                    if (netRequirements.has_key(item.preferredVendor)):
231
                        netRequirements[item.preferredVendor].append([item, requirementsCount])
232
                    else:
233
                        netRequirements[item.preferredVendor] = [[item, requirementsCount]];
234
 
235
            if not netRequirements:
236
                return purchaseOrders
237
 
238
 
239
            suppliersMap = {}
240
            for supplier in self.getSuppliers():
241
                suppliersMap[supplier.id] = supplier
242
 
243
 
244
            for vendorId in netRequirements.keys():
245
                t_purchase_order = {}
246
                supplier = suppliersMap.get(vendorId)
247
                t_purchase_order['SupplierName'] = supplier.name
248
                t_purchase_order['lineitems']= []
249
                for key in netRequirements.get(vendorId):
250
                    item = key[0]
251
                    quantity = key[1]
252
 
253
                    t_po_lineitem = {}
254
                    t_po_lineitem['productGroup'] = item.productGroup
255
                    t_po_lineitem['brand'] = item.brand
256
                    t_po_lineitem['modelNumber'] = item.modelNumber
257
                    t_po_lineitem['modelName'] = item.modelName
258
                    t_po_lineitem['color'] = item.color
259
                    t_po_lineitem['itemId'] = item.id
260
                    t_po_lineitem['packQuantity'] = item.packQuantity
261
                    if quantity <0: #TODO Check this logic
262
                        quantity=0
263
                    t_po_lineitem['quantity'] = quantity
264
                    t_po_lineitem['availableQuantity'] = 0
265
                    if availability.has_key(item.id):
266
                        if previouslyOrderedQty.has_key(item.id):
267
                            t_po_lineitem['availableQuantity'] = availability[item.id][0] - previouslyOrderedQty[item.id]
268
                        else:
269
                            t_po_lineitem['availableQuantity'] = availability[item.id][0]
270
                    if requirements.has_key(item.id):
271
                        t_po_lineitem['reservedQuantity'] = requirements[item.id]
272
                    additionalQty = max(advancedPOParameters[item.id][0], advancedPOParameters[item.id][3])
273
                    additionalQty = max(0,(additionalQty - (advancedPOParameters[item.id][6]/2)))
274
                    suggestedQuantity = additionalQty +key[1]
275
                    t_po_lineitem['suggestedQuantity'] = max(0,suggestedQuantity)
276
                    #t_po_lineitem.suggestedQuantity = max(advancedPOParameters[item.id][0], advancedPOParameters[item.id][3]) + key[1]
277
                    t_po_lineitem['avgSales'] = advancedPOParameters[item.id][1]
278
                    t_po_lineitem['numberOfDaysInStock'] = advancedPOParameters[item.id][2] 
279
                    t_po_lineitem['minStockLevel'] = advancedPOParameters[item.id][3]
280
                    t_po_lineitem['numberOfDaysStock'] = advancedPOParameters[item.id][4]
281
                    t_po_lineitem['lastXdaysSale'] = advancedPOParameters[item.id][5]
282
                    t_po_lineitem['rtoOrders'] = advancedPOParameters[item.id][6]
283
                    if previouslyOrderedQty.has_key(item.id):
284
                        t_po_lineitem['previouslyOrderedQty'] = previouslyOrderedQty[item.id]
285
                    else:
286
                        t_po_lineitem['previouslyOrderedQty'] = 0
287
                    if codRequirements.has_key(item.id):
288
                        t_po_lineitem['codCount'] = min(codRequirements[item.id], quantity)
289
                    try:
290
                        item_pricing = inventory_client.getItemPricing(item.id, vendorId)
291
                    except Exception as e:
292
                        vendor = self.getSupplier(vendorId)
293
                        print 'Could not find transfer price for Item id: ' + str(item.id) + ' and vendor id: ' + str(vendorId)
294
                        print e
295
                        raise PurchaseServiceException(101, 'Transfer price missing for ' + vendor.name + ' and ' + " ".join([item.brand, item.modelName, item.modelNumber, item.color]))
296
                    t_po_lineitem['unitPrice'] = item_pricing.transferPrice
297
                    t_po_lineitem['nlc'] = item_pricing.nlc
298
                    t_po_lineitem['mrp'] = item.mrp
299
                    t_purchase_order['lineitems'].append(t_po_lineitem)
300
                purchaseOrders.append(t_purchase_order)
301
            return purchaseOrders
302
        except Exception as e:
303
            print e
304
            print sys.exc_info()[0]
305
        finally:
306
            self.close_session()
307
 
308
    def close_session(self):
309
        if session.is_active:
310
            print "session is active. closing it."
311
            session.close()
312
 
313
    def __get_item_from_master(self, item_id):
314
        client = CatalogClient("catalog_service_server_host_master", "catalog_service_server_port").get_client()
315
        return client.getItem(item_id)
316
 
317
def inc():
318
    global i
319
    i+=1
320
    return i
321
 
322
def sendmail(email, message, title, *varargs):
323
    if email == "":
324
        return
325
    mailServer = smtplib.SMTP(SMTP_SERVER, SMTP_PORT)
326
    mailServer.ehlo()
327
    mailServer.starttls()
328
    mailServer.ehlo()
329
 
330
    # Create the container (outer) email message.
331
    msg = MIMEMultipart()
332
    msg['Subject'] = title
333
    msg.preamble = title
334
    html_msg = MIMEText(message, 'html')
335
    msg.attach(html_msg)
336
 
337
    #snapdeal more to be added here
338
    for fileName in varargs:
339
        snapdeal = MIMEBase('application', 'vnd.ms-excel')
340
        snapdeal.set_payload(file(fileName).read())
341
        encoders.encode_base64(snapdeal)
342
        snapdeal.add_header('Content-Disposition', 'attachment;filename=' + fileName)
343
        msg.attach(snapdeal)
344
 
345
 
346
    MAILTO = email 
347
    mailServer.login(SENDER, PASSWORD)
348
    mailServer.sendmail(SENDER, MAILTO, msg.as_string())
349
 
350
def main():
351
    global i
352
    i = -1
353
    row = 0
354
    wb = xlwt.Workbook()
355
    worksheet = wb.add_sheet("All Pending Purchase Orders")
356
    worksheet.write(row, inc(), 'Supplier Name', boldStyle)
357
    worksheet.write(row, inc(), 'Item Id', boldStyle)
358
    worksheet.write(row, inc(), 'Product Name', boldStyle)
359
    worksheet.write(row, inc(), 'Quantity', boldStyle)
360
    worksheet.write(row, inc(), 'COD', boldStyle)
361
    worksheet.write(row, inc(), 'Prepaid', boldStyle)
362
    worksheet.write(row, inc(), 'Transfer price', boldStyle)
363
    worksheet.write(row, inc(), 'Nlc', boldStyle)
364
    worksheet.write(row, inc(), 'Total amount', boldStyle)
18016 manish.sha 365
    worksheet.write(row, inc(), 'Pack Quantity', boldStyle)
18010 manish.sha 366
    worksheet.write(row, inc(), 'NetPendingOrderQty', boldStyle)
367
    worksheet.write(row, inc(), 'PreviouslyOrderedQty', boldStyle)
368
    worksheet.write(row, inc(), 'AverageSale', boldStyle)
369
    worksheet.write(row, inc(), 'Pending RTOs', boldStyle)
370
    worksheet.write(row, inc(), 'NumDaysStock', boldStyle)
371
    worksheet.write(row, inc(), 'MinStockReq', boldStyle)
372
    worksheet.write(row, inc(), 'Additional Qty', boldStyle)
373
 
374
 
375
    purchaseHandler = PurchaseHandler()
376
    pendingPurchaseOrders = purchaseHandler.getPendingPurchaseOrders(7)
377
    print pendingPurchaseOrders
378
    for purchaseOrder in pendingPurchaseOrders:
379
        for lineitem in purchaseOrder.get('lineitems'):
380
            row += 1
381
            i=-1
382
            worksheet.write(row, inc(), purchaseOrder.get('SupplierName'))
383
            worksheet.write(row, inc(), lineitem.get('itemId'))
384
            worksheet.write(row, inc(), lineitem.get('brand')+" "+lineitem.get('modelName')+" "+lineitem.get('modelNumber')+" "+lineitem.get('color'))
385
            worksheet.write(row, inc(), lineitem.get('suggestedQuantity'))
386
            codCount =0;
387
            if lineitem.get('codCount') is not None:
388
                codCount = lineitem.get('codCount')
389
            worksheet.write(row, inc(), codCount)
390
            worksheet.write(row, inc(), long(lineitem.get('quantity'))-long(codCount))
391
            worksheet.write(row, inc(), lineitem.get('unitPrice'))
392
            worksheet.write(row, inc(), lineitem.get('nlc'))
393
            worksheet.write(row, inc(), float(lineitem.get('suggestedQuantity')) * float(lineitem.get('unitPrice')))
18016 manish.sha 394
            worksheet.write(row, inc(), lineitem.get('packQuantity'))
18010 manish.sha 395
            reservedCount = 0
396
            if lineitem.get('reservedQuantity') is not None:
397
                reservedCount = lineitem.get('reservedQuantity')
18423 manish.sha 398
            worksheet.write(row, inc(), long(reservedCount))-long(lineitem.get('availableQuantity'))
18010 manish.sha 399
            worksheet.write(row, inc(), lineitem.get('previouslyOrderedQty'))
400
            worksheet.write(row, inc(), "("+lineitem.get('lastXdaysSale')+")"+str(lineitem.get('avgSales')))
401
            worksheet.write(row, inc(), lineitem.get('rtoOrders'))
402
            worksheet.write(row, inc(), lineitem.get('numberOfDaysStock'))
403
            worksheet.write(row, inc(), lineitem.get('minStockLevel'))
404
 
405
            stockThroughAvgSales = float(lineitem.get('avgSales')) * float(lineitem.get('numberOfDaysStock'))
406
            additionalQty = 0
407
            if stockThroughAvgSales > float(lineitem.get('minStockLevel')):
408
                additionalQty = stockThroughAvgSales
409
            else:
410
                additionalQty = float(lineitem.get('minStockLevel'))
411
 
412
            if float(lineitem.get('rtoOrders')) >1:
413
                additionalQty = additionalQty - (float(lineitem.get('rtoOrders'))/2)
414
 
415
            if additionalQty<0:
416
                additionalQty = 0
417
            worksheet.write(row, inc(), additionalQty)
418
    wb.save(XLS_O_FILENAME)
419
 
420
    sendmail(["amit.gupta@shop2020.in", "rajneesh.arora@saholic.com", "chaitnaya.vats@saholic.com", "manoj.kumar@saholic.com", "manish.sharma@shop2020.in"], "", "All Pending Purchase Orders", XLS_O_FILENAME)
421
    #sendmail(["manish.sharma@shop2020.in"], "", "All Pending Purchase Orders", XLS_O_FILENAME)
422
 
423
if __name__ == '__main__':
424
    main()