chore: bootstrap module from working instance and add install guide
This commit is contained in:
146
views/settings/history.php
Normal file
146
views/settings/history.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\donations\models\DonationSubscription;
|
||||
use humhub\modules\donations\models\DonationTransaction;
|
||||
use humhub\modules\donations\models\DonationWebhookEvent;
|
||||
use humhub\modules\space\models\Space;
|
||||
use yii\helpers\Html;
|
||||
|
||||
/* @var string|null $subNav */
|
||||
/* @var DonationTransaction[] $transactions */
|
||||
/* @var DonationSubscription[] $subscriptions */
|
||||
/* @var DonationWebhookEvent[] $webhookEvents */
|
||||
/* @var Space $space */
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?= Yii::t('DonationsModule.base', '<strong>Donations</strong> History') ?></div>
|
||||
|
||||
<?php if (!empty($subNav)): ?>
|
||||
<?= $subNav ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel-body">
|
||||
<div style="margin-bottom:12px;">
|
||||
<?= Html::a(
|
||||
Yii::t('DonationsModule.base', 'Back to Donations Settings'),
|
||||
$space->createUrl('/donations/settings'),
|
||||
['class' => 'btn btn-default btn-sm']
|
||||
) ?>
|
||||
|
||||
<?= Html::beginForm($space->createUrl('/donations/settings/reconcile-pending'), 'post', ['style' => 'display:inline-block;margin-left:8px;']) ?>
|
||||
<?= Html::submitButton(
|
||||
Yii::t('DonationsModule.base', 'Reconcile Pending Transactions'),
|
||||
[
|
||||
'class' => 'btn btn-primary btn-sm',
|
||||
'data-confirm' => Yii::t('DonationsModule.base', 'Attempt reconciliation for pending transactions in this space now?'),
|
||||
]
|
||||
) ?>
|
||||
<?= Html::endForm() ?>
|
||||
</div>
|
||||
|
||||
<h4 style="margin-top:0;"><?= Yii::t('DonationsModule.base', 'Transactions') ?></h4>
|
||||
<?php if (empty($transactions)): ?>
|
||||
<div class="alert alert-info"><?= Yii::t('DonationsModule.base', 'No transactions found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:14px;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Mode') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Status') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Amount') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Goal') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Checkout ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Payment ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($transactions as $transaction): ?>
|
||||
<tr>
|
||||
<td><?= (int)$transaction->id ?></td>
|
||||
<td><?= Html::encode($transaction->provider) ?></td>
|
||||
<td><?= Html::encode($transaction->mode) ?></td>
|
||||
<td><?= Html::encode($transaction->status) ?></td>
|
||||
<td><?= number_format((float)$transaction->amount, 2) ?> <?= Html::encode($transaction->currency) ?></td>
|
||||
<td>#<?= (int)$transaction->goal_id ?></td>
|
||||
<td style="max-width:180px;word-break:break-all;"><?= Html::encode((string)$transaction->provider_checkout_id) ?></td>
|
||||
<td style="max-width:180px;word-break:break-all;"><?= Html::encode((string)$transaction->provider_payment_id) ?></td>
|
||||
<td><?= Html::encode((string)$transaction->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h4><?= Yii::t('DonationsModule.base', 'Subscriptions') ?></h4>
|
||||
<?php if (empty($subscriptions)): ?>
|
||||
<div class="alert alert-info"><?= Yii::t('DonationsModule.base', 'No subscriptions found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:14px;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Status') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Amount') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Interval') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Subscription ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($subscriptions as $subscription): ?>
|
||||
<tr>
|
||||
<td><?= (int)$subscription->id ?></td>
|
||||
<td><?= Html::encode($subscription->provider) ?></td>
|
||||
<td><?= Html::encode($subscription->status) ?></td>
|
||||
<td><?= number_format((float)$subscription->amount, 2) ?> <?= Html::encode($subscription->currency) ?></td>
|
||||
<td><?= Html::encode((string)$subscription->interval_count) ?> <?= Html::encode((string)$subscription->interval_unit) ?></td>
|
||||
<td style="max-width:220px;word-break:break-all;"><?= Html::encode((string)$subscription->provider_subscription_id) ?></td>
|
||||
<td><?= Html::encode((string)$subscription->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h4><?= Yii::t('DonationsModule.base', 'Recent Webhook Events (Global)') ?></h4>
|
||||
<?php if (empty($webhookEvents)): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;"><?= Yii::t('DonationsModule.base', 'No webhook events found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:0;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Event Type') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Event ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Processed') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($webhookEvents as $event): ?>
|
||||
<tr>
|
||||
<td><?= (int)$event->id ?></td>
|
||||
<td><?= Html::encode($event->provider) ?></td>
|
||||
<td><?= Html::encode((string)$event->event_type) ?></td>
|
||||
<td style="max-width:220px;word-break:break-all;"><?= Html::encode((string)$event->provider_event_id) ?></td>
|
||||
<td><?= (int)$event->is_processed === 1 ? Yii::t('DonationsModule.base', 'Yes') : Yii::t('DonationsModule.base', 'No') ?></td>
|
||||
<td><?= Html::encode((string)$event->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
635
views/settings/index.php
Normal file
635
views/settings/index.php
Normal file
@@ -0,0 +1,635 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\donations\models\DonationGoal;
|
||||
use humhub\modules\donations\models\DonationSubscription;
|
||||
use humhub\modules\donations\models\DonationTransaction;
|
||||
use humhub\modules\donations\models\DonationWebhookEvent;
|
||||
use humhub\modules\donations\models\forms\DonationGoalForm;
|
||||
use humhub\modules\donations\models\forms\ProviderSettingsForm;
|
||||
use yii\bootstrap\ActiveForm;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Json;
|
||||
|
||||
/* @var string|null $subNav */
|
||||
/* @var ProviderSettingsForm $providerForm */
|
||||
/* @var DonationGoalForm $goalForm */
|
||||
/* @var DonationGoal[] $goals */
|
||||
/* @var DonationTransaction[] $transactions */
|
||||
/* @var DonationSubscription[] $subscriptions */
|
||||
/* @var DonationWebhookEvent[] $webhookEvents */
|
||||
/* @var array $animalOptions */
|
||||
/* @var array $animalGalleryImageMap */
|
||||
/* @var string $activeTab */
|
||||
/* @var bool $schemaReady */
|
||||
|
||||
$goalTypeOptions = DonationGoal::goalTypeOptions();
|
||||
$isEditingGoal = !empty($goalForm->id);
|
||||
$showAnimalTargetField = $goalForm->goal_type === DonationGoal::TYPE_ANIMAL;
|
||||
$hostInfo = Yii::$app->request->hostInfo;
|
||||
$stripeWebhookUrl = $hostInfo . $providerForm->contentContainer->createUrl('/donations/donations/stripe-webhook');
|
||||
$paypalWebhookUrl = $hostInfo . $providerForm->contentContainer->createUrl('/donations/donations/paypal-webhook');
|
||||
|
||||
$tabs = [
|
||||
'general' => Yii::t('DonationsModule.base', 'General'),
|
||||
'goals' => Yii::t('DonationsModule.base', 'Goals'),
|
||||
'payment-providers' => Yii::t('DonationsModule.base', 'Payment Providers'),
|
||||
'donation-history' => Yii::t('DonationsModule.base', 'Donation History'),
|
||||
'advanced' => Yii::t('DonationsModule.base', 'Advanced'),
|
||||
];
|
||||
|
||||
if (!array_key_exists($activeTab, $tabs)) {
|
||||
$activeTab = 'general';
|
||||
}
|
||||
|
||||
$tabUrl = static function (string $tab) use ($providerForm): string {
|
||||
return $providerForm->contentContainer->createUrl('/donations/settings', ['tab' => $tab]);
|
||||
};
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><?= Yii::t('DonationsModule.base', '<strong>Donations</strong> Settings') ?></div>
|
||||
|
||||
<?php if (!empty($subNav)): ?>
|
||||
<?= $subNav ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-warning" style="margin-bottom:14px;">
|
||||
<?= Yii::t('DonationsModule.base', 'Donations schema is not initialized for this environment yet. Use the Advanced tab to run setup before configuring providers, goals, or history.') ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<ul class="nav nav-tabs" style="margin-bottom:14px;">
|
||||
<?php foreach ($tabs as $tabKey => $tabLabel): ?>
|
||||
<li class="<?= $activeTab === $tabKey ? 'active' : '' ?>">
|
||||
<?= Html::a(Html::encode($tabLabel), $tabUrl($tabKey)) ?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
||||
<?php if ($activeTab === 'general'): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Default Currency') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to enable General settings.') ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php $generalForm = ActiveForm::begin(); ?>
|
||||
<?= Html::hiddenInput('active_tab', 'general') ?>
|
||||
<?= $generalForm->errorSummary($providerForm, ['class' => 'alert alert-danger']) ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<?= $generalForm->field($providerForm, 'default_currency')->textInput(['maxlength' => 8]) ?>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<?= $generalForm->field($providerForm, 'animal_tile_extra_height_px')->input('number', [
|
||||
'min' => 0,
|
||||
'max' => 600,
|
||||
'step' => 1,
|
||||
])->hint(Yii::t('DonationsModule.base', 'Adds extra height to animal cards in pixels to accommodate donation overlays.')) ?>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<?= $generalForm->field($providerForm, 'animal_donation_form_header')->textInput(['maxlength' => 255])
|
||||
->hint(Yii::t('DonationsModule.base', 'Use [animal-name] to insert the animal name, e.g. "Your Donation directly supports [animal-name]".')) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Html::submitButton(Yii::t('DonationsModule.base', 'Save General Settings'), ['class' => 'btn btn-primary']) ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($activeTab === 'goals'): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:14px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Donation Goals') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to manage goals.') ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if ($isEditingGoal): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:12px;">
|
||||
<?= Yii::t('DonationsModule.base', 'You are editing an existing goal.') ?>
|
||||
<?= Html::a(
|
||||
Yii::t('DonationsModule.base', 'Cancel'),
|
||||
$tabUrl('goals'),
|
||||
['class' => 'btn btn-xs btn-default', 'style' => 'margin-left:8px;']
|
||||
) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php $goalActiveForm = ActiveForm::begin([
|
||||
'options' => ['enctype' => 'multipart/form-data'],
|
||||
]); ?>
|
||||
<?= $goalActiveForm->errorSummary($goalForm, ['class' => 'alert alert-danger']) ?>
|
||||
<?= $goalActiveForm->field($goalForm, 'id')->hiddenInput()->label(false) ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-3"><?= $goalActiveForm->field($goalForm, 'goal_type')->dropDownList($goalTypeOptions) ?></div>
|
||||
<div class="col-md-3" id="donation-goal-animal-field" style="display:<?= $showAnimalTargetField ? 'block' : 'none' ?>;">
|
||||
<?= $goalActiveForm->field($goalForm, 'target_animal_id')->dropDownList($animalOptions, ['prompt' => Yii::t('DonationsModule.base', 'Select animal')]) ?>
|
||||
</div>
|
||||
<div class="col-md-4"><?= $goalActiveForm->field($goalForm, 'title') ?></div>
|
||||
<div class="col-md-2"><?= $goalActiveForm->field($goalForm, 'target_amount')->input('number', ['step' => '0.01', 'min' => '0']) ?></div>
|
||||
</div>
|
||||
|
||||
<?= $goalActiveForm->field($goalForm, 'description')->textarea(['rows' => 3]) ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Goal Image') ?></div>
|
||||
<div class="panel-body">
|
||||
<?= $goalActiveForm->field($goalForm, 'imageGalleryPath')->hiddenInput()->label(false) ?>
|
||||
<div id="donation-goal-current-preview" style="margin-bottom:10px;"></div>
|
||||
|
||||
<div id="donation-goal-gallery-wrapper" style="margin-bottom:12px;">
|
||||
<div id="donation-goal-gallery-options" style="display:flex;flex-wrap:wrap;"></div>
|
||||
<div id="donation-goal-gallery-empty" class="text-muted" style="display:none;">
|
||||
<?= Yii::t('DonationsModule.base', 'No gallery images found for this animal. You can upload a new image below.') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $goalActiveForm->field($goalForm, 'imageFile')->fileInput(['accept' => 'image/*']) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= $goalActiveForm->field($goalForm, 'is_active')->checkbox() ?>
|
||||
|
||||
<?= Html::submitButton(
|
||||
$isEditingGoal ? Yii::t('DonationsModule.base', 'Update Goal') : Yii::t('DonationsModule.base', 'Create Goal'),
|
||||
['class' => 'btn btn-primary']
|
||||
) ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Existing Goals') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (empty($goals)): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;"><?= Yii::t('DonationsModule.base', 'No donation goals configured yet.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:0;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Title') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Type') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Progress') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Status') ?></th>
|
||||
<th style="width:180px;"><?= Yii::t('DonationsModule.base', 'Actions') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($goals as $goal): ?>
|
||||
<tr>
|
||||
<td><?= Html::encode($goal->title) ?></td>
|
||||
<td><?= Html::encode($goalTypeOptions[$goal->goal_type] ?? $goal->goal_type) ?></td>
|
||||
<td><?= number_format((float)$goal->current_amount, 2) ?> / <?= number_format((float)$goal->target_amount, 2) ?> <?= Html::encode($goal->currency) ?></td>
|
||||
<td>
|
||||
<?php if ((int)$goal->is_active === 1): ?>
|
||||
<span class="label label-success"><?= Yii::t('DonationsModule.base', 'Active') ?></span>
|
||||
<?php else: ?>
|
||||
<span class="label label-default"><?= Yii::t('DonationsModule.base', 'Inactive') ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?= Html::a(
|
||||
Yii::t('DonationsModule.base', 'Edit'),
|
||||
$providerForm->contentContainer->createUrl('/donations/settings', [
|
||||
'tab' => 'goals',
|
||||
'goalId' => (int)$goal->id,
|
||||
]),
|
||||
['class' => 'btn btn-xs btn-primary']
|
||||
) ?>
|
||||
<?= Html::a(
|
||||
Yii::t('DonationsModule.base', 'Delete'),
|
||||
$providerForm->contentContainer->createUrl('/donations/settings/delete-goal', ['id' => (int)$goal->id]),
|
||||
[
|
||||
'class' => 'btn btn-xs btn-danger',
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('DonationsModule.base', 'Delete this donation goal?'),
|
||||
]
|
||||
) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($activeTab === 'payment-providers'): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Payment Providers') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to manage payment providers.') ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php $providerActiveForm = ActiveForm::begin(); ?>
|
||||
<?= Html::hiddenInput('active_tab', 'payment-providers') ?>
|
||||
<?= $providerActiveForm->errorSummary($providerForm, ['class' => 'alert alert-danger']) ?>
|
||||
|
||||
<div class="alert alert-info" style="margin-bottom:12px;">
|
||||
<?= Yii::t('DonationsModule.base', 'Sandbox mode automatically uses sandbox credentials. Disable sandbox mode to use live credentials.') ?>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-bottom:8px;">
|
||||
<div class="col-md-4" style="padding-top:6px;"><?= $providerActiveForm->field($providerForm, 'sandbox_mode')->checkbox() ?></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'PayPal') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<div class="row">
|
||||
<div class="col-md-6"><?= $providerActiveForm->field($providerForm, 'paypal_enabled')->checkbox() ?></div>
|
||||
<div class="col-md-6"><?= $providerActiveForm->field($providerForm, 'paypal_recurring_enabled')->checkbox() ?></div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:8px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Sandbox Credentials') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_sandbox_client_id') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_sandbox_client_secret') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_sandbox_webhook_id') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Live Credentials') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_live_client_id') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_live_client_secret') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'paypal_live_webhook_id') ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Stripe') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<div class="row">
|
||||
<div class="col-md-6"><?= $providerActiveForm->field($providerForm, 'stripe_enabled')->checkbox() ?></div>
|
||||
<div class="col-md-6"><?= $providerActiveForm->field($providerForm, 'stripe_recurring_enabled')->checkbox() ?></div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:8px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Sandbox Credentials') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_sandbox_publishable_key') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_sandbox_secret_key') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_sandbox_webhook_secret') ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Live Credentials') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:4px;">
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_live_publishable_key') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_live_secret_key') ?>
|
||||
<?= $providerActiveForm->field($providerForm, 'stripe_live_webhook_secret') ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Html::submitButton(Yii::t('DonationsModule.base', 'Save Provider Settings'), ['class' => 'btn btn-primary']) ?>
|
||||
<?php ActiveForm::end(); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($activeTab === 'donation-history'): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:14px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Transactions') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to view transaction history.') ?>
|
||||
</div>
|
||||
<?php elseif (empty($transactions)): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;"><?= Yii::t('DonationsModule.base', 'No transactions found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:0;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Mode') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Status') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Amount') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Goal') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Checkout ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Payment ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($transactions as $transaction): ?>
|
||||
<tr>
|
||||
<td><?= (int)$transaction->id ?></td>
|
||||
<td><?= Html::encode($transaction->provider) ?></td>
|
||||
<td><?= Html::encode($transaction->mode) ?></td>
|
||||
<td><?= Html::encode($transaction->status) ?></td>
|
||||
<td><?= number_format((float)$transaction->amount, 2) ?> <?= Html::encode($transaction->currency) ?></td>
|
||||
<td>#<?= (int)$transaction->goal_id ?></td>
|
||||
<td style="max-width:180px;word-break:break-all;"><?= Html::encode((string)$transaction->provider_checkout_id) ?></td>
|
||||
<td style="max-width:180px;word-break:break-all;"><?= Html::encode((string)$transaction->provider_payment_id) ?></td>
|
||||
<td><?= Html::encode((string)$transaction->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:14px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Subscriptions') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to view subscription history.') ?>
|
||||
</div>
|
||||
<?php elseif (empty($subscriptions)): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;"><?= Yii::t('DonationsModule.base', 'No subscriptions found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:0;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Status') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Amount') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Interval') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Subscription ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($subscriptions as $subscription): ?>
|
||||
<tr>
|
||||
<td><?= (int)$subscription->id ?></td>
|
||||
<td><?= Html::encode($subscription->provider) ?></td>
|
||||
<td><?= Html::encode($subscription->status) ?></td>
|
||||
<td><?= number_format((float)$subscription->amount, 2) ?> <?= Html::encode($subscription->currency) ?></td>
|
||||
<td><?= Html::encode((string)$subscription->interval_count) ?> <?= Html::encode((string)$subscription->interval_unit) ?></td>
|
||||
<td style="max-width:220px;word-break:break-all;"><?= Html::encode((string)$subscription->provider_subscription_id) ?></td>
|
||||
<td><?= Html::encode((string)$subscription->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:0;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Recent Webhook Events (Global)') ?></div>
|
||||
<div class="panel-body">
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run Donations setup from the Advanced tab to view webhook event history.') ?>
|
||||
</div>
|
||||
<?php elseif (empty($webhookEvents)): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:0;"><?= Yii::t('DonationsModule.base', 'No webhook events found.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive" style="margin-bottom:0;">
|
||||
<table class="table table-condensed table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Provider') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Event Type') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Event ID') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Processed') ?></th>
|
||||
<th><?= Yii::t('DonationsModule.base', 'Created') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($webhookEvents as $event): ?>
|
||||
<tr>
|
||||
<td><?= (int)$event->id ?></td>
|
||||
<td><?= Html::encode($event->provider) ?></td>
|
||||
<td><?= Html::encode((string)$event->event_type) ?></td>
|
||||
<td style="max-width:220px;word-break:break-all;"><?= Html::encode((string)$event->provider_event_id) ?></td>
|
||||
<td><?= (int)$event->is_processed === 1 ? Yii::t('DonationsModule.base', 'Yes') : Yii::t('DonationsModule.base', 'No') ?></td>
|
||||
<td><?= Html::encode((string)$event->created_at) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($activeTab === 'advanced'): ?>
|
||||
<div class="well well-sm" style="margin-bottom:14px;">
|
||||
<div style="font-weight:700;margin-bottom:6px;"><?= Yii::t('DonationsModule.base', 'Module Setup') ?></div>
|
||||
<div style="margin-bottom:8px;">
|
||||
<?= Yii::t('DonationsModule.base', 'Donations supports one-time and recurring contributions using PayPal and Stripe.') ?>
|
||||
</div>
|
||||
<div style="margin-bottom:10px;">
|
||||
<?= Yii::t('DonationsModule.base', 'Run setup to apply pending Donations migrations and initialize defaults for this space.') ?>
|
||||
</div>
|
||||
<?= Html::a(
|
||||
Yii::t('DonationsModule.base', 'Run Donations Setup'),
|
||||
$providerForm->contentContainer->createUrl('/donations/settings/setup'),
|
||||
[
|
||||
'class' => 'btn btn-primary btn-sm',
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('DonationsModule.base', 'Run Donations setup now for this space?'),
|
||||
]
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<?php if (!$schemaReady): ?>
|
||||
<div class="alert alert-warning" style="margin-bottom:0;">
|
||||
<?= Yii::t('DonationsModule.base', 'Donations schema is not initialized for this environment yet. Run setup above to continue.') ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="alert alert-info" style="margin-bottom:12px;">
|
||||
<div><strong><?= Yii::t('DonationsModule.base', 'Stripe Webhook URL') ?>:</strong> <?= Html::encode($stripeWebhookUrl) ?></div>
|
||||
<div><strong><?= Yii::t('DonationsModule.base', 'PayPal Webhook URL') ?>:</strong> <?= Html::encode($paypalWebhookUrl) ?></div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading" style="font-weight:600;"><?= Yii::t('DonationsModule.base', 'Webhook Simulation Tools') ?></div>
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<p style="margin-bottom:10px;">
|
||||
<?= Yii::t('DonationsModule.base', 'Use these tools to test webhook processing locally after creating donation intents. Latest matching transaction in this space is used automatically.') ?>
|
||||
</p>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<?= Html::beginForm($providerForm->contentContainer->createUrl('/donations/settings/simulate-stripe-webhook'), 'post', ['style' => 'display:inline-block;']) ?>
|
||||
<?= Html::submitButton(Yii::t('DonationsModule.base', 'Simulate Stripe Checkout Completed'), ['class' => 'btn btn-default btn-sm']) ?>
|
||||
<?= Html::endForm() ?>
|
||||
|
||||
<?= Html::beginForm($providerForm->contentContainer->createUrl('/donations/settings/simulate-paypal-webhook'), 'post', ['style' => 'display:inline-block;']) ?>
|
||||
<?= Html::submitButton(Yii::t('DonationsModule.base', 'Simulate PayPal Capture Completed'), ['class' => 'btn btn-default btn-sm']) ?>
|
||||
<?= Html::endForm() ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<?= Html::beginForm($providerForm->contentContainer->createUrl('/donations/settings/reconcile-pending'), 'post', ['style' => 'display:inline-block;margin-bottom:0;']) ?>
|
||||
<?= Html::submitButton(
|
||||
Yii::t('DonationsModule.base', 'Reconcile Pending Transactions'),
|
||||
[
|
||||
'class' => 'btn btn-primary btn-sm',
|
||||
'data-confirm' => Yii::t('DonationsModule.base', 'Attempt reconciliation for pending transactions in this space now?'),
|
||||
]
|
||||
) ?>
|
||||
<?= Html::endForm() ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$animalGalleryMapJson = Json::htmlEncode($animalGalleryImageMap);
|
||||
$selectedImageUrl = trim((string)$goalForm->imageGalleryPath) !== ''
|
||||
? trim((string)$goalForm->imageGalleryPath)
|
||||
: trim((string)$goalForm->image_path);
|
||||
|
||||
$selectedImageUrlJson = Json::htmlEncode($selectedImageUrl);
|
||||
|
||||
$this->registerCss(<<<CSS
|
||||
.donation-gallery-item {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.donation-gallery-item.is-active {
|
||||
border-color: #337ab7;
|
||||
box-shadow: 0 0 0 1px rgba(51, 122, 183, 0.25);
|
||||
}
|
||||
|
||||
#donation-goal-current-preview img {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
object-fit: cover;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
(function() {
|
||||
var galleryMap = $animalGalleryMapJson;
|
||||
var selectedImageUrl = $selectedImageUrlJson;
|
||||
|
||||
function setSelectedImage(url) {
|
||||
$('#donationgoalform-imagegallerypath').val(url || '');
|
||||
selectedImageUrl = url || '';
|
||||
renderCurrentPreview();
|
||||
renderGalleryOptions();
|
||||
}
|
||||
|
||||
function renderCurrentPreview() {
|
||||
var wrapper = $('#donation-goal-current-preview');
|
||||
wrapper.empty();
|
||||
|
||||
if (!selectedImageUrl) {
|
||||
wrapper.append('<span class="text-muted">No image selected.</span>');
|
||||
return;
|
||||
}
|
||||
|
||||
var image = $('<img>').attr('src', selectedImageUrl);
|
||||
wrapper.append(image);
|
||||
}
|
||||
|
||||
function renderGalleryOptions() {
|
||||
var goalType = $('#donationgoalform-goal_type').val();
|
||||
var animalId = $('#donationgoalform-target_animal_id').val();
|
||||
var wrapper = $('#donation-goal-gallery-options');
|
||||
var emptyState = $('#donation-goal-gallery-empty');
|
||||
|
||||
wrapper.empty();
|
||||
|
||||
if (goalType !== 'animal' || !animalId || !galleryMap[animalId] || !galleryMap[animalId].length) {
|
||||
emptyState.show();
|
||||
return;
|
||||
}
|
||||
|
||||
emptyState.hide();
|
||||
|
||||
galleryMap[animalId].forEach(function(url) {
|
||||
var button = $('<button type="button" class="donation-gallery-item" style="margin:0 8px 8px 0;padding:4px;"></button>');
|
||||
button.attr('data-url', url);
|
||||
|
||||
if (selectedImageUrl === url) {
|
||||
button.addClass('is-active');
|
||||
}
|
||||
|
||||
button.append($('<img>').attr('src', url).css({
|
||||
width: '72px',
|
||||
height: '72px',
|
||||
objectFit: 'cover'
|
||||
}));
|
||||
|
||||
wrapper.append(button);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleAnimalField() {
|
||||
var goalType = $('#donationgoalform-goal_type').val();
|
||||
var wrapper = $('#donation-goal-animal-field');
|
||||
|
||||
if (goalType === 'animal') {
|
||||
wrapper.show();
|
||||
} else {
|
||||
wrapper.hide();
|
||||
$('#donationgoalform-target_animal_id').val('');
|
||||
}
|
||||
|
||||
renderGalleryOptions();
|
||||
}
|
||||
|
||||
$(document).on('change', '#donationgoalform-goal_type', toggleAnimalField);
|
||||
$(document).on('change', '#donationgoalform-target_animal_id', renderGalleryOptions);
|
||||
$(document).on('click', '.donation-gallery-item', function() {
|
||||
var url = $(this).data('url') || '';
|
||||
setSelectedImage(url);
|
||||
});
|
||||
|
||||
$(document).on('change', '#donationgoalform-imagefile', function() {
|
||||
if (this.files && this.files.length > 0) {
|
||||
setSelectedImage('');
|
||||
}
|
||||
});
|
||||
|
||||
toggleAnimalField();
|
||||
renderCurrentPreview();
|
||||
})();
|
||||
JS
|
||||
);
|
||||
Reference in New Issue
Block a user