Skip to content

Commit

Permalink
Merge pull request #1508 from younginnovations/1492-remove-requiremen…
Browse files Browse the repository at this point in the history
…t-for-actual-and-target-value-against-a-result-period

Review: 1492-remove-requirement-for-actual-and-target-value-against-a-result-period
  • Loading branch information
Sanilblank authored Jul 30, 2024
2 parents 99d469f + 3e512f2 commit 47870f8
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 27 deletions.
31 changes: 20 additions & 11 deletions app/Http/Requests/Activity/Period/PeriodRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Http\Requests\Activity\ActivityBaseRequest;
use App\IATI\Services\Activity\IndicatorService;
use App\Rules\RequiredEitherNumericTargetValueOrActualValue;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
Expand Down Expand Up @@ -59,8 +60,8 @@ public function getWarningForPeriod(array $formFields, bool $fileUpload = false,
$tempRules = [
$this->getWarningForIndicatorPeriodStart($formFields['period_start'], 'period_start'),
$this->getWarningForIndicatorPeriodEnd($formFields['period_end'], 'period_end', $periodBase),
$this->getWarningForTarget($formFields['target'], 'target', $fileUpload, $indicator, $indicatorId),
$this->getWarningForTarget($formFields['actual'], 'actual', $fileUpload, $indicator, $indicatorId),
$this->getWarningForTargetOrActual($formFields, 'target', $fileUpload, $indicator, $indicatorId),
$this->getWarningForTargetOrActual($formFields, 'actual', $fileUpload, $indicator, $indicatorId),
];

foreach ($tempRules as $index => $tempRule) {
Expand Down Expand Up @@ -119,8 +120,8 @@ public function getMessagesForPeriod(array $formFields, bool $fileUpload = false
$tempMessages = [
$this->getMessagesForResultPeriod($formFields['period_start'], 'period_start'),
$this->getMessagesForResultPeriod($formFields['period_end'], 'period_end'),
$this->getMessagesForTarget($formFields['target'], 'target', $fileUpload, $indicator, $indicatorId),
$this->getMessagesForTarget($formFields['actual'], 'actual', $fileUpload, $indicator, $indicatorId),
$this->getMessagesForTargetOrActual($formFields['target'], 'target', $fileUpload, $indicator, $indicatorId),
$this->getMessagesForTargetOrActual($formFields['actual'], 'actual', $fileUpload, $indicator, $indicatorId),
];

foreach ($tempMessages as $index => $tempMessage) {
Expand Down Expand Up @@ -274,8 +275,12 @@ protected function getMessagesForResultPeriod($formFields, $periodType): array
* @return array
* @throws BindingResolutionException
*/
protected function getWarningForTarget($formFields, $valueType, $fileUpload, $indicator, $indicatorId): array
protected function getWarningForTargetOrActual($formFields, $valueType, $fileUpload, $indicator, $indicatorId): array
{
$targetOrActualFields = $formFields[$valueType];
$fieldToValidateAgainst = $valueType === 'target' ? 'actual' : 'target';

/** @var IndicatorService $indicatorService */
$rules = [];
$indicatorService = app()->make(IndicatorService::class);

Expand All @@ -294,7 +299,12 @@ protected function getWarningForTarget($formFields, $valueType, $fileUpload, $in
return false;
});

foreach ($formFields as $targetIndex => $target) {
/*
* The variables names are not factual.
* DO NOT get confused with the variable names.
* Since this method is called for both actual and target fields.
*/
foreach ($targetOrActualFields as $targetIndex => $target) {
$targetForm = sprintf('%s.%s', $valueType, $targetIndex);
$narrativeRules = $this->getWarningForNarrative($target['comment'][0]['narrative'], sprintf('%s.comment.0', $targetForm));
$docLinkRules = $this->getWarningForDocumentLink(Arr::get($target, 'document_link', []), $targetForm);
Expand All @@ -308,7 +318,7 @@ protected function getWarningForTarget($formFields, $valueType, $fileUpload, $in
}

if ($indicatorMeasureType['non_qualitative']) {
$rules[sprintf('%s.%s.value', $valueType, $targetIndex)] = 'required|numeric';
$rules[sprintf('%s.%s.value', $valueType, $targetIndex)] = [new RequiredEitherNumericTargetValueOrActualValue($valueType, $fieldToValidateAgainst, $formFields)];
} elseif ($indicatorMeasureType['qualitative'] && !empty($target['value'])) {
$rules[sprintf('%s.%s.value', $valueType, $targetIndex)] = 'qualitative_empty';
}
Expand Down Expand Up @@ -361,8 +371,9 @@ protected function getErrorsForTarget($formFields, $valueType, $fileUpload, $ind
* @return array
* @throws BindingResolutionException
*/
protected function getMessagesForTarget($formFields, $valueType, $fileUpload, $indicator, $indicatorId): array
protected function getMessagesForTargetOrActual($formFields, $valueType, $fileUpload, $indicator, $indicatorId): array
{
/** @var IndicatorService $indicatorService */
$messages = [];
$indicatorService = app()->make(IndicatorService::class);

Expand Down Expand Up @@ -394,9 +405,7 @@ protected function getMessagesForTarget($formFields, $valueType, $fileUpload, $i
$messages[$key] = $docLinkMessage;
}

if ($indicatorMeasureType['non_qualitative']) {
$messages[sprintf('%s.%s.value', $valueType, $targetIndex)] = 'Value must be filled when the indicator measure is non-qualitative.';
} elseif ($indicatorMeasureType['qualitative'] && !empty($target['value'])) {
if ($indicatorMeasureType['qualitative'] && !empty($target['value'])) {
$messages[sprintf('%s.%s.value.qualitative_empty', $valueType, $targetIndex)] = 'Value must be omitted when the indicator measure is qualitative.';
}
}
Expand Down
114 changes: 114 additions & 0 deletions app/Rules/RequiredEitherNumericTargetValueOrActualValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;
use Illuminate\Support\Arr;

/**
* @class RequiredEitherNumericTargetValueOrActualValue
*
* Change source: https://github.com/younginnovations/iatipublisher/issues/1492
*/
class RequiredEitherNumericTargetValueOrActualValue implements Rule
{
/**
* @var string
*/
public string $errorType = '';

/**
* Create a new rule instance.
*
* @param string $field
* @param string $otherField
* @param array $formFields
*/
public function __construct(protected string $field, protected string $otherField, protected array $formFields)
{
}

/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes($attribute, $value): bool
{
if ($this->bothTargetAnDActualHaveEmptyValues()) {
return false;
}

/**
* I'm doing this because $value can be null or N empty spaces.
* Null during creation/untouched value field.
* Empty spaces when value filed data is edited/cleared.
* strlen > 0 because I'm allowing ''.
*/
$value = trim($value ?? '');

if ($this->otherFieldHasAtleastOneNonEmptyValue() && strlen($value) > 0 && !is_numeric($value)) {
$this->errorType = 'numeric';

return false;
}

return true;
}

/**
* Get the validation error message.
*
* @return string
*/
public function message(): string
{
if ($this->errorType === 'numeric') {
return 'The @value field must be numeric.';
}

return sprintf('%s value is required if %s value is not provided.', ucfirst($this->field), $this->otherField);
}

/**
* Check if both target and actual fields have empty value field.
*
* @return bool
*/
private function bothTargetAndActualHaveEmptyValues(): bool
{
$targetValues = Arr::get($this->formFields, 'target', []);
$actualValues = Arr::get($this->formFields, 'actual', []);

$targetAllNonEmpty = !collect($targetValues)->every(function ($item) {
return !empty(trim($item['value'] ?? ''));
});

$actualAllNonEmpty = !collect($actualValues)->every(function ($item) {
return !empty(trim($item['value'] ?? ''));
});

return $targetAllNonEmpty && $actualAllNonEmpty;
}

/**
* Check if the other field (target or actual) has at least one non-empty value field.
*
* @return bool
*/
private function otherFieldHasAtleastOneNonEmptyValue(): bool
{
foreach ($this->formFields[$this->otherField] as $item) {
$item = trim($item['value'] ?? '');
if ($item !== '') {
return true;
}
}

return false;
}
}
32 changes: 16 additions & 16 deletions resources/assets/sass/component/_input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -256,41 +256,41 @@ label {
}

select.select2.default-value-indicator
+ .select2
.selection
.select2-selection:not(:focus) {
+ .select2
.selection
.select2-selection:not(:focus) {
border: 2px solid #3f9a7c;
background-color: #3f9a7c15;
}

select.select2.default-value-indicator
+ .select2
.selection
.select2-selection:not(:focus) {
+ .select2
.selection
.select2-selection:not(:focus) {
border: 2px solid #3f9a7c;
background-color: #3f9a7c15;
}

select.select2.default-value-indicator
+ .select2
.selection
.select2-selection
.select2-selection__placeholder {
+ .select2
.selection
.select2-selection
.select2-selection__placeholder {
color: var(--bluecoral-50);
}

select.select2.default-value-indicator
+ .select2.select2-container--open
.selection
.select2-selection {
+ .select2.select2-container--open
.selection
.select2-selection {
border: 1px solid #a6b5ba;
background-color: transparent;
}

select.select2.default-value-indicator
+ .select2
.selection
.select2-selection.select2-selection--clearable {
+ .select2
.selection
.select2-selection.select2-selection--clearable {
border: 1px solid #a6b5ba;
background-color: transparent;
}
Expand Down

0 comments on commit 47870f8

Please sign in to comment.