257 lines
10 KiB
PHP
257 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Plan;
|
|
use App\Models\PlanOrder;
|
|
use App\Models\PaymentSetting;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Mollie\Api\MollieApiClient;
|
|
|
|
class MolliePaymentController extends Controller
|
|
{
|
|
private function getMollieCredentials()
|
|
{
|
|
$settings = getPaymentGatewaySettings();
|
|
|
|
return [
|
|
'api_key' => $settings['payment_settings']['mollie_api_key'] ?? null,
|
|
'currency' => $settings['general_settings']['defaultCurrency'] ?? 'EUR'
|
|
];
|
|
}
|
|
|
|
public function processPayment(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'plan_id' => 'required|exists:plans,id',
|
|
'billing_cycle' => 'required|in:monthly,yearly',
|
|
'coupon_code' => 'nullable|string',
|
|
'customer_details' => 'required|array',
|
|
'customer_details.firstName' => 'required|string',
|
|
'customer_details.lastName' => 'required|string',
|
|
'customer_details.email' => 'required|email'
|
|
]);
|
|
|
|
try {
|
|
$plan = Plan::findOrFail($validated['plan_id']);
|
|
$pricing = calculatePlanPricing($plan, $validated['coupon_code'] ?? null);
|
|
$credentials = $this->getMollieCredentials();
|
|
|
|
if (!$credentials['api_key']) {
|
|
return back()->withErrors(['error' => __('Mollie not configured')]);
|
|
}
|
|
|
|
$paymentId = 'mollie_' . $plan->id . '_' . time() . '_' . uniqid();
|
|
|
|
// Create pending order
|
|
createPlanOrder([
|
|
'user_id' => auth()->id(),
|
|
'plan_id' => $plan->id,
|
|
'billing_cycle' => $validated['billing_cycle'],
|
|
'payment_method' => 'mollie',
|
|
'coupon_code' => $validated['coupon_code'] ?? null,
|
|
'payment_id' => $paymentId,
|
|
'status' => 'pending'
|
|
]);
|
|
|
|
// Initialize Mollie SDK
|
|
$mollie = new MollieApiClient();
|
|
$mollie->setApiKey($credentials['api_key']);
|
|
|
|
$paymentData = [
|
|
'amount' => [
|
|
'currency' => $credentials['currency'],
|
|
'value' => number_format($pricing['final_price'], 2, '.', '')
|
|
],
|
|
'description' => 'Plan Subscription - ' . $plan->name,
|
|
'redirectUrl' => route('mollie.success'),
|
|
'metadata' => [
|
|
'payment_id' => $paymentId,
|
|
'plan_id' => $plan->id,
|
|
'user_id' => auth()->id(),
|
|
'billing_cycle' => $validated['billing_cycle']
|
|
]
|
|
];
|
|
|
|
// Only add webhook URL if not localhost
|
|
if (!str_contains(config('app.url'), 'localhost')) {
|
|
$paymentData['webhookUrl'] = route('mollie.callback');
|
|
}
|
|
|
|
$payment = $mollie->payments->create($paymentData);
|
|
|
|
// Update the plan order with the actual Mollie payment ID
|
|
PlanOrder::where('payment_id', $paymentId)
|
|
->update(['payment_id' => $payment->id, 'notes' => __('Mollie Payment ID: ') . $payment->id]);
|
|
|
|
return redirect($payment->getCheckoutUrl());
|
|
|
|
} catch (\Exception $e) {
|
|
return back()->withErrors(['error' => __('Payment failed. Please try again.')]);
|
|
}
|
|
}
|
|
|
|
public function createPayment(Request $request)
|
|
{
|
|
$validated = validatePaymentRequest($request, [
|
|
'customer_name' => 'required|string',
|
|
'customer_email' => 'required|email',
|
|
]);
|
|
|
|
try {
|
|
$plan = Plan::findOrFail($validated['plan_id']);
|
|
$pricing = calculatePlanPricing($plan, $validated['coupon_code'] ?? null);
|
|
$credentials = $this->getMollieCredentials();
|
|
|
|
if (!$credentials['api_key']) {
|
|
throw new \Exception(__('Mollie API key not configured'));
|
|
}
|
|
|
|
$paymentId = 'mollie_' . $plan->id . '_' . time() . '_' . uniqid();
|
|
|
|
// Create pending order
|
|
createPlanOrder([
|
|
'user_id' => auth()->id(),
|
|
'plan_id' => $plan->id,
|
|
'billing_cycle' => $validated['billing_cycle'],
|
|
'payment_method' => 'mollie',
|
|
'coupon_code' => $validated['coupon_code'] ?? null,
|
|
'payment_id' => $paymentId,
|
|
'status' => 'pending'
|
|
]);
|
|
|
|
// Initialize Mollie SDK
|
|
$mollie = new MollieApiClient();
|
|
$mollie->setApiKey($credentials['api_key']);
|
|
|
|
$payment = $mollie->payments->create([
|
|
'amount' => [
|
|
'currency' => $credentials['currency'],
|
|
'value' => number_format($pricing['final_price'], 2, '.', '')
|
|
],
|
|
'description' => 'Plan Subscription - ' . $plan->name,
|
|
'redirectUrl' => route('mollie.success'),
|
|
'webhookUrl' => route('mollie.callback'),
|
|
'metadata' => [
|
|
'payment_id' => $paymentId,
|
|
'plan_id' => $plan->id,
|
|
'user_id' => auth()->id(),
|
|
'billing_cycle' => $validated['billing_cycle']
|
|
]
|
|
]);
|
|
|
|
// Update the plan order with the actual Mollie payment ID
|
|
PlanOrder::where('payment_id', $paymentId)
|
|
->update(['payment_id' => $payment->id, 'notes' => 'Mollie Payment ID: ' . $payment->id]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'payment_id' => $payment->id,
|
|
'checkout_url' => $payment->getCheckoutUrl()
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function checkPaymentStatus(Request $request)
|
|
{
|
|
$validated = $request->validate([
|
|
'payment_id' => 'required|string'
|
|
]);
|
|
|
|
try {
|
|
$credentials = $this->getMollieCredentials();
|
|
$mollie = new MollieApiClient();
|
|
$mollie->setApiKey($credentials['api_key']);
|
|
|
|
$payment = $mollie->payments->get($validated['payment_id']);
|
|
|
|
return response()->json([
|
|
'status' => $payment->status,
|
|
'is_paid' => $payment->isPaid(),
|
|
'is_failed' => $payment->isFailed(),
|
|
'is_canceled' => $payment->isCanceled()
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
return response()->json(['error' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
public function success(Request $request)
|
|
{
|
|
try {
|
|
$credentials = $this->getMollieCredentials();
|
|
|
|
if (!$credentials['api_key']) {
|
|
return redirect()->route('plans.index')->with('error', __('Payment configuration error.'));
|
|
}
|
|
|
|
// Find the most recent pending order for this user
|
|
$userId = auth()->id();
|
|
if ($userId) {
|
|
$planOrder = PlanOrder::where('user_id', $userId)
|
|
->where('status', 'pending')
|
|
->where('payment_method', 'mollie')
|
|
->orderBy('created_at', 'desc')
|
|
->first();
|
|
|
|
if ($planOrder) {
|
|
$mollie = new MollieApiClient();
|
|
$mollie->setApiKey($credentials['api_key']);
|
|
|
|
try {
|
|
$payment = $mollie->payments->get($planOrder->payment_id);
|
|
|
|
if ($payment->isPaid()) {
|
|
$planOrder->update(['status' => 'approved']);
|
|
$planOrder->activateSubscription();
|
|
|
|
return redirect()->route('plans.index')->with('success', __('Payment completed successfully! Your plan has been activated.'));
|
|
} elseif ($payment->status === 'pending') {
|
|
return redirect()->route('plans.index')->with('info', __('Payment is being processed. Your plan will be activated shortly.'));
|
|
} else {
|
|
return redirect()->route('plans.index')->with('error', __('Payment was not successful. Please try again.'));
|
|
}
|
|
} catch (\Exception $e) {
|
|
return redirect()->route('plans.index')->with('info', __('Payment is being processed. Your plan will be activated shortly.'));
|
|
}
|
|
}
|
|
}
|
|
|
|
return redirect()->route('plans.index')->with('info', __('Payment is being processed. Your plan will be activated shortly.'));
|
|
|
|
} catch (\Exception $e) {
|
|
return redirect()->route('plans.index')->with('error', __('Payment verification failed. Please contact support.'));
|
|
}
|
|
}
|
|
|
|
public function callback(Request $request)
|
|
{
|
|
try {
|
|
$paymentId = $request->input('id');
|
|
$credentials = $this->getMollieCredentials();
|
|
|
|
$mollie = new MollieApiClient();
|
|
$mollie->setApiKey($credentials['api_key']);
|
|
|
|
$payment = $mollie->payments->get($paymentId);
|
|
|
|
if ($payment->isPaid()) {
|
|
$planOrder = PlanOrder::where('payment_id', $paymentId)->first();
|
|
|
|
if ($planOrder && $planOrder->status === 'pending') {
|
|
$planOrder->update(['status' => 'approved']);
|
|
$planOrder->activateSubscription();
|
|
}
|
|
}
|
|
|
|
return response('OK', 200);
|
|
} catch (\Exception $e) {
|
|
return response('ERROR', 500);
|
|
}
|
|
}
|
|
} |