Subversion Repositories SmartDukaan

Rev

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

'''
Created on Jan 15, 2015

@author: amit
'''
from datetime import datetime
import time
from pprint import pprint
from pymongo.mongo_client import MongoClient
import importlib
import json
import math
import mechanize
import traceback
import urllib
import urllib2
sourceMap = {1:"amazon", 2:"flipkart", 3:"snapdeal", 4:"spice", 5:"homeshop18"}
headers = { 
           'User-agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
            'Accept-Language' : 'en-US,en;q=0.8',                     
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'
        }
CASHBACK_URL = 'http://api.profittill.com/cashbacks/index/%s/%s'
USER_LOOKUP_URL = 'http://api.profittill.com/user_account/saholic/%s'
WALLET_CREDIT_URL = 'http://www.shop2020.in:8080/mobileapi/wallet!batchUpdate'

def getStore(source_id):
    #module = sourceMap[source_id]
    store = Store(source_id)
    try:
        module = importlib.import_module("dtr.sources." + sourceMap[source_id])
        store = getattr(module, "Store")(source_id)
        return store
    except:
        traceback.print_exc()
        return None

class ScrapeException(Exception):
    """Exception raised for errors in the input.

    Attributes:
        expr -- input expression in which the error occurred
        msg  -- explanation of the error
    """

    def __init__(self, expr, msg):
        self.expr = expr
        self.msg = msg

class ParseException(Exception):
    """Exception raised for errors in the input.

    Attributes:
        expr -- input expression in which the error occurred
        msg  -- explanation of the error
    """

    def __init__(self, expr, msg):
        self.expr = expr
        self.msg = msg

client = MongoClient('mongodb://localhost:27017/') 

class Store(object):
    
    ORDER_PLACED = 'Order Placed'
    ORDER_DELIVERED = 'Delivered'
    ORDER_SHIPPED = 'Shipped' #Lets see if we can make use of it
    ORDER_CANCELLED = 'Cancelled'
    
    CB_INIT = 'Waiting Confirmation'
    CB_PENDING = 'Pending'
    CB_CREDITED = 'Credited to wallet'
    CB_NA = 'Not Applicable'
    CB_APPROVED = 'Approved'
    CB_CANCELLED = 'Cancelled'
    
    CONF_CB_SELLING_PRICE = 0
    CONF_CB_DISCOUNTED_PRICE = 1
    
    def __init__(self, store_id):
        self.db = client.Dtr
        self.store_id = store_id
        self.store_name = sourceMap[store_id]
    
    '''
    To Settle payback for respective stores.
    Also ensures that settlement happens only for approved orders
    '''
    
    def getName(self):
        raise NotImplementedError
    
    def scrapeAffiliate(self, startDate=None, endDate=None):
        raise NotImplementedError
    
    def saveToAffiliate(self, offers):
        raise NotImplementedError
    
    def scrapeStoreOrders(self,):
        raise NotImplementedError
    
    def _saveToOrder(self, order):
        collection = self.db.merchantOrder
        try:
            order = collection.insert(order)
            #merchantOder 
        except Exception as e:
            traceback.print_exc()
    
    def getCashbackAmount(self, productCode, amount):
        alagvar = CASHBACK_URL % (self.store_id,productCode)
        filehandle = urllib2.Request(alagvar,headers=headers)
        x= urllib2.urlopen(filehandle)
        map = json.loads(x.read())
        if map['cashback']==0:
            return (0,0)
        else:
            if map['cashback_type'] == 'percentage':
                return (math.floor((amount * map['cashback'])/100), map['cashback'])
            else:
                return (map['cashback'], 0)
            
    
    '''
    Parses the order for specific store
    
    order id, total amount, created on(now() if could not parse
    suborder id, title, quantity, unit price, expected delivery date,
    status (default would be Order placed)
    
    once products are identified, each suborder can then be updated
    with respective cashback.
    
    Possible fields to display for Not yet delivered orders are 
    Product/Quantity/Amount/Store/CashbackAmount/OrderDate/ExpectedDelivery/OrderStaus/DetailedStatus/CashbackStatus
    No need to show cancelled orders.
    CashbackStatus - NotApplicable/Pending/Approved/Cancelled/CreditedToWallet
    OrderStatus - Placed/Cancelled/Delivered
    '''
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
        
        pass
    
    def _updateOrdersPayBackStatus(self, searchMap, updateMap):
        searchMap['subOrders.missingAff'] = False
        updateMap['subOrders.$.missingAff'] = True
        self.db.merchantOrder.update(searchMap, { '$set': updateMap })
        
    def _getActiveOrders(self, searchMap={}, collectionMap={}):
        collection = self.db.merchantOrder
        searchMap = dict(searchMap.items()+ {"closed": False, "storeId" : self.store_id}.items()) 
        collectionMap =  dict(collectionMap.items() + {"orderSuccessUrl":1, "orderId":1,"subOrders":1, "placedOn":1}.items())
        stores = collection.find(searchMap, collectionMap)
        return [store for store in stores]
    
    def _isSubOrderActive(self,order, merchantSubOrderId):
        subOrders = order.get("subOrders")
        for subOrder in subOrders:
            if merchantSubOrderId == subOrder.get("merchantSubOrderId"):
                return subOrder
        return None

