Subversion Repositories SmartDukaan

Rev

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