Package: django-cybersource-hosted-checkout
Django CyberSource Hosted CheckoutThis package provides utilities for using CyberSource Secure Acceptance Hosted Checkout.CyberSource Secure Acceptance Hosted Checkout is a round-trip process: you start the payment on your server, then pass off to CyberSource. At the end of the transaction, CyberSource returns to your server at a URL you configure.We assume you have a working knowledge of the product and profiles; you canread the CyberSource manual here.The heavy lifting it does is properly creating thesigned_date_time,fields_to_sign, andsignaturefields and automatically include them in thePOST, along with any fields you need to pass along.If you don't feel like making your eyes bleed with that awful PDF above, here's a TL;DR.Create Your CyberSource ProfileYou'll have to do this in both the CyberSource TEST and LIVE environments. Start with TEST. The process is the same.Log in here:https://businesscenter.cybersource.com/ebc/login/UnderTools & Settings, clickProfiles, thenCreate New Profile.Fill in the form and clickSave. Then click the profile name you just created to edit it further.Copy yourProfile IDfrom this screen into your Django settings asCYBERSOURCE_PROFILE_ID. You will notice there are eight sections you can modify. I will only cover the required areas here.Payment Settings: enter at least oneCard Typewith at least oneCurrencyassociated with it.Security: clickCreate New Key. Copy theAccess KeyandSecret Keyvalues to your Django settings asCYBERSOURCE_ACCESS_KEYandCYBERSOURCE_SECRET_KEYrespectively.Customer Response Pages: forTransaction Response Page, selectHosted by you, and enter a route that you will create later in Django, such ashttps://www.mysite.com/orders/payment-response/Once you have completed all of the fields, be sure toActivatethe profile!Install Django CyberSource Hosted CheckoutFirst,pip install django-cybersource-hosted-checkout, and add'cybersource_hosted_checkout'to yourINSTALLED_APPSlist.If you're going to be using the examples below to get started, you'll also need topip install django-braces.SettingsThese settings are required to be present in Django's settings.CYBERSOURCE_URLFor CyberSource's TEST Environment:https://testsecureacceptance.cybersource.com/payFor CyberSource's LIVE Environment:https://secureacceptance.cybersource.com/payCYBERSOURCE_PROFILE_ID= '[Your CyberSource Profile ID]'CYBERSOURCE_ACCESS_KEY= '[Your CyberSource Access Key]'CYBERSOURCE_SECRET_KEY= '[Your CyberSource Secret Key]'Code and Configurationmodels.pyIn this example, we will be charging a user of our Django site $19.95 in U.S. dollars to purchase a course.First, create a model in an app in your Django project which inherits fromAbstractCyberSourceTransaction; the abstract model stores a unique identifier, a transaction UUID, a time stamp of when the transaction is created in Django, and another time stamp of when it is completed from CyberSource. You can add any additional fields you wish to track and store. In this example, we are addinguserandcourse, so we can complete the transaction after payment. Thenmakemigrationsandmigrate.fromdjango.dbimportmodelsfromcybersource_hosted_checkout.modelsimportAbstractCyberSourceTransactionclassCyberSourceTransaction(AbstractCyberSourceTransaction):"""Stores credit card transaction receipts made with CyberSource."""user=models.ForeignKey(User,on_delete=models.CASCADE)course=models.ForeignKey(Course,on_delete=models.PROTECT)views.pyHere, we leverage a DjangoFormView, and inform_valid()we call the functions and render the template which will automatically prepare the data for CyberSource and POST it to their server. Thefieldsdictionary contains CyberSource specific fields required to perform a transaction. You can see a full list in the manual; the example below is for a one-time purchase of the course for $19.95.importdatetimefromuuidimportuuid4fromdjango.confimportsettingsfromdjango.contribimportmessagesfromdjango.contrib.messages.viewsimportSuccessMessageMixinfromdjango.viewsimportViewfromdjango.views.genericimportFormViewfrombracesimportLoginRequiredMixin,CsrfExemptMixinfrommy_app.modelsimportCyberSourceTransactionclassAddCourseView(LoginRequiredMixin,SuccessMessageMixin,FormView):template_name='my_app/transaction.html'form_class=TransactionFormsuccess_url=reverse_lazy('home')success_message="Your transaction has been completed."defform_valid(self,form,request,**kwargs):# Get the proverbial `course` from the database based on something in the form.course=Course.objects.get(course_code=form.cleaned_data['course_code'])# Create a transaction in the database before we pass to CyberSource;# we will update this with a timestamp on return from CyberSourcetransaction_uuid=uuid4().hextransaction=CyberSourceTransaction()transaction.transaction_uuid=transaction_uuidtransaction.user=request.usertransaction.course=coursetransaction.save()# Fields to pass to CyberSource - see manual for a full listfields={}fields['profile_id']=settings.CYBERSOURCE_PROFILE_IDfields['access_key']=settings.CYBERSOURCE_ACCESS_KEYfields['amount']='19.95'fields['transaction_uuid']=transaction_uuidfields['bill_to_forename']=request.user.first_namefields['bill_to_surname']=request.user.last_namefields['bill_to_email']=request.user.emailfields['locale']='en-us'fields['currency']='usd'fields['transaction_type']='sale'fields['reference_number']=transaction.idcontext=super().get_context_data(**kwargs)context=sign_fields_to_context(fields,context)# Render a page which POSTs to CyberSource via JavaScript.returnrender(request,'cybersource_hosted_checkout/post_to_cybersource.html',context=context,)classCyberSourceResponseView(CsrfExemptMixin,View):"""Recevies a POST from CyberSource and redirects to home."""defpost(self,request):ifrequest.POST.get('decision').upper()=='ACCEPT':# Success! Add the course by getting the transaction we started.# Check both reference number and UUID since we're not requiring# a login.transaction=CyberSourceTransaction.objects.get(id=request.POST.get('req_reference_number'),uuid=request.POST.get('req_transaction_uuid'),)transaction.return_from_cybersource=datetime.datetime.now()# Here is where you'll put your code in place of this dummy function.add_course_for_user(transaction.course,transaction.user,request)messages.success(request,'Your payment was successful and the course has been added. Happy trading!',)transaction.save()else:# Uh oh, unsuccessful payment.messages.error(request,'Sorry, your payment was not successful.',)returnredirect(reverse_lazy('home'))TheAddCourseViewclass will display your purchase form, and when it is valid, pass the necessary fields to CyberSource to display their checkout page.TheCyberSourceResponseViewis the class for the view that is run after a successful checkout from CyberSource. After successfully completing a purchase, the user will then be directed back to the route you put in your CyberSource profile (in the example,https://www.mysite.com/orders/payment-response/), where we mark the transaction as complete by updating the timestampreturn_from_cybersourceto mark the transaction complete.urls.pyWe need to plug our views into routes that match CyberSource.fromdjango.urlsimportpathfrommyapp.viewsimportMyHomeView,AddCourseView,CyberSourceResponseViewurlpatterns=[path('',MyHomeView.as_view(),name='home'),path('orders/buy-course/',AddCourseView.as_view(),name='add-course'),path('orders/payment-response/',CyberSourceResponseView.as_view(),name='add-course-cybersource-response'),]Running Testsgitclonegit@github.com:wharton/django-cybersource-hosted-checkout.git
mkvirtualenvtest-cybersourcecddjango-cybersource-hosted-checkout/testproject
pipinstall-rrequirements.txt
coveragerun--source='..'manage.pytestcybersource_hosted_checkout
coveragereportRelease Notes0.0.1 - 0.0.6Initial release, tests, and documentation improvements.ContributorsTimothy Allen (https://github.com/FlipperPA)