def settlePayBack():
        result = client.Dtr.merchantOrder\
            .aggregate([
                        {'$match':{'subOrders.cashBackStatus':Store.CB_APPROVED}},
                        {'$unwind':"$subOrders"},
                        { 
                         '$group':{
                                   '_id':'$userId',
                                   'amount': { '$sum':'$subOrders.cashBackAmount'},
                                   }
                         }
                    ])['result']
                    
        userAmountMap = {}
        for res in result:
            userAmountMap[res['_id']] = res['amount'] 
        batchId = int(time.mktime(datetime.now().timetuple()))
        batchUpdateMap = {'batchId':batchId}
        batchUpdateMap['userAmount'] = result
        #for 
        #get batch id
        print batchId 
        if __refundToWallet(batchUpdateMap):
            client.Dtr.merchantOrder.update({'subOrders.cashBackStatus':Store.CB_APPROVED},{'subOrders.$.cashBackStatus':Store.CB_CREDITED}, multi=True)
        else:
            tprint("Error Occurred while running batch")
    
    
def main():
    #store = getStore(3)
    #print store.getCashbackAmount('864683341', 100)
    #data = urllib.urlencode({'orderId':6000, 'amount':200})
    #request = urllib2.Request(WALLET_CREDIT_URL % (483649), headers=headers)
    #response = urllib2.urlopen(request, data)
    #print response.read()
    settlePayBack()
        
if __name__ == '__main__':
    main()


###
#Settlement process is suposed to be a batch and run weekly
#It is should be running on first hour of mondays. As cron should
# Maintain a batch id.

def __refundToWallet(self, batchUpdateMap):
    result = False
    try :
        userAmountMap = batchUpdateMap['userAmount']
        saholicUserAmountMap = {}
        for key, value in userAmountMap:
            userLookupRequest = urllib2.Request(USER_LOOKUP_URL %(key), headers=headers)
            response = urllib2.urlopen(userLookupRequest).read()
            saholicUserId = json.loads(response)['account_id']
            saholicUserAmountMap[saholicUserId] = value
        batchUpdateMap['userAmount'] = saholicUserAmountMap
        request = urllib2.Request(WALLET_CREDIT_URL, headers=headers)
        data = urllib.urlencode(batchUpdateMap)
        response = urllib2.urlopen(request, data)
    except:
        traceback.print_exc()
        return False
    
    return json.loads(response.read())['credited']

def getBrowserObject():
    import cookielib
    br = mechanize.Browser(factory=mechanize.RobustFactory())
    cj = cookielib.LWPCookieJar()
    br.set_cookiejar(cj)
    br.set_handle_equiv(True)
    br.set_handle_redirect(True)
    br.set_handle_referer(True)
    br.set_handle_robots(False)
    br.set_debug_http(False)
    br.set_debug_redirects(False)
    br.set_debug_responses(False)
    
    br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
    
    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'),
                     ('Accept', 'text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8'),
                     ('Accept-Encoding', 'gzip,deflate,sdch'),                  
                     ('Accept-Language', 'en-US,en;q=0.8'),                     
                     ('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')]
    return br

def ungzipResponse(r):
    headers = r.info()
    if headers['Content-Encoding']=='gzip':
        import gzip
        gz = gzip.GzipFile(fileobj=r, mode='rb')
        html = gz.read()
        gz.close()
        return html

def tprint(*msg):
    print datetime.now(), "-", msg