Subversion Repositories SmartDukaan

Rev

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