Subversion Repositories SmartDukaan

Rev

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