Merge 15bee32810 into 9e17c85f1b
This commit is contained in:
commit
2ee7e5321d
|
|
@ -133,12 +133,12 @@ class Gateway extends StaticModel
|
|||
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true]]; //Payfast
|
||||
case 7:
|
||||
return [
|
||||
GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true, 'webhooks' => ['all']], // Mollie
|
||||
GatewayType::BANK_TRANSFER => ['refund' => false, 'token_billing' => true, 'webhooks' => ['all']],
|
||||
GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true, 'webhooks' => ['all']],
|
||||
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['all']],
|
||||
GatewayType::KBC => ['refund' => false, 'token_billing' => false, 'webhooks' => ['all']],
|
||||
GatewayType::BANCONTACT => ['refund' => false, 'token_billing' => false, 'webhooks' => ['all']],
|
||||
GatewayType::IDEAL => ['refund' => false, 'token_billing' => false, 'webhooks' => ['all']],
|
||||
];
|
||||
GatewayType::IDEAL => ['refund' => true, 'token_billing' => false, 'webhooks' => ['all']],
|
||||
]; // Mollie
|
||||
case 15:
|
||||
return [
|
||||
GatewayType::PAYPAL => ['refund' => false, 'token_billing' => false],
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ namespace App\Models;
|
|||
* @method static \Illuminate\Database\Eloquent\Builder|GatewayType whereAlias($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|GatewayType whereId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|GatewayType whereName($value)
|
||||
* @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\PaymentType> $payment_methods
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class GatewayType extends StaticModel
|
||||
|
|
|
|||
|
|
@ -37,33 +37,22 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
$this->mollie->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the authorization page for Bancontact.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeView(array $data): View
|
||||
{
|
||||
return render('gateways.mollie.bancontact.authorize', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the authorization for Bancontact.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeResponse(Request $request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the payment page for Bancontact.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Http\RedirectResponseor|RedirectResponse
|
||||
* @throws \Exception
|
||||
* @throws PaymentFailed
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
|
|
@ -95,44 +84,17 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
|
||||
return redirect(
|
||||
$payment->getCheckoutUrl()
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
return redirect($payment->getCheckoutUrl());
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param Exception $exception
|
||||
* @throws PaymentFailed
|
||||
* @return void
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $exception): void
|
||||
{
|
||||
$this->mollie->sendFailureMail($exception->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$exception->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the payments for the KBC.
|
||||
*
|
||||
* @param PaymentResponseRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
public function paymentResponse(PaymentResponseRequest $request): \Illuminate\Http\Response|RedirectResponse
|
||||
{
|
||||
if (! \property_exists($this->mollie->payment_hash->data, 'payment_id')) {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
|
|
@ -141,19 +103,19 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
}
|
||||
|
||||
try {
|
||||
$payment = $this->mollie->gateway->payments->get(
|
||||
$molliePayment = $this->mollie->gateway->payments->get(
|
||||
$this->mollie->payment_hash->data->payment_id
|
||||
);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
if ($molliePayment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'open') {
|
||||
return $this->processOpenPayment($payment);
|
||||
if ($molliePayment->status === 'open') {
|
||||
return $this->processOpenPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'failed') {
|
||||
if ($molliePayment->status === 'failed') {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_failed'))
|
||||
);
|
||||
|
|
@ -162,7 +124,7 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_voided'))
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
|
@ -170,17 +132,17 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
/**
|
||||
* Handle the successful payment for Bancontact.
|
||||
*
|
||||
* @param string $status
|
||||
* @param ResourcesPayment $payment
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @param string $status The payment status (default: 'paid')
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment, string $status = 'paid'): RedirectResponse
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $molliePayment, string $status = 'paid'): RedirectResponse
|
||||
{
|
||||
$data = [
|
||||
'gateway_type_id' => GatewayType::BANCONTACT,
|
||||
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::BANCONTACT,
|
||||
'transaction_reference' => $payment->id,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment(
|
||||
|
|
@ -189,7 +151,7 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
['response' => $molliePayment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
|
|
@ -203,17 +165,45 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
/**
|
||||
* Handle 'open' payment status for Bancontact.
|
||||
*
|
||||
* @param ResourcesPayment $payment
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processOpenPayment(\Mollie\Api\Resources\Payment $payment): RedirectResponse
|
||||
public function processOpenPayment(\Mollie\Api\Resources\Payment $molliePayment): RedirectResponse
|
||||
{
|
||||
return $this->processSuccessfulPayment($payment, 'open');
|
||||
return $this->processSuccessfulPayment($molliePayment, 'open');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param \Exception $exception The exception that was thrown
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $exception): \Illuminate\Http\Response
|
||||
{
|
||||
$this->mollie->sendFailureMail($exception->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$exception->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
$response = response([
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
]);
|
||||
|
||||
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function livewirePaymentView(array $data): string
|
||||
{
|
||||
// Doesn't support, it's offsite payment method.
|
||||
|
|
@ -221,9 +211,7 @@ class Bancontact implements MethodInterface, LivewireMethodInterface
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function paymentData(array $data): array
|
||||
{
|
||||
$this->paymentView($data);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ use App\PaymentDrivers\MolliePaymentDriver;
|
|||
use Exception;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\View\View;
|
||||
use Mollie\Api\Resources\Payment as ResourcesPayment;
|
||||
|
||||
|
|
@ -40,33 +39,21 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
$this->mollie->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the authorization page for bank transfer.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeView(array $data): View
|
||||
{
|
||||
return render('gateways.mollie.bank_transfer.authorize', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the authorization for bank transfer.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeResponse(Request $request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the payment page for bank transfer.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Http\RedirectResponseor|RedirectResponse
|
||||
* @throws \Exception
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
|
|
@ -98,44 +85,17 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
|
||||
return redirect(
|
||||
$payment->getCheckoutUrl()
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
return redirect($payment->getCheckoutUrl());
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param Exception $e
|
||||
* @throws PaymentFailed
|
||||
* @return void
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function processUnsuccessfulPayment(Exception $e): void
|
||||
{
|
||||
$this->mollie->sendFailureMail($e->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$e->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the payments for the bank transfer.
|
||||
*
|
||||
* @param PaymentResponseRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
public function paymentResponse(PaymentResponseRequest $request): \Illuminate\Http\Response|RedirectResponse
|
||||
{
|
||||
if (! \property_exists($this->mollie->payment_hash->data, 'payment_id')) {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
|
|
@ -144,22 +104,22 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
}
|
||||
|
||||
try {
|
||||
$payment = $this->mollie->gateway->payments->get(
|
||||
$molliePayment = $this->mollie->gateway->payments->get(
|
||||
$this->mollie->payment_hash->data->payment_id
|
||||
);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
if ($molliePayment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'open') {
|
||||
return $this->processOpenPayment($payment);
|
||||
if ($molliePayment->status === 'open') {
|
||||
return $this->processOpenPayment($molliePayment);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_voided'))
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
|
@ -167,17 +127,17 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
/**
|
||||
* Handle the successful payment for bank transfer.
|
||||
*
|
||||
* @param ResourcesPayment $payment
|
||||
* @param string $status
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @param string $status The payment status (default: 'paid')
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processSuccessfulPayment(ResourcesPayment $payment, $status = 'paid'): RedirectResponse
|
||||
public function processSuccessfulPayment(ResourcesPayment $molliePayment, $status = 'paid'): RedirectResponse
|
||||
{
|
||||
$data = [
|
||||
'gateway_type_id' => GatewayType::BANK_TRANSFER,
|
||||
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::MOLLIE_BANK_TRANSFER,
|
||||
'transaction_reference' => $payment->id,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment(
|
||||
|
|
@ -186,7 +146,7 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
['response' => $molliePayment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
|
|
@ -200,17 +160,45 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
/**
|
||||
* Handle 'open' payment status for bank transfer.
|
||||
*
|
||||
* @param ResourcesPayment $payment
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processOpenPayment(ResourcesPayment $payment): RedirectResponse
|
||||
public function processOpenPayment(ResourcesPayment $molliePayment): RedirectResponse
|
||||
{
|
||||
return $this->processSuccessfulPayment($payment, 'open');
|
||||
return $this->processSuccessfulPayment($molliePayment, 'open');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param \Exception $e The exception that was thrown
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function processUnsuccessfulPayment(Exception $e): \Illuminate\Http\Response
|
||||
{
|
||||
$this->mollie->sendFailureMail($e->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$e->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
$response = response([
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
]);
|
||||
|
||||
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function livewirePaymentView(array $data): string
|
||||
{
|
||||
// Doesn't support, it's offsite payment method.
|
||||
|
|
@ -218,9 +206,7 @@ class BankTransfer implements MethodInterface, LivewireMethodInterface
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function paymentData(array $data): array
|
||||
{
|
||||
$this->paymentView($data);
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ use App\Models\Payment;
|
|||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Common\LivewireMethodInterface;
|
||||
use App\PaymentDrivers\Common\MethodInterface;
|
||||
use App\PaymentDrivers\MolliePaymentDriver;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class CreditCard implements LivewireMethodInterface
|
||||
class CreditCard implements MethodInterface, LivewireMethodInterface
|
||||
{
|
||||
/**
|
||||
* @var MolliePaymentDriver
|
||||
|
|
@ -30,12 +30,19 @@ class CreditCard implements LivewireMethodInterface
|
|||
$this->mollie->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the page for credit card payments.
|
||||
*
|
||||
* @param array $data
|
||||
* @return Factory|View
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeView(array $data): View
|
||||
{
|
||||
return render('gateways.mollie.credit_card.authorize', $data);
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function authorizeResponse($request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
$data = $this->paymentData($data);
|
||||
|
|
@ -44,12 +51,10 @@ class CreditCard implements LivewireMethodInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a payment object.
|
||||
*
|
||||
* @param PaymentResponseRequest $request
|
||||
* @return mixed
|
||||
* @throws PaymentFailed When the payment processing fails
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
public function paymentResponse(PaymentResponseRequest $request): \Illuminate\Http\Response|RedirectResponse
|
||||
{
|
||||
$amount = $this->mollie->convertToMollieAmount((float) $this->mollie->payment_hash->data->amount_with_fee);
|
||||
|
||||
|
|
@ -63,8 +68,8 @@ class CreditCard implements LivewireMethodInterface
|
|||
try {
|
||||
$cgt = ClientGatewayToken::where('token', $request->token)->firstOrFail();
|
||||
|
||||
$payment = $this->mollie->gateway->payments->create([
|
||||
'method' => 'creditcard',
|
||||
$molliePayment = $this->mollie->gateway->payments->create([
|
||||
'method' => 'creditcard',
|
||||
'amount' => [
|
||||
'currency' => $this->mollie->client->currency()->code,
|
||||
'value' => $amount,
|
||||
|
|
@ -83,22 +88,22 @@ class CreditCard implements LivewireMethodInterface
|
|||
],
|
||||
]);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
if ($molliePayment->status === 'paid') {
|
||||
$this->mollie->logSuccessfulGatewayResponse(
|
||||
['response' => $payment, 'data' => $this->mollie->payment_hash->data],
|
||||
['response' => $molliePayment, 'data' => $this->mollie->payment_hash->data],
|
||||
SystemLog::TYPE_MOLLIE
|
||||
);
|
||||
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'open') {
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
if ($molliePayment->status === 'open') {
|
||||
$this->mollie->payment_hash->withData('payment_id', $molliePayment->id);
|
||||
|
||||
if (!$payment->getCheckoutUrl()) {
|
||||
if (!$molliePayment->getCheckoutUrl()) {
|
||||
return render('gateways.mollie.mollie_placeholder');
|
||||
} else {
|
||||
return redirect()->away($payment->getCheckoutUrl());
|
||||
return redirect()->away($molliePayment->getCheckoutUrl());
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
|
@ -131,43 +136,50 @@ class CreditCard implements LivewireMethodInterface
|
|||
];
|
||||
|
||||
if ($request->shouldStoreToken()) {
|
||||
$customer = $this->mollie->gateway->customers->create([
|
||||
'name' => $this->mollie->client->name,
|
||||
'email' => $this->mollie->client->present()->email(),
|
||||
'metadata' => [
|
||||
'id' => $this->mollie->client->hashed_id,
|
||||
],
|
||||
]);
|
||||
// Check if a mollie CustomerId already exists for this client, if so, use that
|
||||
$gateway_customer_reference = null;
|
||||
if ($this->mollie->client->gateway_tokens->count() > 0) {
|
||||
$gateway_customer_reference = $this->mollie->client->gateway_tokens->first()->gateway_customer_reference;
|
||||
} else {
|
||||
$customer = $this->mollie->gateway->customers->create([
|
||||
'name' => $this->mollie->client->name,
|
||||
'email' => $this->mollie->client->present()->email(),
|
||||
'metadata' => [
|
||||
'id' => $this->mollie->client->hashed_id,
|
||||
],
|
||||
]);
|
||||
$gateway_customer_reference = $customer->id;
|
||||
}
|
||||
|
||||
$data['customerId'] = $customer->id;
|
||||
$data['customerId'] = $gateway_customer_reference;
|
||||
$data['sequenceType'] = 'first';
|
||||
|
||||
$this->mollie->payment_hash
|
||||
->withData('mollieCustomerId', $customer->id)
|
||||
->withData('mollieCustomerId', $gateway_customer_reference)
|
||||
->withData('shouldStoreToken', true);
|
||||
}
|
||||
|
||||
$payment = $this->mollie->gateway->payments->create($data);
|
||||
$molliePayment = $this->mollie->gateway->payments->create($data);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
if ($molliePayment->status === 'paid') {
|
||||
$this->mollie->logSuccessfulGatewayResponse(
|
||||
['response' => $payment, 'data' => $this->mollie->payment_hash->data],
|
||||
['response' => $molliePayment, 'data' => $this->mollie->payment_hash->data],
|
||||
SystemLog::TYPE_MOLLIE
|
||||
);
|
||||
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'open') {
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
if ($molliePayment->status === 'open') {
|
||||
$this->mollie->payment_hash->withData('payment_id', $molliePayment->id);
|
||||
|
||||
nlog("Mollie");
|
||||
nlog($payment);
|
||||
nlog($molliePayment);
|
||||
|
||||
if (!$payment->getCheckoutUrl()) {
|
||||
return render('gateways.mollie.mollie_placeholder');
|
||||
if (!$molliePayment->getCheckoutUrl()) {
|
||||
return response()->render('gateways.mollie.mollie_placeholder');
|
||||
} else {
|
||||
return redirect()->away($payment->getCheckoutUrl());
|
||||
return redirect()->away($molliePayment->getCheckoutUrl());
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
|
@ -175,44 +187,32 @@ class CreditCard implements LivewireMethodInterface
|
|||
|
||||
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||
}
|
||||
return response()->render('gateways.mollie.mollie_placeholder');
|
||||
}
|
||||
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment)
|
||||
/**
|
||||
* Process a successful credit card payment.
|
||||
*
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $molliePayment): RedirectResponse
|
||||
{
|
||||
$payment_hash = $this->mollie->payment_hash;
|
||||
|
||||
if (property_exists($payment_hash->data, 'shouldStoreToken') && $payment_hash->data->shouldStoreToken) {
|
||||
try {
|
||||
$mandates = \iterator_to_array($this->mollie->gateway->mandates->listForId($payment_hash->data->mollieCustomerId));
|
||||
} catch (\Mollie\Api\Exceptions\ApiException $e) {
|
||||
return $this->processUnsuccessfulPayment($e);
|
||||
}
|
||||
|
||||
$payment_meta = new \stdClass();
|
||||
$payment_meta->exp_month = (string) $mandates[0]->details->cardExpiryDate;
|
||||
$payment_meta->exp_year = (string) '';
|
||||
$payment_meta->brand = (string) $mandates[0]->details->cardLabel;
|
||||
$payment_meta->last4 = (string) $mandates[0]->details->cardNumber;
|
||||
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||
|
||||
$this->mollie->storeGatewayToken([
|
||||
'token' => $mandates[0]->id,
|
||||
'payment_method_id' => GatewayType::CREDIT_CARD,
|
||||
'payment_meta' => $payment_meta,
|
||||
], ['gateway_customer_reference' => $payment_hash->data->mollieCustomerId]);
|
||||
}
|
||||
$this->mollie->createClientGatewayTokenFromMolliePayment($molliePayment);
|
||||
|
||||
$data = [
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'transaction_reference' => $payment->id,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment($data, $payment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING);
|
||||
$payment_record = $this->mollie->createPayment($data, $molliePayment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
['response' => $molliePayment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
|
|
@ -223,7 +223,14 @@ class CreditCard implements LivewireMethodInterface
|
|||
return redirect()->route('client.payments.show', ['payment' => $this->mollie->encodePrimaryKey($payment_record->id)]);
|
||||
}
|
||||
|
||||
public function processUnsuccessfulPayment(\Exception $e)
|
||||
/**
|
||||
* Handle an unsuccessful payment attempt.
|
||||
*
|
||||
* @param \Exception $e The exception that was thrown
|
||||
* @throws PaymentFailed Always throws a PaymentFailed exception
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $e): \Illuminate\Http\Response
|
||||
{
|
||||
$this->mollie->sendFailureMail($e->getMessage());
|
||||
|
||||
|
|
@ -236,42 +243,23 @@ class CreditCard implements LivewireMethodInterface
|
|||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
$response = response([
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
]);
|
||||
|
||||
throw new PaymentFailed($e->getMessage(), $e->getCode());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show authorization page.
|
||||
*
|
||||
* @param array $data
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
return render('gateways.mollie.credit_card.authorize', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle authorization response.
|
||||
*
|
||||
* @param mixed $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function authorizeResponse($request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function livewirePaymentView(array $data): string
|
||||
{
|
||||
return 'gateways.mollie.credit_card.pay_livewire';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function paymentData(array $data): array
|
||||
{
|
||||
$data['gateway'] = $this->mollie;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ use App\PaymentDrivers\MolliePaymentDriver;
|
|||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
use Mollie\Api\Exceptions\ApiException;
|
||||
|
||||
class IDEAL implements MethodInterface, LivewireMethodInterface
|
||||
{
|
||||
|
|
@ -37,33 +38,21 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
$this->mollie->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the authorization page for iDEAL.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeView(array $data): View
|
||||
{
|
||||
return render('gateways.mollie.ideal.authorize', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the authorization for iDEAL.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeResponse(Request $request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the payment page for iDEAL.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Http\RedirectResponseor|RedirectResponse
|
||||
* @throws \Exception
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
|
|
@ -72,7 +61,7 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
->withData('client_id', $this->mollie->client->id);
|
||||
|
||||
try {
|
||||
$payment = $this->mollie->gateway->payments->create([
|
||||
$data = [
|
||||
'method' => 'ideal',
|
||||
'amount' => [
|
||||
'currency' => $this->mollie->client->currency()->code,
|
||||
|
|
@ -91,48 +80,48 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
'gateway_type_id' => GatewayType::IDEAL,
|
||||
'payment_type_id' => PaymentType::IDEAL,
|
||||
],
|
||||
]);
|
||||
];
|
||||
|
||||
if ($this->mollie->company_gateway->token_billing == 'always') {
|
||||
// Check if a mollie CustomerId already exists for this client, if so, use that
|
||||
$gateway_customer_reference = null;
|
||||
if ($this->mollie->client->gateway_tokens->count() > 0) {
|
||||
$gateway_customer_reference = $this->mollie->client->gateway_tokens->first()->gateway_customer_reference;
|
||||
}
|
||||
if (!$gateway_customer_reference) {
|
||||
$customer = $this->mollie->gateway->customers->create([
|
||||
'name' => $this->mollie->client->name,
|
||||
'email' => $this->mollie->client->present()->email(),
|
||||
'metadata' => [
|
||||
'id' => $this->mollie->client->hashed_id,
|
||||
],
|
||||
]);
|
||||
$gateway_customer_reference = $customer->id;
|
||||
}
|
||||
|
||||
$data['customerId'] = $gateway_customer_reference;
|
||||
$data['sequenceType'] = 'first';
|
||||
|
||||
$this->mollie->payment_hash
|
||||
->withData('mollieCustomerId', $gateway_customer_reference)
|
||||
->withData('shouldStoreToken', true);
|
||||
}
|
||||
|
||||
$payment = $this->mollie->gateway->payments->create($data);
|
||||
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
|
||||
return redirect(
|
||||
$payment->getCheckoutUrl()
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
return redirect($payment->getCheckoutUrl());
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param Exception $exception
|
||||
* @throws PaymentFailed
|
||||
* @return void
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $exception): void
|
||||
{
|
||||
$this->mollie->sendFailureMail($exception->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$exception->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the payments for the iDEAL.
|
||||
*
|
||||
* @param PaymentResponseRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
public function paymentResponse(PaymentResponseRequest $request): \Illuminate\Http\Response|RedirectResponse
|
||||
{
|
||||
if (! \property_exists($this->mollie->payment_hash->data, 'payment_id')) {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
|
|
@ -141,19 +130,19 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
}
|
||||
|
||||
try {
|
||||
$payment = $this->mollie->gateway->payments->get(
|
||||
$molliePayment = $this->mollie->gateway->payments->get(
|
||||
$this->mollie->payment_hash->data->payment_id
|
||||
);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
if ($molliePayment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'open') {
|
||||
return $this->processOpenPayment($payment);
|
||||
if ($molliePayment->status === 'open') {
|
||||
return $this->processOpenPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'failed') {
|
||||
if ($molliePayment->status === 'failed') {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_failed'))
|
||||
);
|
||||
|
|
@ -162,7 +151,7 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_voided'))
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
|
@ -170,16 +159,21 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
/**
|
||||
* Handle the successful payment for iDEAL.
|
||||
*
|
||||
* @param string $status
|
||||
* @param ResourcesPayment $payment
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @param string $status The payment status (default: 'paid')
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment, string $status = 'paid'): RedirectResponse
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $molliePayment, string $status = 'paid'): RedirectResponse
|
||||
{
|
||||
$p = \App\Models\Payment::query()
|
||||
->withTrashed()
|
||||
$payment_hash = $this->mollie->payment_hash;
|
||||
|
||||
$this->mollie->createClientGatewayTokenFromMolliePayment($molliePayment);
|
||||
|
||||
/** @var \App\Models\Payment $p */
|
||||
$p = \App\Models\Payment::withTrashed()
|
||||
->where('company_id', $this->mollie->client->company_id)
|
||||
->where('transaction_reference', $payment->id)
|
||||
->where('transaction_reference', $molliePayment->id)
|
||||
->first();
|
||||
|
||||
if ($p) {
|
||||
|
|
@ -193,8 +187,7 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
'gateway_type_id' => GatewayType::IDEAL,
|
||||
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::IDEAL,
|
||||
'transaction_reference' => $payment->id,
|
||||
'idempotency_key' => substr("{$payment->id}{$this->mollie->payment_hash->hash}", 0, 64)
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment(
|
||||
|
|
@ -203,7 +196,7 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
['response' => $molliePayment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
|
|
@ -215,19 +208,48 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Handle 'open' payment status for IDEAL.
|
||||
* Handle 'open' payment status for iDEAL.
|
||||
*
|
||||
* @param ResourcesPayment $payment
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function processOpenPayment(\Mollie\Api\Resources\Payment $payment): RedirectResponse
|
||||
public function processOpenPayment(\Mollie\Api\Resources\Payment $molliePayment): RedirectResponse
|
||||
{
|
||||
return $this->processSuccessfulPayment($payment, 'open');
|
||||
return $this->processSuccessfulPayment($molliePayment, 'open');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param \Exception $exception The exception that was thrown
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $exception): \Illuminate\Http\Response
|
||||
{
|
||||
$this->mollie->sendFailureMail($exception->getMessage());
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$exception->getMessage(),
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
$response = response([
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
]);
|
||||
|
||||
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
public function livewirePaymentView(array $data): string
|
||||
{
|
||||
// Doesn't support, it's offsite payment method.
|
||||
|
|
@ -235,9 +257,7 @@ class IDEAL implements MethodInterface, LivewireMethodInterface
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function paymentData(array $data): array
|
||||
{
|
||||
$this->paymentView($data);
|
||||
|
|
|
|||
|
|
@ -37,33 +37,21 @@ class KBC implements MethodInterface, LivewireMethodInterface
|
|||
$this->mollie->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the authorization page for KBC.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeView(array $data): View
|
||||
{
|
||||
return render('gateways.mollie.kbc.authorize', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the authorization for KBC.
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function authorizeResponse(Request $request): RedirectResponse
|
||||
{
|
||||
return redirect()->route('client.payment_methods.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the payment page for KBC.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Illuminate\Http\RedirectResponseor|RedirectResponse
|
||||
* @throws \Exception
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentView(array $data)
|
||||
{
|
||||
|
|
@ -95,22 +83,87 @@ class KBC implements MethodInterface, LivewireMethodInterface
|
|||
|
||||
$this->mollie->payment_hash->withData('payment_id', $payment->id);
|
||||
|
||||
return redirect(
|
||||
$payment->getCheckoutUrl()
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
return redirect($payment->getCheckoutUrl());
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request): \Illuminate\Http\Response|RedirectResponse
|
||||
{
|
||||
if (! \property_exists($this->mollie->payment_hash->data, 'payment_id')) {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed('Whoops, something went wrong. Missing required [payment_id] parameter. Please contact administrator. Reference hash: '.$this->mollie->payment_hash->hash)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$molliePayment = $this->mollie->gateway->payments->get(
|
||||
$this->mollie->payment_hash->data->payment_id
|
||||
);
|
||||
|
||||
if ($molliePayment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($molliePayment);
|
||||
}
|
||||
|
||||
if ($molliePayment->status === 'failed') {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_failed'))
|
||||
);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_voided'))
|
||||
);
|
||||
} catch (\Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the successful payment for KBC.
|
||||
*
|
||||
* @param \Mollie\Api\Resources\Payment $molliePayment The Mollie payment object
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $molliePayment): RedirectResponse
|
||||
{
|
||||
$data = [
|
||||
'gateway_type_id' => GatewayType::KBC,
|
||||
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::KBC,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment(
|
||||
$data,
|
||||
$molliePayment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING
|
||||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $molliePayment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->mollie->encodePrimaryKey($payment_record->id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsuccessful payment.
|
||||
*
|
||||
* @param Exception $exception
|
||||
* @throws PaymentFailed
|
||||
* @return void
|
||||
* @param \Exception $exception The exception that was thrown
|
||||
* @throws PaymentFailed When the payment fails
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function processUnsuccessfulPayment(\Exception $exception): void
|
||||
public function processUnsuccessfulPayment(\Exception $exception): \Illuminate\Http\Response
|
||||
{
|
||||
$this->mollie->sendFailureMail($exception->getMessage());
|
||||
|
||||
|
|
@ -123,81 +176,17 @@ class KBC implements MethodInterface, LivewireMethodInterface
|
|||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
$response = response([
|
||||
'message' => $exception->getMessage(),
|
||||
'code' => $exception->getCode(),
|
||||
]);
|
||||
|
||||
throw new PaymentFailed($exception->getMessage(), $exception->getCode());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the payments for the KBC.
|
||||
*
|
||||
* @param PaymentResponseRequest $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function paymentResponse(PaymentResponseRequest $request)
|
||||
{
|
||||
if (! \property_exists($this->mollie->payment_hash->data, 'payment_id')) {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed('Whoops, something went wrong. Missing required [payment_id] parameter. Please contact administrator. Reference hash: '.$this->mollie->payment_hash->hash)
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$payment = $this->mollie->gateway->payments->get(
|
||||
$this->mollie->payment_hash->data->payment_id
|
||||
);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
return $this->processSuccessfulPayment($payment);
|
||||
}
|
||||
|
||||
if ($payment->status === 'failed') {
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_failed'))
|
||||
);
|
||||
}
|
||||
|
||||
return $this->processUnsuccessfulPayment(
|
||||
new PaymentFailed(ctrans('texts.status_voided'))
|
||||
);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException | \Exception $exception) {
|
||||
return $this->processUnsuccessfulPayment($exception);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the successful payment for KBC.
|
||||
*
|
||||
* @param ResourcesPayment $payment
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function processSuccessfulPayment(\Mollie\Api\Resources\Payment $payment): RedirectResponse
|
||||
{
|
||||
$data = [
|
||||
'gateway_type_id' => GatewayType::KBC,
|
||||
'amount' => array_sum(array_column($this->mollie->payment_hash->invoices(), 'amount')) + $this->mollie->payment_hash->fee_total,
|
||||
'payment_type' => PaymentType::KBC,
|
||||
'transaction_reference' => $payment->id,
|
||||
];
|
||||
|
||||
$payment_record = $this->mollie->createPayment(
|
||||
$data,
|
||||
$payment->status === 'paid' ? Payment::STATUS_COMPLETED : Payment::STATUS_PENDING
|
||||
);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->mollie->client,
|
||||
$this->mollie->client->company,
|
||||
);
|
||||
|
||||
return redirect()->route('client.payments.show', ['payment' => $this->mollie->encodePrimaryKey($payment_record->id)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function livewirePaymentView(array $data): string
|
||||
{
|
||||
// Doesn't support, it's offsite payment method.
|
||||
|
|
@ -205,9 +194,7 @@ class KBC implements MethodInterface, LivewireMethodInterface
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
/** @inheritDoc */
|
||||
public function paymentData(array $data): array
|
||||
{
|
||||
$this->paymentView($data);
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ use App\PaymentDrivers\Mollie\CreditCard;
|
|||
use App\PaymentDrivers\Mollie\IDEAL;
|
||||
use App\PaymentDrivers\Mollie\KBC;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Mollie\Api\Exceptions\ApiException;
|
||||
use Mollie\Api\MollieApiClient;
|
||||
|
|
@ -76,6 +78,11 @@ class MolliePaymentDriver extends BaseDriver
|
|||
|
||||
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_MOLLIE;
|
||||
|
||||
/**
|
||||
* Initialize the Mollie API client with the API key from the company gateway.
|
||||
*
|
||||
* @return self Returns the current instance for method chaining.
|
||||
*/
|
||||
public function init(): self
|
||||
{
|
||||
$this->gateway = new MollieApiClient();
|
||||
|
|
@ -87,6 +94,11 @@ class MolliePaymentDriver extends BaseDriver
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of supported gateway types for Mollie.
|
||||
*
|
||||
* @return array Array of supported gateway type constants.
|
||||
*/
|
||||
public function gatewayTypes(): array
|
||||
{
|
||||
$types = [];
|
||||
|
|
@ -100,30 +112,65 @@ class MolliePaymentDriver extends BaseDriver
|
|||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the payment method for the current transaction.
|
||||
*
|
||||
* @param string $payment_method_id The payment method identifier
|
||||
* @return self Returns the current instance for method chaining.
|
||||
* @throws \Exception When the payment method is not supported
|
||||
*/
|
||||
public function setPaymentMethod($payment_method_id)
|
||||
{
|
||||
$class = self::$methods[$payment_method_id];
|
||||
if (!isset(self::$methods[$payment_method_id])) {
|
||||
throw new \Exception("Payment method not supported: " . $payment_method_id);
|
||||
}
|
||||
|
||||
$class = self::$methods[$payment_method_id];
|
||||
$this->payment_method = new $class($this);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the authorization page for the payment method.
|
||||
*
|
||||
* @param array $data Payment method data
|
||||
* @return mixed The response from the payment method's authorizeView method
|
||||
*/
|
||||
public function authorizeView(array $data)
|
||||
{
|
||||
return $this->payment_method->authorizeView($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the authorization response from the payment gateway.
|
||||
*
|
||||
* @param mixed $request The authorization request
|
||||
* @return mixed The response from the payment method's authorizeResponse method
|
||||
*/
|
||||
public function authorizeResponse($request)
|
||||
{
|
||||
return $this->payment_method->authorizeResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the payment page for the payment method.
|
||||
*
|
||||
* @param array $data Payment data
|
||||
* @return mixed The response from the payment method's paymentView method
|
||||
*/
|
||||
public function processPaymentView(array $data)
|
||||
{
|
||||
return $this->payment_method->paymentView($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the payment response from the payment gateway.
|
||||
*
|
||||
* @param mixed $request The payment response request
|
||||
* @return mixed The response from the payment method's paymentResponse method
|
||||
* @throws \Exception When the payment processing fails
|
||||
*/
|
||||
public function processPaymentResponse($request)
|
||||
{
|
||||
return $this->payment_method->paymentResponse($request);
|
||||
|
|
@ -134,33 +181,23 @@ class MolliePaymentDriver extends BaseDriver
|
|||
$this->init();
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->get($payment->transaction_reference);
|
||||
$molliePayment = $this->gateway->payments->get($payment->transaction_reference);
|
||||
|
||||
$refund = $this->gateway->payments->refund($payment, [
|
||||
$refund = $this->gateway->payments->refund($molliePayment, [
|
||||
'amount' => [
|
||||
'currency' => $this->client->currency()->code,
|
||||
'value' => $this->convertToMollieAmount((float) $amount),
|
||||
],
|
||||
]);
|
||||
|
||||
if ($refund->status === 'refunded') {
|
||||
SystemLogger::dispatch(
|
||||
['server_response' => $refund, 'data' => request()->all()],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
|
||||
return [
|
||||
'transaction_reference' => $refund->id,
|
||||
'transaction_response' => json_encode($refund),
|
||||
'success' => $refund->status === 'refunded' ? true : false, //@phpstan-ignore-line
|
||||
'description' => $refund->description,
|
||||
'code' => 200,
|
||||
];
|
||||
}
|
||||
SystemLogger::dispatch(
|
||||
['server_response' => $refund, 'data' => request()->all()],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
|
||||
return [
|
||||
'transaction_reference' => $refund->id,
|
||||
|
|
@ -191,7 +228,15 @@ class MolliePaymentDriver extends BaseDriver
|
|||
}
|
||||
}
|
||||
|
||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||
/**
|
||||
* Process a payment using a stored payment token.
|
||||
*
|
||||
* @param ClientGatewayToken $cgt The client gateway token containing payment method details
|
||||
* @param PaymentHash $payment_hash The payment hash containing payment details
|
||||
* @return Payment|null The created payment or null if payment fails
|
||||
* @throws \Exception When there's an error processing the payment
|
||||
*/
|
||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash): ?Payment
|
||||
{
|
||||
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||
$invoice = Invoice::query()->whereIn('id', $this->transformKeys(array_column($payment_hash->invoices(), 'invoice_id')))->withTrashed()->first();
|
||||
|
|
@ -209,7 +254,7 @@ class MolliePaymentDriver extends BaseDriver
|
|||
$this->init();
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->create([
|
||||
$molliePayment = $this->gateway->payments->create([
|
||||
'amount' => [
|
||||
'currency' => $this->client->currency()->code,
|
||||
'value' => $this->convertToMollieAmount($amount),
|
||||
|
|
@ -218,56 +263,8 @@ class MolliePaymentDriver extends BaseDriver
|
|||
'customerId' => $cgt->gateway_customer_reference,
|
||||
'sequenceType' => 'recurring',
|
||||
'description' => $description,
|
||||
'idempotencyKey' => uniqid("st", true),
|
||||
'webhookUrl' => $this->company_gateway->webhookUrl(),
|
||||
]);
|
||||
|
||||
if ($payment->status === 'paid') {
|
||||
|
||||
|
||||
$data = [
|
||||
'payment_method' => $cgt->token,
|
||||
'payment_type' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'amount' => $amount,
|
||||
'transaction_reference' => $payment->id,
|
||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||
];
|
||||
|
||||
$this->confirmGatewayFee($data);
|
||||
|
||||
$payment = $this->createPayment($data, Payment::STATUS_COMPLETED);
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
|
||||
return $payment;
|
||||
}
|
||||
|
||||
$this->unWindGatewayFees($payment_hash);
|
||||
|
||||
$this->sendFailureMail($payment->details);
|
||||
|
||||
$message = [
|
||||
'server_response' => $payment,
|
||||
'data' => $payment_hash->data,
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_CHECKOUT,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
|
||||
return false;
|
||||
} catch (ApiException $e) {
|
||||
$this->unWindGatewayFees($payment_hash);
|
||||
|
||||
|
|
@ -280,113 +277,261 @@ class MolliePaymentDriver extends BaseDriver
|
|||
];
|
||||
|
||||
SystemLogger::dispatch($data, SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_MOLLIE, $this->client, $this->client->company);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
$data = [
|
||||
'payment_method' => $cgt->token,
|
||||
'payment_type' => self::convertFromMolliePaymentType($molliePayment->method),
|
||||
'amount' => $amount,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
'gateway_type_id' => self::convertFromMollieGatewayType($molliePayment->method),
|
||||
];
|
||||
|
||||
$payment = $this->createPayment($data, self::convertFromMollieStatus($molliePayment->status));
|
||||
|
||||
SystemLogger::dispatch(
|
||||
['response' => $payment, 'data' => $data],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
return $payment;
|
||||
} catch (\Exception $e) {
|
||||
$this->unWindGatewayFees($payment_hash);
|
||||
|
||||
$this->sendFailureMail($molliePayment->details);
|
||||
|
||||
$message = [
|
||||
'server_response' => $molliePayment,
|
||||
'data' => $payment_hash->data,
|
||||
'exception' => $e->getMessage()
|
||||
];
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_CHECKOUT,
|
||||
$this->client,
|
||||
$this->client->company
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request)
|
||||
/**
|
||||
* Process an incoming webhook request from Mollie.
|
||||
*
|
||||
* @param PaymentWebhookRequest $request The webhook request
|
||||
* @return JsonResponse JSON response indicating success or failure
|
||||
* @throws \Exception When there's an error processing the webhook
|
||||
*/
|
||||
public function processWebhookRequest(PaymentWebhookRequest $request): JsonResponse
|
||||
{
|
||||
// Allow app to catch up with webhook request.
|
||||
// sleep(4);
|
||||
// Sometimes the webhook is called before the Client is sent back to InvoiceNinja,
|
||||
// since we first want the client to execute `$this->payment_method->paymentResponse()`
|
||||
// before processing the webhook, we wait a bit here.
|
||||
usleep(rand(1500000, 4000000));
|
||||
|
||||
$validator = Validator::make($request->all(), [
|
||||
'id' => ['required', 'starts_with:tr'],
|
||||
'id' => ['required', 'string', 'starts_with:tr', 'max:255'],
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return response()->json($validator->errors(), 422);
|
||||
}
|
||||
|
||||
nlog("Mollie webhook called with id: {$request->id}", $request->toArray());
|
||||
|
||||
$this->init();
|
||||
|
||||
$codes = [
|
||||
'open' => Payment::STATUS_PENDING,
|
||||
'canceled' => Payment::STATUS_CANCELLED,
|
||||
'pending' => Payment::STATUS_PENDING,
|
||||
'expired' => Payment::STATUS_CANCELLED,
|
||||
'failed' => Payment::STATUS_FAILED,
|
||||
'paid' => Payment::STATUS_COMPLETED,
|
||||
];
|
||||
|
||||
nlog($request->id);
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->get($request->id);
|
||||
$record = Payment::withTrashed()->where('transaction_reference', $request->id)->first();
|
||||
$molliePayment = $this->gateway->payments->get($request->id);
|
||||
if (!$molliePayment) {
|
||||
throw new \Exception('Mollie payment not found in the webhook request');
|
||||
}
|
||||
|
||||
if ($record) {
|
||||
$client = $record->client;
|
||||
$payment = Payment::withTrashed()->where('transaction_reference', $request->id)->first();
|
||||
|
||||
if (!$payment) {
|
||||
// Sometimes the user is not returned to the site with a response from Mollie
|
||||
// so we may not have a payment record. For these cases we need to re-construct the payment
|
||||
// record from the metadata in the payment hash.
|
||||
|
||||
if (!$molliePayment->metadata?->client_id) {
|
||||
throw new \Exception('No client_id found in Mollie payment metadata');
|
||||
}
|
||||
$client = Client::withTrashed()->find($this->decodePrimaryKey($molliePayment->metadata->client_id));
|
||||
$this->client = $client;
|
||||
|
||||
if (!$molliePayment->metadata?->hash) {
|
||||
throw new \Exception('No payment hash found in Mollie payment metadata');
|
||||
}
|
||||
$payment_hash = PaymentHash::where('hash', $molliePayment->metadata->hash)->firstOrFail();
|
||||
// If we are here, then we do not have access to the class payment hash, so lets set it here
|
||||
$this->payment_hash = $payment_hash;
|
||||
|
||||
$data = [
|
||||
'gateway_type_id' => $molliePayment->metadata->gateway_type_id,
|
||||
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
||||
'payment_type' => $molliePayment->metadata->payment_type_id,
|
||||
'transaction_reference' => $molliePayment->id,
|
||||
'idempotency_key' => substr("{$molliePayment->id}{$payment_hash->hash}", 0, 64)
|
||||
];
|
||||
|
||||
// Uses $this->payment_hash
|
||||
$this->confirmGatewayFee($data);
|
||||
|
||||
// Uses $this->payment_hash
|
||||
$payment = $this->createPayment(
|
||||
$data,
|
||||
self::convertFromMollieStatus($molliePayment->status)
|
||||
);
|
||||
} else {
|
||||
$client = Client::withTrashed()->find($this->decodePrimaryKey($payment->metadata->client_id));
|
||||
$client = $payment->client;
|
||||
$this->client = $client;
|
||||
// sometimes if the user is not returned to the site with a response from Mollie
|
||||
// we may not have a payment record - in these cases we need to re-construct the payment
|
||||
// record from the meta data in the payment hash.
|
||||
}
|
||||
|
||||
if ($payment && property_exists($payment->metadata, 'hash') && $payment->metadata->hash) {
|
||||
/* Harvest Payment Hash*/
|
||||
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
|
||||
$this->createClientGatewayTokenFromMolliePayment($molliePayment);
|
||||
|
||||
/* If we are here, then we do not have access to the class payment hash, so lets set it here*/
|
||||
$this->payment_hash = $payment_hash;
|
||||
$status = self::convertFromMollieStatus($molliePayment->status);
|
||||
if (in_array($status, [Payment::STATUS_CANCELLED, Payment::STATUS_FAILED])) {
|
||||
if ($molliePayment->metadata?->hash) {
|
||||
$payment_hash = PaymentHash::where('hash', $molliePayment->metadata->hash)->firstOrFail();
|
||||
$this->handlePendingGatewayFeeRemoval($payment_hash);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'gateway_type_id' => $payment->metadata->gateway_type_id,
|
||||
'amount' => $amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
||||
'payment_type' => $payment->metadata->payment_type_id,
|
||||
'transaction_reference' => $payment->id,
|
||||
'idempotency_key' => substr("{$payment->id}{$payment_hash->hash}", 0, 64)
|
||||
];
|
||||
// Sets payment status to cancelled synchronously and handles other consequences
|
||||
$payment->service()->deletePayment(false);
|
||||
}
|
||||
$payment->status_id = $status; // Set or overwrite payment status to the mollie status
|
||||
$payment->date = $molliePayment->paidAt ?: null;
|
||||
|
||||
$this->confirmGatewayFee($data);
|
||||
// Handle refunded amounts
|
||||
if ($molliePayment->amountRefunded?->currency === $payment->currency->code) {
|
||||
$payment->refunded = self::convertFromMollieAmount($molliePayment->amountRefunded->value);
|
||||
}
|
||||
|
||||
$record = $this->createPayment(
|
||||
$data,
|
||||
$codes[$payment->status]
|
||||
);
|
||||
// Handle remaining amount (applied amount)
|
||||
if ($molliePayment->amountRemaining?->currency === $payment->currency->code) {
|
||||
$payment->applied = self::convertFromMollieAmount($molliePayment->amountRemaining->value);
|
||||
} else {
|
||||
// If no remaining amount, use the full amount as applied for completed payments
|
||||
if ($molliePayment->isPaid() || $molliePayment->isAuthorized()) {
|
||||
$payment->applied = $payment->amount - ($payment->refunded ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
$message = [
|
||||
'server_response' => $payment,
|
||||
'data' => $request->all(),
|
||||
];
|
||||
|
||||
$response = SystemLog::EVENT_GATEWAY_FAILURE;
|
||||
|
||||
if ($record) {
|
||||
if (in_array($payment->status, ['canceled', 'expired', 'failed'])) {
|
||||
|
||||
if(property_exists($payment->metadata, 'hash') && $payment->metadata->hash){
|
||||
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
|
||||
$this->handlePendingGatewayFeeRemoval($payment_hash);
|
||||
}
|
||||
|
||||
$record->service()->deletePayment(false);
|
||||
|
||||
}
|
||||
|
||||
$record->status_id = $codes[$payment->status];
|
||||
$record->save();
|
||||
$response = SystemLog::EVENT_GATEWAY_SUCCESS;
|
||||
// Add description to private notes if not already present
|
||||
$private_notes = "description: " . $molliePayment->description;
|
||||
if (!str_contains($payment->private_notes, $private_notes)) {
|
||||
$payment->private_notes .= $private_notes;
|
||||
}
|
||||
|
||||
SystemLogger::dispatch(
|
||||
$message,
|
||||
$payment->save();
|
||||
|
||||
SystemLogger::dispatch([
|
||||
'request' => $request->toArray(),
|
||||
'mollie_payment' => $molliePayment,
|
||||
'payment' => $payment
|
||||
],
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
$response,
|
||||
SystemLog::EVENT_GATEWAY_SUCCESS,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$client,
|
||||
$client->company
|
||||
$this->client,
|
||||
$this->company_gateway->company
|
||||
);
|
||||
|
||||
return response()->json([], 200);
|
||||
} catch (ApiException $e) {
|
||||
return response()->json(['message' => $e->getMessage(), 'gatewayStatusCode' => $e->getCode()], 500);
|
||||
} catch (\Exception $e) {
|
||||
$ctx = [
|
||||
'request' => $request->toArray(),
|
||||
'exception' => $e
|
||||
];
|
||||
nlog("Mollie webhook call failed", $ctx);
|
||||
SystemLogger::dispatch($ctx,
|
||||
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||
SystemLog::EVENT_GATEWAY_FAILURE,
|
||||
SystemLog::TYPE_MOLLIE,
|
||||
$this->client,
|
||||
$this->company_gateway->company
|
||||
);
|
||||
}
|
||||
return response()->json([], 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores a Mollie mandateId as ClientGatewayToken based on the mollie customerId attached to a given Mollie Payment.
|
||||
* @param \Mollie\Api\Resources\Payment $payment
|
||||
* @return ClientGatewayToken|null Returns new ClientGatewayToken on success, null on failure or if token already exists
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function createClientGatewayTokenFromMolliePayment(\Mollie\Api\Resources\Payment $payment): ?ClientGatewayToken
|
||||
{
|
||||
if (!in_array($payment->status, ['paid'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$payment->metadata?->hash) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$payment_hash = PaymentHash::where('hash', $payment->metadata->hash)->first();
|
||||
|
||||
if (!$payment_hash || !property_exists($payment_hash->data, 'shouldStoreToken') || !$payment_hash->data->shouldStoreToken) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mandates = \iterator_to_array($this->gateway->mandates->listForId($payment_hash->data->mollieCustomerId));
|
||||
$mandate = !empty($mandates) ? $mandates[0] : null;
|
||||
|
||||
if (!$mandate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$token_already_exists = $this->client->gateway_tokens
|
||||
->where('token', $mandate->id)
|
||||
->where('company_gateway_id', $this->company_gateway->id)
|
||||
->first();
|
||||
|
||||
if ($token_already_exists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$payment_method_id = self::convertFromMollieGatewayType($mandate->method);
|
||||
$payment_meta = new \stdClass();
|
||||
$payment_meta->type = $payment_method_id;
|
||||
|
||||
if ($payment_method_id == GatewayType::CREDIT_CARD) {
|
||||
// Parse the card expiry date (format: YYYY-MM-DD)
|
||||
$dateParts = explode('-', $mandate->details->cardExpiryDate);
|
||||
if (count($dateParts) >= 2) {
|
||||
$payment_meta->exp_year = substr($dateParts[0], -2); // Last 2 digits of YYYY
|
||||
$payment_meta->exp_month = ltrim($dateParts[1], '0'); // MM (remove leading zero)
|
||||
}
|
||||
$payment_meta->brand = $mandate->details->cardLabel;
|
||||
$payment_meta->last4 = $mandate->details->cardNumber;
|
||||
} elseif ($payment_method_id == GatewayType::DIRECT_DEBIT) {
|
||||
$payment_meta->last4 = substr($mandate->details->consumerAccount, -4); // Last 4 characters
|
||||
$payment_meta->brand = "mollie";
|
||||
}
|
||||
|
||||
return $this->storeGatewayToken([
|
||||
'token' => $mandate->id,
|
||||
'payment_method_id' => $payment_method_id,
|
||||
'payment_meta' => $payment_meta,
|
||||
], ['gateway_customer_reference' => $payment_hash->data->mollieCustomerId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove pending gateway fees from an invoice.
|
||||
*
|
||||
* @param PaymentHash $payment_hash The payment hash containing fee information
|
||||
* @return void
|
||||
*/
|
||||
private function handlePendingGatewayFeeRemoval(PaymentHash $payment_hash)
|
||||
{
|
||||
$invoice = $payment_hash->fee_invoice;
|
||||
|
|
@ -402,27 +547,35 @@ class MolliePaymentDriver extends BaseDriver
|
|||
})->toArray();
|
||||
|
||||
$invoice->line_items = array_values($line_items);
|
||||
|
||||
$invoice = $invoice->calc()->getInvoice();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process 3D Secure confirmation for a payment.
|
||||
*
|
||||
* @param Mollie3dsRequest $request The 3DS confirmation request
|
||||
* @return mixed The result of the payment processing
|
||||
*/
|
||||
public function process3dsConfirmation(Mollie3dsRequest $request)
|
||||
{
|
||||
$this->init();
|
||||
|
||||
$this->setPaymentHash($request->getPaymentHash());
|
||||
|
||||
try {
|
||||
$payment = $this->gateway->payments->get($request->getPaymentId());
|
||||
|
||||
return (new CreditCard($this))->processSuccessfulPayment($payment);
|
||||
} catch (\Mollie\Api\Exceptions\ApiException $e) {
|
||||
return (new CreditCard($this))->processUnsuccessfulPayment($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detach a payment method by revoking the mandate from Mollie.
|
||||
*
|
||||
* @param ClientGatewayToken $token The client gateway token to detach
|
||||
* @return void
|
||||
*/
|
||||
public function detach(ClientGatewayToken $token)
|
||||
{
|
||||
$this->init();
|
||||
|
|
@ -455,18 +608,141 @@ class MolliePaymentDriver extends BaseDriver
|
|||
return \number_format((float) $amount, 2, '.', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Mollie amount string back to a float.
|
||||
*
|
||||
* @param string $amount The amount string from Mollie (e.g., "123.45")
|
||||
* @return float The converted amount as a float
|
||||
* @throws \InvalidArgumentException If the input is not a valid numeric string
|
||||
*/
|
||||
public static function convertFromMollieAmount(string $amount): float
|
||||
{
|
||||
if (!is_numeric($amount)) {
|
||||
throw new \InvalidArgumentException("Invalid amount format. Expected a numeric string, got: " . $amount);
|
||||
}
|
||||
|
||||
return (float) $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ISO 4217 currency code to InvoiceNinja currency ID
|
||||
*
|
||||
* @param string $currencyCode ISO 4217 currency code (e.g., 'EUR', 'USD')
|
||||
* @return int Returns the currency ID
|
||||
* @throws ModelNotFoundException When the currency is not found
|
||||
*/
|
||||
public static function convertFromMollieCurrency(string $currencyCode): int
|
||||
{
|
||||
$currency = \App\Models\Currency::where('code', strtoupper($currencyCode))->firstOrFail();
|
||||
return $currency->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Mollie payment method to PaymentType ID
|
||||
*
|
||||
* @param string $type
|
||||
* @return int
|
||||
* @throws \Exception When the payment method is not supported
|
||||
*/
|
||||
static public function convertFromMolliePaymentType(string $type): int
|
||||
{
|
||||
$types = [
|
||||
'banktransfer' => PaymentType::BANK_TRANSFER,
|
||||
'creditcard' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'directdebit' => PaymentType::DIRECT_DEBIT,
|
||||
'ideal' => PaymentType::IDEAL,
|
||||
'bancontact' => PaymentType::BANCONTACT,
|
||||
'sofort' => PaymentType::SOFORT,
|
||||
'klarnapaylater' => PaymentType::KLARNA,
|
||||
'klarnasliceit' => PaymentType::KLARNA,
|
||||
'klarnapaynow' => PaymentType::KLARNA,
|
||||
'kbc' => PaymentType::KBC,
|
||||
'eps' => PaymentType::EPS,
|
||||
'giropay' => PaymentType::GIROPAY,
|
||||
'p24' => PaymentType::PRZELEWY24,
|
||||
'applepay' => PaymentType::CREDIT_CARD_OTHER,
|
||||
'paypal' => PaymentType::PAYPAL,
|
||||
'belfius' => PaymentType::BANK_TRANSFER,
|
||||
'inghomepay' => PaymentType::BANK_TRANSFER,
|
||||
'giftcard' => PaymentType::CREDIT,
|
||||
'paysafecard' => PaymentType::CREDIT,
|
||||
'przelewy24' => PaymentType::PRZELEWY24,
|
||||
'mybank' => PaymentType::BANK_TRANSFER,
|
||||
'billet' => PaymentType::BANK_TRANSFER,
|
||||
'tikkiepayment' => PaymentType::BANK_TRANSFER,
|
||||
];
|
||||
|
||||
if (!array_key_exists($type, $types)) {
|
||||
throw new \Exception("Unsupported Mollie payment method: " . $type);
|
||||
}
|
||||
|
||||
return $types[$type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Mollie payment method to GatewayType ID
|
||||
*
|
||||
* @param string $type
|
||||
* @return int
|
||||
* @throws \Exception When the payment method is not supported
|
||||
*/
|
||||
static public function convertFromMollieGatewayType(string $type): int
|
||||
{
|
||||
$types = [
|
||||
'creditcard' => GatewayType::CREDIT_CARD,
|
||||
'directdebit' => GatewayType::DIRECT_DEBIT,
|
||||
'paypal' => GatewayType::PAYPAL,
|
||||
'bancontact' => GatewayType::BANCONTACT,
|
||||
'banktransfer' => GatewayType::BANK_TRANSFER,
|
||||
'kbc' => GatewayType::KBC,
|
||||
'ideal' => GatewayType::IDEAL,
|
||||
];
|
||||
|
||||
if (!isset($types[strtolower($type)])) {
|
||||
throw new \Exception("Unsupported Mollie payment method: " . $type);
|
||||
}
|
||||
|
||||
return $types[strtolower($type)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Mollie payment status to InvoiceNinja payment status
|
||||
*
|
||||
* @param string $mollieStatus
|
||||
* @return int
|
||||
*/
|
||||
private static function convertFromMollieStatus(string $mollieStatus): int
|
||||
{
|
||||
$statusMap = [
|
||||
'paid' => Payment::STATUS_COMPLETED,
|
||||
'authorized' => Payment::STATUS_PENDING,
|
||||
'pending' => Payment::STATUS_PENDING,
|
||||
'failed' => Payment::STATUS_FAILED,
|
||||
'expired' => Payment::STATUS_FAILED,
|
||||
'canceled' => Payment::STATUS_CANCELLED,
|
||||
'refunded' => Payment::STATUS_REFUNDED,
|
||||
'partially_refunded' => Payment::STATUS_PARTIALLY_REFUNDED,
|
||||
];
|
||||
|
||||
return $statusMap[strtolower($mollieStatus)] ?? Payment::STATUS_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the connection to the Mollie API.
|
||||
*
|
||||
* @return string 'ok' if the connection is successful, 'error' otherwise
|
||||
*/
|
||||
public function auth(): string
|
||||
{
|
||||
$this->init();
|
||||
|
||||
try {
|
||||
// Attempt to fetch a page of payments to test the connection
|
||||
$p = $this->gateway->payments->page();
|
||||
return 'ok';
|
||||
} catch (\Exception $e) {
|
||||
|
||||
// Log the error or handle it as needed
|
||||
return 'error';
|
||||
}
|
||||
|
||||
return 'error';
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue