Merge pull request #133 from levivm/feature/new_digitalglarus

Feature/new digitalglarus
This commit is contained in:
Levi Velázquez 2016-10-18 23:31:55 -05:00 committed by GitHub
commit 8b75ddd64f
14 changed files with 201 additions and 87 deletions

View file

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-10-17 19:58
from __future__ import unicode_literals
import datetime
from django.db import migrations, models
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('digitalglarus', '0020_auto_20161013_0253'),
]
operations = [
migrations.AddField(
model_name='membership',
name='end_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 0, 209303, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membership',
name='start_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 7, 361473, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membershiporder',
name='end_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 15, 657240, tzinfo=utc)),
preserve_default=False,
),
migrations.AddField(
model_name='membershiporder',
name='start_date',
field=models.DateField(default=datetime.datetime(2016, 10, 17, 19, 58, 16, 897120, tzinfo=utc)),
preserve_default=False,
),
]

View file

@ -62,6 +62,13 @@ class MembershipType(models.Model):
class Membership(models.Model): class Membership(models.Model):
type = models.ForeignKey(MembershipType) type = models.ForeignKey(MembershipType)
active = models.BooleanField(default=True) active = models.BooleanField(default=True)
start_date = models.DateField()
end_date = models.DateField()
@classmethod
def get_by_user(cls, user):
return cls.objects.\
filter(membershiporder__customer__user=user).last()
@classmethod @classmethod
def create(cls, data): def create(cls, data):
@ -79,6 +86,11 @@ class Membership(models.Model):
return cls.objects.filter(has_order_past_month | has_order_current_month).\ return cls.objects.filter(has_order_past_month | has_order_current_month).\
filter(active_membership).exists() filter(active_membership).exists()
def update_dates(self, start_date, end_date):
self.start_date = start_date
self.end_date = end_date
self.save()
def deactivate(self): def deactivate(self):
self.active = False self.active = False
self.save() self.save()
@ -86,17 +98,19 @@ class Membership(models.Model):
class MembershipOrder(Ordereable, models.Model): class MembershipOrder(Ordereable, models.Model):
membership = models.ForeignKey(Membership) membership = models.ForeignKey(Membership)
start_date = models.DateField()
end_date = models.DateField()
@classmethod @classmethod
def current_membership(cls, user): def current_membership(cls, user):
last_payment = cls.objects.\ last_membership_payment = cls.objects.\
filter(customer__user=user).last() filter(customer__user=user).last()
start_date = last_payment.created_at # start_date = last_payment.created_at
_, days_in_month = calendar.monthrange(start_date.year, # _, days_in_month = calendar.monthrange(start_date.year,
start_date.month) # start_date.month)
start_date.replace(day=1) # start_date.replace(day=1)
end_date = start_date + timedelta(days=days_in_month) # end_date = start_date + timedelta(days=days_in_month)
return start_date, end_date return last_membership_payment.start_date, last_membership_payment.end_date
def first_membership_range_date(self): def first_membership_range_date(self):
start_date = self.created_at start_date = self.created_at

View file

@ -1172,11 +1172,11 @@ footer {
} }
.map-caption{ .map-caption{
text-transform: none; text-transform:uppercase;
font-size: 13px;
font-family:"Montserrat","Helvetica Neue",Helvetica, Arial,sans-serif; font-family:"Montserrat","Helvetica Neue",Helvetica, Arial,sans-serif;
font-weight: 400; font-weight: 400;
color: #ffffff; color: #ffffff;
font-size: 14px;
letter-spacing: 1px; letter-spacing: 1px;
text-align:center; text-align:center;
} }

View file

@ -18,4 +18,6 @@ $( document ).ready(function() {
}); });
}); });

View file

@ -56,7 +56,12 @@
<h2 class="col-xs-6 payment-total text-left"> Total</h2> <h2 class="col-xs-6 payment-total text-left"> Total</h2>
<h2 class="order-result">{{final_price|floatformat}}CHF</h2> <h2 class="order-result">{{final_price|floatformat}}CHF</h2>
<br> <br>
<p class="order-bottom-text">
View my bookings <a href="{% url 'digitalglarus:booking_orders_list' %}">Go to my page</a>
</p>
</div> </div>
</div> </div>
<div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown hidden-print"> <div class="col-xs-12 col-sm-4 col-lg-4 wow fadeInDown hidden-print">

View file

@ -24,6 +24,7 @@
<th>#</th> <th>#</th>
<th>Booking dates</th> <th>Booking dates</th>
<th>Days</th> <th>Days</th>
<th>Membership Required Months</th>
<th>Invoice</th> <th>Invoice</th>
</tr> </tr>
</thead> </thead>
@ -33,6 +34,7 @@
<th scope="row">{{order.id}}</th> <th scope="row">{{order.id}}</th>
<td>{{order.booking.start_date}}-{{order.booking.end_date}}</td> <td>{{order.booking.start_date}}-{{order.booking.end_date}}</td>
<td>{{order.booking_days}}</td> <td>{{order.booking_days}}</td>
<td>{{order.membership_required_months}}</td>
<td><a class="btn btn-xs btn-primary btn-darkgrey" href="{% url 'digitalglarus:booking_orders_detail' order.id %}">View</a></td> <td><a class="btn btn-xs btn-primary btn-darkgrey" href="{% url 'digitalglarus:booking_orders_detail' order.id %}">View</a></td>
</tr> </tr>
{% endfor %} {% endfor %}

View file

@ -18,6 +18,10 @@
padding: .5em; padding: .5em;
padding-right: 1.5em padding-right: 1.5em
} }
.order-bottom-text a{
margin-left: 0px;
}
</style> </style>
<section id="price"> <section id="price">
@ -141,8 +145,9 @@
</div> </div>
<div class="order-box"> <div class="order-box">
<h3 class="col-xs-6 order-item">Dates {{start_date}} - {{end_date}}</h3> <h3 class="col-xs-6 order-item">Dates {{start_date}} - {{end_date}}</h3>
<br/> <p class="order-bottom-text">
<a href="{{request.META.HTTP_REFERER}}">Change dates</a>
</p>
<hr class="greyline"> <hr class="greyline">
<h2 class="col-xs-6 payment-total">Total days: {{booking_days}} </h2> <h2 class="col-xs-6 payment-total">Total days: {{booking_days}} </h2>
<h2 class="order-sum">{{original_price|floatformat}}CHF</h2> <h2 class="order-sum">{{original_price|floatformat}}CHF</h2>
@ -168,7 +173,7 @@
<div class="button-box"> <div class="button-box">
<div class="row"> <div class="row">
<div class="col-xs-12"> <div class="col-xs-12">
<button id="payment_button" class="btn btn-primary btn-lg btn-blck " type="submit">Book</button> <button id="payment_button" class="btn btn-primary btn-md btn-blck " type="submit">Book</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -3,6 +3,15 @@
{% block title %}crowdfunding{% endblock %} {% block title %}crowdfunding{% endblock %}
{% block content %} {% block content %}
<style type="text/css">
#cancel-subscription-modal{
margin-top:10%;
}
</style>
<section id="price"> <section id="price">
<div class="signup-container"> <div class="signup-container">
<div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div> <div class="col-xs-12 col-sm-3 col-lg-4 text-center wow fadeInDown"> </div>
@ -25,6 +34,7 @@
<button type="button" class="btn btn-primary btn-blue" data-toggle="modal" data-target="#cancel-subscription-modal">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 fade bs-example-modal-sm" id="cancel-subscription-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
@ -36,7 +46,7 @@
<p>Do you want to cancel your subscription?</p> <p>Do you want to cancel your subscription?</p>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">No</button> <button type="button" class="btn btn-primary btn-grey" data-dismiss="modal">No</button>
<button type="submit" class="btn btn-primary">Yes</button> <button type="submit" class="btn btn-primary">Yes</button>
</div> </div>
</div><!-- /.modal-content --> </div><!-- /.modal-content -->
@ -49,7 +59,7 @@
</div> </div>
<div class="notice-box text-left"> <div class="notice-box text-left">
<p class="order-bottom-text"> <p class="order-bottom-text">
Your membership wouldn't be automatically renewed each month. Your membership wouldn't be automatically renewed each month. <a href="{{request.META.HTTP_REFERER}}">Go back</a>
</p> </p>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@
<div class="signup-container"> <div class="signup-container">
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown"> <div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
<div class="payment-box"> <div class="payment-box">
<h2 class="section-heading payment-head">Your membership invoice for {{order.created_at|date:"F"}}</h2> <h2 class="section-heading payment-head">Your membership invoice for {{order.created_at|date:"Y-m"}}</h2>
<hr class="greyline-long"> <hr class="greyline-long">
<h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print hidden-print" data-print="price">Get PDF</btn></h2> <h2 class="billing-head">Invoice<btn class="btn btn-primary btn-grey btn-edit print hidden-print" data-print="price">Get PDF</btn></h2>

View file

