Subversion Repositories SmartDukaan

Rev

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