Subversion Repositories SmartDukaan

Rev

Rev 21316 | Rev 21318 | 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
'''
13690 amit.gupta 6
from BeautifulSoup import BeautifulSoup
13721 amit.gupta 7
from datetime import datetime, date, timedelta
13569 amit.gupta 8
from dtr import main
14412 amit.gupta 9
from dtr.dao import AffiliateInfo, Order, SubOrder, FlipkartAffiliateInfo
13690 amit.gupta 10
from dtr.main import getBrowserObject, getStore, ParseException, ungzipResponse, \
14398 amit.gupta 11
    Store as MStore, sourceMap, tprint
21246 amit.gupta 12
from dtr.storage.DataService import Clicks, Users, FlipkartOrders, OrdersRaw
16209 amit.gupta 13
from dtr.utils import utils
21310 amit.gupta 14
from dtr.utils.utils import fetchResponseUsingProxy, todict, getSkuData, \
20395 amit.gupta 15
    ORDER_PLACED
15539 amit.gupta 16
from elixir import *
13690 amit.gupta 17
from pprint import pprint
18
from pymongo.mongo_client import MongoClient
21310 amit.gupta 19
from urlparse import urlparse
17238 amit.gupta 20
import StringIO
21
import csv
13690 amit.gupta 22
import hashlib
13658 manas 23
import importlib
13690 amit.gupta 24
import json
25
import mechanize
14412 amit.gupta 26
import pymongo
13658 manas 27
import re
21310 amit.gupta 28
import time
14338 amit.gupta 29
import traceback
13658 manas 30
import urllib
18156 amit.gupta 31
import urllib2
17238 amit.gupta 32
import zipfile
13658 manas 33
USERNAME='saholic1@gmail.com'
34
PASSWORD='spice@2020'
21264 amit.gupta 35
ORDER_TRACK_URL='https://www.flipkart.com/order_details?src=or&pr=1&type=physical&'
17238 amit.gupta 36
AFFILIATE_URL='https://affiliate.flipkart.com/'
37
AFFILIATE_LOGIN_URL='https://affiliate.flipkart.com/a_login'
38
AFF_REPORT_URL = "https://affiliate.flipkart.com/downloads/a_downloadRequest?type=OrdersReport&parameters=%s"
39
AFF_DOWNLOAD_URL="https://affiliate.flipkart.com/downloads/file?id=%s"
13690 amit.gupta 40
AFF_STATUS_CANCELLED='cancelled'
41
AFF_STATUS_APPROVED='approved'
42
AFF_STATUS_DISAPPROVED='disapproved'
43
AFF_STATUS_PENDING='pending'
17238 amit.gupta 44
statuses = [AFF_STATUS_CANCELLED, AFF_STATUS_APPROVED, AFF_STATUS_DISAPPROVED,AFF_STATUS_PENDING ]
15539 amit.gupta 45
categoryMap = {3:"Mobiles", 5:"Tablets"}
21269 amit.gupta 46
mobileAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4'
13658 manas 47
 
21266 amit.gupta 48
headers = { 
21269 amit.gupta 49
            'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4',
21266 amit.gupta 50
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
51
            'Accept-Language' : 'en-US,en;q=0.8',                     
52
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
53
            'Connection':'keep-alive',
54
            'Accept-Encoding' : 'gzip,deflate,sdch'
55
        }
56
 
21316 amit.gupta 57
TRACK_URLS = ['https://www.flipkart.com/api/1/self-serve/orders?pageNum=1&link=myAccounts', 'https://www.flipkart.com/api/1/self-serve/orders?pageNum=2&link=myAccounts', 'https://www.flipkart.com/api/1/self-serve/orders?pageNum=1&link=myAccounts']
21273 amit.gupta 58
TRACK_HEADERS = {
59
        "sn":"2.VIBAC8BD9D21024F649B0482FAC385814A.SIE6C5F25D78974A5EB850D89167D52009.VSE7C76F85C2EE463786F89407CA46CA31.1492756338",
60
        "Connection":"keep-alive",
61
        "Referer":"https://www.flipkart.com/rv/orders?link=myAccounts",
62
        "cache-control":"no-cache",
63
        "Accept":"/",
64
        "Accept-Language":"en-US,en;q=0.8",
65
        "content-type":"application/json",
66
        "User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML:like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36",
67
        "flipkart_secure":"true",
68
        "sc":"",
69
        "Accept-Encoding":"gzip:deflate:sdch:br",
70
        "x-user-agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML:like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36 FKUA/msite/0.0.1/msite/Mobile,Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML:like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36 FKUA/msite/0.0.1/msite/Mobile",
71
        "pragma":"no-cache",
72
        "issecureresource":"true"
73
}
74
 
75
 
13781 amit.gupta 76
class Store(MStore):
13658 manas 77
    OrderStatusMap = {
14679 amit.gupta 78
                      main.Store.ORDER_PLACED : ['approval', 'processing', 'shipping'],
79
                      main.Store.ORDER_DELIVERED : ['your item has been delivered'],
14680 amit.gupta 80
                      main.Store.ORDER_SHIPPED : ['in transit', 'shipment yet to be delivered'],
81
                      main.Store.ORDER_CANCELLED : ['shipment is returned', 'your item has been returned', 'your shipment has been cancelled', 'your shipment has been cancelled.']
13658 manas 82
 
83
                      }
84
    def __init__(self,store_id):
85
        client = MongoClient('mongodb://localhost:27017/')
86
        self.db = client.dtr
87
        super(Store, self).__init__(store_id)
88
 
13569 amit.gupta 89
    def getName(self):
90
        return "flipkart"
91
 
21310 amit.gupta 92
    def _parseJSON(self,merchantOrder, transaction):
93
        update = False
94
        if not merchantOrder.subOrders:
95
            merchantOrder.placedOn = transaction['orderDate'] 
96
            merchantOrder.paidAmount = transaction['amount']
97
            subOrders = []
98
            merchantOrder.subOrders = subOrders
99
            for shipment in transaction['groupedItems']:
100
                for item in shipment:
101
                    productUrl = "https://www.flipkart.com/" + item['itemMetadata']
102
                    merchantsubOrder = SubOrder(item['title']+ item['itemMetadata']['color'], productUrl, merchantOrder.placedOn, item['amount'],MStore.ORDER_PLACED, item['quantity'])
103
                    merchantsubOrder.merchantSubOrderId = item['orderItemId']
104
                    merchantsubOrder.imgUrl  = item['itemMetadata']['images']['1000x1000']
105
                    productCode=productUrl.split("pid=")[1]
106
                    merchantsubOrder.productCode = productCode
107
                    merchantsubOrder.merchantSubOrderId = item['orderItemId']
108
                    merchantsubOrder.amount = item['sellingPrice']*merchantsubOrder.quantity
109
                    merchantsubOrder.unitPrice = item['sellingPrice']
110
                    merchantsubOrder.detailedStatus = item['desktopSubStatus']
111
                    subOrders.append(merchantsubOrder)
112
        else:
113
            update = True
114
            for shipment in transaction['groupedItems']:
115
                for item in shipment:
116
                    subOrder = self._isSubOrderActive(merchantOrder,  item['orderItemId'])
117
                    if subOrder:
118
                        subOrder.detailedStatus = item['desktopSubStatus']
119
 
120
        self.populateDerivedFields(merchantOrder, update)
121
 
122
    def _getActiveOrders(self, searchMap={}, collectionMap={}):
123
        collection = self.db.merchantOrder
124
        searchMap = dict(searchMap.items()+ {"closed": False, "storeId" : self.store_id}.items()) 
125
        #collectionMap =  dict(collectionMap.items() + {"orderSuccessUrl":1, "orderId":1,"subOrders":1, "placedOn":1, "orderTracking"}.items())
126
        stores = collection.find(searchMap)
127
        return [store for store in stores]    
128
 
129
 
21273 amit.gupta 130
    def trackOrdersForUser(self, userId, url, rawHtml):
131
        rawHtml = re.sub(r'[^\x00-\x7F]+',' ', rawHtml)
132
        if url not in TRACK_URLS:
133
            for lis in re.findall('SN:"(.*?)"', rawHtml):
134
                TRACK_HEADERS['sn'] = lis
135
                break
136
            for lis in re.findall('SN:"(.*?)"', rawHtml):
137
                TRACK_HEADERS['User-Agent'] = lis.split(" fkUA")[0]
138
                TRACK_HEADERS['x-user-agent'] = lis
139
                break
21317 amit.gupta 140
 
141
            if self._getActiveOrders({"createdOnInt":{"$gt":int(time.mktime(datetime.now().timetuple() - 30*86400))}}):
21310 amit.gupta 142
                return {"headers":TRACK_HEADERS, "urls":TRACK_URLS}
143
            else:
144
                return {"headers":TRACK_HEADERS, "urls":[]}
21273 amit.gupta 145
        else:
21310 amit.gupta 146
            jsonObject = json.loads(rawHtml)
147
            #Get only orders less than one month old
148
            activeOrders = self._getActiveOrders({"createdOnInt":{"$gt":int(time.mktime(datetime.now().timetuple() - 30*86400))}})
149
            for order in activeOrders:
150
                for transaction in jsonObject['RESPONSE']['orderGranularDetails']:
151
                    if transaction['orderId'][:-3] == order["mechantOrderId"]:
152
                        self._parseJSON(order, transaction)
153
                        break
154
 
155
 
156
 
21273 amit.gupta 157
            return 'PARSED_SUCCESS'
158
 
17238 amit.gupta 159
 
160
    def requestDownload(self):
161
    #"https://affiliate.flipkart.com/downloads/a_downloadRequest?type=OrdersReport&parameters=%7B%22filter%22%3A%22approved%22%2C%22till%22%3A%222015-10-03%22%2C%22from%22%3A%222015-04-03%22%7D"
162
        requestReportUrl = "https://affiliate.flipkart.com/downloads/a_downloadRequest?type=OrdersReport&parameters=%s"
163
        br = getBrowserObject()
164
        br.set_debug_responses(True)
165
        br.open(AFFILIATE_URL)
166
        response = br.response()  # copy
167
        #token =  re.findall('window.__FK = "(.*?)"', utils.ungzipResponse(response), re.IGNORECASE)[0]
168
        data = {
169
                    'j_username':'saholic1@gmail.com',
170
                    'j_password':'spice@2020'
171
            }
172
        print utils.ungzipResponse(br.open(AFFILIATE_LOGIN_URL, urllib.urlencode(data)))
173
        till = datetime.strftime(date.today(),"%Y-%m-%d")
174
        start = datetime.strftime(date.today() - timedelta(4), "%Y-%m-%d")
175
        #target = open("dowloadreportids", 'w')
176
        #target.truncate()
177
        for status in statuses:
178
            #try:
179
                data = {"till":till, "from":start, "filter":status}
180
                print json.dumps(data)
181
                request = requestReportUrl%(urllib.quote_plus(json.dumps(data).replace(" ", "")))
182
                print request
183
                response = utils.ungzipResponse(br.open(request))
184
                response = json.loads(response)
185
                print response
186
                if(response['status']=="OK"):
187
                    self.db.flipkartdownloadids.save(response)
188
                else:
189
                    utils.sendmail(['amit.gupta@shop2020.in'], '', "Could not get request data for Flipkart Affiliate downlaod")
190
                    #break 
191
            #except:
192
                utils.sendmail(['amit.gupta@shop2020.in'], '', "Could not get request data for Flipkart Affiliate downlaod due to Internal Server Error")
193
                #break 
194
 
195
 
13690 amit.gupta 196
    def scrapeStoreOrders(self,):
21311 amit.gupta 197
        pass
13690 amit.gupta 198
        orders = self._getActiveOrders()
13721 amit.gupta 199
        for order in orders:
14692 amit.gupta 200
            print "Order", self.store_name, order['orderId']
14398 amit.gupta 201
            try:
202
                closed = True
20421 amit.gupta 203
                url = ORDER_TRACK_URL + urlparse(order['orderSuccessUrl']).query    
21266 amit.gupta 204
                page = fetchResponseUsingProxy(url, headers)
14398 amit.gupta 205
                soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
206
 
207
                sections = soup.findAll("div", {"class":"ui-app-card-body"})
208
                sections.pop(1)
13721 amit.gupta 209
 
14398 amit.gupta 210
                mainOrder = soup.find("ul",{"class":"m-bottom p-cart"})
211
                fkSubOrders = mainOrder.findAll("li")
212
 
213
                #remove unwanted list
214
                fkSubOrders.pop(-1)
215
 
216
 
217
                bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
218
                #fetching suborders details
219
                for subOrder in fkSubOrders:
220
                    updateMap = {}
14692 amit.gupta 221
                    ul = subOrder.find("ul")
222
                    if ul is None:
223
                        ul = subOrder.findAll("div", recursive=False)[0].div.div
224
                    orderItems = ul.findAll("div", recursive=False)
14398 amit.gupta 225
                    for orderItem in orderItems:
226
                        closedStatus = False
20422 amit.gupta 227
                        divs = orderItem.findAll('div', recursive=False)
228
                        orderTracking = divs[2]
229
                        merchantSubOrderId = divs[3].get('id')
14398 amit.gupta 230
                        subOrder =  self._isSubOrderActive(order, merchantSubOrderId)
231
                        if subOrder is None:
232
                            break
14460 amit.gupta 233
                        elif subOrder['closed']:
234
                            break
14398 amit.gupta 235
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": merchantSubOrderId}
236
                        orderTrackingDetDiv = divs[3].find('div',{'class':'c-tabs-content m-top active'})
20422 amit.gupta 237
                        cashbackStatus = subOrder.get("cashBackStatus")
20420 amit.gupta 238
                        if orderTrackingDetDiv is not None:
239
                            orderTrackingDet = str(orderTrackingDetDiv.find("div", "tracking-remark").text)
240
                            updateMap["subOrders.$.detailedStatus"] = orderTrackingDet
241
                            tr = orderTracking.findAll("div",{"class":"tap-bullet-area c-tab-trigger"})
242
 
243
                            tr = orderTracking.findAll("div",{"class":"tap-bullet-area c-tab-trigger"})
244
 
245
                            if "approveDetails-ongoing" in str(tr) or "processingDetails-ongoing" in str(tr):
246
                                status=MStore.ORDER_PLACED
247
                            elif "shippingDetails-ongoing" in str(tr):
248
                                status = MStore.ORDER_SHIPPED
249
                            elif "delivery-complete" in str(tr):
250
                                status = MStore.ORDER_DELIVERED
20421 amit.gupta 251
                                if cashbackStatus != Store.CB_NA:
20420 amit.gupta 252
                                    cashbackStatus = Store.CB_APPROVED
253
                                closedStatus = True
254
                            if "dead" in str(tr) or "shippingDetails-returnOngoing" in str(tr) or "shippingDetails-return" in str(tr):
255
                                status = MStore.ORDER_CANCELLED
256
                                closedStatus = True
257
                                if cashbackStatus == Store.CB_PENDING:
258
                                    cashbackStatus = Store.CB_CANCELLED
259
                        else:
260
                            updateMap["subOrders.$.detailedStatus"] = "Refunded"
14398 amit.gupta 261
                            status = MStore.ORDER_CANCELLED
262
                            closedStatus = True
263
                            if cashbackStatus == Store.CB_PENDING:
264
                                cashbackStatus = Store.CB_CANCELLED
20417 amit.gupta 265
                        print "Sub Order Status " + str(status)
14398 amit.gupta 266
 
267
                        updateMap["subOrders.$.cashBackStatus"] = cashbackStatus
268
                        updateMap["subOrders.$.status"] = status
269
                        updateMap["subOrders.$.closed"] = closedStatus
270
                        if closed:
271
                            closed = closedStatus
272
                        bulk.find(findMap).update({'$set' : updateMap})
14692 amit.gupta 273
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed, 'parseError':False}})
14398 amit.gupta 274
                bulk.execute()            
275
            except:
14692 amit.gupta 276
                self.db.merchantOrder.update({"orderId":order['orderId']}, {"$set":{"parseError":True}})
14847 amit.gupta 277
                tprint("Could not update " + str(order['orderId']) + ' for store ' + self.getName())
14398 amit.gupta 278
                traceback.print_exc()
17238 amit.gupta 279
 
280
    def scrapeAffiliate(self, deltaDays=0):
281
        if deltaDays is None:
282
            deltaDays=0
283
        endDate=date.today() - timedelta(days=1)
284
        startDate = endDate - timedelta(days=deltaDays)
15539 amit.gupta 285
 
17238 amit.gupta 286
        endDate = datetime.strftime(endDate, "%Y-%m-%d")
287
        startDate = datetime.strftime(startDate, "%Y-%m-%d")
17241 amit.gupta 288
        url  = "https://affiliate-api.flipkart.net/affiliate/report/orders/detail/json?startDate=%s&endDate=%s&status=%s&offset=0"
17238 amit.gupta 289
 
290
        for status in statuses:
17241 amit.gupta 291
            nextUrl = url%(startDate, endDate, status)
292
            while nextUrl:
17243 amit.gupta 293
                req = urllib2.Request(nextUrl)
17242 amit.gupta 294
                nextUrl=''
17238 amit.gupta 295
                req.add_header('Fk-Affiliate-Id', 'saholic1g')
296
                req.add_header('Fk-Affiliate-Token', 'a757444e260c46be8c4aeb20352246ac')
297
                resp = urllib2.urlopen(req)
298
                resString = json.loads(resp.read())
299
                orderList = resString["orderList"]
300
                if orderList:
301
                    for order in orderList:
302
                        order['sales'] = int(order['sales']['amount'])
303
                        order['tentativeCommission'] = int(order['tentativeCommission']['amount'])
304
                        subTagId = order.get("affExtParam1")
305
                        userId = None
306
                        email = None
307
                        if subTagId:
308
                            click = session.query(Clicks).filter_by(tag = subTagId).first()
309
                            if click is not None:
310
                                userId= click.user_id 
311
                                user = session.query(Users.email).filter_by(id = userId).first()
312
                                if user is not None:
313
                                    email = user.email
314
 
315
                        flipkartOrder = FlipkartOrders()
316
                        flipkartOrder.subtagId = subTagId
317
                        flipkartOrder.user_id = userId
318
                        flipkartOrder.identifier = order.get("identifier")
319
                        flipkartOrder.email = email
18465 amit.gupta 320
                        flipkartOrder.created = datetime.strptime(order.get("orderDate"), "%d-%m-%Y %H:%M:%S")
17238 amit.gupta 321
                        flipkartOrder.status = order.get("status")
322
                        flipkartOrder.title = order.get("title")
323
                        flipkartOrder.price = order.get("price")
324
                        flipkartOrder.quantity = order.get("quantity")
325
                        flipkartOrder.productCode = order.get("productId")
326
                        flipkartOrder.affiliateOrderItemId = order.get("affiliateOrderItemId")
327
                        flipkartOrder.payOut = order['tentativeCommission']
328
                        flipkartOrder.payOutPercentage = order['commissionRate']
329
                        skuData = getSkuData(2, order.get("productId"))
330
                        if skuData is not None:
331
                            flipkartOrder.catalogId = skuData.get("skuBundleId")
332
                            flipkartOrder.brand = skuData.get("brand")
333
                            flipkartOrder.model = skuData.get("model_name")
334
                            flipkartOrder.category = categoryMap.get(skuData.get("category_id"))
335
                            flipkartOrder.title =skuData.get("source_product_name")
336
 
337
                    session.commit()
17241 amit.gupta 338
                    nextUrl = resString['next']  
13721 amit.gupta 339
 
14412 amit.gupta 340
    def _saveToAffiliate(self, offers):
17238 amit.gupta 341
        collection = self.db.flipkartOrderAffiliateInfo1
342
        count=0
343
        for row in offers:
344
            if count==0:
345
                count += 1
346
                continue
347
            offer = self.covertToObj(row)
348
            collection.save(offer)
349
 
350
    def covertToObj(self,offer):
351
        affiliateorderitemid,title,productid,category,quantity,sales,price,commissionrate,tentativecommission,status,orderdate,saleschannel,customertype,affextparam1, affextparam2  = offer
352
        saleMap = {
353
               "affiliateorderitemid":affiliateorderitemid,
354
                "title":title,
355
                "productid":productid,
356
                "category":category,
357
                "quantity":quantity,
358
                "saleAmount":sales,
359
                "price":price,
360
                "commissionrate":commissionrate,
361
                "payOut":tentativecommission,
362
                "conversionStatus":status,
363
                "saleDate":orderdate,
364
                "saleschannel":saleschannel,
365
                "customertype":customertype,
366
                "affextparam1":affextparam1,
367
                "_id":affiliateorderitemid
368
        }
369
        return saleMap
14412 amit.gupta 370
 
371
 
21312 amit.gupta 372
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
373
        resp= {}
374
        try:
375
            url = ORDER_TRACK_URL + urlparse(orderSuccessUrl).query 
376
            merchantOrderId = re.findall('reference_id=(.*?)&', orderSuccessUrl,re.IGNORECASE)[0]
21310 amit.gupta 377
 
21312 amit.gupta 378
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
379
            merchantOrder.closed = False
380
            merchantOrder.merchantOrderId = merchantOrderId
381
            merchantOrder.orderTrackingUrl = url
382
            if self._saveToOrder(todict(merchantOrder)):
383
                resp['result'] = 'ORDER_CREATED'
384
            else:
385
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
386
 
387
            return resp 
388
        except:
389
            traceback.print_exc()
390
            resp['result'] = 'ORDER_NOT_CREATED'
391
            return resp 
392
 
21310 amit.gupta 393
 
394
 
14617 amit.gupta 395
    def _getStatusFromDetailedStatus(self, detailedStatus):
396
        for key, value in Store.OrderStatusMap.iteritems():
14626 amit.gupta 397
            if detailedStatus.lower() in value:
14617 amit.gupta 398
                return key
14676 amit.gupta 399
        print "Detailed Status need to be mapped", detailedStatus, "Store:", self.store_name
20392 amit.gupta 400
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)           
13658 manas 401
 
402
def _saveToOrderFlipkart(self, order):
403
        collection = self.db.merchantOrder
404
        order = collection.insert(order)
405
 
13690 amit.gupta 406
 
407
 
408
def hex_md5(password):
409
    m = hashlib.md5()
410
    print(m.digest())
411
 
13658 manas 412
def main():
16210 amit.gupta 413
    store = getStore(2)
21312 amit.gupta 414
    store.parseOrderRawHtml(1, '1234', 14, '', 'https://www.flipkart.com/rv/orderConfirmation/orderresponse?pr=1&reference_id=OD1090350248246880&src=or&type=physical&token=3f720f955fc94219e7fef31992302b38')
21246 amit.gupta 415
    #store.scrapeStoreOrders()
13679 manas 416
 
16209 amit.gupta 417
if __name__ == '__main__':
418
        main()
14145 amit.gupta 419