Awight has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/314509

Change subject: WIP Regression test for T143903
......................................................................

WIP Regression test for T143903

Bug: T143903
Change-Id: I866b1771f77989085e840a4eb2d320c5fb1a2f89
---
A audit/__init__.py
M audit/paypal/TrrFile.py
M audit/paypal/paypal_api.py
A audit/paypal/tests/test_trr_file.py
M process/globals.py
5 files changed, 113 insertions(+), 20 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/wikimedia/fundraising/tools 
refs/changes/09/314509/1

diff --git a/audit/__init__.py b/audit/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audit/__init__.py
diff --git a/audit/paypal/TrrFile.py b/audit/paypal/TrrFile.py
index 1bbed11..b68e465 100644
--- a/audit/paypal/TrrFile.py
+++ b/audit/paypal/TrrFile.py
@@ -6,12 +6,12 @@
 import re
 
 from process.logging import Logger as log
-from process.globals import config
-from queue.redis_wrap import Redis
+import process.globals
+import queue.redis_wrap
 import ppreport
 
-from civicrm.civicrm import Civicrm
-from paypal_api import PaypalApiClassic
+import civicrm.civicrm
+import paypal_api
 
 
 class TrrFile(object):
@@ -83,7 +83,8 @@
 
     def __init__(self, path):
         self.path = path
-        self.crm = Civicrm(config.civicrm_db)
+        self.config = process.globals.get_config()
+        self.crm = civicrm.civicrm.Civicrm(self.config.civicrm_db)
 
     def parse(self):
         # FIXME: encapsulation issues
@@ -180,19 +181,19 @@
             return
 
         if 'last_name' not in out and queue != 'refund':
-            out['first_name'], out['last_name'] = 
self.fetch_donor_name(out['gateway_txn_id'])
+            out['first_name'], out['last_name'] = 
paypal_api.PaypalApiClassic().fetch_donor_name(out['gateway_txn_id'])
 
-        if config.no_thankyou:
+        if self.config.no_thankyou:
             out['thankyou_date'] = 0
 
         
log.info("+Sending\t{id}\t{date}\t{type}".format(id=out['gateway_txn_id'], 
date=row['Transaction Initiation Date'], type=queue))
         self.send(queue, out)
 
-    def send(self, queue, msg):
+    def send(self, queue_name, msg):
         if not self.redis:
-            self.redis = Redis()
+            self.redis = queue.redis_wrap.Redis()
 
-        self.redis.send(queue, msg)
+        self.redis.send(queue_name, msg)
 
     def normalize_recurring(self, msg):
         'Synthesize a raw PayPal message'
@@ -200,6 +201,14 @@
         if 'fee' not in msg:
             msg['fee'] = 0
 
+        # TODO: Move validation elsewhere.
+        required_fields = ['subscr_id']
+        for field in required_fields:
+            if field not in msg or not msg[field]:
+                raise Exception("Missing field " + field)
+
+        # FIXME: Are the names available in these records?  That would save us
+        # an API to fetch_donor_name.
         out = {
             'gateway': 'paypal',
             'txn_type': 'subscr_payment',
@@ -219,10 +228,3 @@
         }
 
         return out
