-
Notifications
You must be signed in to change notification settings - Fork 0
/
payment.py
154 lines (130 loc) · 5.76 KB
/
payment.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from helpers import decorate_all_methods, return_status
from visa_api import visa_api_call
from flask import request
from flask_restful import Resource
from db import PaymentSchema
from db import database
from datetime import datetime
import requests
import json
import os
from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Mail
from firebase_admin import auth
# Testing visa API calls
def visa_push_funds(json):
url = 'https://sandbox.api.visa.com/visadirect/fundstransfer/v1/pushfundstransactions'
headers = {"Content-Type":"application/json", "Accept":"application/json"}
x = visa_api_call(url, methodType=requests.post, headers=headers, json=json)
return x
def visa_pull_funds(json):
url = 'https://sandbox.api.visa.com/visadirect/fundstransfer/v1/pullfundstransactions'
headers = {"Content-Type":"application/json", "Accept":"application/json"}
x = visa_api_call(url, methodType=requests.post, headers=headers, json=json)
return x
def send_confirmation(email, data):
# Send confirmation Email
message = Mail(
from_email='[email protected]',
to_emails=email
)
message.dynamic_template_data = data
message.template_id = 'd-2a96789c5f1c4ee5a612d632f7704937'
try:
sg = SendGridAPIClient(os.getenv('SENDGRID_API_KEY'))
response = sg.send(message)
except Exception as e:
print(e)
@decorate_all_methods(return_status)
class Payment(Resource):
def post(self):
# verify JSON with schema
load_json = request.json
if load_json is None:
load_json = json.loads(request.data)
sender_json = PaymentSchema().load(load_json)
print(str(sender_json))
# Get the invoices obj from the given code
code = sender_json['invoiceId']
doc_ref = database.collection(u'invoices').document(code)
doc = doc_ref.get()
assert doc.exists, 'Record doesn\'t exist with given invoiceId'
invoice = doc.to_dict()
# Check if the invoice has merchantId
merchant_doc = None
merchant_doc_ref = None
if 'merchantId' in invoice:
merchant_doc_ref = database.collection(u'merchants').document(invoice['merchantId'])
merchant_doc = merchant_doc_ref.get()
assert merchant_doc.exists, 'Invalid merchantId'
invoice['email'] = auth.get_user(invoice['merchantId']).email
del invoice['merchantId']
invoice = dict(invoice, **merchant_doc.to_dict()['paymentInfo'])
# Get the tip
tip = 0 if 'tip' not in sender_json else sender_json['tip']
# Get the date and audit number
now = datetime.now()
auditNumber = str(hash(sender_json['invoiceId']) % 1000000).zfill(6)
retrievalReferenceNumber = now.strftime("%y")[1] + now.strftime("%j%H") + auditNumber
# Build the push json to send
api_json = {
"amount": "%.2f" % float(tip + sum([float(item['amount']) for item in invoice['items']])),
"recipientPrimaryAccountNumber": invoice['PAN'],
"localTransactionDateTime": now.strftime('%Y-%m-%dT%H:%M:%S'),
"retrievalReferenceNumber": retrievalReferenceNumber,
"systemsTraceAuditNumber": auditNumber,
"acquirerCountryCode": "840",
"acquiringBin": os.getenv("acquiringBin"),
"businessApplicationId": "AA",
"cardAcceptor": {
"address": {
"country": "USA",
"state": "CA",
"zipCode": "94404"
},
"idCode": "CA-IDCode-77765",
"name": "Visa Inc. USA-Foster City",
"terminalId": "TID-9999"
}
}
print('amount', api_json['amount'])
pull_api_json = dict({
'senderPrimaryAccountNumber': sender_json['senderPAN'],
"acquirerCountryCode": "840",
"senderCurrencyCode":"USD",
"senderCardExpiryDate": "2015-10",
"cpsAuthorizationCharacteristicsIndicator": "Y"
}, **api_json)
push_api_json = dict({
'senderAccountNumber': sender_json['senderPAN'],
"transactionCurrencyCode": "USD"
}, **api_json)
# Build the pull json to send
pull_res = visa_pull_funds(pull_api_json)
pull_res_json = json.loads(pull_res.content)
pull_res_err = str(pull_res_json)
if 'errorMessage' in pull_res_json:
pull_res_err = pull_res_json['errorMessage']
assert pull_res.status_code == 200, '{\"senderPAN\":[\"Pull: '+ str(pull_res_err) +'\"]}'
push_res = visa_push_funds(push_api_json)
push_res_json = json.loads(push_res.content)
push_res_err = str(push_res_json)
if 'errorMessage' in push_res_json:
push_res_err = push_res_json['errorMessage']
assert push_res.status_code == 200, '{\"senderPAN\":[\"Push: '+ str(push_res_err) +'\"]}'
data = {
'invoiceId': code,
'total': str(format(tip + sum([float(item['amount']) for item in invoice['items']]), ".2f")),
'items': [{"amount":"%.2f" % item['amount'], "desc":item['desc']} for item in invoice['items']]
}
send_confirmation(invoice['email'], data)
if 'email' in sender_json:
send_confirmation(sender_json['email'], data)
# Add the tip to the total if they're signed in
if merchant_doc_ref is not None and 'tip' in sender_json:
currTotal = merchant_doc.to_dict()['tipsTotal']
# issue: This could result in concurrent inconsistency
merchant_doc_ref.update({'tipsTotal': currTotal + tip})
# Delete the invoice now that payment is successful
doc_ref.delete()
return push_res.json()