10. Cài đặt paypal
pip install django-oscar-paypal
Gói paypal có một số lỗi, bạn chạy lệnh dưới đây để sửa lỗi trước khi sử dụng
paypaldir=~/python-env/myshop/lib/python3.6/site-packages/paypal &&
sed -i 's,ppe\.message,six.text_type(ppe),' $paypaldir/express/views.py &&
sed -i '/import patterns/s/patterns,//;/urlpatterns =/s/patterns(.*$/[/;/^\s*)$/s/)/]/' \
$paypaldir/{payflow/dashboard/app,express/dashboard/app,express/urls}.py &&
sed -i '/load url/d' \
$paypaldir/templates/paypal/payflow/{transaction_detail,transaction_list}.html &&
sed -i '/load url/d' $paypaldir/templates/paypal/express/preview.html &&
sed -i '/load url/d' \
$paypaldir/templates/paypal/express/dashboard/{transaction_detail,transaction_list}.html
11. Fork chương trình Oscar
Oscar mặc định không cung cấp tích hợp thanh toán. Nhưng nó có các lớp lõi để chúng ta tùy biến, kế thừa. Tạo hai chương trình checkout và shipping cho dự án. Chương trình checkout tích hợp thanh toán và chương trình shipping tạo thêm phương thức vận chuyển. Chúng được sử dụng thay cho các chương trình tương ứng của Oscar. Việc này được gọi là fork chương trình hay tùy biến module.
mkdir apps &&
touch apps/__init__.py
python manage.py oscar_fork_app checkout apps
python manage.py oscar_fork_app shipping apps
Tạo tệp apps/app.py:
from oscar.app import Shop
from apps.checkout.app import application as checkout_app
class PayPalShop(Shop):
checkout_app = checkout_app
application = PayPalShop()
Tạo tệp apps/checkout/app.py:
from oscar.apps.checkout import app from apps.checkout import views class CheckoutApplication(app.CheckoutApplication): payment_details_view = views.PaymentDetailsView application = CheckoutApplication()
Tạo tệp apps/checkout/views.py:
from django.contrib import messages from django.http import HttpResponseRedirect from django.core.urlresolvers import reverse from oscar.apps.checkout import views from oscar.apps.payment import forms, models from paypal.payflow import facade class PaymentDetailsView(views.PaymentDetailsView): """ An example view that shows how to integrate BOTH Paypal Express (see get_context_data method)and Payppal Flow (the other methods). Naturally, you will only want to use one of the two. """ def get_context_data(self, **kwargs): """ Add data for Paypal Express flow. """ # Override method so the bankcard and billing address forms can be # added to the context. ctx = super(PaymentDetailsView, self).get_context_data(**kwargs) ctx['bankcard_form'] = kwargs.get( 'bankcard_form', forms.BankcardForm()) ctx['billing_address_form'] = kwargs.get( 'billing_address_form', forms.BillingAddressForm()) return ctx def post(self, request, *args, **kwargs): # Override so we can validate the bankcard/billingaddress submission. # If it is valid, we render the preview screen with the forms hidden # within it. When the preview is submitted, we pick up the 'action' # parameters and actually place the order. if request.POST.get('action', '') == 'place_order': return self.do_place_order(request) bankcard_form = forms.BankcardForm(request.POST) billing_address_form = forms.BillingAddressForm(request.POST) if not all([bankcard_form.is_valid(), billing_address_form.is_valid()]): # Form validation failed, render page again with errors self.preview = False ctx = self.get_context_data( bankcard_form=bankcard_form, billing_address_form=billing_address_form) return self.render_to_response(ctx) # Render preview with bankcard and billing address details hidden return self.render_preview(request, bankcard_form=bankcard_form, billing_address_form=billing_address_form) def do_place_order(self, request): # Helper method to check that the hidden forms wasn't tinkered with. bankcard_form = forms.BankcardForm(request.POST) billing_address_form = forms.BillingAddressForm(request.POST) if not all([bankcard_form.is_valid(), billing_address_form.is_valid()]): messages.error(request, "Invalid submission") return HttpResponseRedirect(reverse('checkout:payment-details')) # Attempt to submit the order, passing the bankcard object so that it # gets passed back to the 'handle_payment' method below. submission = self.build_submission() submission['payment_kwargs']['bankcard'] = bankcard_form.bankcard submission['payment_kwargs']['billing_address'] = billing_address_form.cleaned_data return self.submit(**submission) def handle_payment(self, order_number, total, **kwargs): """ Make submission to PayPal """ # Using authorization here (two-stage model). You could use sale to # perform the auth and capture in one step. The choice is dependent # on your business model. facade.authorize( order_number, total.incl_tax, kwargs['bankcard'], kwargs['billing_address']) # Record payment source and event source_type, is_created = models.SourceType.objects.get_or_create( name='PayPal') source = source_type.sources.model( source_type=source_type, amount_allocated=total.incl_tax, currency=total.currency) self.add_payment_source(source) self.add_payment_event('Authorised', total.incl_tax)
Nếu chỉ có 1 phương thức vận chuyển thì phương thức đó được chọn tự động và không trình bày trang lựa chọn phương thức vận chuyển trong chuỗi phân trang khi bắt đầu quá trình thanh toán. Các phương thức vận chuyển có thể tùy biến bằng cách viết đè lớp Repository. Bạn tạo tệp apps/shipping/repository.py:
from decimal import Decimal as D from oscar.apps.shipping.methods import Free, FixedPrice from oscar.apps.shipping.repository import Repository as CoreRepository class Repository(CoreRepository): """ This class is included so that there is a choice of shipping methods. Oscar's default behaviour is to only have one which means you can't test the shipping features of PayPal. """ methods = [Free(), FixedPrice(D('5.00'), D('5.00'))]
Trong lớp Repository mới, methods bao gồm 2 phương thức vận chuyển: phương thức miễn phí và phương thức giá cố định. Do đó khuôn mẫu ‘checkout/shipping_methods.html’ sẽ được trình bày.
12. Cập nhật settings.py
Thay
INSTALLED_APPS += get_core_apps()
Với
INSTALLED_APPS += [ 'paypal' ] + get_core_apps([ 'apps.shipping', 'apps.checkout',])
Bổ sung trạng thái tuyến khi một trạng thái đơn hàng thay đổi:
OSCAR_ORDER_STATUS_CASCADE = { 'Being processed': 'Being processed', 'Cancelled': 'Cancelled', 'Complete': 'Shipped', }
Thêm menu PayPal vào Dashboard:
from django.utils.translation import gettext_lazy as _ OSCAR_DASHBOARD_NAVIGATION.append( { 'label': _('PayPal'), 'icon': 'icon-globe', 'children': [ { 'label': _('PayFlow transactions'), 'url_name': 'paypal-payflow-list', }, { 'label': _('Express transactions'), 'url_name': 'paypal-express-list', }, ] })
Chúng ta sẽ giao dịch mua bán và trả tiền thực sự qua các tài khoản PayPal sandbox để test. Bạn cần tạo hai tài khoản PayPal sandbox: tài khoản loại kinh doanh cho chủ cửa hàng và tài khoản loại cá nhân cho người mua. Nhập thông tin tài khoản chủ cửa hàng như dưới đây. Nó là tài khoản có thật nhưng chỉ là ví dụ đối với bạn. Sau khi bạn đã xây dựng cửa hàng theo hướng dẫn, chỉ cần một bước duy nhất để tích hợp PayPal Express hoạt động:
PAYPAL_API_USERNAME = 'pham_api1.gmail.com' PAYPAL_API_PASSWORD = 'Z563RYZHEE6MAHT7' PAYPAL_API_SIGNATURE = 'A.CSYz4u5IILQm5wM0J0JbJiIcEuAj-2gwErolARWB-mVnzn.ISevDVm'
Thêm dòng cấu hình dưới đây để người mua có thể về được tới cửa hàng sau khi đã trả tiền tại PayPal, dù server phát triển đang sử dụng giao thức http. Cửa hàng sau đó sẽ trình bày chi tiết thanh toán:
PAYPAL_CALLBACK_HTTPS = False