Merge pull request #129 from levivm/feature/new_digitalglarus

Feature/new digitalglarus
This commit is contained in:
Levi Velázquez 2016-10-13 23:39:37 -05:00 committed by GitHub
commit 68b149cebd
24 changed files with 735 additions and 148 deletions

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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">&times;</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>
@ -32,6 +53,9 @@
</p> </p>
</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>

View file

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

View file

@ -38,11 +38,14 @@
{% endfor %} {% endfor %}
</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,19 +70,38 @@
<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>

View file

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

View file

@ -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>&nbsp;</p>
</span>
</div>
<p>&nbsp;</p>
</div>
</div>
</div>
</section>
<!-- stripe key data -->
{% if stripe_key %}
<script type="text/javascript">
(function () {window.stripeKey = "{{stripe_key}}";})();
</script>
{%endif%}
{% endblock %}

View file

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

View file

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

View file

@ -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(),

View file

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

View file

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

File diff suppressed because one or more lines are too long

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

View file

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