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

Refactor: Update goal/stats to use Donation Query #7376

Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 19 additions & 1 deletion src/DonationForms/DataTransferObjects/DonationFormGoalData.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Give\DonationForms\Properties\FormSettings;
use Give\DonationForms\Repositories\DonationFormRepository;
use Give\DonationForms\ValueObjects\GoalProgressType;
use Give\DonationForms\ValueObjects\GoalType;
use Give\Framework\Support\Contracts\Arrayable;

Expand Down Expand Up @@ -32,6 +33,18 @@ class DonationFormGoalData implements Arrayable
* @var int
*/
public $targetAmount;
/**
* @var GoalProgressType
*/
public $goalProgressType;
/**
* @var string|null
*/
public $goalStartDate;
/**
* @var string|null
*/
public $goalEndDate;

/**
* @since 3.0.0
Expand All @@ -43,6 +56,9 @@ public function __construct(int $formId, FormSettings $formSettings)
$this->isEnabled = $formSettings->enableDonationGoal ?? false;
$this->goalType = $formSettings->goalType ?? GoalType::AMOUNT();
$this->targetAmount = $this->formSettings->goalAmount ?? 0;
$this->goalProgressType = $this->formSettings->goalProgressType ?? GoalProgressType::ALL_TIME();
$this->goalStartDate = $this->formSettings->goalStartDate ?? null;
$this->goalEndDate = $this->formSettings->goalEndDate ?? null;
}

/**
Expand All @@ -68,7 +84,9 @@ public function getCurrentAmount()
return $donationFormRepository->getTotalNumberOfDonorsFromSubscriptions($this->formId);
case GoalType::AMOUNT():
default:
return $donationFormRepository->getTotalRevenue($this->formId);
return $this->goalProgressType->isAllTime()
? $donationFormRepository->getTotalRevenue($this->formId)
: $donationFormRepository->getTotalRevenueForDateRange($this->formId,$this->goalStartDate, $this->goalEndDate);
endswitch;
}

Expand Down
79 changes: 79 additions & 0 deletions src/DonationForms/DonationQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

namespace Give\DonationForms;

use Give\Framework\QueryBuilder\JoinQueryBuilder;
use Give\Framework\QueryBuilder\QueryBuilder;

/**
* An opinionated Query Builder for GiveWP donations and meta fields.
*
* @unreleased
*
* Example usage:
* (new DonationQuery)
* ->form(1816)
* ->between('2024-02-00', '2024-02-23')
* ->sumIntendedAmount();
*/
class DonationQuery extends QueryBuilder
{
/**
* @unreleased
*/
public function __construct()
{
$this->from('posts', 'donation');
}

/**
* An opinionated join method for the donation meta table.
* @unreleased
*/
public function joinMeta($key, $alias)
{
$this->join(function (JoinQueryBuilder $builder) use ($key, $alias) {
$builder
->leftJoin('give_donationmeta', $alias)
->on('donation.ID', $alias . '.donation_id')
->andOn($alias . '.meta_key', $key, true);
});
return $this;
}

/**
* An opinionated where method for the donation form ID meta field.
* @unreleased
*/
public function form($formId)
{
$this->joinMeta('_give_payment_form_id', 'formId');
$this->where('formId.meta_value', $formId);
return $this;
}

/**
* An opinionated whereBetween method for the completed date meta field.
* @unreleased
*/
public function between($startDate, $endDate)
{
$this->joinMeta('_give_completed_date', 'completed');
$this->whereBetween('completed.meta_value', $startDate, $endDate);
Copy link
Member

@alaca alaca Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't test it on my end, but I'm very surprised that this works because the meta_value type is longtext and not datetime 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested this on my end and it works 😅
Interesting

return $this;
}

/**
* Returns a calculated sum of the intended amounts (without recovered fees) for the donations.
* @unreleased
* @return int|float
*/
public function sumIntendedAmount()
{
$this->joinMeta('_give_payment_total', 'amount');
$this->joinMeta('_give_fee_donation_amount', 'intendedAmount');
return $this->sum(
'COALESCE(intendedAmount.meta_value, amount.meta_value)'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I'm not sure I fully understand this.
_give_payment_total has an amount that includes fees, and _give_fee_donation_amount doesn't include fees.
_give_fee_donation_amount is set only if fee recovery is checked. Correct me if I'm wrong, but COALESCE will return both _give_payment_total and _give_fee_donation_amount if the values are not null. So, if both are set, then the calculation is wrong, or I'm missing something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, it works as expected.

);
}
}
39 changes: 25 additions & 14 deletions src/DonationForms/Repositories/DonationFormRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Closure;
use Give\DonationForms\Actions\ConvertDonationFormBlocksToFieldsApi;
use Give\DonationForms\DonationQuery;
use Give\DonationForms\Models\DonationForm;
use Give\DonationForms\ValueObjects\DonationFormMetaKeys;
use Give\Donations\ValueObjects\DonationMetaKeys;
Expand Down Expand Up @@ -393,10 +394,16 @@ public function getTotalNumberOfDonorsFromSubscriptions(int $formId): int
*/
public function getTotalNumberOfDonations(int $formId): int
{
return DB::table('posts')
->leftJoin('give_donationmeta', 'ID', 'donation_id')
->where('meta_key', DonationMetaKeys::FORM_ID)
->where('meta_value', $formId)
return (new DonationQuery)
->form($formId)
->count();
}

public function getTotalNumberOfDonationsForDateRange(int $formId, string $startDate, string $endDate): int
{
return (new DonationQuery)
->form($formId)
->between($startDate, $endDate)
->count();
}

Expand All @@ -411,21 +418,25 @@ public function getTotalNumberOfSubscriptions(int $formId): int
}

/**
* @unreleased Update query to use intended amounts (without recovered fees).
* @since 3.0.0
*/
public function getTotalRevenue(int $formId): int
{
$query = DB::table('give_formmeta')
->select('meta_value as totalRevenue')
->where('form_id', $formId)
->where('meta_key', '_give_form_earnings')
->get();

if (!$query) {
return 0;
}
return (int) (new DonationQuery)
->form($formId)
->sumIntendedAmount();
}

return (int)$query->totalRevenue;
/**
* @unreleased
*/
public function getTotalRevenueForDateRange(int $formId, string $startDate, string $endDate): int
{
return (int) (new DonationQuery)
->form($formId)
->between($startDate, $endDate)
->sumIntendedAmount();
}

/**
Expand Down
17 changes: 11 additions & 6 deletions src/DonationForms/ViewModels/DonationFormViewModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Give\DonationForms\Actions\GenerateDonateRouteUrl;
use Give\DonationForms\Actions\GenerateDonationFormValidationRouteUrl;
use Give\DonationForms\DataTransferObjects\DonationFormGoalData;
use Give\DonationForms\DonationQuery;
use Give\DonationForms\Properties\FormSettings;
use Give\DonationForms\Repositories\DonationFormRepository;
use Give\DonationForms\ValueObjects\GoalType;
Expand Down Expand Up @@ -181,14 +182,18 @@ private function formStatsData(): array
{
$goalType = $this->goalType();

$totalRevenue = $this->getTotalRevenue($goalType);
$totalCountValue = $this->getTotalCountValue($goalType);
$totalCountLabel = $this->getCountLabel($goalType);
$donationQuery = (new DonationQuery)->form($this->donationFormId);

if($this->formSettings->goalProgressType->isCustom()) {
$donationQuery->between($this->formSettings->goalStartDate, $this->formSettings->goalEndDate);
}

return [
'totalRevenue' => $totalRevenue,
'totalCountValue' => $totalCountValue,
'totalCountLabel' => $totalCountLabel,
'totalRevenue' => $donationQuery->sumIntendedAmount(),
'totalCountValue' => $goalType->isDonations() || $goalType->isAmount()
? $donationQuery->count()
: $this->getTotalCountValue($goalType),
'totalCountLabel' => $this->getCountLabel($goalType),
];
}

Expand Down
Loading