Subversion Repositories SmartDukaan

Rev

Rev 13868 | Rev 13927 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13569 amit.gupta 1
'''
2
Created on Jan 15, 2015
3
 
4
@author: amit
5
'''
13724 amit.gupta 6
from datetime import datetime
13869 amit.gupta 7
import time
13868 amit.gupta 8
from pprint import pprint
13569 amit.gupta 9
from pymongo.mongo_client import MongoClient
10
import importlib
13662 amit.gupta 11
import json
12
import math
13569 amit.gupta 13
import mechanize
13631 amit.gupta 14
import traceback
13662 amit.gupta 15
import urllib
16
import urllib2
13582 amit.gupta 17
sourceMap = {1:"amazon", 2:"flipkart", 3:"snapdeal", 4:"spice", 5:"homeshop18"}
13662 amit.gupta 18
headers = { 
19
           'User-agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
20
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
21
            'Accept-Language' : 'en-US,en;q=0.8',                     
22
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'
23
        }
24
CASHBACK_URL = 'http://api.profittill.com/cashbacks/index/%s/%s'
13677 amit.gupta 25
USER_LOOKUP_URL = 'http://api.profittill.com/user_account/saholic/%s'
13868 amit.gupta 26
WALLET_CREDIT_URL = 'http://www.shop2020.in:8080/mobileapi/wallet!batchUpdate'
13569 amit.gupta 27
 
28
def getStore(source_id):
29
    #module = sourceMap[source_id]
30
    store = Store(source_id)
13631 amit.gupta 31
    try:
32
        module = importlib.import_module("dtr.sources." + sourceMap[source_id])
33
        store = getattr(module, "Store")(source_id)
34
        return store
35
    except:
13781 amit.gupta 36
        traceback.print_exc()
13631 amit.gupta 37
        return None
13569 amit.gupta 38
 
39
class ScrapeException(Exception):
40
    """Exception raised for errors in the input.
41
 
42
    Attributes:
43
        expr -- input expression in which the error occurred
44
        msg  -- explanation of the error
45
    """
46
 
47
    def __init__(self, expr, msg):
48
        self.expr = expr
49
        self.msg = msg
50
 
51
class ParseException(Exception):
52
    """Exception raised for errors in the input.
53
 
54
    Attributes:
55
        expr -- input expression in which the error occurred
56
        msg  -- explanation of the error
57
    """
58
 
59
    def __init__(self, expr, msg):
60
        self.expr = expr
61
        self.msg = msg
62
 
13677 amit.gupta 63
client = MongoClient('mongodb://localhost:27017/') 
64
 
13569 amit.gupta 65
class Store(object):
66
 
67
    ORDER_PLACED = 'Order Placed'
68
    ORDER_DELIVERED = 'Delivered'
69
    ORDER_SHIPPED = 'Shipped' #Lets see if we can make use of it
70
    ORDER_CANCELLED = 'Cancelled'
71
 
13662 amit.gupta 72
    CB_INIT = 'Waiting Confirmation'
13610 amit.gupta 73
    CB_PENDING = 'Pending'
74
    CB_CREDITED = 'Credited to wallet'
75
    CB_NA = 'Not Applicable'
76
    CB_APPROVED = 'Approved'
77
    CB_CANCELLED = 'Cancelled'
13569 amit.gupta 78
 
13662 amit.gupta 79
    CONF_CB_SELLING_PRICE = 0
80
    CONF_CB_DISCOUNTED_PRICE = 1
13610 amit.gupta 81
 
13569 amit.gupta 82
    def __init__(self, store_id):
13662 amit.gupta 83
        self.db = client.Dtr
13569 amit.gupta 84
        self.store_id = store_id
13576 amit.gupta 85
        self.store_name = sourceMap[store_id]
13569 amit.gupta 86
 
13662 amit.gupta 87
    '''
88
    To Settle payback for respective stores.
89
    Also ensures that settlement happens only for approved orders
90
    '''
13569 amit.gupta 91
 
