Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions backend/app/DomainObjects/Enums/StripePlatform.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace HiEvents\DomainObjects\Enums;

enum StripePlatform: string
{
case CANADA = 'ca';
case IRELAND = 'ie';

public static function fromString(?string $value): ?self
{
if ($value === null) {
return null;
}

return self::tryFrom($value);
}

public function toString(): string
{
return $this->value;
}

public static function getAllValues(): array
{
return array_column(self::cases(), 'value');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ abstract class AccountDomainObjectAbstract extends \HiEvents\DomainObjects\Abstr
final public const ACCOUNT_VERIFIED_AT = 'account_verified_at';
final public const STRIPE_CONNECT_ACCOUNT_TYPE = 'stripe_connect_account_type';
final public const IS_MANUALLY_VERIFIED = 'is_manually_verified';
final public const STRIPE_PLATFORM = 'stripe_platform';

protected int $id;
protected ?int $account_configuration_id = null;
Expand All @@ -41,6 +42,7 @@ abstract class AccountDomainObjectAbstract extends \HiEvents\DomainObjects\Abstr
protected ?string $account_verified_at = null;
protected ?string $stripe_connect_account_type = null;
protected bool $is_manually_verified = false;
protected ?string $stripe_platform = null;

public function toArray(): array
{
Expand All @@ -60,6 +62,7 @@ public function toArray(): array
'account_verified_at' => $this->account_verified_at ?? null,
'stripe_connect_account_type' => $this->stripe_connect_account_type ?? null,
'is_manually_verified' => $this->is_manually_verified ?? null,
'stripe_platform' => $this->stripe_platform ?? null,
];
}

Expand Down Expand Up @@ -227,4 +230,15 @@ public function getIsManuallyVerified(): bool
{
return $this->is_manually_verified;
}

public function setStripePlatform(?string $stripe_platform): self
{
$this->stripe_platform = $stripe_platform;
return $this;
}

public function getStripePlatform(): ?string
{
return $this->stripe_platform;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ abstract class EmailTemplateDomainObjectAbstract extends \HiEvents\DomainObjects
final public const IS_ACTIVE = 'is_active';
final public const CREATED_AT = 'created_at';
final public const UPDATED_AT = 'updated_at';
final public const DELETED_AT = 'deleted_at';

protected int $id;
protected int $account_id;
Expand All @@ -35,6 +36,7 @@ abstract class EmailTemplateDomainObjectAbstract extends \HiEvents\DomainObjects
protected bool $is_active = true;
protected ?string $created_at = null;
protected ?string $updated_at = null;
protected ?string $deleted_at = null;

public function toArray(): array
{
Expand All @@ -51,6 +53,7 @@ public function toArray(): array
'is_active' => $this->is_active ?? null,
'created_at' => $this->created_at ?? null,
'updated_at' => $this->updated_at ?? null,
'deleted_at' => $this->deleted_at ?? null,
];
}

Expand Down Expand Up @@ -185,4 +188,15 @@ public function getUpdatedAt(): ?string
{
return $this->updated_at;
}

public function setDeletedAt(?string $deleted_at): self
{
$this->deleted_at = $deleted_at;
return $this;
}

public function getDeletedAt(): ?string
{
return $this->deleted_at;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

namespace HiEvents\Exceptions\Stripe;

use HiEvents\Exceptions\BaseException;

class StripeClientConfigurationException extends BaseException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,10 @@

class CreatePaymentIntentActionPublic extends BaseAction
{
private CreatePaymentIntentHandler $createPaymentIntentHandler;

public function __construct(CreatePaymentIntentHandler $createPaymentIntentHandler)
public function __construct(
private readonly CreatePaymentIntentHandler $createPaymentIntentHandler,
)
{
$this->createPaymentIntentHandler = $createPaymentIntentHandler;
}

public function __invoke(int $eventId, string $orderShortId): JsonResponse
Expand All @@ -28,6 +27,8 @@ public function __invoke(int $eventId, string $orderShortId): JsonResponse
return $this->jsonResponse([
'client_secret' => $createIntent->clientSecret,
'account_id' => $createIntent->accountId,
'public_key' => $createIntent->publicKey,
'stripe_platform' => $createIntent->stripePlatform?->value,
]);
}
}
9 changes: 7 additions & 2 deletions backend/app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;
use Stripe\StripeClient;
use HiEvents\Services\Infrastructure\Stripe\StripeConfigurationService;
use HiEvents\Services\Infrastructure\Stripe\StripeClientFactory;

class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->bindDoctrineConnection();
$this->bindStripeClient();
$this->bindStripeServices();
$this->bindCurrencyConversionClient();
}

