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