Skip to content
This repository has been archived by the owner on Aug 27, 2020. It is now read-only.

Commit

Permalink
Add payu integration
Browse files Browse the repository at this point in the history
  • Loading branch information
kaniak274 committed Dec 7, 2019
1 parent 730b547 commit 0ffd90e
Show file tree
Hide file tree
Showing 14 changed files with 233 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,4 @@ db.py
/ebiznes/uploads/*
public/
email.py
payu.py
1 change: 1 addition & 0 deletions ebiznes/apps/service/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ class PriceListAdmin(admin.ModelAdmin):
admin.site.register(Rating, RatingAdmin)
admin.site.register(Rent, RentAdmin)
admin.site.register(PriceList, PriceListAdmin)
admin.site.register(Order)
10 changes: 10 additions & 0 deletions ebiznes/apps/service/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@
(APPROVED, _('Approved')),
(DONE, _('Done')),
)

PENDING = 'PENDING'
SUCCESS = 'SUCCESS'
FAILURE = 'FAILURE'

PAYMENT_CHOICES = (
(PENDING, 'W trakcie'),
(SUCCESS, 'Udane'),
(FAILURE, 'Nie udane'),
)
33 changes: 33 additions & 0 deletions ebiznes/apps/service/migrations/0018_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Generated by Django 2.2.8 on 2019-12-07 11:34

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('service', '0017_auto_20191128_2045'),
]

operations = [
migrations.CreateModel(
name='Order',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('totalAmount', models.CharField(max_length=50)),
('order_id', models.CharField(max_length=255)),
('status', models.CharField(choices=[('PENDING', 'W trakcie'), ('SUCCESS', 'Udane'), ('FAILURE', 'Nie udane')], max_length=40)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]
18 changes: 18 additions & 0 deletions ebiznes/apps/service/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,17 @@ def save(self, *args, **kwargs):
[self.user.email],
msg_ctx,
)
elif self.status == DONE:
msg_ctx = {
'pk': self.pk
}

send_email(
'Zaplata za usluge',
'service/email/payment.html',
[self.user.email],
msg_ctx,
)

super().save(*args, **kwargs)

Expand All @@ -132,3 +143,10 @@ def calculate_total_price(cls, price_list):

def __str__(self):
return self.name


class Order(TimeStampedModel):
totalAmount = models.CharField(max_length=50)
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
order_id = models.CharField(max_length=255)
status = models.CharField(max_length=40, choices=PAYMENT_CHOICES)
2 changes: 2 additions & 0 deletions ebiznes/apps/service/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@
path('price-list/remove/<int:pk>/', views.RemovePriceListRecord.as_view(), name='remove-price-list'),
path('price-list/update/<int:pk>/', views.UpdatePriceListRecord.as_view(), name='update-price-list'),
path('rents/<int:pk>/', views.UpdateRentView.as_view(), name='update-rent'),
path('rents/retrieve/<int:pk>/', views.RentRetrieveView.as_view(), name='retrieve-rent'),
path('payment/create/<int:pk>/', views.CreatePaymentAPIView.as_view(), name='create-payment'),
] + router.urls
92 changes: 91 additions & 1 deletion ebiznes/apps/service/views.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from decimal import Decimal
import json
import requests
from urllib import parse

from django.conf import settings
from django.http import Http404
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, render
from django_filters.rest_framework import DjangoFilterBackend

from rest_framework import status, viewsets
Expand All @@ -11,7 +15,9 @@
RetrieveAPIView, UpdateAPIView)
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from .choices import PENDING
from .filters import *
from .models import *
from .serializers import *
Expand Down Expand Up @@ -168,3 +174,87 @@ def check_objectt_permissions(self, request, obj):

if not obj.service.owner == request.user:
raise PermissionDenied()


class RentRetrieveView(RetrieveAPIView):
permission_classes = []
serializer_class = RentSerializer
queryset = Rent.objects.all()


def payment_view(request, pk):
rent = get_object_or_404(Rent, pk=pk)

return render(request, 'base.html')


class CreatePaymentAPIView(APIView):
permission_classes = []

def post(self, request, pk):
rent = get_object_or_404(Rent.objects.select_related('service', 'user'), pk=pk)

access_token = self._get_oauth_token()

if not access_token:
return Response(
'OAuth token nie może zostać pobrany. Skontaktuj się z administratorem.',
status=status.HTTP_400_BAD_REQUEST
)

order_data = self._get_order_data(request, rent)
headers = {
'Authorization': 'Bearer {}'.format(access_token),
'Content-Type': 'application/json; UTF-8',
}

response = requests.post(settings.PAYU_ORDER_URL, order_data, headers=headers)

if response.status_code == status.HTTP_200_OK:
order_id = parse.parse_qs(parse.urlparse(response.url).query)['orderId'][0]

Order.objects.create(
status=PENDING,
totalAmount='{}'.format((rent.total_price + 1) * 100).split('.')[0],
order_id=order_id,
user=rent.user
)

return Response({'redirectURI': response.url})

return Response(
'Proszę spróbować ponownie za kilka minut',
status=status.HTTP_400_BAD_REQUEST
)

def _get_oauth_token(self):
data = {
'grant_type': 'client_credentials',
'client_id': settings.PAYU_CLIENT_ID,
'client_secret': settings.PAYU_CLIENT_SECRET,
}

response = requests.post(settings.PAYU_OAUTH_URL, data)

if response.status_code == status.HTTP_200_OK:
return response.json()['access_token']
else:
return None

def _get_order_data(self, request, rent):
order_data = {
'customerIp': request.META.get('REMOTE_ADDR'),
'merchantPosId': settings.PAYU_POS_ID,
'description': 'Zapłata za usługę {}'.format(rent.service.name),
'currencyCode': 'PLN',
'totalAmount': '{}'.format((rent.total_price + 1) * 100).split('.')[0],
'products': [
{
'name': 'Usługa {}'.format(rent.service.name),
'unitPrice': '{}'.format((rent.total_price + 1) * 100).split('.')[0],
'quantity': '1'
}
]
}

return json.dumps(order_data)
2 changes: 2 additions & 0 deletions ebiznes/apps/users/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from . import views

from ebiznes.apps.service.views import payment_view

urlpatterns = [
path('', views.base_view),
Expand All @@ -19,4 +20,5 @@
path('about/', views.base_view),
path('contact/', views.base_view),
path('rules/', views.base_view),
path('payment/rent/<int:pk>/', payment_view, name='payment'),
]
6 changes: 6 additions & 0 deletions ebiznes/assets/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import RentHistory from './views/RentHistory';
import About from './views/About';
import Contact from './views/Contact';
import Rules from './views/Rules';
import Payment from './views/Payment';

Vue.use(Router)

Expand Down Expand Up @@ -103,6 +104,11 @@ const router = new Router({
component: RentHistory,
beforeEnter: checkNotLogged,
},
{
path: '/payment/rent/:id/',
name: 'payment',
component: Payment,
},
{
path: '/about/',
name: 'about',
Expand Down
11 changes: 11 additions & 0 deletions ebiznes/assets/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@
color: white;
}
}

#Payment {
button {
border: 0px;
height: 300px;
width: 300px;
background: url('http://static.payu.com/pl/standard/partners/buttons/payu_account_button_long_03.png');
background-repeat: no-repeat;
cursor: pointer;
}
}
38 changes: 38 additions & 0 deletions ebiznes/assets/views/Payment.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<div id="Payment">
<b-loading :active.sync="isLoading"/>
<button type="button" @click="startPayment"></button>
</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'Payment',
data () {
return {
rent: {},
isLoading: false,
}
},
methods: {
startPayment: function() {
this.isLoading = true;
const { id } = this.$route.params;
axios.post(`/api/services/payment/create/${id}/`)
.then(({ data }) => {
this.isLoading = false;
window.open(data.redirectURI, '_self')
})
.catch(error => {
this.isLoading = false;
this.$toastr.e(error.response.data)
})
},
},
};
</script>
1 change: 1 addition & 0 deletions ebiznes/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
WSGI_APPLICATION = 'ebiznes.wsgi.application'

from .db import *
from .payu import *

# Internationalization
# https://docs.djangoproject.com/en/2.2/topics/i18n/
Expand Down
5 changes: 5 additions & 0 deletions ebiznes/settings/payu.base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
PAYU_CLIENT_ID = ''
PAYU_CLIENT_SECRET = ''
PAYU_POS_ID = ''
PAYU_OAUTH_URL = ''
PAYU_ORDER_URL = ''
14 changes: 14 additions & 0 deletions ebiznes/templates/service/email/payment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<h1>Twoje zamowienie zostalo zakonczone</h1>
<p>Ponizej znajduje sie link do platnosci elektroniczne</p>
<p>Prosimy o jak najszybsza wplate</p>

<a href="{% url 'payment' pk=pk %}">Link do zaplaty</a>

<footer>
<p>Zespol ServiceRent</p>
</footer>
</body>
</html>

0 comments on commit 0ffd90e

Please sign in to comment.