Django Virtual Pos
==================
Django module that abstracts the flow of several virtual points of sale
including PayPal
What’s this?
-------------------------
This module abstracts the use of the most used virtual points of sale in
Spain.
License
-------------------------
`MIT LICENSE`_.
Implemented payment methods
----------------------------
Paypal
-------------------------
`Paypal`_ paypal payment available.
Bitpay
-------------------------
`Bitpay`_ bitcoin payments, from wallet to checkout
Spanish Virtual Points of Sale
------------------------------
- Ceca
`CECA`_ is the Spanish confederation of savings banks.
- RedSyS
`RedSyS`_ gives payment services to several Spanish banks like CaixaBank
or Caja Rural.
Santander Elavon
----------------
`Santander Elavon`_ is one of the payment methods of the Spanish bank
Santander.
Requirements and Installation
==============================
Requirements
----------------
- Python 2.7 (Python 3 not tested, contributors wanted!)
- ``Django``
- ``BeautifulSoup4``
- ``lxml``
- ``pycrypto``
- ``Pytz``
- ``Requests``
Type:
.. code:: sh
$ pip install django beautifulsoup4 lxml pycrypto pytz
Installation
----------------
From PyPi
----------------
.. code:: sh
$ pip install django-virtual-pos
From master branch
-------------------
Master branch will allways contain a working version of this module.
.. code:: sh
$ pip install git+git://github.com/intelligenia/django-virtual-pos.git
settings.py
-------------
Add the application djangovirtualpos to your settings.py:
.. code:: python
INSTALLED_APPS = (
# ...
"djangovirtualpos",
)
Use
----
See this ``manual`` (currently only in Spanish).
Needed models
-------------
You will need to implement this skeleton view using your own **Payment**
model.
This model has must have at least the following attributes: - **code**:
sale code given by our system. - **operation_number**: bank operation
number. - **status**: status of the payment: “paid”, “pending”
(**pending** is mandatory) or “canceled”. - **amount**: amount to be
charged.
And the following methods: - **online_confirm**: mark the payment as
paid.
Integration examples
-----------------------
- ``djshop``
Needed views
--------------
Sale summary view
------------------
.. code:: python
def payment_summary(request, payment_id):
"""
Load a Payment object and show a summary of its contents to the user.
"""
payment = get_object_or_404(Payment, id=payment_id, status="pending")
replacements = {
"payment": payment,
# ...
}
return render(request, '<sale summary template path>', replacements)
Note that this payment summary view should load a JS file called
**set_payment_attributes.js**.
This file is needed to set initial payment attributes according to which
bank have the user selected.
Payment_confirm view
-------------------------
.. code:: python
@csrf_exempt
def payment_confirmation(request, virtualpos_type):
"""
This view will be called by the bank.
"""
# Directly call to confirm_payment view
# Or implement the following actions
# Checking if the Point of Sale exists
virtual_pos = VirtualPointOfSale.receiveConfirmation(request, virtualpos_type=virtualpos_type)
if not virtual_pos:
# The VPOS does not exist, inform the bank with a cancel
# response if needed
return VirtualPointOfSale.staticResponseNok(virtualpos_type)
# Verify if bank confirmation is indeed from the bank
verified = virtual_pos.verifyConfirmation()
operation_number = virtual_pos.operation.operation_number
with transaction.atomic():
try:
# Getting your payment object from operation number
payment = Payment.objects.get(operation_number=operation_number, status="pending")
except Payment.DoesNotExist:
return virtual_pos.responseNok("not_exists")
if verified:
# Charge the money and answer the bank confirmation
try:
response = virtual_pos.charge()
# Implement the online_confirm method in your payment
# this method will mark this payment as paid and will
# store the payment date and time.
payment.online_confirm()
except VPOSCantCharge as e:
return virtual_pos.responseNok(extended_status=e)
except Exception as e:
return virtual_pos.responseNok("cant_charge")
else:
# Payment could not be verified
# signature is not right
response = virtual_pos.responseNok("verification_error")
return response
Payment ok view
-------------------------
.. code:: python
def payment_ok(request, sale_code):
"""
Informs the user that the payment has been made successfully
:param payment_code: Payment code.
:param request: request.
"""
# Load your Payment model given its code
payment = get_object_or_404(Payment, code=sale_code, status="paid")
context = {'pay_status': "Done", "request": request}
return render(request, '<payment_ok template>', {'context': context, 'payment': payment})
Payment cancel view
--------------------
.. code:: python
def payment_cancel(request, sale_code):
"""
Informs the user that the payment has been canceled
:param payment_code: Payment code.
:param request: request.
"""
# Load your Payment model given its code
payment = get_object_or_404(Payment, code=sale_code, status="pending")
# Mark this payment as canceled
payment.cancel()
context = {'pay_status': "Done", "request": request}
return render(request, '<payment_canceled template>', {'context': context, 'payment': payment})
Refund view
-----------
.. code:: python
def refund(request, tpv, payment_code, amount, description):
"""
:param request:
:param tpv: TPV Id
:param payment_code: Payment code
:param amount: Refund Amount (Example 10.89).
:param description: Description of refund cause.
:return:
"""
amount = Decimal(amount)
try:
# Checking if the Point of Sale exists
tpv = VirtualPointOfSale.get(id=tpv)
# Checking if the Payment exists
payment = Payment.objects.get(code=payment_code, state="paid")
except Payment.DoesNotExist as e:
return http_bad_request_response_json_error(message=u"Does not exist payment with code {0}".format(payment_code))
refund_status = tpv.refund(payment_code, amount, description)
if refund_status:
message = u"Refund successful"
else:
message = u"Refund with erros"
return http_response_json_ok(message)
Authors
===============
- Mario Barchéin marioREMOVETHIS@REMOVETHISintelligenia.com
- Diego J. Romero diegoREMOVETHIS@REMOVETHISintelligenia.com
Remove REMOVETHIS to contact the authors.
.. _MIT LICENSE: LICENSE
.. _Paypal: https://www.paypal.com/
.. _Bitpay: http://bitpay.com
.. _CECA: http://www.cajasdeahorros.es/
.. _RedSyS: http://www.redsys.es/
.. _Santander Elavon: https://www.santanderelavon.com/
.. _Django: https://pypi.python.org/pypi/django
.. _BeautifulSoup4: https://pypi.python.org/pypi/beautifulsoup4
.. _lxml: https://pypi.python.org/pypi/lxml
.. _pycrypto: https://pypi.python.org/pypi/pycrypto
.. _Pytz: https://pypi.python.org/pypi/pytz
.. _Requests: https://pypi.python.org/pypi/requests
.. _manual: manual/COMMON.md
.. _djshop: https://github.com/diegojromerolopez/djshop