mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-04 00:54:35 -04:00
Pay with credit card and save for future use
This commit is contained in:
parent
e306278547
commit
8af3cfe737
@ -37,6 +37,11 @@ class PaymentResponseRequest extends FormRequest
|
|||||||
return PaymentHash::whereRaw('BINARY `hash`= ?', [$input['payment_hash']])->first();
|
return PaymentHash::whereRaw('BINARY `hash`= ?', [$input['payment_hash']])->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shouldStoreToken(): bool
|
||||||
|
{
|
||||||
|
return (bool) $this->store_card;
|
||||||
|
}
|
||||||
|
|
||||||
public function prepareForValidation()
|
public function prepareForValidation()
|
||||||
{
|
{
|
||||||
if ($this->has('store_card')) {
|
if ($this->has('store_card')) {
|
||||||
|
@ -31,9 +31,9 @@ class CreditCard
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the page for credit card payments.
|
* Show the page for credit card payments.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @return Factory|View
|
* @return Factory|View
|
||||||
*/
|
*/
|
||||||
public function paymentView(array $data)
|
public function paymentView(array $data)
|
||||||
{
|
{
|
||||||
@ -44,9 +44,9 @@ class CreditCard
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a payment object.
|
* Create a payment object.
|
||||||
*
|
*
|
||||||
* @param PaymentResponseRequest $request
|
* @param PaymentResponseRequest $request
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function paymentResponse(PaymentResponseRequest $request)
|
public function paymentResponse(PaymentResponseRequest $request)
|
||||||
{
|
{
|
||||||
@ -58,16 +58,7 @@ class CreditCard
|
|||||||
->withData('client_id', $this->mollie->client->id);
|
->withData('client_id', $this->mollie->client->id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$customer = $this->mollie->gateway->customers->create([
|
$data = [
|
||||||
'name' => $this->mollie->client->name,
|
|
||||||
'metadata' => [
|
|
||||||
'id' => $this->mollie->client->hashed_id,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$payment = $this->mollie->gateway->payments->create([
|
|
||||||
'customerId' => $customer->id,
|
|
||||||
'sequenceType' => 'first',
|
|
||||||
'amount' => [
|
'amount' => [
|
||||||
'currency' => $this->mollie->client->currency()->code,
|
'currency' => $this->mollie->client->currency()->code,
|
||||||
'value' => $amount,
|
'value' => $amount,
|
||||||
@ -80,7 +71,26 @@ class CreditCard
|
|||||||
]),
|
]),
|
||||||
'webhookUrl' => 'https://invoiceninja.com',
|
'webhookUrl' => 'https://invoiceninja.com',
|
||||||
'cardToken' => $request->token,
|
'cardToken' => $request->token,
|
||||||
]);
|
];
|
||||||
|
|
||||||
|
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,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$data['customerId'] = $customer->id;
|
||||||
|
$data['sequenceType'] = 'first';
|
||||||
|
|
||||||
|
$this->mollie->payment_hash
|
||||||
|
->withData('mollieCustomerId', $customer->id)
|
||||||
|
->withData('shouldStoreToken', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$payment = $this->mollie->gateway->payments->create($data);
|
||||||
|
|
||||||
if ($payment->status === 'paid') {
|
if ($payment->status === 'paid') {
|
||||||
$this->mollie->logSuccessfulGatewayResponse(
|
$this->mollie->logSuccessfulGatewayResponse(
|
||||||
@ -107,6 +117,27 @@ class CreditCard
|
|||||||
{
|
{
|
||||||
$payment_hash = $this->mollie->payment_hash;
|
$payment_hash = $this->mollie->payment_hash;
|
||||||
|
|
||||||
|
if ($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,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
'gateway_type_id' => GatewayType::CREDIT_CARD,
|
||||||
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
|
||||||
@ -151,9 +182,9 @@ class CreditCard
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show authorization page.
|
* Show authorization page.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
* @return Factory|View
|
* @return Factory|View
|
||||||
*/
|
*/
|
||||||
public function authorizeView(array $data)
|
public function authorizeView(array $data)
|
||||||
{
|
{
|
||||||
@ -162,9 +193,9 @@ class CreditCard
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle authorization response.
|
* Handle authorization response.
|
||||||
*
|
*
|
||||||
* @param mixed $request
|
* @param mixed $request
|
||||||
* @return RedirectResponse
|
* @return RedirectResponse
|
||||||
*/
|
*/
|
||||||
public function authorizeResponse($request): RedirectResponse
|
public function authorizeResponse($request): RedirectResponse
|
||||||
{
|
{
|
||||||
|
@ -29,26 +29,19 @@ ctrans('texts.credit_card')])
|
|||||||
@include('portal.ninja2020.gateways.includes.payment_details')
|
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||||
@if(count($tokens) > 0)
|
@if (count($tokens) > 0)
|
||||||
@foreach($tokens as $token)
|
@foreach ($tokens as $token)
|
||||||
<label class="mr-4">
|
<label class="mr-4">
|
||||||
<input
|
<input type="radio" data-token="{{ $token->token }}" name="payment-type"
|
||||||
type="radio"
|
class="form-radio cursor-pointer toggle-payment-with-token" />
|
||||||
data-token="{{ $token->token }}"
|
|
||||||
name="payment-type"
|
|
||||||
class="form-radio cursor-pointer toggle-payment-with-token"/>
|
|
||||||
<span class="ml-1 cursor-pointer">**** {{ optional($token->meta)->last4 }}</span>
|
<span class="ml-1 cursor-pointer">**** {{ optional($token->meta)->last4 }}</span>
|
||||||
</label>
|
</label>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input type="radio" id="toggle-payment-with-credit-card" class="form-radio cursor-pointer" name="payment-type"
|
||||||
type="radio"
|
checked />
|
||||||
id="toggle-payment-with-credit-card"
|
|
||||||
class="form-radio cursor-pointer"
|
|
||||||
name="payment-type"
|
|
||||||
checked/>
|
|
||||||
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
|
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
|
||||||
</label>
|
</label>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
@ -83,13 +76,7 @@ ctrans('texts.credit_card')])
|
|||||||
</div>
|
</div>
|
||||||
@endcomponent
|
@endcomponent
|
||||||
|
|
||||||
@component('portal.ninja2020.components.general.card-element-single')
|
@include('portal.ninja2020.gateways.includes.save_card')
|
||||||
<span class="text-sm text-gray-900">If you want to save the card for future purchases, please click on the
|
|
||||||
<a href="{{ route('client.payment_methods.index') }}" class="underline text-primary">Payment methods</a> page and authorize the credit card manually.
|
|
||||||
</span>
|
|
||||||
|
|
||||||
<span class="text-sm text-gray-900">After that, come back to this page and select your payment method.</span>
|
|
||||||
@endcomponent
|
|
||||||
|
|
||||||
@include('portal.ninja2020.gateways.includes.pay_now')
|
@include('portal.ninja2020.gateways.includes.pay_now')
|
||||||
@endsection
|
@endsection
|
||||||
@ -193,6 +180,15 @@ ctrans('texts.credit_card')])
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tokenBillingCheckbox = document.querySelector(
|
||||||
|
'input[name="token-billing-checkbox"]:checked'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tokenBillingCheckbox) {
|
||||||
|
document.querySelector('input[name="store_card"]').value =
|
||||||
|
tokenBillingCheckbox.value;
|
||||||
|
}
|
||||||
|
|
||||||
document.querySelector('input[name=token]').value = token;
|
document.querySelector('input[name=token]').value = token;
|
||||||
document.getElementById('server-response').submit();
|
document.getElementById('server-response').submit();
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user