Skip to content

Commit cc41139

Browse files
committed
✨ Add NotchPay
1 parent 6cbadf7 commit cc41139

30 files changed

+826
-120835
lines changed

.env.example

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,5 @@ FORMS_FILESYSTEM_DRIVER=${MEDIA_DISK}
8282

8383
SENTRY_LARAVEL_DSN=
8484
SENTRY_TRACES_SAMPLE_RATE=
85+
86+
NOTCHPAY_PUBLIC_KEY=

app/Enums/PaymentType.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
enum PaymentType: string
8+
{
9+
case SUBSCRIPTION = 'subscription';
10+
case SPONSORING = 'sponsoring';
11+
}

app/Enums/PlanType.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44

55
namespace App\Enums;
66

7-
use BenSampo\Enum\Enum;
8-
9-
final class PlanType extends Enum
7+
enum PlanType: string
108
{
11-
public const DEVELOPER = 'developer';
12-
13-
public const ENTERPRISE = 'enterprise';
9+
case DEVELOPER = 'developer';
10+
case ENTERPRISE = 'enterprise';
1411
}

app/Enums/TransactionStatus.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
enum TransactionStatus: string
8+
{
9+
case PENDING = 'pending';
10+
case COMPLETE = 'complete';
11+
case CANCELED = 'canceled';
12+
case Failed = 'failed';
13+
}

app/Enums/TransactionType.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Enums;
6+
7+
enum TransactionType: string
8+
{
9+
case ONETIME = 'one-time';
10+
case RECURSIVE = 'recursive';
11+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use App\Models\Transaction;
8+
use Illuminate\Http\RedirectResponse;
9+
use Illuminate\Http\Request;
10+
11+
class NotchPayCallBackController extends Controller
12+
{
13+
public function __invoke(Request $request): RedirectResponse
14+
{
15+
$transaction = Transaction::query()
16+
->where('transaction_reference', $request->get('reference'))
17+
->firstOrFail();
18+
$transaction->update(['status' => $request->get('status')]);
19+
20+
// @ToDO Envoie de mail de notification de remerciement pour le sponsoring si l'utilisateur est dans la base de données
21+
22+
session()->flash('status', __('Votre paiement a été pris en compte merci de soutenir Laravel Cameroun.'));
23+
24+
return redirect(route('sponsors'));
25+
}
26+
}

app/Http/Controllers/SponsoringController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace App\Http\Controllers;
46

57
use Illuminate\Contracts\View\View;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Livewire\Modals;
6+
7+
use App\Enums\PaymentType;
8+
use App\Enums\TransactionType;
9+
use App\Models\Transaction;
10+
use App\Models\User;
11+
use Illuminate\Contracts\View\View;
12+
use Illuminate\Support\Facades\Auth;
13+
use LivewireUI\Modal\ModalComponent;
14+
use NotchPay\NotchPay;
15+
16+
class AnonymousSponsors extends ModalComponent
17+
{
18+
public ?string $amount = null;
19+
public ?string $option = null;
20+
public ?string $name = null;
21+
public ?string $email = null;
22+
public string $type = 'company';
23+
public ?string $url = null;
24+
25+
public function mount(string $amount, string $option): void
26+
{
27+
$this->amount = $amount;
28+
$this->option = $option;
29+
}
30+
31+
public function submit(): void
32+
{
33+
$this->validate([
34+
'name' => 'required',
35+
'email' => 'required|email',
36+
], [
37+
'name.required' => 'Votre nom est requis',
38+
'email.required' => 'Une adresse e-mail est requise',
39+
'email.email' => 'Veuillez renseigner une adresse e-mail valide',
40+
]);
41+
42+
$adminUser = User::findByEmailAddress('support@laravel.cm');
43+
44+
$notchPay = new NotchPay(config('lcm.notch-pay-public-token'));
45+
46+
try {
47+
// @phpstan-ignore-next-line
48+
$payload = $notchPay->payment->initialize([
49+
'amount' => $this->amount,
50+
'email' => $this->email,
51+
'name' => $this->name,
52+
'currency' => config('notchpay-toolkit.currency.default'),
53+
'reference' => $adminUser->id . '-' . $adminUser->username() . '-' . uniqid(),
54+
'callback' => route('notchpay-callback'),
55+
]);
56+
57+
Transaction::query()->create([
58+
'amount' => $this->amount,
59+
'status' => $payload->transaction->status,
60+
'transaction_reference' => $payload->transaction->reference,
61+
'user_id' => $adminUser->id,
62+
'fees' => $payload->transaction->fee,
63+
'type' => $this->option === 'one-time'
64+
? TransactionType::ONETIME->value
65+
: TransactionType::RECURSIVE->value,
66+
'metadata' => [
67+
'currency' => $payload->transaction->currency,
68+
'reference' => $payload->transaction->reference,
69+
'merchant' => [
70+
'reference' => $payload->transaction->merchant_reference,
71+
'name' => $payload->transaction->customer->name,
72+
'email' => $payload->transaction->customer->email,
73+
'laravel_cm_id' => null,
74+
],
75+
'initiated_at' => $payload->transaction->initiated_at,
76+
'description' => $payload->transaction->description,
77+
'for' => PaymentType::SPONSORING->value,
78+
]
79+
]);
80+
81+
$this->redirect($payload->authorization_url);
82+
} catch (NotchPay\Exception\ApiException $e) {
83+
session()->flash('error', __('Impossible de procéder au paiement, veuillez recommencer plus tard. Merci'));
84+
}
85+
}
86+
87+
public static function modalMaxWidth(): string
88+
{
89+
return 'xl';
90+
}
91+
92+
public function render(): View
93+
{
94+
return view('livewire.modals.anonymous-sponsors');
95+
}
96+
}

app/Http/Livewire/Modals/ApprovedArticle.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public function approved(): void
3939

4040
Cache::forget('post-'.$this->article->id); // @phpstan-ignore-line
4141

42-
$this->article->author->notify(new SendApprovedArticle($this->article)); // @phpstan-ignore-line
42+
$this->article->user->notify(new SendApprovedArticle($this->article)); // @phpstan-ignore-line
4343

4444
session()->flash('status', __('L\'article a été approuvé et le mail a été envoyé à l\'auteur pour le notifier.'));
4545

app/Http/Livewire/Modals/DeleteArticle.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function delete(): void
3232

3333
$this->article->delete(); // @phpstan-ignore-line
3434

35-
session()->flash('status', 'La discussion a été supprimé avec tous ses commentaires.');
35+
session()->flash('status', __('La discussion a été supprimé avec tous ses commentaires.'));
3636

3737
$this->redirectRoute('articles');
3838
}

app/Http/Livewire/Modals/DeleteDiscussion.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public function delete(): void
3232

3333
$this->discussion->delete(); // @phpstan-ignore-line
3434

35-
session()->flash('status', 'La discussion a été supprimé avec tous ses commentaires.');
35+
session()->flash('status', __('La discussion a été supprimé avec tous ses commentaires.'));
3636