@ -14,7 +14,7 @@
<h2 class="order-head">Member Name</h2> <h2 class="order-head">Member Name</h2>
<h2 class="member-name">{{request.user.name}}</h2> <h2 class="member-name">{{request.user.name}}</h2>
<hr class="greyline-long"> <hr class="greyline-long">
<h2 class="order-head">Active Membership</h2> <h2 class="order-head">Current Membership</h2>
<h2 class="member-name">{{membership_start_date|date}}-{{membership_end_date|date}}</h2> <h2 class="member-name">{{membership_start_date|date}}-{{membership_end_date|date}}</h2>
<hr class="greyline-long"> <hr class="greyline-long">
<h2 class="order-head">Orders history</h2> <h2 class="order-head">Orders history</h2>

View file

@ -91,6 +91,13 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<label class="custom-control custom-checkbox">
<br/>
<input type="checkbox" class="custom-control-input">
<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>
</label>
<div class="col-xs-12"> <div class="col-xs-12">
<button class="btn btn-primary btn-md btn-blck " type="submit">Purchase membership</button> <button class="btn btn-primary btn-md btn-blck " type="submit">Purchase membership</button>
</div> </div>
@ -132,12 +139,6 @@
<h2 class="col-xs-6 payment-total">Total</h2> <h2 class="col-xs-6 payment-total">Total</h2>
<h2 class="order-result">{{membership_type.first_month_price|floatformat}}CHF</h2> <h2 class="order-result">{{membership_type.first_month_price|floatformat}}CHF</h2>
<div class="text-center"> <div class="text-center">
<label class="custom-control custom-checkbox">
<br/>
<input type="checkbox" class="custom-control-input">
<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>
</label>
<div class="button-box"> <div class="button-box">
</div> </div>

View file

@ -5,8 +5,8 @@
{% block content %} {% block content %}
<section id="price"> <section id="price">
<div class="container"> <div class="container">
<div class="row col-md-3 text-center wow fadeInDown"></div> <div class="row col-md-2 text-center wow fadeInDown"></div>
<div class="row col-md-6 text-center wow fadeInDown"> <div class="row col-md-8 text-center wow fadeInDown">
<div class="price-box"> <div class="price-box">
<span class="glyphicon glyphicon-star"></span> <span class="glyphicon glyphicon-star"></span>
<h2 class="section-heading">Digital Glarus Membership</h2> <h2 class="section-heading">Digital Glarus Membership</h2>
@ -39,7 +39,7 @@
</div> </div>
</div> </div>
<div class="row col-md-3 text-center wow fadeInDown"></div> <div class="row col-md-2 text-center wow fadeInDown"></div>
</div> </div>
</section> </section>
<!--membership includes--> <!--membership includes-->

View file

@ -24,7 +24,7 @@
<div class="signup-container"> <div class="signup-container">
<div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown"> <div class="col-xs-12 col-sm-6 col-lg-8 text-center wow fadeInDown">
<div class="payment-box"> <div class="payment-box">
<h2 class="section-heading payment-head">Billing Address Info</h2> <h2 class="section-heading payment-head">Billing Address</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="billing-head">Billing Adress</h2>
@ -35,6 +35,7 @@
{% bootstrap_field field show_label=False type='fields'%} {% bootstrap_field field show_label=False type='fields'%}
{% endfor %} {% endfor %}
{% bootstrap_form_errors form type='non_fields'%} {% bootstrap_form_errors form type='non_fields'%}
<input type="hidden" name="next" value="{{request.META.HTTP_REFERER}}">
<br> <br>
<div class="row"> <div class="row">
@ -44,7 +45,7 @@
<h2 class="signup-lead text-center">{{ message }}</h2> <h2 class="signup-lead text-center">{{ message }}</h2>
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<button id="payment_button" class="btn btn-primary btn-lg btn-blck " type="submit">Save</button> <button id="payment_button" class="btn btn-primary btn-md btn-blck " type="submit">Save</button>
</div> </div>
</div> </div>
</form> </form>

View file

@ -209,44 +209,46 @@ 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: # if is_free:
billing_address = form.save() # billing_address = form.save()
# Create Billing Address for User if he does not have one # # Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count(): # if not customer.user.billing_addresses.count():
data.update({ # data.update({
'user': customer.user.id # 'user': customer.user.id
}) # })
billing_address_user_form = UserBillingAddressForm(data) # billing_address_user_form = UserBillingAddressForm(data)
billing_address_user_form.is_valid() # billing_address_user_form.is_valid()
billing_address_user_form.save() # billing_address_user_form.save()
# Create membership plan # # Create membership plan
booking_data = { # booking_data = {
'start_date': start_date, # 'start_date': start_date,
'end_date': end_date, # 'end_date': end_date,
'start_date': start_date, # 'start_date': start_date,
'free_days': free_days, # 'free_days': free_days,
'price': normal_price, # 'price': normal_price,
'final_price': final_price, # 'final_price': final_price,
} # }
booking = Booking.create(booking_data) # booking = Booking.create(booking_data)
# Create membership order # # Create membership order
order_data = { # order_data = {
'booking': booking, # 'booking': booking,
'customer': customer, # 'customer': customer,
'billing_address': billing_address, # 'billing_address': billing_address,
'amount': final_price, # 'amount': final_price,
'original_price': normal_price, # 'original_price': normal_price,
'special_month_price': BookingPrice.objects.last().special_month_price, # 'special_month_price': BookingPrice.objects.last().special_month_price,
'membership_required_months': membership_required_months, # 'membership_required_months': membership_required_months,
'membership_required_months_price': membership_required_months_price, # 'membership_required_months_price': membership_required_months_price,
} # }
order = BookingOrder.create(order_data) # order = BookingOrder.create(order_data)
return HttpResponseRedirect(self.get_success_url(order.id)) # return HttpResponseRedirect(self.get_success_url(order.id))
# If booking is not free, make the stripe charge
if not is_free:
# 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,
@ -266,6 +268,24 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
# Create Billing Address for Membership Order # Create Billing Address for Membership Order
billing_address = form.save() billing_address = form.save()
# Check if user had to pay membership months in advaced
# if membership_required_months:
# # Get current user membership
# membership = Membership.get_by_user(self.request.user)
# # Create membership order
# order_data = {
# 'membership': membership,
# 'customer': customer,
# 'billing_address': billing_address,
# 'amount': membership_required_months_price,
# 'start_date': start_date,
# 'end_date': end_date
# }
# MembershipOrder.create(order_data)
# Create Billing Address for User if he does not have one # Create Billing Address for User if he does not have one
if not customer.user.billing_addresses.count(): if not customer.user.billing_addresses.count():
data.update({ data.update({
@ -275,7 +295,7 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
billing_address_user_form.is_valid() billing_address_user_form.is_valid()
billing_address_user_form.save() billing_address_user_form.save()
# Create membership plan # Create Booking
booking_data = { booking_data = {
'start_date': start_date, 'start_date': start_date,
'end_date': end_date, 'end_date': end_date,
@ -286,7 +306,7 @@ class BookingPaymentView(LoginRequiredMixin, MembershipRequiredMixin, FormView):
} }
booking = Booking.create(booking_data) booking = Booking.create(booking_data)
# Create membership order # Create Booking order
order_data = { order_data = {
'booking': booking, 'booking': booking,
'customer': customer, 'customer': customer,
@ -383,8 +403,15 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView):
billing_address_user_form.is_valid() billing_address_user_form.is_valid()
billing_address_user_form.save() billing_address_user_form.save()
# Get membership dates
membership_start_date, membership_end_date = membership_type.first_month_range
# Create membership plan # Create membership plan
membership_data = {'type': membership_type} membership_data = {
'type': membership_type,
'start_date': membership_start_date,
'end_date': membership_end_date
}
membership = Membership.create(membership_data) membership = Membership.create(membership_data)
# Create membership order # Create membership order
@ -393,7 +420,9 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView):
'customer': customer, 'customer': customer,
'billing_address': billing_address, 'billing_address': billing_address,
'stripe_charge': charge, 'stripe_charge': charge,
'amount': membership_type.first_month_price 'amount': membership_type.first_month_price,
'start_date': membership_start_date,
'end_date': membership_end_date
} }
membership_order = MembershipOrder.create(order_data) membership_order = MembershipOrder.create(order_data)
@ -403,13 +432,11 @@ class MembershipPaymentView(LoginRequiredMixin, IsNotMemberMixin, FormView):
'membership_dates': membership.type.first_month_formated_range 'membership_dates': membership.type.first_month_formated_range
}) })
start_m_date, end_m_date = membership_order.first_membership_range_date()
context = { context = {
'membership': membership, 'membership': membership,
'order': membership_order, 'order': membership_order,
'membership_start_date': start_m_date, 'membership_start_date': membership_start_date,
'membership_end_date': end_m_date, 'membership_end_date': membership_end_date,
'base_url': "{0}://{1}".format(request.scheme, request.get_host()) 'base_url': "{0}://{1}".format(request.scheme, request.get_host())
} }
@ -475,6 +502,12 @@ class UserBillingAddressView(LoginRequiredMixin, UpdateView):
success_url = reverse_lazy('digitalglarus:user_billing_address') success_url = reverse_lazy('digitalglarus:user_billing_address')
success_message = "Billing Address Updated" success_message = "Billing Address Updated"
def get_success_url(self):
next_url = self.request.POST.get('next') if self.request.POST.get('next')\
else self.success_url
return next_url
def form_valid(self, form): def form_valid(self, form):
""" """
If the form is valid, save the associated model. If the form is valid, save the associated model.