def get_queryset(self): active = Count("optionwheel", filter=Q(optionwheel__is_active=True)) completed = Count("optionwheel", filter=Q(optionwheel__is_active=False)) profit = Sum(F("optionwheel__total_profit") * F("optionwheel__quantity"), filter=Q(optionwheel__is_active=False), output_field=fields.DecimalField()) collateral = Sum(F("optionwheel__collatoral") * F("optionwheel__quantity"), filter=Q(optionwheel__is_active=False), output_field=fields.DecimalField()) total_wheels = Sum(F("optionwheel__quantity"), filter=Q(optionwheel__is_active=False)) total_days_active_weighted_by_collateral = Sum( F("optionwheel__total_days_active") * F("optionwheel__quantity") * F("optionwheel__collatoral"), filter=Q(optionwheel__is_active=False)) average_days = Cast(total_days_active_weighted_by_collateral, fields.FloatField()) / Cast( collateral, fields.FloatField()) annualized_rate_of_return = Power( 1 + profit / collateral, BUSINESS_DAYS_IN_YEAR / Coalesce(average_days, 252)) users = User.objects.annotate( active=active, completed=completed, profit=Round(100 * Coalesce(profit, 0)), collateral=Round(100 * Coalesce(collateral, 0)), return_percentage=Coalesce(profit / collateral, 0), total_wheels=Coalesce(total_wheels, 0), average_days=Coalesce(average_days, 0), annualized_rate_of_return=Coalesce(annualized_rate_of_return, 0), ) return users
class CartItem(models.Model): id = fields.AutoField( verbose_name=_('ID'), primary_key=True, ) cart = models.ForeignKey( Cart, related_name='items', on_delete=models.CASCADE, null=False, blank=False, ) product = models.ForeignKey( Product, related_name='items', on_delete=models.CASCADE, null=False, blank=False, ) term = fields.PositiveSmallIntegerField( verbose_name=_('Term'), null=False, blank=False, choices=Product.Payment_Terms, ) unit_price = fields.DecimalField( verbose_name=_('Unit Price'), max_digits=10, decimal_places=4, null=False, blank=False, ) quantity = fields.PositiveSmallIntegerField( verbose_name=_('Quantity'), null=False, blank=False, default=1, ) item_price = fields.DecimalField( verbose_name=_('Item Price'), max_digits=10, decimal_places=4, null=False, blank=False, ) records = models.Manager() class Meta: db_table = 'billing_cart_items' default_related_name = 'items' verbose_name = _('Cart Item') verbose_name_plural = _('Cart Items') def __unicode__(self): return str(self.id)
def profit(self): carts = self.prefetch_related('cart') profit = F('cart__price_ttc') - F('cart__price_ht') total_profit = Sum(profit * F('cart__quantity'), output_field=fields.DecimalField()) return carts.annotate(total_profit=total_profit).aggregate( Sum('total_profit'))
class Leg(models.Model): date = fields.DateField(default=now) name = fields.CharField(max_length=40, unique=True) slug = fields.SlugField(max_length=40, db_index=True, editable=False) start = fields.CharField(max_length=30) end = fields.CharField(max_length=30) description = fields.TextField(max_length=320, blank=True) duration = fields.DecimalField(decimal_places=1, max_digits=2, default=1.0) distanceKM = fields.IntegerField() morning = fields.BooleanField(default=True) map = models.FileField(upload_to=get_map_path, blank=True) class Meta: unique_together = ('date', 'morning') def __str__(self): return "{} - {} {}: {}km from {} to {}".format( self.name, self.date, "am" if self.morning else "pm", self.distanceKM, self.start, self.end) @classmethod def Totals(cls): return cls.objects.aggregate(distance=Sum('distanceKM'), days=Count('date', distinct=True)) prepopulated_fields = {"slug": ("title", )}
def discounted_total_cart(self, cart_id): annotated_cart = self.cart_total(cart_id) total_discounted_with_coupon = F('true_price') / ( F('coupon__value') * (1 - F('coupon__value') / 100)) total_minus_coupon = F('true_price') - F('coupon__value') coupon_on_entire_order_percentage = Q(coupon__isnull=False) & Q( coupon__on_entire_order=True) & Q(coupon__value_type='percentage') coupon_on_entire_order_value = Q(coupon__isnull=False) & Q( coupon__on_entire_order=True) & Q( coupon__value_type='fixed amount') # coupon_on_collection_percentage = Q(coupon__isnull=False) & Q(coupon__collection=True) & Q(value_type='percentage') # coupon_on_collection_value = Q(coupon__isnull=False) & Q(coupon__collection=True) & Q(value_type='fixed amount') first_case = When(coupon_on_entire_order_percentage, then=total_discounted_with_coupon) second_case = When(coupon_on_entire_order_value, then=total_minus_coupon) # third_case = When(coupon_on_collection_percentage, then=total_discounted_with_coupon) # fourth_case = When(coupon_on_collection_value, then=total_minus_coupon) case = Case(first_case, second_case, default=0, output_field=fields.DecimalField()) return annotated_cart.annotate(reduced_price=case)
class DebtLoan(models.Model): DEBT = 0 LOAN = 1 CATEGORY_CHOICES = ( (DEBT, 'debt'), (LOAN, 'loan'), ) with_who = fields.CharField(max_length=255) title = fields.CharField(max_length=255, null=True, blank=True) amount = fields.DecimalField(max_digits=10, decimal_places=2) category = fields.PositiveSmallIntegerField(choices=CATEGORY_CHOICES) created = fields.DateTimeField(default=timezone.now, editable=False) modified = fields.DateTimeField(default=timezone.now) active = fields.BooleanField(default=True) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): if self.title: return "{}: {}".format(self.with_who, self.title) else: return "{}".format(self.with_who) def deactivate(self): if self.active: self.active = False self.save()
class Fp17Exemptions(models.EpisodeSubrecord): _is_singleton = True _title = "Exemptions and Remissions" patient_under_18 = fields.BooleanField(default=False) full_remission_hc2_cert = fields.BooleanField(default=False) partial_remission_hc3_cert = fields.BooleanField(default=False) expectant_mother = fields.BooleanField(default=False) nursing_mother = fields.BooleanField(default=False) aged_18_in_full_time_education = fields.BooleanField(default=False) income_support = fields.BooleanField(default=False) nhs_tax_credit_exemption = fields.BooleanField(default=False) income_based_jobseekers_allowance = fields.BooleanField(default=False) pension_credit_guarantee_credit = fields.BooleanField(default=False) prisoner = fields.BooleanField(default=False) universal_credit = fields.BooleanField(default=False) evidence_of_exception_or_remission_seen = fields.BooleanField( default=False) income_related_employment_and_support_allowance = fields.BooleanField( default=False) # logically I'd like to split this into its own PatientRemittance model # to keep all the Exemptions cleanly together in their own Model. patient_charge_collected = fields.DecimalField(decimal_places=2, max_digits=5, blank=True, null=True)
class Currency(models.Model): id = fields.AutoField( verbose_name=_('ID'), primary_key=True, ) iso_code = fields.CharField( verbose_name=_('ISO Code'), max_length=3, null=False, blank=False, unique=True, ) title = fields.CharField( verbose_name=_('Title'), max_length=255, null=False, blank=False, ) prefix = fields.CharField( verbose_name=_('Prefix'), max_length=255, null=False, blank=True, ) suffix = fields.CharField( verbose_name=_('Suffix'), max_length=255, null=False, blank=True, ) rate = fields.DecimalField( verbose_name=_('Conversion Rate'), max_digits=10, decimal_places=4, null=False, blank=False, default=1, ) is_active = fields.BooleanField( verbose_name=_('Is Active'), null=False, blank=False, default=True, db_index=True, ) records = models.Manager() class Meta: db_table = 'billing_currency' default_related_name = 'currencies' verbose_name = _('Currency') verbose_name_plural = _('Currencies') def __unicode__(self): return '%(id)d: %(title)s (%(iso_code)s)' % { 'id': self.id, 'iso_code': self.iso_code, 'title': self.title, }
class Cart(models.Model): id = fields.AutoField( verbose_name=_('ID'), primary_key=True, ) user = models.ForeignKey( User, related_name='carts', null=False, blank=False, ) currency = models.ForeignKey( Currency, related_name='carts', null=False, blank=False, ) product = models.ManyToManyField( Product, through='CartItem', through_fields=('cart', 'product'), ) total_amount = fields.DecimalField( verbose_name=_('Total Amount'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) create_date = models.DateTimeField( verbose_name=_('Create Date'), null=False, blank=False, auto_now_add=True, ) update_date = models.DateTimeField( verbose_name=_('Update Date'), null=True, blank=True, auto_now=True, ) records = models.Manager() class Meta: db_table = 'billing_cart' default_related_name = 'carts' verbose_name = _('Cart') verbose_name_plural = _('Carts') def __unicode__(self): return str(self.id)
class Registration(Model): camp = ForeignKey(Camp, on_delete=CASCADE) clan = ForeignKey(Clan, on_delete=PROTECT) telephone = fields.CharField(max_length=100) contact_name = fields.CharField(max_length=100) email = fields.EmailField(max_length=100) comment = fields.TextField(max_length=1000, null=True, blank=True) paid = fields.DecimalField(decimal_places=2, max_digits=6, default=0) rules_accepted = fields.BooleanField(default=False, validators=[validate_true]) present_participants = fields.PositiveIntegerField(null=True) def get_price(self): price = 0 for info in self.ticketinfo_set.all(): price += info.quantity * info.fee.price return price def get_quantity(self): quantity = 0 for info in self.ticketinfo_set.all(): quantity += info.quantity return quantity def get_quantities(self): quantities = list() for fee in self.camp.fee_set.all().order_by('pk'): value = 0 for info in self.ticketinfo_set.all(): if info.fee == fee: value = info.quantity quantities.append(value) return quantities def get_ticket_count(self): tickets = list() for info in self.ticketinfo_set.all(): tickets.extend(info.ticket_set.all()) return len(tickets) def get_registrated_participant_count(self): count = 0 for info in self.ticketinfo_set.all(): for ticket in info.ticket_set.all(): if ticket.registrated: count += 1 return count def __str__(self): return "Registration from {}".format(self.clan.name)
class Fp17NHSBSAFields(models.EpisodeSubrecord): _is_singleton = True Fp17_NHSBSA_field_1 = fields.CharField(max_length=255, blank=True, null=True) Fp17_NHSBSA_field_2 = fields.CharField(max_length=255, blank=True, null=True) Fp17_NHSBSA_field_3 = fields.CharField(max_length=255, blank=True, null=True) Fp17_NHSBSA_field_4 = fields.DecimalField(decimal_places=2, max_digits=5, blank=True, null=True)
def cart_total(self, cart_id): """Total of a customer's cart""" cart = self.my_cart(cart_id) # Since we have two different prices (price_ht, discounted_price), # determine which price to use when computing the total discounted_price_times_quantity = F('product__discounted_price') * F( 'quantity') price_ht_times_quantity = F('product__price_ht') * F('quantity') product_marked_as_discounted = Q(product__discounted_price__gt=0) & Q( product__discounted=True) first_case = When(product_marked_as_discounted, then=discounted_price_times_quantity) case = Case(first_case, default=price_ht_times_quantity, output_field=fields.DecimalField()) true_price_queryset = cart.annotate(true_price=case) return true_price_queryset.aggregate(cart_total=Sum('true_price'))
class Fp17Exemptions(models.EpisodeSubrecord): _is_singleton = True patient_under_18 = fields.BooleanField(default=False, verbose_name="Patient under 18") full_remission_hc2_cert = fields.BooleanField( default=False, verbose_name="Full remission - HC2 cert.") partial_remission_hc3_cert = fields.BooleanField( default=False, verbose_name="Partial remission - HC3 cert.") expectant_mother = fields.BooleanField(default=False, verbose_name="Expectant mother") nursing_mother = fields.BooleanField(default=False, verbose_name="Nursing mother") aged_18_in_full_time_education = fields.BooleanField( default=False, verbose_name="Aged 18 in full time education") income_support = fields.BooleanField(default=False, verbose_name="Income support") nhs_tax_credit_exemption = fields.BooleanField( default=False, verbose_name="NHS tax credit exemption") income_based_jobseekers_allowance = fields.BooleanField( default=False, verbose_name="Income based jobseekers allowance") pension_credit_guarantee_credit = fields.BooleanField( default=False, verbose_name="Pension credit guarantee credit") prisoner = fields.BooleanField(default=False) universal_credit = fields.BooleanField(default=False, verbose_name="Universal credit") income_related_employment_and_support_allowance = fields.BooleanField( default=False, verbose_name="Income related employment and support allowance") evidence_of_exception_or_remission_seen = fields.BooleanField( default=False, verbose_name="Evidence of exception or remission seen") patient_charge_collected = fields.DecimalField( decimal_places=2, max_digits=5, blank=True, null=True, verbose_name="Patient charge collected") class Meta: verbose_name = "Exemptions and remissions"
def cart_total_discount_entire_order(self, cart_id): """ This calculates the total price of a cart based on whether the cart has coupon and that it is applicable on the entire order """ queryset = self.cart_products(cart_id) total_discounted_with_coupon = F('true_price') / (F('coupon__value') * (1 - F('coupon__value') / 100)) total_minus_coupon = F('true_price') - F('coupon__value') coupon_is_for_entire_order = Q(coupon__isnull=False) & Q(coupon__on_entire_order=True) coupon_on_entire_order_percentage = coupon_is_for_entire_order & Q(coupon__value_type='percentage') coupon_on_entire_order_value = coupon_is_for_entire_order & Q(coupon__value_type='fixed amount') first_case = When(coupon_on_entire_order_percentage, then=total_discounted_with_coupon) second_case = When(coupon_on_entire_order_value, then=total_minus_coupon) case = Case(first_case, second_case, default='true_price', output_field=fields.DecimalField()) return queryset.annotate(reduced_price=case)
class Transaction(models.Model): EXPENSE = 'exp' INCOME = 'inc' CATEGORY_CHOICES = ( (EXPENSE, 'expense'), (INCOME, 'income'), ) title = fields.CharField(max_length=255) amount = fields.DecimalField(max_digits=10, decimal_places=2) category = fields.CharField(max_length=3, choices=CATEGORY_CHOICES) created = fields.DateTimeField(default=timezone.now, editable=False) modified = fields.DateTimeField(default=timezone.now) active = fields.BooleanField(default=True) user = models.ForeignKey(User, on_delete=models.CASCADE) def __str__(self): return "{}".format(self.title) def deactivate(self): if self.active: self.active = False self.save()
def _resolve_output_field(self): if isinstance(self.value, str): return fields.CharField() if isinstance(self.value, bool): return fields.BooleanField() if isinstance(self.value, int): return fields.IntegerField() if isinstance(self.value, float): return fields.FloatField() if isinstance(self.value, datetime.datetime): return fields.DateTimeField() if isinstance(self.value, datetime.date): return fields.DateField() if isinstance(self.value, datetime.time): return fields.TimeField() if isinstance(self.value, datetime.timedelta): return fields.DurationField() if isinstance(self.value, Decimal): return fields.DecimalField() if isinstance(self.value, bytes): return fields.BinaryField() if isinstance(self.value, UUID): return fields.UUIDField()
def cart_total(self, cart_id): """Total of a customer's cart""" cart = self.my_cart(cart_id) # Since we have two different prices (price_ht, discounted_price), # determine which price to use when computing the total discounted_price_times_quantity = F('product__discounted_price') * F( 'quantity') price_ht_times_quantity = F('product__price_ht') * F('quantity') # In the specific case where a coupon is applied, we need # to multiply that price to the quantity # coupon_price_times_quantity = F('discounted_price') * F('quantity') # user_applies_coupon = Q(discounted_price > 0) & Q(coupon__isnull=False) # second_case = When(user_applies_coupon, then=coupon_price_times_quantity) product_marked_as_discounted = Q(product__discounted_price__gt=0) & Q( product__discounted=True) first_case = When(product_marked_as_discounted, then=discounted_price_times_quantity) case = Case(first_case, default=price_ht_times_quantity, output_field=fields.DecimalField()) true_price_queryset = cart.annotate(true_price=case) return true_price_queryset.aggregate(cart_total=Sum('true_price'))
class Request(SafeDeleteModel): class Meta: app_label = "crisis" db_table = "crisis_request" _safedelete_policy = SOFT_DELETE_CASCADE TYPE_OF_REQUEST = [("G", "Grocery"), ("M", "Medicine"), ("O", "Other")] STATUS_PENDING = "P" STATUS_TRANSIT = "T" STATUS_FINISHED = "F" STATUS_CANCELLED = "C" UNFINISHED_STATUSES = [STATUS_PENDING, STATUS_TRANSIT] FINISHED_STATUSES = [STATUS_FINISHED, STATUS_CANCELLED] TYPE_OF_REQUEST_STATUSES = [ (STATUS_PENDING, "Pending"), (STATUS_TRANSIT, "Transit"), (STATUS_FINISHED, "Finished"), (STATUS_CANCELLED, "Cancelled"), ] owner = models.ForeignKey( "management.Participant", related_name="created_request", on_delete=models.CASCADE, ) assignee = models.ForeignKey( "management.Participant", related_name="assigned_request", null=True, blank=True, on_delete=models.DO_NOTHING, ) status = fields.CharField(choices=TYPE_OF_REQUEST_STATUSES, max_length=2) created_at = fields.DateTimeField(auto_now_add=True) modified_at = fields.DateTimeField(auto_now=True) type = models.CharField(choices=TYPE_OF_REQUEST, max_length=2, default="O") deadline = models.DateTimeField(null=True) description = models.TextField() bounty_amount_offered_to_volunteer = fields.DecimalField(max_digits=6, decimal_places=2, default=0.0) @property def related_request_assignment(self): return RequestAssignment.objects.get(assignee=self.assignee, request=self) def clean(self): if self.status in ["T"] and not self.assignee: raise ValidationError( "Assignee missing while changing status to assigned.") def __str__(self): return (f"{self.id}-{self.owner.user.first_name}" f"-{self.get_type_display()}-deadline-{self.deadline}") def assign_user(self, assignee_participant): self.status = self.STATUS_TRANSIT self.assignee = assignee_participant request_assignment = RequestAssignment.objects.create( status=RequestAssignment.STATUS_ASSIGNED, request=self, assignee=assignee_participant, ) # Notify the original dude here ? self.save() self.refresh_from_db() self.notify_request_owner_about_assignment( request_assignment=request_assignment) def notify_request_owner_about_assignment(self, request_assignment): """ I can send the whole request object to the template and fill up things there. Easy. :return: """ return EmailPusher.send_email_to_af_user_on_assignment_by_hl( request=self, request_assignment=request_assignment) def notify_request_owner_about_assignment_drop(self): # @TODO pass def notify_request_owner_about_assignment_finish(self): # @TODO pass def resolve_request_from_assignee(self, status=STATUS_FINISHED): """ Called when an asignee updates the status of a request. Depending on the status, we have to update the related RequestAssignment model too. :param status: :return: """ related_assignment = self.related_request_assignment if status == self.STATUS_FINISHED: related_assignment.status = RequestAssignment.STATUS_COMPLETED related_assignment.did_complete = True related_assignment.save() return def drop_request_from_assignee(self): related_assignment = self.related_request_assignment if self.status == Request.STATUS_FINISHED: raise Exception("Cannot update this request at this point. Sorry.") related_assignment.status = RequestAssignment.STATUS_DROPPED related_assignment.save() self.status = self.STATUS_PENDING self.save() self.notify_request_owner_about_assignment_drop() return
class ProductPricing(models.Model): id = fields.AutoField( verbose_name=_('ID'), primary_key=True, ) product = models.ForeignKey( Product, related_name='pricing', null=False, blank=False, ) currency = models.ForeignKey( Currency, related_name='pricing', null=False, blank=False, ) onetime_setup_fee = fields.DecimalField( verbose_name=_('One Time (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) onetime = fields.DecimalField( verbose_name=_('One Time'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) onetime_cost = fields.DecimalField( verbose_name=_('One Time (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) hourly_setup_fee = fields.DecimalField( verbose_name=_('Hourly (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) hourly = fields.DecimalField( verbose_name=_('Hourly'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) hourly_cost = fields.DecimalField( verbose_name=_('Hourly (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) daily_setup_fee = fields.DecimalField( verbose_name=_('Daily (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) daily = fields.DecimalField( verbose_name=_('Daily'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) daily_cost = fields.DecimalField( verbose_name=_('Daily (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) weekly_setup_fee = fields.DecimalField( verbose_name=_('Weekly (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) weekly = fields.DecimalField( verbose_name=_('Weekly'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) weekly_cost = fields.DecimalField( verbose_name=_('Weekly (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) monthly_setup_fee = fields.DecimalField( verbose_name=_('Monthly (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) monthly = fields.DecimalField( verbose_name=_('Monthly'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) monthly_cost = fields.DecimalField( verbose_name=_('Monthly (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) quarterly_setup_fee = fields.DecimalField( verbose_name=_('Quarterly (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) quarterly = fields.DecimalField( verbose_name=_('Quarterly'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) quarterly_cost = fields.DecimalField( verbose_name=_('Quarterly (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) semi_annually_setup_fee = fields.DecimalField( verbose_name=_('Semi-Annually (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) semi_annually = fields.DecimalField( verbose_name=_('Semi-Annually'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) semi_annually_cost = fields.DecimalField( verbose_name=_('Semi-Annually (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) annually_setup_fee = fields.DecimalField( verbose_name=_('Annually (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) annually = fields.DecimalField( verbose_name=_('Annually'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) annually_cost = fields.DecimalField( verbose_name=_('Annually (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) biennially_setup_fee = fields.DecimalField( verbose_name=_('Biennially (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) biennially = fields.DecimalField( verbose_name=_('Biennially'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) biennially_cost = fields.DecimalField( verbose_name=_('Biennially (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) triennially_setup_fee = fields.DecimalField( verbose_name=_('Triennially (Setup Fee)'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) triennially = fields.DecimalField( verbose_name=_('Triennially'), max_digits=10, decimal_places=4, null=False, blank=True, default=-1, ) triennially_cost = fields.DecimalField( verbose_name=_('Triennially (Cost)'), max_digits=10, decimal_places=4, null=False, blank=True, default=0, ) records = models.Manager() class Meta: db_table = 'billing_product_pricing' default_related_name = 'pricing' unique_together = (('product', 'currency')) verbose_name = _('Product Pricing') verbose_name_plural = _('Product Pricing')
class Cyclist(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, db_index=True) legs = models.ManyToManyField(Leg, related_name='cyclist', blank=True) targetAmount = fields.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), blank=False) currentPledgedAmount = fields.DecimalField(max_digits=7, decimal_places=2, default=Decimal(0), blank=False) fundraising_site = fields.URLField(default='', blank=True) statement = fields.TextField(max_length=1200, default="", blank=True) picture = models.ImageField( upload_to=get_portrait_path, blank=True, storage=HashedURLStorage()) # Use custom FileStorageSystem as above def get_absolute_url(self): """Return the absolute URL - always the FundMe page""" return reverse('FundMe', kwargs={'username': self.user.username}) def __repr__(self): """A nice representation of this cyclist""" return "Cyclist(username={})".format(self.user.username) def __str__(self): return "Cyclist : {}".format(self.user.username) def get_full_name(self): """The full name of the cyclist - derived from the User attribute""" return self.user.get_full_name() def total_distance(self): """ Total Distance in km which this cyclist has signed up for""" return "{:.1f}".format(sum(l.distanceKM for l in self.legs.all())) def total_days(self): """ Return the number of days that this cyclist is involved in""" return self.legs.all().aggregate( day_count=Count('date', distinct=True))['day_count'] def percentage_funding(self): """Return as a formatted string the % funding - current vs target""" if not (self.currentPledgedAmount and self.targetAmount): return 0 if self.targetAmount == 0: return 0 return "{:.0f}".format(100.0 * int(self.currentPledgedAmount) / int(self.targetAmount)) def fundraising_domain(self): """Return as a domain name of the users fundraising site""" parsed_uri = urlparse(self.fundraising_site) return parsed_uri.netloc @classmethod def total_funds(cls): """Calculate the funds across all cyclists""" return cls.objects.aggregate(pledges=Sum('currentPledgedAmount'), target=Sum('targetAmount'))