此后的任何修改都是我存储了名为 token 的额外字段,该字段与 HATEOAS 链接一起传递。通过存储此令牌,我能够找到用户的待付款以继续执行。
更新:
这是实现细节。它可能并不完美,但它现在起到了作用。
class PayPalPayment(db.Model):
__tablename__ = 'paypal_payment'
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
product_id = db.Column(db.Integer, db.ForeignKey('product.id'))
payment_id = db.Column(db.String(30))
amount = db.Column(db.String(10))
state = db.Column(db.String(10))
token = db.Column(db.String(30))
redirect_url = db.Column(db.Text)
created_at = db.Column(db.DateTime)
updated_at = db.Column(db.DateTime)
def __init__(self, payment, product_id, user_id):
self.user_id = user_id
self.product_id = product_id
self.payment_id = payment.id
self.amount = payment.transactions[0].amount.total
self.state = payment.state
self.created_at = datetime.datetime.strptime(payment.create_time, "%Y-%m-%dT%H:%M:%SZ")
self.updated_at = datetime.datetime.strptime(payment.update_time, "%Y-%m-%dT%H:%M:%SZ")
for link in payment.links:
if link.method == "REDIRECT":
self.redirect_url = link.href
parsed = urlparse.urlparse(self.redirect_url)
self.token = urlparse.parse_qs(parsed.query)['token'][0]
@payment_view.route('/paypal', methods=['POST'])
@login_required
def paypal_payment():
user_id = current_user.get_id()
product = Product.query.filter_by(id=request.form.get('product')).first_or_404()
past = datetime.datetime.utcnow() - datetime.timedelta(minutes=3)
count = PayPalPayment.query.filter_by(user_id=user_id).filter_by(state='created').filter(PayPalPayment.created_at >= past).count()
# To prevent a spam where user creates Payment and never comes back to it
if count > 4:
return Response(render_template('payment/overflow.html'), mimetype='text/html')
payment = paypalrestsdk.Payment({
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": url_for('.payment_success', _external=True),
"cancel_url": url_for('.payment_cancel', _external=True)
},
"transactions": [{
"amount": {
"total": product.amount,
"currency": "USD"
},
"description": product.description
}]
})
if payment.create():
new_payment = PayPalPayment(payment, product.id, user_id)
db.session.add(new_payment)
db.session.commit()
return redirect(new_payment.redirect_url, code=302)
else:
return Response(render_template('payment/cancel.html'), mimetype='text/html')
@payment_view.route('/success')
@login_required
def payment_success():
user_id = current_user.get_id()
payerID = request.args.get('PayerID', None)
token = request.args.get('token', None)
pending_payment = PayPalPayment.query.filter_by(token=token).filter_by(state='created').first_or_404()
try:
payment = paypalrestsdk.Payment.find(pending_payment.payment_id)
except paypalrestsdk.exceptions.ResourceNotFound:
abort(404)
template = 'payment/error.html'
if payment.execute({"payer_id": request.args.get('PayerID')}):
pending_payment.state = payment.state
pending_payment.updated_at = datetime.datetime.strptime(payment.update_time, "%Y-%m-%dT%H:%M:%SZ")
template = 'payment/success.html'
db.session.commit()
return Response(render_template(template), mimetype='text/html')
请随时批评。