3737
$this->redirectRoute('discussions.index');
3838
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Livewire;
6+
7+
use App\Enums\PaymentType;
8+
use App\Enums\TransactionType;
9+
use App\Models\Transaction;
10+
use Illuminate\Contracts\View\View;
11+
use Illuminate\Support\Facades\Auth;
12+
use Livewire\Component;
13+
use NotchPay\NotchPay;
14+
15+
class SponsorSubscription extends Component
16+
{
17+
public string $option = 'one-time';
18+
public string $amount = '';
19+
20+
public function chooseOption(string $option): void
21+
{
22+
$this->option = $option;
23+
}
24+
25+
public function subscribe(): void
26+
{
27+
$this->validate(
28+
['amount' => 'required'],
29+
['amount.required' => __('Votre montant est requis')],
30+
);
31+
32+
if (!Auth::check()) {
33+
$this->emit('openModal', 'modals.anonymous-sponsors', [
34+
'amount' => $this->amount,
35+
'option' => $this->option,
36+
]);
37+
return;
38+
}
39+
40+
$notchPay = new NotchPay(config('lcm.notch-pay-public-token'));
41+
42+
try {
43+
// @phpstan-ignore-next-line
44+
$payload = $notchPay->payment->initialize([
45+
'amount' => $this->amount,
46+
'email' => Auth::user()?->email,
47+
'name' => Auth::user()?->name,
48+
'currency' => config('notchpay-toolkit.currency.default'),
49+
'reference' => Auth::id() . '-' . Auth::user()?->username() . '-' . uniqid(),
50+
'callback' => route('notchpay-callback'),
51+
]);
52+
53+
Transaction::query()->create([
54+
'amount' => $this->amount,
55+
'status' => $payload->transaction->status,
56+
'transaction_reference' => $payload->transaction->reference,
57+
'user_id' => Auth::id(),
58+
'fees' => $payload->transaction->fee,
59+
'type' => $this->option === 'one-time'
60+
? TransactionType::ONETIME->value
61+
: TransactionType::RECURSIVE->value,
62+
'metadata' => [
63+
'currency' => $payload->transaction->currency,
64+
'reference' => $payload->transaction->reference,
65+
'merchant' => [
66+
'reference' => $payload->transaction->merchant_reference,
67+
'name' => $payload->transaction->customer->name,
68+
'email' => $payload->transaction->customer->email,
69+
'phone' => $payload->transaction->customer->phone,
70+
'laravel_cm_id' => Auth::id(),
71+
],
72+
'initiated_at' => $payload->transaction->initiated_at,
73+
'description' => $payload->transaction->description,
74+
'for' => PaymentType::SPONSORING->value,
75+
]
76+
]);
77+
78+
$this->redirect($payload->authorization_url);
79+
} catch (NotchPay\Exception\ApiException $e) {
80+
session()->flash('error', __('Impossible de procéder au paiement, veuillez recommencer plus tard. Merci'));
81+
}
82+
}
83+
84+
public function render(): View
85+
{
86+
return view('livewire.sponsor-subscription');
87+
}
88+
}

app/Models/Transaction.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Models;
6+
7+
use Illuminate\Database\Eloquent\Concerns\HasUuids;
8+
use Illuminate\Database\Eloquent\Factories\HasFactory;
9+
use Illuminate\Database\Eloquent\Model;
10+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
11+
12+
class Transaction extends Model
13+
{
14+
use HasFactory;
15+
use HasUuids;
16+
17+
public $guarded = [];
18+
19+
public $casts = [
20+
'metadata' => 'json',
21+
];
22+
23+
public function user(): BelongsTo
24+
{
25+
return $this->belongsTo(User::class);
26+
}
27+
}

app/Models/User.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,11 @@ public function subscriptions(): HasMany
242242
return $this->hasMany(Subscribe::class);
243243
}
244244

245+
public function transactions(): HasMany
246+
{
247+
return $this->hasMany(Transaction::class);
248+
}
249+
245250
public function deleteThreads(): void
246251
{
247252
// We need to explicitly iterate over the threads and delete them
@@ -255,8 +260,7 @@ public function deleteReplies(): void
255260
{
256261
// We need to explicitly iterate over the replies and delete them
257262
// separately because all related models need to be deleted.
258-
// @phpstan-ignore-next-line
259-
foreach ($this->replyAble->get() as $reply) {
263+
foreach ($this->replyAble->all() as $reply) {
260264
$reply->delete();
261265
}
262266
}

composer.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"livewire/livewire": "^2.11",
3232
"lorisleiva/laravel-actions": "^2.5",
3333
"nnjeim/world": "^1.1",
34+
"notchpay/laravel-toolkit": "^1.5",
35+
"notchpay/php-sdk": "^2.2",
3436
"qcod/laravel-gamify": "^1.0.6",
3537
"ramsey/uuid": "^4.2",
3638
"rinvex/laravel-subscriptions": "^6.1",

0 commit comments

Comments
 (0)