Expand Down Expand Up @@ -67,8 +69,11 @@ function () {
);
}

private function bindStripeClient(): void
private function bindStripeServices(): void
{
$this->app->singleton(StripeConfigurationService::class);
$this->app->singleton(StripeClientFactory::class);

if (!config('services.stripe.secret_key')) {
logger()?->debug('Stripe secret key is not set in the configuration file. Payment processing will not work.');
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
use HiEvents\Exceptions\CreateStripeConnectAccountFailedException;
use HiEvents\Exceptions\CreateStripeConnectAccountLinksFailedException;
use HiEvents\Exceptions\SaasModeEnabledException;
use HiEvents\Exceptions\Stripe\StripeClientConfigurationException;
use HiEvents\Helper\Url;
use HiEvents\Repository\Interfaces\AccountRepositoryInterface;
use HiEvents\Services\Application\Handlers\Account\Payment\Stripe\DTO\CreateStripeConnectAccountDTO;
use HiEvents\Services\Application\Handlers\Account\Payment\Stripe\DTO\CreateStripeConnectAccountResponse;
use HiEvents\Services\Infrastructure\Stripe\StripeClientFactory;
use HiEvents\Services\Infrastructure\Stripe\StripeConfigurationService;
use HiEvents\DomainObjects\Enums\StripePlatform;
use Illuminate\Config\Repository;
use Illuminate\Database\DatabaseManager;
use Psr\Log\LoggerInterface;
Expand All @@ -24,9 +28,10 @@
public function __construct(
private AccountRepositoryInterface $accountRepository,
private DatabaseManager $databaseManager,
private StripeClient $stripe,
private LoggerInterface $logger,
private Repository $config,
private StripeClientFactory $stripeClientFactory,
private StripeConfigurationService $stripeConfigurationService,
)
{
}
Expand All @@ -47,13 +52,19 @@ public function handle(CreateStripeConnectAccountDTO $command): CreateStripeConn

/**
* @throws CreateStripeConnectAccountFailedException|CreateStripeConnectAccountLinksFailedException
* @throws StripeClientConfigurationException
*/
private function createOrGetStripeConnectAccount(CreateStripeConnectAccountDTO $command): CreateStripeConnectAccountResponse
{
$account = $this->accountRepository->findById($command->accountId);

$primaryPlatform = $this->stripeConfigurationService->getPrimaryPlatform();
$stripeClient = $this->stripeClientFactory->createForPlatform($primaryPlatform);

$stripeConnectAccount = $this->getOrCreateStripeConnectAccount(
account: $account,
stripeClient: $stripeClient,
platform: $primaryPlatform,
);

$response = new CreateStripeConnectAccountResponse(
Expand All @@ -72,22 +83,26 @@ private function createOrGetStripeConnectAccount(CreateStripeConnectAccountDTO $
return $response;
}

$response->connectUrl = $this->getStripeAccountSetupUrl($stripeConnectAccount, $account);
$response->connectUrl = $this->getStripeAccountSetupUrl($stripeConnectAccount, $account, $stripeClient);

return $response;
}

/**
* @throws CreateStripeConnectAccountFailedException
*/
private function getOrCreateStripeConnectAccount(AccountDomainObject $account): Account
private function getOrCreateStripeConnectAccount(
AccountDomainObject $account,
StripeClient $stripeClient,
?StripePlatform $platform
): Account
{
try {
if ($account->getStripeAccountId() !== null) {
return $this->stripe->accounts->retrieve($account->getStripeAccountId());
return $stripeClient->accounts->retrieve($account->getStripeAccountId());
}

$stripeAccount = $this->stripe->accounts->create([
$stripeAccount = $stripeClient->accounts->create([
'type' => $this->config->get('app.stripe_connect_account_type')
?? StripeConnectAccountType::EXPRESS->value,
]);
Expand All @@ -105,11 +120,18 @@ private function getOrCreateStripeConnectAccount(AccountDomainObject $account):
);
}

$updateAttributes = [
AccountDomainObjectAbstract::STRIPE_ACCOUNT_ID => $stripeAccount->id,
AccountDomainObjectAbstract::STRIPE_CONNECT_ACCOUNT_TYPE => $stripeAccount->type,
];

// Set the platform that was actually used to create this account
if ($platform && $account->getStripePlatform() === null) {
$updateAttributes[AccountDomainObjectAbstract::STRIPE_PLATFORM] = $platform->value;
}

$this->accountRepository->updateWhere(
attributes: [
AccountDomainObjectAbstract::STRIPE_ACCOUNT_ID => $stripeAccount->id,
AccountDomainObjectAbstract::STRIPE_CONNECT_ACCOUNT_TYPE => $stripeAccount->type,
],
attributes: $updateAttributes,
where: [
'id' => $account->getId(),
]
Expand All @@ -131,10 +153,10 @@ private function isStripeAccountComplete(Account $stripAccount): bool
/**
* @throws CreateStripeConnectAccountLinksFailedException
*/
private function getStripeAccountSetupUrl(Account $stripAccount, AccountDomainObject $account): string
private function getStripeAccountSetupUrl(Account $stripAccount, AccountDomainObject $account, StripeClient $stripeClient): string
{
try {
$accountLink = $this->stripe->accountLinks->create([
$accountLink = $stripeClient->accountLinks->create([
'account' => $stripAccount->id,
'refresh_url' => Url::getFrontEndUrlFromConfig(Url::STRIPE_CONNECT_REFRESH_URL, [
'is_refresh' => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
use HiEvents\Repository\Interfaces\AccountRepositoryInterface;
use HiEvents\Repository\Interfaces\OrderRepositoryInterface;
use HiEvents\Repository\Interfaces\StripePaymentsRepositoryInterface;
use HiEvents\Services\Infrastructure\Stripe\StripeClientFactory;
use HiEvents\Services\Infrastructure\Stripe\StripeConfigurationService;
use HiEvents\DomainObjects\Enums\StripePlatform;
use HiEvents\Services\Domain\Payment\Stripe\DTOs\CreatePaymentIntentRequestDTO;
use HiEvents\Services\Domain\Payment\Stripe\DTOs\CreatePaymentIntentResponseDTO;
use HiEvents\Services\Domain\Payment\Stripe\StripePaymentIntentCreationService;
Expand All @@ -34,6 +37,8 @@ public function __construct(
private CheckoutSessionManagementService $sessionIdentifierService,
private StripePaymentsRepositoryInterface $stripePaymentsRepository,
private AccountRepositoryInterface $accountRepository,
private StripeClientFactory $stripeClientFactory,
private StripeConfigurationService $stripeConfigurationService,
)
{
}
Expand Down Expand Up @@ -71,24 +76,35 @@ public function handle(string $orderShortId): CreatePaymentIntentResponseDTO
))
->findByEventId($order->getEventId());

// Get platform information from account
$stripePlatform = StripePlatform::fromString($account->getStripePlatform());
$stripeClient = $this->stripeClientFactory->createForPlatform($stripePlatform);
$publicKey = $this->stripeConfigurationService->getPublicKey($stripePlatform);

// If we already have a Stripe session then re-fetch the client secret
if ($order->getStripePayment() !== null) {
return new CreatePaymentIntentResponseDTO(
paymentIntentId: $order->getStripePayment()->getPaymentIntentId(),
clientSecret: $this->stripePaymentService->retrievePaymentIntentClientSecret(
clientSecret: $this->stripePaymentService->retrievePaymentIntentClientSecretWithClient(
$stripeClient,
$order->getStripePayment()->getPaymentIntentId(),
$account->getStripeAccountId()
),
accountId: $account->getStripeAccountId(),
stripePlatform: $stripePlatform,
publicKey: $publicKey,
);
}

$paymentIntent = $this->stripePaymentService->createPaymentIntent(CreatePaymentIntentRequestDTO::fromArray([
'amount' => MoneyValue::fromFloat($order->getTotalGross(), $order->getCurrency()),
'currencyCode' => $order->getCurrency(),
'account' => $account,
'order' => $order,
]));
$paymentIntent = $this->stripePaymentService->createPaymentIntentWithClient(
$stripeClient,
CreatePaymentIntentRequestDTO::fromArray([
'amount' => MoneyValue::fromFloat($order->getTotalGross(), $order->getCurrency()),
'currencyCode' => $order->getCurrency(),
'account' => $account,
'order' => $order,
])
);

$this->stripePaymentsRepository->create([
StripePaymentDomainObjectAbstract::ORDER_ID => $order->getId(),
Expand All @@ -97,6 +113,13 @@ public function handle(string $orderShortId): CreatePaymentIntentResponseDTO
StripePaymentDomainObjectAbstract::APPLICATION_FEE => $paymentIntent->applicationFeeAmount,
]);

return $paymentIntent;
return new CreatePaymentIntentResponseDTO(
paymentIntentId: $paymentIntent->paymentIntentId,
clientSecret: $paymentIntent->clientSecret,
accountId: $paymentIntent->accountId,
applicationFeeAmount: $paymentIntent->applicationFeeAmount,
stripePlatform: $stripePlatform,
publicKey: $publicKey,
);
}
}
Loading
Loading