Skip to content

Commit

Permalink
Feature/243 calculate sponsored percentage (#255)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Nicolas Dontigny <[email protected]>
Co-authored-by: Samuel T. <[email protected]>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
4 people authored and Andrew-Beslogic committed Oct 10, 2024
1 parent e98e973 commit dec91d9
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# flake8: noqa: S311 -- Accept random int generation for database seeding

import random
from collections.abc import Iterable
from datetime import timedelta
from pathlib import Path

Expand Down Expand Up @@ -29,6 +30,7 @@
Role,
Site,
Siteadmin,
Sitetreespecies,
Sitetype,
SitetypeInternationalization,
TreespeciestypeInternationalization,
Expand Down Expand Up @@ -269,12 +271,32 @@ def create_sponsor_for_batch():
)


def create_species_for_site(site: Site, batches: Iterable[Batch]):
already_added_tree_type: dict[int, Sitetreespecies] = {}
for batch in batches:
for batch_specie in BatchSpecies.objects.filter(batch=batch):
quantity = batch_specie.quantity
# Add more to the site's quantity than the batches' quantity
# so they don't appear at 100%. Except Canopeum, let's use it as a 100% example
if site.name != "Canopeum":
quantity += random.randint(0, 50)
if batch_specie.tree_type.pk in already_added_tree_type:
site_tree_specie = already_added_tree_type[batch_specie.tree_type.pk]
site_tree_specie.quantity += quantity
site_tree_specie.save()
else:
site_tree_specie = Sitetreespecies.objects.create(
site=site, tree_type=batch_specie.tree_type, quantity=quantity
)
already_added_tree_type[batch_specie.tree_type.pk] = site_tree_specie


def create_batches_for_site(site):
num_batches = random.randint(3, 8)
for i in range(num_batches):
number_of_seed = random.randint(50, 200)
plant_count = random.randint(0, number_of_seed)
survived_count = random.randint(0, plant_count)
survived_count = random.randint(100, 200)
replace_count = random.randint(0, 50)

sponsor = create_sponsor_for_batch()

Expand All @@ -284,9 +306,8 @@ def create_batches_for_site(site):
size=random.randint(20, 150),
sponsor=sponsor,
soil_condition="Good",
plant_count=plant_count,
survived_count=survived_count,
replace_count=plant_count - survived_count,
replace_count=replace_count,
total_number_seed=number_of_seed,
total_propagation=random.randint(0, number_of_seed),
)
Expand All @@ -297,6 +318,7 @@ def create_batches_for_site(site):
batch=batch,
fertilizer_type=fertilizer_type,
)
yield batch


class Command(BaseCommand):
Expand Down Expand Up @@ -352,8 +374,7 @@ def handle(self, *args, **kwargs):
self.create_roles()
self.create_users()

self.create_canopeum_site()
self.create_other_sites()
self.create_sites()

self.create_siteadmins()
self.stdout.write(self.style.SUCCESS("Data Generated"))
Expand Down Expand Up @@ -479,8 +500,9 @@ def create_users(self):
role=Role.objects.get(name="User"),
)

def create_canopeum_site(self):
site = Site.objects.create(
def create_sites(self):
# Canopeum's site
site1 = Site.objects.create(
name="Canopeum",
is_public=True,
site_type=Sitetype.objects.get(
Expand Down Expand Up @@ -511,15 +533,16 @@ def create_canopeum_site(self):
link="https://www.canopeum-pos.com",
),
)
create_batches_for_site(site)
batches = create_batches_for_site(site1)
create_species_for_site(site1, batches)
post = Post.objects.create(
site=site,
site=site1,
body="The season is officially started; "
+ "new plants are starting to grow and our volunteers are very dedicated!",
share_count=5,
)
post.media.add(*Asset.objects.filter(asset__contains="canopeum_post_img"))
create_posts_for_site(site)
create_posts_for_site(site1)
Comment.objects.create(
body="Wow, I'm very excited to join the team!",
user=User.objects.get(email="[email protected]"),
Expand All @@ -530,8 +553,8 @@ def create_canopeum_site(self):
user=User.objects.get(email="[email protected]"),
post=post,
)
# end of Canopeum's site

def create_other_sites(self):
site_2 = Site.objects.create(
name="Maple Grove Retreat",
is_public=True,
Expand Down Expand Up @@ -564,7 +587,8 @@ def create_other_sites(self):
link="https://www.maplegroveretreat.com/events/maple-syrup-festival",
),
)
create_batches_for_site(site_2)
batches = create_batches_for_site(site_2)
create_species_for_site(site_2, batches)
create_posts_for_site(site_2)

