Subversion Repositories SmartDukaan

Rev

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

Rev Author Line No. Line
13774 amit.gupta 1
# coding=utf-8
13569 amit.gupta 2
'''
3
Created on Jan 15, 2015
4
 
5
@author: amit
6
'''
13774 amit.gupta 7
from base64 import encode
8
from bs4 import BeautifulSoup
14162 amit.gupta 9
from datetime import datetime
13774 amit.gupta 10
from dtr.dao import Order, SubOrder
13995 amit.gupta 11
from dtr.main import getStore, Store as MStore, ParseException
13774 amit.gupta 12
from dtr.sources.flipkart import todict
14162 amit.gupta 13
from paramiko import sftp
14
from paramiko.client import SSHClient
15
from paramiko.sftp_client import SFTPClient
14285 amit.gupta 16
import os.path
14162 amit.gupta 17
import paramiko
13774 amit.gupta 18
import re
14033 amit.gupta 19
import time
13809 amit.gupta 20
import traceback
13774 amit.gupta 21
 
22
ORDER_REDIRECT_URL = 'https://www.amazon.in/gp/css/summary/edit.html?orderID=%s'
13810 amit.gupta 23
ORDER_SUCCESS_URL = 'https://www.amazon.in/gp/buy/spc/handlers/static-submit-decoupled.html'
13823 amit.gupta 24
THANKYOU_URL = 'https://www.amazon.in/gp/buy/thankyou/handlers/display.html'
13774 amit.gupta 25
class Store(MStore):
13821 amit.gupta 26
 
14032 amit.gupta 27
    orderStatusRegexMap = { MStore.ORDER_PLACED : ['ordered from', 'not yet dispatched','dispatching now', 'preparing for dispatch'],
14064 amit.gupta 28
                            MStore.ORDER_SHIPPED : ['dispatched on','dispatched', 'on the way', 'out for delivery', 'Out for delivery'],
14032 amit.gupta 29
                            MStore.ORDER_CANCELLED : ['return complete', 'refunded', 'cancelled'],
30
                            MStore.ORDER_DELIVERED : ['delivered']
13821 amit.gupta 31
                           }
13774 amit.gupta 32
 
33
    def __init__(self,store_id):
34
        super(Store, self).__init__(store_id)
35
 
36
    def getName(self):
37
        return "flipkart"
38
 
14202 amit.gupta 39
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl, insert=False):
13796 amit.gupta 40
        resp = {}
13821 amit.gupta 41
        if ORDER_SUCCESS_URL in orderSuccessUrl or THANKYOU_URL in orderSuccessUrl:
13774 amit.gupta 42
            try:
43
                soup = BeautifulSoup(rawHtml)
44
                orderUrl = soup.find('div', {"id":"thank-you-box-wrapper"}).div.findAll('div', recursive=False)[1].a['href']
14202 amit.gupta 45
                merchantOrderId = re.findall(r'.*&oid=(.*)&?.*?', orderUrl)[0]
14211 amit.gupta 46
                order = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl, False)
47
                order.orderSuccessUrl = ORDER_REDIRECT_URL % (merchantOrderId)
48
                order.merchantOrderId = merchantOrderId
14291 amit.gupta 49
                order.requireDetail = True
14297 amit.gupta 50
                order.closed = None
14312 amit.gupta 51
                if self._saveToOrder(todict(order)):
52
                    resp['result'] = 'ORDER_CREATED'
53
                    resp["url"] = ORDER_REDIRECT_URL % (merchantOrderId)
54
                    resp["htmlRequired"] = True
55
                    resp['orderId'] = orderId
56
                else:
57
                    resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
58
 
13796 amit.gupta 59
                return resp
13774 amit.gupta 60
            except:
14312 amit.gupta 61
                resp["result"] = 'ORDER_NOT_CREATED'
13796 amit.gupta 62
                return resp
13774 amit.gupta 63
 
64
        else:
13781 amit.gupta 65
            try:
66
                merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
14145 amit.gupta 67
                merchantOrder.orderTrackingUrl = orderSuccessUrl
13781 amit.gupta 68
                soup = BeautifulSoup(rawHtml,from_encoding="utf-8")
13774 amit.gupta 69
 
13781 amit.gupta 70
                table = soup.body.findAll("table", recursive=False)[1]
71
                #print table
72
                tables = table.tr.td.findAll("table", recursive=False)
73
                for tr in tables[2].findAll("tr"):
74
                    boldElement = tr.td.b
75
                    if "Order Placed" in str(boldElement):
76
                        merchantOrder.placedOn = boldElement.next_sibling.strip()
77
                    if "order number" in str(boldElement):
14023 amit.gupta 78
                        merchantOrder.merchantOrderId = boldElement.next_sibling.strip()
13781 amit.gupta 79
                    if "Order Total" in str(boldElement):
