Merge pull request #128 from levivm/feature/new_digitalglarus

Feature/new digitalglarus
This commit is contained in:
Levi Velázquez 2016-10-01 17:20:36 -05:00 committed by GitHub
commit 2481f610a6
18 changed files with 687 additions and 86 deletions

View file

@ -7,7 +7,7 @@ from datetime import datetime
from utils.models import BillingAddress from utils.models import BillingAddress
from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm from utils.forms import LoginFormMixin, SignupFormMixin, BillingAddressForm
from .models import MembershipType from .models import MembershipType, MembershipOrder
from .models import Booking 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): class BookingBillingForm(BillingAddressForm):
token = forms.CharField(widget=forms.HiddenInput()) token = forms.CharField(widget=forms.HiddenInput())
start_date = forms.DateField(widget=forms.HiddenInput()) start_date = forms.DateField(widget=forms.HiddenInput())
@ -60,37 +77,14 @@ class BookingBillingForm(BillingAddressForm):
class BookingDateForm(forms.Form): class BookingDateForm(forms.Form):
start_date = forms.DateField(required=False, start_date = forms.DateField(required=False,
widget=forms.TextInput(attrs={'id': 'booking-date-1', widget=forms.TextInput(attrs={'id': 'booking-date-1',
'value': ''})) 'value': 'Select your date'}))
end_date = forms.DateField(required=False, end_date = forms.DateField(required=False,
widget=forms.TextInput(attrs={'id': 'booking-date-2'})) 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): def clean_start_date(self):
start_date = self.cleaned_data.get('start_date') start_date = self.cleaned_data.get('start_date')
if not start_date: if not start_date:
raise forms.ValidationError("This field is required.") 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 return start_date
def clean_end_date(self): def clean_end_date(self):

View 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

View 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,
),
]

View 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),
),
]

View file

@ -9,7 +9,7 @@ class MembershipRequiredMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
from .models import Membership 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 HttpResponseRedirect(self.membership_redirect_url)
return super(MembershipRequiredMixin, self).dispatch(request, *args, **kwargs) return super(MembershipRequiredMixin, self).dispatch(request, *args, **kwargs)
@ -20,7 +20,7 @@ class IsNotMemberMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
from .models import Membership 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 HttpResponseRedirect(self.already_member_redirect_url)
return super(IsNotMemberMixin, self).dispatch(request, *args, **kwargs) return super(IsNotMemberMixin, self).dispatch(request, *args, **kwargs)

View file

@ -16,8 +16,9 @@ from .mixins import Ordereable
class MembershipType(models.Model): class MembershipType(models.Model):
STANDARD = 'standard'
MEMBERSHIP_TYPES = ( MEMBERSHIP_TYPES = (
('standard', 'Standard'), (STANDARD, 'Standard'),
) )
name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20) name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20)
@ -63,7 +64,12 @@ class Membership(models.Model):
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
@classmethod @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 past_month = (datetime.today() - relativedelta(months=1)).month
has_booking_current_month = Q(membershiporder__customer__user=user, has_booking_current_month = Q(membershiporder__customer__user=user,
membershiporder__created_at__month=datetime.today().month) 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).\ return cls.objects.filter(has_booking_past_month | has_booking_current_month).\
filter(active_membership).exists() filter(active_membership).exists()
@classmethod
def create(cls, data):
instance = cls.objects.create(**data)
return instance
def deactivate(self): def deactivate(self):
self.active = False self.active = False
self.save() self.save()
@ -158,6 +159,14 @@ class Booking(models.Model):
total_free_days = months * TWO_DAYS + free_days_this_month total_free_days = months * TWO_DAYS + free_days_this_month
return total_free_days 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 @classmethod
def booking_price(cls, user, start_date, end_date): 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) free_days = cls.get_ramaining_free_days(user, start_date, end_date)
final_booking_price = normal_price - (free_days * price_per_day) 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): class BookingOrder(Ordereable, models.Model):
booking = models.OneToOneField(Booking) booking = models.OneToOneField(Booking)
original_price = models.FloatField() original_price = models.FloatField()
special_month_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): def booking_days(self):
return (self.booking.end_date - self.booking.start_date).days + 1 return (self.booking.end_date - self.booking.start_date).days + 1

View file

@ -7,14 +7,16 @@ $( document ).ready(function() {
var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000); var tomorrow = new Date(new Date().getTime() + 24 * 60 * 60 * 1000);
$('#booking-date-1').datetimepicker({ $('#booking-date-1').datetimepicker({
// minDate: tomorrow, minDate: tomorrow,
format: 'MM/d/YYYY', format: 'MM/DD/YYYY',
defaultDate: false // defaultDate: false
}); });
$('#booking-date-1').val('');
$('#booking-date-2').datetimepicker({ $('#booking-date-2').datetimepicker({
useCurrent: false, //Important! See issue #1075 useCurrent: false, //Important! See issue #1075
format: 'MM/d/YYYY', format: 'MM/DD/YYYY',
}); });
$("#booking-date-1").on("dp.change", function (e) { $("#booking-date-1").on("dp.change", function (e) {
$('#booking-date-2').data("DateTimePicker").minDate(e.date); $('#booking-date-2').data("DateTimePicker").minDate(e.date);
@ -23,24 +25,4 @@ $( document ).ready(function() {
$('#booking-date-1').data("DateTimePicker").maxDate(e.date); $('#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');
// });
}); });

View file

@ -7,6 +7,7 @@
.invoice-title{ .invoice-title{
text-align: center !important; text-align: center !important;
} }
</style> </style>
<script type="text/javascript"> <script type="text/javascript">
@ -19,7 +20,7 @@
<div class="payment-box"> <div class="payment-box">
<h2 class="section-heading payment-head">Your Booking Detail</h2> <h2 class="section-heading payment-head">Your Booking Detail</h2>
<hr class="greyline-long"> <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="order-head">Order Number</h2>
<h2 class="member-name">#{{order.id}}</h2> <h2 class="member-name">#{{order.id}}</h2>
@ -43,6 +44,10 @@
</h2> </h2>
<h2 class="col-xs-6 payment-total text-left">Total days {{booking_days}}</h2> <h2 class="col-xs-6 payment-total text-left">Total days {{booking_days}}</h2>
<h2 class="order-sum">{{original_price|floatformat}}CHF</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 %} {% if free_days %}
<h2 class="col-xs-6 payment-total text-left">Free days {{free_days}} </h2> <h2 class="col-xs-6 payment-total text-left">Free days {{free_days}} </h2>
<h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2> <h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>
@ -54,7 +59,7 @@
</div> </div>
</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="order-summary">
<div class="header text-center"> <div class="header text-center">
<h2 class="order-name">Order Summary</h2> <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="col-xs-6 payment-total">Total days {{booking_days}}</h2>
<h2 class="order-sum">{{original_price|floatformat}}CHF</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 %} {% 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">-{{total_discount|floatformat}}CHF</h2> <h2 class="order-sum">-{{total_discount|floatformat}}CHF</h2>

View file

@ -121,15 +121,20 @@
<br/> <br/>
<hr class="greyline"> <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> <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 %} {% 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> <h2 class="order-sum"><span class="text-danger">-{{total_discount|floatformat}}CHF</span></h2>
{% endif %} {% endif %}
<hr class="greyline"> <hr class="greyline">
<h2 class="col-xs-6 payment-total">Total</h2> <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"> <div class="text-center">
<label class="custom-control custom-checkbox"> <label class="custom-control custom-checkbox">
<br/> <br/>

View file

@ -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>

View file

@ -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>

View file

@ -10,7 +10,9 @@
<div class="signup-box"> <div class="signup-box">
<span class="glyphicon glyphicon-user"></span> <span class="glyphicon glyphicon-user"></span>
<h2 class="section-heading">Log In</h2> <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 %} {% if messages %}

View file

@ -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>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
{% endblock %}

View file

@ -17,9 +17,9 @@
<div class="signup-container"> <div class="signup-container">
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown"> <div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
<div class="payment-box"> <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"> <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="order-head">Order Number</h2>
<h2 class="member-name">#{{order.id}}</h2> <h2 class="member-name">#{{order.id}}</h2>

View file

@ -5,7 +5,8 @@ from . import views
from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\ from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, SignupView,\
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\ PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\ MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, MembershipDeactivateView BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, \
MembershipDeactivateView, MembershipDeactivateSuccessView
# from membership.views import LoginRegistrationView # from membership.views import LoginRegistrationView
urlpatterns = [ urlpatterns = [
@ -30,6 +31,8 @@ urlpatterns = [
name='membership_activated'), name='membership_activated'),
url(_(r'membership/deactivate/?$'), MembershipDeactivateView.as_view(), url(_(r'membership/deactivate/?$'), MembershipDeactivateView.as_view(),
name='membership_deactivate'), name='membership_deactivate'),
url(_(r'membership/deactivate/success/?$'), MembershipDeactivateSuccessView.as_view(),
name='membership_deactivate_success'),
url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(), url(_(r'membership/pricing/?$'), MembershipPricingView.as_view(),
name='membership_pricing'), name='membership_pricing'),
url(_(r'membership/orders/(?P<pk>\d+)/?$'), OrdersMembershipDetailView.as_view(), url(_(r'membership/orders/(?P<pk>\d+)/?$'), OrdersMembershipDetailView.as_view(),

View file

@ -47,7 +47,15 @@ class IndexView(TemplateView):
class LoginView(LoginViewMixin): class LoginView(LoginViewMixin):
template_name = "digitalglarus/login.html" template_name = "digitalglarus/login.html"
form_class = LoginForm 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): class SignupView(SignupViewMixin):
@ -92,11 +100,22 @@ class BookingSelectDatesView(LoginRequiredMixin, MembershipRequiredMixin, FormVi
start_date = form.cleaned_data.get('start_date') start_date = form.cleaned_data.get('start_date')
end_date = form.cleaned_data.get('end_date') end_date = form.cleaned_data.get('end_date')
booking_days = (end_date - start_date).days + 1 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) booking_price(user, start_date, end_date)
total_discount = price_per_day * free_days
self.request.session.update({ self.request.session.update({
'original_price': original_price, '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, 'booking_days': booking_days,
'free_days': free_days, 'free_days': free_days,
'start_date': start_date.strftime('%m/%d/%Y'), 'start_date': start_date.strftime('%m/%d/%Y'),
@ -110,8 +129,10 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
form_class = BookingBillingForm form_class = BookingBillingForm
membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing') membership_redirect_url = reverse_lazy('digitalglarus:membership_pricing')
# success_url = reverse_lazy('digitalglarus:booking_payment') # success_url = reverse_lazy('digitalglarus:booking_payment')
booking_needed_fields = ['original_price', 'discount_price', 'booking_days', 'free_days', booking_needed_fields = ['original_price', 'final_price', 'booking_days', 'free_days',
'start_date', 'end_date'] 'start_date', 'end_date', 'membership_required_months_price',
'membership_required_months', 'booking_price_per_day',
'total_discount']
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
from_booking = all(field in request.session.keys() from_booking = all(field in request.session.keys()
@ -130,7 +151,7 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
'initial': { 'initial': {
'start_date': self.request.session.get('start_date'), 'start_date': self.request.session.get('start_date'),
'end_date': self.request.session.get('end_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 return form_kwargs
@ -140,11 +161,11 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
booking_data = {key: self.request.session.get(key) booking_data = {key: self.request.session.get(key)
for key in self.booking_needed_fields} for key in self.booking_needed_fields}
booking_price_per_day = BookingPrice.objects.get().price_per_day # booking_price_per_day = BookingPrice.objects.get().price_per_day
total_discount = booking_price_per_day * booking_data.get('free_days') # total_discount = booking_price_per_day * booking_data.get('free_days')
booking_data.update({ booking_data.update({
'booking_price_per_day': booking_price_per_day, # 'booking_price_per_day': booking_price_per_day,
'total_discount': total_discount, # 'total_discount': total_discount,
'stripe_key': settings.STRIPE_API_PUBLIC_KEY 'stripe_key': settings.STRIPE_API_PUBLIC_KEY
}) })
context.update(booking_data) context.update(booking_data)
@ -157,7 +178,8 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
start_date = data.get('start_date') start_date = data.get('start_date')
end_date = data.get('end_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) booking_price(self.request.user, start_date, end_date)
# Get or create stripe customer # Get or create stripe customer
@ -205,14 +227,12 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
'stripe_charge': charge, 'stripe_charge': charge,
'amount': final_price, 'amount': final_price,
'original_price': normal_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) 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)) return HttpResponseRedirect(self.get_success_url(order.id))
@ -367,6 +387,10 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView):
return HttpResponseRedirect(self.success_url) return HttpResponseRedirect(self.success_url)
class MembershipDeactivateSuccessView(LoginRequiredMixin, TemplateView):
template_name = "digitalglarus/membership_deactivated_success.html"
class MembershipOrdersListView(LoginRequiredMixin, ListView): class MembershipOrdersListView(LoginRequiredMixin, ListView):
template_name = "digitalglarus/membership_orders_list.html" template_name = "digitalglarus/membership_orders_list.html"
context_object_name = "orders" context_object_name = "orders"
@ -427,9 +451,15 @@ class OrdersBookingDetailView(LoginRequiredMixin, DetailView):
booking_days = (end_date - start_date).days + 1 booking_days = (end_date - start_date).days + 1
original_price = booking.price original_price = booking.price
final_price = booking.final_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({ context.update({
'original_price': original_price, 'original_price': original_price,
'total_discount': original_price - final_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, 'final_price': final_price,
'booking_days': booking_days, 'booking_days': booking_days,
'free_days': free_days, 'free_days': free_days,

View file

@ -24,7 +24,6 @@ def get_anonymous_user_instance(User):
validation_slug=make_password(None)) validation_slug=make_password(None))
class MyUserManager(BaseUserManager): class MyUserManager(BaseUserManager):
def create_user(self, email, name, password=None): def create_user(self, email, name, password=None):
""" """
@ -89,6 +88,10 @@ class CustomUser(AbstractBaseUser, PermissionsMixin):
else: else:
return None return None
@classmethod
def get_all_members(cls):
return cls.objects.filter(stripecustomer__membershiporder__isnull=False)
@classmethod @classmethod
def validate_url(cls, validation_slug): def validate_url(cls, validation_slug):
user = cls.objects.filter(validation_slug=validation_slug).first() user = cls.objects.filter(validation_slug=validation_slug).first()

View file

@ -9,7 +9,6 @@ from nosystemd.models import DonatorStatus, Donation
from nosystemd.forms import DonationForm from nosystemd.forms import DonationForm
class Command(BaseCommand): class Command(BaseCommand):
help = 'Make the monthly stripe charge to all donators' help = 'Make the monthly stripe charge to all donators'
CURRENCY = 'usd' CURRENCY = 'usd'