opnform-host-nginx/api/app/Http/Controllers/Forms/FormPaymentController.php

165 lines
6.7 KiB
PHP

<?php
namespace App\Http\Controllers\Forms;
use App\Http\Controllers\Controller;
use App\Models\OAuthProvider;
use App\Http\Requests\Forms\GetStripeAccountRequest;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Stripe\Stripe;
use Stripe\PaymentIntent;
class FormPaymentController extends Controller
{
/**
* Get the Stripe Connect Account ID for the form's payment block.
*
* Handles two cases:
* 1. Editor Preview: `oauth_provider_id` is provided in the request by an authenticated user.
* 2. Public Form/Saved: Loads the ID from the form's saved payment block properties.
*
* @param GetStripeAccountRequest $request
* @return \Illuminate\Http\JsonResponse
*/
public function getAccount(GetStripeAccountRequest $request)
{
// Disable payment features on self-hosted instances
if (config('app.self_hosted')) {
return $this->error(['message' => 'Payment features are not available in the self-hosted version.'], 403);
}
$form = $request->form;
$provider = null;
// Case 1: Editor Preview (Validated by GetStripeAccountRequest)
if ($request->isPreview()) {
$provider = $request->getPreviewProvider();
if ($provider === null) {
// Should not happen if validation passes, but defensively handle
return $this->error(['message' => 'Invalid Stripe account selection.'], 400);
}
}
// Case 2: Public Form / Loading from Saved Form Data
else {
$paymentBlock = collect($form->properties)->first(fn ($prop) => $prop['type'] === 'payment');
if (!$paymentBlock || !isset($paymentBlock['stripe_account_id'])) {
// Allow preview by returning a specific, non-blocking error message
if (Auth::check()) { // Only return this hint to authenticated users (in editor)
return $this->error(['message' => 'Please save the form and try again.'], 400);
} else {
return $this->error(['message' => 'Payment configuration not found.'], 404); // Public error
}
}
// Load provider based on saved ID
$provider = OAuthProvider::find($paymentBlock['stripe_account_id']);
if ($provider === null) {
return $this->error(['message' => 'Configured Stripe account not found.'], 404);
}
// Use the new workspace method to check if the provider belongs to *any* workspace user
if (!$form->workspace->hasProvider($provider->id)) {
Log::error('User attempted to use Stripe account not associated with the workspace', [
'form_id' => $form->id,
'stripe_account_id' => $paymentBlock['stripe_account_id'],
'provider_id' => $provider->id,
'workspace_id' => $form->workspace_id,
'auth_user_id' => Auth::id(), // Keep auth user for logging context
]);
return $this->error(['message' => 'The configured Stripe account is not associated with this workspace.'], 403);
}
}
// Return the Stripe Connect Account ID
return $this->success(['stripeAccount' => $provider->provider_user_id]);
}
public function createIntent(Request $request)
{
// Disable payment features on self-hosted instances
if (config('app.self_hosted')) {
return $this->error(['message' => 'Payment features are not available in the self-hosted version.'], 403);
}
$form = $request->form;
// Verify form exists and is accessible
if ($form->workspace === null || $form->visibility !== 'public') {
Log::warning('Attempt to create payment for invalid form', [
'form_id' => $form->id
]);
return $this->error(['message' => 'Form not found.'], 404);
}
// Get payment block (only one allowed)
$paymentBlock = collect($form->properties)->first(fn ($prop) => $prop['type'] === 'payment');
if (!$paymentBlock) {
Log::warning('Attempt to create payment for form without payment block', [
'form_id' => $form->id
]);
return $this->error(['message' => 'Form does not have a payment block. If you just added a payment block, please save the form and try again.']);
}
// Get provider
$provider = OAuthProvider::find($paymentBlock['stripe_account_id']);
if ($provider === null) {
Log::error('Failed to find Stripe account', [
'stripe_account_id' => $paymentBlock['stripe_account_id']
]);
return $this->error(['message' => 'Failed to find Stripe account']);
}
try {
Log::info('Creating payment intent', [
'form_id' => $form->id,
'amount' => $paymentBlock['amount'],
'currency' => $paymentBlock['currency']
]);
Stripe::setApiKey(config('cashier.secret'));
$intent = PaymentIntent::create([
'description' => 'Form - ' . $form->title,
'amount' => (int) ($paymentBlock['amount'] * 100), // Stripe requires amount in cents
'currency' => strtolower($paymentBlock['currency']),
'payment_method_types' => ['card'],
'metadata' => [
'form_id' => $form->id,
'workspace_id' => $form->workspace_id,
'form_name' => $form->title,
],
], [
'stripe_account' => $provider->provider_user_id
]);
Log::info('Payment intent created', [
'form_id' => $form->id,
'intent' => $intent
]);
if ($intent->id) {
return $this->success([
'intent' => ['id' => $intent->id, 'secret' => $intent->client_secret]
]);
} else {
return $this->error(['message' => 'Failed to create payment intent']);
}
} catch (\Stripe\Exception\CardException $e) {
Log::warning('Failed to create payment intent', [
'form_id' => $form->id,
'message' => $e->getMessage()
]);
return $this->error(['message' => $e->getMessage()]);
} catch (\Exception $e) {
Log::error('Failed to create payment intent', [
'form_id' => $form->id,
'error' => $e->getMessage()
]);
return $this->error(['message' => 'Failed to initialize payment.']);
}
}
}