Just checking in.
This commit is contained in:
parent
54e84be36a
commit
4ca76378df
21 changed files with 200 additions and 35 deletions
|
@ -1,11 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
class Profile(models.Model):
|
from localauth.models import Profile
|
||||||
user = models.ForeignKey(get_user_model(), models.CASCADE)
|
|
||||||
|
|
||||||
class ClientProfile(Profile):
|
class ClientProfile(Profile):
|
||||||
pass
|
|
||||||
|
|
||||||
class PartnerProfile(Profile):
|
|
||||||
pass
|
pass
|
|
@ -1,4 +1,10 @@
|
||||||
class SuperUserRequiredMixin(object):
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.shortcuts import redirect
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
class SuperUserRequiredMixin:
|
||||||
"""
|
"""
|
||||||
View mixin which requires that the authenticated user is a super user
|
View mixin which requires that the authenticated user is a super user
|
||||||
(i.e. `is_superuser` is True).
|
(i.e. `is_superuser` is True).
|
||||||
|
@ -12,5 +18,17 @@ class SuperUserRequiredMixin(object):
|
||||||
'You do not have the permission required to perform the '
|
'You do not have the permission required to perform the '
|
||||||
'requested operation.')
|
'requested operation.')
|
||||||
return redirect(settings.LOGIN_URL)
|
return redirect(settings.LOGIN_URL)
|
||||||
return super(SuperUserRequiredMixin, self).dispatch(request,
|
return super().dispatch(request, *args, **kwargs)
|
||||||
*args, **kwargs)
|
|
||||||
|
|
||||||
|
class LoginRequiredMixin:
|
||||||
|
"""
|
||||||
|
View mixin which verifies that the user has authenticated.
|
||||||
|
|
||||||
|
NOTE:
|
||||||
|
This should be the left-most mixin of a view.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@method_decorator(login_required)
|
||||||
|
def dispatch(self, *args, **kwargs):
|
||||||
|
return super().dispatch(*args, **kwargs)
|
|
@ -3,6 +3,8 @@ from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from django_countries.fields import CountryField
|
||||||
|
|
||||||
class UserManager(BaseUserManager):
|
class UserManager(BaseUserManager):
|
||||||
use_in_migrations = True
|
use_in_migrations = True
|
||||||
|
|
||||||
|
@ -56,4 +58,19 @@ class User(AbstractBaseUser):
|
||||||
return self.is_superuser
|
return self.is_superuser
|
||||||
|
|
||||||
has_module_perms = has_permission
|
has_module_perms = has_permission
|
||||||
has_perm = has_permission
|
has_perm = has_permission
|
||||||
|
|
||||||
|
class Profile(models.Model):
|
||||||
|
user = models.OneToOneField(User, models.CASCADE)
|
||||||
|
company = models.CharField(max_length=64, null=True, blank=True)
|
||||||
|
vat_id = models.CharField(max_length=32, null=True, blank=True)
|
||||||
|
first_name = models.CharField(max_length=64)
|
||||||
|
last_name = models.CharField(max_length=64)
|
||||||
|
street = models.CharField(max_length=64)
|
||||||
|
city = models.CharField(max_length=64)
|
||||||
|
zip = models.CharField(max_length=16)
|
||||||
|
state = models.CharField(max_length=64)
|
||||||
|
country = CountryField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
|
@ -1,6 +1,8 @@
|
||||||
from django.contrib.auth.views import LoginView as Login, LogoutView as Logout
|
from django.contrib.auth.views import LoginView as Login, LogoutView as Logout
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
from django.contrib.auth import login
|
from django.contrib.auth import login
|
||||||
|
from django.shortcuts import resolve_url
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from .forms import RegistrationForm
|
from .forms import RegistrationForm
|
||||||
from .models import User
|
from .models import User
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
# Create your models here.
|
from localauth.models import User, Profile
|
||||||
|
|
||||||
|
from django_countries.fields import CountryField
|
||||||
|
|
||||||
|
class PartnerProfile(Profile):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Establishment(models.Model):
|
||||||
|
owner = models.ForeignKey(PartnerProfile, models.CASCADE)
|
||||||
|
name = models.CharField(max_length=64)
|
||||||
|
stars = models.IntegerField(null=True, blank=True)
|
||||||
|
street = models.CharField(max_length=64)
|
||||||
|
city = models.CharField(max_length=64)
|
||||||
|
zip = models.CharField(max_length=16)
|
||||||
|
state = models.CharField(max_length=64)
|
||||||
|
country = CountryField()
|
||||||
|
|
||||||
|
class RoomCategory(models.Model):
|
||||||
|
establishment = models.ForeignKey(Establishment, models.CASCADE)
|
||||||
|
name = models.CharField(max_length=64)
|
|
@ -3,6 +3,27 @@ from django import template
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def stars(count, color="yellow"):
|
def stars(number, classes=""):
|
||||||
return """
|
number = int(number)
|
||||||
"""
|
if not 1 <= number <= 5:
|
||||||
|
raise ValueError("Number of stars must be between 1 and 5.")
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
|
||||||
|
for i in range(5):
|
||||||
|
output += '<span><i class="fa%s fa-star %s"></i></span>' % (("" if i < number else "r"), classes)
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def hearts(number, classes=""):
|
||||||
|
number = int(number)
|
||||||
|
if not 1 <= number <= 5:
|
||||||
|
raise ValueError("Number of hearts must be between 1 and 5.")
|
||||||
|
|
||||||
|
output = ""
|
||||||
|
|
||||||
|
for i in range(5):
|
||||||
|
output += '<span><i class="fa%s fa-heart %s"></i></span>' % (("" if i < number else "r"), classes)
|
||||||
|
|
||||||
|
return output
|
|
@ -1,3 +1,9 @@
|
||||||
from django.shortcuts import render
|
from django.views.generic import CreateView
|
||||||
|
|
||||||
# Create your views here.
|
from .models import PartnerProfile
|
||||||
|
|
||||||
|
from localauth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
class PartnerRegistrationView(LoginRequiredMixin, CreateView):
|
||||||
|
model = PartnerProfile
|
||||||
|
exclude = ["user"]
|
|
@ -21,6 +21,8 @@ from .functions import invoice_upload_path
|
||||||
|
|
||||||
class BillingAddress(models.Model):
|
class BillingAddress(models.Model):
|
||||||
user = models.ForeignKey(get_user_model(), models.CASCADE)
|
user = models.ForeignKey(get_user_model(), models.CASCADE)
|
||||||
|
company = models.CharField(max_length=64, null=True, blank=True)
|
||||||
|
vat_id = models.CharField(max_length=32, null=True, blank=True)
|
||||||
first_name = models.CharField(max_length=64)
|
first_name = models.CharField(max_length=64)
|
||||||
last_name = models.CharField(max_length=64)
|
last_name = models.CharField(max_length=64)
|
||||||
street = models.CharField(max_length=128)
|
street = models.CharField(max_length=128)
|
||||||
|
@ -129,6 +131,6 @@ class InvoicePayment(PolymorphicModel):
|
||||||
def gateway(self):
|
def gateway(self):
|
||||||
raise NotImplementedError("%s does not implement gateway" % type(self))
|
raise NotImplementedError("%s does not implement gateway" % type(self))
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def initiate(invoice):
|
def initiate(cls, invoice):
|
||||||
raise NotImplementedError("%s does not implement initiate()" % type(self))
|
raise NotImplementedError("%s does not implement initiate()" % cls.__name__)
|
||||||
|
|
|
@ -11,6 +11,9 @@ class SepaPaymentReference(models.Model):
|
||||||
invoice = models.ForeignKey(Invoice, models.CASCADE)
|
invoice = models.ForeignKey(Invoice, models.CASCADE)
|
||||||
reference = models.IntegerField(default=generate_reference)
|
reference = models.IntegerField(default=generate_reference)
|
||||||
|
|
||||||
|
def create_payment(self, amount):
|
||||||
|
return SepaInvoicePayment.objects.create(invoice=self.invoice, gateway_id=self.reference, amount=amount)
|
||||||
|
|
||||||
class SepaInvoicePayment(InvoicePayment):
|
class SepaInvoicePayment(InvoicePayment):
|
||||||
@property
|
@property
|
||||||
def gateway(self):
|
def gateway(self):
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import SepaApplyPaymentView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('apply/', SepaApplyPaymentView.as_view(), name="superuser_apply"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
from django.views.generic import FormView
|
from django.views.generic import FormView
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
from localauth.mixins import SuperUserRequiredMixin
|
from localauth.mixins import SuperUserRequiredMixin
|
||||||
|
|
||||||
|
@ -8,15 +9,14 @@ from .forms import SepaApplyPaymentForm
|
||||||
from .models import SepaPaymentReference, SepaInvoicePayment
|
from .models import SepaPaymentReference, SepaInvoicePayment
|
||||||
|
|
||||||
class SepaApplyPaymentView(SuperUserRequiredMixin, FormView):
|
class SepaApplyPaymentView(SuperUserRequiredMixin, FormView):
|
||||||
|
template_name = "payment/sepa/apply.html"
|
||||||
form_class = SepaApplyPaymentForm
|
form_class = SepaApplyPaymentForm
|
||||||
success_url = '/'
|
success_url = reverse_lazy("sepa:apply")
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
reference = form.cleaned_data["reference"]
|
reference = form.cleaned_data["reference"]
|
||||||
pr = get_object_or_404(SepaPaymentReference, reference=reference)
|
pr = get_object_or_404(SepaPaymentReference, reference=reference)
|
||||||
invoice = pr.invoice
|
pr.create_payment(form.cleaned_data["amount"])
|
||||||
|
|
||||||
SepaInvoicePayment.objects.create(invoice=invoice, amount=form.cleaned_data["amount"])
|
|
||||||
|
|
||||||
messages.success(self.request, "Zahlung angewendet.")
|
messages.success(self.request, "Zahlung angewendet.")
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('gateways/paypal/', include("payment.paypal.urls")),
|
path('gateways/paypal/', include("payment.paypal.urls"), name="paypal"),
|
||||||
path('gateways/sepa/', include("payment.sepa.urls")),
|
path('gateways/sepa/', include("payment.sepa.urls"), name="sepa"),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
class Testimonial(models.Model):
|
||||||
|
name = models.CharField(max_length=128)
|
||||||
|
text = models.TextField()
|
||||||
|
stars = models.PositiveIntegerField(
|
||||||
|
validators=[
|
||||||
|
MaxValueValidator(5),
|
||||||
|
MinValueValidator(1)
|
||||||
|
])
|
||||||
|
language = models.CharField(max_length=12, choices=settings.LANGUAGES)
|
||||||
|
public = models.BooleanField(default=False)
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
|
from random import SystemRandom
|
||||||
|
|
||||||
|
from public.models import Testimonial
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def testimonials():
|
def testimonials(count=5, language="de"):
|
||||||
return """
|
objects = list(Testimonial.objects.filter(language=language)) # pylint: disable=no-member
|
||||||
"""
|
SystemRandom().shuffle(objects)
|
||||||
|
return objects[:min(count, len(objects))]
|
||||||
|
|
|
@ -5,4 +5,5 @@ dbsettings
|
||||||
django-bootstrap4
|
django-bootstrap4
|
||||||
pyinvoice
|
pyinvoice
|
||||||
django-countries
|
django-countries
|
||||||
paypal-checkout-serversdk
|
paypal-checkout-serversdk
|
||||||
|
python-dateutil
|
1
static/frontend/css/toastr.min.css
vendored
Normal file
1
static/frontend/css/toastr.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
static/frontend/js/toastr.min.js
vendored
Normal file
7
static/frontend/js/toastr.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@
|
||||||
<link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon">
|
<link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon">
|
||||||
|
|
||||||
<!-- Google Fonts -->
|
<!-- Google Fonts -->
|
||||||
<link href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i,900,900i%7CMerriweather:300,300i,400,400i,700,700i,900,900i" rel="stylesheet">
|
<link href="https://fontproxy.kumi.systems/css?family=Lato:300,300i,400,400i,700,700i,900,900i%7CMerriweather:300,300i,400,400i,700,700i,900,900i" rel="stylesheet">
|
||||||
|
|
||||||
<!-- Bootstrap Stylesheet -->
|
<!-- Bootstrap Stylesheet -->
|
||||||
<link rel="stylesheet" href="{% static "frontend/css/bootstrap.min4.2.1.css" %}">
|
<link rel="stylesheet" href="{% static "frontend/css/bootstrap.min4.2.1.css" %}">
|
||||||
|
@ -40,6 +40,9 @@
|
||||||
<!-- Magnific Gallery -->
|
<!-- Magnific Gallery -->
|
||||||
<link rel="stylesheet" href="{% static "frontend/css/magnific-popup.css" %}">
|
<link rel="stylesheet" href="{% static "frontend/css/magnific-popup.css" %}">
|
||||||
|
|
||||||
|
<!-- Toastr -->
|
||||||
|
<link rel="stylesheet" href="{% static "frontend/css/toastr.min.css" %}">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,7 +178,15 @@
|
||||||
<li><a class="dropdown-item" href="/">{% trans "Impressum" %}</a></li>
|
<li><a class="dropdown-item" href="/">{% trans "Impressum" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li class="dropdown-item search-btn">
|
{% if request.user.is_superuser %}
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a href="#" class="nav-link" data-toggle="dropdown">Admin<span><i class="fa fa-angle-down"></i></span></a>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><a class="dropdown-item" href="{% url "payment:sepa:apply" %}">{% trans "SEPA-Zahlung anwenden" %}</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="dropdown-item search-btn" style="display: none;">
|
||||||
<a href="#" class="search-button" onClick="openSearch()"><span><i class="fa fa-search"></i></span></a>
|
<a href="#" class="search-button" onClick="openSearch()"><span><i class="fa fa-search"></i></span></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -520,6 +531,7 @@
|
||||||
<script src="{% static "frontend/js/bootstrap.min4.2.1.js" %}"></script>
|
<script src="{% static "frontend/js/bootstrap.min4.2.1.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/jquery.flexslider.js" %}"></script>
|
<script src="{% static "frontend/js/jquery.flexslider.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/bootstrap-datepicker.js" %}"></script>
|
<script src="{% static "frontend/js/bootstrap-datepicker.js" %}"></script>
|
||||||
|
<script src="{% static "frontend/js/toastr.min.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/owl.carousel.min.js" %}"></script>
|
<script src="{% static "frontend/js/owl.carousel.min.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/custom-navigation.js" %}"></script>
|
<script src="{% static "frontend/js/custom-navigation.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/custom-flex.js" %}"></script>
|
<script src="{% static "frontend/js/custom-flex.js" %}"></script>
|
||||||
|
@ -528,6 +540,21 @@
|
||||||
<script src="{% static "frontend/js/custom-video.js" %}"></script>
|
<script src="{% static "frontend/js/custom-video.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/popup-ad.js" %}"></script>
|
<script src="{% static "frontend/js/popup-ad.js" %}"></script>
|
||||||
<script src="{% static "frontend/js/autocomplete.js" %}"></script>
|
<script src="{% static "frontend/js/autocomplete.js" %}"></script>
|
||||||
|
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
{% if message.tags == 'success'%}
|
||||||
|
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
|
||||||
|
{% elif message.tags == 'info' %}
|
||||||
|
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
|
||||||
|
{% elif message.tags == 'warning' %}
|
||||||
|
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
|
||||||
|
{% elif message.tags == 'error' %}
|
||||||
|
<script type=text/javascript>toastr.{{ message.tags }}('{{ message }}')</script>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% block "scripts" %}
|
{% block "scripts" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
<!-- Page Scripts Ends -->
|
<!-- Page Scripts Ends -->
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Urlaubsauktion - {% trans "Weiterleitung" %}</title>
|
<title>JourneyJoker - {% trans "Weiterleitung" %}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>{% trans "Sie werden zu unserem Zahlungsdienstleister weitergeleitet. Wir bitten um einen Augenblick Geduld." %}</p>
|
<p>{% trans "Sie werden zu unserem Zahlungsdienstleister weitergeleitet. Wir bitten um einen Augenblick Geduld." %}</p>
|
||||||
|
|
24
templates/payment/sepa/apply.html
Normal file
24
templates/payment/sepa/apply.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
{% extends "frontend/base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load bootstrap4 %}
|
||||||
|
{% block "content" %}
|
||||||
|
<!--===== INNERPAGE-WRAPPER ====-->
|
||||||
|
<section class="innerpage-wrapper">
|
||||||
|
<div id="payment-success" class="section-padding">
|
||||||
|
<div class="container text-center">
|
||||||
|
<div class="row d-flex justify-content-center">
|
||||||
|
<div class="col-md-12 col-lg-8 col-lg-offset-2">
|
||||||
|
<div class="payment-success-text">
|
||||||
|
<h2>{% trans "SEPA-Zahlung anwenden" %}</h2>
|
||||||
|
|
||||||
|
<form method="POST">
|
||||||
|
{% csrf_token %}
|
||||||
|
{% bootstrap_form form %}
|
||||||
|
<button class="btn btn-orange btn-block">{% trans "Anwenden" %}</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- end columns -->
|
||||||
|
</div><!-- end row -->
|
||||||
|
</div><!-- end container -->
|
||||||
|
</div><!-- end coming-soon-text -->
|
||||||
|
</section><!-- end innerpage-wrapper -->
|
||||||
|
{% endblock %}
|
|
@ -18,8 +18,8 @@ from django.urls import path, include
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('', include('public.urls')),
|
path('', include('public.urls'), name="frontend"),
|
||||||
path('auth/', include('localauth.urls')),
|
path('auth/', include('localauth.urls'), name="localauth"),
|
||||||
path('auction/', include('auction.urls')),
|
path('auction/', include('auction.urls'), name="auction"),
|
||||||
path('payment/', include('payment.urls')),
|
path('payment/', include('payment.urls'), name="payment"),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue