2016-08-22 07:52:29 +00:00
|
|
|
|
|
|
|
import calendar
|
|
|
|
from datetime import datetime, date, timedelta
|
2016-09-06 00:45:45 +00:00
|
|
|
from dateutil.relativedelta import relativedelta
|
2015-05-02 15:00:15 +00:00
|
|
|
from django.db import models
|
2016-09-06 00:45:45 +00:00
|
|
|
from django.db.models import Q
|
2016-03-05 19:57:41 +00:00
|
|
|
from cms.models import CMSPlugin
|
|
|
|
from filer.fields.image import FilerImageField
|
2016-04-23 17:00:20 +00:00
|
|
|
from django.core.urlresolvers import reverse
|
2016-08-22 07:52:29 +00:00
|
|
|
from django.utils.functional import cached_property
|
2016-08-31 02:32:45 +00:00
|
|
|
from .mixins import Ordereable
|
2016-08-22 07:52:29 +00:00
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
# from membership.models import StripeCustomer
|
|
|
|
# from utils.models import BillingAddress
|
2015-05-02 15:00:15 +00:00
|
|
|
|
|
|
|
|
2016-08-20 05:57:35 +00:00
|
|
|
class MembershipType(models.Model):
|
|
|
|
|
2016-09-29 05:04:40 +00:00
|
|
|
STANDARD = 'standard'
|
2016-08-20 05:57:35 +00:00
|
|
|
MEMBERSHIP_TYPES = (
|
2016-09-29 05:04:40 +00:00
|
|
|
(STANDARD, 'Standard'),
|
2016-08-20 05:57:35 +00:00
|
|
|
|
|
|
|
)
|
|
|
|
name = models.CharField(choices=MEMBERSHIP_TYPES, max_length=20)
|
|
|
|
price = models.FloatField()
|
|
|
|
|
2016-08-22 07:52:29 +00:00
|
|
|
@cached_property
|
|
|
|
def days_left(self):
|
|
|
|
current_date = date.today()
|
|
|
|
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
|
|
|
|
pass_days = current_date.day
|
|
|
|
days_left = days_in_month - pass_days + 1
|
|
|
|
return days_left
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def first_month_price(self):
|
|
|
|
current_date = date.today()
|
|
|
|
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
|
|
|
|
pass_days = current_date.day
|
|
|
|
days_left = days_in_month - pass_days + 1
|
|
|
|
percentage = days_left / days_in_month
|
|
|
|
membership_price = self.price
|
|
|
|
final_price = membership_price * percentage
|
|
|
|
return final_price
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def first_month_range(self):
|
|
|
|
current_date = date.today()
|
|
|
|
_, days_in_month = calendar.monthrange(current_date.year, current_date.month)
|
|
|
|
pass_days = current_date.day
|
|
|
|
days_left = days_in_month - pass_days
|
|
|
|
end_date = current_date + timedelta(days=days_left)
|
|
|
|
return current_date, end_date
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def first_month_formated_range(self):
|
|
|
|
start_date, end_date = self.first_month_range
|
|
|
|
return "{} - {}".format(datetime.strftime(start_date, "%b, %d %Y"),
|
|
|
|
datetime.strftime(end_date, "%b, %d %Y"))
|
|
|
|
|
2016-08-20 05:57:35 +00:00
|
|
|
|
|
|
|
class Membership(models.Model):
|
|
|
|
type = models.ForeignKey(MembershipType)
|
Reduced pixels needed to navbar transition color, Added membership deactivation form, Added membership deactivation view, Added membership status, Added membership charged.html, Added membership charged.txt, Extended class to send membership charge email, After membership, charge for first time an email is sent to the user, Fixed bug on redirecting, user to membership payment after signup, Fixed redirecting after buying a membership
2016-09-14 05:24:20 +00:00
|
|
|
active = models.BooleanField(default=True)
|
2016-08-20 05:57:35 +00:00
|
|
|
|
2016-09-06 00:45:45 +00:00
|
|
|
@classmethod
|
2016-09-29 05:04:40 +00:00
|
|
|
def is_digitalglarus_active_member(cls, user):
|
2016-09-06 00:45:45 +00:00
|
|
|
past_month = (datetime.today() - relativedelta(months=1)).month
|
2016-09-09 04:24:52 +00:00
|
|
|
has_booking_current_month = Q(membershiporder__customer__user=user,
|
|
|
|
membershiporder__created_at__month=datetime.today().month)
|
2016-09-06 00:45:45 +00:00
|
|
|
has_booking_past_month = Q(membershiporder__customer__user=user,
|
|
|
|
membershiporder__created_at__month=past_month)
|
Reduced pixels needed to navbar transition color, Added membership deactivation form, Added membership deactivation view, Added membership status, Added membership charged.html, Added membership charged.txt, Extended class to send membership charge email, After membership, charge for first time an email is sent to the user, Fixed bug on redirecting, user to membership payment after signup, Fixed redirecting after buying a membership
2016-09-14 05:24:20 +00:00
|
|
|
active_membership = Q(active=True)
|
|
|
|
return cls.objects.filter(has_booking_past_month | has_booking_current_month).\
|
|
|
|
filter(active_membership).exists()
|
2016-09-06 00:45:45 +00:00
|
|
|
|
2016-08-20 05:57:35 +00:00
|
|
|
@classmethod
|
2016-08-22 07:52:29 +00:00
|
|
|
def create(cls, data):
|
2016-08-20 05:57:35 +00:00
|
|
|
instance = cls.objects.create(**data)
|
|
|
|
return instance
|
|
|
|
|
Reduced pixels needed to navbar transition color, Added membership deactivation form, Added membership deactivation view, Added membership status, Added membership charged.html, Added membership charged.txt, Extended class to send membership charge email, After membership, charge for first time an email is sent to the user, Fixed bug on redirecting, user to membership payment after signup, Fixed redirecting after buying a membership
2016-09-14 05:24:20 +00:00
|
|
|
def deactivate(self):
|
|
|
|
self.active = False
|
|
|
|
self.save()
|
|
|
|
|
2016-08-20 05:57:35 +00:00
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
class MembershipOrder(Ordereable, models.Model):
|
2016-08-20 05:57:35 +00:00
|
|
|
membership = models.ForeignKey(Membership)
|
|
|
|
|
Reduced pixels needed to navbar transition color, Added membership deactivation form, Added membership deactivation view, Added membership status, Added membership charged.html, Added membership charged.txt, Extended class to send membership charge email, After membership, charge for first time an email is sent to the user, Fixed bug on redirecting, user to membership payment after signup, Fixed redirecting after buying a membership
2016-09-14 05:24:20 +00:00
|
|
|
def first_membership_range_date(self):
|
|
|
|
start_date = self.created_at
|
|
|
|
_, days_in_month = calendar.monthrange(start_date.year,
|
|
|
|
start_date.month)
|
|
|
|
pass_days = start_date.day
|
|
|
|
days_left = days_in_month - pass_days
|
|
|
|
end_date = start_date + timedelta(days=days_left)
|
|
|
|
return start_date, end_date
|
|
|
|
|
2016-09-09 04:24:52 +00:00
|
|
|
@classmethod
|
|
|
|
def current_membership(cls, user):
|
|
|
|
last_payment = cls.objects.\
|
|
|
|
filter(customer__user=user).last()
|
|
|
|
start_date = last_payment.created_at
|
|
|
|
_, days_in_month = calendar.monthrange(start_date.year,
|
|
|
|
start_date.month)
|
|
|
|
start_date.replace(day=1)
|
|
|
|
end_date = start_date + timedelta(days=days_in_month)
|
|
|
|
return start_date, end_date
|
|
|
|
|
|
|
|
def get_membership_range_date(self):
|
|
|
|
start_date = self.created_at
|
|
|
|
_, days_in_month = calendar.monthrange(start_date.year,
|
|
|
|
start_date.month)
|
|
|
|
start_date.replace(day=1)
|
|
|
|
end_date = start_date + timedelta(days=days_in_month)
|
|
|
|
return start_date, end_date
|
|
|
|
|
2016-08-22 07:52:29 +00:00
|
|
|
@classmethod
|
|
|
|
def create(cls, data):
|
|
|
|
stripe_charge = data.pop('stripe_charge', None)
|
|
|
|
instance = cls.objects.create(**data)
|
|
|
|
instance.stripe_charge_id = stripe_charge.id
|
|
|
|
instance.last4 = stripe_charge.source.last4
|
|
|
|
instance.cc_brand = stripe_charge.source.brand
|
2016-09-09 04:24:52 +00:00
|
|
|
instance.save()
|
2016-08-22 07:52:29 +00:00
|
|
|
return instance
|
|
|
|
|
2016-08-20 05:57:35 +00:00
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
class BookingPrice(models.Model):
|
|
|
|
price_per_day = models.FloatField()
|
2016-09-09 04:24:52 +00:00
|
|
|
special_month_price = models.FloatField()
|
2016-08-31 02:32:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Booking(models.Model):
|
|
|
|
start_date = models.DateField()
|
|
|
|
end_date = models.DateField()
|
|
|
|
price = models.FloatField()
|
|
|
|
free_days = models.IntegerField(default=0)
|
2016-09-06 00:45:45 +00:00
|
|
|
final_price = models.FloatField()
|
2016-08-31 02:32:45 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create(cls, data):
|
|
|
|
instance = cls.objects.create(**data)
|
|
|
|
return instance
|
|
|
|
|
|
|
|
@classmethod
|
2016-09-06 00:45:45 +00:00
|
|
|
def get_ramaining_free_days(cls, user, start_date, end_date):
|
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
TWO_DAYS = 2
|
|
|
|
|
2016-09-06 00:45:45 +00:00
|
|
|
start_month = start_date.month
|
|
|
|
end_month = end_date.month
|
|
|
|
months = abs(start_month - (end_month + 12) if end_month < start_month
|
|
|
|
else end_month - start_month)
|
2016-08-31 02:32:45 +00:00
|
|
|
current_date = datetime.today()
|
|
|
|
current_month_bookings = cls.objects.filter(bookingorder__customer__user=user,
|
|
|
|
start_date__month=current_date.month)
|
2016-09-06 00:45:45 +00:00
|
|
|
free_days_this_month = TWO_DAYS - sum(map(lambda x: x.free_days, current_month_bookings))
|
|
|
|
total_free_days = months * TWO_DAYS + free_days_this_month
|
|
|
|
return total_free_days
|
2016-08-31 02:32:45 +00:00
|
|
|
|
2016-09-29 05:04:40 +00:00
|
|
|
@staticmethod
|
|
|
|
def membership_required_booking_months(start_date, end_date):
|
|
|
|
start_month = start_date.month
|
|
|
|
end_month = end_date.month
|
|
|
|
months = abs(start_month - (end_month + 12) if end_month < start_month
|
|
|
|
else end_month - start_month)
|
|
|
|
return months
|
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
@classmethod
|
|
|
|
def booking_price(cls, user, start_date, end_date):
|
2016-09-06 00:45:45 +00:00
|
|
|
|
2016-09-09 04:24:52 +00:00
|
|
|
MAX_MONTH_PRICE = BookingPrice.objects.last().special_month_price
|
2016-09-06 00:45:45 +00:00
|
|
|
MAX_MONTH_DAYS_PROMOTION = 31
|
|
|
|
MIN_MONTH_DAYS_PROMOTION = 19
|
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
booking_prices = BookingPrice.objects.last()
|
|
|
|
price_per_day = booking_prices.price_per_day
|
2016-09-06 00:45:45 +00:00
|
|
|
booking_days = (end_date - start_date).days + 1
|
|
|
|
months = booking_days // MAX_MONTH_DAYS_PROMOTION
|
|
|
|
remanent_days = booking_days % MAX_MONTH_DAYS_PROMOTION
|
|
|
|
months_prices = months * MAX_MONTH_PRICE
|
|
|
|
remanent_days_price = remanent_days * price_per_day \
|
|
|
|
if remanent_days <= MIN_MONTH_DAYS_PROMOTION else MAX_MONTH_PRICE
|
|
|
|
normal_price = months_prices + remanent_days_price
|
2016-08-31 02:32:45 +00:00
|
|
|
|
2016-09-06 00:45:45 +00:00
|
|
|
free_days = cls.get_ramaining_free_days(user, start_date, end_date)
|
|
|
|
final_booking_price = normal_price - (free_days * price_per_day)
|
2016-08-31 02:32:45 +00:00
|
|
|
|
2016-09-29 05:04:40 +00:00
|
|
|
# Calculating membership required months price for booking
|
|
|
|
required_membership_months = 0
|
|
|
|
membership_booking_price = 0.0
|
|
|
|
if BookingOrder.user_has_not_bookings(user):
|
|
|
|
today = datetime.today().date()
|
|
|
|
membership_price = MembershipType.objects.get(name=MembershipType.STANDARD).price
|
|
|
|
required_membership_months = cls.membership_required_booking_months(today, end_date)
|
|
|
|
membership_booking_price = membership_price * required_membership_months
|
|
|
|
|
|
|
|
# Add required membership months to final prices
|
|
|
|
final_booking_price += membership_booking_price
|
|
|
|
|
|
|
|
return normal_price, final_booking_price, free_days,\
|
|
|
|
required_membership_months, membership_booking_price
|
2016-08-31 02:32:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
class BookingOrder(Ordereable, models.Model):
|
|
|
|
booking = models.OneToOneField(Booking)
|
2016-09-09 04:24:52 +00:00
|
|
|
original_price = models.FloatField()
|
|
|
|
special_month_price = models.FloatField()
|
2016-09-29 05:04:40 +00:00
|
|
|
membership_required_months = models.IntegerField(default=0)
|
|
|
|
membership_required_months_price = models.FloatField(default=0)
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def user_has_not_bookings(cls, user):
|
|
|
|
return cls.objects.filter(customer__user=user).exists()
|
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
|
2016-09-06 00:45:45 +00:00
|
|
|
def booking_days(self):
|
|
|
|
return (self.booking.end_date - self.booking.start_date).days + 1
|
|
|
|
|
2016-08-31 02:32:45 +00:00
|
|
|
|
2016-04-04 01:39:57 +00:00
|
|
|
class Supporter(models.Model):
|
|
|
|
name = models.CharField(max_length=200)
|
|
|
|
description = models.TextField(null=True, blank=True)
|
2016-04-10 21:12:43 +00:00
|
|
|
|
2016-04-04 01:39:57 +00:00
|
|
|
def __str__(self):
|
|
|
|
return "%s" % (self.name)
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('dgSupporters_view', args=[self.pk])
|
2016-03-25 18:18:07 +00:00
|
|
|
|
2016-04-01 10:37:01 +00:00
|
|
|
|
|
|
|
class DGGallery(models.Model):
|
|
|
|
parent = models.ForeignKey('self', blank=True, null=True)
|
|
|
|
name = models.CharField(max_length=30)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return "%s" % (self.name)
|
|
|
|
|
|
|
|
def get_absolute_url(self):
|
|
|
|
return reverse('dgGallery_view', args=[self.pk])
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
verbose_name_plural = 'dgGallery'
|
2016-03-25 18:18:07 +00:00
|
|
|
#
|
2016-04-01 10:37:01 +00:00
|
|
|
class DGPicture(models.Model):
|
|
|
|
gallery = models.ForeignKey(DGGallery)
|
|
|
|
image = FilerImageField(related_name='dg_gallery')
|
|
|
|
description = models.CharField(max_length=60)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return "%s" % (self.image.name)
|
|
|
|
|
|
|
|
class DGGalleryPlugin(CMSPlugin):
|
|
|
|
dgGallery = models.ForeignKey(DGGallery)
|
|
|
|
|
|
|
|
class DGSupportersPlugin(CMSPlugin):
|
|
|
|
pass
|