Merge pull request #129 from levivm/feature/new_digitalglarus
Feature/new digitalglarus
This commit is contained in:
commit
68b149cebd
24 changed files with 735 additions and 148 deletions
|
@ -57,7 +57,7 @@ class MembershipOrderForm(forms.ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class BookingBillingForm(BillingAddressForm):
|
class BookingBillingForm(BillingAddressForm):
|
||||||
token = forms.CharField(widget=forms.HiddenInput())
|
token = forms.CharField(widget=forms.HiddenInput(), required=False)
|
||||||
start_date = forms.DateField(widget=forms.HiddenInput())
|
start_date = forms.DateField(widget=forms.HiddenInput())
|
||||||
end_date = forms.DateField(widget=forms.HiddenInput())
|
end_date = forms.DateField(widget=forms.HiddenInput())
|
||||||
price = forms.FloatField(widget=forms.HiddenInput())
|
price = forms.FloatField(widget=forms.HiddenInput())
|
||||||
|
|
|
@ -97,70 +97,3 @@ class Command(BaseCommand):
|
||||||
print(e)
|
print(e)
|
||||||
print("-------------------------")
|
print("-------------------------")
|
||||||
continue
|
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
|
|
||||||
|
|
35
digitalglarus/migrations/0020_auto_20161013_0253.py
Normal file
35
digitalglarus/migrations/0020_auto_20161013_0253.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-10-13 02:53
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('digitalglarus', '0019_auto_20160929_0324'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='bookingorder',
|
||||||
|
name='cc_brand',
|
||||||
|
field=models.CharField(blank=True, max_length=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='bookingorder',
|
||||||
|
name='last4',
|
||||||
|
field=models.CharField(blank=True, max_length=4),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='membershiporder',
|
||||||
|
name='cc_brand',
|
||||||
|
field=models.CharField(blank=True, max_length=10),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='membershiporder',
|
||||||
|
name='last4',
|
||||||
|
field=models.CharField(blank=True, max_length=4),
|
||||||
|
),
|
||||||
|
]
|
|
@ -32,8 +32,8 @@ class Ordereable(models.Model):
|
||||||
billing_address = models.ForeignKey(BillingAddress)
|
billing_address = models.ForeignKey(BillingAddress)
|
||||||
created_at = models.DateTimeField(auto_now_add=True)
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
approved = models.BooleanField(default=False)
|
approved = models.BooleanField(default=False)
|
||||||
last4 = models.CharField(max_length=4)
|
last4 = models.CharField(max_length=4, blank=True)
|
||||||
cc_brand = models.CharField(max_length=10)
|
cc_brand = models.CharField(max_length=10, blank=True)
|
||||||
stripe_charge_id = models.CharField(max_length=100, null=True)
|
stripe_charge_id = models.CharField(max_length=100, null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -43,6 +43,8 @@ class Ordereable(models.Model):
|
||||||
def create(cls, data):
|
def create(cls, data):
|
||||||
stripe_charge = data.pop('stripe_charge', None)
|
stripe_charge = data.pop('stripe_charge', None)
|
||||||
instance = cls.objects.create(**data)
|
instance = cls.objects.create(**data)
|
||||||
|
if not stripe_charge:
|
||||||
|
return instance
|
||||||
instance.stripe_charge_id = stripe_charge.id
|
instance.stripe_charge_id = stripe_charge.id
|
||||||
instance.last4 = stripe_charge.source.last4
|
instance.last4 = stripe_charge.source.last4
|
||||||
instance.cc_brand = stripe_charge.source.brand
|
instance.cc_brand = stripe_charge.source.brand
|
||||||
|
|
|
@ -71,12 +71,12 @@ class Membership(models.Model):
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_digitalglarus_active_member(cls, user):
|
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_order_current_month = Q(membershiporder__customer__user=user,
|
||||||
membershiporder__created_at__month=datetime.today().month)
|
membershiporder__created_at__month=datetime.today().month)
|
||||||
has_booking_past_month = Q(membershiporder__customer__user=user,
|
has_order_past_month = Q(membershiporder__customer__user=user,
|
||||||
membershiporder__created_at__month=past_month)
|
membershiporder__created_at__month=past_month)
|
||||||
active_membership = Q(active=True)
|
active_membership = Q(active=True)
|
||||||
return cls.objects.filter(has_booking_past_month | has_booking_current_month).\
|
return cls.objects.filter(has_order_past_month | has_order_current_month).\
|
||||||
filter(active_membership).exists()
|
filter(active_membership).exists()
|
||||||
|
|
||||||
def deactivate(self):
|
def deactivate(self):
|
||||||
|
@ -147,7 +147,7 @@ class Booking(models.Model):
|
||||||
def get_ramaining_free_days(cls, user, start_date, end_date):
|
def get_ramaining_free_days(cls, user, start_date, end_date):
|
||||||
|
|
||||||
TWO_DAYS = 2
|
TWO_DAYS = 2
|
||||||
|
ONE_DAY = 1
|
||||||
start_month = start_date.month
|
start_month = start_date.month
|
||||||
end_month = end_date.month
|
end_month = end_date.month
|
||||||
months = abs(start_month - (end_month + 12) if end_month < start_month
|
months = abs(start_month - (end_month + 12) if end_month < start_month
|
||||||
|
@ -156,6 +156,10 @@ class Booking(models.Model):
|
||||||
current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
|
current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
|
||||||
start_date__month=current_date.month)
|
start_date__month=current_date.month)
|
||||||
free_days_this_month = TWO_DAYS - sum(map(lambda x: x.free_days, current_month_bookings))
|
free_days_this_month = TWO_DAYS - sum(map(lambda x: x.free_days, current_month_bookings))
|
||||||
|
|
||||||
|
if start_date == end_date and free_days_this_month == TWO_DAYS:
|
||||||
|
free_days_this_month = ONE_DAY
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
|
@ -190,11 +194,11 @@ class Booking(models.Model):
|
||||||
# Calculating membership required months price for booking
|
# Calculating membership required months price for booking
|
||||||
required_membership_months = 0
|
required_membership_months = 0
|
||||||
membership_booking_price = 0.0
|
membership_booking_price = 0.0
|
||||||
if BookingOrder.user_has_not_bookings(user):
|
# if not BookingOrder.user_has_not_bookings(user):
|
||||||
today = datetime.today().date()
|
today = datetime.today().date()
|
||||||
membership_price = MembershipType.objects.get(name=MembershipType.STANDARD).price
|
membership_price = MembershipType.objects.get(name=MembershipType.STANDARD).price
|
||||||
required_membership_months = cls.membership_required_booking_months(today, end_date)
|
required_membership_months = cls.membership_required_booking_months(today, end_date)
|
||||||
membership_booking_price = membership_price * required_membership_months
|
membership_booking_price = membership_price * required_membership_months
|
||||||
|
|
||||||
# Add required membership months to final prices
|
# Add required membership months to final prices
|
||||||
final_booking_price += membership_booking_price
|
final_booking_price += membership_booking_price
|
||||||
|
@ -210,11 +214,15 @@ class BookingOrder(Ordereable, models.Model):
|
||||||
membership_required_months = models.IntegerField(default=0)
|
membership_required_months = models.IntegerField(default=0)
|
||||||
membership_required_months_price = models.FloatField(default=0)
|
membership_required_months_price = models.FloatField(default=0)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def user_has_not_bookings(cls, user):
|
def user_has_not_bookings(cls, user):
|
||||||
return cls.objects.filter(customer__user=user).exists()
|
return cls.objects.filter(customer__user=user).exists()
|
||||||
|
|
||||||
|
def get_booking_cc_data(self):
|
||||||
|
return {
|
||||||
|
'last4': self.last4,
|
||||||
|
'cc_brand': self.cc_brand,
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -241,6 +241,8 @@ fieldset[disabled] .btn-xl.active {
|
||||||
|
|
||||||
.navbar-default .navbar-collapse {
|
.navbar-default .navbar-collapse {
|
||||||
border-color: rgba(255,255,255,.02);
|
border-color: rgba(255,255,255,.02);
|
||||||
|
padding-right: 100px;
|
||||||
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navbar-default .navbar-toggle {
|
.navbar-default .navbar-toggle {
|
||||||
|
@ -259,7 +261,7 @@ fieldset[disabled] .btn-xl.active {
|
||||||
|
|
||||||
.navbar-default .nav li a {
|
.navbar-default .nav li a {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-family: Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;
|
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
|
@ -197,7 +197,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.glyphicon-ok {
|
.glyphicon-ok {
|
||||||
font-size: 42px;
|
font-size: 28px;
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
@ -364,7 +364,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control {
|
||||||
color: #999;
|
color: #000;
|
||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,21 @@ $( document ).ready(function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var submit_form_btn = $('#payment_button');
|
||||||
|
submit_form_btn.on('click', submit_payment);
|
||||||
|
|
||||||
|
function submit_payment(e){
|
||||||
|
$('#billing-form').submit();
|
||||||
|
// $form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var $form = $('#payment-form');
|
var $form = $('#payment-form');
|
||||||
$form.submit(payWithStripe);
|
$form.submit(payWithStripe);
|
||||||
|
|
||||||
/* If you're using Stripe for payments */
|
/* If you're using Stripe for payments */
|
||||||
function payWithStripe(e) {
|
function payWithStripe(e) {
|
||||||
|
console.log("submiting");
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
/* Visual feedback */
|
/* Visual feedback */
|
||||||
|
|
|
@ -39,11 +39,15 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2 class="order-head">Billing Adress<btn class="btn btn-primary btn-grey btn-edit">Edit</btn></h2>
|
<h2 class="order-head">Billing Adress<a class="btn btn-primary btn-grey btn-edit" href="{% url 'digitalglarus:user_billing_address' %}">Edit</a></h2>
|
||||||
<h2 class="history-name">Nico Schottelius<br>
|
<h2 class="history-name">
|
||||||
In der Au 7 8762 Schwanden<br>
|
{{request.user.name}}
|
||||||
Switzerland
|
|
||||||
</h2>
|
</h2>
|
||||||
|
<h2 class="history-name">
|
||||||
|
{{billing_address.street_address}},{{billing_address.postal_code}}<br>
|
||||||
|
{{billing_address.city}}, {{billing_address.country}}.
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<h2 class="section-heading payment-head">Booking</h2>
|
<h2 class="section-heading payment-head">Booking</h2>
|
||||||
<!-- <h2 class="membership-amount">35CHF</h2> -->
|
<!-- <h2 class="membership-amount">35CHF</h2> -->
|
||||||
<hr class="greyline-long">
|
<hr class="greyline-long">
|
||||||
<h2 class="billing-head">Billing Adress</h2>
|
|
||||||
<h2 class="membership-lead">
|
<h2 class="membership-lead">
|
||||||
Your Digital Glarus Membership enables
|
Your Digital Glarus Membership enables
|
||||||
you to use our coworking space and it includes
|
you to use our coworking space and it includes
|
||||||
|
@ -37,7 +37,25 @@
|
||||||
15CHF per day. More than 17 days a month it
|
15CHF per day. More than 17 days a month it
|
||||||
will charge only 290CHF/month.
|
will charge only 290CHF/month.
|
||||||
</h2>
|
</h2>
|
||||||
|
{% if is_free %}
|
||||||
|
<h2 class="billing-head">Billing Adress</h2>
|
||||||
|
<div class="signup-form form-group row">
|
||||||
|
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
||||||
|
{% for field in form %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{% bootstrap_field field show_label=False type='fields'%}
|
||||||
|
{% endfor %}
|
||||||
|
{% bootstrap_form_errors form type='non_fields'%}
|
||||||
|
<br>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<br/>
|
||||||
|
<h2 class="billing-head">Your Booking is TOTALLY FREE</h2>
|
||||||
|
<br/><br/>
|
||||||
|
{% else %}
|
||||||
|
<h2 class="billing-head">Billing Adress</h2>
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
|
@ -48,18 +66,26 @@
|
||||||
<br>
|
<br>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<h2 class="billing-head">Credit Card</h2>
|
{% if credit_card_data %}
|
||||||
|
<form role="form" id="billing-form" method="post" action="{% url 'digitalglarus:booking_payment' %}" novalidate>
|
||||||
|
<h2 class="billing-head">Credit Card</h2>
|
||||||
|
<h2 class="membership-lead">Last 4: {{credit_card_data.last4}}</h2>
|
||||||
|
<h2 class="membership-lead">Type: {{credit_card_data.cc_brand}}</h2>
|
||||||
|
<input type="hidden" name="credit_card_needed" value="false"/>
|
||||||
|
</form>
|
||||||
|
{% else %}
|
||||||
|
<h2 class="billing-head">Credit Card (Last used)</h2>
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
<form role="form" id="payment-form" novalidate>
|
<form role="form" id="payment-form" novalidate>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
|
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
|
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,11 +112,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col-xs-12">
|
|
||||||
<button class="btn btn-primary btn-lg btn-blck " type="submit">Book</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" style="display:none;">
|
<div class="row" style="display:none;">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<p class="payment-errors"></p>
|
<p class="payment-errors"></p>
|
||||||
|
@ -109,6 +130,8 @@
|
||||||
</form>
|
</form>
|
||||||
<br>
|
<br>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
</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">
|
||||||
|
@ -136,18 +159,20 @@
|
||||||
<h2 class="col-xs-6 payment-total">Total</h2>
|
<h2 class="col-xs-6 payment-total">Total</h2>
|
||||||
<h2 class="order-result">{{final_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/>
|
||||||
<input type="checkbox" class="custom-control-input">
|
<input type="checkbox" class="custom-control-input">
|
||||||
<span class="custom-control-indicator"></span>
|
<span class="custom-control-indicator"></span>
|
||||||
<span class="custom-control-description">I accept the Digital Glarus <a href=#>Terms and Conditions</a>, <a href=#>Community Guidelines</a> and <a href=#>Privacy Policy</a></span>
|
<span class="custom-control-description">I accept the Digital Glarus <a href=#>Terms and Conditions</a>, <a href=#>Community Guidelines</a> and <a href=#>Privacy Policy</a></span>
|
||||||
</label>
|
</label>
|
||||||
<div class="button-box">
|
<div class="button-box">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<button id="payment_button" class="btn btn-primary btn-lg btn-blck " type="submit">Book</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="button-box">
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<a class="btn btn-primary btn-blue" href={% url 'digitalglarus:booking' %}>Go to Booking</a>
|
<a class="btn btn-primary btn-blue" href={% url 'digitalglarus:booking' %}>Go to Booking</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="notice-box text-left">
|
<div class="notice-box text-left">
|
||||||
<p class="order-bottom-text">Your membership will be automatically renewed each month. For deactivating go to<a href=#>my page</a></p>
|
<p class="order-bottom-text">Your membership will be automatically renewed each month. For deactivating go to<a href="{% url 'digitalglarus:membership_deactivate' %}">deactivate page</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,28 @@
|
||||||
|
|
||||||
<form method="POST" action="">
|
<form method="POST" action="">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<button type="submit" class="btn btn-primary btn-blue">Cancel my Membership</button>
|
<button type="button" class="btn btn-primary btn-blue" data-toggle="modal" data-target="#cancel-subscription-modal">Cancel my Membership</button>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="modal fade bs-example-modal-sm" id="cancel-subscription-modal" tabindex="-1" role="dialog">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title">Cancel Subscription</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>Do you want to cancel your subscription?</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">No</button>
|
||||||
|
<button type="submit" class="btn btn-primary">Yes</button>
|
||||||
|
</div>
|
||||||
|
</div><!-- /.modal-content -->
|
||||||
|
</div><!-- /.modal-dialog -->
|
||||||
|
</div><!-- /.modal -->
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -33,6 +54,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
|
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -60,6 +60,7 @@
|
||||||
|
|
||||||
<h2 class="col-xs-6 payment-total">Membership month {{order.created_at|date:"F"}}</h2>
|
<h2 class="col-xs-6 payment-total">Membership month {{order.created_at|date:"F"}}</h2>
|
||||||
<h2 class="order-sum">{{order.amount|floatformat}}CHF</h2>
|
<h2 class="order-sum">{{order.amount|floatformat}}CHF</h2>
|
||||||
|
<br/>
|
||||||
<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">{{order.amount|floatformat}}CHF</h2>
|
<h2 class="order-result">{{order.amount|floatformat}}CHF</h2>
|
||||||
|
|
|
@ -39,10 +39,13 @@
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h2 class="order-head">Billing Adress<btn class="btn btn-primary btn-grey btn-edit">Edit</btn></h2>
|
<h2 class="order-head">Billing Adress<a class="btn btn-primary btn-grey btn-edit" href="{% url 'digitalglarus:user_billing_address' %}">Edit</a></h2>
|
||||||
<h2 class="history-name">Nico Schottelius<br>
|
<h2 class="history-name">
|
||||||
In der Au 7 8762 Schwanden<br>
|
{{request.user.name}}
|
||||||
Switzerland
|
</h2>
|
||||||
|
<h2 class="history-name">
|
||||||
|
{{billing_address.street_address}},{{billing_address.postal_code}}<br>
|
||||||
|
{{billing_address.city}}, {{billing_address.country}}.
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<hr class="greyline-long">
|
<hr class="greyline-long">
|
||||||
|
@ -50,14 +53,15 @@
|
||||||
<h2 class="history-name">
|
<h2 class="history-name">
|
||||||
Dates: {{membership_start_date|date}} - {{membership_end_date|date}}<br>
|
Dates: {{membership_start_date|date}} - {{membership_end_date|date}}<br>
|
||||||
</h2>
|
</h2>
|
||||||
<h2 class="history-name">
|
<div class="edit-button">
|
||||||
|
|
||||||
<a class="btn btn-primary btn-grey btn-edit print" href="{% url 'digitalglarus:membership_deactivate' %}">Deactivate</a>
|
<a class="btn btn-primary btn-grey btn-deactivate print" href="{% url 'digitalglarus:membership_deactivate' %}">Deactivate</a>
|
||||||
</h2>
|
</div>
|
||||||
|
<hr class="greyline-long">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-10">
|
<div class="col-md-12 notice-box">
|
||||||
<span>You will be charged on the first of the month until you
|
<p class="order-bottom-text">You will be charged on the first of the month until you
|
||||||
cancel your subscription. Previous charges won't be refunded.</span>
|
cancel your subscription. Previous charges won't be refunded.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -66,18 +70,37 @@
|
||||||
|
|
||||||
|
|
||||||
<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">
|
||||||
|
|
||||||
<div class="order-summary">
|
<div class="order-summary">
|
||||||
<h2 class="thankyou">Thank You!</h2>
|
|
||||||
|
{% if messages %}
|
||||||
|
<div class="order-box">
|
||||||
|
<h2 class="thankyou">Message</h2>
|
||||||
|
<hr class="greyline">
|
||||||
|
{% for message in messages %}
|
||||||
|
<h2 class="signup-lead text-center">{{ message }}</h2>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
<h2 class="thankyou">Thank You!</h2>
|
||||||
<div class="order-box">
|
<div class="order-box">
|
||||||
<span class="glyphicon glyphicon-heart icon-up"></span>
|
<span class="glyphicon glyphicon-heart icon-up"></span>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h2 class="signup-lead text-center">Digital Glarus lives with your love!<br>
|
<h2 class="signup-lead text-center">Digital Glarus lives with your love!<br>
|
||||||
Our coworking space is here because of your love and support.</h2>
|
Our coworking space is here because of your love and support.</h2>
|
||||||
|
|
||||||
<hr class="greyline">
|
<hr class="greyline">
|
||||||
|
<p class="order-bottom-text text-center">This box is here just to thank you</p>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<p class="order-bottom-text text-center">This box is here just to thank you</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -56,14 +56,14 @@
|
||||||
<div class="signup-form form-group row">
|
<div class="signup-form form-group row">
|
||||||
<form role="form" id="payment-form" novalidate>
|
<form role="form" id="payment-form" novalidate>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
|
<input type="text" class="form-control" name="cardName" placeholder="Name on card" required autofocus data-stripe="name" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-9 col-md-12">
|
<div class="col-xs-12 col-md-12">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
|
<input type="text" class="form-control" name="cardNumber" placeholder="Valid Card Number" required data-stripe="number" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12">
|
<div class="col-xs-12">
|
||||||
<button class="btn btn-primary btn-lg btn-blck " type="submit">Purchase membership</button>
|
<button class="btn btn-primary btn-md btn-blck " type="submit">Purchase membership</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" style="display:none;">
|
<div class="row" style="display:none;">
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
{% extends "new_base_glarus.html" %}
|
||||||
|
{% load staticfiles bootstrap3 i18n %}
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
.nopadding {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-control#id_country{
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
|
background-position: right 50%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAMCAYAAABSgIzaAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDZFNDEwNjlGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDZFNDEwNkFGNzFEMTFFMkJEQ0VDRTM1N0RCMzMyMkIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0NkU0MTA2N0Y3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0NkU0MTA2OEY3MUQxMUUyQkRDRUNFMzU3REIzMzIyQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuGsgwQAAAA5SURBVHjaYvz//z8DOYCJgUxAf42MQIzTk0D/M+KzkRGPoQSdykiKJrBGpOhgJFYTWNEIiEeAAAMAzNENEOH+do8AAAAASUVORK5CYII=);
|
||||||
|
padding: .5em;
|
||||||
|
padding-right: 1.5em
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<section id="price">
|
||||||
|
<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">Billing Address Info</h2>
|
||||||
|
<!-- <h2 class="membership-amount">35CHF</h2> -->
|
||||||
|
<hr class="greyline-long">
|
||||||
|
<h2 class="billing-head">Billing Adress</h2>
|
||||||
|
<div class="signup-form form-group row">
|
||||||
|
<form role="form" id="billing-address-form" method="post" action="{% url 'digitalglarus:user_billing_address' %}" novalidate>
|
||||||
|
{% for field in form %}
|
||||||
|
{% csrf_token %}
|
||||||
|
{% bootstrap_field field show_label=False type='fields'%}
|
||||||
|
{% endfor %}
|
||||||
|
{% bootstrap_form_errors form type='non_fields'%}
|
||||||
|
<br>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-12">
|
||||||
|
<button id="payment_button" class="btn btn-primary btn-lg btn-blck " type="submit">Save</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</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>
|
||||||
|
|
||||||
|
<!-- stripe key data -->
|
||||||
|
{% if stripe_key %}
|
||||||
|
<script type="text/javascript">
|
||||||
|
(function () {window.stripeKey = "{{stripe_key}}";})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{%endif%}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -107,7 +107,7 @@
|
||||||
<a href="#page-top"></a>
|
<a href="#page-top"></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="page-scroll" href="#portfolio">booking & price</a>
|
<a class="page-scroll" href="{% url 'digitalglarus:booking' %}">booking & price</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="page-scroll" href="{% url 'digitalglarus:history' %}">history</a>
|
<a class="page-scroll" href="{% url 'digitalglarus:history' %}">history</a>
|
||||||
|
|
|
@ -1,11 +1,25 @@
|
||||||
import json
|
import json
|
||||||
|
from model_mommy import mommy
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.conf import settings
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.core.urlresolvers import resolve
|
from django.core.urlresolvers import resolve
|
||||||
from cms.test_utils.testcases import CMSTestCase
|
from cms.test_utils.testcases import CMSTestCase
|
||||||
|
from django.contrib.auth.tokens import default_token_generator
|
||||||
|
from django.utils.http import urlsafe_base64_encode
|
||||||
|
from django.utils.encoding import force_bytes
|
||||||
from cms.api import create_page
|
from cms.api import create_page
|
||||||
|
|
||||||
|
from membership.models import CustomUser, StripeCustomer
|
||||||
|
from utils.tests import BaseTestCase
|
||||||
|
|
||||||
|
|
||||||
|
from .views import LoginView, SignupView, PasswordResetView, PasswordResetConfirmView,\
|
||||||
|
MembershipPricingView, MembershipPaymentView
|
||||||
|
from .models import MembershipType, MembershipOrder
|
||||||
|
|
||||||
|
|
||||||
class ContactViewTest(TestCase):
|
class ContactViewTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -38,14 +52,243 @@ class ViewsTest(CMSTestCase):
|
||||||
self.assertEqual(res2.status_code, 200)
|
self.assertEqual(res2.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
class CalendarApiTestCase(TestCase):
|
class MembershipPricingViewTest(BaseTestCase):
|
||||||
def test_api_response(self):
|
|
||||||
calendar_api_url_1 = reverse('digitalglarus:calendar_api_1', kwargs={'month': '3', 'year': '2016'})
|
|
||||||
res1 = self.client.get(calendar_api_url_1)
|
|
||||||
pd = json.loads(res1.content.decode('utf-8'))
|
|
||||||
self.assertEqual(pd['month'], '3')
|
|
||||||
self.assertEqual(pd['year'], '2016')
|
|
||||||
|
|
||||||
# TODO:check post
|
def setUp(self):
|
||||||
# calendar_api_url = reverse('digitalglarus:calendar_api')
|
super(MembershipPricingViewTest, self).setUp()
|
||||||
# res = self.client.get(calendar_api_url)
|
|
||||||
|
self.membership_type = mommy.make(MembershipType)
|
||||||
|
self.url = reverse('digitalglarus:membership_pricing')
|
||||||
|
self.view = MembershipPricingView
|
||||||
|
self.expected_template = 'digitalglarus/membership_pricing.html'
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
# Anonymous user should get data
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.context['membership_type'], self.membership_type)
|
||||||
|
self.assertTemplateUsed(response, self.expected_template)
|
||||||
|
|
||||||
|
|
||||||
|
class MembershipPaymentViewTest(BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(MembershipPaymentViewTest, self).setUp()
|
||||||
|
|
||||||
|
self.membership_type = mommy.make(MembershipType)
|
||||||
|
self.url = reverse('digitalglarus:membership_payment')
|
||||||
|
self.view = MembershipPaymentView
|
||||||
|
self.expected_template = 'digitalglarus/membership_payment.html'
|
||||||
|
|
||||||
|
# post data
|
||||||
|
self.billing_address = {
|
||||||
|
'street_address': 'street name',
|
||||||
|
'city': 'MyCity',
|
||||||
|
'postal_code': '32123123123123',
|
||||||
|
'country': 'VE',
|
||||||
|
'token': 'a23kfmslwxhkwis',
|
||||||
|
'membership_type': self.membership_type.id
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
|
||||||
|
# Anonymous user should get redirect to login
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
expected_url = "%s?next=%s" % (reverse('digitalglarus:signup'),
|
||||||
|
reverse('digitalglarus:membership_payment'))
|
||||||
|
self.assertRedirects(response, expected_url=expected_url,
|
||||||
|
status_code=302, target_status_code=200)
|
||||||
|
|
||||||
|
# Logged user should get the page
|
||||||
|
response = self.customer_client.get(self.url, follow=True)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.context['stripe_key'],
|
||||||
|
settings.STRIPE_API_PUBLIC_KEY)
|
||||||
|
self.assertEqual(response.context['membership_type'],
|
||||||
|
self.membership_type)
|
||||||
|
|
||||||
|
@mock.patch('utils.stripe_utils.StripeUtils.create_customer')
|
||||||
|
def test_post(self, stripe_mocked_call):
|
||||||
|
|
||||||
|
# Anonymous user should get redirect to login
|
||||||
|
# response = self.client.post(self.url)
|
||||||
|
# expected_url = "%s?next=%s" % (reverse('digitalglarus:signup'),
|
||||||
|
# reverse('digitalglarus:membership_payment'))
|
||||||
|
# self.assertRedirects(response, expected_url=expected_url,
|
||||||
|
# status_code=302, target_status_code=200)
|
||||||
|
|
||||||
|
# Customer user should be able to pay
|
||||||
|
stripe_mocked_call.return_value = {
|
||||||
|
'paid': True,
|
||||||
|
'response_object': self.stripe_mocked_customer,
|
||||||
|
'error': None
|
||||||
|
}
|
||||||
|
response = self.customer_client.post(self.url, self.billing_address)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTrue(StripeCustomer.objects.filter(user__email=self.customer.email).exists())
|
||||||
|
stripe_customer = StripeCustomer.objects.get(user__email=self.customer.email)
|
||||||
|
self.assertEqual(stripe_customer.user, self.customer)
|
||||||
|
self.assertTrue(MembershipOrder.objects.filter(customer=stripe_customer).exists())
|
||||||
|
membership_order = MembershipOrder.objects.filter(customer=stripe_customer).first()
|
||||||
|
session_data = {
|
||||||
|
'membership_price': membership_order.membership.type.first_month_price,
|
||||||
|
'membership_dates': membership_order.membership.type.first_month_formated_range
|
||||||
|
}
|
||||||
|
self.assertEqual(session_data.get('membership_price'),
|
||||||
|
self.session_data.get('membership_price'))
|
||||||
|
self.assertEqual(session_data.get('membership_dates'),
|
||||||
|
self.session_data.get('membership_dates'))
|
||||||
|
|
||||||
|
# self.assertTrue(HostingOrder.objects.filter(customer=stripe_customer).exists())
|
||||||
|
# hosting_order = HostingOrder.objects.filter(customer=stripe_customer)[0]
|
||||||
|
# vm_plan = {
|
||||||
|
# 'cores': hosting_order.vm_plan.cores,
|
||||||
|
# 'memory': hosting_order.vm_plan.memory,
|
||||||
|
# 'disk_size': hosting_order.vm_plan.disk_size,
|
||||||
|
# 'price': hosting_order.vm_plan.price,
|
||||||
|
# 'hosting_company': hosting_order.vm_plan.vm_type.hosting_company,
|
||||||
|
# 'configuration': hosting_order.vm_plan.configuration
|
||||||
|
# }
|
||||||
|
# self.assertEqual(vm_plan, self.session_data.get('vm_specs'))
|
||||||
|
|
||||||
|
|
||||||
|
class LoginViewTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.url = reverse('digitalglarus:login')
|
||||||
|
self.view = LoginView
|
||||||
|
self.expected_template = 'digitalglarus/login.html'
|
||||||
|
self.user = mommy.make('membership.CustomUser')
|
||||||
|
self.password = 'fake_password'
|
||||||
|
self.user.set_password(self.password)
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, self.expected_template)
|
||||||
|
|
||||||
|
def test_anonymous_user_can_login(self):
|
||||||
|
data = {
|
||||||
|
'email': self.user.email,
|
||||||
|
'password': self.password
|
||||||
|
}
|
||||||
|
response = self.client.post(self.url, data=data, follow=True)
|
||||||
|
self.assertEqual(response.context['user'], self.user)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class SignupViewTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.url = reverse('digitalglarus:signup')
|
||||||
|
self.expected_template = 'digitalglarus/signup.html'
|
||||||
|
self.view = SignupView
|
||||||
|
self.signup_data = {
|
||||||
|
'name': 'ungleich',
|
||||||
|
'email': 'test@ungleich.com',
|
||||||
|
'password': 'fake_password',
|
||||||
|
'confirm_password': 'fake_password',
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, self.expected_template)
|
||||||
|
|
||||||
|
def test_anonymous_user_can_signup(self):
|
||||||
|
response = self.client.post(self.url, data=self.signup_data, follow=True)
|
||||||
|
self.user = CustomUser.objects.get(email=self.signup_data.get('email'))
|
||||||
|
self.assertEqual(response.context['user'], self.user)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetViewTest(BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(PasswordResetViewTest, self).setUp()
|
||||||
|
|
||||||
|
self.url = reverse('digitalglarus:reset_password')
|
||||||
|
self.view = PasswordResetView
|
||||||
|
self.expected_template = 'digitalglarus/reset_password.html'
|
||||||
|
self.user = mommy.make('membership.CustomUser')
|
||||||
|
self.password = 'fake_password'
|
||||||
|
self.user.set_password(self.password)
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
self.post_data = {
|
||||||
|
'email': self.user.email
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, self.expected_template)
|
||||||
|
|
||||||
|
def test_post(self):
|
||||||
|
response = self.client.post(self.url, data=self.post_data, follow=True)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_test_generate_email_context(self):
|
||||||
|
context = self.setup_view(self.view()).\
|
||||||
|
test_generate_email_context(self.user)
|
||||||
|
self.assertEqual(context.get('user'), self.user)
|
||||||
|
self.assertEqual(context.get('site_name'), 'ungleich')
|
||||||
|
self.assertEqual(len(context.get('token')), 24)
|
||||||
|
|
||||||
|
|
||||||
|
class PasswordResetConfirmViewTest(BaseTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(PasswordResetConfirmViewTest, self).setUp()
|
||||||
|
|
||||||
|
self.view = PasswordResetConfirmView
|
||||||
|
self.expected_template = 'digitalglarus/confirm_reset_password.html'
|
||||||
|
self.user = mommy.make('membership.CustomUser')
|
||||||
|
self.password = 'fake_password'
|
||||||
|
self.user.set_password(self.password)
|
||||||
|
self.user.save()
|
||||||
|
|
||||||
|
self.token = default_token_generator.make_token(self.user)
|
||||||
|
self.uid = urlsafe_base64_encode(force_bytes(self.user.pk))
|
||||||
|
self.url = reverse('digitalglarus:reset_password_confirm',
|
||||||
|
kwargs={'token': self.token, 'uidb64': self.uid})
|
||||||
|
|
||||||
|
self.post_data = {
|
||||||
|
'new_password1': 'new_password',
|
||||||
|
'new_password2': 'new_password'
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_url_resolve_to_view_correctly(self):
|
||||||
|
found = resolve(self.url)
|
||||||
|
self.assertEqual(found.func.__name__, self.view.__name__)
|
||||||
|
|
||||||
|
def test_get(self):
|
||||||
|
response = self.client.get(self.url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed(response, self.expected_template)
|
||||||
|
|
||||||
|
def test_post(self):
|
||||||
|
response = self.client.post(self.url, data=self.post_data, follow=True)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTrue(not response.context['form'].errors)
|
||||||
|
|
|
@ -6,7 +6,7 @@ from .views import ContactView, IndexView, AboutView, HistoryView, LoginView, Si
|
||||||
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
|
PasswordResetView, PasswordResetConfirmView, MembershipPaymentView, MembershipActivatedView,\
|
||||||
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
|
MembershipPricingView, BookingSelectDatesView, BookingPaymentView, OrdersBookingDetailView,\
|
||||||
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, \
|
BookingOrdersListView, MembershipOrdersListView, OrdersMembershipDetailView, \
|
||||||
MembershipDeactivateView, MembershipDeactivateSuccessView
|
MembershipDeactivateView, MembershipDeactivateSuccessView, UserBillingAddressView
|
||||||
# from membership.views import LoginRegistrationView
|
# from membership.views import LoginRegistrationView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
@ -20,6 +20,7 @@ urlpatterns = [
|
||||||
url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
|
url(r'reset-password-confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$',
|
||||||
PasswordResetConfirmView.as_view(), name='reset_password_confirm'),
|
PasswordResetConfirmView.as_view(), name='reset_password_confirm'),
|
||||||
url(_(r'history/?$'), HistoryView.as_view(), name='history'),
|
url(_(r'history/?$'), HistoryView.as_view(), name='history'),
|
||||||
|
url(_(r'users/billing_address/?$'), UserBillingAddressView.as_view(), name='user_billing_address'),
|
||||||
url(_(r'booking/?$'), BookingSelectDatesView.as_view(), name='booking'),
|
url(_(r'booking/?$'), BookingSelectDatesView.as_view(), name='booking'),
|
||||||
url(_(r'booking/payment/?$'), BookingPaymentView.as_view(), name='booking_payment'),
|
url(_(r'booking/payment/?$'), BookingPaymentView.as_view(), name='booking_payment'),
|
||||||
url(_(r'booking/orders/(?P<pk>\d+)/?$'), OrdersBookingDetailView.as_view(),
|
url(_(r'booking/orders/(?P<pk>\d+)/?$'), OrdersBookingDetailView.as_view(),
|
||||||
|
|
|
@ -27,8 +27,9 @@ from membership.models import Calendar as CalendarModel, StripeCustomer
|
||||||
|
|
||||||
from utils.views import LoginViewMixin, SignupViewMixin, \
|
from utils.views import LoginViewMixin, SignupViewMixin, \
|
||||||
PasswordResetViewMixin, PasswordResetConfirmViewMixin
|
PasswordResetViewMixin, PasswordResetConfirmViewMixin
|
||||||
from utils.forms import PasswordResetRequestForm
|
from utils.forms import PasswordResetRequestForm, UserBillingAddressForm
|
||||||
from utils.stripe_utils import StripeUtils
|
from utils.stripe_utils import StripeUtils
|
||||||
|
from utils.models import UserBillingAddress
|
||||||
|
|
||||||
|
|
||||||
from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm,\
|
from .forms import LoginForm, SignupForm, MembershipBillingForm, BookingDateForm,\
|
||||||
|
@ -120,6 +121,7 @@ class BookingSelectDatesView(LoginRequiredMixin, MembershipRequiredMixin, FormVi
|
||||||
'free_days': free_days,
|
'free_days': free_days,
|
||||||
'start_date': start_date.strftime('%m/%d/%Y'),
|
'start_date': start_date.strftime('%m/%d/%Y'),
|
||||||
'end_date': end_date.strftime('%m/%d/%Y'),
|
'end_date': end_date.strftime('%m/%d/%Y'),
|
||||||
|
'is_free': final_price == 0
|
||||||
})
|
})
|
||||||
return super(BookingSelectDatesView, self).form_valid(form)
|
return super(BookingSelectDatesView, self).form_valid(form)
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
booking_needed_fields = ['original_price', 'final_price', 'booking_days', 'free_days',
|
booking_needed_fields = ['original_price', 'final_price', 'booking_days', 'free_days',
|
||||||
'start_date', 'end_date', 'membership_required_months_price',
|
'start_date', 'end_date', 'membership_required_months_price',
|
||||||
'membership_required_months', 'booking_price_per_day',
|
'membership_required_months', 'booking_price_per_day',
|
||||||
'total_discount']
|
'total_discount', 'is_free']
|
||||||
|
|
||||||
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()
|
||||||
|
@ -146,12 +148,17 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
return reverse('digitalglarus:booking_orders_detail', kwargs={'pk': order_id})
|
return reverse('digitalglarus:booking_orders_detail', kwargs={'pk': order_id})
|
||||||
|
|
||||||
def get_form_kwargs(self):
|
def get_form_kwargs(self):
|
||||||
|
current_billing_address = self.request.user.billing_addresses.first()
|
||||||
form_kwargs = super(BookingPaymentView, self).get_form_kwargs()
|
form_kwargs = super(BookingPaymentView, self).get_form_kwargs()
|
||||||
form_kwargs.update({
|
form_kwargs.update({
|
||||||
'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('final_price'),
|
'price': self.request.session.get('final_price'),
|
||||||
|
'street_address': current_billing_address.street_address,
|
||||||
|
'city': current_billing_address.city,
|
||||||
|
'postal_code': current_billing_address.postal_code,
|
||||||
|
'country': current_billing_address.country,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return form_kwargs
|
return form_kwargs
|
||||||
|
@ -161,11 +168,15 @@ 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}
|
||||||
|
user = self.request.user
|
||||||
|
last_booking_order = BookingOrder.objects.filter(customer__user=user).last()
|
||||||
# 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,
|
# 'current_billing_address': self.request.user.billing_addresses.first().to_dict(),
|
||||||
|
'credit_card_data': last_booking_order.get_booking_cc_data() if last_booking_order
|
||||||
|
else None,
|
||||||
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
|
'stripe_key': settings.STRIPE_API_PUBLIC_KEY
|
||||||
})
|
})
|
||||||
context.update(booking_data)
|
context.update(booking_data)
|
||||||
|
@ -177,11 +188,12 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
token = data.get('token')
|
token = data.get('token')
|
||||||
start_date = data.get('start_date')
|
start_date = data.get('start_date')
|
||||||
end_date = data.get('end_date')
|
end_date = data.get('end_date')
|
||||||
|
is_free = context.get('is_free')
|
||||||
normal_price, final_price, free_days, membership_required_months,\
|
normal_price, final_price, free_days, membership_required_months,\
|
||||||
membership_required_months_price = Booking.\
|
membership_required_months_price = Booking.\
|
||||||
booking_price(self.request.user, start_date, end_date)
|
booking_price(self.request.user, start_date, end_date)
|
||||||
|
|
||||||
|
# if not credit_card_needed:
|
||||||
# Get or create stripe customer
|
# Get or create stripe customer
|
||||||
customer = StripeCustomer.get_or_create(email=self.request.user.email,
|
customer = StripeCustomer.get_or_create(email=self.request.user.email,
|
||||||
token=token)
|
token=token)
|
||||||
|
@ -189,6 +201,44 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
form.add_error("__all__", "Invalid credit card")
|
form.add_error("__all__", "Invalid credit card")
|
||||||
return self.render_to_response(self.get_context_data(form=form))
|
return self.render_to_response(self.get_context_data(form=form))
|
||||||
|
|
||||||
|
if is_free:
|
||||||
|
billing_address = form.save()
|
||||||
|
|
||||||
|
# Create Billing Address for User if he does not have one
|
||||||
|
if not customer.user.billing_addresses.count():
|
||||||
|
data.update({
|
||||||
|
'user': customer.user.id
|
||||||
|
})
|
||||||
|
billing_address_user_form = UserBillingAddressForm(data)
|
||||||
|
billing_address_user_form.is_valid()
|
||||||
|
billing_address_user_form.save()
|
||||||
|
|
||||||
|
# Create membership plan
|
||||||
|
booking_data = {
|
||||||
|
'start_date': start_date,
|
||||||
|
'end_date': end_date,
|
||||||
|
'start_date': start_date,
|
||||||
|
'free_days': free_days,
|
||||||
|
'price': normal_price,
|
||||||
|
'final_price': final_price,
|
||||||
|
}
|
||||||
|
booking = Booking.create(booking_data)
|
||||||
|
|
||||||
|
# Create membership order
|
||||||
|
order_data = {
|
||||||
|
'booking': booking,
|
||||||
|
'customer': customer,
|
||||||
|
'billing_address': billing_address,
|
||||||
|
'amount': final_price,
|
||||||
|
'original_price': normal_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)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(self.get_success_url(order.id))
|
||||||
|
|
||||||
# Make stripe charge to a customer
|
# Make stripe charge to a customer
|
||||||
stripe_utils = StripeUtils()
|
stripe_utils = StripeUtils()
|
||||||
charge_response = stripe_utils.make_charge(amount=final_price,
|
charge_response = stripe_utils.make_charge(amount=final_price,
|
||||||
|
@ -205,9 +255,18 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
|
||||||
|
|
||||||
charge = charge_response.get('response_object')
|
charge = charge_response.get('response_object')
|
||||||
|
|
||||||
# Create Billing Address
|
# Create Billing Address for Membership Order
|
||||||
billing_address = form.save()
|
billing_address = form.save()
|
||||||
|
|
||||||
|
# Create Billing Address for User if he does not have one
|
||||||
|
if not customer.user.billing_addresses.count():
|
||||||
|
data.update({
|
||||||
|
'user': customer.user.id
|
||||||
|
})
|
||||||
|
billing_address_user_form = UserBillingAddressForm(data)
|
||||||
|
billing_address_user_form.is_valid()
|
||||||
|
billing_address_user_form.save()
|
||||||
|
|
||||||
# Create membership plan
|
# Create membership plan
|
||||||
booking_data = {
|
booking_data = {
|
||||||
'start_date': start_date,
|
'start_date': start_date,
|
||||||
|
@ -319,6 +378,7 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView):
|
||||||
'stripe_charge': charge,
|
'stripe_charge': charge,
|
||||||
'amount': membership_type.first_month_price
|
'amount': membership_type.first_month_price
|
||||||
}
|
}
|
||||||
|
|
||||||
membership_order = MembershipOrder.create(order_data)
|
membership_order = MembershipOrder.create(order_data)
|
||||||
|
|
||||||
request.session.update({
|
request.session.update({
|
||||||
|
@ -369,6 +429,7 @@ class MembershipActivatedView(TemplateView):
|
||||||
class MembershipDeactivateView(LoginRequiredMixin, UpdateView):
|
class MembershipDeactivateView(LoginRequiredMixin, UpdateView):
|
||||||
template_name = "digitalglarus/membership_deactivated.html"
|
template_name = "digitalglarus/membership_deactivated.html"
|
||||||
model = Membership
|
model = Membership
|
||||||
|
success_message = "Your membership has been deactivated :("
|
||||||
success_url = reverse_lazy('digitalglarus:membership_orders_list')
|
success_url = reverse_lazy('digitalglarus:membership_orders_list')
|
||||||
login_url = reverse_lazy('digitalglarus:login')
|
login_url = reverse_lazy('digitalglarus:login')
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
@ -384,9 +445,38 @@ class MembershipDeactivateView(LoginRequiredMixin, UpdateView):
|
||||||
def post(self, *args, **kwargs):
|
def post(self, *args, **kwargs):
|
||||||
membership = self.get_object()
|
membership = self.get_object()
|
||||||
membership.deactivate()
|
membership.deactivate()
|
||||||
|
|
||||||
|
messages.add_message(self.request, messages.SUCCESS, self.success_message)
|
||||||
|
|
||||||
return HttpResponseRedirect(self.success_url)
|
return HttpResponseRedirect(self.success_url)
|
||||||
|
|
||||||
|
|
||||||
|
class UserBillingAddressView(LoginRequiredMixin, UpdateView):
|
||||||
|
model = UserBillingAddress
|
||||||
|
form_class = UserBillingAddressForm
|
||||||
|
template_name = "digitalglarus/user_billing_address.html"
|
||||||
|
success_url = reverse_lazy('digitalglarus:user_billing_address')
|
||||||
|
|
||||||
|
def get_form_kwargs(self):
|
||||||
|
current_billing_address = self.request.user.billing_addresses.first()
|
||||||
|
form_kwargs = super(UserBillingAddressView, self).get_form_kwargs()
|
||||||
|
form_kwargs.update({
|
||||||
|
'initial': {
|
||||||
|
'street_address': current_billing_address.street_address,
|
||||||
|
'city': current_billing_address.city,
|
||||||
|
'postal_code': current_billing_address.postal_code,
|
||||||
|
'country': current_billing_address.country,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return form_kwargs
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
|
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
|
||||||
|
if not current_billing_address:
|
||||||
|
raise AttributeError("Billing Address does not exists")
|
||||||
|
return current_billing_address
|
||||||
|
|
||||||
|
|
||||||
class MembershipDeactivateSuccessView(LoginRequiredMixin, TemplateView):
|
class MembershipDeactivateSuccessView(LoginRequiredMixin, TemplateView):
|
||||||
template_name = "digitalglarus/membership_deactivated_success.html"
|
template_name = "digitalglarus/membership_deactivated_success.html"
|
||||||
|
|
||||||
|
@ -401,9 +491,11 @@ class MembershipOrdersListView(LoginRequiredMixin, ListView):
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(MembershipOrdersListView, self).get_context_data(**kwargs)
|
context = super(MembershipOrdersListView, self).get_context_data(**kwargs)
|
||||||
start_date, end_date = MembershipOrder.current_membership(self.request.user)
|
start_date, end_date = MembershipOrder.current_membership(self.request.user)
|
||||||
|
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
|
||||||
context.update({
|
context.update({
|
||||||
'membership_start_date': start_date,
|
'membership_start_date': start_date,
|
||||||
'membership_end_date': end_date,
|
'membership_end_date': end_date,
|
||||||
|
'billing_address': current_billing_address
|
||||||
})
|
})
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
@ -477,6 +569,14 @@ class BookingOrdersListView(LoginRequiredMixin, ListView):
|
||||||
model = BookingOrder
|
model = BookingOrder
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(BookingOrdersListView, self).get_context_data(**kwargs)
|
||||||
|
current_billing_address = self.request.user.billing_addresses.filter(current=True).last()
|
||||||
|
context.update({
|
||||||
|
'billing_address': current_billing_address
|
||||||
|
})
|
||||||
|
return context
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
queryset = super(BookingOrdersListView, self).get_queryset()
|
queryset = super(BookingOrdersListView, self).get_queryset()
|
||||||
queryset = queryset.filter(customer__user=self.request.user)
|
queryset = queryset.filter(customer__user=self.request.user)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from .models import ContactMessage, BillingAddress
|
from .models import ContactMessage, BillingAddress, UserBillingAddress
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -109,6 +109,19 @@ class BillingAddressForm(forms.ModelForm):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class UserBillingAddressForm(forms.ModelForm):
|
||||||
|
user = forms.ModelChoiceField(queryset=CustomUser.objects.all(),
|
||||||
|
widget=forms.HiddenInput())
|
||||||
|
class Meta:
|
||||||
|
model = UserBillingAddress
|
||||||
|
fields = ['street_address', 'city', 'postal_code', 'country', 'user']
|
||||||
|
labels = {
|
||||||
|
'street_address': _('Street Address'),
|
||||||
|
'city': _('City'),
|
||||||
|
'postal_code': _('Postal Code'),
|
||||||
|
'Country': _('Country'),
|
||||||
|
}
|
||||||
|
|
||||||
class ContactUsForm(forms.ModelForm):
|
class ContactUsForm(forms.ModelForm):
|
||||||
error_css_class = 'autofocus'
|
error_css_class = 'autofocus'
|
||||||
|
|
||||||
|
|
34
utils/migrations/0003_userbillingaddress.py
Normal file
34
utils/migrations/0003_userbillingaddress.py
Normal file
File diff suppressed because one or more lines are too long
22
utils/migrations/0004_auto_20161013_0253.py
Normal file
22
utils/migrations/0004_auto_20161013_0253.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.9.4 on 2016-10-13 02:53
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('utils', '0003_userbillingaddress'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='userbillingaddress',
|
||||||
|
name='user',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='billing_addresses', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,20 +1,45 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core import serializers
|
||||||
|
from django.forms.models import model_to_dict
|
||||||
|
|
||||||
|
from membership.models import CustomUser
|
||||||
|
|
||||||
from .fields import CountryField
|
from .fields import CountryField
|
||||||
|
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
|
class BaseBillingAddress(models.Model):
|
||||||
class BillingAddress(models.Model):
|
|
||||||
street_address = models.CharField(max_length=100)
|
street_address = models.CharField(max_length=100)
|
||||||
city = models.CharField(max_length=50)
|
city = models.CharField(max_length=50)
|
||||||
postal_code = models.CharField(max_length=50)
|
postal_code = models.CharField(max_length=50)
|
||||||
country = CountryField()
|
country = CountryField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
class BillingAddress(BaseBillingAddress):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.street_address
|
return self.street_address
|
||||||
|
|
||||||
|
|
||||||
|
class UserBillingAddress(BaseBillingAddress):
|
||||||
|
user = models.ForeignKey(CustomUser, related_name='billing_addresses')
|
||||||
|
current = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.street_address
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
'Street Address': self.street_address,
|
||||||
|
'City': self.city,
|
||||||
|
'Postal Code': self.postal_code,
|
||||||
|
'Country': self.country,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class ContactMessage(models.Model):
|
class ContactMessage(models.Model):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
email = models.EmailField()
|
email = models.EmailField()
|
||||||
|
|
Loading…
Reference in a new issue