├── main ├── __init__.py ├── migrations │ ├── __init__.py │ ├── 0002_delete_paymentstatusmodel.py │ └── 0001_initial.py ├── models.py ├── tests.py ├── admin.py ├── apps.py └── views.py ├── easypaisa ├── __init__.py ├── wsgi.py ├── urls.py └── settings.py ├── Procfile ├── requirements.txt ├── templates ├── pay.html └── index.html ├── manage.py ├── .gitignore └── README.md /main/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /easypaisa/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python manage.py collectstatic --no-input; gunicorn easypaisa.wsgi -b 0.0.0.0:$PORT 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | django==1.11.1 2 | gunicorn==0.14.6 3 | whitenoise==3.3.0 4 | httplib2==0.10.3 5 | git+https://github.com/qasimgulzar/easypaisa_module -------------------------------------------------------------------------------- /main/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.db import models 5 | 6 | # Create your models here. -------------------------------------------------------------------------------- /main/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /main/admin.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.contrib import admin 5 | 6 | # Register your models here. 7 | -------------------------------------------------------------------------------- /main/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class MainConfig(AppConfig): 8 | name = 'main' 9 | -------------------------------------------------------------------------------- /main/migrations/0002_delete_paymentstatusmodel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-05-16 17:51 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('main', '0001_initial'), 12 | ] 13 | 14 | operations = [ 15 | migrations.DeleteModel( 16 | name='PaymentStatusModel', 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /templates/pay.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | pay 6 | 7 | 8 |
9 | 10 | 11 | 12 |
13 | 14 | -------------------------------------------------------------------------------- /easypaisa/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for easypaisa project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | from whitenoise.django import DjangoWhiteNoise 14 | 15 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "easypaisa.settings") 16 | 17 | application = get_wsgi_application() 18 | application = DjangoWhiteNoise(application) 19 | -------------------------------------------------------------------------------- /main/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.1 on 2017-05-16 16:33 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='PaymentStatusModel', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('status', models.CharField(max_length=100)), 21 | ('desc', models.CharField(max_length=1000)), 22 | ('orderRefNumber', models.IntegerField()), 23 | ], 24 | ), 25 | ] 26 | -------------------------------------------------------------------------------- /main/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | # Create your views here. 4 | import logging 5 | from django.contrib.auth.models import User 6 | from django.http import HttpResponseRedirect 7 | from django.shortcuts import render 8 | from django.views.generic import ListView 9 | from django.views.generic.base import View 10 | from rest_framework import serializers, viewsets 11 | from django.conf import settings 12 | # Serializers define the API representation. 13 | 14 | 15 | class UserSerializer(serializers.HyperlinkedModelSerializer): 16 | class Meta: 17 | model = User 18 | fields = ('url', 'username', 'email', 'is_staff') 19 | 20 | 21 | # ViewSets define the view behavior. 22 | class UserViewSet(viewsets.ModelViewSet): 23 | queryset = User.objects.all() 24 | serializer_class = UserSerializer -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "easypaisa.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Payment 6 | 7 | 8 |

Payment Module

