| 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
|
| 14650 |
amit.gupta |
9 |
from datetime import datetime, timedelta
|
|
|
10 |
from dtr.dao import Order, SubOrder, AmazonAffiliateInfo
|
| 14464 |
amit.gupta |
11 |
from dtr.main import getStore, Store as MStore, ParseException, getBrowserObject, \
|
| 14624 |
amit.gupta |
12 |
ungzipResponse, tprint
|
| 14650 |
amit.gupta |
13 |
from dtr.sources.flipkart import todict, AFF_REPORT_URL
|
| 14162 |
amit.gupta |
14 |
from paramiko import sftp
|
|
|
15 |
from paramiko.client import SSHClient
|
|
|
16 |
from paramiko.sftp_client import SFTPClient
|
| 14650 |
amit.gupta |
17 |
import base64
|
|
|
18 |
import gzip
|
| 14624 |
amit.gupta |
19 |
import mechanize
|
| 14285 |
amit.gupta |
20 |
import os.path
|
| 14162 |
amit.gupta |
21 |
import paramiko
|
| 13774 |
amit.gupta |
22 |
import re
|
| 14033 |
amit.gupta |
23 |
import time
|
| 13809 |
amit.gupta |
24 |
import traceback
|
| 14650 |
amit.gupta |
25 |
import urllib2
|
| 13774 |
amit.gupta |
26 |
|
|
|
27 |
ORDER_REDIRECT_URL = 'https://www.amazon.in/gp/css/summary/edit.html?orderID=%s'
|
| 13810 |
amit.gupta |
28 |
ORDER_SUCCESS_URL = 'https://www.amazon.in/gp/buy/spc/handlers/static-submit-decoupled.html'
|
| 13823 |
amit.gupta |
29 |
THANKYOU_URL = 'https://www.amazon.in/gp/buy/thankyou/handlers/display.html'
|
| 14624 |
amit.gupta |
30 |
AMAZON_AFF_URL = 'https://assoc-datafeeds-eu.amazon.com/datafeed/listReports'
|
| 14650 |
amit.gupta |
31 |
AMAZON_AFF_FILE_URL = 'https://assoc-datafeeds-eu.amazon.com/datafeed/getReport?filename=saholic-21-orders-report-%s.tsv.gz'
|
| 13774 |
amit.gupta |
32 |
class Store(MStore):
|
| 13821 |
amit.gupta |
33 |
|
| 14032 |
amit.gupta |
34 |
orderStatusRegexMap = { MStore.ORDER_PLACED : ['ordered from', 'not yet dispatched','dispatching now', 'preparing for dispatch'],
|
| 14064 |
amit.gupta |
35 |
MStore.ORDER_SHIPPED : ['dispatched on','dispatched', 'on the way', 'out for delivery', 'Out for delivery'],
|
| 14032 |
amit.gupta |
36 |
MStore.ORDER_CANCELLED : ['return complete', 'refunded', 'cancelled'],
|
|
|
37 |
MStore.ORDER_DELIVERED : ['delivered']
|
| 13821 |
amit.gupta |
38 |
}
|
| 13774 |
amit.gupta |
39 |
|
|
|
40 |
def __init__(self,store_id):
|
|
|
41 |
super(Store, self).__init__(store_id)
|
|
|
42 |
|
|
|
43 |
def getName(self):
|
|
|
44 |
return "flipkart"
|
|
|
45 |
|
| 14202 |
amit.gupta |
46 |
def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl, insert=False):
|
| 13796 |
amit.gupta |
47 |
resp = {}
|
| 13821 |
amit.gupta |
48 |
if ORDER_SUCCESS_URL in orderSuccessUrl or THANKYOU_URL in orderSuccessUrl:
|
| 13774 |
amit.gupta |
49 |
try:
|
|
|
50 |
soup = BeautifulSoup(rawHtml)
|
| 14608 |
amit.gupta |
51 |
try:
|
|
|
52 |
orderUrl = soup.find('div', {"id":"thank-you-box-wrapper"}).div.findAll('div', recursive=False)[1].a['href']
|
|
|
53 |
merchantOrderId = re.findall(r'.*&oid=(.*)&?.*?', orderUrl)[0]
|
|
|
54 |
except:
|
|
|
55 |
merchantOrderId = soup.find(id="orders-list").div.span.b.text
|
| 14699 |
amit.gupta |
56 |
order = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl, True)
|
| 14211 |
amit.gupta |
57 |
order.orderSuccessUrl = ORDER_REDIRECT_URL % (merchantOrderId)
|
|
|
58 |
order.merchantOrderId = merchantOrderId
|
| 14291 |
amit.gupta |
59 |
order.requireDetail = True
|
| 14698 |
amit.gupta |
60 |
order.status = 'html_required'
|
| 14297 |
amit.gupta |
61 |
order.closed = None
|
| 14312 |
amit.gupta |
62 |
if self._saveToOrder(todict(order)):
|
|
|
63 |
resp['result'] = 'ORDER_CREATED'
|
|
|
64 |
resp["url"] = ORDER_REDIRECT_URL % (merchantOrderId)
|
|
|
65 |
resp["htmlRequired"] = True
|
|
|
66 |
resp['orderId'] = orderId
|
|
|
67 |
else:
|
|
|
68 |
resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
|
|
|
69 |
|
| 13796 |
amit.gupta |
70 |
return resp
|
| 13774 |
amit.gupta |
71 |
except:
|
| 14312 |
amit.gupta |
72 |
resp["result"] = 'ORDER_NOT_CREATED'
|
| 13796 |
amit.gupta |
73 |
return resp
|
| 13774 |
amit.gupta |
74 |
|
|
|
75 |
else:
|
| 13781 |
amit.gupta |
76 |
try:
|
| 14722 |
amit.gupta |
77 |
mo = self.db.merchantOrder.find_one({"orderId":orderId})
|
|
|
78 |
if mo is not None:
|
|
|
79 |
merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
|
|
|
80 |
merchantOrder.createdOn = mo.get("createdOn")
|
|
|
81 |
merchantOrder.createdOnInt = mo.get("createdOnInt")
|
|
|
82 |
else:
|
|
|
83 |
merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl, False)
|
| 14464 |
amit.gupta |
84 |
soup = BeautifulSoup(rawHtml)
|
|
|
85 |
try:
|
|
|
86 |
self.parseOldStlye(merchantOrder, soup)
|
|
|
87 |
except:
|
| 14545 |
amit.gupta |
88 |
try:
|
| 14566 |
amit.gupta |
89 |
traceback.print_exc()
|
| 14545 |
amit.gupta |
90 |
self.parseNewStlye(merchantOrder, soup)
|
|
|
91 |
except:
|
| 14566 |
amit.gupta |
92 |
traceback.print_exc()
|
| 14545 |
amit.gupta |
93 |
self.parseCancelled(merchantOrder, soup)
|
| 14319 |
amit.gupta |
94 |
resp['result'] = 'ORDER_CREATED'
|
|
|
95 |
return resp
|
| 13781 |
amit.gupta |
96 |
except:
|
| 14703 |
amit.gupta |
97 |
order = self.db.merchantOrder.find_one({"orderId":orderId})
|
| 14682 |
amit.gupta |
98 |
if order is not None:
|
| 14698 |
amit.gupta |
99 |
self.db.merchantOrder.update({"orderId":orderId}, {"$set":{"status":"parse_failed"}})
|
| 13809 |
amit.gupta |
100 |
print "Error occurred"
|
|
|
101 |
traceback.print_exc()
|
| 14312 |
amit.gupta |
102 |
resp['result'] = 'ORDER_NOT_CREATED'
|
| 13796 |
amit.gupta |
103 |
return resp
|
| 13774 |
amit.gupta |
104 |
|
| 13868 |
amit.gupta |
105 |
#This should be exposed from api for specific sources
|
|
|
106 |
def scrapeStoreOrders(self):
|
| 14624 |
amit.gupta |
107 |
br = getBrowserObject()
|
|
|
108 |
orders = self.db.merchantOrder.find({"storeId":1, "closed":False, "subOrders.closed":False, "subOrders.trackingUrl":{"$exists":True}})
|
|
|
109 |
for merchantOrder in orders:
|
|
|
110 |
try:
|
|
|
111 |
bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
|
|
|
112 |
closed = True
|
|
|
113 |
map1 = {}
|
|
|
114 |
for subOrder in merchantOrder.get("subOrders"):
|
|
|
115 |
if subOrder.get("closed"):
|
|
|
116 |
continue
|
|
|
117 |
elif subOrder.get("trackingUrl") is None:
|
|
|
118 |
closed = False
|
|
|
119 |
continue
|
|
|
120 |
findMap = {"orderId":merchantOrder.get("orderId"), "subOrders.merchantSubOrderId":subOrder.get("merchantSubOrderId")}
|
|
|
121 |
trackingUrl = subOrder.get("trackingUrl")
|
|
|
122 |
if not map1.has_key(trackingUrl):
|
|
|
123 |
map1[trackingUrl] = self.parseTrackingUrl(br, trackingUrl)
|
|
|
124 |
newOrder = map1.get(trackingUrl)
|
|
|
125 |
newOrder['cashBackStatus'] = subOrder.get('cashBackStatus')
|
|
|
126 |
updateMap = self.getUpdateMap(newOrder)
|
|
|
127 |
print findMap, "\n", updateMap
|
|
|
128 |
bulk.find(findMap).update({'$set' : updateMap})
|
|
|
129 |
closed = closed and newOrder['closed']
|
| 14697 |
amit.gupta |
130 |
bulk.find({"orderId":merchantOrder.get("orderId")}).update({"$set":{"closed":closed, "parseError":False}})
|
| 14624 |
amit.gupta |
131 |
result = bulk.execute()
|
|
|
132 |
tprint(result)
|
|
|
133 |
except:
|
|
|
134 |
tprint("Could not update " + str(merchantOrder['orderId']))
|
| 14692 |
amit.gupta |
135 |
self.db.merchantOrder.update({"orderId":merchantOrder['orderId']}, {"$set":{"parseError":True}})
|
| 14624 |
amit.gupta |
136 |
traceback.print_exc()
|
|
|
137 |
|
| 14608 |
amit.gupta |
138 |
|
|
|
139 |
|
|
|
140 |
|
| 14464 |
amit.gupta |
141 |
def parseOldStlye(self, merchantOrder, soup):
|
|
|
142 |
merchantOrder.orderTrackingUrl = merchantOrder.orderSuccessUrl
|
|
|
143 |
table = soup.body.findAll("table", recursive=False)[1]
|
|
|
144 |
#print table
|
|
|
145 |
tables = table.tr.td.findAll("table", recursive=False)
|
|
|
146 |
for tr in tables[2].findAll("tr"):
|
|
|
147 |
boldElement = tr.td.b
|
|
|
148 |
if "Order Placed" in str(boldElement):
|
|
|
149 |
merchantOrder.placedOn = boldElement.next_sibling.strip()
|
|
|
150 |
if "order number" in str(boldElement):
|
|
|
151 |
merchantOrder.merchantOrderId = boldElement.next_sibling.strip()
|
|
|
152 |
if "Order Total" in str(boldElement):
|
|
|
153 |
merchantOrder.paidAmount = int(float(boldElement.find('span').contents[-1].replace(',','')))
|
|
|
154 |
anchors = table.tr.td.findAll("a", recursive=False)
|
|
|
155 |
paymentAnchor = anchors.pop(-1)
|
|
|
156 |
|
|
|
157 |
count = 0
|
|
|
158 |
subOrders = []
|
|
|
159 |
merchantOrder.subOrders = subOrders
|
|
|
160 |
counter = 0
|
|
|
161 |
for anchor in anchors:
|
|
|
162 |
count += 1
|
|
|
163 |
tab = anchor.next_sibling
|
|
|
164 |
status = MStore.ORDER_PLACED
|
|
|
165 |
subStr = "Delivery #" + str(count) + ":"
|
|
|
166 |
if subStr in tab.find("b").text:
|
|
|
167 |
detailedStatus = tab.find("b").text.replace(subStr, '').strip()
|
|
|
168 |
|
|
|
169 |
tab = tab.next_sibling.next_sibling
|
|
|
170 |
trs = tab.find("table").find('tbody').findAll("tr", recursive = False)
|
|
|
171 |
|
|
|
172 |
estimatedDelivery = trs[0].td.find("b").next_sibling.strip()
|
|
|
173 |
|
|
|
174 |
orderItemTrs = trs[1].findAll("td", recursive=False)[1].table.tbody.findAll("tr", recursive = False)
|
|
|
175 |
i = -1
|
|
|
176 |
for orderItemTr in orderItemTrs:
|
|
|
177 |
i += 1
|
|
|
178 |
if i%2 == 0:
|
|
|
179 |
continue
|
|
|
180 |
counter += 1
|
|
|
181 |
quantity = int(re.findall(r'\d+', orderItemTr.td.contents[0])[0])
|
|
|
182 |
|
|
|
183 |
productUrl = orderItemTr.td.contents[1].a["href"]
|
|
|
184 |
productTitle = orderItemTr.td.contents[1].a.text
|
|
|
185 |
|
|
|
186 |
unitPrice = int(float(orderItemTr.findAll('td')[1].span.text.replace('Rs. ','').replace(',','')))
|
|
|
187 |
|
|
|
188 |
|
|
|
189 |
subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, unitPrice*quantity, status, quantity)
|
|
|
190 |
subOrder.merchantSubOrderId = str(counter) + " of " + merchantOrder.merchantOrderId
|
|
|
191 |
subOrder.estimatedDeliveryDate = estimatedDelivery
|
| 14722 |
amit.gupta |
192 |
estDlvyTime = datetime.strptime(estimatedDelivery.split('-')[0].strip(), "%A %d %B %Y")
|
|
|
193 |
createdOn = datetime.fromtimestamp(merchantOrder.createdOnInt)
|
|
|
194 |
subOrder.trackAfter = int(time.mktime(max(estDlvyTime-timedelta(days=4),createdOn + timedelta(days=3)).timetuple()))
|
| 14464 |
amit.gupta |
195 |
subOrder.productCode = productUrl.split('/')[5]
|
|
|
196 |
subOrder.detailedStatus = detailedStatus
|
|
|
197 |
(cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, unitPrice*quantity)
|
|
|
198 |
cashbackStatus = Store.CB_PENDING
|
|
|
199 |
if cashbackAmount <= 0:
|
|
|
200 |
cashbackStatus = Store.CB_NA
|
|
|
201 |
subOrder.cashBackStatus = cashbackStatus
|
|
|
202 |
subOrder.cashBackAmount = cashbackAmount
|
|
|
203 |
if percentage > 0:
|
|
|
204 |
subOrder.cashBackPercentage = percentage
|
|
|
205 |
subOrders.append(subOrder)
|
|
|
206 |
priceList = paymentAnchor.next_sibling.next_sibling.next_sibling.table.table.tbody.tbody.tbody.findAll('tr', recursive=False)
|
|
|
207 |
totalAmount = 0
|
|
|
208 |
grandAmount = 0
|
|
|
209 |
for price in priceList:
|
|
|
210 |
labelTd = price.td
|
|
|
211 |
if 'Subtotal:' in labelTd.text:
|
|
|
212 |
totalAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
|
|
|
213 |
elif 'Grand Total:' in labelTd.text:
|
|
|
214 |
grandAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
|
|
|
215 |
if grandAmount < totalAmount:
|
|
|
216 |
diff = totalAmount - grandAmount
|
|
|
217 |
for subOrder in merchantOrder.subOrders:
|
|
|
218 |
subOrder.amountPaid -= int(diff*(1-subOrder.amountPaid/totalAmount))
|
| 14698 |
amit.gupta |
219 |
merchantOrder.status='success'
|
| 14464 |
amit.gupta |
220 |
self._updateToOrder(todict(merchantOrder))
|
|
|
221 |
|
|
|
222 |
def parseNewStlye(self, merchantOrder, soup):
|
|
|
223 |
merchantOrder.orderTrackingUrl = merchantOrder.orderSuccessUrl
|
|
|
224 |
orderDetailsContainer = soup.body.find(id="orderDetails")
|
| 14566 |
amit.gupta |
225 |
divAfterH1 = orderDetailsContainer.h1.next_sibling.next_sibling
|
|
|
226 |
orderLeftDiv = divAfterH1.div
|
| 14464 |
amit.gupta |
227 |
placedOnSpan = orderLeftDiv.find("span", {'class':'order-date-invoice-item'})
|
|
|
228 |
merchantOrder.placedOn =placedOnSpan.text.split('Ordered on')[1].strip()
|
|
|
229 |
merchantOrder.merchantOrderId = placedOnSpan.next_sibling.next_sibling.text.split('Order#')[1].strip()
|
| 14566 |
amit.gupta |
230 |
priceBox = divAfterH1.next_sibling.next_sibling.next_sibling.next_sibling.find("div", {"class":"a-box-inner"}).div.div.findAll('div', recursive=False)[-1]
|
| 14464 |
amit.gupta |
231 |
priceRows = priceBox.findAll('div', {'class':'a-row'})
|
|
|
232 |
subTotal = 0
|
| 14566 |
amit.gupta |
233 |
shippingPrice = 0
|
| 14464 |
amit.gupta |
234 |
promoApplied = 0
|
|
|
235 |
for priceRow in priceRows:
|
|
|
236 |
if "Item(s) Subtotal:" in str(priceRow):
|
|
|
237 |
subTotal = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
|
|
|
238 |
elif "Shipping:" in str(priceRow):
|
|
|
239 |
shippingPrice = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
|
|
|
240 |
elif "Grand Total:" in str(priceRow):
|
|
|
241 |
grandPrice = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
|
|
|
242 |
merchantOrder.paidAmount = grandPrice
|
|
|
243 |
elif "Total:" in str(priceRow):
|
|
|
244 |
totalPrice = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
|
|
|
245 |
elif "Promotion Applied:" in str(priceRow):
|
|
|
246 |
promoApplied += int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
|
|
|
247 |
totalPaid = subTotal
|
|
|
248 |
if promoApplied > 0:
|
|
|
249 |
totalPaid -= promoApplied
|
|
|
250 |
if shippingPrice <= promoApplied:
|
|
|
251 |
totalPaid += shippingPrice
|
|
|
252 |
|
|
|
253 |
shipmentDivs = orderDetailsContainer.find('div', {'class':'a-box shipment'}).findAll('div', recursive = False)
|
|
|
254 |
subOrders = []
|
|
|
255 |
merchantOrder.subOrders = subOrders
|
|
|
256 |
i=1
|
|
|
257 |
for shipmentDiv in shipmentDivs:
|
|
|
258 |
innerBoxes = shipmentDiv.findAll('div', recursive = False)
|
|
|
259 |
statusDiv = innerBoxes[0]
|
|
|
260 |
subOrderStatus = statusDiv.div.span.text.strip()
|
| 14566 |
amit.gupta |
261 |
deliverySpan = statusDiv.div.div.find_next_sibling('div').span
|
| 14464 |
amit.gupta |
262 |
productDivs = innerBoxes[-1].div.div.div.findAll('div', recursive=False)
|
|
|
263 |
subOrders = []
|
|
|
264 |
merchantOrder.subOrders = subOrders
|
|
|
265 |
for i, productDiv in enumerate(productDivs):
|
|
|
266 |
i +=1
|
|
|
267 |
imgDiv = productDiv.div.div
|
|
|
268 |
detailDiv = imgDiv.find_next_sibling('div')
|
|
|
269 |
detailDivs = detailDiv.findAll('div', recursive=False)
|
|
|
270 |
arr = detailDivs[0].a.text.strip().split(" of ", 1)
|
| 14465 |
amit.gupta |
271 |
(productTitle, quantity) = (arr[-1], (1 if len(arr)==1 else int(arr[0])) )
|
| 14464 |
amit.gupta |
272 |
unitPrice = int(float(detailDivs[2].span.text.replace('Rs. ','').replace(',','')))
|
|
|
273 |
amountPaid = int((unitPrice*quantity*totalPaid)/subTotal)
|
|
|
274 |
productUrl = "http://www.amazon.in" + detailDivs[0].a.get('href')
|
|
|
275 |
subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, amountPaid, MStore.ORDER_PLACED, quantity)
|
|
|
276 |
subOrder.productCode = productUrl.split('/')[5]
|
|
|
277 |
subOrder.unitPrice = unitPrice
|
| 14566 |
amit.gupta |
278 |
subOrder.merchantSubOrderId = str(i) + " of " + merchantOrder.merchantOrderId
|
| 14722 |
amit.gupta |
279 |
estDlvyTime = datetime.now()
|
| 14566 |
amit.gupta |
280 |
if deliverySpan is not None:
|
| 14722 |
amit.gupta |
281 |
subOrder.estimatedDeliveryDate = deliverySpan.span.text.strip()
|
|
|
282 |
estDate = subOrder.estimatedDeliveryDate.split("-")[0].strip()
|
|
|
283 |
subOrder.estimatedDeliveryInt = int(time.mktime((datetime.strptime(estDate, "%A %d %B %Y")).timetuple()))
|
|
|
284 |
estDlvyTime = datetime.strptime(estDate, "%A %d %B %Y")
|
|
|
285 |
|
|
|
286 |
createdOn = datetime.fromtimestamp(merchantOrder.createdOnInt)
|
|
|
287 |
subOrder.trackAfter = int(time.mktime(max(estDlvyTime-timedelta(days=4),createdOn + timedelta(days=3)).timetuple()))/1000
|
| 14464 |
amit.gupta |
288 |
subOrder.detailedStatus = subOrderStatus
|
|
|
289 |
subOrder.deliveryCharges = shippingPrice
|
| 14466 |
amit.gupta |
290 |
subOrder.imgUrl = imgDiv.img["src"]
|
| 14464 |
amit.gupta |
291 |
(cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amountPaid)
|
|
|
292 |
cashbackStatus = Store.CB_PENDING
|
|
|
293 |
if cashbackAmount <= 0:
|
|
|
294 |
cashbackStatus = Store.CB_NA
|
|
|
295 |
subOrder.cashBackStatus = cashbackStatus
|
|
|
296 |
subOrder.cashBackAmount = cashbackAmount
|
|
|
297 |
if percentage > 0:
|
|
|
298 |
subOrder.cashBackPercentage = percentage
|
|
|
299 |
subOrders.append(subOrder)
|
| 14698 |
amit.gupta |
300 |
merchantOrder.status='success'
|
| 14464 |
amit.gupta |
301 |
self._updateToOrder(todict(merchantOrder))
|
| 14545 |
amit.gupta |
302 |
|
|
|
303 |
def parseCancelled(self, merchantOrder,soup):
|
| 14722 |
amit.gupta |
304 |
try:
|
|
|
305 |
fonts = soup.body.findAll("table", recursive=False)[1].findAll("font")
|
|
|
306 |
if fonts[0].text == "Important Message":
|
|
|
307 |
if fonts[1].text=="This order has been cancelled.":
|
|
|
308 |
merchantOrder.closed = True
|
|
|
309 |
merchantOrder.status = "cancelled"
|
|
|
310 |
merchantOrder.requireDetail = False
|
|
|
311 |
self._updateToOrder(todict(merchantOrder))
|
|
|
312 |
return
|
|
|
313 |
else:
|
|
|
314 |
raise ParseException("parseCancelled", "Found detailed status" + fonts[1].text)
|
| 14545 |
amit.gupta |
315 |
else:
|
|
|
316 |
raise ParseException("parseCancelled", "Found detailed status" + fonts[1].text)
|
| 14722 |
amit.gupta |
317 |
except:
|
| 14549 |
amit.gupta |
318 |
orderDetails = soup.body.find(id="orderDetails")
|
|
|
319 |
if orderDetails is not None and orderDetails.h4.text == "This order has been cancelled.":
|
|
|
320 |
merchantOrder.closed = True
|
| 14698 |
amit.gupta |
321 |
merchantOrder.status = "cancelled"
|
| 14549 |
amit.gupta |
322 |
merchantOrder.requireDetail = False
|
|
|
323 |
self._updateToOrder(todict(merchantOrder))
|
|
|
324 |
else:
|
|
|
325 |
raise ParseException("parseCancelled", "Found detailed status" + fonts[1].text)
|
| 14464 |
amit.gupta |
326 |
|
| 13868 |
amit.gupta |
327 |
def getTrackingUrls(self, userId):
|
| 14074 |
amit.gupta |
328 |
|
|
|
329 |
missingOrderUrls = []
|
|
|
330 |
missingOrders = self._getMissingOrders({'userId':userId})
|
|
|
331 |
for missingOrder in missingOrders:
|
|
|
332 |
missingOrderUrls.append(ORDER_REDIRECT_URL%(missingOrder['merchantOrderId']))
|
| 14683 |
amit.gupta |
333 |
orders = self._getActiveOrders({'userId':userId, "subOrders.trackingUrl":{"$exists":False} })
|
| 13882 |
amit.gupta |
334 |
count = len(orders)
|
| 13879 |
amit.gupta |
335 |
print "count", count
|
| 13868 |
amit.gupta |
336 |
if count > 0:
|
| 14684 |
amit.gupta |
337 |
return missingOrderUrls + ['https://www.amazon.in/gp/css/order-history', 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled', 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled&startIndex=10']
|
| 13959 |
amit.gupta |
338 |
else:
|
| 14074 |
amit.gupta |
339 |
return missingOrderUrls
|
| 13927 |
amit.gupta |
340 |
|
|
|
341 |
def trackOrdersForUser(self, userId, url, rawHtml):
|
| 14285 |
amit.gupta |
342 |
directory = "/tmp/User" + str(userId)
|
|
|
343 |
if not os.path.exists(directory):
|
|
|
344 |
os.makedirs(directory)
|
| 14298 |
amit.gupta |
345 |
filename = directory + "/" + str(datetime.now())
|
|
|
346 |
print "filename---", filename
|
|
|
347 |
f = open(filename,'w')
|
| 14173 |
amit.gupta |
348 |
f.write(rawHtml) # python will convert \n to os.linesep
|
|
|
349 |
f.close() # you can omit in most cases as the destructor will call if
|
|
|
350 |
|
| 13995 |
amit.gupta |
351 |
try:
|
|
|
352 |
searchMap = {'userId':userId}
|
|
|
353 |
collectionMap = {'merchantOrderId':1}
|
|
|
354 |
activeOrders = self._getActiveOrders(searchMap, collectionMap)
|
| 14033 |
amit.gupta |
355 |
datetimeNow = datetime.now()
|
|
|
356 |
timestamp = int(time.mktime(datetimeNow.timetuple()))
|
| 14009 |
amit.gupta |
357 |
print "url----------------", url
|
| 14008 |
amit.gupta |
358 |
|
| 14320 |
amit.gupta |
359 |
if url == 'https://www.amazon.in/gp/css/order-history' or 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled' in url:
|
| 13995 |
amit.gupta |
360 |
soup = BeautifulSoup(rawHtml)
|
|
|
361 |
allOrders = soup.find(id="ordersContainer").findAll('div', {'class':'a-box-group a-spacing-base order'})
|
|
|
362 |
bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
|
|
|
363 |
for activeOrder in activeOrders:
|
|
|
364 |
for orderEle in allOrders:
|
|
|
365 |
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'})
|
|
|
366 |
merchantOrderId = orderdiv.find('span', {'class':'a-color-secondary value'}).text.strip()
|
|
|
367 |
if merchantOrderId==activeOrder['merchantOrderId']:
|
|
|
368 |
closed = True
|
|
|
369 |
shipments = orderEle.findAll('div',{'class':re.compile('.*?a-box.*?')}, recursive=False)
|
|
|
370 |
shipments.pop(0)
|
|
|
371 |
for shipment in shipments:
|
|
|
372 |
shipdiv = shipment.find('div', {'class':'a-box-inner'})
|
| 14050 |
amit.gupta |
373 |
sdivs = shipment.div.div.findAll('div', recursive=False)
|
| 14065 |
amit.gupta |
374 |
orderStatus = sdivs[0].span.text.strip()
|
| 14050 |
amit.gupta |
375 |
status = self._getStatusFromDetailedStatus(orderStatus)
|
|
|
376 |
if status == MStore.ORDER_DELIVERED:
|
| 14299 |
amit.gupta |
377 |
deliveredOn = sdivs[0].findAll('span')[-1].text.strip()
|
| 14050 |
amit.gupta |
378 |
deliveredOn = deliveredOn.split(":")[1].strip()
|
| 14335 |
amit.gupta |
379 |
deliveryestimatespan = sdivs[0].find('span', {'class':'a-color-success'})
|
|
|
380 |
deliveryEstimate = None
|
|
|
381 |
if deliveryestimatespan is not None:
|
|
|
382 |
deliveryEstimate = deliveryestimatespan.find('span', {'class':'a-text-bold'}).text.strip()
|
|
|
383 |
productDivs = shipdiv.find('div', {'class':re.compile('.*?a-spacing-top-medium.*?')}).find('div', {'class':'a-row'}).findAll('div', recursive=False)
|
| 13995 |
amit.gupta |
384 |
trackingUrl = None
|
|
|
385 |
for buttonDiv in shipdiv.findAll('span', {'class':'a-button-inner'}):
|
|
|
386 |
if buttonDiv.find('a').text.strip()=='Track package':
|
|
|
387 |
trackingUrl = buttonDiv.find('a')['href'].strip()
|
|
|
388 |
if not trackingUrl.startswith("http"):
|
| 14608 |
amit.gupta |
389 |
trackingUrl = "http://www.amazon.in" + trackingUrl
|
| 13995 |
amit.gupta |
390 |
break
|
|
|
391 |
for prodDiv in productDivs:
|
|
|
392 |
prodDiv.find('div', {'class':'a-fixed-left-grid-inner'})
|
|
|
393 |
productTitle = prodDiv.find('div', {'class':'a-fixed-left-grid-inner'}).find("div", {'class':'a-row'}).find('a').text.strip()
|
|
|
394 |
imgUrl = prodDiv.find("img")["src"]
|
|
|
395 |
for subOrder in activeOrder['subOrders']:
|
|
|
396 |
if subOrder['productTitle'] == productTitle:
|
|
|
397 |
findMap = {"orderId": activeOrder['orderId'], "subOrders.merchantSubOrderId": subOrder.get("merchantSubOrderId")}
|
|
|
398 |
updateMap = {}
|
|
|
399 |
closedStatus = False
|
|
|
400 |
updateMap['subOrders.$.imgUrl'] = imgUrl
|
| 14033 |
amit.gupta |
401 |
updateMap['subOrders.$.lastTracked'] = timestamp
|
| 13995 |
amit.gupta |
402 |
updateMap['subOrders.$.detailedStatus'] = orderStatus
|
|
|
403 |
cashbackStatus = subOrder.get("cashBackStatus")
|
|
|
404 |
updateMap['subOrders.$.status'] = status
|
|
|
405 |
|
|
|
406 |
if status==MStore.ORDER_DELIVERED:
|
| 14291 |
amit.gupta |
407 |
updateMap['subOrders.$.deliveredOn'] = deliveredOn
|
| 13995 |
amit.gupta |
408 |
closedStatus = True
|
|
|
409 |
updateMap['subOrders.$.closed'] = True
|
|
|
410 |
if cashbackStatus == Store.CB_PENDING:
|
| 14607 |
amit.gupta |
411 |
updateMap['subOrders.$.cashBackStatus'] = Store.CB_APPROVED
|
| 13995 |
amit.gupta |
412 |
if status==MStore.ORDER_CANCELLED:
|
|
|
413 |
closedStatus = True
|
|
|
414 |
updateMap['subOrders.$.closed'] = True
|
|
|
415 |
if cashbackStatus == Store.CB_PENDING:
|
|
|
416 |
updateMap['subOrders.$.cashBackStatus'] = Store.CB_CANCELLED
|
|
|
417 |
if status==MStore.ORDER_SHIPPED:
|
|
|
418 |
updateMap['subOrders.$.estimatedDeliveryDate'] = deliveryEstimate
|
|
|
419 |
if trackingUrl is not None:
|
|
|
420 |
updateMap['subOrders.$.trackingUrl'] = trackingUrl
|
|
|
421 |
if not closedStatus:
|
|
|
422 |
closed = False
|
|
|
423 |
bulk.find(findMap).update({'$set' : updateMap})
|
|
|
424 |
break
|
|
|
425 |
bulk.find({'orderId': activeOrder['orderId']}).update({'$set':{'closed': closed}})
|
| 14080 |
amit.gupta |
426 |
bulk.execute()
|
|
|
427 |
return 'PARSED_SUCCESS'
|
|
|
428 |
else:
|
| 14086 |
amit.gupta |
429 |
merchantOrderId = re.findall(r'https://www.amazon.in/gp/css/summary/edit.html\?orderID=(.*)?', url, re.IGNORECASE)[0]
|
| 14085 |
amit.gupta |
430 |
merchantOrder = self.db.merchantOrder.find_one({"merchantOrderId":merchantOrderId})
|
| 14312 |
amit.gupta |
431 |
self.parseOrderRawHtml(merchantOrder['orderId'], merchantOrder['subTagId'], merchantOrder['userId'], rawHtml, url, False)['result']
|
| 14080 |
amit.gupta |
432 |
return 'PARSED_SUCCESS'
|
|
|
433 |
pass
|
| 14008 |
amit.gupta |
434 |
return 'PARSED_SUCCESS_NO_ORDERS'
|
| 13995 |
amit.gupta |
435 |
except:
|
|
|
436 |
traceback.print_exc()
|
|
|
437 |
return 'PARSED_FAILED'
|
|
|
438 |
|
|
|
439 |
def _getStatusFromDetailedStatus(self, detailedStatus):
|
| 14061 |
amit.gupta |
440 |
if "ordered from" in detailedStatus.lower():
|
|
|
441 |
return MStore.ORDER_PLACED
|
|
|
442 |
|
| 13995 |
amit.gupta |
443 |
for key, value in self.orderStatusRegexMap.iteritems():
|
| 14032 |
amit.gupta |
444 |
if detailedStatus.lower() in value:
|
| 13995 |
amit.gupta |
445 |
return key
|
|
|
446 |
|
| 14676 |
amit.gupta |
447 |
print "Detailed Status need to be mapped", "Store:", self.store_id
|
| 13995 |
amit.gupta |
448 |
raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
|
| 14624 |
amit.gupta |
449 |
def scrapeAffiliate(self, startDate=None, endDate=None):
|
| 14650 |
amit.gupta |
450 |
br = getBrowserObject()
|
|
|
451 |
br.add_password('https://assoc-datafeeds-eu.amazon.com', 'Saholic', 'Fnubyvp')
|
|
|
452 |
url = AMAZON_AFF_URL
|
|
|
453 |
response = br.open(url)
|
|
|
454 |
#get data for past 40 days and store it to mongo
|
|
|
455 |
dt = datetime.now()
|
| 14701 |
amit.gupta |
456 |
dat = dt - timedelta(days=2)
|
| 14651 |
amit.gupta |
457 |
url = AMAZON_AFF_FILE_URL%(datetime.strftime(dat, "%Y%m%d"))
|
|
|
458 |
response = br.open(url)
|
|
|
459 |
page = gzip.GzipFile(fileobj=response, mode='rb').read()
|
|
|
460 |
j=-1
|
|
|
461 |
for row in page.split("\n"):
|
|
|
462 |
j += 1
|
|
|
463 |
if j== 0 or j==1:
|
|
|
464 |
continue
|
|
|
465 |
fields = row.split("\t")
|
|
|
466 |
if len(fields)>1:
|
|
|
467 |
print fields
|
|
|
468 |
amazonAffiliate = AmazonAffiliateInfo(fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6], fields[7], fields[8], fields[9])
|
|
|
469 |
print amazonAffiliate
|
|
|
470 |
self.db.amazonAffiliateInfo.insert(todict(amazonAffiliate))
|
|
|
471 |
else:
|
|
|
472 |
break
|
| 14650 |
amit.gupta |
473 |
|
| 14608 |
amit.gupta |
474 |
|
|
|
475 |
def parseTrackingUrl(self, br, trackingUrl):
|
| 14624 |
amit.gupta |
476 |
subOrder = {}
|
| 14608 |
amit.gupta |
477 |
response = br.open(trackingUrl)
|
|
|
478 |
page = ungzipResponse(response)
|
| 14624 |
amit.gupta |
479 |
soup = BeautifulSoup(page)
|
|
|
480 |
alertContainer = soup.find("div", {"class":"a-box-inner a-alert-container"})
|
|
|
481 |
if alertContainer is not None:
|
|
|
482 |
statusText = alertContainer.h4.span.text
|
|
|
483 |
detailedStatus = statusText.split(":")[0].strip()
|
|
|
484 |
subOrder['detailedStatus'] = detailedStatus
|
|
|
485 |
if detailedStatus.lower() == "in transit":
|
|
|
486 |
pass
|
|
|
487 |
elif detailedStatus.lower() == "undeliverable":
|
|
|
488 |
subOrder['status'] = MStore.ORDER_CANCELLED
|
|
|
489 |
return subOrder
|
|
|
490 |
else:
|
|
|
491 |
summaryLeft = soup.find(id="summaryLeft")
|
|
|
492 |
statusText = summaryLeft.h2.text
|
|
|
493 |
detailedStatus = statusText.split(":")[0].strip()
|
|
|
494 |
subOrder['detailedStatus'] = detailedStatus
|
|
|
495 |
if detailedStatus.lower() == "delivered":
|
|
|
496 |
subOrder['deliveredOn'] = summaryLeft.findAll("span")[-2].text.strip()
|
|
|
497 |
subOrder['status'] = MStore.ORDER_DELIVERED
|
|
|
498 |
return subOrder
|
|
|
499 |
else:
|
|
|
500 |
subOrder['expectedDelivery'] = summaryLeft.findAll("span")[-1].text.strip()
|
|
|
501 |
return subOrder
|
|
|
502 |
|
|
|
503 |
|
|
|
504 |
|
| 14608 |
amit.gupta |
505 |
|
|
|
506 |
|
| 13927 |
amit.gupta |
507 |
|
|
|
508 |
|
| 13774 |
amit.gupta |
509 |
def main():
|
|
|
510 |
store = getStore(1)
|
| 14650 |
amit.gupta |
511 |
# br = mechanize.Browser()
|
|
|
512 |
# br.addheaders = [('User-agent','Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'),
|
|
|
513 |
# ('Accept', 'text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8'),
|
|
|
514 |
# ('Accept-Encoding', 'gzip,deflate,sdch'),
|
|
|
515 |
# ('Accept-Language', 'en-US,en;q=0.8'),
|
|
|
516 |
# ('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')]
|
|
|
517 |
# store.scrapeStoreOrders()
|
| 14722 |
amit.gupta |
518 |
store.parseOrderRawHtml(2121, "13232", 14, readSSh("/home/amit/1313.html"), "https://www.amazon.in/gp/css/summary/edit.html?orderID=171-5857029-0804336")
|
|
|
519 |
#store.parseOrderRawHtml(2121, "13232", 14, readSSh("/home/amit/f1.html"), "https://www.amazon.in/gp/css/summary/edit.html?orderID=171-5196461-3230730")
|
| 14703 |
amit.gupta |
520 |
#readSSh("/tmp/User211/2015-04-01 15:31:42.250309")
|
|
|
521 |
#store.scrapeAffiliate()
|
| 14162 |
amit.gupta |
522 |
def readSSh(fileName):
|
|
|
523 |
try:
|
|
|
524 |
str1 = open(fileName).read()
|
|
|
525 |
return str1
|
|
|
526 |
except:
|
|
|
527 |
ssh_client = SSHClient()
|
|
|
528 |
str1 = ""
|
|
|
529 |
ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
|
|
530 |
ssh_client.connect('104.200.25.40', 22, 'root', 'ecip$dtrMay2014')
|
|
|
531 |
sftp_client = ssh_client.open_sftp()
|
|
|
532 |
try:
|
| 14299 |
amit.gupta |
533 |
if not os.path.exists(os.path.dirname(fileName)):
|
|
|
534 |
os.makedirs(os.path.dirname(fileName))
|
| 14162 |
amit.gupta |
535 |
sftp_client.get(fileName, fileName)
|
|
|
536 |
try:
|
|
|
537 |
str1 = open(fileName).read()
|
|
|
538 |
return str1
|
|
|
539 |
finally:
|
|
|
540 |
pass
|
|
|
541 |
except:
|
|
|
542 |
"could not read"
|
|
|
543 |
return str1
|
| 13774 |
amit.gupta |
544 |
|
|
|
545 |
|
|
|
546 |
if __name__ == '__main__':
|
| 14284 |
amit.gupta |
547 |
main()
|