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> | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
|  | @ -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> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue