mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 01:57:30 -04:00 
			
		
		
		
	wip
This commit is contained in:
		
							parent
							
								
									99d0259365
								
							
						
					
					
						commit
						a29d4f2075
					
				| @ -68,6 +68,7 @@ class SystemLog extends Model | ||||
|     const TYPE_BRAINTREE = 307; | ||||
|     const TYPE_WEPAY = 309; | ||||
|     const TYPE_PAYFAST = 310; | ||||
|     const TYPE_MOLLIE = 311; | ||||
|      | ||||
| 
 | ||||
|     const TYPE_QUOTA_EXCEEDED = 400; | ||||
|  | ||||
							
								
								
									
										63
									
								
								app/PaymentDrivers/Mollie/CreditCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								app/PaymentDrivers/Mollie/CreditCard.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace App\PaymentDrivers\Mollie; | ||||
| 
 | ||||
| use App\Exceptions\PaymentFailed; | ||||
| use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; | ||||
| use App\PaymentDrivers\MolliePaymentDriver; | ||||
| use Illuminate\Contracts\View\Factory; | ||||
| use Illuminate\View\View; | ||||
| use Illuminate\Contracts\Container\BindingResolutionException; | ||||
| 
 | ||||
| use function Symfony\Component\String\b; | ||||
| 
 | ||||
| class CreditCard | ||||
| { | ||||
|     /** | ||||
|      * @var MolliePaymentDriver | ||||
|      */ | ||||
|     protected $mollie; | ||||
| 
 | ||||
|     public function __construct(MolliePaymentDriver $mollie) | ||||
|     { | ||||
|         $this->mollie = $mollie; | ||||
| 
 | ||||
|         $this->mollie->init(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show the page for credit card payments. | ||||
|      *  | ||||
|      * @param array $data  | ||||
|      * @return Factory|View  | ||||
|      */ | ||||
|     public function paymentView(array $data) | ||||
|     { | ||||
|         $data['gateway'] = $this->mollie; | ||||
| 
 | ||||
|         return render('gateways.mollie.credit_card.pay', $data); | ||||
|     } | ||||
| 
 | ||||
|     public function paymentResponse(PaymentResponseRequest $request) | ||||
|     { | ||||
|         try { | ||||
|             $payment = $this->mollie->gateway->payments->create([ | ||||
|                 "amount" => [ | ||||
|                     "currency" => "USD", | ||||
|                     "value" => "10.00" | ||||
|                 ], | ||||
|                 "description" => "Order #12345", | ||||
|                 "redirectUrl" => "https://webshop.example.org/order/12345/", | ||||
|                 "webhookUrl"  => "https://webshop.example.org/mollie-webhook/", | ||||
|             ]); | ||||
| 
 | ||||
|             if ($payment->status === 'open') { | ||||
|                 return redirect($payment->getCheckoutUrl()); | ||||
|             } | ||||
|         } catch (\Exception $e) { | ||||
|             throw new PaymentFailed($e->getMessage(), $e->getCode()); | ||||
|         } | ||||
| 
 | ||||
|         dd($payment); | ||||
|     } | ||||
| } | ||||
| @ -18,7 +18,9 @@ use App\Models\GatewayType; | ||||
| use App\Models\Payment; | ||||
| use App\Models\PaymentHash; | ||||
| use App\Models\SystemLog; | ||||
| use App\PaymentDrivers\Mollie\CreditCard; | ||||
| use App\Utils\Traits\MakesHash; | ||||
| use Mollie\Api\MollieApiClient; | ||||
| 
 | ||||
| class MolliePaymentDriver extends BaseDriver | ||||
| { | ||||
| @ -40,7 +42,7 @@ class MolliePaymentDriver extends BaseDriver | ||||
|     public $can_authorise_credit_card = true; | ||||
| 
 | ||||
|     /** | ||||
|      * @var mixed | ||||
|      * @var MollieApiClient | ||||
|      */ | ||||
|     public $gateway; | ||||
| 
 | ||||
| @ -56,14 +58,19 @@ class MolliePaymentDriver extends BaseDriver | ||||
|         GatewayType::CREDIT_CARD => CreditCard::class, | ||||
|     ]; | ||||
| 
 | ||||
|     const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; | ||||
|     const SYSTEM_LOG_TYPE = SystemLog::TYPE_MOLLIE; | ||||
| 
 | ||||
|     public function init() | ||||
|     public function init(): self | ||||
|     { | ||||
|         $this->gateway = new MollieApiClient(); | ||||
| 
 | ||||
|         $this->gateway->setApiKey( | ||||
|             $this->company_gateway->getConfigField('apiKey'), | ||||
|         ); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|     /* Returns an array of gateway types for the payment gateway */ | ||||
|     public function gatewayTypes(): array | ||||
|     { | ||||
|         $types = []; | ||||
| @ -76,7 +83,9 @@ class MolliePaymentDriver extends BaseDriver | ||||
|     public function setPaymentMethod($payment_method_id) | ||||
|     { | ||||
|         $class = self::$methods[$payment_method_id]; | ||||
| 
 | ||||
|         $this->payment_method = new $class($this); | ||||
| 
 | ||||
|         return $this; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										2
									
								
								public/css/app.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/css/app.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -1,6 +1,6 @@ | ||||
| { | ||||
|     "/js/app.js": "/js/app.js?id=696e8203d5e8e7cf5ff5", | ||||
|     "/css/app.css": "/css/app.css?id=f4c07fdabcbe50c9f4be", | ||||
|     "/css/app.css": "/css/app.css?id=3ab7ce803b68a6e66464", | ||||
|     "/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=a09bb529b8e1826f13b4", | ||||
|     "/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=8ce8955ba775ea5f47d1", | ||||
|     "/js/clients/linkify-urls.js": "/js/clients/linkify-urls.js?id=0dc8c34010d09195d2f7", | ||||
|  | ||||
| @ -4286,6 +4286,7 @@ $LANG = array( | ||||
|     'user_created_user' => ':user created :created_user at :time', | ||||
|     'company_deleted' => 'Company deleted', | ||||
|     'company_deleted_body' => 'Company [ :company ] was deleted by :user', | ||||
|     'expiry_date' => 'Expiry date', | ||||
| ); | ||||
| 
 | ||||
| return $LANG; | ||||
|  | ||||
| @ -0,0 +1,183 @@ | ||||
| @extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => | ||||
| ctrans('texts.credit_card')]) | ||||
| 
 | ||||
| @section('gateway_head') | ||||
|     <script src="https://code.jquery.com/jquery-1.11.3.min.js"></script> | ||||
|     <script src="{{ asset('js/clients/payments/card-js.min.js') }}"></script> | ||||
|     <link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css"> | ||||
| @endsection | ||||
| 
 | ||||
| @section('gateway_content') | ||||
|     <form action="{{ route('client.payments.response') }}" method="post" id="server-response"> | ||||
|         @csrf | ||||
|         <input type="hidden" name="gateway_response"> | ||||
|         <input type="hidden" name="store_card"> | ||||
|         <input type="hidden" name="payment_hash" value="{{ $payment_hash }}"> | ||||
| 
 | ||||
|         <input type="hidden" name="company_gateway_id" value="{{ $gateway->getCompanyGatewayId() }}"> | ||||
|         <input type="hidden" name="payment_method_id" value="{{ $payment_method_id }}"> | ||||
| 
 | ||||
|         <input type="hidden" name="token"> | ||||
|     </form> | ||||
| 
 | ||||
|     <div class="alert alert-failure mb-4" hidden id="errors"></div> | ||||
| 
 | ||||
|     @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')]) | ||||
|         {{ ctrans('texts.credit_card') }} | ||||
|     @endcomponent | ||||
| 
 | ||||
|     @include('portal.ninja2020.gateways.includes.payment_details') | ||||
| 
 | ||||
|     @component('portal.ninja2020.components.general.card-element-single') | ||||
|         <div class="flex flex-col"> | ||||
|             <label for="card-number"> | ||||
|                 <span class="text-xs text-gray-900 uppercase">{{ ctrans('texts.card_number') }}</span> | ||||
|                 <div class="input w-full" type="text" id="card-number"></div> | ||||
|                 <div class="text-xs text-red-500 mt-1 block" id="card-number-error"></div> | ||||
|             </label> | ||||
| 
 | ||||
|             <label for="card-holder" class="block mt-2"> | ||||
|                 <span class="text-xs text-gray-900 uppercase">{{ ctrans('texts.name') }}</span> | ||||
|                 <div class="input w-full" type="text" id="card-holder"></div> | ||||
|                 <div class="text-xs text-red-500 mt-1 block" id="card-holder-error"></div> | ||||
|             </label> | ||||
| 
 | ||||
|             <div class="grid grid-cols-12 gap-4 mt-2"> | ||||
|                 <label for="expiry-date" class="col-span-4"> | ||||
|                     <span class="text-xs text-gray-900 uppercase">{{ ctrans('texts.expiry_date') }}</span> | ||||
|                     <div class="input w-full" type="text" id="expiry-date"></div> | ||||
|                     <div class="text-xs text-red-500 mt-1 block" id="expiry-date-error"></div> | ||||
|                 </label> | ||||
| 
 | ||||
|                 <label for="cvv" class="col-span-8"> | ||||
|                     <span class="text-xs text-gray-900 uppercase">{{ ctrans('texts.cvv') }}</span> | ||||
|                     <div class="input w-full border" type="text" id="cvv"></div> | ||||
|                     <div class="text-xs text-red-500 mt-1 block" id="cvv-error"></div> | ||||
|                 </label> | ||||
|             </div> | ||||
|         </div> | ||||
|     @endcomponent | ||||
| 
 | ||||
|     @include('portal.ninja2020.gateways.includes.pay_now') | ||||
| @endsection | ||||
| 
 | ||||
| @section('gateway_footer') | ||||
|     <script src="https://js.mollie.com/v1/mollie.js"></script> | ||||
| 
 | ||||
|     <script> | ||||
|         class _Mollie { | ||||
|             constructor() { | ||||
|                 this.mollie = Mollie('pfl_sFDNzkEdyw', { | ||||
|                     testmode: true, | ||||
|                     locale: 'en_US', | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             createCardHolderInput() { | ||||
|                 let cardHolder = this.mollie.createComponent("cardHolder"); | ||||
|                 cardHolder.mount("#card-holder"); | ||||
| 
 | ||||
|                 let cardHolderError = document.getElementById("card-holder-error"); | ||||
| 
 | ||||
|                 cardHolder.addEventListener("change", function(event) { | ||||
|                     if (event.error && event.touched) { | ||||
|                         cardHolderError.textContent = event.error; | ||||
|                     } else { | ||||
|                         cardHolderError.textContent = ""; | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 return this; | ||||
|             } | ||||
| 
 | ||||
|             createCardNumberInput() { | ||||
|                 let cardNumber = this.mollie.createComponent("cardNumber"); | ||||
|                 cardNumber.mount("#card-number"); | ||||
| 
 | ||||
|                 let cardNumberError = document.getElementById("card-number-error"); | ||||
| 
 | ||||
|                 cardNumber.addEventListener("change", function(event) { | ||||
|                     if (event.error && event.touched) { | ||||
|                         cardNumberError.textContent = event.error; | ||||
|                     } else { | ||||
|                         cardNumberError.textContent = ""; | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 return this; | ||||
|             } | ||||
| 
 | ||||
|             createExpiryDateInput() { | ||||
|                 let expiryDate = this.mollie.createComponent("expiryDate"); | ||||
|                 expiryDate.mount("#expiry-date"); | ||||
| 
 | ||||
|                 let expiryDateError = document.getElementById("expiry-date-error"); | ||||
| 
 | ||||
|                 expiryDate.addEventListener("change", function(event) { | ||||
|                     if (event.error && event.touched) { | ||||
|                         expiryDateError.textContent = event.error; | ||||
|                     } else { | ||||
|                         expiryDateError.textContent = ""; | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 return this; | ||||
|             } | ||||
| 
 | ||||
|             createCvvInput() { | ||||
|                 let verificationCode = this.mollie.createComponent("verificationCode"); | ||||
|                 verificationCode.mount("#cvv"); | ||||
| 
 | ||||
|                 let verificationCodeError = document.getElementById( | ||||
|                     "cvv-error" | ||||
|                 ); | ||||
| 
 | ||||
|                 verificationCode.addEventListener("change", function(event) { | ||||
|                     if (event.error && event.touched) { | ||||
|                         verificationCodeError.textContent = event.error; | ||||
|                     } else { | ||||
|                         verificationCodeError.textContent = ""; | ||||
|                     } | ||||
|                 }); | ||||
| 
 | ||||
|                 return this; | ||||
|             } | ||||
| 
 | ||||
|             handlePayNowButton() { | ||||
|                 document.getElementById('pay-now').disabled = true; | ||||
| 
 | ||||
|                 this.mollie.createToken().then(function(result) { | ||||
|                     let token = result.token; | ||||
|                     let error = result.error; | ||||
| 
 | ||||
|                     if (error) { | ||||
|                         document.getElementById('pay-now').disabled = false; | ||||
| 
 | ||||
|                         let errorsContainer = document.getElementById('errors'); | ||||
|                         errorsContainer.innerText = error.message; | ||||
|                         errorsContainer.hidden = false; | ||||
| 
 | ||||
|                         return; | ||||
|                     } | ||||
| 
 | ||||
|                     document.querySelector('input[name=token]').value = token; | ||||
|                     document.getElementById('server-response').submit(); | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             handle() { | ||||
|                 this | ||||
|                     .createCardHolderInput() | ||||
|                     .createCardNumberInput() | ||||
|                     .createExpiryDateInput() | ||||
|                     .createCvvInput(); | ||||
| 
 | ||||
|                 document | ||||
|                     .getElementById('pay-now') | ||||
|                     .addEventListener('click', () => this.handlePayNowButton()); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         new _Mollie().handle(); | ||||
|     </script> | ||||
| @endsection | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user