Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/243 calculate sponsored percentage #255

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,8 @@ 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 +284,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 Down
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
28 changes: 24 additions & 4 deletions canopeum_backend/canopeum_backend/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import re
from datetime import UTC, datetime, timedelta
from functools import reduce
from typing import TYPE_CHECKING, Any, ClassVar, TypeVar, override

import googlemaps
Expand Down Expand Up @@ -156,6 +157,22 @@ 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):
site_species = Sitetreespecies.objects.filter(site=self)
return reduce(lambda x, y: x + y.quantity, site_species, 0)
NicolasDontigny marked this conversation as resolved.
Show resolved Hide resolved

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

batches = Batch.objects.filter(site=self)
sponsored_plant_count = reduce(lambda x, y: x + y.plant_count(), batches, 0)
NicolasDontigny marked this conversation as resolved.
Show resolved Hide resolved
if sponsored_plant_count >= total_plant_count:
return 100

return sponsored_plant_count / total_plant_count * 100

@override
def delete(self, using=None, keep_parents=False):
# Coordinate
Expand Down Expand Up @@ -191,7 +208,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 +234,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):
Samuel-Therrien-Beslogic marked this conversation as resolved.
Show resolved Hide resolved
batch_species = BatchSpecies.objects.filter(batch=self)
return reduce(lambda x, y: x + y.quantity, batch_species, 0)
NicolasDontigny marked this conversation as resolved.
Show resolved Hide resolved


class FertilizertypeInternationalization(models.Model):
en = models.TextField(db_column="EN", blank=True, null=True)
Expand Down Expand Up @@ -362,9 +382,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 @@ -109,7 +109,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 @@ -21,8 +21,8 @@
if (siteSummaries.length === 0) return options

// total-functions/no-partial-division -- length checked above
options.average = siteSummaries.reduce(

Check warning on line 24 in canopeum_frontend/src/components/analytics/SiteSuccessRatesChart.tsx

View workflow job for this annotation

GitHub Actions / Lint

Division is partial. You should wrap it in a wrapper that returns undefined when the denominator is zero
(accumulator, current) => accumulator + current.progress,
(accumulator, current) => accumulator + current.sponsorProgress,
0,
) / siteSummaries.length

Expand All @@ -34,10 +34,10 @@
// 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 All @@ -60,7 +60,7 @@
const renderChartTooltip = (props: ChartsAxisContentProps) => {
const selectedSerie = props.series.find(serie => serie.id === props.axisValue)
// total-functions/no-unsafe-type-assertion -- value type is known from the context
const data = selectedSerie?.data.find(value => !!value) as number | undefined

Check warning on line 63 in canopeum_frontend/src/components/analytics/SiteSuccessRatesChart.tsx

View workflow job for this annotation

GitHub Actions / Lint

This type assertion is not type-safe

return (
<div className='p-2'>
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
Loading