9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {# #} 20 | 21 | 22 |
23 | 24 | -------------------------------------------------------------------------------- /easypaisa/urls.py: -------------------------------------------------------------------------------- 1 | """easypaisa URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.conf.urls import url, include 18 | from django.views.decorators.csrf import csrf_exempt 19 | from rest_framework import routers 20 | 21 | # Routers provide an easy way of automatically determining the URL conf. 22 | from main.views import UserViewSet 23 | 24 | router = routers.DefaultRouter() 25 | router.register(r'users', UserViewSet) 26 | 27 | 28 | urlpatterns = [ 29 | url(r'^', include(router.urls)), 30 | url(r'^admin/', admin.site.urls), 31 | url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), 32 | url(r'^payments/', include('django_easypaisa.urls', namespace='django_easypaisa')), 33 | ] 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # IPython Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # dotenv 81 | .env 82 | 83 | # virtualenv 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | /.idea/ 94 | /*.iml 95 | /db.sqlite3 96 | staticfiles/ 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to setup easypaisa with django. 2 | 3 | 1. pip install git+https://github.com/qasimgulzar/easypaisa_module 4 | 2. add django_easypaisa in INSTALLED_APPS 5 | `INSTALLED_APPS = [ 6 | 'django.contrib.admin', 7 | 'django.contrib.auth', 8 | 'django.contrib.contenttypes', 9 | 'django.contrib.sessions', 10 | 'django.contrib.messages', 11 | 'django.contrib.staticfiles', 12 | 'main', 13 | 'rest_framework', 14 | 'django_easypaisa' 15 | ]` 16 | 3. add django-easypaisa urls to your application's urls file 17 | url(r'^payments/', include('django_easypaisa.urls', namespace='django_easypaisa')) 18 | 4. set parameters settings 19 | STORE_ID=os.environ.get("STORE_ID",None) ###you will get store id easypaisa's merchant portal. 20 | PAYMEN_TEMPLATE='index.html' ###set payment confirmation template which will also post data t easypaisa's server for first redirection. 21 | PAY_TEMPLATE='pay.html' ### set template for second redirection which will post auth_token to easypaisa for second redirection. 22 | EASYPAISA_POST_BACK_URL=os.environ.get('EASYPAISA_POST_BACK_URL','https://easypaisa-tutorial.herokuapp.com/payments/postbackhandler/') 23 | EASYPAISA_SERVER_URL=os.environ.get('EASYPAISA_SERVER_URL','https://easypaystg.easypaisa.com.pk') 24 | PAYMENT_COMPLETION_REDIRECT_TO_URL='/' # set redirect url. 25 | 4.5 export STORE_ID= 26 | 5. Make migrations `python manage.py makemigrations` 27 | 6. Run migrations `python manage.py migrate` 28 | 29 | ## 4.1 Content for PAYMEN_TEMPLATE 30 | 31 | ```html 32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {# #} 43 | 44 | 45 |
46 | ``` 47 | 48 | ## 4.2 Content for PAY_TEMPLATE 49 | 50 | ```html 51 |
52 | 53 | 54 | 55 |
56 | ``` 57 | 58 | 59 | # How to setup tutorial project. 60 | 61 | git clone https://github.com/qasimgulzar/django-easypaisa-tutorial.git 62 | cd django-easypaisa-tutorial 63 | pip install -r requirements.txt 64 | export DJANGO_SETTINGS_MODULE=easypaisa.settings on linux 65 | set DJANGO_SETTINGS_MODULE=easypaisa.settings if you are using windows 66 | 67 | python manage.py migrate 68 | 69 | python manage.py runserver -------------------------------------------------------------------------------- /easypaisa/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for easypaisa project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.11.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.11/ref/settings/ 11 | """ 12 | import logging 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | # Quick-start development settings - unsuitable for production 19 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 20 | 21 | # SECURITY WARNING: keep the secret key used in production secret! 22 | SECRET_KEY = 'g%5fo$-7s#w4lu08)_f0$)k*-^(y!ss2!5y3)5w0h#cfn^8wjf' 23 | 24 | # SECURITY WARNING: don't run with debug turned on in production! 25 | DEBUG = True 26 | 27 | ALLOWED_HOSTS = [ 28 | '*' 29 | ] 30 | 31 | 32 | # Application definition 33 | #admin123$$## 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'main', 42 | 'rest_framework', 43 | 'django_easypaisa' 44 | ] 45 | 46 | MIDDLEWARE = [ 47 | 'django.middleware.security.SecurityMiddleware', 48 | 'django.contrib.sessions.middleware.SessionMiddleware', 49 | 'django.middleware.common.CommonMiddleware', 50 | 'django.middleware.csrf.CsrfViewMiddleware', 51 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 52 | 'django.contrib.messages.middleware.MessageMiddleware', 53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 54 | ] 55 | 56 | ROOT_URLCONF = 'easypaisa.urls' 57 | 58 | TEMPLATES = [ 59 | { 60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 61 | 'DIRS': [], 62 | 'APP_DIRS': True, 63 | 'OPTIONS': { 64 | 'context_processors': [ 65 | 'django.template.context_processors.debug', 66 | 'django.template.context_processors.request', 67 | 'django.contrib.auth.context_processors.auth', 68 | 'django.contrib.messages.context_processors.messages', 69 | ], 70 | }, 71 | }, 72 | ] 73 | 74 | WSGI_APPLICATION = 'easypaisa.wsgi.application' 75 | 76 | 77 | # Database 78 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases 79 | 80 | DATABASES = { 81 | 'default': { 82 | 'ENGINE': 'django.db.backends.postgresql_psycopg2', 83 | 'NAME': os.environ.get('DB_NAME','dbk21ra6t6ij62'), 84 | 'USER': os.environ.get('DB_USERNAME','gsmxmhwcppemju'), 85 | 'PASSWORD': os.environ.get('DB_PASSWORD','43360d2fbf83db77f8792e276061940bca1459a33bac01c9236e77bde2f7807e'), 86 | 'HOST': os.environ.get('DB_HOST','ec2-23-23-227-188.compute-1.amazonaws.com'), 87 | 'PORT': os.environ.get('DB_PORT',5432), 88 | } 89 | } 90 | 91 | 92 | # Password validation 93 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 94 | 95 | AUTH_PASSWORD_VALIDATORS = [ 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 101 | }, 102 | { 103 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 104 | }, 105 | { 106 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 107 | }, 108 | ] 109 | 110 | 111 | # Internationalization 112 | # https://docs.djangoproject.com/en/1.11/topics/i18n/ 113 | 114 | LANGUAGE_CODE = 'en-us' 115 | 116 | TIME_ZONE = 'UTC' 117 | 118 | USE_I18N = True 119 | 120 | USE_L10N = True 121 | 122 | USE_TZ = True 123 | 124 | 125 | # Static files (CSS, JavaScript, Images) 126 | # https://docs.djangoproject.com/en/1.11/howto/static-files/ 127 | 128 | STATIC_URL = '/static/' 129 | STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') 130 | 131 | 132 | if not os.path.exists(os.path.join(BASE_DIR, 'static')): 133 | os.makedirs(os.path.join(BASE_DIR, 'static')) 134 | 135 | STATICFILES_STORAGE = 'whitenoise.django.GzipManifestStaticFilesStorage' 136 | 137 | 138 | STATICFILES_DIRS = ( 139 | os.path.join(BASE_DIR, 'static'), 140 | ) 141 | 142 | REST_FRAMEWORK = { 143 | # Use Django's standard `django.contrib.auth` permissions, 144 | # or allow read-only access for unauthenticated users. 145 | 'DEFAULT_PERMISSION_CLASSES': [ 146 | 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' 147 | ] 148 | } 149 | 150 | logging.basicConfig( 151 | level=logging.DEBUG, 152 | format="%(asctime)s %(name)s %(levelname)-8s %(message)s", 153 | ) 154 | 155 | TEMPLATES = [ 156 | { 157 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 158 | 'DIRS': [ 159 | os.path.join(BASE_DIR, 'templates'), 160 | ], 161 | 'APP_DIRS': True, 162 | 'OPTIONS': { 163 | 'context_processors': [ 164 | 'django.template.context_processors.debug', 165 | 'django.template.context_processors.request', 166 | 'django.contrib.auth.context_processors.auth', 167 | 'django.contrib.messages.context_processors.messages', 168 | ], 169 | }, 170 | }, 171 | ] 172 | 173 | 174 | STORE_ID=os.environ.get("STORE_ID",None) 175 | PAYMEN_TEMPLATE='index.html' 176 | PAY_TEMPLATE='pay.html' 177 | EASYPAISA_POST_BACK_URL=os.environ.get('EASYPAISA_POST_BACK_URL','https://easypaisa-tutorial.herokuapp.com/payments/postbackhandler/') 178 | EASYPAISA_SERVER_URL=os.environ.get('EASYPAISA_SERVER_URL','https://easypaystg.easypaisa.com.pk') 179 | PAYMENT_COMPLETION_REDIRECT_TO_URL='/' --------------------------------------------------------------------------------