mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-05-24 02:14:21 -04:00
Merge pull request #6488 from turbo124/v5-develop
eWay payment driver + PHP version bump to 7.4
This commit is contained in:
commit
2528fc16b8
2
.github/workflows/phpunit.yml
vendored
2
.github/workflows/phpunit.yml
vendored
@ -13,7 +13,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
operating-system: ['ubuntu-18.04', 'ubuntu-20.04']
|
operating-system: ['ubuntu-18.04', 'ubuntu-20.04']
|
||||||
php-versions: ['7.3','7.4','8.0']
|
php-versions: ['7.4','8.0']
|
||||||
phpunit-versions: ['latest']
|
phpunit-versions: ['latest']
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -100,7 +100,7 @@ class PaymentNotification implements ShouldQueue
|
|||||||
$currency_code = $client->getCurrencyCode();
|
$currency_code = $client->getCurrencyCode();
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
$item .= ' [R]';
|
$item .= ' [R5]';
|
||||||
}
|
}
|
||||||
|
|
||||||
$base = "v=1&tid={$analytics_id}&cid={$client->id}&cu={$currency_code}&ti={$entity_number}";
|
$base = "v=1&tid={$analytics_id}&cid={$client->id}&cu={$currency_code}&ti={$entity_number}";
|
||||||
|
@ -79,9 +79,12 @@ class Gateway extends StaticModel
|
|||||||
{
|
{
|
||||||
switch ($this->id) {
|
switch ($this->id) {
|
||||||
case 1:
|
case 1:
|
||||||
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]];//Authorize.net
|
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true]]; //Authorize.net
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 3:
|
||||||
|
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => true]];//eWay
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false]];//Payfast
|
return [GatewayType::CREDIT_CARD => ['refund' => false, 'token_billing' => false]];//Payfast
|
||||||
break;
|
break;
|
||||||
case 15:
|
case 15:
|
||||||
|
@ -71,6 +71,7 @@ class CompanyPresenter extends EntityPresenter
|
|||||||
else
|
else
|
||||||
return "data:image/png;base64, ". base64_encode(file_get_contents(asset('images/new_logo.png'), false, stream_context_create($context_options)));
|
return "data:image/png;base64, ". base64_encode(file_get_contents(asset('images/new_logo.png'), false, stream_context_create($context_options)));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function address($settings = null)
|
public function address($settings = null)
|
||||||
|
@ -70,7 +70,8 @@ class SystemLog extends Model
|
|||||||
const TYPE_PAYFAST = 310;
|
const TYPE_PAYFAST = 310;
|
||||||
const TYPE_PAYTRACE = 311;
|
const TYPE_PAYTRACE = 311;
|
||||||
const TYPE_MOLLIE = 312;
|
const TYPE_MOLLIE = 312;
|
||||||
|
const TYPE_EWAY = 313;
|
||||||
|
|
||||||
const TYPE_QUOTA_EXCEEDED = 400;
|
const TYPE_QUOTA_EXCEEDED = 400;
|
||||||
const TYPE_UPSTREAM_FAILURE = 401;
|
const TYPE_UPSTREAM_FAILURE = 401;
|
||||||
|
|
||||||
|
@ -182,7 +182,6 @@ class User extends Authenticatable implements MustVerifyEmail
|
|||||||
return $company_token->company;
|
return $company_token->company;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// return false;
|
// return false;
|
||||||
throw new \Exception('No Company Found');
|
throw new \Exception('No Company Found');
|
||||||
//return Company::find(config('ninja.company_id'));
|
//return Company::find(config('ninja.company_id'));
|
||||||
|
@ -103,14 +103,14 @@ class EntitySentNotification extends Notification
|
|||||||
"texts.notification_{$this->entity_name}_sent_subject",
|
"texts.notification_{$this->entity_name}_sent_subject",
|
||||||
[
|
[
|
||||||
'amount' => $amount,
|
'amount' => $amount,
|
||||||
'client' => $this->contact->present()->name(),
|
'client' => $this->contact->client->present()->name(),
|
||||||
'invoice' => $this->entity->number,
|
'invoice' => $this->entity->number,
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
->attachment(function ($attachment) use ($amount) {
|
->attachment(function ($attachment) use ($amount) {
|
||||||
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->entity->number]), $this->invitation->getAdminLink())
|
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->entity->number]), $this->invitation->getAdminLink())
|
||||||
->fields([
|
->fields([
|
||||||
ctrans('texts.client') => $this->contact->present()->name(),
|
ctrans('texts.client') => $this->contact->client->present()->name(),
|
||||||
ctrans('texts.amount') => $amount,
|
ctrans('texts.amount') => $amount,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
250
app/PaymentDrivers/Eway/CreditCard.php
Normal file
250
app/PaymentDrivers/Eway/CreditCard.php
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\Eway;
|
||||||
|
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\PaymentType;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\PaymentDrivers\EwayPaymentDriver;
|
||||||
|
use App\PaymentDrivers\Eway\ErrorCode;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class CreditCard
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public $eway_driver;
|
||||||
|
|
||||||
|
public function __construct(EwayPaymentDriver $eway_driver)
|
||||||
|
{
|
||||||
|
$this->eway_driver = $eway_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeView($data)
|
||||||
|
{
|
||||||
|
|
||||||
|
$data['gateway'] = $this->eway_driver;
|
||||||
|
$data['api_key'] = $this->eway_driver->company_gateway->getConfigField('apiKey');
|
||||||
|
$data['public_api_key'] = $this->eway_driver->company_gateway->getConfigField('publicApiKey');
|
||||||
|
|
||||||
|
return render('gateways.eway.authorize', $data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeResponse($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$token = $this->createEwayToken($request->input('securefieldcode'));
|
||||||
|
|
||||||
|
return redirect()->route('client.payment_methods.index');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createEwayToken($securefieldcode)
|
||||||
|
{
|
||||||
|
$transaction = [
|
||||||
|
'Reference' => $this->eway_driver->client->number,
|
||||||
|
'Title' => '',
|
||||||
|
'FirstName' => $this->eway_driver->client->contacts()->first()->present()->last_name(),
|
||||||
|
'LastName' => $this->eway_driver->client->contacts()->first()->present()->first_name(),
|
||||||
|
'CompanyName' => $this->eway_driver->client->name,
|
||||||
|
'Street1' => $this->eway_driver->client->address1,
|
||||||
|
'Street2' => $this->eway_driver->client->address2,
|
||||||
|
'City' => $this->eway_driver->client->city,
|
||||||
|
'State' => $this->eway_driver->client->state,
|
||||||
|
'PostalCode' => $this->eway_driver->client->postal_code,
|
||||||
|
'Country' => $this->eway_driver->client->country->iso_3166_2,
|
||||||
|
'Phone' => $this->eway_driver->client->phone,
|
||||||
|
'Email' => $this->eway_driver->client->contacts()->first()->email,
|
||||||
|
"Url" => $this->eway_driver->client->website,
|
||||||
|
'Method' => \Eway\Rapid\Enum\PaymentMethod::CREATE_TOKEN_CUSTOMER,
|
||||||
|
'SecuredCardData' => $securefieldcode,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->eway_driver->init()->eway->createCustomer(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
||||||
|
|
||||||
|
$response_status = ErrorCode::getStatus($response->ResponseMessage);
|
||||||
|
|
||||||
|
if(!$response_status['success'])
|
||||||
|
throw new PaymentFailed($response_status['message'], 400);
|
||||||
|
|
||||||
|
//success
|
||||||
|
$cgt = [];
|
||||||
|
$cgt['token'] = $response->Customer->TokenCustomerID;
|
||||||
|
$cgt['payment_method_id'] = GatewayType::CREDIT_CARD;
|
||||||
|
|
||||||
|
$payment_meta = new \stdClass;
|
||||||
|
$payment_meta->exp_month = $response->Customer->CardDetails->ExpiryMonth;
|
||||||
|
$payment_meta->exp_year = $response->Customer->CardDetails->ExpiryYear;
|
||||||
|
$payment_meta->brand = 'CC';
|
||||||
|
$payment_meta->last4 = substr($response->Customer->CardDetails->Number, -4);;
|
||||||
|
$payment_meta->type = GatewayType::CREDIT_CARD;
|
||||||
|
|
||||||
|
$cgt['payment_meta'] = $payment_meta;
|
||||||
|
|
||||||
|
$token = $this->eway_driver->storeGatewayToken($cgt, []);
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentView($data)
|
||||||
|
{
|
||||||
|
|
||||||
|
$data['gateway'] = $this->eway_driver;
|
||||||
|
$data['public_api_key'] = $this->eway_driver->company_gateway->getConfigField('publicApiKey');
|
||||||
|
|
||||||
|
return render('gateways.eway.pay', $data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentResponse($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
$state = [
|
||||||
|
'server_response' => $request->all(),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->eway_driver->payment_hash->data = array_merge((array) $this->eway_driver->payment_hash->data, $state);
|
||||||
|
$this->eway_driver->payment_hash->save();
|
||||||
|
|
||||||
|
if(boolval($request->input('store_card')))
|
||||||
|
{
|
||||||
|
$token = $this->createEwayToken($request->input('securefieldcode'));
|
||||||
|
$payment = $this->tokenBilling($token->token, $this->eway_driver->payment_hash);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if($request->token){
|
||||||
|
|
||||||
|
$payment = $this->tokenBilling($request->token, $this->eway_driver->payment_hash);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$transaction = [
|
||||||
|
'Payment' => [
|
||||||
|
'TotalAmount' => $this->convertAmountForEway(),
|
||||||
|
],
|
||||||
|
'TransactionType' => \Eway\Rapid\Enum\TransactionType::PURCHASE,
|
||||||
|
'SecuredCardData' => $request->input('securefieldcode'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
||||||
|
|
||||||
|
$response_status = ErrorCode::getStatus($response->ResponseMessage);
|
||||||
|
|
||||||
|
if(!$response_status['success']){
|
||||||
|
|
||||||
|
$this->logResponse($response, false);
|
||||||
|
|
||||||
|
throw new PaymentFailed($response_status['message'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logResponse($response, true);
|
||||||
|
|
||||||
|
$payment = $this->storePayment($response);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function storePayment($response)
|
||||||
|
{
|
||||||
|
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
|
||||||
|
|
||||||
|
$payment_record = [];
|
||||||
|
$payment_record['amount'] = $amount;
|
||||||
|
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||||
|
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||||
|
$payment_record['transaction_reference'] = $response->TransactionID;
|
||||||
|
|
||||||
|
$payment = $this->eway_driver->createPayment($payment_record);
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function convertAmountForEway($amount = false)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(!$amount)
|
||||||
|
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
|
||||||
|
|
||||||
|
if(in_array($this->eway_driver->client->currency()->code, ['VND', 'JPY', 'KRW', 'GNF', 'IDR', 'PYG', 'RWF', 'UGX', 'VUV', 'XAF', 'XPF']))
|
||||||
|
return $amount;
|
||||||
|
|
||||||
|
return $amount * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function logResponse($response, $success = true)
|
||||||
|
{
|
||||||
|
|
||||||
|
$logger_message = [
|
||||||
|
'server_response' => $response,
|
||||||
|
];
|
||||||
|
|
||||||
|
SystemLogger::dispatch(
|
||||||
|
$logger_message,
|
||||||
|
SystemLog::CATEGORY_GATEWAY_RESPONSE,
|
||||||
|
$success ? SystemLog::EVENT_GATEWAY_SUCCESS : SystemLog::EVENT_GATEWAY_FAILURE,
|
||||||
|
SystemLog::TYPE_EWAY,
|
||||||
|
$this->eway_driver->client,
|
||||||
|
$this->eway_driver->client->company,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function tokenBilling($token, $payment_hash)
|
||||||
|
{
|
||||||
|
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||||
|
|
||||||
|
$transaction = [
|
||||||
|
'Customer' => [
|
||||||
|
'TokenCustomerID' => $token,
|
||||||
|
],
|
||||||
|
'Payment' => [
|
||||||
|
'TotalAmount' => $this->convertAmountForEway($amount),
|
||||||
|
],
|
||||||
|
'TransactionType' => \Eway\Rapid\Enum\TransactionType::RECURRING,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
||||||
|
|
||||||
|
$response_status = ErrorCode::getStatus($response->ResponseMessage);
|
||||||
|
|
||||||
|
if(!$response_status['success']){
|
||||||
|
|
||||||
|
$this->logResponse($response, false);
|
||||||
|
|
||||||
|
throw new PaymentFailed($response_status['message'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->logResponse($response, true);
|
||||||
|
|
||||||
|
$payment = $this->storePayment($response);
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
}
|
||||||
|
}
|
105
app/PaymentDrivers/Eway/ErrorCode.php
Normal file
105
app/PaymentDrivers/Eway/ErrorCode.php
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\Eway;
|
||||||
|
|
||||||
|
class ErrorCode
|
||||||
|
{
|
||||||
|
|
||||||
|
private static $success = [
|
||||||
|
"A2000" => "Transaction Approved",
|
||||||
|
"A2008" => "Honour With Identification",
|
||||||
|
"A2010" => "Approved For Partial Amount",
|
||||||
|
"A2011" => "Approved, VIP",
|
||||||
|
"A2016" => "Approved, Update Track 3",
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $failure = [
|
||||||
|
"D4401" => "Refer to Issuer",
|
||||||
|
"D4402" => "Refer to Issuer, special",
|
||||||
|
"D4403" => "No Merchant",
|
||||||
|
"D4404" => "Pick Up Card",
|
||||||
|
"D4405" => "Do Not Honour",
|
||||||
|
"D4406" => "Error",
|
||||||
|
"D4407" => "Pick Up Card, Special",
|
||||||
|
"D4409" => "Request In Progress",
|
||||||
|
"D4412" => "Invalid Transaction",
|
||||||
|
"D4413" => "Invalid Amount",
|
||||||
|
"D4414" => "Invalid Card Number",
|
||||||
|
"D4415" => "No Issuer",
|
||||||
|
"D4417" => "3D Secure Error",
|
||||||
|
"D4419" => "Re-enter Last Transaction",
|
||||||
|
"D4421" => "No Action Taken",
|
||||||
|
"D4422" => "Suspected Malfunction",
|
||||||
|
"D4423" => "Unacceptable Transaction Fee",
|
||||||
|
"D4425" => "Unable to Locate Record On File",
|
||||||
|
"D4430" => "Format Error",
|
||||||
|
"D4431" => "Bank Not Supported By Switch",
|
||||||
|
"D4433" => "Expired Card, Capture",
|
||||||
|
"D4434" => "Suspected Fraud, Retain Card",
|
||||||
|
"D4435" => "Card Acceptor, Contact Acquirer, Retain Card",
|
||||||
|
"D4436" => "Restricted Card, Retain Card",
|
||||||
|
"D4437" => "Contact Acquirer Security Department, Retain Card",
|
||||||
|
"D4438" => "PIN Tries Exceeded, Capture",
|
||||||
|
"D4439" => "No Credit Account",
|
||||||
|
"D4440" => "Function Not Supported",
|
||||||
|
"D4441" => "Lost Card",
|
||||||
|
"D4442" => "No Universal Account",
|
||||||
|
"D4443" => "Stolen Card",
|
||||||
|
"D4444" => "No Investment Account",
|
||||||
|
"D4450" => "Click-to-Pay (Visa Checkout) Transaction",
|
||||||
|
"D4451" => "Insufficient Funds",
|
||||||
|
"D4452" => "No Cheque Account",
|
||||||
|
"D4453" => "No Savings Account",
|
||||||
|
"D4454" => "Expired Card",
|
||||||
|
"D4455" => "Incorrect PIN",
|
||||||
|
"D4456" => "No Card Record",
|
||||||
|
"D4457" => "Function Not Permitted to Cardholder",
|
||||||
|
"D4458" => "Function Not Permitted to Terminal",
|
||||||
|
"D4459" => "Suspected Fraud",
|
||||||
|
"D4460" => "Acceptor Contact Acquirer",
|
||||||
|
"D4461" => "Exceeds Withdrawal Limit",
|
||||||
|
"D4462" => "Restricted Card",
|
||||||
|
"D4463" => "Security Violation",
|
||||||
|
"D4464" => "Original Amount Incorrect",
|
||||||
|
"D4466" => "Acceptor Contact Acquirer, Security",
|
||||||
|
"D4467" => "Capture Card",
|
||||||
|
"D4475" => "PIN Tries Exceeded",
|
||||||
|
"D4476" => "Invalidate Txn Reference",
|
||||||
|
"D4481" => "Accumulated Transaction Counter (Amount) Exceeded",
|
||||||
|
"D4482" => "CVV Validation Error",
|
||||||
|
"D4483" => "Acquirer Is Not Accepting Transactions From You At This Time",
|
||||||
|
"D4484" => "Acquirer Is Not Accepting This Transaction",
|
||||||
|
"D4490" => "Cut off In Progress",
|
||||||
|
"D4491" => "Card Issuer Unavailable",
|
||||||
|
"D4492" => "Unable To Route Transaction",
|
||||||
|
"D4493" => "Cannot Complete, Violation Of The Law",
|
||||||
|
"D4494" => "Duplicate Transaction",
|
||||||
|
"D4495" => "Amex Declined",
|
||||||
|
"D4496" => "System Error",
|
||||||
|
"D4497" => "MasterPass Error",
|
||||||
|
"D4498" => "PayPal Create Transaction Error",
|
||||||
|
"D4499" => "Invalid Transaction for Auth/Void",
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
public static function getStatus($code)
|
||||||
|
{
|
||||||
|
if(array_key_exists($code, self::$success))
|
||||||
|
return ['success' => true, 'message' => self::$success[$code]];
|
||||||
|
|
||||||
|
if(array_key_exists($code, self::$failure))
|
||||||
|
return ['success' => false, 'message' => self::$failure[$code]];
|
||||||
|
|
||||||
|
return ['success' => false, 'message' => "Unknown error message code - {$code}"];
|
||||||
|
}
|
||||||
|
}
|
111
app/PaymentDrivers/Eway/Token.php
Normal file
111
app/PaymentDrivers/Eway/Token.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\Eway;
|
||||||
|
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\PaymentType;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\PaymentDrivers\EwayPaymentDriver;
|
||||||
|
use App\PaymentDrivers\Eway\ErrorCode;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class Token
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public $eway_driver;
|
||||||
|
|
||||||
|
public function __construct(EwayPaymentDriver $eway_driver)
|
||||||
|
{
|
||||||
|
$this->eway_driver = $eway_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||||
|
{
|
||||||
|
|
||||||
|
$amount = array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total;
|
||||||
|
|
||||||
|
$transaction = [
|
||||||
|
'Customer' => [
|
||||||
|
'TokenCustomerID' => $cgt->token,
|
||||||
|
],
|
||||||
|
'Payment' => [
|
||||||
|
'TotalAmount' => $this->eway_driver->convertAmount($amount),
|
||||||
|
],
|
||||||
|
'TransactionType' => \Eway\Rapid\Enum\TransactionType::RECURRING,
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->eway_driver->init()->eway->createTransaction(\Eway\Rapid\Enum\ApiMethod::DIRECT, $transaction);
|
||||||
|
|
||||||
|
$response_status = ErrorCode::getStatus($response->ResponseMessage);
|
||||||
|
|
||||||
|
if(!$response_status['success'])
|
||||||
|
return $this->processUnsuccessfulPayment($response);
|
||||||
|
|
||||||
|
$payment = $this->processSuccessfulPayment($response);
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function processSuccessfulPayment($response)
|
||||||
|
{
|
||||||
|
$amount = array_sum(array_column($this->eway_driver->payment_hash->invoices(), 'amount')) + $this->eway_driver->payment_hash->fee_total;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'gateway_type_id' => $cgt->gateway_type_id,
|
||||||
|
'payment_type' => GatewayType::CREDIT_CARD_OTHER,
|
||||||
|
'transaction_reference' => $response->Customer->Reference,
|
||||||
|
'amount' => $amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$payment = $this->eway_driver->createPayment($data);
|
||||||
|
$payment->meta = $cgt->meta;
|
||||||
|
$payment->save();
|
||||||
|
|
||||||
|
$payment_hash->payment_id = $payment->id;
|
||||||
|
$payment_hash->save();
|
||||||
|
|
||||||
|
return $payment;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processUnsuccessfulPayment($response)
|
||||||
|
{
|
||||||
|
|
||||||
|
$response_status = ErrorCode::getStatus($response->ResponseMessage);
|
||||||
|
|
||||||
|
$error = $response_status['message']
|
||||||
|
$error_code = $response->ResponseMessage;
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'response' => $response,
|
||||||
|
'error' => $error,
|
||||||
|
'error_code' => $error_code,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->driver_class->processUnsuccessfulTransaction($data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
200
app/PaymentDrivers/EwayPaymentDriver.php
Normal file
200
app/PaymentDrivers/EwayPaymentDriver.php
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers;
|
||||||
|
|
||||||
|
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\PaymentDrivers\Eway\CreditCard;
|
||||||
|
use App\PaymentDrivers\Eway\Token;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
|
class EwayPaymentDriver extends BaseDriver
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public $refundable = true; //does this gateway support refunds?
|
||||||
|
|
||||||
|
public $token_billing = true; //does this gateway support token billing?
|
||||||
|
|
||||||
|
public $can_authorise_credit_card = true; //does this gateway support authorizations?
|
||||||
|
|
||||||
|
public $eway; //initialized gateway
|
||||||
|
|
||||||
|
public $payment_method; //initialized payment method
|
||||||
|
|
||||||
|
public static $methods = [
|
||||||
|
GatewayType::CREDIT_CARD => CreditCard::class, //maps GatewayType => Implementation class
|
||||||
|
];
|
||||||
|
|
||||||
|
const SYSTEM_LOG_TYPE = SystemLog::TYPE_EWAY; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$apiKey = $this->company_gateway->getConfigField('apiKey');
|
||||||
|
$apiPassword = $this->company_gateway->getConfigField('password');
|
||||||
|
$apiEndpoint = $this->company_gateway->getConfigField('testMode') ? \Eway\Rapid\Client::MODE_SANDBOX : \Eway\Rapid\Client::MODE_PRODUCTION;
|
||||||
|
$this->eway = \Eway\Rapid::createClient($apiKey, $apiPassword, $apiEndpoint);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns an array of gateway types for the payment gateway */
|
||||||
|
public function gatewayTypes(): array
|
||||||
|
{
|
||||||
|
$types = [];
|
||||||
|
|
||||||
|
$types[] = GatewayType::CREDIT_CARD;
|
||||||
|
|
||||||
|
return $types;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets the payment method initialized */
|
||||||
|
public function setPaymentMethod($payment_method_id)
|
||||||
|
{
|
||||||
|
$class = self::$methods[$payment_method_id];
|
||||||
|
$this->payment_method = new $class($this);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeView(array $data)
|
||||||
|
{
|
||||||
|
return $this->payment_method->authorizeView($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeResponse($request)
|
||||||
|
{
|
||||||
|
return $this->payment_method->authorizeResponse($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processPaymentView(array $data)
|
||||||
|
{
|
||||||
|
return $this->payment_method->paymentView($data); //this is your custom implementation from here
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processPaymentResponse($request)
|
||||||
|
{
|
||||||
|
return $this->payment_method->paymentResponse($request); //this is your custom implementation from here
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need PCI compliance prior to enabling this */
|
||||||
|
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||||
|
{
|
||||||
|
|
||||||
|
$refund = [
|
||||||
|
'Refund' => [
|
||||||
|
'TransactionID' => $payment->transaction_reference,
|
||||||
|
'TotalAmount' => $this->convertAmount($amount)
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->init()->eway->refund($refund);
|
||||||
|
|
||||||
|
$transaction_reference = '';
|
||||||
|
$refund_status = true;
|
||||||
|
$refund_message = '';
|
||||||
|
|
||||||
|
if ($response->TransactionStatus) {
|
||||||
|
$transaction_reference = $response->TransactionID;
|
||||||
|
} else {
|
||||||
|
if ($response->getErrors()) {
|
||||||
|
foreach ($response->getErrors() as $error) {
|
||||||
|
$refund_status = false;
|
||||||
|
$refund_message = \Eway\Rapid::getMessage($error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$refund_status = false;
|
||||||
|
$refund_message = 'Sorry, your refund failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'transaction_reference' => $response->TransactionID,
|
||||||
|
'transaction_response' => json_encode($response),
|
||||||
|
'success' => $refund_status,
|
||||||
|
'description' => $refund_message,
|
||||||
|
'code' => '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||||
|
{
|
||||||
|
return (new Token($this))->tokenBilling($cgt, $payment_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertAmount($amount)
|
||||||
|
{
|
||||||
|
$precision = $this->client->currency()->precision;
|
||||||
|
|
||||||
|
if($precision == 0)
|
||||||
|
return $amount;
|
||||||
|
|
||||||
|
if($precision == 1)
|
||||||
|
return $amount*10;
|
||||||
|
|
||||||
|
if($precision == 2)
|
||||||
|
return $amount*100;
|
||||||
|
|
||||||
|
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getClientRequiredFields(): array
|
||||||
|
{
|
||||||
|
$fields = [];
|
||||||
|
$fields[] = ['name' => 'contact_first_name', 'label' => ctrans('texts.first_name'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'contact_last_name', 'label' => ctrans('texts.last_name'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'contact_email', 'label' => ctrans('texts.email'), 'type' => 'text', 'validation' => 'required,email:rfc'];
|
||||||
|
$fields[] = ['name' => 'client_country_id', 'label' => ctrans('texts.country'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
|
||||||
|
if ($this->company_gateway->require_client_name) {
|
||||||
|
$fields[] = ['name' => 'client_name', 'label' => ctrans('texts.client_name'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ($this->company_gateway->require_contact_name) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if ($this->company_gateway->require_contact_email) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
if ($this->company_gateway->require_client_phone) {
|
||||||
|
$fields[] = ['name' => 'client_phone', 'label' => ctrans('texts.client_phone'), 'type' => 'tel', 'validation' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->company_gateway->require_billing_address) {
|
||||||
|
$fields[] = ['name' => 'client_address_line_1', 'label' => ctrans('texts.address1'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_city', 'label' => ctrans('texts.city'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_state', 'label' => ctrans('texts.state'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if($this->company_gateway->require_postal_code)
|
||||||
|
$fields[] = ['name' => 'client_postal_code', 'label' => ctrans('texts.postal_code'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
|
||||||
|
if ($this->company_gateway->require_shipping_address) {
|
||||||
|
$fields[] = ['name' => 'client_shipping_address_line_1', 'label' => ctrans('texts.shipping_address1'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_shipping_city', 'label' => ctrans('texts.shipping_city'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_shipping_state', 'label' => ctrans('texts.shipping_state'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_shipping_postal_code', 'label' => ctrans('texts.shipping_postal_code'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
$fields[] = ['name' => 'client_shipping_country_id', 'label' => ctrans('texts.shipping_country'), 'type' => 'text', 'validation' => 'required'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return $fields;
|
||||||
|
}
|
||||||
|
}
|
113
app/PaymentDrivers/Sample/CreditCard.php
Normal file
113
app/PaymentDrivers/Sample/CreditCard.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\PaymentDrivers\Eway;
|
||||||
|
|
||||||
|
use App\Exceptions\PaymentFailed;
|
||||||
|
use App\Jobs\Mail\PaymentFailureMailer;
|
||||||
|
use App\Jobs\Util\SystemLogger;
|
||||||
|
use App\Models\ClientGatewayToken;
|
||||||
|
use App\Models\GatewayType;
|
||||||
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentHash;
|
||||||
|
use App\Models\PaymentType;
|
||||||
|
use App\Models\SystemLog;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class CreditCard
|
||||||
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
|
public $driver_class;
|
||||||
|
|
||||||
|
public function __construct(PaymentDriver $driver_class)
|
||||||
|
{
|
||||||
|
$this->driver_class = $driver_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeView($data)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function authorizeRequest($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function paymentView($data)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function processPaymentResponse($request)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method is stubbed ready to go - you just need to harvest the equivalent 'transaction_reference' */
|
||||||
|
private function processSuccessfulPayment($response)
|
||||||
|
{
|
||||||
|
$amount = array_sum(array_column($this->driver_class->payment_hash->invoices(), 'amount')) + $this->driver_class->payment_hash->fee_total;
|
||||||
|
|
||||||
|
$payment_record = [];
|
||||||
|
$payment_record['amount'] = $amount;
|
||||||
|
$payment_record['payment_type'] = PaymentType::CREDIT_CARD_OTHER;
|
||||||
|
$payment_record['gateway_type_id'] = GatewayType::CREDIT_CARD;
|
||||||
|
// $payment_record['transaction_reference'] = $response->transaction_id;
|
||||||
|
|
||||||
|
$payment = $this->driver_class->createPayment($payment_record, Payment::STATUS_COMPLETED);
|
||||||
|
|
||||||
|
return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function processUnsuccessfulPayment($response)
|
||||||
|
{
|
||||||
|
/*Harvest your own errors here*/
|
||||||
|
// $error = $response->status_message;
|
||||||
|
|
||||||
|
// if(property_exists($response, 'approval_message') && $response->approval_message)
|
||||||
|
// $error .= " - {$response->approval_message}";
|
||||||
|
|
||||||
|
// $error_code = property_exists($response, 'approval_message') ? $response->approval_message : 'Undefined code';
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'response' => $response,
|
||||||
|
'error' => $error,
|
||||||
|
'error_code' => $error_code,
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->driver_class->processUnsuccessfulTransaction($data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helpers */
|
||||||
|
|
||||||
|
/*
|
||||||
|
You will need some helpers to handle successful and unsuccessful responses
|
||||||
|
|
||||||
|
Some considerations after a succesful transaction include:
|
||||||
|
|
||||||
|
Logging of events: success +/- failure
|
||||||
|
Recording a payment
|
||||||
|
Notifications
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -17,10 +17,9 @@ use App\Models\GatewayType;
|
|||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\PaymentHash;
|
use App\Models\PaymentHash;
|
||||||
use App\Models\SystemLog;
|
use App\Models\SystemLog;
|
||||||
use App\PaymentDrivers\Stripe\CreditCard;
|
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class DriverTemplate extends BaseDriver
|
class PaymentDriver extends BaseDriver
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
@ -85,12 +84,12 @@ class DriverTemplate extends BaseDriver
|
|||||||
|
|
||||||
public function refund(Payment $payment, $amount, $return_client_response = false)
|
public function refund(Payment $payment, $amount, $return_client_response = false)
|
||||||
{
|
{
|
||||||
return $this->payment_method->yourRefundImplementationHere(); //this is your custom implementation from here
|
//this is your custom implementation from here
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
public function tokenBilling(ClientGatewayToken $cgt, PaymentHash $payment_hash)
|
||||||
{
|
{
|
||||||
return $this->payment_method->yourTokenBillingImplmentation(); //this is your custom implementation from here
|
//this is your custom implementation from here
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
public function processWebhookRequest(PaymentWebhookRequest $request, Payment $payment = null)
|
34
app/PaymentDrivers/Sample/resources/authorize.blade.php
Normal file
34
app/PaymentDrivers/Sample/resources/authorize.blade.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_content')
|
||||||
|
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
||||||
|
|
||||||
|
@if(!Request::isSecure())
|
||||||
|
<p class="alert alert-failure">{{ ctrans('texts.https_required') }}</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
|
<!-- This is a generic credit card component utilizing CardJS -->
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||||
|
{{ ctrans('texts.credit_card') }}
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<div class="bg-white px-4 py-5 flex justify-end">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
id="{{ $id ?? 'pay-now' }}"
|
||||||
|
class="button button-primary bg-primary {{ $class ?? '' }}">
|
||||||
|
<span>{{ ctrans('texts.add_payment_method') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
<!-- Your JS includes go here -->
|
||||||
|
@endsection
|
64
app/PaymentDrivers/Sample/resources/pay.blade.php
Normal file
64
app/PaymentDrivers/Sample/resources/pay.blade.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' => ctrans('texts.credit_card')])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_content')
|
||||||
|
<form action="{{ $payment_endpoint_url }}" method="post" id="server_response">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')])
|
||||||
|
{{ ctrans('texts.credit_card') }}
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.includes.payment_details')
|
||||||
|
|
||||||
|
<-- If there are existing tokens available these are displayed here for you -->
|
||||||
|
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
|
||||||
|
@if(count($tokens) > 0)
|
||||||
|
@foreach($tokens as $token)
|
||||||
|
<label class="mr-4">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
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>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
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>
|
||||||
|
</label>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
<!-- This include gives the options to save the payment method -->
|
||||||
|
@include('portal.ninja2020.gateways.includes.save_card')
|
||||||
|
|
||||||
|
<!-- This include pops up a credit card form -->
|
||||||
|
@include('portal.ninja2020.gateways.wepay.includes.credit_card')
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.includes.pay_now')
|
||||||
|
|
||||||
|
</form>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
<script>
|
||||||
|
|
||||||
|
document.getElementById('pay-now').addEventListener('click', function() {
|
||||||
|
document.getElementById('server_response').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
|
|
@ -38,7 +38,7 @@ class SystemHealth
|
|||||||
//'intl', //todo double check whether we need this for email dns validation
|
//'intl', //todo double check whether we need this for email dns validation
|
||||||
];
|
];
|
||||||
|
|
||||||
private static $php_version = 7.3;
|
private static $php_version = 7.4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check loaded extensions / PHP version / DB Connections.
|
* Check loaded extensions / PHP version / DB Connections.
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
],
|
],
|
||||||
"type": "project",
|
"type": "project",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.3|^7.4|^8.0",
|
"php": "^7.4|^8.0",
|
||||||
"ext-dom": "*",
|
"ext-dom": "*",
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"ext-libxml": "*",
|
"ext-libxml": "*",
|
||||||
@ -41,6 +41,7 @@
|
|||||||
"codedge/laravel-selfupdater": "^3.2",
|
"codedge/laravel-selfupdater": "^3.2",
|
||||||
"composer/composer": "^2",
|
"composer/composer": "^2",
|
||||||
"doctrine/dbal": "^2.10",
|
"doctrine/dbal": "^2.10",
|
||||||
|
"eway/eway-rapid-php": "^1.3",
|
||||||
"fakerphp/faker": "^1.14",
|
"fakerphp/faker": "^1.14",
|
||||||
"fideloper/proxy": "^4.2",
|
"fideloper/proxy": "^4.2",
|
||||||
"fruitcake/laravel-cors": "^2.0",
|
"fruitcake/laravel-cors": "^2.0",
|
||||||
|
1448
composer.lock
generated
1448
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\Gateway;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class ActivateEwayPaymentDriver extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
if($eway = Gateway::find(3))
|
||||||
|
{
|
||||||
|
$eway->visible = true;
|
||||||
|
$eway->provider = 'Eway';
|
||||||
|
|
||||||
|
$fields = json_decode($eway->fields);
|
||||||
|
$fields->publicApiKey = '';
|
||||||
|
$eway->fields = json_encode($fields);
|
||||||
|
|
||||||
|
$eway->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
@ -27,7 +27,7 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
'],
|
'],
|
||||||
['id' => 2, 'name' => 'CardSave', 'provider' => 'CardSave', 'key' => '46c5c1fed2c43acf4f379bae9c8b9f76', 'fields' => '{"merchantId":"","password":""}
|
['id' => 2, 'name' => 'CardSave', 'provider' => 'CardSave', 'key' => '46c5c1fed2c43acf4f379bae9c8b9f76', 'fields' => '{"merchantId":"","password":""}
|
||||||
'],
|
'],
|
||||||
['id' => 3, 'name' => 'Eway Rapid', 'provider' => 'Eway_RapidShared', 'is_offsite' => true, 'key' => '944c20175bbe6b9972c05bcfe294c2c7', 'fields' => '{"apiKey":"","password":"","testMode":false}'],
|
['id' => 3, 'name' => 'Eway Rapid', 'provider' => 'Eway', 'is_offsite' => true, 'key' => '944c20175bbe6b9972c05bcfe294c2c7', 'fields' => '{"apiKey":"","password":"","publicApiKey":"","testMode":false}'],
|
||||||
['id' => 4, 'name' => 'FirstData Connect', 'provider' => 'FirstData_Connect', 'key' => '4e0ed0d34552e6cb433506d1ac03a418', 'fields' => '{"storeId":"","sharedSecret":"","testMode":false}'],
|
['id' => 4, 'name' => 'FirstData Connect', 'provider' => 'FirstData_Connect', 'key' => '4e0ed0d34552e6cb433506d1ac03a418', 'fields' => '{"storeId":"","sharedSecret":"","testMode":false}'],
|
||||||
['id' => 5, 'name' => 'Migs ThreeParty', 'provider' => 'Migs_ThreeParty', 'key' => '513cdc81444c87c4b07258bc2858d3fa', 'fields' => '{"merchantId":"","merchantAccessCode":"","secureHash":""}'],
|
['id' => 5, 'name' => 'Migs ThreeParty', 'provider' => 'Migs_ThreeParty', 'key' => '513cdc81444c87c4b07258bc2858d3fa', 'fields' => '{"merchantId":"","merchantAccessCode":"","secureHash":""}'],
|
||||||
['id' => 6, 'name' => 'Migs TwoParty', 'provider' => 'Migs_TwoParty', 'key' => '99c2a271b5088951334d1302e038c01a', 'fields' => '{"merchantId":"","merchantAccessCode":"","secureHash":""}'],
|
['id' => 6, 'name' => 'Migs TwoParty', 'provider' => 'Migs_TwoParty', 'key' => '99c2a271b5088951334d1302e038c01a', 'fields' => '{"merchantId":"","merchantAccessCode":"","secureHash":""}'],
|
||||||
@ -96,7 +96,7 @@ class PaymentLibrariesSeeder extends Seeder
|
|||||||
|
|
||||||
Gateway::query()->update(['visible' => 0]);
|
Gateway::query()->update(['visible' => 0]);
|
||||||
|
|
||||||
Gateway::whereIn('id', [1,7,15,20,39,46,55,50])->update(['visible' => 1]);
|
Gateway::whereIn('id', [1,3,7,15,20,39,46,55,50])->update(['visible' => 1]);
|
||||||
|
|
||||||
if (Ninja::isHosted()) {
|
if (Ninja::isHosted()) {
|
||||||
Gateway::whereIn('id', [20])->update(['visible' => 0]);
|
Gateway::whereIn('id', [20])->update(['visible' => 0]);
|
||||||
|
1112
package-lock.json
generated
1112
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,7 +27,7 @@
|
|||||||
"linkify-urls": "^3.1.1",
|
"linkify-urls": "^3.1.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"resolve-url-loader": "^3.1.4",
|
"resolve-url-loader": "^3.1.4",
|
||||||
"sass": "^1.35.2",
|
"sass": "^1.38.0",
|
||||||
"sass-loader": "^8.0.0",
|
"sass-loader": "^8.0.0",
|
||||||
"tailwindcss": "^1.9.6"
|
"tailwindcss": "^1.9.6"
|
||||||
}
|
}
|
||||||
|
2
public/js/clients/payments/eway-credit-card.js
vendored
Normal file
2
public/js/clients/payments/eway-credit-card.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
@ -11,6 +11,7 @@
|
|||||||
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=c35db3cbb65806ab6a8a",
|
"/js/clients/payments/braintree-paypal.js": "/js/clients/payments/braintree-paypal.js?id=c35db3cbb65806ab6a8a",
|
||||||
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=5469146cd629ea1b5c20",
|
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=5469146cd629ea1b5c20",
|
||||||
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=065e5450233cc5b47020",
|
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=065e5450233cc5b47020",
|
||||||
|
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=08ea84e9451abd434cff",
|
||||||
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=73b66e88e2daabcd6549",
|
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=73b66e88e2daabcd6549",
|
||||||
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=c8d3808a4c02d1392e96",
|
"/js/clients/payments/paytrace-credit-card.js": "/js/clients/payments/paytrace-credit-card.js?id=c8d3808a4c02d1392e96",
|
||||||
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
|
"/js/clients/payments/stripe-ach.js": "/js/clients/payments/stripe-ach.js?id=81c2623fc1e5769b51c7",
|
||||||
|
510
resources/js/clients/payments/eway-credit-card.js
vendored
Normal file
510
resources/js/clients/payments/eway-credit-card.js
vendored
Normal file
@ -0,0 +1,510 @@
|
|||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
class EwayRapid {
|
||||||
|
constructor() {
|
||||||
|
this.cardStyles =
|
||||||
|
'padding: 2px; border: 1px solid #AAA; border-radius: 3px; height: 34px; width: 100%;';
|
||||||
|
|
||||||
|
this.errorCodes = new Map();
|
||||||
|
|
||||||
|
this.errorCodes.set('V6000', 'Validation error');
|
||||||
|
this.errorCodes.set('V6001', 'Invalid CustomerIP');
|
||||||
|
this.errorCodes.set('V6002', 'Invalid DeviceID');
|
||||||
|
this.errorCodes.set('V6003', 'Invalid Request PartnerID');
|
||||||
|
this.errorCodes.set('V6004', 'Invalid Request Method');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6010',
|
||||||
|
'Invalid TransactionType, account not certified for eCome only MOTO or Recurring available'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6011', 'Invalid Payment TotalAmount');
|
||||||
|
this.errorCodes.set('V6012', 'Invalid Payment InvoiceDescription');
|
||||||
|
this.errorCodes.set('V6013', 'Invalid Payment InvoiceNumber');
|
||||||
|
this.errorCodes.set('V6014', 'Invalid Payment InvoiceReference');
|
||||||
|
this.errorCodes.set('V6015', 'Invalid Payment CurrencyCode');
|
||||||
|
this.errorCodes.set('V6016', 'Payment Required');
|
||||||
|
this.errorCodes.set('V6017', 'Payment CurrencyCode Required');
|
||||||
|
this.errorCodes.set('V6018', 'Unknown Payment CurrencyCode');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6019',
|
||||||
|
'Cardholder identity authentication required'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6020', 'Cardholder Input Required');
|
||||||
|
this.errorCodes.set('V6021', 'EWAY_CARDHOLDERNAME Required');
|
||||||
|
this.errorCodes.set('V6022', 'EWAY_CARDNUMBER Required');
|
||||||
|
this.errorCodes.set('V6023', 'EWAY_CARDCVN Required');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6024',
|
||||||
|
'Cardholder Identity Authentication One Time Password Not Active Yet'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6025', 'PIN Required');
|
||||||
|
this.errorCodes.set('V6033', 'Invalid Expiry Date');
|
||||||
|
this.errorCodes.set('V6034', 'Invalid Issue Number');
|
||||||
|
this.errorCodes.set('V6035', 'Invalid Valid From Date');
|
||||||
|
this.errorCodes.set('V6039', 'Invalid Network Token Status');
|
||||||
|
this.errorCodes.set('V6040', 'Invalid TokenCustomerID');
|
||||||
|
this.errorCodes.set('V6041', 'Customer Required');
|
||||||
|
this.errorCodes.set('V6042', 'Customer FirstName Required');
|
||||||
|
this.errorCodes.set('V6043', 'Customer LastName Required');
|
||||||
|
this.errorCodes.set('V6044', 'Customer CountryCode Required');
|
||||||
|
this.errorCodes.set('V6045', 'Customer Title Required');
|
||||||
|
this.errorCodes.set('V6046', 'TokenCustomerID Required');
|
||||||
|
this.errorCodes.set('V6047', 'RedirectURL Required');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6048',
|
||||||
|
'CheckoutURL Required when CheckoutPayment specified'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6049', 'nvalid Checkout URL');
|
||||||
|
this.errorCodes.set('V6051', 'Invalid Customer FirstName');
|
||||||
|
this.errorCodes.set('V6052', 'Invalid Customer LastName');
|
||||||
|
this.errorCodes.set('V6053', 'Invalid Customer CountryCode');
|
||||||
|
this.errorCodes.set('V6058', 'Invalid Customer Title');
|
||||||
|
this.errorCodes.set('V6059', 'Invalid RedirectURL');
|
||||||
|
this.errorCodes.set('V6060', 'Invalid TokenCustomerID');
|
||||||
|
this.errorCodes.set('V6061', 'Invalid Customer Reference');
|
||||||
|
this.errorCodes.set('V6062', 'Invalid Customer CompanyName');
|
||||||
|
this.errorCodes.set('V6063', 'Invalid Customer JobDescription');
|
||||||
|
this.errorCodes.set('V6064', 'Invalid Customer Street1');
|
||||||
|
this.errorCodes.set('V6065', 'Invalid Customer Street2');
|
||||||
|
this.errorCodes.set('V6066', 'Invalid Customer City');
|
||||||
|
this.errorCodes.set('V6067', 'Invalid Customer State');
|
||||||
|
this.errorCodes.set('V6068', 'Invalid Customer PostalCode');
|
||||||
|
this.errorCodes.set('V6069', 'Invalid Customer Email');
|
||||||
|
this.errorCodes.set('V6070', 'Invalid Customer Phone');
|
||||||
|
this.errorCodes.set('V6071', 'Invalid Customer Mobile');
|
||||||
|
this.errorCodes.set('V6072', 'Invalid Customer Comments');
|
||||||
|
this.errorCodes.set('V6073', 'Invalid Customer Fax');
|
||||||
|
this.errorCodes.set('V6074', 'Invalid Customer URL');
|
||||||
|
this.errorCodes.set('V6075', 'Invalid ShippingAddress FirstName');
|
||||||
|
this.errorCodes.set('V6076', 'Invalid ShippingAddress LastName');
|
||||||
|
this.errorCodes.set('V6077', 'Invalid ShippingAddress Street1');
|
||||||
|
this.errorCodes.set('V6078', 'Invalid ShippingAddress Street2');
|
||||||
|
this.errorCodes.set('V6079', 'Invalid ShippingAddress City');
|
||||||
|
this.errorCodes.set('V6080', 'Invalid ShippingAddress State');
|
||||||
|
this.errorCodes.set('V6081', 'Invalid ShippingAddress PostalCode');
|
||||||
|
this.errorCodes.set('V6082', 'Invalid ShippingAddress Email');
|
||||||
|
this.errorCodes.set('V6083', 'Invalid ShippingAddress Phone');
|
||||||
|
this.errorCodes.set('V6084', 'Invalid ShippingAddress Country');
|
||||||
|
this.errorCodes.set('V6085', 'Invalid ShippingAddress ShippingMethod');
|
||||||
|
this.errorCodes.set('V6086', 'Invalid ShippingAddress Fax');
|
||||||
|
this.errorCodes.set('V6091', 'Unknown Customer CountryCode');
|
||||||
|
this.errorCodes.set('V6092', 'Unknown ShippingAddress CountryCode');
|
||||||
|
this.errorCodes.set('V6093', 'Insufficient Address Information');
|
||||||
|
this.errorCodes.set('V6100', 'Invalid EWAY_CARDNAME');
|
||||||
|
this.errorCodes.set('V6101', 'Invalid EWAY_CARDEXPIRYMONTH');
|
||||||
|
this.errorCodes.set('V6102', 'Invalid EWAY_CARDEXPIRYYEAR');
|
||||||
|
this.errorCodes.set('V6103', 'Invalid EWAY_CARDSTARTMONTH');
|
||||||
|
this.errorCodes.set('V6104', 'Invalid EWAY_CARDSTARTYEAR');
|
||||||
|
this.errorCodes.set('V6105', 'Invalid EWAY_CARDISSUENUMBER');
|
||||||
|
this.errorCodes.set('V6106', 'Invalid EWAY_CARDCVN');
|
||||||
|
this.errorCodes.set('V6107', 'Invalid EWAY_ACCESSCODE');
|
||||||
|
this.errorCodes.set('V6108', 'Invalid CustomerHostAddress');
|
||||||
|
this.errorCodes.set('V6109', 'Invalid UserAgent');
|
||||||
|
this.errorCodes.set('V6110', 'Invalid EWAY_CARDNUMBER');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6111',
|
||||||
|
'Unauthorised API Access, Account Not PCI Certified'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6112',
|
||||||
|
'Redundant card details other than expiry year and month'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6113', 'Invalid transaction for refund');
|
||||||
|
this.errorCodes.set('V6114', 'Gateway validation error');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6115',
|
||||||
|
'Invalid DirectRefundRequest, Transaction ID'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6116',
|
||||||
|
'Invalid card data on original TransactionID'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6117',
|
||||||
|
'Invalid CreateAccessCodeSharedRequest, FooterText'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6118',
|
||||||
|
'Invalid CreateAccessCodeSharedRequest, HeaderText'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6119',
|
||||||
|
'Invalid CreateAccessCodeSharedRequest, Language'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6120',
|
||||||
|
'Invalid CreateAccessCodeSharedRequest, LogoUrl'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6121',
|
||||||
|
'Invalid TransactionSearch, Filter Match Type'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6122',
|
||||||
|
'Invalid TransactionSearch, Non numeric Transaction ID'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6123',
|
||||||
|
'Invalid TransactionSearch,no TransactionID or AccessCode specified'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6124',
|
||||||
|
'Invalid Line Items. The line items have been provided however the totals do not match the TotalAmount field'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6125', 'Selected Payment Type not enabled');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6126',
|
||||||
|
'Invalid encrypted card number, decryption failed'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6127',
|
||||||
|
'Invalid encrypted cvn, decryption failed'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6128', 'Invalid Method for Payment Type');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6129',
|
||||||
|
'Transaction has not been authorised for Capture/Cancellation'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6130', 'Generic customer information error');
|
||||||
|
this.errorCodes.set('V6131', 'Generic shipping information error');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6132',
|
||||||
|
'Transaction has already been completed or voided, operation not permitted'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6133', 'Checkout not available for Payment Type');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6134',
|
||||||
|
'Invalid Auth Transaction ID for Capture/Void'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6135', 'PayPal Error Processing Refund');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6136',
|
||||||
|
'Original transaction does not exist or state is incorrect'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6140', 'Merchant account is suspended');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6141',
|
||||||
|
'Invalid PayPal account details or API signature'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6142', 'Authorise not available for Bank/Branch');
|
||||||
|
this.errorCodes.set('V6143', 'Invalid Public Key');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6144',
|
||||||
|
'Method not available with Public API Key Authentication'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6145',
|
||||||
|
'Credit Card not allow if Token Customer ID is provided with Public API Key Authentication'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6146',
|
||||||
|
'Client Side Encryption Key Missing or Invalid'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6147',
|
||||||
|
'Unable to Create One Time Code for Secure Field'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6148', 'Secure Field has Expired');
|
||||||
|
this.errorCodes.set('V6149', 'Invalid Secure Field One Time Code');
|
||||||
|
this.errorCodes.set('V6150', 'Invalid Refund Amount');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6151',
|
||||||
|
'Refund amount greater than original transaction'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6152',
|
||||||
|
'Original transaction already refunded for total amount'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6153', 'Card type not support by merchant');
|
||||||
|
this.errorCodes.set('V6154', 'Insufficent Funds Available For Refund');
|
||||||
|
this.errorCodes.set('V6155', 'Missing one or more fields in request');
|
||||||
|
this.errorCodes.set('V6160', 'Encryption Method Not Supported');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6161',
|
||||||
|
'Encryption failed, missing or invalid key'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6165',
|
||||||
|
'Invalid Click-to-Pay (Visa Checkout) data or decryption failed'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6170',
|
||||||
|
'Invalid TransactionSearch, Invoice Number is not unique'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6171',
|
||||||
|
'Invalid TransactionSearch, Invoice Number not found'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6220', 'Three domain secure XID invalid');
|
||||||
|
this.errorCodes.set('V6221', 'Three domain secure ECI invalid');
|
||||||
|
this.errorCodes.set('V6222', 'Three domain secure AVV invalid');
|
||||||
|
this.errorCodes.set('V6223', 'Three domain secure XID is required');
|
||||||
|
this.errorCodes.set('V6224', 'Three Domain Secure ECI is required');
|
||||||
|
this.errorCodes.set('V6225', 'Three Domain Secure AVV is required');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6226',
|
||||||
|
'Three Domain Secure AuthStatus is required'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6227', 'Three Domain Secure AuthStatus invalid');
|
||||||
|
this.errorCodes.set('V6228', 'Three domain secure Version is required');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6230',
|
||||||
|
'Three domain secure Directory Server Txn ID invalid'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6231',
|
||||||
|
'Three domain secure Directory Server Txn ID is required'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6232', 'Three domain secure Version is invalid');
|
||||||
|
this.errorCodes.set('V6501', 'Invalid Amex InstallementPlan');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6502',
|
||||||
|
'Invalid Number Of Installements for Amex. Valid values are from 0 to 99 inclusive'
|
||||||
|
);
|
||||||
|
this.errorCodes.set('V6503', 'Merchant Amex ID required');
|
||||||
|
this.errorCodes.set('V6504', 'Invalid Merchant Amex ID');
|
||||||
|
this.errorCodes.set('V6505', 'Merchant Terminal ID required');
|
||||||
|
this.errorCodes.set('V6506', 'Merchant category code required');
|
||||||
|
this.errorCodes.set('V6507', 'Invalid merchant category code');
|
||||||
|
this.errorCodes.set('V6508', 'Amex 3D ECI required');
|
||||||
|
this.errorCodes.set('V6509', 'Invalid Amex 3D ECI');
|
||||||
|
this.errorCodes.set('V6510', 'Invalid Amex 3D verification value');
|
||||||
|
this.errorCodes.set('V6511', 'Invalid merchant location data');
|
||||||
|
this.errorCodes.set('V6512', 'Invalid merchant street address');
|
||||||
|
this.errorCodes.set('V6513', 'Invalid merchant city');
|
||||||
|
this.errorCodes.set('V6514', 'Invalid merchant country');
|
||||||
|
this.errorCodes.set('V6515', 'Invalid merchant phone');
|
||||||
|
this.errorCodes.set('V6516', 'Invalid merchant postcode');
|
||||||
|
this.errorCodes.set('V6517', 'Amex connection error');
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6518',
|
||||||
|
'Amex EC Card Details API returned invalid data'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6520',
|
||||||
|
'Invalid or missing Amex Point Of Sale Data'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6521',
|
||||||
|
'Invalid or missing Amex transaction date time'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6522',
|
||||||
|
'Invalid or missing Amex Original transaction date time'
|
||||||
|
);
|
||||||
|
this.errorCodes.set(
|
||||||
|
'V6530',
|
||||||
|
'Credit Card Number in non Credit Card Field'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get groupFieldConfig() {
|
||||||
|
return {
|
||||||
|
publicApiKey: document.querySelector('meta[name=public-api-key]')
|
||||||
|
?.content,
|
||||||
|
fieldDivId: 'eway-secure-panel',
|
||||||
|
fieldType: 'group',
|
||||||
|
styles: '',
|
||||||
|
layout: {
|
||||||
|
fonts: ['Lobster'],
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
styles: '',
|
||||||
|
cells: [
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: 'margin-top: 15px;',
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: document.querySelector(
|
||||||
|
'meta[name=translation-card-name]'
|
||||||
|
)?.content,
|
||||||
|
styles: '',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: 'name',
|
||||||
|
styles: this.cardStyles,
|
||||||
|
divStyles: 'padding-left: 10px;',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: 'margin-top: 15px;',
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: document.querySelector(
|
||||||
|
'meta[name=translation-expiry_date]'
|
||||||
|
)?.content,
|
||||||
|
styles: '',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: 'expirytext',
|
||||||
|
styles: this.cardStyles,
|
||||||
|
divStyles: 'padding-left: 10px;',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
styles: '',
|
||||||
|
cells: [
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: 'margin-top: 15px;',
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: document.querySelector(
|
||||||
|
'meta[name=translation-card_number]'
|
||||||
|
)?.content,
|
||||||
|
styles: '',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: 'card',
|
||||||
|
styles: this.cardStyles,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: 'margin-top: 15px;',
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: document.querySelector(
|
||||||
|
'meta[name=translation-cvv]'
|
||||||
|
)?.content,
|
||||||
|
styles: '',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: 'cvn',
|
||||||
|
styles: this.cardStyles,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
securePanelCallback(event) {
|
||||||
|
document.getElementById('errors').hidden = true;
|
||||||
|
|
||||||
|
if (event.errors) {
|
||||||
|
return this.handleErrors(event.errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById('authorize-card')) {
|
||||||
|
document.getElementById('authorize-card').disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.getElementById('pay-now')) {
|
||||||
|
document.getElementById('pay-now').disabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelector('input[name=securefieldcode]').value =
|
||||||
|
event.secureFieldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleErrors(errors) {
|
||||||
|
let _errors = errors.split(' ');
|
||||||
|
let shouldShowGenericError = false;
|
||||||
|
let message = '';
|
||||||
|
|
||||||
|
_errors.forEach((error) => {
|
||||||
|
message = message.concat(this.errorCodes.get(error) + '<br>');
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('errors').innerHTML = message;
|
||||||
|
document.getElementById('errors').hidden = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
completeAuthorization(event) {
|
||||||
|
event.target.parentElement.disabled = true;
|
||||||
|
|
||||||
|
document.getElementById('server-response').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
completePaymentUsingToken(event) {
|
||||||
|
event.target.parentElement.disabled = true;
|
||||||
|
|
||||||
|
document.getElementById('server-response').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
completePaymentWithoutToken(event) {
|
||||||
|
event.target.parentElement.disabled = true;
|
||||||
|
|
||||||
|
let tokenBillingCheckbox = document.querySelector(
|
||||||
|
'input[name="token-billing-checkbox"]:checked'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (tokenBillingCheckbox) {
|
||||||
|
document.querySelector('input[name="store_card"]').value =
|
||||||
|
tokenBillingCheckbox.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('server-response').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
initialize() {
|
||||||
|
this.eWAY = eWAY.setupSecureField(this.groupFieldConfig, (event) =>
|
||||||
|
this.securePanelCallback(event)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle() {
|
||||||
|
this.initialize();
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById('authorize-card')
|
||||||
|
?.addEventListener('click', (e) => this.completeAuthorization(e));
|
||||||
|
|
||||||
|
Array.from(
|
||||||
|
document.getElementsByClassName('toggle-payment-with-token')
|
||||||
|
).forEach((element) =>
|
||||||
|
element.addEventListener('click', (element) => {
|
||||||
|
document
|
||||||
|
.getElementById('eway-secure-panel')
|
||||||
|
.classList.add('hidden');
|
||||||
|
document.getElementById('save-card--container').style.display =
|
||||||
|
'none';
|
||||||
|
document.querySelector('input[name=token]').value =
|
||||||
|
element.target.dataset.token;
|
||||||
|
document.getElementById('pay-now').disabled = false;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById('toggle-payment-with-credit-card')
|
||||||
|
.addEventListener('click', (element) => {
|
||||||
|
document
|
||||||
|
.getElementById('eway-secure-panel')
|
||||||
|
.classList.remove('hidden');
|
||||||
|
document.getElementById('save-card--container').style.display =
|
||||||
|
'grid';
|
||||||
|
document.querySelector('input[name=token]').value = '';
|
||||||
|
document.getElementById('pay-now').disabled = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('pay-now')?.addEventListener('click', (e) => {
|
||||||
|
let tokenInput = document.querySelector('input[name=token]');
|
||||||
|
|
||||||
|
if (tokenInput.value) {
|
||||||
|
return this.completePaymentUsingToken(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.completePaymentWithoutToken(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new EwayRapid().handle();
|
@ -4296,6 +4296,8 @@ $LANG = array(
|
|||||||
'lang_Persian' => 'Persian',
|
'lang_Persian' => 'Persian',
|
||||||
'lang_Latvian' => 'Latvian',
|
'lang_Latvian' => 'Latvian',
|
||||||
'expiry_date' => 'Expiry date',
|
'expiry_date' => 'Expiry date',
|
||||||
|
'cardholder_name' => 'Card holder name',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' =>
|
||||||
|
ctrans('texts.credit_card')])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
<meta name="public-api-key" content="{{ $public_api_key }}">
|
||||||
|
<meta name="translation-card-name" content="{{ ctrans('texts.cardholder_name') }}">
|
||||||
|
<meta name="translation-expiry_date" content="{{ ctrans('texts.date') }}">
|
||||||
|
<meta name="translation-card_number" content="{{ ctrans('texts.card_number') }}">
|
||||||
|
<meta name="translation-cvv" content="{{ ctrans('texts.cvv') }}">
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_content')
|
||||||
|
<form action="{{ route('client.payment_methods.store', ['method' => App\Models\GatewayType::CREDIT_CARD]) }}"
|
||||||
|
method="post" id="server-response">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<input type="hidden" id="securefieldcode" name="securefieldcode">
|
||||||
|
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="payment_method_id" value="1">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
@if (!Request::isSecure())
|
||||||
|
<p class="alert alert-failure">{{ ctrans('texts.https_required') }}</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element-single')
|
||||||
|
<div id="eway-secure-panel"></div>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'authorize-card', 'disabled' => true])
|
||||||
|
{{ ctrans('texts.add_payment_method') }}
|
||||||
|
@endcomponent
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
<script src="https://secure.ewaypayments.com/scripts/eWAY.min.js" data-init="false"></script>
|
||||||
|
<script src="{{ asset('js/clients/payments/eway-credit-card.js') }}"></script>
|
||||||
|
@endsection
|
@ -0,0 +1,292 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
|
||||||
|
var labelStyles = "padding-right: 20px; float: right;";
|
||||||
|
var publicApiKey = "{{ $public_api_key }}";
|
||||||
|
var cardStyles = "padding: 2px; border: 1px solid #AAA; border-radius: 3px; height: 34px; width: 100%;";
|
||||||
|
var rowStyles = "";
|
||||||
|
var groupStyles = "";
|
||||||
|
|
||||||
|
var groupFieldConfig = {
|
||||||
|
publicApiKey: publicApiKey,
|
||||||
|
fieldDivId: "eway-secure-panel",
|
||||||
|
fieldType: "group",
|
||||||
|
styles: groupStyles,
|
||||||
|
layout : {
|
||||||
|
fonts: [
|
||||||
|
"Lobster"
|
||||||
|
],
|
||||||
|
rows : [
|
||||||
|
{
|
||||||
|
styles: rowStyles,
|
||||||
|
cells: [
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: "margin-top: 15px;",
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: "Card Name:",
|
||||||
|
styles: "",
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: "name",
|
||||||
|
styles: cardStyles,
|
||||||
|
divStyles: "padding-left: 10px;"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: "margin-top: 15px;",
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: "Expiry:",
|
||||||
|
styles: "",
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: "expirytext",
|
||||||
|
styles: cardStyles,
|
||||||
|
divStyles: "padding-left: 10px;"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
styles: rowStyles,
|
||||||
|
cells: [
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: "margin-top: 15px;",
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: "Card Number:",
|
||||||
|
styles: "",
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: "card",
|
||||||
|
styles: cardStyles,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
colSpan: 12,
|
||||||
|
styles: "margin-top: 15px;",
|
||||||
|
label: {
|
||||||
|
fieldColSpan: 4,
|
||||||
|
text: "CVV Number:",
|
||||||
|
styles: "",
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
fieldColSpan: 8,
|
||||||
|
fieldType: "cvn",
|
||||||
|
styles: cardStyles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function securePanelCallback(event) {
|
||||||
|
if (!event.fieldValid) {
|
||||||
|
alert(getError(event.errors));
|
||||||
|
} else {
|
||||||
|
var s = document.querySelector("input[name=securefieldcode]");
|
||||||
|
s.value = event.secureFieldCode
|
||||||
|
console.log(s.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doneCallback() {
|
||||||
|
console.log("done call bak");
|
||||||
|
var form = document.getElementById("server-response");
|
||||||
|
form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveAndSubmit() {
|
||||||
|
console.log("save and sub");
|
||||||
|
eWAY.saveAllFields(doneCallback, 2000);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function getError(k){
|
||||||
|
myArr = k.split(" ");
|
||||||
|
|
||||||
|
var str = "";
|
||||||
|
|
||||||
|
for(error in myArr){
|
||||||
|
str = str.concat(map.get(myArr[error])) + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
const map = new Map();
|
||||||
|
map.set('V6000', 'Validation error');
|
||||||
|
map.set('V6001', 'Invalid CustomerIP');
|
||||||
|
map.set('V6002', 'Invalid DeviceID');
|
||||||
|
map.set('V6003', 'Invalid Request PartnerID');
|
||||||
|
map.set('V6004', 'Invalid Request Method');
|
||||||
|
map.set('V6010', 'Invalid TransactionType, account not certified for eCome only MOTO or Recurring available');
|
||||||
|
map.set('V6011', 'Invalid Payment TotalAmount');
|
||||||
|
map.set('V6012', 'Invalid Payment InvoiceDescription');
|
||||||
|
map.set('V6013', 'Invalid Payment InvoiceNumber');
|
||||||
|
map.set('V6014', 'Invalid Payment InvoiceReference');
|
||||||
|
map.set('V6015', 'Invalid Payment CurrencyCode');
|
||||||
|
map.set('V6016', 'Payment Required');
|
||||||
|
map.set('V6017', 'Payment CurrencyCode Required');
|
||||||
|
map.set('V6018', 'Unknown Payment CurrencyCode');
|
||||||
|
map.set('V6019', 'Cardholder identity authentication required');
|
||||||
|
map.set('V6020', 'Cardholder Input Required');
|
||||||
|
map.set('V6021', 'EWAY_CARDHOLDERNAME Required');
|
||||||
|
map.set('V6022', 'EWAY_CARDNUMBER Required');
|
||||||
|
map.set('V6023', 'EWAY_CARDCVN Required');
|
||||||
|
map.set('V6024', 'Cardholder Identity Authentication One Time Password Not Active Yet');
|
||||||
|
map.set('V6025', 'PIN Required');
|
||||||
|
map.set('V6033', 'Invalid Expiry Date');
|
||||||
|
map.set('V6034', 'Invalid Issue Number');
|
||||||
|
map.set('V6035', 'Invalid Valid From Date');
|
||||||
|
map.set('V6039', 'Invalid Network Token Status');
|
||||||
|
map.set('V6040', 'Invalid TokenCustomerID');
|
||||||
|
map.set('V6041', 'Customer Required');
|
||||||
|
map.set('V6042', 'Customer FirstName Required');
|
||||||
|
map.set('V6043', 'Customer LastName Required');
|
||||||
|
map.set('V6044', 'Customer CountryCode Required');
|
||||||
|
map.set('V6045', 'Customer Title Required');
|
||||||
|
map.set('V6046', 'TokenCustomerID Required');
|
||||||
|
map.set('V6047', 'RedirectURL Required');
|
||||||
|
map.set('V6048', 'CheckoutURL Required when CheckoutPayment specified');
|
||||||
|
map.set('V6049', 'nvalid Checkout URL');
|
||||||
|
map.set('V6051', 'Invalid Customer FirstName');
|
||||||
|
map.set('V6052', 'Invalid Customer LastName');
|
||||||
|
map.set('V6053', 'Invalid Customer CountryCode');
|
||||||
|
map.set('V6058', 'Invalid Customer Title');
|
||||||
|
map.set('V6059', 'Invalid RedirectURL');
|
||||||
|
map.set('V6060', 'Invalid TokenCustomerID');
|
||||||
|
map.set('V6061', 'Invalid Customer Reference');
|
||||||
|
map.set('V6062', 'Invalid Customer CompanyName');
|
||||||
|
map.set('V6063', 'Invalid Customer JobDescription');
|
||||||
|
map.set('V6064', 'Invalid Customer Street1');
|
||||||
|
map.set('V6065', 'Invalid Customer Street2');
|
||||||
|
map.set('V6066', 'Invalid Customer City');
|
||||||
|
map.set('V6067', 'Invalid Customer State');
|
||||||
|
map.set('V6068', 'Invalid Customer PostalCode');
|
||||||
|
map.set('V6069', 'Invalid Customer Email');
|
||||||
|
map.set('V6070', 'Invalid Customer Phone');
|
||||||
|
map.set('V6071', 'Invalid Customer Mobile');
|
||||||
|
map.set('V6072', 'Invalid Customer Comments');
|
||||||
|
map.set('V6073', 'Invalid Customer Fax');
|
||||||
|
map.set('V6074', 'Invalid Customer URL');
|
||||||
|
map.set('V6075', 'Invalid ShippingAddress FirstName');
|
||||||
|
map.set('V6076', 'Invalid ShippingAddress LastName');
|
||||||
|
map.set('V6077', 'Invalid ShippingAddress Street1');
|
||||||
|
map.set('V6078', 'Invalid ShippingAddress Street2');
|
||||||
|
map.set('V6079', 'Invalid ShippingAddress City');
|
||||||
|
map.set('V6080', 'Invalid ShippingAddress State');
|
||||||
|
map.set('V6081', 'Invalid ShippingAddress PostalCode');
|
||||||
|
map.set('V6082', 'Invalid ShippingAddress Email');
|
||||||
|
map.set('V6083', 'Invalid ShippingAddress Phone');
|
||||||
|
map.set('V6084', 'Invalid ShippingAddress Country');
|
||||||
|
map.set('V6085', 'Invalid ShippingAddress ShippingMethod');
|
||||||
|
map.set('V6086', 'Invalid ShippingAddress Fax');
|
||||||
|
map.set('V6091', 'Unknown Customer CountryCode');
|
||||||
|
map.set('V6092', 'Unknown ShippingAddress CountryCode');
|
||||||
|
map.set('V6093', 'Insufficient Address Information');
|
||||||
|
map.set('V6100', 'Invalid EWAY_CARDNAME');
|
||||||
|
map.set('V6101', 'Invalid EWAY_CARDEXPIRYMONTH');
|
||||||
|
map.set('V6102', 'Invalid EWAY_CARDEXPIRYYEAR');
|
||||||
|
map.set('V6103', 'Invalid EWAY_CARDSTARTMONTH');
|
||||||
|
map.set('V6104', 'Invalid EWAY_CARDSTARTYEAR');
|
||||||
|
map.set('V6105', 'Invalid EWAY_CARDISSUENUMBER');
|
||||||
|
map.set('V6106', 'Invalid EWAY_CARDCVN');
|
||||||
|
map.set('V6107', 'Invalid EWAY_ACCESSCODE');
|
||||||
|
map.set('V6108', 'Invalid CustomerHostAddress');
|
||||||
|
map.set('V6109', 'Invalid UserAgent');
|
||||||
|
map.set('V6110', 'Invalid EWAY_CARDNUMBER');
|
||||||
|
map.set('V6111', 'Unauthorised API Access, Account Not PCI Certified');
|
||||||
|
map.set('V6112', 'Redundant card details other than expiry year and month');
|
||||||
|
map.set('V6113', 'Invalid transaction for refund');
|
||||||
|
map.set('V6114', 'Gateway validation error');
|
||||||
|
map.set('V6115', 'Invalid DirectRefundRequest, Transaction ID');
|
||||||
|
map.set('V6116', 'Invalid card data on original TransactionID');
|
||||||
|
map.set('V6117', 'Invalid CreateAccessCodeSharedRequest, FooterText');
|
||||||
|
map.set('V6118', 'Invalid CreateAccessCodeSharedRequest, HeaderText');
|
||||||
|
map.set('V6119', 'Invalid CreateAccessCodeSharedRequest, Language');
|
||||||
|
map.set('V6120', 'Invalid CreateAccessCodeSharedRequest, LogoUrl');
|
||||||
|
map.set('V6121', 'Invalid TransactionSearch, Filter Match Type');
|
||||||
|
map.set('V6122', 'Invalid TransactionSearch, Non numeric Transaction ID');
|
||||||
|
map.set('V6123', 'Invalid TransactionSearch,no TransactionID or AccessCode specified');
|
||||||
|
map.set('V6124', 'Invalid Line Items. The line items have been provided however the totals do not match the TotalAmount field');
|
||||||
|
map.set('V6125', 'Selected Payment Type not enabled');
|
||||||
|
map.set('V6126', 'Invalid encrypted card number, decryption failed');
|
||||||
|
map.set('V6127', 'Invalid encrypted cvn, decryption failed');
|
||||||
|
map.set('V6128', 'Invalid Method for Payment Type');
|
||||||
|
map.set('V6129', 'Transaction has not been authorised for Capture/Cancellation');
|
||||||
|
map.set('V6130', 'Generic customer information error');
|
||||||
|
map.set('V6131', 'Generic shipping information error');
|
||||||
|
map.set('V6132', 'Transaction has already been completed or voided, operation not permitted');
|
||||||
|
map.set('V6133', 'Checkout not available for Payment Type');
|
||||||
|
map.set('V6134', 'Invalid Auth Transaction ID for Capture/Void');
|
||||||
|
map.set('V6135', 'PayPal Error Processing Refund');
|
||||||
|
map.set('V6136', 'Original transaction does not exist or state is incorrect');
|
||||||
|
map.set('V6140', 'Merchant account is suspended');
|
||||||
|
map.set('V6141', 'Invalid PayPal account details or API signature');
|
||||||
|
map.set('V6142', 'Authorise not available for Bank/Branch');
|
||||||
|
map.set('V6143', 'Invalid Public Key');
|
||||||
|
map.set('V6144', 'Method not available with Public API Key Authentication');
|
||||||
|
map.set('V6145', 'Credit Card not allow if Token Customer ID is provided with Public API Key Authentication');
|
||||||
|
map.set('V6146', 'Client Side Encryption Key Missing or Invalid');
|
||||||
|
map.set('V6147', 'Unable to Create One Time Code for Secure Field');
|
||||||
|
map.set('V6148', 'Secure Field has Expired');
|
||||||
|
map.set('V6149', 'Invalid Secure Field One Time Code');
|
||||||
|
map.set('V6150', 'Invalid Refund Amount');
|
||||||
|
map.set('V6151', 'Refund amount greater than original transaction');
|
||||||
|
map.set('V6152', 'Original transaction already refunded for total amount');
|
||||||
|
map.set('V6153', 'Card type not support by merchant');
|
||||||
|
map.set('V6154', 'Insufficent Funds Available For Refund');
|
||||||
|
map.set('V6155', 'Missing one or more fields in request');
|
||||||
|
map.set('V6160', 'Encryption Method Not Supported');
|
||||||
|
map.set('V6161', 'Encryption failed, missing or invalid key');
|
||||||
|
map.set('V6165', 'Invalid Click-to-Pay (Visa Checkout) data or decryption failed');
|
||||||
|
map.set('V6170', 'Invalid TransactionSearch, Invoice Number is not unique');
|
||||||
|
map.set('V6171', 'Invalid TransactionSearch, Invoice Number not found');
|
||||||
|
map.set('V6220', 'Three domain secure XID invalid');
|
||||||
|
map.set('V6221', 'Three domain secure ECI invalid');
|
||||||
|
map.set('V6222', 'Three domain secure AVV invalid');
|
||||||
|
map.set('V6223', 'Three domain secure XID is required');
|
||||||
|
map.set('V6224', 'Three Domain Secure ECI is required');
|
||||||
|
map.set('V6225', 'Three Domain Secure AVV is required');
|
||||||
|
map.set('V6226', 'Three Domain Secure AuthStatus is required');
|
||||||
|
map.set('V6227', 'Three Domain Secure AuthStatus invalid');
|
||||||
|
map.set('V6228', 'Three domain secure Version is required');
|
||||||
|
map.set('V6230', 'Three domain secure Directory Server Txn ID invalid');
|
||||||
|
map.set('V6231', 'Three domain secure Directory Server Txn ID is required');
|
||||||
|
map.set('V6232', 'Three domain secure Version is invalid');
|
||||||
|
map.set('V6501', 'Invalid Amex InstallementPlan');
|
||||||
|
map.set('V6502', 'Invalid Number Of Installements for Amex. Valid values are from 0 to 99 inclusive');
|
||||||
|
map.set('V6503', 'Merchant Amex ID required');
|
||||||
|
map.set('V6504', 'Invalid Merchant Amex ID');
|
||||||
|
map.set('V6505', 'Merchant Terminal ID required');
|
||||||
|
map.set('V6506', 'Merchant category code required');
|
||||||
|
map.set('V6507', 'Invalid merchant category code');
|
||||||
|
map.set('V6508', 'Amex 3D ECI required');
|
||||||
|
map.set('V6509', 'Invalid Amex 3D ECI');
|
||||||
|
map.set('V6510', 'Invalid Amex 3D verification value');
|
||||||
|
map.set('V6511', 'Invalid merchant location data');
|
||||||
|
map.set('V6512', 'Invalid merchant street address');
|
||||||
|
map.set('V6513', 'Invalid merchant city');
|
||||||
|
map.set('V6514', 'Invalid merchant country');
|
||||||
|
map.set('V6515', 'Invalid merchant phone');
|
||||||
|
map.set('V6516', 'Invalid merchant postcode');
|
||||||
|
map.set('V6517', 'Amex connection error');
|
||||||
|
map.set('V6518', 'Amex EC Card Details API returned invalid data');
|
||||||
|
map.set('V6520', 'Invalid or missing Amex Point Of Sale Data');
|
||||||
|
map.set('V6521', 'Invalid or missing Amex transaction date time');
|
||||||
|
map.set('V6522', 'Invalid or missing Amex Original transaction date time');
|
||||||
|
map.set('V6530', 'Credit Card Number in non Credit Card Field');
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
62
resources/views/portal/ninja2020/gateways/eway/pay.blade.php
Normal file
62
resources/views/portal/ninja2020/gateways/eway/pay.blade.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.credit_card'), 'card_title' =>
|
||||||
|
ctrans('texts.credit_card')])
|
||||||
|
|
||||||
|
@section('gateway_head')
|
||||||
|
<meta name="public-api-key" content="{{ $public_api_key }}">
|
||||||
|
<meta name="translation-card-name" content="{{ ctrans('texts.cardholder_name') }}">
|
||||||
|
<meta name="translation-expiry_date" content="{{ ctrans('texts.date') }}">
|
||||||
|
<meta name="translation-card_number" content="{{ ctrans('texts.card_number') }}">
|
||||||
|
<meta name="translation-cvv" content="{{ ctrans('texts.cvv') }}">
|
||||||
|
@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" id="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="1">
|
||||||
|
<input type="hidden" name="token" id="token" value="">
|
||||||
|
<input type="hidden" name="securefieldcode" value="">
|
||||||
|
</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', ['title' => ctrans('texts.pay_with')])
|
||||||
|
@if (count($tokens) > 0)
|
||||||
|
@foreach ($tokens as $token)
|
||||||
|
<label class="mr-4">
|
||||||
|
<input type="radio" 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>
|
||||||
|
</label>
|
||||||
|
@endforeach
|
||||||
|
@endisset
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" 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>
|
||||||
|
</label>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@component('portal.ninja2020.components.general.card-element-single')
|
||||||
|
<div id="eway-secure-panel"></div>
|
||||||
|
@endcomponent
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.includes.save_card')
|
||||||
|
|
||||||
|
@include('portal.ninja2020.gateways.includes.pay_now', ['disabled' => true])
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('gateway_footer')
|
||||||
|
<script src="https://secure.ewaypayments.com/scripts/eWAY.min.js" data-init="false"></script>
|
||||||
|
<script src="{{ asset('js/clients/payments/eway-credit-card.js') }}"></script>
|
||||||
|
@endsection
|
@ -4,7 +4,8 @@
|
|||||||
type="{{ $type ?? 'button' }}"
|
type="{{ $type ?? 'button' }}"
|
||||||
id="{{ $id ?? 'pay-now' }}"
|
id="{{ $id ?? 'pay-now' }}"
|
||||||
@isset($data) @foreach($data as $prop => $value) data-{{ $prop }}="{{ $value }}" @endforeach @endisset
|
@isset($data) @foreach($data as $prop => $value) data-{{ $prop }}="{{ $value }}" @endforeach @endisset
|
||||||
class="button button-primary bg-primary {{ $class ?? '' }}">
|
class="button button-primary bg-primary {{ $class ?? '' }}"
|
||||||
|
{{ isset($disabled) && $disabled === true ? 'disabled' : '' }}>
|
||||||
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
<svg class="animate-spin h-5 w-5 text-white hidden" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||||
|
125
tests/Browser/ClientPortal/Gateways/Eway/CreditCardTest.php
Normal file
125
tests/Browser/ClientPortal/Gateways/Eway/CreditCardTest.php
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Tests\Browser\ClientPortal\Gateways\Eway;
|
||||||
|
|
||||||
|
use Laravel\Dusk\Browser;
|
||||||
|
use Tests\Browser\Pages\ClientPortal\Login;
|
||||||
|
use Tests\DuskTestCase;
|
||||||
|
|
||||||
|
class CreditCardTest extends DuskTestCase
|
||||||
|
{
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
foreach (static::$browsers as $browser) {
|
||||||
|
$browser->driver->manage()->deleteAllCookies();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visit(new Login())
|
||||||
|
->auth();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPaymentWithNewCard()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.invoices.index')
|
||||||
|
->click('@pay-now')
|
||||||
|
->click('@pay-now-dropdown')
|
||||||
|
->clickLink('Credit Card')
|
||||||
|
->withinFrame('iframe', function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->type('EWAY_CARDNAME', 'Invoice Ninja')
|
||||||
|
->type('EWAY_CARDNUMBER', '4111 1111 1111 1111')
|
||||||
|
->type('EWAY_CARDEXPIRY', '04/22')
|
||||||
|
->type('EWAY_CARDCVN', '100');
|
||||||
|
})
|
||||||
|
->click('#pay-now')
|
||||||
|
->waitForText('Details of the payment', 60);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPayWithNewCardAndSaveForFutureUse()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.invoices.index')
|
||||||
|
->click('@pay-now')
|
||||||
|
->click('@pay-now-dropdown')
|
||||||
|
->clickLink('Credit Card')
|
||||||
|
->withinFrame('iframe', function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->type('EWAY_CARDNAME', 'Invoice Ninja')
|
||||||
|
->type('EWAY_CARDNUMBER', '4111 1111 1111 1111')
|
||||||
|
->type('EWAY_CARDEXPIRY', '04/22')
|
||||||
|
->type('EWAY_CARDCVN', '100');
|
||||||
|
})
|
||||||
|
->radio('#proxy_is_default', true)
|
||||||
|
->click('#pay-now')
|
||||||
|
->waitForText('Details of the payment', 60)
|
||||||
|
->visitRoute('client.payment_methods.index')
|
||||||
|
->clickLink('View')
|
||||||
|
->assertSee('1111');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPayWithSavedCreditCard()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.invoices.index')
|
||||||
|
->click('@pay-now')
|
||||||
|
->click('@pay-now-dropdown')
|
||||||
|
->clickLink('Credit Card')
|
||||||
|
->click('.toggle-payment-with-token')
|
||||||
|
->click('#pay-now')
|
||||||
|
->waitForText('Details of the payment', 60);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRemoveCreditCard()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.payment_methods.index')
|
||||||
|
->clickLink('View')
|
||||||
|
->press('Remove Payment Method')
|
||||||
|
->waitForText('Confirmation')
|
||||||
|
->click('@confirm-payment-removal')
|
||||||
|
->assertSee('Payment method has been successfully removed.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAddingCreditCardStandalone()
|
||||||
|
{
|
||||||
|
$this->browse(function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->visitRoute('client.payment_methods.index')
|
||||||
|
->press('Add Payment Method')
|
||||||
|
->clickLink('Credit Card')
|
||||||
|
->withinFrame('iframe', function (Browser $browser) {
|
||||||
|
$browser
|
||||||
|
->type('EWAY_CARDNAME', 'Invoice Ninja')
|
||||||
|
->type('EWAY_CARDNUMBER', '4111 1111 1111 1111')
|
||||||
|
->type('EWAY_CARDEXPIRY', '04/22')
|
||||||
|
->type('EWAY_CARDCVN', '100');
|
||||||
|
})
|
||||||
|
->press('Add Payment Method')
|
||||||
|
->waitForText('**** 1111');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -11,8 +11,10 @@
|
|||||||
namespace Tests\Unit;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
use App\Factory\InvoiceInvitationFactory;
|
use App\Factory\InvoiceInvitationFactory;
|
||||||
|
use App\Models\CompanyToken;
|
||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
|
use Illuminate\Validation\ValidationException;
|
||||||
use Tests\MockAccountData;
|
use Tests\MockAccountData;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
@ -30,6 +32,9 @@ class InvitationTest extends TestCase
|
|||||||
$this->withoutMiddleware(
|
$this->withoutMiddleware(
|
||||||
ThrottleRequests::class
|
ThrottleRequests::class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->withoutExceptionHandling();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testInvitationSanity()
|
public function testInvitationSanity()
|
||||||
@ -54,9 +59,10 @@ class InvitationTest extends TestCase
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-TOKEN' => $this->token,
|
'X-API-TOKEN' => $this->token,
|
||||||
])->put('/api/v1/invoices/'.$this->encodePrimaryKey($this->invoice->id), $this->invoice->toArray());
|
])->put('/api/v1/invoices/'.$this->encodePrimaryKey($this->invoice->id), $this->invoice->toArray());
|
||||||
} catch (\Exception $e) {
|
} catch (ValidationException $e) {
|
||||||
|
|
||||||
nlog($e->getMessage());
|
nlog($e->getMessage());
|
||||||
}
|
}
|
||||||
|
4
webpack.mix.js
vendored
4
webpack.mix.js
vendored
@ -89,6 +89,10 @@ mix.js("resources/js/app.js", "public/js")
|
|||||||
.js(
|
.js(
|
||||||
"resources/js/clients/payments/mollie-credit-card.js",
|
"resources/js/clients/payments/mollie-credit-card.js",
|
||||||
"public/js/clients/payments/mollie-credit-card.js"
|
"public/js/clients/payments/mollie-credit-card.js"
|
||||||
|
)
|
||||||
|
.js(
|
||||||
|
"resources/js/clients/payments/eway-credit-card.js",
|
||||||
|
"public/js/clients/payments/eway-credit-card.js"
|
||||||
);
|
);
|
||||||
|
|
||||||
mix.copyDirectory('node_modules/card-js/card-js.min.css', 'public/css/card-js.min.css');
|
mix.copyDirectory('node_modules/card-js/card-js.min.css', 'public/css/card-js.min.css');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user