Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation #23

Merged
merged 18 commits into from
Jul 28, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -2,8 +2,10 @@
sample_project/local_settings.py
sample_project/dev.db
*.egg-info
*.egg
build/
dist/
.coverage
.tox
htmlcov
docs/_build/
10 changes: 8 additions & 2 deletions .travis.yml
@@ -1,12 +1,13 @@
language: python

python:
- "2.6"
- "2.7"
- 2.6
- 2.7

env:
- DJANGO=Django==1.4.2
- DJANGO=Django==1.5.0
- DJANGO=https://github.com/django/django/tarball/stable/1.6.x
- DJANGO=https://github.com/django/django/tarball/master

install:
Expand All @@ -17,4 +18,9 @@ script:
- coverage run -a setup.py test
- coverage report

matrix:
exclude:
- python: 2.6
env: DJANGO=https://github.com/django/django/tarball/master

after_success: coveralls
51 changes: 51 additions & 0 deletions CONTRIBUTING.rst
@@ -0,0 +1,51 @@
Contributing
============

Below is a list of tips for submitting issues and pull requests. These are
suggestions and not requirements.

Submitting Issues
-----------------

Issues are often easier to reproduce/resolve when they have:

- A pull request with a failing test demonstrating the issue
- A code example that produces the issue consistently
- A traceback (when applicable)

Pull Requests
-------------

When creating a pull request, try to:

- Write tests if applicable
- Update the `README`_ file if needed
- Update the documentation if needed

.. _README: README.rst

Testing
-------

Please add tests for your code and ensure existing tests don't break. To run
the tests against your code::

python setup.py test

Please use tox to test the code against supported Python and Django versions.
First install tox::

pip install tox

To run tox and generate a coverage report (in ``htmlcov`` directory)::

make test

Generating documentation
------------------------

To regenerate the documentation use::

make docs

The generated documentation HTML files can be found in ``docs/_build/html``.
14 changes: 14 additions & 0 deletions Makefile
@@ -0,0 +1,14 @@
all: init test sphinx

init:
easy_install tox coverage Sphinx

test:
coverage erase
tox
coverage html

docs: sphinx

sphinx:
python setup.py build_sphinx
18 changes: 17 additions & 1 deletion authorizenet/conf.py
@@ -1,4 +1,20 @@
"""Application-specific settings for django-authorizenet"""
"""
Application-specific settings for django-authorizenet

Available settings:

- AUTHNET_DEBUG: Set to ``True`` if using Authorize.NET test account
- AUTHNET_LOGIN_ID: Set to value of Authorize.NET login ID
- AUTHNET_TRANSACTION_KEY: Set to value of Authorize.NET transaction key
- AUTHNET_CUSTOMER_MODEL: Used to set customer model used for CIM customers
(defaults to Django user)
- AUTHNET_DELIM_CHAR: Used to set delimiter character for CIM requests
(defaults to "|")
- AUTHNET_FORCE_TEST_REQUEST
- AUTHNET_EMAIL_CUSTOMER
- AUTHNET_MD5_HASH

"""

from django.conf import settings as django_settings

Expand Down
21 changes: 20 additions & 1 deletion authorizenet/models.py
Expand Up @@ -127,6 +127,9 @@ def create_from_list(self, items):


class Response(models.Model):

"""Transaction Response (See Section 4 of AIM Developer Guide)"""

response_code = models.CharField(max_length=2, choices=RESPONSE_CHOICES)
response_subcode = models.CharField(max_length=10)
response_reason_code = models.CharField(max_length=15)
Expand Down Expand Up @@ -193,6 +196,9 @@ def __unicode__(self):


class CIMResponse(models.Model):

"""Response for CIM API call (See Section 3 in CIM XML Guide)"""

result = models.CharField(max_length=8)
result_code = models.CharField(max_length=8,
choices=CIM_RESPONSE_CODE_CHOICES)
Expand All @@ -218,6 +224,7 @@ class CustomerProfile(models.Model):
profile_id = models.CharField(max_length=50)

def save(self, *args, **kwargs):
"""If creating new instance, create profile on Authorize.NET also"""
data = kwargs.pop('data', {})
sync = kwargs.pop('sync', True)
if not self.id and sync:
Expand All @@ -231,6 +238,7 @@ def delete(self):
super(CustomerProfile, self).delete()

def push_to_server(self, data):
"""Create customer profile for given ``customer`` on Authorize.NET"""
output = add_profile(self.customer.pk, data, data)
output['response'].raise_if_error()
self.profile_id = output['profile_id']
Expand Down Expand Up @@ -281,13 +289,22 @@ def __init__(self, *args, **kwargs):
return super(CustomerPaymentProfile, self).__init__(*args, **kwargs)

def save(self, *args, **kwargs):
"""Sync payment profile on Authorize.NET if sync kwarg is not False"""
if kwargs.pop('sync', True):
self.push_to_server()
self.card_code = None
self.card_number = "XXXX%s" % self.card_number[-4:]
super(CustomerPaymentProfile, self).save(*args, **kwargs)

def push_to_server(self):
"""
Use appropriate CIM API call to save payment profile to Authorize.NET

1. If customer has no profile yet, create one with this payment profile
2. If payment profile is not on Authorize.NET yet, create it there
3. If payment profile exists on Authorize.NET update it there

"""
if not self.customer_profile_id:
try:
self.customer_profile = CustomerProfile.objects.get(
Expand All @@ -301,13 +318,15 @@ def push_to_server(self):
self.raw_data,
self.raw_data,
)
response.raise_if_error()
elif self.customer_profile_id:
output = create_payment_profile(
self.customer_profile.profile_id,
self.raw_data,
self.raw_data,
)
response = output['response']
response.raise_if_error()
self.payment_profile_id = output['payment_profile_id']
else:
output = add_profile(
Expand All @@ -316,13 +335,13 @@ def push_to_server(self):
self.raw_data,
)
response = output['response']
response.raise_if_error()
self.customer_profile = CustomerProfile.objects.create(
customer=self.customer,
profile_id=output['profile_id'],
sync=False,
)
self.payment_profile_id = output['payment_profile_ids'][0]
response.raise_if_error()

@property
def raw_data(self):
Expand Down
10 changes: 10 additions & 0 deletions authorizenet/views.py
Expand Up @@ -126,6 +126,12 @@ def validate_payment_form(self):


class PaymentProfileCreateView(CreateView):
"""
View for creating a CustomerPaymentProfile instance

CustomerProfile instance will be created automatically if needed.
"""

template_name = 'authorizenet/create_payment_profile.html'
form_class = CustomerPaymentForm

Expand All @@ -136,6 +142,10 @@ def get_form_kwargs(self):


class PaymentProfileUpdateView(UpdateView):
"""
View for modifying an existing CustomerPaymentProfile instance
"""

template_name = 'authorizenet/update_payment_profile.html'
form_class = CustomerPaymentForm

Expand Down
26 changes: 26 additions & 0 deletions docs.rst
@@ -0,0 +1,26 @@
Usage
=====

Installation
------------

Install from `PyPI`_:

.. code-block:: bash

$ pip install django-authorizenet

.. _PyPI: https://pypi.python.org/pypi/django-authorizenet/


Quickstart
----------

Add ``authorizenet`` to ``INSTALLED_APPS`` in your settings file:

.. code-block:: python

INSTALLED_APPS = (
...
'authorizenet',
)