Django e-commerce part74 Run Braintree Transaction
Bratintreeのtransactionを試してみる。
Braintreeのtokenを処理するClient を自分たちのサイトに設定する。
公式ドキュメント参照:
Set Up Your Client | JS - Braintree Developer Documentation
templates/javascript.html に追記する。
ちょっとjsv3は難しそうだったので、v2でやってみる。
<script src="https://js.braintreegateway.com/js/braintree-2.29.0.min.js"></script>
checkout_view.html にjavascriptをコピペしてみる。
<script> {% block jquery %} var clientToken = "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiJjMTA5MzkyMWZjMGVkOTZkYWRjMTgwY2I5NzAwMmI5ODkwMGE2ZWE2ZmMxNzEwMzU5MGYwOGQ5NjVjZjFiNzE5fGNyZWF0ZWRfYXQ9MjAxNi0xMC0xMlQwMDoyMjo1NS43NDM2MDE4MDMrMDAwMFx1MDAyNm1lcmNoYW50X2lkPTM0OHBrOWNnZjNiZ3l3MmJcdTAwMjZwdWJsaWNfa2V5PTJuMjQ3ZHY4OWJxOXZtcHIiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMvMzQ4cGs5Y2dmM2JneXcyYi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJjaGFsbGVuZ2VzIjpbXSwiZW52aXJvbm1lbnQiOiJzYW5kYm94IiwiY2xpZW50QXBpVXJsIjoiaHR0cHM6Ly9hcGkuc2FuZGJveC5icmFpbnRyZWVnYXRld2F5LmNvbTo0NDMvbWVyY2hhbnRzLzM0OHBrOWNnZjNiZ3l3MmIvY2xpZW50X2FwaSIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vY2xpZW50LWFuYWx5dGljcy5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tLzM0OHBrOWNnZjNiZ3l3MmIifSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwicGF5cGFsRW5hYmxlZCI6dHJ1ZSwicGF5cGFsIjp7ImRpc3BsYXlOYW1lIjoiQWNtZSBXaWRnZXRzLCBMdGQuIChTYW5kYm94KSIsImNsaWVudElkIjpudWxsLCJwcml2YWN5VXJsIjoiaHR0cDovL2V4YW1wbGUuY29tL3BwIiwidXNlckFncmVlbWVudFVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS90b3MiLCJiYXNlVXJsIjoiaHR0cHM6Ly9hc3NldHMuYnJhaW50cmVlZ2F0ZXdheS5jb20iLCJhc3NldHNVcmwiOiJodHRwczovL2NoZWNrb3V0LnBheXBhbC5jb20iLCJkaXJlY3RCYXNlVXJsIjpudWxsLCJhbGxvd0h0dHAiOnRydWUsImVudmlyb25tZW50Tm9OZXR3b3JrIjp0cnVlLCJlbnZpcm9ubWVudCI6Im9mZmxpbmUiLCJ1bnZldHRlZE1lcmNoYW50IjpmYWxzZSwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJtZXJjaGFudEFjY291bnRJZCI6ImFjbWV3aWRnZXRzbHRkc2FuZGJveCIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9LCJjb2luYmFzZUVuYWJsZWQiOmZhbHNlLCJtZXJjaGFudElkIjoiMzQ4cGs5Y2dmM2JneXcyYiIsInZlbm1vIjoib2ZmIn0="; braintree.setup(clientToken, "dropin", { container: "payment-form" }); {% endblock %} </script>
この、clientToken は、例なので、この部分にclient_tokenを代入する。
<script> {% block jquery %} var clientToken = "{{ client_token }}"; braintree.setup(clientToken, "dropin", { container: "payment-form" }); {% endblock %} </script>
checkout_view.html にbraintreeのフォームを入れてみる。
公式マニュアルよりそのままコピペしてみる。
<form id="checkout" method="post" action="/checkout"> <div id="payment-form"></div> <input type="submit" value="Pay $10"> </form>
これを既存の注文確定ボタンと合体させると以下のようになる。
<form id="checkout" method='POST' action="{% url 'checkout_final' %}">{% csrf_token %} <!-- <input type='hidden' name='payment_token' value='ABC' /> --> <div id="payment-form"></div> <p><b><button type='submit'>注文を確定する</button></b> </p> </form>
payment_tokenはコメントアウトしてある。
これで、checkout画面に行くと、braintreeのフォームが表示される。
CheckoutFinalView にpostの内容をprintさせる。
class CheckoutFinalView(CartOrderMixin, View): def post(self, request, *args, **kwargs): print (request.POST)
これで、postされた内容が確認できる。以下のような辞書がprintされていると思われる。
<QueryDict: {'payment_method_nonce': ['****-0c55-42a9-9588-*****'], 'csrfmiddlewaretoken': ['*******************']}>
この、payment_method_nonce というのが、braintree側に送付され、これがキーとなって、取引の決済がされるはず。
Transaction Sale を追加してみる。
公式ドキュメント:
Transaction.sale() | Python - Braintree Developer Documentation
result = braintree.Transaction.sale({ "amount": "10.00", "payment_method_nonce": nonce_from_the_client, "options": { "submit_for_settlement": True } })
これをCheckoutFinalViewに組み込んでみる。 この辺りの公式ドキュメントを参照:
Transaction.sale() | Python - Braintree Developer Documentation
class CheckoutFinalView(CartOrderMixin, View): def post(self, request, *args, **kwargs): order = self.get_order() order_total = order.order_total nonce = request.POST.get("payment_method_nonce") if nonce: result = braintree.Transaction.sale({ "amount": order_total, "payment_method_nonce": nonce, "billing": { "postal_code": "%s" %(order.billing_address.zipcode), }, "options": { "submit_for_settlement": True } }) if result.is_success: print (result.transaction.id) # result.transaction.id to order order.mark_completed() messages.success(request, "ご注文ありがとうございました。") del request.session["cart_id"] del request.session["order_id"] else: messages.success(request, "%s" %(result.message)) return redirect("checkout") return redirect("orders_detail", pk=order.pk)
ポイント
- 全体的な流れとしては、決済した時に生成されるpayment_method_nonceを、keyにして、braintree.Transaction.saleを実行し、resultがサクセスだった場合は、orderをcompletedにして、cart_idなどをセッションから削除する。
braintreeの設定をviewにimportする。
import braintree from django.conf import settings if settings.DEBUG: braintree.Configuration.configure(braintree.Environment.Sandbox, merchant_id=settings.BRAINTREE_MERCHANT, public_key=settings.BRAINTREE_PUBLIC, private_key=settings.BRAINTREE_PRIVATE)
orders/models.py に、braintreeのtransaction.idを格納する、order_idフィールドを作成する。
ついで、statusもpaidと、shippedに変更しておく。
ORDER_STATUS_CHOICES = ( ('created', 'Created'), ('paid','Paid'), ('shipped','Shipped'), ) class Order(models.Model): status = models.CharField(max_length=120, choices=ORDER_STATUS_CHOICES, default='created') ... order_id = models.CharField(max_length=20, null=True, blank=True) ... def mark_completed(self): self.status = "paid" self.save()
さらに、mark_completed()に少し追記する。
def mark_completed(self, order_id=None): self.status = "paid" if order_id and not self.order_id: self.order_id = order_id self.save()
- これは、order_idがすでにある場合は、上書きしないような設定にしている と思われる。
CheckoutFinalViewに追記する。
class CheckoutFinalView(CartOrderMixin, View): ... if result.is_success: order.mark_completed(order_id=result.transaction.id)
- result.is_success がtrueの時は、status=paid, order_idには、transaction.idがセットされるように設定してある。