92
    def getName(self):
93
        raise NotImplementedError
94
 
95
    def scrapeAffiliate(self, startDate=None, endDate=None):
96
        raise NotImplementedError
97
 
98
    def saveToAffiliate(self, offers):
99
        raise NotImplementedError
100
 
101
    def scrapeStoreOrders(self,):
102
        raise NotImplementedError
13610 amit.gupta 103
 
13690 amit.gupta 104
    def _saveToOrder(self, order):
105
        collection = self.db.merchantOrder
106
        try:
107
            order = collection.insert(order)
108
            #merchantOder 
109
        except Exception as e:
110
            traceback.print_exc()
13662 amit.gupta 111
 
112
    def getCashbackAmount(self, productCode, amount):
113
        alagvar = CASHBACK_URL % (self.store_id,productCode)
114
        filehandle = urllib2.Request(alagvar,headers=headers)
115
        x= urllib2.urlopen(filehandle)
116
        map = json.loads(x.read())
117
        if map['cashback']==0:
13721 amit.gupta 118
            return (0,0)
13662 amit.gupta 119
        else:
120
            if map['cashback_type'] == 'percentage':
13721 amit.gupta 121
                return (math.floor((amount * map['cashback'])/100), map['cashback'])
13662 amit.gupta 122
            else:
13721 amit.gupta 123
                return (map['cashback'], 0)
124
 
13662 amit.gupta 125
 
13569 amit.gupta 126
    '''
127
    Parses the order for specific store
128
 
129
    order id, total amount, created on(now() if could not parse
130
    suborder id, title, quantity, unit price, expected delivery date,
131
    status (default would be Order placed)
132
 
133
    once products are identified, each suborder can then be updated
134
    with respective cashback.
135
 
136
    Possible fields to display for Not yet delivered orders are 
137
    Product/Quantity/Amount/Store/CashbackAmount/OrderDate/ExpectedDelivery/OrderStaus/DetailedStatus/CashbackStatus
138
    No need to show cancelled orders.
13610 amit.gupta 139
    CashbackStatus - NotApplicable/Pending/Approved/Cancelled/CreditedToWallet
13569 amit.gupta 140
    OrderStatus - Placed/Cancelled/Delivered
141
    '''
13576 amit.gupta 142
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
13569 amit.gupta 143
 
144
        pass
145
 
13721 amit.gupta 146
    def _updateOrdersPayBackStatus(self, searchMap, updateMap):
13781 amit.gupta 147
        searchMap['subOrders.missingAff'] = False
148
        updateMap['subOrders.$.missingAff'] = True
13721 amit.gupta 149
        self.db.merchantOrder.update(searchMap, { '$set': updateMap })
150
 
13781 amit.gupta 151
    def _getActiveOrders(self, searchMap={}, collectionMap={}):
13721 amit.gupta 152
        collection = self.db.merchantOrder
13781 amit.gupta 153
        searchMap = dict(searchMap.items()+ {"closed": False, "storeId" : self.store_id}.items()) 
154
        collectionMap =  dict(collectionMap.items() + {"orderSuccessUrl":1, "orderId":1,"subOrders":1, "placedOn":1}.items())
155
        stores = collection.find(searchMap, collectionMap)
13721 amit.gupta 156
        return [store for store in stores]
157
 
158
    def _isSubOrderActive(self,order, merchantSubOrderId):
159
        subOrders = order.get("subOrders")
160
        for subOrder in subOrders:
161
            if merchantSubOrderId == subOrder.get("merchantSubOrderId"):
162
                return subOrder
163
        return None
164
 
13868 amit.gupta 165
def settlePayBack():
166
        result = client.Dtr.merchantOrder\
167
            .aggregate([
168
                        {'$match':{'subOrders.cashBackStatus':Store.CB_APPROVED}},
169
                        {'$unwind':"$subOrders"},
170
                        { 
171
                         '$group':{
172
                                   '_id':'$userId',
173
                                   'amount': { '$sum':'$subOrders.cashBackAmount'},
174
                                   }
175
                         }
176
                    ])['result']
