├── wm_sample
├── __init__.py
├── templates
│ ├── wm_sample
│ │ ├── base.html
│ │ ├── simple_payment_desc.txt
│ │ ├── fail.html
│ │ ├── success.html
│ │ └── simple_payment.html
│ └── base.html
├── management
│ └── __init__.py
├── manage.py
├── helpers.py
├── urls.py
├── views.py
└── settings.py
├── webmoney
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── clean_webmoney.py
├── signals.py
├── urls.py
├── __init__.py
├── admin.py
├── forms.py
├── views.py
└── models.py
├── .gitignore
├── README.rst
├── setup.py
└── LICENSE
/wm_sample/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webmoney/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webmoney/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wm_sample/templates/wm_sample/base.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
--------------------------------------------------------------------------------
/wm_sample/templates/wm_sample/simple_payment_desc.txt:
--------------------------------------------------------------------------------
1 | payment for account {{ request.user }}.
2 |
--------------------------------------------------------------------------------
/webmoney/signals.py:
--------------------------------------------------------------------------------
1 | from django.dispatch import Signal
2 |
3 | webmoney_payment_accepted = Signal(providing_args=["payment"])
4 |
--------------------------------------------------------------------------------
/wm_sample/templates/wm_sample/fail.html:
--------------------------------------------------------------------------------
1 | {% extends "wm_sample/base.html" %}
2 |
3 | {% block content %}
4 | Payment failed.
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | *.pyc
3 | semantic.cache
4 | .ropeproject/
5 | /build/
6 | /dist/
7 | /django_payment_webmoney.egg-info/
8 | /wm_sample/wm_sample.db
9 |
--------------------------------------------------------------------------------
/wm_sample/templates/wm_sample/success.html:
--------------------------------------------------------------------------------
1 | {% extends "wm_sample/base.html" %}
2 |
3 | {% block content %}
4 | Your payment number {{ id }} is successfully procceded at {{ date|date:"Y.m.d H:i" }}.
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/wm_sample/templates/wm_sample/simple_payment.html:
--------------------------------------------------------------------------------
1 | {% extends "wm_sample/base.html" %}
2 |
3 | {% block content %}
4 |
5 |
9 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/wm_sample/management/__init__.py:
--------------------------------------------------------------------------------
1 | from webmoney.signals import webmoney_payment_accepted
2 |
3 |
4 | def webmoney_payment_accepted_processor(sender, payment, **kwargs):
5 | print payment
6 |
7 |
8 | webmoney_payment_accepted.connect(
9 | webmoney_payment_accepted_processor, sender=None)
10 |
--------------------------------------------------------------------------------
/wm_sample/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import os
4 | import sys
5 |
6 | if __name__ == "__main__":
7 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
8 |
9 | from django.core.management import execute_from_command_line
10 |
11 | execute_from_command_line(sys.argv)
12 |
--------------------------------------------------------------------------------
/webmoney/urls.py:
--------------------------------------------------------------------------------
1 | try:
2 | from django.conf.urls import patterns, url
3 | except ImportError:
4 | from django.conf.urls.defaults import patterns, url
5 |
6 | from webmoney.views import result
7 |
8 | urlpatterns = patterns(
9 | '',
10 | url(r'^result/$', result, name='webmoney-result'),
11 | )
12 |
--------------------------------------------------------------------------------
/webmoney/__init__.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | VERSION = (0, 3, 0, "final")
4 | PURSE_RE = re.compile(ur'^(?P[ZREUYBGDC])(?P\d{12})$')
5 | WMID_RE = re.compile(ur'^\d{12}$')
6 |
7 |
8 | def get_version():
9 | if VERSION[3] != "final":
10 | return "%s.%s.%s%s" % (VERSION[0], VERSION[1], VERSION[2], VERSION[3])
11 | else:
12 | return "%s.%s.%s" % (VERSION[0], VERSION[1], VERSION[2])
13 |
14 |
15 | __version__ = get_version()
16 |
--------------------------------------------------------------------------------
/webmoney/management/commands/clean_webmoney.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, timedelta
2 |
3 | from django.core.management.base import NoArgsCommand
4 |
5 |
6 | class Command(NoArgsCommand):
7 | help = "Clean unpayed invoces older than one day."
8 |
9 | def handle_noargs(self, **options):
10 | from webmoney.models import Invoice
11 | Invoice.objects.filter(
12 | created_on__lt=datetime.utcnow()-timedelta(days=1),
13 | payment__isnull=True).delete()
14 |
--------------------------------------------------------------------------------
/wm_sample/templates/base.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block title %}{% endblock %}
6 | {% block css %}{% endblock %}
7 | {% block js %}{% endblock %}
8 | {% block extra-head %}{% endblock %}
9 |
10 |
11 | {% block content %}{% endblock %}
12 |
13 |
14 |
--------------------------------------------------------------------------------
/wm_sample/helpers.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render_to_response
2 | from django.template import RequestContext
3 |
4 |
5 | def render_to(template=None):
6 | def renderer(function):
7 | def wrapper(request, *args, **kwargs):
8 | output = function(request, *args, **kwargs)
9 | if not isinstance(output, dict):
10 | return output
11 | tmpl = output.pop('TEMPLATE', template)
12 | return render_to_response(
13 | tmpl, output, context_instance=RequestContext(request))
14 |
15 | return wrapper
16 |
17 | return renderer
18 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Django-Payment-WebMoney
2 | =======================
3 |
4 | WebMoney Merchant Interface support for Django.
5 |
6 |
7 | How to configure WM
8 | -------------------
9 | 1. Change your attestation from none to personal or higher
10 | 2. Configure payment settings on this page https://merchant.webmoney.ru/conf/purse.asp
11 | 3. Choose your purse & click to configure link
12 | 4. Edit the following fields: Result URL, Success URL, Fail URL
13 | 5. Save & enjoy
14 |
15 | Fields urls example for wm-sample:
16 | ----------------------------------
17 | * Result URL = http://127.0.0.1:8000/webmoney/result/
18 |
19 | * Success URL = http://127.0.0.1:8000/success/
20 |
21 | * Fail URL = http://127.0.0.1:8000/fail/
22 |
--------------------------------------------------------------------------------
/wm_sample/urls.py:
--------------------------------------------------------------------------------
1 | try:
2 | from django.conf.urls import patterns, url, include
3 | except ImportError:
4 | from django.conf.urls.defaults import patterns, url, include
5 |
6 | from django.contrib.staticfiles.urls import staticfiles_urlpatterns
7 | from django.contrib import admin
8 |
9 | from views import *
10 |
11 |
12 | admin.autodiscover()
13 |
14 | urlpatterns = patterns(
15 | '',
16 | (r'^admin/', include(admin.site.urls)),
17 | (r'^webmoney/', include('webmoney.urls')),
18 | )
19 |
20 | urlpatterns += patterns(
21 | '',
22 | url(r'^success/$', success, name='wm_sample-success'),
23 | url(r'^fail/$', fail, name='wm_sample-fail'),
24 | url(r'^$', simple_payment, name='wm_sample-payment'),
25 | )
26 |
27 | urlpatterns += staticfiles_urlpatterns()
28 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 |
2 | from setuptools import setup
3 |
4 | setup(
5 | name='django-payment-webmoney',
6 | version=__import__('webmoney').__version__,
7 | description='WebMoney Merchant Interface support for Django.',
8 | author='Ivan Fedorov',
9 | author_email='oxyum@oxyum.ru',
10 | url='http://code.google.com/p/django-payment-webmoney/',
11 | packages=['webmoney',],
12 | classifiers=[
13 | 'Development Status :: 3 - Alpha',
14 | 'Environment :: Web Environment',
15 | 'Intended Audience :: Developers',
16 | 'License :: OSI Approved :: MIT License',
17 | 'Operating System :: OS Independent',
18 | 'Programming Language :: Python',
19 | 'Framework :: Django',
20 | ],
21 | include_package_data=True,
22 | zip_safe=False,
23 | )
24 |
--------------------------------------------------------------------------------
/webmoney/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from webmoney.models import Invoice, Payment, Purse
4 |
5 |
6 | class InvoiceAdmin(admin.ModelAdmin):
7 | list_display = [
8 | '__unicode__', 'payment_no', 'created_on', 'user', '_is_payed_admin']
9 | list_filter = ['created_on', 'user']
10 | date_hierarchy = 'created_on'
11 | ordering = ['-created_on', 'user']
12 | search_fields = ['payment_no', 'created_on']
13 |
14 |
15 | class PaymentAdmin(admin.ModelAdmin):
16 | date_hierarchy = 'created_on'
17 | list_display = ['id', 'sys_invs_no', 'sys_trans_no', 'amount', 'invoice']
18 | list_filter = ['created_on']
19 | ordering = ['-created_on']
20 | search_fields = ['id']
21 |
22 |
23 | class PurseAdmin(admin.ModelAdmin):
24 | list_display = ['__unicode__']
25 | ordering = ['purse']
26 | search_fields = ['purse']
27 |
28 |
29 | admin.site.register(Invoice, InvoiceAdmin)
30 | admin.site.register(Payment, PaymentAdmin)
31 | admin.site.register(Purse, PurseAdmin)
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2009-2010 Ivan Fedorov
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/wm_sample/views.py:
--------------------------------------------------------------------------------
1 | from django.template import loader, RequestContext
2 | from helpers import render_to
3 |
4 | from webmoney.forms import *
5 | from webmoney.models import Invoice, Purse
6 |
7 |
8 | @render_to('wm_sample/simple_payment.html')
9 | def simple_payment(request):
10 | response = {}
11 |
12 | initial = {
13 | 'LMI_PAYEE_PURSE': Purse.objects.all()[0],
14 | 'LMI_PAYMENT_NO': Invoice.objects.create(user=request.user).payment_no,
15 | 'LMI_PAYMENT_DESC': loader.render_to_string(
16 | 'wm_sample/simple_payment_desc.txt',
17 | RequestContext(request)).strip()[:255],
18 | }
19 |
20 | response['form'] = PaymentRequestForm(initial=initial)
21 |
22 | return response
23 |
24 |
25 | @render_to('wm_sample/success.html')
26 | def success(request):
27 | response = {}
28 |
29 | if request.method == 'POST':
30 | form = SettledPaymentForm(request.POST)
31 | if form.is_valid():
32 | response['id'] = form.cleaned_data['LMI_PAYMENT_NO']
33 | response['sys_invs_no'] = form.cleaned_data['LMI_SYS_INVS_NO']
34 | response['sys_trans_no'] = form.cleaned_data['LMI_SYS_TRANS_NO']
35 | response['date'] = form.cleaned_data['LMI_SYS_TRANS_DATE']
36 |
37 | return response
38 |
39 |
40 | @render_to('wm_sample/fail.html')
41 | def fail(request):
42 | response = {}
43 | if request.method == 'POST':
44 | form = UnSettledPaymentForm(request.POST)
45 | if form.is_valid():
46 | response['id'] = form.cleaned_data['LMI_PAYMENT_NO']
47 | response['sys_invs_no'] = form.cleaned_data['LMI_SYS_INVS_NO']
48 | response['sys_trans_no'] = form.cleaned_data['LMI_SYS_TRANS_NO']
49 | response['date'] = form.cleaned_data['LMI_SYS_TRANS_DATE']
50 |
51 | return response
52 |
--------------------------------------------------------------------------------
/webmoney/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 | from webmoney import PURSE_RE, WMID_RE
5 |
6 |
7 | class PaymentRequestForm(forms.Form):
8 | LMI_PAYMENT_AMOUNT = forms.DecimalField(
9 | max_digits=7, decimal_places=2, label=_(u'Amount'))
10 | LMI_PAYMENT_DESC = forms.CharField(
11 | label=_(u'Description'), widget=forms.HiddenInput())
12 | LMI_PAYMENT_NO = forms.IntegerField(
13 | label=_(u'Payment Number'), widget=forms.HiddenInput())
14 | LMI_PAYEE_PURSE = forms.RegexField(
15 | regex=PURSE_RE, widget=forms.HiddenInput())
16 | LMI_SIM_MODE = forms.IntegerField(
17 | initial="0", widget=forms.HiddenInput())
18 |
19 |
20 | class BasePaymentForm(forms.Form):
21 | LMI_PAYMENT_NO = forms.IntegerField(label=_(u'Payment Number'))
22 |
23 |
24 | class ExtraPaymentForm(BasePaymentForm):
25 | # Paymer
26 | LMI_PAYMER_NUMBER = forms.CharField(required=False)
27 | LMI_PAYMER_EMAIL = forms.EmailField(required=False)
28 |
29 | # Telepat
30 | LMI_TELEPAT_PHONENUMBER = forms.CharField(required=False)
31 | LMI_TELEPAT_ORDERID = forms.CharField(required=False)
32 |
33 | # Credit
34 | LMI_PAYMENT_CREDITDAYS = forms.IntegerField(min_value=0, required=False)
35 |
36 |
37 | class PrerequestForm(ExtraPaymentForm):
38 | LMI_PREREQUEST = forms.BooleanField(
39 | label=_('Prerequest flag'), required=False)
40 | LMI_PAYEE_PURSE = forms.RegexField(regex=PURSE_RE)
41 |
42 | LMI_PAYMENT_AMOUNT = forms.DecimalField(
43 | max_digits=7, decimal_places=2, label=_(u'Amount'))
44 | LMI_MODE = forms.IntegerField(
45 | label=_('Test mode'), min_value=0, max_value=1)
46 |
47 | LMI_PAYER_WM = forms.RegexField(regex=WMID_RE)
48 | LMI_PAYER_PURSE = forms.RegexField(regex=PURSE_RE)
49 |
50 |
51 | class PayedPaymentForm(BasePaymentForm):
52 | LMI_SYS_INVS_NO = forms.IntegerField()
53 | LMI_SYS_TRANS_NO = forms.IntegerField()
54 | LMI_SYS_TRANS_DATE = forms.DateTimeField(input_formats=['%Y%m%d %H:%M:%S'])
55 |
56 |
57 | class PaymentNotificationForm(PrerequestForm, PayedPaymentForm):
58 | LMI_HASH = forms.CharField()
59 |
60 | # Please do not USE IT!!! Security flaw!
61 | # LMI_SECRET_KEY
62 |
63 |
64 | class SettledPaymentForm(PayedPaymentForm, ExtraPaymentForm):
65 | pass
66 |
67 |
68 | class UnSettledPaymentForm(PayedPaymentForm, ExtraPaymentForm):
69 | pass
70 |
--------------------------------------------------------------------------------
/webmoney/views.py:
--------------------------------------------------------------------------------
1 | try:
2 | from hashlib import md5
3 | except ImportError:
4 | from md5 import md5
5 |
6 | from django.core.exceptions import ObjectDoesNotExist
7 | from django.core.mail import mail_admins
8 | from django.http import (
9 | HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed)
10 |
11 | try:
12 | from django.views.decorators.csrf import csrf_exempt
13 | except ImportError:
14 | from django.contrib.csrf.middleware import csrf_exempt
15 |
16 | from webmoney.forms import PrerequestForm, PaymentNotificationForm
17 | from webmoney.models import Invoice, Payment, Purse
18 | from webmoney.signals import webmoney_payment_accepted
19 |
20 |
21 | @csrf_exempt
22 | def result(request):
23 | if request.method != 'POST':
24 | return HttpResponseNotAllowed(permitted_methods=('POST',))
25 |
26 | form = PrerequestForm(request.POST)
27 | if form.is_valid() and form.cleaned_data['LMI_PREREQUEST']:
28 | payment_no = int(form.cleaned_data['LMI_PAYMENT_NO'])
29 | try:
30 | Invoice.objects.get(payment_no=payment_no)
31 | except ObjectDoesNotExist:
32 | return HttpResponseBadRequest(
33 | "Invoice with number %s not found." % payment_no)
34 | return HttpResponse("YES")
35 |
36 | form = PaymentNotificationForm(request.POST)
37 | if form.is_valid():
38 | purse = Purse.objects.get(purse=form.cleaned_data['LMI_PAYEE_PURSE'])
39 |
40 | key = "%s%s%s%s%s%s%s%s%s%s" % (
41 | purse.purse,
42 | form.cleaned_data['LMI_PAYMENT_AMOUNT'],
43 | form.cleaned_data['LMI_PAYMENT_NO'],
44 | form.cleaned_data['LMI_MODE'],
45 | form.cleaned_data['LMI_SYS_INVS_NO'],
46 | form.cleaned_data['LMI_SYS_TRANS_NO'],
47 | form.cleaned_data['LMI_SYS_TRANS_DATE'].strftime(
48 | '%Y%m%d %H:%M:%S'),
49 | purse.secret_key,
50 | form.cleaned_data['LMI_PAYER_PURSE'],
51 | form.cleaned_data['LMI_PAYER_WM']
52 | )
53 |
54 | generated_hash = md5(key).hexdigest().upper()
55 |
56 | if generated_hash == form.cleaned_data['LMI_HASH']:
57 | payment = Payment(
58 | payee_purse=purse,
59 | amount=form.cleaned_data['LMI_PAYMENT_AMOUNT'],
60 | payment_no=form.cleaned_data['LMI_PAYMENT_NO'],
61 | mode=form.cleaned_data['LMI_MODE'],
62 | sys_invs_no=form.cleaned_data['LMI_SYS_INVS_NO'],
63 | sys_trans_no=form.cleaned_data['LMI_SYS_TRANS_NO'],
64 | sys_trans_date=form.cleaned_data['LMI_SYS_TRANS_DATE'],
65 | payer_purse=form.cleaned_data['LMI_PAYER_PURSE'],
66 | payer_wm=form.cleaned_data['LMI_PAYER_WM'],
67 | paymer_number=form.cleaned_data['LMI_PAYMER_NUMBER'],
68 | paymer_email=form.cleaned_data['LMI_PAYMER_EMAIL'],
69 | telepat_phonenumber=form.cleaned_data[
70 | 'LMI_TELEPAT_PHONENUMBER'],
71 | telepat_orderid=form.cleaned_data['LMI_TELEPAT_ORDERID'],
72 | payment_creditdays=form.cleaned_data['LMI_PAYMENT_CREDITDAYS']
73 | )
74 |
75 | try:
76 | payment.invoice = Invoice.objects.get(
77 | payment_no=form.cleaned_data['LMI_PAYMENT_NO'])
78 | except ObjectDoesNotExist:
79 | mail_admins(
80 | 'Unprocessed payment without invoice!',
81 | 'Payment NO is %s.' % form.cleaned_data['LMI_PAYMENT_NO'],
82 | fail_silently=True)
83 |
84 | payment.save()
85 |
86 | webmoney_payment_accepted.send(
87 | sender=payment.__class__, payment=payment)
88 | return HttpResponse("OK")
89 | else:
90 | mail_admins(
91 | 'Unprocessed payment with incorrect hash!',
92 | 'Payment NO is %s.' % form.cleaned_data['LMI_PAYMENT_NO'],
93 | fail_silently=True)
94 | return HttpResponseBadRequest("Incorrect hash")
95 | return HttpResponseBadRequest("Unknown error!")
96 |
--------------------------------------------------------------------------------
/wm_sample/settings.py:
--------------------------------------------------------------------------------
1 | # Django settings for wm_sample project.
2 | import os.path
3 |
4 |
5 | PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
6 |
7 | DEBUG = True
8 | TEMPLATE_DEBUG = DEBUG
9 |
10 | ADMINS = (
11 | # ('Your Name', 'your_email@domain.com'),
12 | )
13 |
14 | MANAGERS = ADMINS
15 |
16 | DATABASES = {
17 | 'default': {
18 | 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
19 | 'NAME': 'wm_sample.db', # Or path to database file if using sqlite3.
20 | 'USER': '', # Not used with sqlite3.
21 | 'PASSWORD': '', # Not used with sqlite3.
22 | 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
23 | 'PORT': '', # Set to empty string for default. Not used with sqlite3.
24 | }
25 | }
26 |
27 | # Local time zone for this installation. Choices can be found here:
28 | # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
29 | # although not all choices may be available on all operating systems.
30 | # On Unix systems, a value of None will cause Django to use the same
31 | # timezone as the operating system.
32 | # If running in a Windows environment this must be set to the same as your
33 | # system time zone.
34 | TIME_ZONE = 'America/Chicago'
35 |
36 | # Language code for this installation. All choices can be found here:
37 | # http://www.i18nguy.com/unicode/language-identifiers.html
38 | LANGUAGE_CODE = 'en-us'
39 |
40 | SITE_ID = 1
41 |
42 | # If you set this to False, Django will make some optimizations so as not
43 | # to load the internationalization machinery.
44 | USE_I18N = True
45 |
46 | # If you set this to False, Django will not format dates, numbers and
47 | # calendars according to the current locale
48 | USE_L10N = True
49 |
50 | # Absolute path to the directory that holds media.
51 | # Example: "/home/media/media.lawrence.com/"
52 | MEDIA_ROOT = ''
53 |
54 | # URL that handles the media served from MEDIA_ROOT. Make sure to use a
55 | # trailing slash if there is a path component (optional in other cases).
56 | # Examples: "http://media.lawrence.com", "http://example.com/media/"
57 | MEDIA_URL = '/media/'
58 |
59 | STATIC_URL = '/static/'
60 |
61 | # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
62 | # trailing slash.
63 | # Examples: "http://foo.com/media/", "/media/".
64 | ADMIN_MEDIA_PREFIX = '/media/'
65 |
66 | # Make this unique, and don't share it with anybody.
67 | SECRET_KEY = 'secret'
68 |
69 | # List of callables that know how to import templates from various sources.
70 | TEMPLATE_LOADERS = (
71 | 'django.template.loaders.filesystem.Loader',
72 | 'django.template.loaders.app_directories.Loader',
73 | )
74 |
75 | TEMPLATE_CONTEXT_PROCESSORS = (
76 | 'django.contrib.auth.context_processors.auth',
77 | 'django.core.context_processors.debug',
78 | 'django.core.context_processors.i18n',
79 | 'django.core.context_processors.csrf',
80 | 'django.core.context_processors.request',
81 | 'django.core.context_processors.media',
82 | 'django.core.context_processors.static',
83 | )
84 |
85 | MIDDLEWARE_CLASSES = (
86 | 'django.middleware.common.CommonMiddleware',
87 | 'django.contrib.sessions.middleware.SessionMiddleware',
88 | 'django.middleware.csrf.CsrfViewMiddleware',
89 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
90 | 'django.contrib.messages.middleware.MessageMiddleware',
91 | )
92 |
93 | ROOT_URLCONF = 'urls'
94 |
95 | TEMPLATE_DIRS = (
96 | os.path.join(PROJECT_ROOT, 'templates')
97 | )
98 |
99 | INSTALLED_APPS = (
100 | 'django.contrib.auth',
101 | 'django.contrib.contenttypes',
102 | 'django.contrib.sessions',
103 | 'django.contrib.sites',
104 | 'django.contrib.messages',
105 | 'django.contrib.admin',
106 |
107 | 'webmoney',
108 | )
109 |
110 | STATICFILES_FINDERS = (
111 | 'django.contrib.staticfiles.finders.FileSystemFinder',
112 | 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
113 | )
114 |
--------------------------------------------------------------------------------
/webmoney/models.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime, timedelta
2 | from time import sleep
3 |
4 | from django.core.exceptions import ObjectDoesNotExist
5 | from django.db import IntegrityError, models, transaction
6 | from django.conf import settings
7 |
8 |
9 | AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')
10 |
11 | PAYMENT_MODE_CHOICES = (
12 | (0, 'REAL'),
13 | (1, 'TEST'),
14 | )
15 |
16 |
17 | class Purse(models.Model):
18 | purse = models.CharField(max_length=13, unique=True)
19 | secret_key = models.CharField(max_length=50)
20 |
21 | def __unicode__(self):
22 | return '%s' % (self.purse, )
23 |
24 |
25 | class Invoice(models.Model):
26 | user = models.ForeignKey(AUTH_USER_MODEL)
27 | created_on = models.DateTimeField(unique=True, editable=False)
28 | payment_no = models.PositiveIntegerField(unique=True, editable=False)
29 |
30 | def _is_payed_admin(self):
31 | try:
32 | self.payment
33 | return True
34 | except ObjectDoesNotExist:
35 | return False
36 |
37 | _is_payed_admin.boolean = True
38 | _is_payed_admin.short_description = 'is payed'
39 | _is_payed_admin.admin_order_field = 'payment'
40 |
41 | is_payed = property(_is_payed_admin)
42 |
43 | @transaction.commit_manually
44 | def save(self, force_insert=False, force_update=False, using=None):
45 | sid = transaction.savepoint()
46 | if self.pk is None:
47 | i = 1
48 | while self.pk is None:
49 |
50 | if i > 10:
51 | sleep(0.001)
52 |
53 | if i > 20:
54 | # Protection from infinite loop
55 | raise IntegrityError(
56 | 'Too many iterations while generating '
57 | 'unique Invoice number.'
58 | )
59 |
60 | try:
61 | self.created_on = datetime.utcnow()
62 | self.created_on = self.created_on - timedelta(
63 | microseconds=self.created_on.microsecond % 100)
64 |
65 | self.payment_no = (
66 | self.created_on.hour * 3600 +
67 | self.created_on.minute * 60 +
68 | self.created_on.second) * 10000 + (
69 | self.created_on.microsecond // 100)
70 | super(Invoice, self).save(force_insert, force_update)
71 |
72 | except IntegrityError:
73 | transaction.savepoint_rollback(sid)
74 |
75 | i += 1
76 | else:
77 | super(Invoice, self).save(force_insert, force_update)
78 |
79 | transaction.savepoint_commit(sid)
80 | transaction.commit()
81 |
82 | def __unicode__(self):
83 | return '%s/%s (for: %s)' % (
84 | self.payment_no, self.created_on.date(), self.user, )
85 |
86 |
87 | class Payment(models.Model):
88 | created_on = models.DateTimeField(auto_now_add=True, editable=False)
89 |
90 | invoice = models.OneToOneField(
91 | Invoice, blank=True, null=True, related_name='payment')
92 | payee_purse = models.ForeignKey(Purse, related_name='payments')
93 | amount = models.DecimalField(decimal_places=2, max_digits=9)
94 | payment_no = models.PositiveIntegerField(unique=True)
95 | mode = models.PositiveSmallIntegerField(choices=PAYMENT_MODE_CHOICES)
96 |
97 | sys_invs_no = models.PositiveIntegerField()
98 | sys_trans_no = models.PositiveIntegerField()
99 | sys_trans_date = models.DateTimeField()
100 |
101 | payer_purse = models.CharField(max_length=13)
102 | payer_wm = models.CharField(max_length=12)
103 |
104 | paymer_number = models.CharField(max_length=30, blank=True)
105 | paymer_email = models.EmailField(blank=True)
106 |
107 | telepat_phonenumber = models.CharField(max_length=30, blank=True)
108 | telepat_orderid = models.CharField(max_length=30, blank=True)
109 |
110 | payment_creditdays = models.PositiveIntegerField(blank=True, null=True)
111 |
112 | def __unicode__(self):
113 | return "%s - %s WM%s" % (
114 | self.payment_no, self.amount, self.payee_purse.purse[0])
115 |
--------------------------------------------------------------------------------