-
-    def fetch_donor_name(self, txn_id):
-        api = PaypalApiClassic()
-        response = api.call('GetTransactionDetails', TRANSACTIONID=txn_id)
-        if 'FIRSTNAME' not in response:
-            raise RuntimeError("Failed to get transaction details for {id}, 
repsonse: {response}".format(id=txn_id, response=response))
-        return (response['FIRSTNAME'][0], response['LASTNAME'][0])
diff --git a/audit/paypal/paypal_api.py b/audit/paypal/paypal_api.py
index 327d7b6..a4f2599 100644
--- a/audit/paypal/paypal_api.py
+++ b/audit/paypal/paypal_api.py
@@ -1,9 +1,9 @@
-from process.globals import config
-
 import httplib
 import urllib
 import urllib2
 import urlparse
+
+import process.globals
 
 
 class PaypalApiClassic(object):
@@ -11,6 +11,7 @@
     VERSION = '124.0'
 
     def call(self, cmd, **kw):
+        config = process.globals.get_config()
         params = {
             'PWD': config.api.password,
             'USER': config.api.username,
@@ -44,6 +45,12 @@
 
         return result
 
+    def fetch_donor_name(self, txn_id):
+        response = self.call('GetTransactionDetails', TRANSACTIONID=txn_id)
+        if 'FIRSTNAME' not in response:
+            raise RuntimeError("Failed to get transaction details for {id}, 
repsonse: {response}".format(id=txn_id, response=response))
+        return (response['FIRSTNAME'][0], response['LASTNAME'][0])
+
 
 # from 
http://stackoverflow.com/questions/1875052/using-paired-certificates-with-urllib2
 class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
diff --git a/audit/paypal/tests/test_trr_file.py 
b/audit/paypal/tests/test_trr_file.py
new file mode 100644
index 0000000..54f5dab
--- /dev/null
+++ b/audit/paypal/tests/test_trr_file.py
@@ -0,0 +1,83 @@
+from mock import patch
+import nose.tools
+
+import audit.paypal.TrrFile
+
+
+@patch("queue.redis_wrap.Redis")
+@patch("civicrm.civicrm.Civicrm")
+@patch("process.globals")
+@patch("audit.paypal.paypal_api.PaypalApiClassic")
+def test_recurring_charge_without_subscription(MockPaypalApi, MockGlobals, 
MockCivicrm, MockRedis):
+    '''
+    Regression test for T143903
+    '''
+    row = {
+        "Column Type": "",
+        "Transaction ID": "",
+        "Invoice ID": "",
+        "PayPal Reference ID": "",
+        "PayPal Reference ID Type": "SUB",
+        "Transaction Event Code": "T0002",
+        "Transaction Initiation Date": "",
+        "Transaction Completion Date": "",
+        "Transaction  Debit or Credit": "",
+        "Gross Transaction Amount": "10.00",
+        "Gross Transaction Currency": "",
+        "Fee Debit or Credit": "",
+        "Fee Amount": "",
+        "Fee Currency": "",
+        "Transactional Status": "",
+        "Insurance Amount": "",
+        "Sales Tax Amount": "",
+        "Shipping Amount": "",
+        "Transaction Subject": "",
+        "Transaction Note": "",
+        "Payer's Account ID": "",
+        "Payer Address Status": "",
+        "Item Name": "",
+        "Item ID": "",
+        "Option 1 Name": "",
+        "Option 1 Value": "",
+        "Option 2 Name": "",
+        "Option 2 Value": "",
+        "Auction Site": "",
+        "Auction Buyer ID": "",
+        "Auction Closing Date": "",
+        "Shipping Address Line1": "",
+        "Shipping Address Line2": "",
+        "Shipping Address City": "",
+        "Shipping Address State": "",
+        "Shipping Address Zip": "",
+        "Shipping Address Country": "",
+        "Shipping Method": "",
+        "Custom Field": "",
+        "Billing Address Line1": "",
+        "Billing Address Line2": "",
+        "Billing Address City": "",
+        "Billing Address State": "",
+        "Billing Address Zip": "",
+        "Billing Address Country": "",
+        "Consumer ID": "",
+        "First Name": "Malcolm",
+        "Last Name": "3X",
+        "Consumer Business Name": "",
+        "Card Type": "",
+        "Payment Source": "",
+        "Shipping Name": "",
+        "Authorization Review Status": "",
+        "Protection Eligibility": "",
+        "Payment Tracking ID": "",
+    }
+    MockCivicrm().transaction_exists.return_value = False
+    MockPaypalApi().fetch_donor_name.return_value = ("Malcolm", "3X")
+
+    parser = audit.paypal.TrrFile.TrrFile("dummy_path")
+    with nose.tools.assert_raises(Exception) as cm:
+        parser.parse_line(row)
+
+    # Should have failed with a specific missing field error.
+    assert cm.exception.message == "Missing field subscr_id"
+
+    # Make sure we didn't try to send anything to the queue.
+    MockRedis().send.assert_has_calls([])
diff --git a/process/globals.py b/process/globals.py
index 4b7825b..5173fd0 100644
--- a/process/globals.py
+++ b/process/globals.py
@@ -3,7 +3,8 @@
 
 from process.logging import Logger as log
 
-# n.b. Careful not to import `config` by value
+# n.b. Careful not to import `config` by value.  TODO: rename to _config to
+# break external usages.
 config = dict()
 
 

-- 
To view, visit https://gerrit.wikimedia.org/r/314509
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I866b1771f77989085e840a4eb2d320c5fb1a2f89
Gerrit-PatchSet: 1
Gerrit-Project: wikimedia/fundraising/tools
Gerrit-Branch: master
Gerrit-Owner: Awight <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to