13809 amit.gupta 80
                        merchantOrder.paidAmount = int(float(boldElement.find('span').contents[-1].replace(',','')))
13781 amit.gupta 81
                anchors = table.tr.td.findAll("a", recursive=False)
14293 amit.gupta 82
                paymentAnchor = anchors.pop(-1)
13774 amit.gupta 83
 
13809 amit.gupta 84
                count = 0
13781 amit.gupta 85
                subOrders = []
86
                merchantOrder.subOrders = subOrders
87
                for anchor in anchors:
13809 amit.gupta 88
                    count += 1
13781 amit.gupta 89
                    tab = anchor.next_sibling
90
                    status = MStore.ORDER_PLACED
91
                    subStr = "Delivery #" + str(count) + ":"
92
                    if subStr in  tab.find("b").text:
93
                        detailedStatus = tab.find("b").text.replace(subStr, '').strip()
94
 
95
                    tab = tab.next_sibling.next_sibling
13813 amit.gupta 96
                    trs = tab.find("table").find('tbody').findAll("tr", recursive = False)
13781 amit.gupta 97
 
98
                    estimatedDelivery = trs[0].td.find("b").next_sibling.strip()
99
 
13813 amit.gupta 100
                    orderItemTrs = trs[1].findAll("td", recursive=False)[1].table.tbody.findAll("tr", recursive = False)
13781 amit.gupta 101
                    i = -1
102
                    for orderItemTr in orderItemTrs:
103
                        i += 1
104
                        if i%2 == 0:
105
                            continue
13809 amit.gupta 106
                        quantity =  int(re.findall(r'\d+', orderItemTr.td.contents[0])[0])
13781 amit.gupta 107
 
13809 amit.gupta 108
                        productUrl = orderItemTr.td.contents[1].a["href"]
109
                        productTitle = orderItemTr.td.contents[1].a.text
110
 
111
                        unitPrice = int(float(orderItemTr.findAll('td')[1].span.text.replace('Rs. ','').replace(',','')))
112
 
13781 amit.gupta 113
 
13809 amit.gupta 114
                        subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, unitPrice*quantity, status, quantity)
115
                        subOrder.merchantSubOrderId = orderItemTr.find("input")["name"]
116
                        subOrder.estimatedDeliveryDate = estimatedDelivery
117
                        subOrder.productCode = productUrl.split('/')[5]
118
                        subOrder.detailedStatus = detailedStatus
119
                        (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, unitPrice*quantity)
120
                        cashbackStatus = Store.CB_PENDING
121
                        if cashbackAmount <= 0:
122
                            cashbackStatus = Store.CB_NA
123
                        subOrder.cashBackStatus = cashbackStatus
124
                        subOrder.cashBackAmount = cashbackAmount
125
                        if percentage > 0:
126
                            subOrder.cashBackPercentage = percentage
127
                        subOrders.append(subOrder)
14293 amit.gupta 128
                priceList = paymentAnchor.next_sibling.next_sibling.next_sibling.table.table.tbody.tbody.tbody.findAll('tr', recursive=False)
129
                totalAmount = 0
130
                grandAmount = 0
131
                for price in priceList:
132
                    labelTd = price.td
133
                    if 'Subtotal:' in labelTd.text:
14314 amit.gupta 134
                        totalAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
14293 amit.gupta 135
                    elif 'Grand Total:' in labelTd.text:
14314 amit.gupta 136
                        grandAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
14293 amit.gupta 137
                if grandAmount < totalAmount:
138
                    diff = totalAmount - grandAmount
139
                    for subOrder in merchantOrder.subOrders:
14294 amit.gupta 140
                        subOrder.amountPaid -= int(diff*(1-subOrder.amountPaid/totalAmount))
14319 amit.gupta 141
                self._updateToOrder(todict(merchantOrder))
142
                resp['result'] = 'ORDER_CREATED'
143
                return resp    
13781 amit.gupta 144
            except:
13809 amit.gupta 145
                print "Error occurred"
146
                traceback.print_exc()
14312 amit.gupta 147
                resp['result'] = 'ORDER_NOT_CREATED'
13796 amit.gupta 148
                return resp    
13774 amit.gupta 149
 
13868 amit.gupta 150
    #This should be exposed from api for specific sources
151
    def scrapeStoreOrders(self):
152
        pass
153
 
154
    def getTrackingUrls(self, userId):
14074 amit.gupta 155
 
156
        missingOrderUrls = []
157
        missingOrders = self._getMissingOrders({'userId':userId})
158
        for missingOrder in missingOrders:
159
            missingOrderUrls.append(ORDER_REDIRECT_URL%(missingOrder['merchantOrderId']))
13879 amit.gupta 160
        orders = self._getActiveOrders({'userId':userId})
13882 amit.gupta 161
        count = len(orders)