177
 
178
        userAmountMap = {}
179
        for res in result:
180
            userAmountMap[res['_id']] = res['amount'] 
13869 amit.gupta 181
        batchId = int(time.mktime(datetime.now().timetuple()))
13868 amit.gupta 182
        batchUpdateMap = {'batchId':batchId}
183
        batchUpdateMap['userAmount'] = result
184
        #for 
185
        #get batch id
186
        print batchId 
187
        if __refundToWallet(batchUpdateMap):
188
            client.Dtr.merchantOrder.update({'subOrders.cashBackStatus':Store.CB_APPROVED},{'subOrders.$.cashBackStatus':Store.CB_CREDITED}, multi=True)
189
        else:
190
            tprint("Error Occurred while running batch")
13721 amit.gupta 191
 
13868 amit.gupta 192
 
13662 amit.gupta 193
def main():
13677 amit.gupta 194
    #store = getStore(3)
195
    #print store.getCashbackAmount('864683341', 100)
13868 amit.gupta 196
    #data = urllib.urlencode({'orderId':6000, 'amount':200})
197
    #request = urllib2.Request(WALLET_CREDIT_URL % (483649), headers=headers)
198
    #response = urllib2.urlopen(request, data)
199
    #print response.read()
200
    settlePayBack()
13662 amit.gupta 201
 
13569 amit.gupta 202
if __name__ == '__main__':
13662 amit.gupta 203
    main()
13569 amit.gupta 204
 
205
 
13868 amit.gupta 206
###
207
#Settlement process is suposed to be a batch and run weekly
208
#It is should be running on first hour of mondays. As cron should
209
# Maintain a batch id.
210
 
211
def __refundToWallet(self, batchUpdateMap):
212
    result = False
213
    try :
214
        userAmountMap = batchUpdateMap['userAmount']
215
        saholicUserAmountMap = {}
216
        for key, value in userAmountMap:
217
            userLookupRequest = urllib2.Request(USER_LOOKUP_URL %(key), headers=headers)
218
            response = urllib2.urlopen(userLookupRequest).read()
219
            saholicUserId = json.loads(response)['account_id']
220
            saholicUserAmountMap[saholicUserId] = value
221
        batchUpdateMap['userAmount'] = saholicUserAmountMap
222
        request = urllib2.Request(WALLET_CREDIT_URL, headers=headers)
223
        data = urllib.urlencode(batchUpdateMap)
224
        response = urllib2.urlopen(request, data)
225
    except:
226
        traceback.print_exc()
227
        return False
13677 amit.gupta 228
 
229
    return json.loads(response.read())['credited']
230
 
13569 amit.gupta 231
def getBrowserObject():
232
    import cookielib
233
    br = mechanize.Browser(factory=mechanize.RobustFactory())
234
    cj = cookielib.LWPCookieJar()
235
    br.set_cookiejar(cj)
236
    br.set_handle_equiv(True)
237
    br.set_handle_redirect(True)
238
    br.set_handle_referer(True)
239
    br.set_handle_robots(False)
240
    br.set_debug_http(False)
241
    br.set_debug_redirects(False)
242
    br.set_debug_responses(False)
243
 
244
    br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
245
 
246
    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'),
247
                     ('Accept', 'text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8'),
248
                     ('Accept-Encoding', 'gzip,deflate,sdch'),                  
249
                     ('Accept-Language', 'en-US,en;q=0.8'),                     
250
                     ('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')]
13677 amit.gupta 251
    return br
252
 
13690 amit.gupta 253
def ungzipResponse(r):
254
    headers = r.info()
255
    if headers['Content-Encoding']=='gzip':
256
        import gzip
257
        gz = gzip.GzipFile(fileobj=r, mode='rb')
258
        html = gz.read()
259
        gz.close()
260
        return html
13724 amit.gupta 261
 
262
def tprint(*msg):
13728 amit.gupta 263
    print datetime.now(), "-", msg