Merge pull request #128 from levivm/feature/new_digitalglarus
Feature/new digitalglarus
This commit is contained in:
commit
2481f610a6
|
@ -7,7 +7,7 @@ from datetime import datetime
|
|||
from utils.models import BillingAddress
|
||||
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
|
||||
|
||||
from .models import MembershipType
|
||||
from .models import MembershipType, MembershipOrder
|
||||
from .models import Booking
|
||||
|
||||
|
||||
|
@ -39,6 +39,23 @@ class MembershipBillingForm(BillingAddressForm):
|
|||
}
|
||||
|
||||
|
||||
class MembershipOrderForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = MembershipOrder
|
||||
fields = ['membership', 'customer', 'billing_address',
|
||||
'last4', 'cc_brand', 'stripe_charge_id', 'amount']
|
||||
|
||||
# def save(self, commit=True):
|
||||
# instance = super(MembershipOrderForm, self).save(commit=False)
|
||||
|
||||
# # if commit:
|
||||
# # DonatorStatus.create(self.cleaned_data['donator'].user)
|
||||
# # instance.save()
|
||||
|
||||
# return instance
|
||||
|
||||
|
||||
class BookingBillingForm(BillingAddressForm):
|
||||
token = forms.CharField(widget=forms.HiddenInput())
|
||||
start_date = forms.DateField(widget=forms.HiddenInput())
|
||||
|
@ -60,37 +77,14 @@ class BookingBillingForm(BillingAddressForm):
|
|||
class BookingDateForm(forms.Form):
|
||||
start_date = forms.DateField(required=False,
|
||||
widget=forms.TextInput(attrs={'id': 'booking-date-1',
|
||||
'value': ''}))
|
||||
'value': 'Select your date'}))
|
||||
end_date = forms.DateField(required=False,
|
||||
widget=forms.TextInput(attrs={'id': 'booking-date-2'}))
|
||||
|
||||
# def clean_date_range(self):
|
||||
# date_range = self.cleaned_data.get('date_range')
|
||||
# dates = date_range.replace(' ', '').split('-')
|
||||
# try:
|
||||
# start_date, end_date = [datetime.strptime(date_string, "%m/%d/%Y").date()
|
||||
# for date_string in dates]
|
||||
# except ValueError:
|
||||
# raise forms.ValidationError("Submit valid dates.")
|
||||
|
||||
# if start_date > end_date:
|
||||
# raise forms.ValidationError("Your end date must be greather than your start date.")
|
||||
|
||||
# q1 = Q(start_date__lte=start_date, end_date__gte=start_date)
|
||||
# q2 = Q(start_date__gt=start_date, start_date__lte=end_date)
|
||||
# if Booking.objects.filter(q1 | q2).exists():
|
||||
# raise forms.ValidationError("You already have a booking in these dates.")
|
||||
|
||||
# return start_date, end_date
|
||||
|
||||
def clean_start_date(self):
|
||||
start_date = self.cleaned_data.get('start_date')
|
||||
if not start_date:
|
||||
raise forms.ValidationError("This field is required.")
|
||||
# try:
|
||||
# start_date = datetime.strptime(start_date, "%m/%d/%Y").date()
|
||||
# except ValueError:
|
||||
# raise forms.ValidationError("Submit valid dates.")
|
||||
return start_date
|
||||
|
||||
def clean_end_date(self):
|
||||
|
|
166
digitalglarus/management/commands/make_membership_charge.py
Normal file
166
digitalglarus/management/commands/make_membership_charge.py
Normal file
|
@ -0,0 +1,166 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
|
||||
from datetime import datetime
|
||||
from django.utils import translation
|
||||
|
||||
from utils.stripe_utils import StripeUtils
|
||||
|
||||
from utils.mailer import BaseEmail
|
||||
from digitalglarus.models import MembershipOrder
|
||||
from digitalglarus.forms import MembershipOrderForm
|
||||
# from membership.U
|
||||
# from nosystemd.models import DonatorStatus, Donation
|
||||
# from nosystemd.forms import DonationForm
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Make the monthly stripe charge to all donators'
|
||||
CURRENCY = 'usd'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
translation.activate('en-us')
|
||||
memberships_orders = MembershipOrder.objects.filter(membership__active=True)
|
||||
current_month = datetime.now().month
|
||||
current_year = datetime.now().year
|
||||
|
||||
print("--------- STARTING MEMBERSHIP CHARGING SCRIPT ---------")
|
||||
print("Memberhips date: %s-%s" % (current_month, current_year))
|
||||
|
||||
for membership_order in memberships_orders:
|
||||
member = membership_order.customer
|
||||
try:
|
||||
MembershipOrder.objects.get(created_at__month=current_month,
|
||||
created_at__year=current_year,
|
||||
customer=member)
|
||||
except MembershipOrder.DoesNotExist:
|
||||
try:
|
||||
current_membership_price = membership_order.membership.type.price
|
||||
|
||||
last_membership_order = MembershipOrder.objects.filter(customer=member).last()
|
||||
|
||||
# Make stripe charge to a customer
|
||||
stripe_utils = StripeUtils()
|
||||
stripe_utils.CURRENCY = self.CURRENCY
|
||||
charge_response = stripe_utils.make_charge(amount=current_membership_price,
|
||||
customer=member.stripe_id)
|
||||
charge = charge_response.get('response_object')
|
||||
# Check if the payment was approved
|
||||
if not charge:
|
||||
# There is an error trying to creating the stripe charge
|
||||
context = {
|
||||
'paymentError': charge_response.get('error'),
|
||||
}
|
||||
print("--------- STRIPE PAYMENT ERROR ---------")
|
||||
print(context)
|
||||
print("-------------------------")
|
||||
continue
|
||||
|
||||
# Create a donation
|
||||
charge = charge_response.get('response_object')
|
||||
membership_order_data = {
|
||||
'cc_brand': charge.source.brand,
|
||||
'stripe_charge_id': charge.id,
|
||||
'last4': charge.source.last4,
|
||||
'membership': last_membership_order.membership.id,
|
||||
'billing_address': last_membership_order.billing_address.id,
|
||||
'customer': member.id,
|
||||
'amount': current_membership_price
|
||||
}
|
||||
membership_order_form = MembershipOrderForm(membership_order_data)
|
||||
import pdb
|
||||
pdb.set_trace()
|
||||
if membership_order_form.is_valid():
|
||||
membership_order = membership_order_form.save()
|
||||
|
||||
context = {
|
||||
'order': membership_order,
|
||||
'base_url': "{0}://{1}".format('https', 'dynamicweb.ungleich.ch')
|
||||
|
||||
}
|
||||
email_data = {
|
||||
'subject': 'Your monthly membership has been charged',
|
||||
'to': member.user.email,
|
||||
'context': context,
|
||||
'template_name': 'membership_monthly_charge',
|
||||
'template_path': 'digitalglarus/emails/'
|
||||
}
|
||||
email = BaseEmail(**email_data)
|
||||
email.send()
|
||||
|
||||
print("--------- PAYMENT DONATION SUCCESSFULL ---------")
|
||||
print("Member: %s" % member.user.email)
|
||||
print("Amount: %s %s" % (current_membership_price, self.CURRENCY))
|
||||
print("-----------------------------------------------")
|
||||
|
||||
except Exception as e:
|
||||
print("--------- ERROR ---------")
|
||||
print(e)
|
||||
print("-------------------------")
|
||||
continue
|
||||
# for donator_status in donators:
|
||||
# donator = donator_status.user.stripecustomer
|
||||
# try:
|
||||
# Donation.objects.get(created_at__month=current_month,
|
||||
# created_at__year=current_year,
|
||||
# donator=donator)
|
||||
# except Donation.DoesNotExist:
|
||||
# try:
|
||||
# # Get donator last donation amount
|
||||
# last_donation = Donation.objects.filter(donator=donator).last()
|
||||
# donation_amount = last_donation.donation
|
||||
|
||||
# # Make stripe charge to a customer
|
||||
# stripe_utils = StripeUtils()
|
||||
# stripe_utils.CURRENCY = self.CURRENCY
|
||||
# charge_response = stripe_utils.make_charge(amount=donation_amount,
|
||||
# customer=donator.stripe_id)
|
||||
# charge = charge_response.get('response_object')
|
||||
|
||||
# # Check if the payment was approved
|
||||
# if not charge:
|
||||
# # There is an error trying to creating the stripe charge
|
||||
# context = {
|
||||
# 'paymentError': charge_response.get('error'),
|
||||
# }
|
||||
# print("--------- STRIPE PAYMENT ERROR ---------")
|
||||
# print(context)
|
||||
# print("-------------------------")
|
||||
# continue
|
||||
# # Create a donation
|
||||
# charge = charge_response.get('response_object')
|
||||
# donation_data = {
|
||||
# 'cc_brand': charge.source.brand,
|
||||
# 'stripe_charge_id': charge.id,
|
||||
# 'last4': charge.source.last4,
|
||||
# 'billing_address': last_donation.billing_address.id,
|
||||
# 'donator': donator.id,
|
||||
# 'donation': donation_amount
|
||||
# }
|
||||
# donation_form = DonationForm(donation_data)
|
||||
# if donation_form.is_valid():
|
||||
# donation = donation_form.save()
|
||||
|
||||
# context = {
|
||||
# 'donation': donation,
|
||||
# 'base_url': "{0}://{1}".format('https', 'dynamicweb.ungleich.ch')
|
||||
|
||||
# }
|
||||
# email_data = {
|
||||
# 'subject': 'Your donation have been charged',
|
||||
# 'to': donation.donator.user.email,
|
||||
# 'context': context,
|
||||
# 'template_name': 'donation_charge',
|
||||
# 'template_path': 'nosystemd/emails/'
|
||||
# }
|
||||
# email = BaseEmail(**email_data)
|
||||
# email.send()
|
||||
|
||||
# print("--------- PAYMENT DONATION SUCCESSFULL ---------")
|
||||
# print("Donator: %s" % donation.donator.user.email)
|
||||
# print("Amount: %s %s" % (donation.donation, self.CURRENCY))
|
||||
# print("-----------------------------------------------")
|
||||
# except Exception as e:
|
||||
# print("--------- ERROR ---------")
|
||||
# print(e)
|
||||
# print("-------------------------")
|
||||
# continue
|
27
digitalglarus/migrations/0018_auto_20160928_0424.py
Normal file
27
digitalglarus/migrations/0018_auto_20160928_0424.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2016-09-28 04:24
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('digitalglarus', '0017_membership_active'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bookingorder',
|
||||
name='membership_required_months',
|
||||
field=models.IntegerField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='bookingorder',
|
||||
name='membership_required_months_price',
|
||||
field=models.FloatField(default=0),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
25
digitalglarus/migrations/0019_auto_20160929_0324.py
Normal file
25
digitalglarus/migrations/0019_auto_20160929_0324.py
Normal file
|
@ -0,0 +1,25 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.4 on 2016-09-29 03:24
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('digitalglarus', '0018_auto_20160928_0424'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='bookingorder',
|
||||
name='membership_required_months',
|
||||
field=models.IntegerField(default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='bookingorder',
|
||||
name='membership_required_months_price',
|
||||
field=models.FloatField(default=0),
|
||||
),
|
||||
]
|
|
@ -9,7 +9,7 @@ class MembershipRequiredMixin(object):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
from .models import Membership
|
||||
if not Membership.is_digitalglarus_member(request.user):
|
||||
if not Membership.is_digitalglarus_active_member(request.user):
|
||||
return HttpResponseRedirect(self.membership_redirect_url)
|
||||
|
||||
return super(MembershipRequiredMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
@ -20,7 +20,7 @@ class IsNotMemberMixin(object):
|
|||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
from .models import Membership
|
||||
if Membership.is_digitalglarus_member(request.user):
|
||||
if Membership.is_digitalglarus_active_member(request.user):
|
||||
return HttpResponseRedirect(self.already_member_redirect_url)
|
||||
|
||||
return super(IsNotMemberMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
|
|
@ -16,8 +16,9 @@ from .mixins import Ordereable
|
|||
|
||||
class MembershipType(models.Model):
|
||||
|
||||
STANDARD = 'standard'
|
||||
MEMBERSHIP_TYPES = (
|
||||
('standard', 'Standard'),
|
||||
(STANDARD, 'Standard'),
|
||||
|
||||
)
|
||||
name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20)
|
||||
|
@ -63,7 +64,12 @@ class Membership(models.Model):
|
|||
active = models.BooleanField(default=True)
|
||||
|
||||
@classmethod
|
||||
def is_digitalglarus_member(cls, user):
|
||||
def create(cls, data):
|
||||
instance = cls.objects.create(**data)
|
||||
return instance
|
||||
|
||||
@classmethod
|
||||
def is_digitalglarus_active_member(cls, user):
|
||||
past_month = (datetime.today() - relativedelta(months=1)).month
|
||||
has_booking_current_month = Q(membershiporder__customer__user=user,
|
||||
membershiporder__created_at__month=datetime.today().month)
|
||||
|
@ -73,11 +79,6 @@ class Membership(models.Model):
|
|||
return cls.objects.filter(has_booking_past_month | has_booking_current_month).\
|
||||
filter(active_membership).exists()
|
||||
|
||||
@classmethod
|
||||
def create(cls, data):
|
||||
instance = cls.objects.create(**data)
|
||||
return instance
|
||||
|
||||
def deactivate(self):
|
||||
self.active = False
|
||||
self.save()
|
||||
|
@ -158,6 +159,14 @@ class Booking(models.Model):
|
|||
total_free_days = months * TWO_DAYS + free_days_this_month
|
||||
return total_free_days
|
||||
|
||||
@staticmethod
|
||||
def membership_required_booking_months(start_date, end_date):
|
||||
start_month = start_date.month
|
||||
end_month = end_date.month
|
||||
months = abs(start_month - (end_month + 12) if end_month < start_month
|
||||
else end_month - start_month)
|
||||
return months
|
||||
|
||||
@classmethod
|
||||
def booking_price(cls, user, start_date, end_date):
|
||||
|
||||
|
@ -178,13 +187,34 @@ class Booking(models.Model):
|
|||
free_days = cls.get_ramaining_free_days(user, start_date, end_date)
|
||||
final_booking_price = normal_price - (free_days * price_per_day)
|
||||
|
||||
return normal_price, final_booking_price, free_days
|
||||
# Calculating membership required months price for booking
|
||||
required_membership_months = 0
|
||||
membership_booking_price = 0.0
|
||||
if BookingOrder.user_has_not_bookings(user):
|
||||
today = datetime.today().date()
|
||||
membership_price = MembershipType.objects.get(name=MembershipType.STANDARD).price
|
||||
required_membership_months = cls.membership_required_booking_months(today, end_date)
|
||||
membership_booking_price = membership_price * required_membership_months
|
||||
|
||||
# Add required membership months to final prices
|
||||
final_booking_price += membership_booking_price
|
||||
|
||||
return normal_price, final_booking_price, free_days,\
|
||||
required_membership_months, membership_booking_price
|
||||
|
||||
|
||||
class BookingOrder(Ordereable, models.Model):
|
||||
booking = models.OneToOneField(Booking)
|
||||
original_price = models.FloatField()
|
||||
special_month_price = models.FloatField()
|
||||
membership_required_months = models.IntegerField(default=0)
|
||||
membership_required_months_price = models.FloatField(default=0)
|
||||
|
||||
|
||||
@classmethod
|
||||
def user_has_not_bookings(cls, user):
|
||||
return cls.objects.filter(customer__user=user).exists()
|
||||
|
||||
|
||||
def booking_days(self):
|
||||
return (self.booking.end_date - self.booking.start_date).days + 1
|
||||
|
|
|
@ -7,14 +7,16 @@ $( document ).ready(function() {
|
|||
|
||||
|
||||
var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
|
||||
|
||||
$('#booking-date-1').datetimepicker({
|
||||
// minDate: tomorrow,
|
||||
format: 'MM/d/YYYY',
|
||||
defaultDate: false
|
||||
minDate: tomorrow,
|
||||
format: 'MM/DD/YYYY',
|
||||
// defaultDate: false
|
||||
});
|
||||
$('#booking-date-1').val('');
|
||||
$('#booking-date-2').datetimepicker({
|
||||
useCurrent: false, //Important! See issue #1075
|
||||
format: 'MM/d/YYYY',
|
||||
format: 'MM/DD/YYYY',
|
||||
});
|
||||
$("#booking-date-1").on("dp.change", function (e) {
|
||||
$('#booking-date-2').data("DateTimePicker").minDate(e.date);
|
||||
|
@ -23,24 +25,4 @@ $( document ).ready(function() {
|
|||
$('#booking-date-1').data("DateTimePicker").maxDate(e.date);
|
||||
});
|
||||
|
||||
|
||||
// var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
|
||||
// // var tomorrow = today.setDate(today.getDate() + 1);
|
||||
// $('#booking-date-range').daterangepicker({
|
||||
// autoUpdateInput: false,
|
||||
// locale: {
|
||||
// cancelLabel: 'Clear'
|
||||
// },
|
||||
// minDate: tomorrow,
|
||||
// });
|
||||
|
||||
|
||||
// $('#booking-date-range').on('apply.daterangepicker', function(ev, picker) {
|
||||
// $(this).val(picker.startDate.format('MM/DD/YYYY') + ' - ' + picker.endDate.format('MM/DD/YYYY'));
|
||||
// });
|
||||
|
||||
// $('#booking-date-range').on('dp.cancel', function(ev, picker) {
|
||||
// $(this).val('Select your dates');
|
||||
// });
|
||||
|
||||
});
|
|
@ -7,6 +7,7 @@
|
|||
.invoice-title{
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
@ -19,7 +20,7 @@
|
|||
<div class="payment-box">
|
||||
<h2 class="section-heading payment-head">Your Booking Detail</h2>
|
||||
<hr class="greyline-long">
|
||||
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print" data-print="price">Get PDF</btn></h2>
|
||||
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print hidden-print" data-print="price">Get PDF</btn></h2>
|
||||
|
||||
<h2 class="order-head">Order Number</h2>
|
||||
<h2 class="member-name">#{{order.id}}</h2>
|
||||
|
@ -43,6 +44,10 @@
|
|||
</h2>
|
||||
<h2 class="col-xs-6 payment-total text-left">Total days {{booking_days}}</h2>
|
||||
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
|
||||
{% if membership_required_months and membership_required_months_price %}
|
||||
<h2 class="col-xs-6 payment-total text-left">Required Membership months: {{membership_required_months}}</h2>
|
||||
<h2 class="order-sum"><span>{{membership_required_months_price|floatformat}}CHF</span></h2>
|
||||
{% endif %}
|
||||
{% if free_days %}
|
||||
<h2 class="col-xs-6 payment-total text-left">Free days {{free_days}} </h2>
|
||||
<h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>
|
||||
|
@ -54,7 +59,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown">
|
||||
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown hidden-print">
|
||||
<div class="order-summary">
|
||||
<div class="header text-center">
|
||||
<h2 class="order-name">Order Summary</h2>
|
||||
|
@ -64,6 +69,10 @@
|
|||
|
||||
<h2 class="col-xs-6 payment-total">Total days {{booking_days}}</h2>
|
||||
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
|
||||
{% if membership_required_months and membership_required_months_price %}
|
||||
<h2 class="col-xs-6 payment-total">Required Membership months: {{membership_required_months}}</h2>
|
||||
<h2 class="order-sum"><span>{{membership_required_months_price|floatformat}}CHF</span></h2>
|
||||
{% endif %}
|
||||
{% if free_days %}
|
||||
<h2 class="col-xs-6 payment-total">Free days {{free_days}}</h2>
|
||||
<h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>
|
||||
|
|
|
@ -121,15 +121,20 @@
|
|||
<br/>
|
||||
|
||||
<hr class="greyline">
|
||||
<h2 class="col-xs-6 payment-total">Total days {{booking_days}} </h2>
|
||||
<h2 class="col-xs-6 payment-total">Total days: {{booking_days}} </h2>
|
||||
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
|
||||
{% if membership_required_months and membership_required_months_price %}
|
||||
<h2 class="col-xs-6 payment-total">Required Membership months: {{membership_required_months}}</h2>
|
||||
<h2 class="order-sum"><span>{{membership_required_months_price|floatformat}}CHF</span></h2>
|
||||
{% endif %}
|
||||
<br/>
|
||||
{% if free_days %}
|
||||
<h2 class="col-xs-6 payment-total">Free days {{free_days}}</h2>
|
||||
<h2 class="col-xs-6 payment-total">Free days: {{free_days}}</h2>
|
||||
<h2 class="order-sum"><span class="text-danger">-{{total_discount|floatformat}}CHF</span></h2>
|
||||
{% endif %}
|
||||
<hr class="greyline">
|
||||
<h2 class="col-xs-6 payment-total">Total</h2>
|
||||
<h2 class="order-result">{{discount_price|floatformat}}CHF</h2>
|
||||
<h2 class="order-result">{{final_price|floatformat}}CHF</h2>
|
||||
<div class="text-center">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<br/>
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
{% load static from staticfiles %}
|
||||
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Oxygen Invoice</title>
|
||||
</head>
|
||||
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width: 480px) {
|
||||
table[class*="container-for-gmail-android"] {
|
||||
min-width: 290px !important; width: 100% !important;
|
||||
}
|
||||
img[class="force-width-gmail"] {
|
||||
display: none !important; width: 0 !important; height: 0 !important;
|
||||
}
|
||||
table[class="w320"] {
|
||||
width: 320px !important;
|
||||
}
|
||||
td[class*="mobile-header-padding-left"] {
|
||||
width: 160px !important; padding-left: 0 !important;
|
||||
}
|
||||
td[class*="mobile-header-padding-right"] {
|
||||
width: 160px !important; padding-right: 0 !important;
|
||||
}
|
||||
td[class="header-lg"] {
|
||||
font-size: 24px !important; padding-bottom: 5px !important;
|
||||
}
|
||||
td[class="content-padding"] {
|
||||
padding: 5px 0 5px !important;
|
||||
}
|
||||
td[class="button"] {
|
||||
padding: 5px 5px 30px !important;
|
||||
}
|
||||
td[class*="free-text"] {
|
||||
padding: 10px 18px 30px !important;
|
||||
}
|
||||
td[class~="mobile-hide-img"] {
|
||||
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
|
||||
}
|
||||
td[class~="item"] {
|
||||
width: 140px !important; vertical-align: top !important;
|
||||
}
|
||||
td[class~="quantity"] {
|
||||
width: 50px !important;
|
||||
}
|
||||
td[class~="price"] {
|
||||
width: 90px !important;
|
||||
}
|
||||
td[class="item-table"] {
|
||||
padding: 30px 20px !important;
|
||||
}
|
||||
td[class="mini-container-left"] {
|
||||
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
|
||||
}
|
||||
td[class="mini-container-right"] {
|
||||
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
|
||||
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
|
||||
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
|
||||
</td>
|
||||
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
|
||||
Thank you for your subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
|
||||
Your monthly membership for {{order.created_at|date:"F"}} has been charged. <br/> You can view your invoice clicking on the button below.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
|
||||
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<!--[if mso]>
|
||||
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
|
||||
<w:anchorlock/>
|
||||
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
|
||||
</v:roundrect>
|
||||
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
|
||||
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
{% load static from staticfiles %}
|
||||
<!-- Inliner Build Version 4380b7741bb759d6cb997545f3add21ad48f010b -->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Oxygen Invoice</title>
|
||||
</head>
|
||||
<body bgcolor="#f7f7f7" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; -webkit-font-smoothing: antialiased; -webkit-text-size-adjust: none; width: 100% !important; height: 100%; color: white; margin: 0;">
|
||||
<style type="text/css">
|
||||
@media only screen and (max-width: 480px) {
|
||||
table[class*="container-for-gmail-android"] {
|
||||
min-width: 290px !important; width: 100% !important;
|
||||
}
|
||||
img[class="force-width-gmail"] {
|
||||
display: none !important; width: 0 !important; height: 0 !important;
|
||||
}
|
||||
table[class="w320"] {
|
||||
width: 320px !important;
|
||||
}
|
||||
td[class*="mobile-header-padding-left"] {
|
||||
width: 160px !important; padding-left: 0 !important;
|
||||
}
|
||||
td[class*="mobile-header-padding-right"] {
|
||||
width: 160px !important; padding-right: 0 !important;
|
||||
}
|
||||
td[class="header-lg"] {
|
||||
font-size: 24px !important; padding-bottom: 5px !important;
|
||||
}
|
||||
td[class="content-padding"] {
|
||||
padding: 5px 0 5px !important;
|
||||
}
|
||||
td[class="button"] {
|
||||
padding: 5px 5px 30px !important;
|
||||
}
|
||||
td[class*="free-text"] {
|
||||
padding: 10px 18px 30px !important;
|
||||
}
|
||||
td[class~="mobile-hide-img"] {
|
||||
display: none !important; height: 0 !important; width: 0 !important; line-height: 0 !important;
|
||||
}
|
||||
td[class~="item"] {
|
||||
width: 140px !important; vertical-align: top !important;
|
||||
}
|
||||
td[class~="quantity"] {
|
||||
width: 50px !important;
|
||||
}
|
||||
td[class~="price"] {
|
||||
width: 90px !important;
|
||||
}
|
||||
td[class="item-table"] {
|
||||
padding: 30px 20px !important;
|
||||
}
|
||||
td[class="mini-container-left"] {
|
||||
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
|
||||
}
|
||||
td[class="mini-container-right"] {
|
||||
padding: 0 15px 15px !important; display: block !important; width: 290px !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<table align="center" cellpadding="0" cellspacing="0" class="container-for-gmail-android" width="100%" style="border-collapse: collapse !important; min-width: 600px; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="left" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #ffffff url(http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg) repeat-x;" bgcolor="#ffffff">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="100%" bgcolor="#ffffff" background="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; background: transparent;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td width="100%" height="80" valign="top" style="text-align: center; vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; line-height: 21px;" align="center">
|
||||
<!--[if gte mso 9]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="mso-width-percent:1000;height:80px; v-text-anchor:middle;">
|
||||
<v:fill type="tile" src="http://s3.amazonaws.com/swu-filepicker/4E687TRe69Ld95IDWyEg_bg_top_02.jpg" color="#ffffff" />
|
||||
<v:textbox inset="0,0,0,0">
|
||||
<![endif]-->
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellpadding="0" cellspacing="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="pull-left mobile-header-padding-left" style="vertical-align: middle; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: left; line-height: 21px; width: 290px; padding-left: 10px;" align="left" valign="middle">
|
||||
<a href="{{base_url}}" style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; color: #676767; text-decoration: none !important;"><img width="137" src="{{base_url}}{% static "hosting/img/logo_black.png" %}" alt="logo" style="max-width: 600px; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; border: none;"></a>
|
||||
</td>
|
||||
<td class="pull-right mobile-header-padding-right" style="color: #4d4d4d; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; text-align: right; line-height: 21px; width: 290px; padding-left: 10px;" align="right">
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
<!--[if gte mso 9]>
|
||||
</v:textbox>
|
||||
</v:rect>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="center" valign="top" width="100%" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7; padding: 20px 0 5px;" class="content-padding" bgcolor="#f7f7f7">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="header-lg" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 32px; color: #4d4d4d; text-align: center; line-height: normal; font-weight: 700; padding: 35px 0 0;" align="center">
|
||||
Thank you for your subscription.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="free-text" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; width: 100% !important; padding: 10px 60px 0px;" align="center">
|
||||
Your monthly membership for {{order.created_at|date:"F"}} has been charged. <br/> You can view your invoice clicking on the button below.
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td class="button" style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 30px 0;" align="center">
|
||||
<div style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<!--[if mso]>
|
||||
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="http://" style="height:45px;v-text-anchor:middle;width:155px;" arcsize="15%" strokecolor="#ffffff" fillcolor="#ff6f6f">
|
||||
<w:anchorlock/>
|
||||
<center style="color:#ffffff;font-family:Helvetica, Arial, sans-serif;font-size:14px;font-weight:regular;">My Account</center>
|
||||
</v:roundrect>
|
||||
<![endif]--><a href="{{ base_url }}{% url 'digitalglarus:membership_orders_detail' order.id %}" style="border-radius: 5px; color: #ffffff; display: inline-block; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; font-weight: regular; line-height: 45px; text-align: center; text-decoration: none !important; width: 155px; -webkit-text-size-adjust: none; mso-hide: all; background: #ff6f6f;">View Invoice</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td align="center" valign="top" width="100%" style="height: 100px; border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; background: #f7f7f7;" bgcolor="#f7f7f7">
|
||||
<center style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320" style="border-collapse: collapse !important; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;"><tr style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
<td style="border-collapse: collapse; font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important; font-size: 14px; color: #777777; text-align: center; line-height: 21px; padding: 25px 0;" align="center">
|
||||
<strong style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">ungleich</strong><br style="font-family: 'Oxygen', 'Helvetica Neue', 'Arial', 'sans-serif' !important;">
|
||||
</td>
|
||||
</tr></table>
|
||||
</center>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -10,7 +10,9 @@
|
|||
<div class="signup-box">
|
||||
<span class="glyphicon glyphicon-user"></span>
|
||||
<h2 class="section-heading">Log In</h2>
|
||||
<h2 class="signup-lead">Welcome!<br></h2>
|
||||
{% if not messages %}
|
||||
<h2 class="signup-lead">Welcome!<br></h2>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if messages %}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
{% extends "new_base_glarus.html" %}
|
||||
{% load staticfiles cms_tags bootstrap3%}
|
||||
{% block title %}crowdfunding{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section id="price">
|
||||
<div class="signup-container">
|
||||
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
|
||||
<div class="col-xs-12 col-sm-6 col-lg-4 text-center wow fadeInDown">
|
||||
|
||||
<!-- <span class="glyphicon glyphicon-user"></span> -->
|
||||
<div class="payment-box">
|
||||
<h2 class="billing-head">Membership Deactivated</h2>
|
||||
<hr class="greyline-long">
|
||||
<h2 class="membership-lead">Your Digital Glarus membership has been deactivated.</h2>
|
||||
<div class="date-box">
|
||||
</div>
|
||||
<!--<hr class="primary">-->
|
||||
<div class="signup-form form-group row">
|
||||
|
||||
<div class="button-booking-box form-inline row">
|
||||
<a class="btn btn-primary btn-blue" href={% url 'digitalglarus:membership_orders_list' %}>Go to your membership orders</a>
|
||||
</div>
|
||||
<div class="notice-box text-left">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="contact">
|
||||
<div class="fill">
|
||||
<div class="row" class="wow fadeInDown">
|
||||
<div class="col-lg-12 text-center wow fadeInDown">
|
||||
<div class="col-md-4 map-title">
|
||||
Digital Glarus<br>
|
||||
<span class="map-caption">In der Au 7 Schwanden 8762 Switzerland
|
||||
<br>info@digitalglarus.ch
|
||||
<br>
|
||||
(044) 534-66-22
|
||||
<p> </p>
|
||||
</span>
|
||||
</div>
|
||||
<p> </p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -17,9 +17,9 @@
|
|||
<div class="signup-container">
|
||||
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
|
||||
<div class="payment-box">
|
||||
<h2 class="section-heading payment-head">Your Membership Order Detail</h2>
|
||||
<h2 class="section-heading payment-head">Your membership invoice for {{order.created_at|date:"F"}}</h2>
|
||||
<hr class="greyline-long">
|
||||
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print" data-print="price">Get PDF</btn></h2>
|
||||
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print hidden-print" data-print="price">Get PDF</btn></h2>
|
||||
|
||||
<h2 class="order-head">Order Number</h2>
|
||||
<h2 class="member-name">#{{order.id}}</h2>
|
||||
|
|
|
@ -5,7 +5,8 @@ from . import views
|
|||
from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
|
||||
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
|
||||
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
|
||||
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, MembershipDeactivateView
|
||||
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, \
|
||||
MembershipDeactivateView, MembershipDeactivateSuccessView
|
||||
# from membership.views import LoginRegistrationView
|
||||
|
||||
urlpatterns = [
|
||||
|
@ -30,6 +31,8 @@ urlpatterns = [
|
|||
name='membership_activated'),
|
||||
url(_(r'membership/deactivate/?$'), MembershipDeactivateView.as_view(),
|
||||
name='membership_deactivate'),
|
||||
url(_(r'membership/deactivate/success/?$'), MembershipDeactivateSuccessView.as_view(),
|
||||
name='membership_deactivate_success'),
|
||||
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
|
||||
name='membership_pricing'),
|
||||
url(_(r'membership/orders/(?P<pk>\d+)/?$'), OrdersMembershipDetailView.as_view(),
|
||||
|
|
|
@ -47,7 +47,15 @@ class IndexView(TemplateView):
|
|||
class LoginView(LoginViewMixin):
|
||||
template_name = "digitalglarus/login.html"
|
||||
form_class = LoginForm
|
||||
success_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||
|
||||
def get_success_url(self):
|
||||
# redirect to membership orders list if user has at least one.
|
||||
if self.request.user \
|
||||
and MembershipOrder.objects.filter(customer__user=self.request.user):
|
||||
|
||||
return reverse_lazy('digitalglarus:membership_orders_list')
|
||||
|
||||
return reverse_lazy('digitalglarus:membership_pricing')
|
||||
|
||||
|
||||
class SignupView(SignupViewMixin):
|
||||
|
@ -92,11 +100,22 @@ class BookingSelectDatesView(LoginRequiredMixin, MembershipRequiredMixin, FormVi
|
|||
start_date = form.cleaned_data.get('start_date')
|
||||
end_date = form.cleaned_data.get('end_date')
|
||||
booking_days = (end_date - start_date).days + 1
|
||||
original_price, discount_price, free_days = Booking.\
|
||||
|
||||
price_per_day = BookingPrice.objects.get().price_per_day
|
||||
|
||||
original_price, final_price, free_days,\
|
||||
membership_required_months, membership_required_months_price = Booking.\
|
||||
booking_price(user, start_date, end_date)
|
||||
|
||||
total_discount = price_per_day * free_days
|
||||
|
||||
self.request.session.update({
|
||||
'original_price': original_price,
|
||||
'discount_price': discount_price,
|
||||
'final_price': final_price,
|
||||
'total_discount': total_discount,
|
||||
'membership_required_months_price': membership_required_months_price,
|
||||
'membership_required_months': membership_required_months,
|
||||
'booking_price_per_day': price_per_day,
|
||||
'booking_days': booking_days,
|
||||
'free_days': free_days,
|
||||
'start_date': start_date.strftime('%m/%d/%Y'),
|
||||
|
@ -110,8 +129,10 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
|||
form_class = BookingBillingForm
|
||||
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
|
||||
# success_url = reverse_lazy('digitalglarus:booking_payment')
|
||||
booking_needed_fields = ['original_price', 'discount_price', 'booking_days', 'free_days',
|
||||
'start_date', 'end_date']
|
||||
booking_needed_fields = ['original_price', 'final_price', 'booking_days', 'free_days',
|
||||
'start_date', 'end_date', 'membership_required_months_price',
|
||||
'membership_required_months', 'booking_price_per_day',
|
||||
'total_discount']
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
from_booking = all(field in request.session.keys()
|
||||
|
@ -130,7 +151,7 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
|||
'initial': {
|
||||
'start_date': self.request.session.get('start_date'),
|
||||
'end_date': self.request.session.get('end_date'),
|
||||
'price': self.request.session.get('discount_price'),
|
||||
'price': self.request.session.get('final_price'),
|
||||
}
|
||||
})
|
||||
return form_kwargs
|
||||
|
@ -140,11 +161,11 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
|||
|
||||
booking_data = {key: self.request.session.get(key)
|
||||
for key in self.booking_needed_fields}
|
||||
booking_price_per_day = BookingPrice.objects.get().price_per_day
|
||||
total_discount = booking_price_per_day * booking_data.get('free_days')
|
||||
# booking_price_per_day = BookingPrice.objects.get().price_per_day
|
||||
# total_discount = booking_price_per_day * booking_data.get('free_days')
|
||||
booking_data.update({
|
||||
'booking_price_per_day': booking_price_per_day,
|
||||
'total_discount': total_discount,
|
||||
# 'booking_price_per_day': booking_price_per_day,
|
||||
# 'total_discount': total_discount,
|
||||
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
|
||||
})
|
||||
context.update(booking_data)
|
||||
|
@ -157,7 +178,8 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
|||
start_date = data.get('start_date')
|
||||
end_date = data.get('end_date')
|
||||
|
||||
normal_price, final_price, free_days = Booking.\
|
||||
normal_price, final_price, free_days, membership_required_months,\
|
||||
membership_required_months_price = Booking.\
|
||||
booking_price(self.request.user, start_date, end_date)
|
||||
|
||||
# Get or create stripe customer
|
||||
|
@ -205,14 +227,12 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
|||
'stripe_charge': charge,
|
||||
'amount': final_price,
|
||||
'original_price': normal_price,
|
||||
'special_month_price': BookingPrice.objects.last().special_month_price
|
||||
'special_month_price': BookingPrice.objects.last().special_month_price,
|
||||
'membership_required_months': membership_required_months,
|
||||
'membership_required_months_price': membership_required_months_price,
|
||||
}
|
||||
order = BookingOrder.create(order_data)
|
||||
|
||||
# request.session.update({
|
||||
# 'membership_price': membership.type.first_month_price,
|
||||
# 'membership_dates': membership.type.first_month_formated_range
|
||||
# })
|
||||
return HttpResponseRedirect(self.get_success_url(order.id))
|
||||
|
||||
|
||||
|
@ -367,6 +387,10 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView):
|
|||
return HttpResponseRedirect(self.success_url)
|
||||
|
||||
|
||||
class MembershipDeactivateSuccessView(LoginRequiredMixin, TemplateView):
|
||||
template_name = "digitalglarus/membership_deactivated_success.html"
|
||||
|
||||
|
||||
class MembershipOrdersListView(LoginRequiredMixin, ListView):
|
||||
template_name = "digitalglarus/membership_orders_list.html"
|
||||
context_object_name = "orders"
|
||||
|
@ -427,9 +451,15 @@ class OrdersBookingDetailView(LoginRequiredMixin, DetailView):
|
|||
booking_days = (end_date - start_date).days + 1
|
||||
original_price = booking.price
|
||||
final_price = booking.final_price
|
||||
|
||||
membership_required_months = bookig_order.membership_required_months
|
||||
membership_required_months_price = bookig_order.membership_required_months_price
|
||||
|
||||
context.update({
|
||||
'original_price': original_price,
|
||||
'total_discount': original_price - final_price,
|
||||
'membership_required_months': membership_required_months,
|
||||
'membership_required_months_price': membership_required_months_price,
|
||||
'final_price': final_price,
|
||||
'booking_days': booking_days,
|
||||
'free_days': free_days,
|
||||
|
|
|
@ -24,7 +24,6 @@ def get_anonymous_user_instance(User):
|
|||
validation_slug=make_password(None))
|
||||
|
||||
|
||||
|
||||
class MyUserManager(BaseUserManager):
|
||||
def create_user(self, email, name, password=None):
|
||||
"""
|
||||
|
@ -89,6 +88,10 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
|
|||
else:
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_all_members(cls):
|
||||
return cls.objects.filter(stripecustomer__membershiporder__isnull=False)
|
||||
|
||||
@classmethod
|
||||
def validate_url(cls, validation_slug):
|
||||
user = cls.objects.filter(validation_slug=validation_slug).first()
|
||||
|
|
|
@ -9,7 +9,6 @@ from nosystemd.models import DonatorStatus, Donation
|
|||
from nosystemd.forms import DonationForm
|
||||
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Make the monthly stripe charge to all donators'
|
||||
CURRENCY = 'usd'
|
||||
|
|
Loading…
Reference in a new issue