13879 amit.gupta 162
        print "count", count
13868 amit.gupta 163
        if count > 0:
14320 amit.gupta 164
            return missingOrderUrls + ['https://www.amazon.in/gp/css/order-history', 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled', 'https://www.amazon.in/gp/css/order-history?orderFilter=cancelled&startIndex=10']
13959 amit.gupta 165
        else: 
14074 amit.gupta 166
            return missingOrderUrls
13927 amit.gupta 167
 
168
    def trackOrdersForUser(self, userId, url, rawHtml):
14285 amit.gupta 169
        directory = "/tmp/User" + str(userId)
170
        if not os.path.exists(directory):
171
            os.makedirs(directory)
14298 amit.gupta 172
        filename = directory + "/" + str(datetime.now())
173
        print "filename---", filename
174
        f = open(filename,'w')
14173 amit.gupta 175
        f.write(rawHtml) # python will convert \n to os.linesep
176
        f.close() # you can omit in most cases as the destructor will call if
177
 
13995 amit.gupta 178
        try:
179
            searchMap = {'userId':userId}
180
            collectionMap = {'merchantOrderId':1}
181
            activeOrders = self._getActiveOrders(searchMap, collectionMap)
14033 amit.gupta 182
            datetimeNow = datetime.now()
183
            timestamp = int(time.mktime(datetimeNow.timetuple()))
14009 amit.gupta 184
            print "url----------------", url
14008 amit.gupta 185
 
14320 amit.gupta 186
            if url == 'https://www.amazon.in/gp/css/order-history' or 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled' in url:
13995 amit.gupta 187
                soup = BeautifulSoup(rawHtml)
188
                allOrders = soup.find(id="ordersContainer").findAll('div', {'class':'a-box-group a-spacing-base order'})
189
                bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
190
                for activeOrder in activeOrders:
191
                    for orderEle in allOrders:
192
                        orderdiv = orderEle.find('div', {'class':'a-box a-color-offset-background order-info'}).find('div', {'class':'a-fixed-right-grid-col actions a-col-right'})
193
                        merchantOrderId = orderdiv.find('span', {'class':'a-color-secondary value'}).text.strip()
194
                        if merchantOrderId==activeOrder['merchantOrderId']:
195
                            closed = True
196
                            shipments = orderEle.findAll('div',{'class':re.compile('.*?a-box.*?')}, recursive=False)
197
                            shipments.pop(0)
198
                            for shipment in shipments:
199
                                shipdiv = shipment.find('div', {'class':'a-box-inner'})
14050 amit.gupta 200
                                sdivs = shipment.div.div.findAll('div', recursive=False)
14065 amit.gupta 201
                                orderStatus = sdivs[0].span.text.strip()
14050 amit.gupta 202
                                status = self._getStatusFromDetailedStatus(orderStatus)
203
                                if status == MStore.ORDER_DELIVERED:
14299 amit.gupta 204
                                    deliveredOn = sdivs[0].findAll('span')[-1].text.strip()
14050 amit.gupta 205
                                    deliveredOn = deliveredOn.split(":")[1].strip()
206
                                else:
14065 amit.gupta 207
                                    deliveryestimatespan = sdivs[0].find('span', {'class':'a-color-success'})
14050 amit.gupta 208
                                    deliveryEstimate = None
209
                                    if deliveryestimatespan is not None:
210
                                        deliveryEstimate = deliveryestimatespan.find('span', {'class':'a-text-bold'}).text.strip()
211
                                    productDivs = shipdiv.find('div', {'class':re.compile('.*?a-spacing-top-medium.*?')}).find('div', {'class':'a-row'}).findAll('div', recursive=False)
13995 amit.gupta 212
                                trackingUrl = None
213
                                for buttonDiv in shipdiv.findAll('span', {'class':'a-button-inner'}):
214
                                    if buttonDiv.find('a').text.strip()=='Track package':
215
                                        trackingUrl = buttonDiv.find('a')['href'].strip()
216
                                        if not trackingUrl.startswith("http"):
217
                                            trackingUrl = "https://www.amazon.in/" + trackingUrl
218
                                        break
219
                                for prodDiv in productDivs:
220
                                    prodDiv.find('div', {'class':'a-fixed-left-grid-inner'})
221
                                    productTitle = prodDiv.find('div', {'class':'a-fixed-left-grid-inner'}).find("div", {'class':'a-row'}).find('a').text.strip()
222
                                    imgUrl = prodDiv.find("img")["src"]
223
                                    for subOrder in activeOrder['subOrders']:
224
                                        if subOrder['productTitle'] == productTitle:
225
                                            findMap = {"orderId": activeOrder['orderId'], "subOrders.merchantSubOrderId": subOrder.get("merchantSubOrderId")}
226
                                            updateMap = {}
227
                                            closedStatus = False
228
                                            updateMap['subOrders.$.imgUrl'] = imgUrl
14033 amit.gupta 229
                                            updateMap['subOrders.$.lastTracked'] = timestamp
13995 amit.gupta 230
                                            updateMap['subOrders.$.detailedStatus'] = orderStatus
231
                                            cashbackStatus = subOrder.get("cashBackStatus")
232
                                            updateMap['subOrders.$.status'] = status 
233
 
234
                                            if status==MStore.ORDER_DELIVERED:                               
14291 amit.gupta 235
                                                updateMap['subOrders.$.deliveredOn'] = deliveredOn
13995 amit.gupta 236
                                                closedStatus = True
237
                                                updateMap['subOrders.$.closed'] = True
238
                                                if cashbackStatus == Store.CB_PENDING:
239
                                                    updateMap['subOrders.$.cashbackStatus'] = Store.CB_APPROVED
240
                                            if status==MStore.ORDER_CANCELLED:     
241
                                                closedStatus = True
242
                                                updateMap['subOrders.$.closed'] = True
243
                                                if cashbackStatus == Store.CB_PENDING:
244
                                                    updateMap['subOrders.$.cashBackStatus'] = Store.CB_CANCELLED
245
                                            if status==MStore.ORDER_SHIPPED:   
246
                                                updateMap['subOrders.$.estimatedDeliveryDate'] = deliveryEstimate
247
                                                if trackingUrl is not None:
248
                                                    updateMap['subOrders.$.trackingUrl'] = trackingUrl
249
                                            if not closedStatus:
250
                                                closed = False
251
                                            bulk.find(findMap).update({'$set' : updateMap})
252
                                            break
253
                            bulk.find({'orderId': activeOrder['orderId']}).update({'$set':{'closed': closed}})            
14080 amit.gupta 254
                bulk.execute()
255
                return 'PARSED_SUCCESS'
256
            else:
14086 amit.gupta 257
                merchantOrderId = re.findall(r'https://www.amazon.in/gp/css/summary/edit.html\?orderID=(.*)?', url, re.IGNORECASE)[0] 
14085 amit.gupta 258
                merchantOrder = self.db.merchantOrder.find_one({"merchantOrderId":merchantOrderId})
14312 amit.gupta 259
                self.parseOrderRawHtml(merchantOrder['orderId'], merchantOrder['subTagId'], merchantOrder['userId'], rawHtml, url, False)['result']
14080 amit.gupta 260
                return 'PARSED_SUCCESS'
261
                pass
14008 amit.gupta 262
            return 'PARSED_SUCCESS_NO_ORDERS'
13995 amit.gupta 263
        except:
264
            traceback.print_exc()    
265
            return 'PARSED_FAILED'
266
 
267
    def _getStatusFromDetailedStatus(self, detailedStatus):
14061 amit.gupta 268
        if "ordered from" in detailedStatus.lower():
269
            return MStore.ORDER_PLACED 
270
 
13995 amit.gupta 271
        for key, value in self.orderStatusRegexMap.iteritems():
14032 amit.gupta 272
            if detailedStatus.lower() in value:
13995 amit.gupta 273
                return key
274
 
275
        print "Detailed Status need to be mapped"
14062 amit.gupta 276
        print "Found new order status", detailedStatus
13995 amit.gupta 277
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13927 amit.gupta 278
 
279
 
13774 amit.gupta 280
def main():
281
    store = getStore(1)
282
 
14299 amit.gupta 283
    #store.parseOrderRawHtml(1, 'saad', '2123221', readSSh('/tmp/User8/2015-03-02 12:51:59.545557'), 'https://www.amazon.in/gp/css/summary/edit.html?orderID=12212')
14320 amit.gupta 284
    store.trackOrdersForUser(8,'https://www.amazon.in/gp/css/order-history', readSSh('/tmp/User2/2015-03-02 23:02:16.531611'))
13774 amit.gupta 285
 
14162 amit.gupta 286
def readSSh(fileName):
287
    try:
288
            str1 = open(fileName).read()
289
            return str1
290
    except:
291
        ssh_client = SSHClient()
292
        str1 = ""
293
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
294
        ssh_client.connect('104.200.25.40', 22, 'root', 'ecip$dtrMay2014')
295
        sftp_client = ssh_client.open_sftp()
296
        try:
14299 amit.gupta 297
            if not os.path.exists(os.path.dirname(fileName)):
298
                os.makedirs(os.path.dirname(fileName))
14162 amit.gupta 299
            sftp_client.get(fileName, fileName)
300
            try:
301
                str1 = open(fileName).read()
302
                return str1
303
            finally:
304
                pass
305
        except:
306
            "could not read"
307
        return str1
13774 amit.gupta 308
 
309
 
310
if __name__ == '__main__':
14284 amit.gupta 311
        main()