Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
4503 mandeep.dh 1
'''
2
Created on 29-Jul-2011
3
 
4
@author: Chandranshu
5
'''
6
from elixir import metadata, setup_all, session
4754 mandeep.dh 7
from shop2020.clients.CatalogClient import CatalogClient
8
from shop2020.clients.TransactionClient import TransactionClient
4503 mandeep.dh 9
from shop2020.purchase.main.model.LineItem import LineItem
10
from shop2020.purchase.main.model.Purchase import Purchase
11
from shop2020.purchase.main.model.PurchaseOrder import PurchaseOrder
5110 mandeep.dh 12
from shop2020.purchase.main.model.RevisionedPurchaseOrder import \
13
    RevisionedPurchaseOrder
4503 mandeep.dh 14
from shop2020.purchase.main.model.Supplier import Supplier
5110 mandeep.dh 15
from shop2020.thriftpy.model.v1.catalog.ttypes import WarehouseType, \
16
    InventoryType
4754 mandeep.dh 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
4503 mandeep.dh 20
from sqlalchemy import create_engine
21
import datetime
22
import logging
4754 mandeep.dh 23
import sys
4503 mandeep.dh 24
 
25
 
26
logging.basicConfig(level=logging.DEBUG)
27
 
28
class PurchaseServiceHandler:
29
    '''
30
    classdocs
31
    '''
32
 
33
    def __init__(self, dbname='warehouse', db_hostname='localhost',  echoOn=True):
34
        '''
35
        Constructor
36
        '''
37
        engine = create_engine('mysql://root:shop2020@' + db_hostname + '/' + dbname, pool_recycle=7200)
38
        metadata.bind = engine
39
        metadata.bind.echo = echoOn
40
        setup_all(True)
41
 
42
    def createPurchaseOrder(self, tPurchaseOrder):
43
        """
44
        Creates a purchase order based on the data in the given purchase order object.
45
        This method populates a number of missing fields
46
 
47
        Parameters:
48
         - purchaseOrder
49
        """
50
        try:
51
            purchaseOrder = PurchaseOrder(tPurchaseOrder)
52
            session.commit()
53
            purchaseOrder.set_po_number()
54
            session.commit()
55
            return purchaseOrder.id
56
        finally:
57
            self.close_session()
58
 
59
    def getAllPurchaseOrders(self, status):
60
        """
61
        Returns a list of all the purchase orders in the given state
62
 
63
        Parameters:
64
         - status
65
        """
66
        try:
67
            pos = PurchaseOrder.query.filter_by(status=status).all()
68
            return [po.to_thrift_object() for po in pos ]
69
        finally:
70
            self.close_session()
71
 
72
    def getPurchaseOrder(self, id):
73
        """
74
        Returns the purchase order with the given id. Throws an exception if there is no such purchase order.
75
 
76
        Parameters:
77
         - id
78
        """
79
        try:
80
            purchaseOrder = PurchaseOrder.get_by(id=id)
81
            if not purchaseOrder:
82
                raise PurchaseServiceException(101, "No purchase order can be found with id:" + str(id)) 
83
            return purchaseOrder.to_thrift_object()
84
        finally:
85
            self.close_session()
86
 
87
    def getSupplier(self, id):
88
        """
89
        Returns the supplier with the given order id. Throws an exception if there is no such supplier.
90
 
91
        Parameters:
92
         - id
93
        """
94
        try:
95
            return Supplier.get_by(id=id).to_thrift_object()
96
        finally:
97
            self.close_session()
98
 
99
    def startPurchase(self, purchaseOrderId, invoiceNumber, freightCharges):
100
        """
101
        Creates a purchase for the given purchase order.
102
        Throws an exception if no more purchases are allowed against the given purchase order.
103
 
104
        Parameters:
105
         - purchaseOrderId
106
         - invoiceNumber
107
         - freightCharges
108
        """
109
        try:
110
            purchase_order = PurchaseOrder.get_by(id = purchaseOrderId)
111
            purchase = Purchase(purchase_order, invoiceNumber, freightCharges)
112
            session.commit()
113
            return purchase.id
114
        finally:
115
            self.close_session()
116
 
117
    def closePurchase(self, purchaseId):
118
        """
119
        Marks a purchase as complete and updates the receivedOn time.
120
        Throws an exception if no such purchase exists.
121
 
122
        Parameters:
123
         - purchaseId
124
        """
125
        try:
126
            purchase = Purchase.get_by(id=purchaseId)
127
            purchase.receivedOn = datetime.datetime.now()
128
            session.commit()
129
        finally:
130
            self.close_session()
131
 
132
    def getAllPurchases(self, purchaseOrderId, open):
133
        """
134
        Returns all open or closed purchases for the given purchase order. Throws an exception if no such purchase order exists
135
 
136
        Parameters:
137
         - purchaseOrderId
138
         - open
139
        """
140
        try:
141
            if open:
142
                purchases = Purchase.query.filter_by(purchaseOrder_id = purchaseOrderId, receivedOn = None).all()
143
            else:
5110 mandeep.dh 144
                purchases = Purchase.query.filter_by(purchaseOrder_id = purchaseOrderId).filter(Purchase.receivedOn != None).all()
4503 mandeep.dh 145
 
146
            return [purchase.to_thrift_object() for purchase in purchases]
147
        finally:
148
            self.close_session()
149
 
4555 mandeep.dh 150
    def getPurchaseOrderForPurchase(self, purchaseId):
4503 mandeep.dh 151
        """
4555 mandeep.dh 152
        Returns the purchase order for a given purchase
4503 mandeep.dh 153
 
154
        Parameters:
155
         - purchaseId
156
        """
4555 mandeep.dh 157
        try:
158
            return self.getPurchaseOrder(Purchase.query.filter_by(id = purchaseId).one().purchaseOrder_id)
159
        finally:
160
            self.close_session()
4503 mandeep.dh 161
 
4754 mandeep.dh 162
    def getPendingPurchaseOrders(self, warehouseId):
163
        """
164
        Creates purchase order objects from pending orders
165
 
166
        Parameters:
167
         - warehouseId
168
        """
169
        try:
170
            purchaseOrders = []
171
            if not warehouseId:
172
                raise PurchaseServiceException(101, "bad warehouse id")
173
 
174
            transactionClient = TransactionClient().get_client()
175
            pending_orders = transactionClient.getOrdersInBatch([OrderStatus.SUBMITTED_FOR_PROCESSING, OrderStatus.INVENTORY_LOW, OrderStatus.ACCEPTED], 0, 0, warehouseId)
176
 
177
            if not pending_orders:
178
                return purchaseOrders
179
 
180
            catalog_client = CatalogClient().get_client()
181
            availability = {}
5110 mandeep.dh 182
 
183
            warehouses = catalog_client.getWarehouses(WarehouseType.OURS, InventoryType.GOOD, 0, None, warehouseId)
184
            for warehouse in warehouses:
185
                goodWarehouseId = warehouse.id
186
                for item in catalog_client.getAllItemsForWarehouse(goodWarehouseId):
187
                    if availability.has_key(item.id):
188
                        availability[item.id] = [availability[item.id][0] + item.itemInventory.availability[goodWarehouseId], item]
189
                    else:
190
                        availability[item.id] = [item.itemInventory.availability[goodWarehouseId], item]
4754 mandeep.dh 191
 
192
            codRequirements = {}
193
            requirements = {}
194
            for order in pending_orders:
4758 mandeep.dh 195
                if order.purchaseOrderId:
4757 mandeep.dh 196
                    continue
4754 mandeep.dh 197
                for lineitem in order.lineitems:
198
                    if (requirements.has_key(lineitem.item_id)):
199
                        requirements[lineitem.item_id] += lineitem.quantity
200
                    else:
201
                        requirements[lineitem.item_id] = lineitem.quantity
202
 
203
                    if order.cod:
204
                        if (codRequirements.has_key(lineitem.item_id)):
205
                            codRequirements[lineitem.item_id] += lineitem.quantity
206
                        else:
207
                            codRequirements[lineitem.item_id] = lineitem.quantity
208
 
209
            netRequirements = {}
210
            for itemId in requirements.keys():
211
                requirementsCount = requirements.get(itemId)
212
                if  availability.has_key(itemId):
213
                    availabilityCount = availability.get(itemId)[0]
214
                    item              = availability.get(itemId)[1]
215
                    if item.preferredVendor is None or item.preferredVendor == 1:
216
                        continue
217
                    if requirementsCount > availabilityCount:
218
                        if (netRequirements.has_key(item.preferredVendor)):
219
                            netRequirements[item.preferredVendor].append([item, requirementsCount - availabilityCount])
220
                        else:
221
                            netRequirements[item.preferredVendor] = [[item, requirementsCount - availabilityCount]];
222
                else:
223
                    item = catalog_client.getItem(itemId);
224
                    if item.preferredVendor is None:
225
                        raise PurchaseServiceException(101, 'Preferred Vendor missing for ' + " ".join([item.brand, item.modelName, item.modelNumber, item.color]))
226
                    if item.preferredVendor == 1:
227
                        raise PurchaseServiceException(101, 'Preferred Vendor set to HotSpot for ' + " ".join([item.brand, item.modelName, item.modelNumber, item.color]))
228
                    if (netRequirements.has_key(item.preferredVendor)):
229
                        netRequirements[item.preferredVendor].append([item, requirementsCount])
230
                    else:
231
                        netRequirements[item.preferredVendor] = [[item, requirementsCount]];
232
 
233
            if not netRequirements:
234
                return purchaseOrders
235
 
236
            for vendorId in netRequirements.keys():
237
                t_purchase_order = TPurchaseOrder()
238
                t_purchase_order.supplierId = vendorId
239
                t_purchase_order.warehouseId = warehouseId
240
                t_purchase_order.lineitems = []
241
                for key in netRequirements.get(vendorId):
242
                    item     = key[0]
243
                    quantity = key[1]
244
                    t_po_lineitem = TLineItem()
245
                    t_po_lineitem.productGroup = item.productGroup
246
                    t_po_lineitem.brand = item.brand
247
                    t_po_lineitem.modelNumber = item.modelNumber
248
                    t_po_lineitem.modelName = item.modelName
249
                    t_po_lineitem.color = item.color
250
                    t_po_lineitem.itemId = item.id
251
                    t_po_lineitem.quantity = quantity
252
                    if codRequirements.has_key(item.id):
253
                        t_po_lineitem.codCount = min(codRequirements[item.id], quantity)
254
                    try:
255
                        item_pricing = catalog_client.getItemPricing(item.id, vendorId)
256
                    except Exception as e:
257
                        vendor = self.getSupplier(vendorId)
258
                        print 'Could not find transfer price for Item id: ' + str(item.id) + ' and vendor id: ' + str(vendorId)
259
                        print e
260
                        raise PurchaseServiceException(101, 'Transfer price missing for ' + vendor.name + ' and ' + " ".join([item.brand, item.modelName, item.modelNumber, item.color]))
261
                    t_po_lineitem.unitPrice = item_pricing.transferPrice
262
                    t_purchase_order.lineitems.append(t_po_lineitem)
263
                purchaseOrders.append(t_purchase_order)
264
            return purchaseOrders
265
        finally:
266
            self.close_session()
267
 
268
    def getSuppliers(self, ):
269
        """
270
        Returns all the valid suppliers
271
        """
272
        try:
273
            return [Supplier.to_thrift_object(supplier) for supplier in Supplier.query.all()]
274
        finally:
275
            self.close_session()
276
 
277
    def fulfillPO(self, purchaseOrderId, itemId, quantity):
278
        """
279
        Fulfills a given purchase order with an item.
280
 
281
        Parameters:
282
         - purchaseOrderId
283
         - itemId
284
         - quantity
285
        """
286
        try:
287
            lineitems = LineItem.query.filter_by(purchaseOrder_id = purchaseOrderId, itemId = itemId).all()
288
            if lineitems:
289
                if lineitems[0].unfulfilledQuantity < quantity:
290
                    raise PurchaseServiceException(101, 'Can fulfill only ' + str(lineitems[0].unfulfilledQuantity) + 'quantity')
291
                else:
292
                    lineitems[0].unfulfilledQuantity -= quantity
293
                    if not lineitems[0].unfulfilledQuantity:
294
                        lineitems[0].fulfilled = 1
295
                        if not LineItem.query.filter_by(purchaseOrder_id = purchaseOrderId, fulfilled = 0).all():
296
                            purchaseOrder = self.getPurchaseOrder(purchaseOrderId)
297
                            purchaseOrder.status = POStatus.CLOSED
298
                    session.commit()
299
                    return
300
 
301
            raise PurchaseServiceException(101, 'No lineitem found with this itemId: ' + str(itemId) + ' in PO Id: ' + str(purchaseOrderId) )
302
        finally:
303
            self.close_session()
304
 
305
    def updatePurchaseOrder(self, purchaseOrder):
306
        """
307
        Amends a PO sa per the new lineitems passed
308
 
309
        Parameters:
310
         - purchaseOrder
311
        """
312
        try:
313
            existingPurchaseOrder = PurchaseOrder.get_by(id = purchaseOrder.id)
314
            maxRevision = 0
315
            existingRevisions = RevisionedPurchaseOrder.query.filter_by(purchaseOrderId = purchaseOrder.id).all()
316
            if existingRevisions:
317
                maxRevision = max([a.revision for a in existingRevisions]) + 1
5147 mandeep.dh 318
 
319
            newPOItems = {}
320
            for t_lineitem in purchaseOrder.lineitems:
321
                newPOItems[t_lineitem.itemId] = t_lineitem
322
 
4754 mandeep.dh 323
            for lineitem in existingPurchaseOrder.lineitems:
5147 mandeep.dh 324
                fulfilledQuantity = lineitem.quantity - lineitem.unfulfilledQuantity
325
                if fulfilledQuantity:
326
                    if not newPOItems.has_key(lineitem.itemId):
327
                        raise PurchaseServiceException(101, 'Cannot remove fulfilled item id: ' + str(lineitem.itemId) + ' from PO')
328
                    else:
329
                        if newPOItems[lineitem.itemId].quantity < fulfilledQuantity:
330
                            raise PurchaseServiceException(101, 'More quantity already fulfilled for item id: ' + str(lineitem.itemId))
331
                        else:
332
                            newPOItems[lineitem.itemId].unfulfilledQuantity -= fulfilledQuantity
4754 mandeep.dh 333
                revisionedPurchaseOrder = RevisionedPurchaseOrder()
334
                revisionedPurchaseOrder.purchaseOrderId = purchaseOrder.id
335
                revisionedPurchaseOrder.revision = maxRevision
336
                revisionedPurchaseOrder.itemId = lineitem.itemId
337
                revisionedPurchaseOrder.unfulfilledQuantity = lineitem.unfulfilledQuantity
338
                revisionedPurchaseOrder.unitPrice = lineitem.unitPrice
339
                revisionedPurchaseOrder.createdAt = lineitem.createdAt
340
                revisionedPurchaseOrder.quantity = lineitem.quantity
341
                lineitem.delete()
342
            existingPurchaseOrder.lineitems = [LineItem(existingPurchaseOrder, t_lineitem) for t_lineitem in purchaseOrder.lineitems]
343
            existingPurchaseOrder.totalCost = sum([t_lineitem.quantity * t_lineitem.unitPrice for t_lineitem in purchaseOrder.lineitems])
344
            session.commit()
345
        finally:
346
            self.close_session()
347
 
4503 mandeep.dh 348
    def close_session(self):
349
        if session.is_active:
350
            print "session is active. closing it."
351
            session.close()
352
 
353
    def isAlive(self, ):
354
        """
355
        For checking weather service is active alive or not. It also checks connectivity with database
356
        """
357
        try:
358
            session.query(Supplier.id).limit(1).all()
359
            return True
360
        except:
361
            return False
362
        finally:
363
            self.close_session()
364