Subversion Repositories SmartDukaan

Rev

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