Subversion Repositories SmartDukaan

Rev

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