site_3 = Site.objects.create(
Expand Down Expand Up @@ -600,7 +624,8 @@ def create_other_sites(self):
link="https://www.lakesideoasis.com/winter-getaway",
),
)
create_batches_for_site(site_3)
batches = create_batches_for_site(site_3)
create_species_for_site(site_3, batches)
create_posts_for_site(site_3)

site_4 = Site.objects.create(
Expand Down Expand Up @@ -636,7 +661,8 @@ def create_other_sites(self):
link="https://www.evergreentrail.com/guided-walks",
),
)
create_batches_for_site(site_4)
batches = create_batches_for_site(site_4)
create_species_for_site(site_4, batches)
create_posts_for_site(site_4)

def create_siteadmins(self):
Expand Down
9 changes: 4 additions & 5 deletions canopeum_backend/canopeum_backend/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.1 on 2024-09-26 20:15
# Generated by Django 5.1 on 2024-09-30 16:29

import canopeum_backend.models
import django.contrib.auth.models
Expand Down Expand Up @@ -232,7 +232,6 @@ class Migration(migrations.Migration):
('name', models.TextField(blank=True, null=True)),
('size', models.IntegerField(blank=True, null=True)),
('soil_condition', models.TextField(blank=True, null=True)),
('plant_count', models.IntegerField(blank=True, null=True)),
('survived_count', models.IntegerField(blank=True, null=True)),
('replace_count', models.IntegerField(blank=True, null=True)),
('total_number_seed', models.IntegerField(blank=True, null=True)),
Expand Down Expand Up @@ -316,9 +315,9 @@ class Migration(migrations.Migration):
name='Sitetreespecies',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', models.IntegerField(blank=True, null=True)),
('site', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='canopeum_backend.site')),
('tree_type', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='canopeum_backend.treetype')),
('quantity', models.IntegerField()),
('site', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='canopeum_backend.site')),
('tree_type', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='canopeum_backend.treetype')),
],
options={
'constraints': [models.UniqueConstraint(fields=('site', 'tree_type'), name='unique_tree_species_per_site')],
Expand Down
26 changes: 22 additions & 4 deletions canopeum_backend/canopeum_backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,21 @@ class Site(models.Model):
announcement = models.ForeignKey(Announcement, models.SET_NULL, blank=True, null=True)
image = models.ForeignKey(Asset, models.SET_NULL, blank=True, null=True)

def get_plant_count(self) -> int:
site_species = Sitetreespecies.objects.filter(site=self)
return sum(specie.quantity for specie in site_species)

def get_sponsor_progress(self) -> float:
total_plant_count = self.get_plant_count()
if total_plant_count == 0:
return 0

batches = Batch.objects.filter(site=self)
sponsored_plant_count = sum(batch.plant_count() for batch in batches)

# Note: We don't cap the progress at 100% so it's obvious if there's a data issue
return sponsored_plant_count / total_plant_count * 100

@override
def delete(self, using=None, keep_parents=False):
# Coordinate
Expand Down Expand Up @@ -191,7 +206,6 @@ class Batch(models.Model):
sponsor = models.ForeignKey(BatchSponsor, models.CASCADE)
size = models.IntegerField(blank=True, null=True)
soil_condition = models.TextField(blank=True, null=True)
plant_count = models.IntegerField(blank=True, null=True)
survived_count = models.IntegerField(blank=True, null=True)
replace_count = models.IntegerField(blank=True, null=True)
total_number_seed = models.IntegerField(blank=True, null=True)
Expand All @@ -218,6 +232,10 @@ def add_supported_specie_by_id(self, pk: int):
tree_type = Treetype.objects.get(pk=pk)
return BatchSupportedSpecies.objects.create(tree_type=tree_type, batch=self)

def plant_count(self) -> int:
batch_species = BatchSpecies.objects.filter(batch=self)
return sum(specie.quantity for specie in batch_species)


class FertilizertypeInternationalization(models.Model):
en = models.TextField(db_column="EN", blank=True, null=True)
Expand Down Expand Up @@ -362,9 +380,9 @@ class SiteFollower(models.Model):


class Sitetreespecies(models.Model):
site = models.ForeignKey(Site, models.CASCADE, blank=True, null=True)
tree_type = models.ForeignKey(Treetype, models.DO_NOTHING, blank=True, null=True)
quantity = models.IntegerField(blank=True, null=True)
site = models.ForeignKey(Site, models.CASCADE)
tree_type = models.ForeignKey(Treetype, models.DO_NOTHING)
quantity = models.IntegerField()

class Meta:
constraints = (
Expand Down
28 changes: 14 additions & 14 deletions canopeum_backend/canopeum_backend/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,9 +543,9 @@ class SiteSummarySerializer(serializers.ModelSerializer[Site]):
site_type = SiteTypeSerializer()
coordinate = CoordinatesSerializer()
plant_count = serializers.SerializerMethodField()
sponsor_progress = serializers.SerializerMethodField()
survived_count = serializers.SerializerMethodField()
propagation_count = serializers.SerializerMethodField()
progress = serializers.SerializerMethodField()
admins = SiteAdminSerializer(source="siteadmin_set", many=True)
batches = serializers.SerializerMethodField()

Expand All @@ -557,26 +557,26 @@ class Meta:
"coordinate",
"site_type",
"plant_count",
"sponsor_progress",
"survived_count",
"propagation_count",
"visitor_count",
"progress",
"admins",
"batches",
)

def get_plant_count(self, obj) -> int:
return random.randint(100, 200) # noqa: S311
def get_plant_count(self, obj: Site) -> int:
return obj.get_plant_count()

def get_sponsor_progress(self, obj: Site) -> float:
return obj.get_sponsor_progress()

def get_survived_count(self, obj) -> int:
return random.randint(50, 100) # noqa: S311

def get_propagation_count(self, obj) -> int:
return random.randint(5, 50) # noqa: S311

def get_progress(self, obj) -> float:
return random.randint(0, 10000) / 100 # noqa: S311

@extend_schema_field(BatchDetailSerializer(many=True))
def get_batches(self, obj):
batches = obj.batch_set.all().order_by("-updated_at")
Expand All @@ -587,9 +587,9 @@ class SiteSummaryDetailSerializer(serializers.ModelSerializer[Site]):
site_type = SiteTypeSerializer()
coordinate = CoordinatesSerializer()
plant_count = serializers.SerializerMethodField()
sponsor_progress = serializers.SerializerMethodField()
survived_count = serializers.SerializerMethodField()
propagation_count = serializers.SerializerMethodField()
progress = serializers.SerializerMethodField()
sponsors = serializers.SerializerMethodField()
admins = SiteAdminSerializer(source="siteadmin_set", many=True)
batches = serializers.SerializerMethodField()
Expand All @@ -603,28 +603,28 @@ class Meta:
"coordinate",
"site_type",
"plant_count",
"sponsor_progress",
"survived_count",
"propagation_count",
"visitor_count",
"sponsors",
"progress",
"admins",
"batches",
"weather",
)

def get_plant_count(self, obj) -> int:
return random.randint(100, 200) # noqa: S311
def get_plant_count(self, obj: Site) -> int:
return obj.get_plant_count()

def get_sponsor_progress(self, obj: Site) -> float:
return obj.get_sponsor_progress()

def get_survived_count(self, obj) -> int:
return random.randint(50, 100) # noqa: S311

def get_propagation_count(self, obj) -> int:
return random.randint(5, 50) # noqa: S311

def get_progress(self, obj) -> float:
return random.randint(0, 10000) / 100 # noqa: S311

@extend_schema_field(BatchSponsorSerializer(many=True))
def get_sponsors(self, obj):
batches = Batch.objects.filter(site=obj)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const AnalyticsSiteHeader = ({ siteSummary }: Props) => {
</div>

<div className='mt-1'>
<SiteSponsorProgress progress={siteSummary.progress} />
<SiteSponsorProgress progress={siteSummary.sponsorProgress} />
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const buildChartOptions = (siteSummaries: SiteSummary[]) => {

// total-functions/no-partial-division -- length checked above
options.average = siteSummaries.reduce(
(accumulator, current) => accumulator + current.progress,
(accumulator, current) => accumulator + current.sponsorProgress,
0,
) / siteSummaries.length

Expand All @@ -34,10 +34,10 @@ const buildChartOptions = (siteSummaries: SiteSummary[]) => {
// However, bars will appear really thin, so we use stacked bars to stack
// 0-height bars on top of each other.
const strackedSerie = Array.from<number>({ length: siteSummaries.length }).fill(0)
strackedSerie[siteIndex] = site.progress
strackedSerie[siteIndex] = site.sponsorProgress

options.colors.push(
site.progress > options.average
site.sponsorProgress > options.average
? 'var(--bs-primary)'
: 'var(--bs-secondary)',
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ const SiteSummaryCard = ({ site, admins, onSiteChange, onSiteEdit }: Props) => {
</div>

<div className='mt-4'>
<SiteSponsorProgress progress={site.progress} />
<SiteSponsorProgress progress={site.sponsorProgress} />
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit dec91d9

Please sign in to comment.