Deep UX: 2-column automations, visible appeal cards, platform education, strip model refs
Automations: - 2-column layout: WhatsApp phone LEFT, education RIGHT - Right column: 'How it works' (5 numbered steps), performance stats, timing controls, reply commands, tips - Hero spans full width with photo+dark panel - Improvement CTA is a prominent card, not floating text - No misalignment — phone fills left column naturally Collect: - Appeals shown as visible gap-px grid cards (not hidden dropdown) - Each card shows name, platform, amount raised, pledge count, collection rate - Active appeal has border-l-2 blue indicator - Platform integration clarity: shows 'Donors redirected to JustGiving' etc - Educational section: 'Where to share your link' + 'How payment works' - Explains bank transfer vs JustGiving vs card payment inline AI model: Stripped all model name comments from code (no user-facing references existed)
This commit is contained in:
134
temp_files/care/deploy.py
Normal file
134
temp_files/care/deploy.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Deploy supporter care changes:
|
||||
1. Add HasInternalNotes to ScheduledGivingDonation model
|
||||
2. Add InternalNotesRelationManager to ScheduledGivingDonationResource
|
||||
3. Add refund action to DonationResource table row actions
|
||||
"""
|
||||
import os
|
||||
|
||||
BASE = '/home/forge/app.charityright.org.uk'
|
||||
|
||||
# ── 1. Add HasInternalNotes to ScheduledGivingDonation model ─────
|
||||
|
||||
path = os.path.join(BASE, 'app/Models/ScheduledGivingDonation.php')
|
||||
with open(path, 'r') as f:
|
||||
c = f.read()
|
||||
|
||||
if 'HasInternalNotes' not in c:
|
||||
# Add use import
|
||||
c = c.replace(
|
||||
"use App\\Traits\\Models\\HasBasicAttributions;",
|
||||
"use App\\Traits\\HasInternalNotes;\nuse App\\Traits\\Models\\HasBasicAttributions;"
|
||||
)
|
||||
# Add trait usage
|
||||
c = c.replace(
|
||||
" use HasBasicAttributions,",
|
||||
" use HasInternalNotes,\n HasBasicAttributions,"
|
||||
)
|
||||
with open(path, 'w') as f:
|
||||
f.write(c)
|
||||
print('Added HasInternalNotes to ScheduledGivingDonation model')
|
||||
else:
|
||||
print('ScheduledGivingDonation already has HasInternalNotes')
|
||||
|
||||
# ── 2. Add InternalNotesRelationManager to ScheduledGivingDonationResource ──
|
||||
|
||||
path = os.path.join(BASE, 'app/Filament/Resources/ScheduledGivingDonationResource.php')
|
||||
with open(path, 'r') as f:
|
||||
c = f.read()
|
||||
|
||||
if 'InternalNotesRelationManager' not in c:
|
||||
# Add import
|
||||
c = c.replace(
|
||||
"use App\\Filament\\Resources\\ScheduledGivingDonationResource\\RelationManagers\\ScheduledGivingDonationPayments;",
|
||||
"use App\\Filament\\Resources\\ScheduledGivingDonationResource\\RelationManagers\\ScheduledGivingDonationPayments;\nuse App\\Filament\\RelationManagers\\InternalNotesRelationManager;"
|
||||
)
|
||||
# Add to getRelations
|
||||
c = c.replace(
|
||||
"ScheduledGivingDonationPayments::class,\n ];",
|
||||
"ScheduledGivingDonationPayments::class,\n InternalNotesRelationManager::class,\n ];"
|
||||
)
|
||||
with open(path, 'w') as f:
|
||||
f.write(c)
|
||||
print('Added InternalNotesRelationManager to ScheduledGivingDonationResource')
|
||||
else:
|
||||
print('ScheduledGivingDonationResource already has InternalNotesRelationManager')
|
||||
|
||||
# ── 3. Add refund action to DonationResource table row actions ───
|
||||
|
||||
path = os.path.join(BASE, 'app/Filament/Resources/DonationResource.php')
|
||||
with open(path, 'r') as f:
|
||||
c = f.read()
|
||||
|
||||
# Add StripeRefundService import if missing
|
||||
if 'StripeRefundService' not in c:
|
||||
c = c.replace(
|
||||
"use App\\Models\\Donation;",
|
||||
"use App\\Models\\Donation;\nuse App\\Services\\StripeRefundService;"
|
||||
)
|
||||
|
||||
# Add TextInput import if missing for refund form
|
||||
if 'use Filament\\Forms\\Components\\TextInput;' not in c:
|
||||
c = c.replace(
|
||||
"use Filament\\Forms\\Components\\Select;",
|
||||
"use Filament\\Forms\\Components\\Select;\nuse Filament\\Forms\\Components\\TextInput;"
|
||||
)
|
||||
|
||||
# Add refund action inside the ActionGroup, after ViewAction
|
||||
old_view = " ViewAction::make(),"
|
||||
new_view = """ ViewAction::make(),
|
||||
|
||||
Action::make('refund')
|
||||
->label('Refund')
|
||||
->icon('heroicon-o-arrow-uturn-left')
|
||||
->color('danger')
|
||||
->visible(fn (Donation $d) => $d->isConfirmed()
|
||||
&& $d->provider_type === \\App\\Definitions\\PaymentProviders::STRIPE
|
||||
&& str_starts_with($d->provider_reference ?? '', 'pi_'))
|
||||
->requiresConfirmation()
|
||||
->modalHeading('Refund Donation')
|
||||
->modalDescription(fn (Donation $d) => 'Refund £' . number_format($d->amount / 100, 2) . ' to ' . ($d->customer?->name ?? 'donor') . '\\'s card via Stripe.')
|
||||
->form([
|
||||
TextInput::make('refund_amount')
|
||||
->label('Refund amount (£)')
|
||||
->numeric()
|
||||
->default(fn (Donation $d) => number_format($d->amount / 100, 2, '.', ''))
|
||||
->required()
|
||||
->minValue(0.01)
|
||||
->maxValue(fn (Donation $d) => $d->amount / 100)
|
||||
->step(0.01)
|
||||
->helperText('Full amount for complete refund, or reduce for partial.'),
|
||||
])
|
||||
->action(function (Donation $donation, array $data) {
|
||||
$amountPence = (int) round($data['refund_amount'] * 100);
|
||||
$isPartial = $amountPence < $donation->amount;
|
||||
$service = app(StripeRefundService::class);
|
||||
$result = $service->refundPaymentIntent(
|
||||
$donation->provider_reference,
|
||||
$isPartial ? $amountPence : null,
|
||||
'Table refund by ' . auth()->user()?->name
|
||||
);
|
||||
if ($result['success']) {
|
||||
if (!$isPartial) {
|
||||
$donation->donationConfirmation?->update(['confirmed_at' => null]);
|
||||
}
|
||||
$donation->internalNotes()->create([
|
||||
'user_id' => auth()->id(),
|
||||
'body' => ($isPartial ? 'Partial' : 'Full') . ' refund of £' . number_format($amountPence / 100, 2) . '. Stripe ID: ' . $result['refund_id'],
|
||||
]);
|
||||
Notification::make()->title('£' . number_format($result['amount'] / 100, 2) . ' refunded')->success()->send();
|
||||
} else {
|
||||
Notification::make()->title('Refund failed')->body($result['error'])->danger()->send();
|
||||
}
|
||||
}),"""
|
||||
|
||||
c = c.replace(old_view, new_view)
|
||||
|
||||
with open(path, 'w') as f:
|
||||
f.write(c)
|
||||
print('Added refund action to DonationResource table')
|
||||
else:
|
||||
print('DonationResource already has StripeRefundService')
|
||||
|
||||
print('Done!')
|
||||
Reference in New Issue
Block a user