Implement login system
Copy over payment system from kumi.xxx Add missing requirements Other stuff
This commit is contained in:
parent
b31ebc4818
commit
54e84be36a
47 changed files with 564 additions and 88 deletions
5
auction/apps.py
Normal file
5
auction/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AuctionConfig(AppConfig):
|
||||
name = 'auction'
|
16
auction/models.py
Normal file
16
auction/models.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from django.contrib.gis.db import models
|
||||
|
||||
from localauth.models import User
|
||||
|
||||
class Inquiry(models.Model):
|
||||
user = models.ForeignKey(User, models.PROTECT)
|
||||
destination_name = models.CharField(max_length=128)
|
||||
destination_coords = models.PointField()
|
||||
destination_radius = models.IntegerField()
|
||||
budget = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
adults = models.IntegerField()
|
||||
children = models.IntegerField()
|
||||
comment = models.TextField()
|
||||
|
||||
def get_hotels(self):
|
||||
pass
|
10
auction/urls.py
Normal file
10
auction/urls.py
Normal file
|
@ -0,0 +1,10 @@
|
|||
from django.urls import path
|
||||
|
||||
from public.views import HomeView
|
||||
|
||||
app_name = "auction"
|
||||
|
||||
urlpatterns = [
|
||||
path('create_inquiry/', HomeView.as_view(), name="create_inquiry"),
|
||||
path('process_inquiry/<slug:uuid>/', HomeView.as_view(), name="process_inquiry"),
|
||||
]
|
|
@ -1,3 +1,4 @@
|
|||
libpq-dev
|
||||
build-essential
|
||||
libpython3-dev
|
||||
postgis
|
|
@ -1,5 +0,0 @@
|
|||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from .models import Account
|
||||
|
||||
admin.site.register(Account, UserAdmin)
|
12
localauth/forms.py
Normal file
12
localauth/forms.py
Normal file
|
@ -0,0 +1,12 @@
|
|||
from django.contrib.auth.forms import UserCreationForm
|
||||
|
||||
from .models import User
|
||||
|
||||
class RegistrationForm(UserCreationForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs.pop("request")
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ["email", "password1", "password2"]
|
16
localauth/mixins.py
Normal file
16
localauth/mixins.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
class SuperUserRequiredMixin(object):
|
||||
"""
|
||||
View mixin which requires that the authenticated user is a super user
|
||||
(i.e. `is_superuser` is True).
|
||||
"""
|
||||
|
||||
@method_decorator(login_required)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
messages.error(
|
||||
request,
|
||||
'You do not have the permission required to perform the '
|
||||
'requested operation.')
|
||||
return redirect(settings.LOGIN_URL)
|
||||
return super(SuperUserRequiredMixin, self).dispatch(request,
|
||||
*args, **kwargs)
|
|
@ -1,58 +1,46 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from polymorphic.models import PolymorphicModel
|
||||
|
||||
class Profile:
|
||||
account = models.ForeignKey(get_user_model(), models.CASCADE)
|
||||
from django.utils import timezone
|
||||
|
||||
class UserManager(BaseUserManager):
|
||||
use_in_migrations = True
|
||||
|
||||
def _create_user(self, email, password, **extra_fields):
|
||||
now = timezone.now()
|
||||
if not username:
|
||||
raise ValueError('The given username must be set')
|
||||
def _create_user(self, email, display_name, password, **extra_fields):
|
||||
values = [email, display_name]
|
||||
field_value_map = dict(zip(self.model.REQUIRED_FIELDS, values))
|
||||
for field_name, value in field_value_map.items():
|
||||
if not value:
|
||||
raise ValueError('The {} value must be set'.format(field_name))
|
||||
|
||||
email = self.normalize_email(email)
|
||||
user = self.model(username=username, email=email,
|
||||
is_staff=is_staff, is_active=True,
|
||||
is_superuser=is_superuser,
|
||||
date_joined=now, **extra_fields)
|
||||
user = self.model(
|
||||
email=email,
|
||||
display_name=display_name,
|
||||
**extra_fields
|
||||
)
|
||||
user.set_password(password)
|
||||
user.save(using=self._db)
|
||||
return user
|
||||
|
||||
def create_user(self, username, email=None, password=None, **extra_fields):
|
||||
return self._create_user(username, email, password, False, False,
|
||||
**extra_fields)
|
||||
def create_user(self, email, display_name, password=None, **extra_fields):
|
||||
return self._create_user(email, display_name, password, **extra_fields)
|
||||
|
||||
def create_superuser(self, username, email, password, **extra_fields):
|
||||
return self._create_user(username, email, p
|
||||
def create_superuser(self, email, display_name, password=None, **extra_fields):
|
||||
extra_fields.setdefault('is_superuser', True)
|
||||
return self._create_user(email, display_name, password, **extra_fields)
|
||||
|
||||
class Account(AbstractBaseUser):
|
||||
email = models.EmailField(_('username'), max_length=30, unique=True,
|
||||
help_text=_('Required. 30 characters or fewer. Letters, digits and '
|
||||
'@/./+/-/_ only.'),
|
||||
validators=[
|
||||
validators.RegexValidator(r'^[\w.@+-]+$',
|
||||
_('Enter a valid username. '
|
||||
'This value may contain only letters, numbers '
|
||||
'and @/./+/-/_ characters.'), 'invalid'),
|
||||
],
|
||||
error_messages={
|
||||
'unique': _("A user with that username already exists."),
|
||||
})
|
||||
class User(AbstractBaseUser):
|
||||
email = models.EmailField(unique=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
date_joined = models.DateTimeField(default=timezone.now)
|
||||
last_login = models.DateTimeField(null=True)
|
||||
is_superuser = models.BooleanField(default=False)
|
||||
|
||||
objects = AccountManager()
|
||||
objects = UserManager()
|
||||
|
||||
USERNAME_FIELD = 'email'
|
||||
REQUIRED_FIELDS = []
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('account')
|
||||
verbose_name_plural = _('accounts')
|
||||
REQUIRED_FIELDS = ['display_name']
|
||||
|
||||
def get_full_name(self):
|
||||
return self.email
|
||||
|
@ -60,5 +48,12 @@ class Account(AbstractBaseUser):
|
|||
def get_short_name(self):
|
||||
return self.email
|
||||
|
||||
def email_user(self, subject, message, from_email=None, **kwargs):
|
||||
send_mail(subject, message, from_email, [self.email], **kwargs)
|
||||
def has_permission(self, *args, **kwargs):
|
||||
return self.is_superuser
|
||||
|
||||
@property
|
||||
def is_staff(self):
|
||||
return self.is_superuser
|
||||
|
||||
has_module_perms = has_permission
|
||||
has_perm = has_permission
|
11
localauth/urls.py
Normal file
11
localauth/urls.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from django.urls import path
|
||||
|
||||
from .views import LoginView, LogoutView, RegistrationView
|
||||
|
||||
app_name = "localauth"
|
||||
|
||||
urlpatterns = [
|
||||
path('login/', LoginView.as_view(), name="login"),
|
||||
path('logout/', LogoutView.as_view(), name="logout"),
|
||||
path('register/', RegistrationView.as_view(), name="register"),
|
||||
]
|
|
@ -1,3 +1,24 @@
|
|||
from django.shortcuts import render
|
||||
from django.contrib.auth.views import LoginView as Login, LogoutView as Logout
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.contrib.auth import login
|
||||
|
||||
# Create your views here.
|
||||
from .forms import RegistrationForm
|
||||
from .models import User
|
||||
|
||||
class LoginView(Login):
|
||||
template_name = "localauth/register.html"
|
||||
|
||||
class LogoutView(Logout):
|
||||
next_page = "/"
|
||||
|
||||
class RegistrationView(Login):
|
||||
form_class = RegistrationForm
|
||||
template_name = "localauth/register.html"
|
||||
|
||||
def form_valid(self, form):
|
||||
user = User.objects.create_user(form.cleaned_data["email"], form.cleaned_data["password1"])
|
||||
login(self.request, user)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
|
||||
def get_default_redirect_url(self):
|
||||
return resolve_url(self.next_page or settings.REGISTER_REDIRECT_URL)
|
0
partners/templatetags/__init__.py
Normal file
0
partners/templatetags/__init__.py
Normal file
8
partners/templatetags/offeroptions.py
Normal file
8
partners/templatetags/offeroptions.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def stars(count, color="yellow"):
|
||||
return """
|
||||
"""
|
0
payment/__init__.py
Normal file
0
payment/__init__.py
Normal file
13
payment/admin.py
Normal file
13
payment/admin.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import InvoicePayment, Invoice
|
||||
from .paypal.models import PaypalInvoicePayment
|
||||
from .sepa.models import SepaInvoicePayment
|
||||
|
||||
# Register your models here.
|
||||
|
||||
admin.site.register(InvoicePayment)
|
||||
admin.site.register(Invoice)
|
||||
|
||||
admin.site.register(PaypalInvoicePayment)
|
||||
admin.site.register(SepaInvoicePayment)
|
5
payment/apps.py
Normal file
5
payment/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PaymentConfig(AppConfig):
|
||||
name = 'payment'
|
4
payment/functions.py
Normal file
4
payment/functions.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
import uuid
|
||||
|
||||
def invoice_upload_path(instance, filename):
|
||||
return "/".join(["userfiles", str(instance.user.id), str(uuid.uuid4()), filename])
|
134
payment/models.py
Normal file
134
payment/models.py
Normal file
|
@ -0,0 +1,134 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.files.base import ContentFile
|
||||
from django.utils import timezone
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from pyinvoice.models import InvoiceInfo, ServiceProviderInfo, ClientInfo, Item, Transaction, PDFInfo
|
||||
from pyinvoice.templates import SimpleInvoice
|
||||
|
||||
from polymorphic.models import PolymorphicModel
|
||||
from django_countries.fields import CountryField
|
||||
|
||||
from io import BytesIO
|
||||
|
||||
import urllib.request
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
from .functions import invoice_upload_path
|
||||
|
||||
class BillingAddress(models.Model):
|
||||
user = models.ForeignKey(get_user_model(), models.CASCADE)
|
||||
first_name = models.CharField(max_length=64)
|
||||
last_name = models.CharField(max_length=64)
|
||||
street = models.CharField(max_length=128)
|
||||
city = models.CharField(max_length=64)
|
||||
zip = models.CharField(max_length=16)
|
||||
state = models.CharField(max_length=32, null=True, blank=True)
|
||||
country = CountryField()
|
||||
|
||||
class Invoice(models.Model):
|
||||
user = models.ForeignKey(get_user_model(), models.PROTECT)
|
||||
billing_address = models.ForeignKey(BillingAddress, models.PROTECT)
|
||||
currency = models.CharField(max_length=3)
|
||||
tax_rate = models.DecimalField(max_digits=4, decimal_places=2)
|
||||
invoice = models.FileField(null=True, blank=True, upload_to=invoice_upload_path)
|
||||
|
||||
@property
|
||||
def price_net(self):
|
||||
price = 0
|
||||
|
||||
for item in self.invoiceitem_set().all():
|
||||
price += item.net_total
|
||||
|
||||
return price
|
||||
|
||||
@property
|
||||
def tax(self):
|
||||
return round(self.price_net * self.tax_rate / 100, 2)
|
||||
|
||||
@property
|
||||
def price_gross(self):
|
||||
return self.price_net + self.tax
|
||||
|
||||
@property
|
||||
def payment_instructions(self):
|
||||
return "Alle Preise in %s." % self.currency
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
return False
|
||||
|
||||
def generate_invoice(self):
|
||||
output = BytesIO()
|
||||
|
||||
pdfinfo = PDFInfo(title='Rechnung', author='Kumi Media Ltd.', subject='Rechnung')
|
||||
doc = SimpleInvoice(output, pdfinfo)
|
||||
|
||||
doc.is_paid = True
|
||||
|
||||
doc.invoice_info = InvoiceInfo("%s%i" % (getValue("billing.prefix", ""), self.id), timezone.now().date(), timezone.now().date())
|
||||
|
||||
provider_data = { key: value for key, value in {
|
||||
"name": getValue("billing.provider.name", False),
|
||||
"street": getValue("billing.provider.street", False),
|
||||
"city": getValue("billing.provider.city", False),
|
||||
"state": getValue("billing.provider.state", False),
|
||||
"country": getValue("billing.provider.country", False),
|
||||
"post_code": getValue("billing.provider.zip", False),
|
||||
"vat_tax_number": getValue("billing.provider.vat_id", False)
|
||||
}.items() if value}
|
||||
|
||||
doc.service_provider_info = ServiceProviderInfo(**provider_data)
|
||||
|
||||
logo_url = getValue("billing.logo_url", False)
|
||||
if logo_url:
|
||||
try:
|
||||
logo = BytesIO(urllib.request.urlopen(logo_url).read())
|
||||
doc.logo(logo)
|
||||
except:
|
||||
pass
|
||||
|
||||
doc.client_info = ClientInfo(email='invoice.user.email', country="Austria")
|
||||
|
||||
for item in self.invoiceitem_set().all():
|
||||
doc.add_item(Item(item.name, item.description, item.count, item.net_each))
|
||||
|
||||
doc.set_item_tax_rate(self.tax_rate)
|
||||
|
||||
for payment in self.invoicepayment_set().all():
|
||||
doc.add_transaction(Transaction(payment.gateway, payment.gateway_id, payment.timestamp, payment.amount))
|
||||
|
||||
bottom_tip = (f"{ self.payment_instructions }<br /><br />" if self.payment_instructions else "") + getValue("billing.bottom_tip", "")
|
||||
bottom_tip += "<br /><br />" if bottom_tip else ""
|
||||
bottom_tip += "Rechnung erstellt: %s" % str(timezone.now())
|
||||
|
||||
doc.set_bottom_tip(bottom_tip)
|
||||
|
||||
doc.finish()
|
||||
|
||||
self.invoice = ContentFile(output.getvalue(), "invoice.pdf")
|
||||
self.save()
|
||||
|
||||
class InvoiceItem(models.Model):
|
||||
invoice = models.ForeignKey(Invoice, models.CASCADE)
|
||||
name = models.CharField(max_length=64)
|
||||
description = models.CharField(max_length=256, null=True, blank=True)
|
||||
count = models.IntegerField()
|
||||
net_each = models.DecimalField(max_digits=11, decimal_places=2)
|
||||
|
||||
class InvoicePayment(PolymorphicModel):
|
||||
invoice = models.ForeignKey(Invoice, models.PROTECT)
|
||||
amount = models.DecimalField(max_digits=9, decimal_places=2)
|
||||
gateway_id = models.CharField(max_length=256)
|
||||
timestamp = models.DateTimeField(default=timezone.now)
|
||||
|
||||
@property
|
||||
def gateway(self):
|
||||
raise NotImplementedError("%s does not implement gateway" % type(self))
|
||||
|
||||
@staticmethod
|
||||
def initiate(invoice):
|
||||
raise NotImplementedError("%s does not implement initiate()" % type(self))
|
0
payment/paypal/__init__.py
Normal file
0
payment/paypal/__init__.py
Normal file
9
payment/paypal/api.py
Normal file
9
payment/paypal/api.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment, LiveEnvironment
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
class PaypalAPI:
|
||||
def __init__(self, client_id=None, client_secret=None, mode=None):
|
||||
mode = SandboxEnvironment if (client_secret == "sandbox" or getValue("paypal.mode") == "sandbox") else LiveEnvironment
|
||||
environment = mode(client_id=(client_id or getValue("paypal.client_id")), client_secret=(client_secret or getValue("paypal.client_secret")))
|
||||
self.client = PayPalHttpClient(environment)
|
64
payment/paypal/models.py
Normal file
64
payment/paypal/models.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
from payment.models import InvoicePayment, Invoice
|
||||
|
||||
from .api import PaypalAPI
|
||||
|
||||
from paypalcheckoutsdk.orders import OrdersCreateRequest
|
||||
from paypalhttp import HttpError
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class PaypalOrder(models.Model):
|
||||
invoice = models.ForeignKey(Invoice, models.CASCADE)
|
||||
order_id = models.CharField(max_length=64)
|
||||
|
||||
class PaypalInvoicePayment(InvoicePayment):
|
||||
@property
|
||||
def gateway(self):
|
||||
return "Paypal"
|
||||
|
||||
@staticmethod
|
||||
def initiate(invoice):
|
||||
request = OrdersCreateRequest()
|
||||
request.prefer('return=representation')
|
||||
|
||||
request.request_body (
|
||||
{
|
||||
"intent": "CAPTURE",
|
||||
"purchase_units": [
|
||||
{
|
||||
"amount": {
|
||||
"currency_code": invoice.currency,
|
||||
"value": float(invoice.price_gross)
|
||||
}
|
||||
}
|
||||
],
|
||||
"application_context": {
|
||||
"return_url": getValue("application.base_url") + reverse_lazy("this_sucks"),
|
||||
"cancel_url": getValue("application.base_url"),
|
||||
"brand_name": getValue("application.name", "JourneyJoker"),
|
||||
"landing_page": "BILLING",
|
||||
"user_action": "CONTINUE"
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
try:
|
||||
client = PaypalAPI().client
|
||||
response = client.execute(request)
|
||||
PaypalOrder.objects.create(subscription=subscription, order_id=response.result.id)
|
||||
|
||||
for link in response.result.links:
|
||||
if link.rel == "approve":
|
||||
return link.href
|
||||
|
||||
except IOError as ioe:
|
||||
logger.error(ioe)
|
||||
if isinstance(ioe, HttpError):
|
||||
logger.error(ioe.status_code)
|
4
payment/paypal/urls.py
Normal file
4
payment/paypal/urls.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
]
|
0
payment/sepa/__init__.py
Normal file
0
payment/sepa/__init__.py
Normal file
5
payment/sepa/forms.py
Normal file
5
payment/sepa/forms.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django import forms
|
||||
|
||||
class SepaApplyPaymentForm(forms.Form):
|
||||
reference = forms.CharField()
|
||||
amount = forms.DecimalField(max_digits=11, decimal_places=2)
|
59
payment/sepa/functions.py
Normal file
59
payment/sepa/functions.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
import string
|
||||
import re
|
||||
import random
|
||||
|
||||
from dbsettings.functions import getValue
|
||||
|
||||
import qrcode
|
||||
|
||||
QRCODE_CONTENT = """
|
||||
BCD
|
||||
002
|
||||
1
|
||||
SCT
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
%s%s
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
%s
|
||||
""".strip()
|
||||
|
||||
def generate_rf(reference):
|
||||
reference = str(reference).upper().zfill(21) + "RF00"
|
||||
pattern = re.compile("[A-Z0-9]+")
|
||||
if not pattern.fullmatch(reference):
|
||||
raise ValueError("Not a valid reference: %s – may only contain 0-9 and A-Z!")
|
||||
|
||||
code = ""
|
||||
|
||||
chars = string.digits + string.ascii_uppercase
|
||||
|
||||
for char in reference:
|
||||
code += str(chars.index(char))
|
||||
|
||||
remainder = int(code) % 97
|
||||
|
||||
checksum = 98 - remainder
|
||||
|
||||
return "RF%i%s" % (checksum, reference[:-4])
|
||||
|
||||
def generate_reference(length=21):
|
||||
return "".join([random.SystemRandom().choice(string.digits + string.ascii_uppercase) for i in range(length)])
|
||||
|
||||
def generate_qrcode(amount, iban="", recipient="", bic="", reference="", currency="EUR", message="", purpose="", notice=""):
|
||||
content = QRCODE_CONTENT % (
|
||||
bic or getValue("sepa.bic", ""),
|
||||
recipient or getValue("sepa.account_holder", ""),
|
||||
iban or getValue("sepa.iban"),
|
||||
currency,
|
||||
"{:0.2f}".format(float(amount)).rstrip("0"),
|
||||
purpose,
|
||||
reference if (not reference) or str(reference).startswith("RF") or len(str(reference)) > 21 else generate_rf(reference),
|
||||
message,
|
||||
notice
|
||||
)
|
||||
|
||||
return qrcode.make(content)
|
21
payment/sepa/models.py
Normal file
21
payment/sepa/models.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from payment.models import InvoicePayment, Invoice
|
||||
|
||||
from django.db import models
|
||||
|
||||
import random
|
||||
import string
|
||||
|
||||
from .functions import generate_reference
|
||||
|
||||
class SepaPaymentReference(models.Model):
|
||||
invoice = models.ForeignKey(Invoice, models.CASCADE)
|
||||
reference = models.IntegerField(default=generate_reference)
|
||||
|
||||
class SepaInvoicePayment(InvoicePayment):
|
||||
@property
|
||||
def gateway(self):
|
||||
return "Bank Transfer"
|
||||
|
||||
@staticmethod
|
||||
def initiate(subscription):
|
||||
SepaPaymentReference.objects.get_or_create(subscription=subscription)
|
4
payment/sepa/urls.py
Normal file
4
payment/sepa/urls.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
from django.urls import path
|
||||
|
||||
urlpatterns = [
|
||||
]
|
23
payment/sepa/views.py
Normal file
23
payment/sepa/views.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.views.generic import FormView
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib import messages
|
||||
|
||||
from localauth.mixins import SuperUserRequiredMixin
|
||||
|
||||
from .forms import SepaApplyPaymentForm
|
||||
from .models import SepaPaymentReference, SepaInvoicePayment
|
||||
|
||||
class SepaApplyPaymentView(SuperUserRequiredMixin, FormView):
|
||||
form_class = SepaApplyPaymentForm
|
||||
success_url = '/'
|
||||
|
||||
def form_valid(self, form):
|
||||
reference = form.cleaned_data["reference"]
|
||||
pr = get_object_or_404(SepaPaymentReference, reference=reference)
|
||||
invoice = pr.invoice
|
||||
|
||||
SepaInvoicePayment.objects.create(invoice=invoice, amount=form.cleaned_data["amount"])
|
||||
|
||||
messages.success(self.request, "Zahlung angewendet.")
|
||||
|
||||
return super().form_valid(form)
|
3
payment/tests.py
Normal file
3
payment/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
6
payment/urls.py
Normal file
6
payment/urls.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('gateways/paypal/', include("payment.paypal.urls")),
|
||||
path('gateways/sepa/', include("payment.sepa.urls")),
|
||||
]
|
0
payment/views.py
Normal file
0
payment/views.py
Normal file
|
@ -1,5 +0,0 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PaymentsConfig(AppConfig):
|
||||
name = 'payments'
|
|
@ -1,3 +0,0 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
0
public/templatetags/__init__.py
Normal file
0
public/templatetags/__init__.py
Normal file
8
public/templatetags/testimonials.py
Normal file
8
public/templatetags/testimonials.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django import template
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.simple_tag
|
||||
def testimonials():
|
||||
return """
|
||||
"""
|
9
public/urls.py
Normal file
9
public/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.urls import path
|
||||
|
||||
from .views import HomeView
|
||||
|
||||
app_name = "frontend"
|
||||
|
||||
urlpatterns = [
|
||||
path('', HomeView.as_view(), name="home"),
|
||||
]
|
|
@ -1,3 +1,4 @@
|
|||
from django.shortcuts import render
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
# Create your views here.
|
||||
class HomeView(TemplateView):
|
||||
template_name = "frontend/index.html"
|
|
@ -1,3 +1,8 @@
|
|||
Django
|
||||
django-polymorphic
|
||||
psycopg2
|
||||
dbsettings
|
||||
django-bootstrap4
|
||||
pyinvoice
|
||||
django-countries
|
||||
paypal-checkout-serversdk
|
|
@ -4,7 +4,7 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Urlaubsauktion - {{ title }}</title>
|
||||
<title>JourneyJoker{% if title %} - {{ title }}{% endif %}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon">
|
||||
|
@ -84,11 +84,11 @@
|
|||
<div id="links">
|
||||
<ul class="list-unstyled list-inline">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li class="list-inline-item">{% trans "Eingeloggt als:" %} {{ request.user.username }}</li>
|
||||
<li class="list-inline-item"><a href="{% url "profiles:logout" %}"><span><i class="fa fa-lock"></i></span>{% trans "Logout" %}</a></li>
|
||||
<li class="list-inline-item">{% trans "Eingeloggt als:" %} {{ request.user.email }} | </li>
|
||||
<li class="list-inline-item"><a href="{% url "localauth:logout" %}"><span><i class="fa fa-lock"></i></span>{% trans "Logout" %}</a></li>
|
||||
{% else %}
|
||||
<li class="list-inline-item"><a href="{% url "profiles:login" %}?next={{ request.path }}"><span><i class="fa fa-lock"></i></span>{% trans "Login" %}</a></li>
|
||||
<li class="list-inline-item"><a href="{% url "profiles:register" %}?next={{ request.path }}"><span><i class="fa fa-plus"></i></span>{% trans "Registrieren" %}</a></li>
|
||||
<li class="list-inline-item"><a href="{% url "localauth:login" %}?next={{ request.path }}"><span><i class="fa fa-lock"></i></span>{% trans "Login" %}</a></li>
|
||||
<li class="list-inline-item"><a href="{% url "localauth:register" %}?next={{ request.path }}"><span><i class="fa fa-plus"></i></span>{% trans "Registrieren" %}</a></li>
|
||||
{% endif %}
|
||||
<li class="list-inline-item">
|
||||
<form>
|
||||
|
@ -126,7 +126,7 @@
|
|||
<nav class="navbar navbar-expand-xl sticky-top navbar-custom main-navbar p-1" id="mynavbar-1">
|
||||
<div class="container">
|
||||
|
||||
<a href="{% url "frontend:index" %}" class="navbar-brand py-1 m-0"><span><i class="fa fa-plane"></i>URLAUBS</span>AUKTION</a>
|
||||
<a href="{% url "frontend:home" %}" class="navbar-brand py-1 m-0"><span><i class="fa fa-plane"></i>JOURNEY</span>JOKER</a>
|
||||
<div class="header-search d-xl-none my-auto ml-auto py-1">
|
||||
<a href="#" class="search-button" onClick="openSearch()"><span><i class="fa fa-search"></i></span></a>
|
||||
</div>
|
||||
|
@ -139,30 +139,28 @@
|
|||
<li class="nav-item active">
|
||||
<a href="/" class="nav-link" id="navbarDropdown" role="button">{% trans "Home" %}</a>
|
||||
</li>
|
||||
{% if request.user.clientprofile or not request.user.partnerprofile %}
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link" data-toggle="dropdown">{% trans "Meine Urlaubsauktion" %}<span><i class="fa fa-angle-down"></i></span></a>
|
||||
<a href="#" class="nav-link" data-toggle="dropdown">{% trans "Mein Urlaub" %}<span><i class="fa fa-angle-down"></i></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
{% if request.user.is_authenticated %}
|
||||
<li><a class="dropdown-item" href="/">{% trans "Gestellte Anfragen" %}</a></li>
|
||||
<li><a class="dropdown-item" href="/">{% trans "Gebuchte Reisen" %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="dropdown-item" href="{% url "profiles:login" %}?next={{ request.path }}">{% trans "Login" %}</a></li>
|
||||
<li><a class="dropdown-item" href="{% url "profiles:register" %}?next={{ request.path }}">{% trans "Registrieren" %}</a></li>
|
||||
<li><a class="dropdown-item" href="{% url "localauth:login" %}?next={{ request.path }}">{% trans "Login" %}</a></li>
|
||||
<li><a class="dropdown-item" href="{% url "localauth:register" %}?next={{ request.path }}">{% trans "Registrieren" %}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if request.user.partnerprofile %}
|
||||
<li class="nav-item dropdown">
|
||||
<a href="#" class="nav-link" data-toggle="dropdown">B2B<span><i class="fa fa-angle-down"></i></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<ul class="dropdown-menu">
|
||||
{% if not request.user.partnerprofile %}
|
||||
<li><a class="dropdown-item" href="/">{% trans "Als Anbieter anmelden" %}</a></li>
|
||||
{% else %}
|
||||
<li><a class="dropdown-item" href="/">{% trans "Bieten" %}</a></li>
|
||||
<li><a class="dropdown-item" href="/">{% trans "Buchungen verwalten" %}</a></li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
@ -452,7 +450,7 @@
|
|||
<div class="col-12 col-md-6 col-lg-3 col-xl-3 footer-widget ftr-contact">
|
||||
<h3 class="footer-heading">Kontakt</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li><span><i class="fa fa-map-marker"></i></span>Think:Put – Die Agentur für Denken & Tun, Kolingasse 10/10, 1090 Wien</li>
|
||||
<li><span><i class="fa fa-map-marker"></i></span>Think:Put<br>Die Agentur für Denken & Tun<br>Kolingasse 10/10<br>1090 Wien</li>
|
||||
<!--<li><span><i class="fa fa-phone"></i></span>+43 800 093004</li>
|
||||
<li><span><i class="fa fa-envelope"></i></span>office@kumi.systems</li>-->
|
||||
</ul>
|
||||
|
@ -466,7 +464,7 @@
|
|||
</div><!-- end columns -->
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-3 col-xl-3 footer-widget ftr-links ftr-pad-left">
|
||||
<h3 class="footer-heading">Urlaubsauktion</h3>
|
||||
<h3 class="footer-heading">JourneyJoker</h3>
|
||||
<ul class="list-unstyled">
|
||||
<li><a href="#">Impressum</a></li>
|
||||
<li><a href="#">Kontakt</a></li>
|
||||
|
@ -477,7 +475,7 @@
|
|||
|
||||
<div class="col-12 col-md-6 col-lg-4 col-xl-4 footer-widget ftr-about">
|
||||
<h3 class="footer-heading">Über uns</h3>
|
||||
<p>Die Urlaubsauktion ist ur leiwand. Oida.</p>
|
||||
<p>Der Joker ist ur leiwand. Oida.</p>
|
||||
<ul class="social-links list-inline list-unstyled">
|
||||
<li class="list-inline-item"><a href="#"><span><i class="fab fa-facebook"></i></span></a></li>
|
||||
<li class="list-inline-item"><a href="#"><span><i class="fab fa-twitter"></i></span></a></li>
|
||||
|
@ -497,7 +495,7 @@
|
|||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 col-lg-6 col-xl-6" id="copyright">
|
||||
<p>© 2020 <a href="https://thinkput.at/">Think:Put – Die Agentur für Denken & Tun</a> – Web-Entwicklung: <a href="https://">Kumi Systems e.U.</a></p>
|
||||
<p>© 2020 – 2021 <a href="https://thinkput.at/">Think:Put – Die Agentur für Denken & Tun</a></p><p>Entwicklung: <a href="https://kumi.systems/">Kumi Systems e.U.</a> – <a href="https://kumi.media">Kumi Media Ltd.</a></p>
|
||||
</div><!-- end columns -->
|
||||
|
||||
<div class="col-12 col-md-6 col-lg-6 col-xl-6" id="terms">
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
height:100%;">
|
||||
<div class=" meta">
|
||||
<div class="container">
|
||||
<h2>{% trans "Willkommen zur großen" %}</h2>
|
||||
<h1>{% trans "Urlaubs-Umkehrauktion" %}</h1>
|
||||
<a href="#" class="btn btn-default">{% trans "Was bedeutet das?" %}</a>
|
||||
<h2>{% trans "Willkommen bei JourneyJoker" %}</h2>
|
||||
<h1>{% trans "Mein Urlaub nach Maß" %}</h1>
|
||||
<a href="#" class="btn btn-default">{% trans "Wie geht das?" %}</a>
|
||||
</div><!-- end container -->
|
||||
</div><!-- end meta -->
|
||||
</li><!-- end item-1 -->
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load bootstrap %}
|
||||
{% load bootstrap4 %}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Urlaubsauktion - {{ title }}</title>
|
||||
<title>JourneyJoker - {{ title }}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<link rel="icon" href="{% static "frontend/images/favicon.png" %}" type="image/x-icon">
|
||||
|
@ -44,14 +44,14 @@
|
|||
<div class="col-md-12">
|
||||
|
||||
<div class="full-page-title">
|
||||
<a href="{% url "frontend:index" %}"><h3 class="company-name"><span><i class="fa fa-plane"></i>Urlaubs</span>Auktion</h3></a>
|
||||
<a href="{% url "frontend:home" %}"><h3 class="company-name"><span><i class="fa fa-plane"></i>Journey</span>Joker</h3></a>
|
||||
</div><!-- end full-page-title -->
|
||||
|
||||
<div class="custom-form custom-form-fields">
|
||||
<h3>{{ title }}</h3>
|
||||
<form method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form|bootstrap }}
|
||||
{% bootstrap_form form %}
|
||||
<button class="btn btn-orange btn-block">{% trans "Login" %}</button>
|
||||
</form>
|
||||
|
||||
|
@ -61,7 +61,7 @@
|
|||
</div><!-- end other-links -->
|
||||
</div><!-- end custom-form -->
|
||||
|
||||
<p class="full-page-copyright">© 2020 <a href="https://kumi.systems/">Kumi Systems e.U.</a> All rights reserved.</p>
|
||||
<p class="full-page-copyright">© 2020 – 2021 <a href="https://kumi.systems/">Kumi Systems e.U.</a> All rights reserved.</p>
|
||||
</div><!-- end columns -->
|
||||
</div><!-- end row -->
|
||||
</div><!-- end container -->
|
|
@ -15,6 +15,14 @@ INSTALLED_APPS = [
|
|||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'localauth',
|
||||
'public',
|
||||
'partners',
|
||||
'payment',
|
||||
'clients',
|
||||
'dbsettings',
|
||||
'auction',
|
||||
'bootstrap4',
|
||||
'django_countries',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
@ -32,7 +40,7 @@ ROOT_URLCONF = 'urlaubsauktion.urls'
|
|||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'DIRS': [BASE_DIR / "templates"],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
|
@ -53,7 +61,7 @@ WSGI_APPLICATION = 'urlaubsauktion.wsgi.application'
|
|||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'ENGINE': 'django.contrib.gis.db.backends.postgis',
|
||||
'NAME': DB_NAME,
|
||||
'USER': DB_USER,
|
||||
'PASSWORD': DB_PASS,
|
||||
|
@ -101,4 +109,11 @@ USE_TZ = True
|
|||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
AUTH_USER_MODEL = "localauth.Account"
|
||||
STATICFILES_DIRS = [
|
||||
BASE_DIR / "static",
|
||||
]
|
||||
|
||||
AUTH_USER_MODEL = "localauth.User"
|
||||
|
||||
REGISTER_REDIRECT_URL = "/"
|
||||
LOGIN_REDIRECT_URL = "/"
|
|
@ -14,8 +14,12 @@ Including another URLconf
|
|||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('', include('public.urls')),
|
||||
path('auth/', include('localauth.urls')),
|
||||
path('auction/', include('auction.urls')),
|
||||
path('payment/', include('payment.urls')),
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue