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

[RELEASE] Gregarious Gopherwood #201

Merged
merged 86 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
7fc861d
[TM-877] Checkpoint commit; the bulk of the real work here is the mig…
roguenet Apr 23, 2024
bf3103d
[TM-877] A couple of tweaks based on feedback from CI/PPC.
roguenet Apr 25, 2024
2b2880e
[TM-877] Workdays migration ready.
roguenet Apr 25, 2024
d6b2514
Merge pull request #163 from wri/feat/TM-877-workday-db-structure
roguenet Apr 26, 2024
9b5938a
[TM-799] Convert bounds validation to a laravel validator.
roguenet Apr 29, 2024
5389f0d
[TM-799] Start up a controller for GH polygon upload.
roguenet Apr 29, 2024
773a4c6
[TM-799] Offload creation of geojson and criteria models to a service.
roguenet Apr 30, 2024
4643553
[TM-799] Convert validations that don't require site context to larav…
roguenet May 1, 2024
cf9e542
[TM-799] Convert within country to a laravel validator.
roguenet May 1, 2024
35e17cf
[TM-799] Convert overlapping polygon validation to a validator.
roguenet May 1, 2024
e87e9f5
[TM-799] Convert valid estimated area to a validator.
roguenet May 2, 2024
766d791
[TM-799] Improve error message handling for polygon validation.
roguenet May 2, 2024
e51bd85
[TM-799] Move validation to the controller.
roguenet May 2, 2024
9e2bbac
Merge remote-tracking branch 'refs/remotes/origin/staging' into epic/…
roguenet May 2, 2024
0c5edc8
Merge pull request #180 from wri/main
roguenet May 2, 2024
8089276
Merge remote-tracking branch 'refs/remotes/origin/staging' into epic/…
roguenet May 2, 2024
25efaa2
[TM-878] Drive-by fix: use the builder pattern for nothing to report …
roguenet May 3, 2024
2df3db2
[TM-878] Use the interface middleware for workdays and tree species.
roguenet May 3, 2024
fe2a2a8
[TM-878] Remove pagination from the workdays endpoint.
roguenet May 3, 2024
2eb36ce
[TM-878] Update workday API shape to use demographics.
roguenet May 3, 2024
65c87c1
[TM-878] Handle syncing workday demographics.
roguenet May 3, 2024
86d3029
[TM-880] Update the workdays get endpoint to include demographics.
roguenet May 5, 2024
eb87b20
[TM-880] Fixes workday sync to DB from form data.
roguenet May 6, 2024
b742b42
[TM-878] Unit tests for the get workdays endpoint.
roguenet May 7, 2024
1791d49
[TM-878] Unit tests syncing workday demographics.
roguenet May 7, 2024
69f91f7
Merge remote-tracking branch 'refs/remotes/origin/staging' into feat/…
roguenet May 7, 2024
ecc2cab
[TM-799] Fix geo json attribute getters.
roguenet May 8, 2024
e1a9794
Merge pull request #186 from wri/feat/TM-878-workdays-ui
roguenet May 8, 2024
a25a558
[TM-799] Set up tests for all validators that don't require site/proj…
roguenet May 8, 2024
89a7988
[TM-799] Create a table migration and seeder for would countries gene…
roguenet May 9, 2024
a1ade92
[TM-799] Test the within country validation.
roguenet May 9, 2024
0171a34
[TM-799] Test the not overlapping validation. Not yet passing; probab…
roguenet May 10, 2024
0eb4f6e
[TM-799] Test estimated area validation.
roguenet May 10, 2024
5f7bec2
[TM-799] Move polygon validator test sample data to a separate file.
roguenet May 10, 2024
f6a7476
[TM-799] Sketch out the bulk polygon post endpoint.
roguenet May 10, 2024
6a05638
[TM-799] All current validator tests now passing.
roguenet May 10, 2024
4bcc73f
[TM-799] Remove some more references to project_id on site polygon.
roguenet May 10, 2024
cbf28dd
[TM-799] Rename endpoint to sites/{id}/geometry to make it a little m…
roguenet May 10, 2024
e2ea75b
[TM-799] Test the geometry type validation.
roguenet May 10, 2024
5a26382
[TM-799] Finished polygon post endpoint.
roguenet May 10, 2024
2f765ed
[TM-799] Fix use path for polygon validators.
roguenet May 10, 2024
d3c1f58
[TM-800] GH polygon validation endpoint implemented.
roguenet May 10, 2024
7eed6b5
[TM-801] Implement created_by field on site_polygon and polygon_geome…
roguenet May 10, 2024
ca0008a
[TM-801] Implement bulk delete of polygons for GH.
roguenet May 10, 2024
4ae8b2e
[TM-801] Implement polygon update endpoint for GH
roguenet May 10, 2024
8799c87
Merge pull request #191 from wri/feat/TM-799-polygon-post-endpoint
roguenet May 13, 2024
57e9e02
Merge pull request #193 from wri/feat/TM-800-polygon-validation-endpoint
roguenet May 13, 2024
7763918
Merge pull request #194 from wri/feat/TM-801-gh-polygon-delete-endpoint
roguenet May 13, 2024
f6dd4ec
Merge pull request #195 from wri/feat/TM-802-gh-polygon-update-endpoint
roguenet May 13, 2024
db3dacb
Merge remote-tracking branch 'refs/remotes/origin/staging' into epic/…
roguenet May 13, 2024
3b7948e
[TM-838] Regenerate docs post merge
roguenet May 13, 2024
6e45220
Get tests and linter passing on staging again
roguenet May 13, 2024
9f98404
Merge branch 'refs/heads/staging' into epic/TM-838-workdays
roguenet May 13, 2024
b62dfc4
[TM-913] Add and sync a description text field to workday
roguenet May 13, 2024
fdbeda9
[TM-913] Implement description on workdays as a virtual property on S…
roguenet May 14, 2024
2669c86
[TM-913] Add the new virtual field to ProjectReport as well with a ne…
roguenet May 14, 2024
e1884cd
[TM-913] Lint fix
roguenet May 14, 2024
e104867
[TM-913] Fix tests
roguenet May 14, 2024
991afeb
[TM-904] Add HBF as a framework permission and admin type.
roguenet May 14, 2024
7026c6d
[TM-675] Rejigger the old_id / old_model columns on sites and projects.
roguenet May 15, 2024
adc6bd7
Merge pull request #196 from wri/feat/TM-913-store-description-on-wor…
roguenet May 15, 2024
cd6b3ec
Merge pull request #197 from wri/feat/TM-904-hbf-admin
roguenet May 15, 2024
9c65f0b
[TM-799] Corrected spelling error and verified existence of error att…
cesarLima1 May 15, 2024
1f9a717
Merge pull request #199 from wri/epic/TM-838-workdays
roguenet May 15, 2024
9fd3cb7
Merge pull request #200 from wri/fix/TM-799_handlePoligonValidationFu…
cesarLima1 May 15, 2024
e35146b
[TM-675] Use the ppc_external_id field.
roguenet May 15, 2024
8378f45
Merge remote-tracking branch 'refs/remotes/origin/release/gregarious-…
roguenet May 15, 2024
7974363
[TM-838] Avoid breaking when an old update request is merged.
roguenet May 15, 2024
aa95131
[TM-838] Include the ppc_external_id on project/site resources.
roguenet May 15, 2024
f733c5f
[TM-675] Fix up the migration after some testing with a fresh clone o…
roguenet May 15, 2024
eb7314e
Merge pull request #204 from wri/feat/TM-675-site-project-ids
roguenet May 16, 2024
164eae6
Merge pull request #202 from wri/epic/TM-838-avoid-breaking-on-old-up…
roguenet May 16, 2024
cc8768c
[TM-930] Don't attempt to create a permission that already exists.
roguenet May 16, 2024
391af10
[TM-931] Use the ppc_external_id for site id on site report export.
roguenet May 16, 2024
5be1880
[TM-931] A migration to copy over the old "other" workdays descriptio…
roguenet May 16, 2024
47a663c
[TM-931] Calculate workday total amounts rather than relying on the r…
roguenet May 16, 2024
0dd5fbc
[TM-931] Dry up totals calculation.
roguenet May 16, 2024
f5b7a67
[TM-931] Bring back the hasBeenSubmitted constraint
roguenet May 16, 2024
251b198
[TM-931] Include the new workdays format in entity exports.
roguenet May 16, 2024
c92c632
[TM-674] Allow searching by ppc external id in the admin sites index.
roguenet May 16, 2024
f126780
[TM-674] Allow searching by ppc external id in the project sites view.
roguenet May 17, 2024
f8eec1f
[TM-931] Lint fix
roguenet May 17, 2024
58365c8
Merge pull request #206 from wri/fix/TM-930-framework-creation
roguenet May 17, 2024
d488bf6
Merge pull request #208 from wri/feat/TM-674-site-ids-searchable
roguenet May 17, 2024
2e66264
[TM-931] Fix unit test that's covering the updated workdays_paid attr…
roguenet May 17, 2024
523c31e
Merge pull request #207 from wri/feat/TM-931-other-description-export
roguenet May 17, 2024
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
7 changes: 6 additions & 1 deletion app/Console/Commands/Migration/RolesMigrationCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function handle()

if (Role::where('name', 'admin-super')->count() === 0) {
$role = Role::create(['name' => 'admin-super']);
$role->givePermissionTo(['framework-terrafund', 'framework-ppc', 'framework-terrafund-enterprises', 'custom-forms-manage', 'users-manage', 'monitoring-manage', 'reports-manage']);
$role->givePermissionTo(['framework-terrafund', 'framework-ppc', 'framework-terrafund-enterprises', 'framework-hbf', 'custom-forms-manage', 'users-manage', 'monitoring-manage', 'reports-manage']);
}

if (Role::where('name', 'admin-ppc')->count() === 0) {
Expand All @@ -65,6 +65,11 @@ public function handle()
$role->givePermissionTo(['framework-terrafund', 'framework-terrafund-enterprises', 'custom-forms-manage', 'users-manage', 'monitoring-manage', 'reports-manage']);
}

if (Role::where('name', 'admin-hbf')->count() === 0) {
$role = Role::create(['name' => 'admin-hbf']);
$role->givePermissionTo(['framework-hbf', 'custom-forms-manage', 'users-manage', 'monitoring-manage', 'reports-manage']);
}

if (Role::where('name', 'project-developer')->count() === 0) {
$role = Role::create(['name' => 'project-developer']);
$role->givePermissionTo(['manage-own']);
Expand Down
138 changes: 138 additions & 0 deletions app/Console/Commands/OneOff/MigrateWorkdayData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<?php

namespace App\Console\Commands\OneOff;

use App\Models\V2\Workdays\Workday;
use App\Models\V2\Workdays\WorkdayDemographic;
use Illuminate\Console\Command;
use Illuminate\Support\Str;

class MigrateWorkdayData extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-off:migrate-workday-data';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Updates Workday data to use the new workday_demographics table';

private const DEMOGRAPHICS = [
WorkdayDemographic::GENDER,
WorkdayDemographic::AGE,
WorkdayDemographic::ETHNICITY,
];

private const SUBTYPE_NULL = 'subtype-null';
private const NAME_NULL = 'name-null';

/**
* Execute the console command.
*/
public function handle()
{
$entityTypes = Workday::select('workdayable_type')->distinct()->pluck('workdayable_type');
foreach ($entityTypes as $entityType) {
$entityIds = Workday::where('workdayable_type', $entityType)
->select('workdayable_id')
->distinct()
->pluck('workdayable_id');
$count = $entityIds->count();
$shortName = explode_pop('\\', $entityType);
echo "Processing $shortName: $count records\n";

foreach ($entityIds as $entityId) {
$this->updateEntityWorkdays($entityType, $entityId);
}
}
}

private function updateEntityWorkdays(string $entityType, int $entityId): void
{
$workdayCollections = Workday::where(['workdayable_type' => $entityType, 'workdayable_id' => $entityId])
->get()
->reduce(function (array $carry, Workday $workday) {
$carry[$workday['collection']][] = $workday;

return $carry;
}, []);

foreach ($workdayCollections as $collection => $workdays) {
$mapping = $this->mapWorkdayCollection($workdays);
$framework_key = $workdays[0]->framework_key;

$workday = Workday::create([
'workdayable_type' => $entityType,
'workdayable_id' => $entityId,
'framework_key' => $framework_key,
'collection' => $collection,
]);
foreach ($mapping as $demographic => $subTypes) {
foreach ($subTypes as $subType => $names) {
foreach ($names as $name => $amount) {
WorkdayDemographic::create([
'workday_id' => $workday->id,
'type' => $demographic,
'subtype' => $subType == self::SUBTYPE_NULL ? null : $subType,
'name' => $name == self::NAME_NULL ? null : $name,
'amount' => $amount,
]);
}
}
}

$workdayIds = collect($workdays)->map(fn ($workday) => $workday->id)->all();
Workday::whereIn('id', $workdayIds)->update(['migrated_to_demographics' => true]);
Workday::whereIn('id', $workdayIds)->delete();
}
}

private function mapWorkdayCollection(array $workdays): array
{
$demographics = [];
foreach (self::DEMOGRAPHICS as $demographic) {
foreach ($workdays as $workday) {
$subType = $this->getSubtype($demographic, $workday);
$name = match ($workday[$demographic]) {
null, 'gender-undefined', 'age-undefined', 'decline-to-specify' => 'unknown',
default => $workday[$demographic],
};
if ($subType == 'unknown' && strcasecmp($name, 'unknown') == 0) {
// We only get an unknown subtype when we're working on ethnicity. If the value is also unknown in
// this case, we want to leave it null.
$name = self::NAME_NULL;
}

$current = data_get($demographics, "$demographic.$subType.$name");
data_set($demographics, "$demographic.$subType.$name", $current + $workday->amount);
}
}

return $demographics;
}

private function getSubtype(string $demographic, Workday $workday): string
{
if ($demographic != WorkdayDemographic::ETHNICITY) {
return self::SUBTYPE_NULL;
}

if ($workday->indigeneity != null && $workday->indigeneity != 'decline to specify') {
return $workday->indigeneity;
}

if (Str::startsWith($workday->ethnicity, 'indigenous')) {
return 'indigenous';
} elseif (Str::startsWith($workday->ethnicity, 'other')) {
return 'other';
}

return 'unknown';
}
}
41 changes: 41 additions & 0 deletions app/Console/Commands/OneOff/MigrateWorkdayOtherDescription.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace App\Console\Commands\OneOff;

use App\Models\V2\Projects\ProjectReport;
use App\Models\V2\Sites\SiteReport;
use Illuminate\Console\Command;

class MigrateWorkdayOtherDescription extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-off:migrate-workday-other-description';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Moves workday other description data from the reports to the workdays';

/**
* Execute the console command.
*/
public function handle()
{
foreach ([SiteReport::class, ProjectReport::class] as $reportClass) {
$query = $reportClass::whereNot('paid_other_activity_description', null);
echo "Updating $reportClass, instance count: " . (clone $query)->count() . "\n";

foreach ($query->get() as $report) {
$report->update(['other_workdays_description' => $report->paid_other_activity_description]);
}
}

echo "Migration complete!\n";
}
}
93 changes: 93 additions & 0 deletions app/Console/Commands/ReportWorkdayDiscrepancies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php

namespace App\Console\Commands;

use App\Models\V2\Projects\ProjectReport;
use App\Models\V2\Sites\SiteReport;
use App\Models\V2\Workdays\Workday;
use Illuminate\Console\Command;

class ReportWorkdayDiscrepancies extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'report-workday-discrepancies';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Reports on project and site reports that have a difference between aggregated and disaggregated workday numbers';

private const PROPERTIES = [
ProjectReport::class => [
'paid' => [
Workday::COLLECTION_PROJECT_PAID_NURSERY_OPERATIONS,
Workday::COLLECTION_PROJECT_PAID_PROJECT_MANAGEMENT,
Workday::COLLECTION_PROJECT_PAID_OTHER,
],
'volunteer' => [
Workday::COLLECTION_PROJECT_VOLUNTEER_NURSERY_OPERATIONS,
Workday::COLLECTION_PROJECT_VOLUNTEER_PROJECT_MANAGEMENT,
Workday::COLLECTION_PROJECT_VOLUNTEER_OTHER,
],
],
SiteReport::class => [
'paid' => [
Workday::COLLECTION_SITE_PAID_SITE_ESTABLISHMENT,
Workday::COLLECTION_SITE_PAID_PLANTING,
Workday::COLLECTION_SITE_PAID_SITE_MAINTENANCE,
Workday::COLLECTION_SITE_PAID_SITE_MONITORING,
Workday::COLLECTION_SITE_PAID_OTHER,
],
'volunteer' => [
Workday::COLLECTION_SITE_VOLUNTEER_SITE_ESTABLISHMENT,
Workday::COLLECTION_SITE_VOLUNTEER_PLANTING,
Workday::COLLECTION_SITE_VOLUNTEER_SITE_MAINTENANCE,
Workday::COLLECTION_SITE_VOLUNTEER_SITE_MONITORING,
Workday::COLLECTION_SITE_VOLUNTEER_OTHER,
],
],
];

/**
* Execute the console command.
*/
public function handle()
{
echo "Model Type,Model UUID,Aggregate Paid Total,Disaggregate Paid Total,Aggregate Volunteer Total,Disaggregate Volunteer Total\n";
foreach (self::PROPERTIES as $model => $propertySets) {
$model::where('status', 'approved')->chunkById(
100,
function ($reports) use ($propertySets) {
foreach ($reports as $report) {
$aggregate_paid = (int)$report->workdays_paid;
$aggregate_volunteer = (int)$report->workdays_volunteer;

$modelType = get_class($report);
$query = Workday::where([
'workdayable_type' => $modelType,
'workdayable_id' => $report->id,
]);
if ($query->count() == 0) {
// Skip reports that have no associated workday rows.
continue;
}

$disaggregate_paid = (int)(clone $query)->whereIn('collection', $propertySets['paid'])->sum('amount');
$disaggregate_volunteer = (int)(clone $query)->whereIn('collection', $propertySets['volunteer'])->sum('amount');

if ($aggregate_paid != $disaggregate_paid || $aggregate_volunteer != $disaggregate_volunteer) {
$shortType = explode_pop('\\', $modelType);
echo "$shortType,$report->uuid,$aggregate_paid,$disaggregate_paid,$aggregate_volunteer,$disaggregate_volunteer\n";
}
}
}
);
}
}
}
26 changes: 20 additions & 6 deletions app/Exports/V2/BaseExportFormSubmission.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ protected function getAnswer(array $field, array $answers): string
if (is_array($answer)) {
$list = [];
foreach ($answer as $item) {
if (is_array($item)) {
$list[] = $item['amount'].':'.$item['gender'].':'.$item['age'].':'.$item['ethnicity'].':'.$item['indigeneity'];
} else {
$list[] = $item;
}
$list[] = data_get($field, 'input_type') . '??' . $item;
}

return implode('|', $list);
Expand All @@ -72,7 +68,25 @@ protected function getAnswer(array $field, array $answers): string
return $this->stringifyModel($answer, ['name', 'amount']);

case 'workdays':
return $this->stringifyModel($answer, ['amount', 'gender', 'age', 'ethnicity', 'indigeneity']);
$list = [];
$workday = $answer->first();
if ($workday == null) {
return '';
}

$types = ['gender' => [], 'age' => [], 'ethnicity' => []];
foreach ($workday->demographics as $demographic) {
$value = match ($demographic->type) {
'ethnicity' => [$demographic->amount, $demographic->subtype, $demographic->name],
default => [$demographic->amount, $demographic->name],
};
$types[$demographic['type']][] = implode(':', $value);
}
$list[] = 'gender:(' . implode(')(', $types['gender']) . ')';
$list[] = 'age:(' . implode(')(', $types['age']) . ')';
$list[] = 'ethnicity:(' . implode(')(', $types['ethnicity']) . ')';

return implode('|', $list);

case 'leadershipTeam':
return $this->stringifyModel($answer, ['first_name', 'last_name', 'position', 'gender', 'age',]);
Expand Down
6 changes: 3 additions & 3 deletions app/Exports/V2/EntityExport.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ protected function getAttachedMappedForEntity($entity): array
$organisation = $entity->organisation;

$mapped = [
$entity->old_id ?? ($entity->id ?? null),
$entity->ppc_external_id ?? $entity->old_id ?? $entity->id ?? null,
$entity->uuid,
$organisation->readable_type ?? null,
$organisation->name ?? null,
Expand All @@ -77,7 +77,7 @@ protected function getAttachedMappedForEntity($entity): array
];

if (in_array($this->form->type, ['nursery', 'nursery-report','site', 'site-report', 'project-report'])) {
$mapped[] = $entity->project->old_id ?? ($entity->project->id ?? null);
$mapped[] = $entity->project->ppc_external_id ?? $entity->project->id ?? null;
}

if ($this->form->type === 'project-report') {
Expand All @@ -92,7 +92,7 @@ protected function getAttachedMappedForEntity($entity): array
}

if ($this->form->type === 'site-report') {
$mapped[] = $entity->site->old_id ?? ($entity->site->id ?? null);
$mapped[] = $entity->site->ppc_external_id ?? $entity->site->id ?? null;
$mapped[] = $entity->site->name ?? null;
$sumTreeSPecies = $entity->treeSpecies()->sum('amount');
$mapped[] = $sumTreeSPecies > 0 ? $sumTreeSPecies : null;
Expand Down
Loading
Loading