mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-12 22:22:32 +01:00
Add basic ACH support
This commit is contained in:
parent
e5fb354643
commit
c536bd8569
@ -117,7 +117,7 @@ class AccountGatewayController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$paymentTypes[$type] = trans('texts.'.strtolower($type));
|
$paymentTypes[$type] = $type == PAYMENT_TYPE_CREDIT_CARD ? trans('texts.other_providers'): trans('texts.'.strtolower($type));
|
||||||
|
|
||||||
if ($type == PAYMENT_TYPE_BITCOIN) {
|
if ($type == PAYMENT_TYPE_BITCOIN) {
|
||||||
$paymentTypes[$type] .= ' - BitPay';
|
$paymentTypes[$type] .= ' - BitPay';
|
||||||
|
@ -32,9 +32,8 @@ class AuthController extends Controller {
|
|||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
$data['account'] = $account;
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,9 +49,7 @@ class PasswordController extends Controller {
|
|||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
$data['account'] = $account;
|
||||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,9 +114,8 @@ class PasswordController extends Controller {
|
|||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
$data['account'] = $account;
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ class PaymentController extends BaseController
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show_payment($invitationKey, $paymentType = false)
|
public function show_payment($invitationKey, $paymentType = false, $sourceId = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
||||||
@ -155,27 +155,31 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
if ($paymentType == PAYMENT_TYPE_TOKEN) {
|
||||||
$useToken = true;
|
$useToken = true;
|
||||||
$paymentType = PAYMENT_TYPE_CREDIT_CARD;
|
$accountGateway = $invoice->client->account->getTokenGateway();
|
||||||
|
$paymentType = $accountGateway->getPaymentType();
|
||||||
|
} else {
|
||||||
|
$accountGateway = $invoice->client->account->getGatewayByType($paymentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::put($invitation->id . 'payment_type', $paymentType);
|
Session::put($invitation->id . 'payment_type', $paymentType);
|
||||||
|
|
||||||
$accountGateway = $invoice->client->account->getGatewayByType($paymentType);
|
|
||||||
$gateway = $accountGateway->gateway;
|
$gateway = $accountGateway->gateway;
|
||||||
|
|
||||||
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
||||||
|
|
||||||
|
$isOffsite = ($paymentType != PAYMENT_TYPE_CREDIT_CARD && $accountGateway->getPaymentType() != PAYMENT_TYPE_STRIPE)
|
||||||
// Handle offsite payments
|
|
||||||
if ($useToken || $paymentType != PAYMENT_TYPE_CREDIT_CARD
|
|
||||||
|| $gateway->id == GATEWAY_EWAY
|
|| $gateway->id == GATEWAY_EWAY
|
||||||
|| $gateway->id == GATEWAY_TWO_CHECKOUT
|
|| $gateway->id == GATEWAY_TWO_CHECKOUT
|
||||||
|| $gateway->id == GATEWAY_PAYFAST
|
|| $gateway->id == GATEWAY_PAYFAST
|
||||||
|| $gateway->id == GATEWAY_MOLLIE) {
|
|| $gateway->id == GATEWAY_MOLLIE;
|
||||||
|
|
||||||
|
// Handle offsite payments
|
||||||
|
if ($useToken || $isOffsite) {
|
||||||
if (Session::has('error')) {
|
if (Session::has('error')) {
|
||||||
Session::reflash();
|
Session::reflash();
|
||||||
return Redirect::to('view/'.$invitationKey);
|
return Redirect::to('view/'.$invitationKey);
|
||||||
} else {
|
} else {
|
||||||
return self::do_payment($invitationKey, false, $useToken);
|
return self::do_payment($invitationKey, false, $useToken, $sourceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,22 +193,24 @@ class PaymentController extends BaseController
|
|||||||
'gateway' => $gateway,
|
'gateway' => $gateway,
|
||||||
'accountGateway' => $accountGateway,
|
'accountGateway' => $accountGateway,
|
||||||
'acceptedCreditCardTypes' => $acceptedCreditCardTypes,
|
'acceptedCreditCardTypes' => $acceptedCreditCardTypes,
|
||||||
|
'paymentType' => $paymentType,
|
||||||
'countries' => Cache::get('countries'),
|
'countries' => Cache::get('countries'),
|
||||||
'currencyId' => $client->getCurrencyId(),
|
'currencyId' => $client->getCurrencyId(),
|
||||||
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
||||||
'account' => $client->account,
|
'account' => $client->account,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
'clientFontUrl' => $client->account->getFontsUrl(),
|
||||||
'hideHeader' => $account->isNinjaAccount(),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
|
||||||
'showAddress' => $accountGateway->show_address,
|
'showAddress' => $accountGateway->show_address,
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($gateway->id = GATEWAY_BRAINTREE) {
|
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH) {
|
||||||
|
$data['currencies'] = Cache::get('currencies');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($gateway->id == GATEWAY_BRAINTREE) {
|
||||||
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
|
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
|
||||||
}
|
}
|
||||||
|
|
||||||
return View::make('payments.payment', $data);
|
return View::make('payments.add_paymentmethod', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show_license_payment()
|
public function show_license_payment()
|
||||||
@ -235,7 +241,7 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
$account = $this->accountRepo->getNinjaAccount();
|
$account = $this->accountRepo->getNinjaAccount();
|
||||||
$account->load('account_gateways.gateway');
|
$account->load('account_gateways.gateway');
|
||||||
$accountGateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD);
|
$accountGateway = $account->getGatewayByType(PAYMENT_TYPE_STRIPE_CREDIT_CARD);
|
||||||
$gateway = $accountGateway->gateway;
|
$gateway = $accountGateway->gateway;
|
||||||
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
||||||
|
|
||||||
@ -260,7 +266,7 @@ class PaymentController extends BaseController
|
|||||||
'showAddress' => true,
|
'showAddress' => true,
|
||||||
];
|
];
|
||||||
|
|
||||||
return View::make('payments.payment', $data);
|
return View::make('payments.add_paymentmethod', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function do_license_payment()
|
public function do_license_payment()
|
||||||
@ -291,7 +297,7 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
$account = $this->accountRepo->getNinjaAccount();
|
$account = $this->accountRepo->getNinjaAccount();
|
||||||
$account->load('account_gateways.gateway');
|
$account->load('account_gateways.gateway');
|
||||||
$accountGateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD);
|
$accountGateway = $account->getGatewayByType(PAYMENT_TYPE_STRIPE_CREDIT_CARD);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$affiliate = Affiliate::find(Session::get('affiliate_id'));
|
$affiliate = Affiliate::find(Session::get('affiliate_id'));
|
||||||
@ -367,13 +373,14 @@ class PaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function do_payment($invitationKey, $onSite = true, $useToken = false)
|
public function do_payment($invitationKey, $onSite = true, $useToken = false, $sourceId = false)
|
||||||
{
|
{
|
||||||
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.currency', 'invoice.client.account.account_gateways.gateway')->where('invitation_key', '=', $invitationKey)->firstOrFail();
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
$accountGateway = $account->getGatewayByType(Session::get($invitation->id . 'payment_type'));
|
$paymentType = Session::get($invitation->id . 'payment_type');
|
||||||
|
$accountGateway = $account->getGatewayByType($paymentType);
|
||||||
|
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
@ -445,11 +452,20 @@ class PaymentController extends BaseController
|
|||||||
if ($useToken) {
|
if ($useToken) {
|
||||||
$details['customerReference'] = $client->getGatewayToken();
|
$details['customerReference'] = $client->getGatewayToken();
|
||||||
unset($details['token']);
|
unset($details['token']);
|
||||||
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) {
|
if ($sourceId) {
|
||||||
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference);
|
$details['cardReference'] = $sourceId;
|
||||||
|
}
|
||||||
|
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing') || $paymentType == PAYMENT_TYPE_STRIPE_ACH) {
|
||||||
|
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */);
|
||||||
if ($token) {
|
if ($token) {
|
||||||
$details['token'] = $token;
|
$details['token'] = $token;
|
||||||
$details['customerReference'] = $customerReference;
|
$details['customerReference'] = $customerReference;
|
||||||
|
|
||||||
|
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty($usingPlaid) ) {
|
||||||
|
// The user needs to complete verification
|
||||||
|
Session::flash('message', trans('texts.bank_account_verification_next_steps'));
|
||||||
|
return Redirect::to('/client/paymentmethods');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
$this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
||||||
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
|
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
|
||||||
@ -463,11 +479,15 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
if ($useToken) {
|
if ($useToken) {
|
||||||
$details['customerId'] = $customerId = $client->getGatewayToken();
|
$details['customerId'] = $customerId = $client->getGatewayToken();
|
||||||
$customer = $gateway->findCustomer($customerId)->send();
|
if (!$sourceId) {
|
||||||
$details['paymentMethodToken'] = $customer->getData()->paymentMethods[0]->token;
|
$customer = $gateway->findCustomer($customerId)->send();
|
||||||
|
$details['paymentMethodToken'] = $customer->getData()->paymentMethods[0]->token;
|
||||||
|
} else {
|
||||||
|
$details['paymentMethodToken'] = $sourceId;
|
||||||
|
}
|
||||||
unset($details['token']);
|
unset($details['token']);
|
||||||
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) {
|
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing')) {
|
||||||
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference);
|
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */);
|
||||||
if ($token) {
|
if ($token) {
|
||||||
$details['paymentMethodToken'] = $token;
|
$details['paymentMethodToken'] = $token;
|
||||||
$details['customerId'] = $customerReference;
|
$details['customerId'] = $customerReference;
|
||||||
@ -683,4 +703,85 @@ class PaymentController extends BaseController
|
|||||||
Session::flash('error', $message);
|
Session::flash('error', $message);
|
||||||
Utils::logError("Payment Error [{$type}]: " . ($exception ? Utils::getErrorString($exception) : $message), 'PHP', true);
|
Utils::logError("Payment Error [{$type}]: " . ($exception ? Utils::getErrorString($exception) : $message), 'PHP', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBankInfo($routingNumber) {
|
||||||
|
if (strlen($routingNumber) != 9 || !preg_match('/\d{9}/', $routingNumber)) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Invalid routing number',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = static::getBankData($routingNumber);
|
||||||
|
|
||||||
|
if (is_string($data)) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => $data,
|
||||||
|
], 500);
|
||||||
|
} elseif (!empty($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Bank not found',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getBankData($routingNumber) {
|
||||||
|
$cached = Cache::get('bankData:'.$routingNumber);
|
||||||
|
|
||||||
|
if ($cached != null) {
|
||||||
|
return $cached == false ? null : $cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dataPath = base_path('vendor/gatepay/FedACHdir/FedACHdir.txt');
|
||||||
|
|
||||||
|
if (!file_exists($dataPath) || !$size = filesize($dataPath)) {
|
||||||
|
return 'Invalid data file';
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineSize = 157;
|
||||||
|
$numLines = $size/$lineSize;
|
||||||
|
|
||||||
|
if ($numLines % 1 != 0) {
|
||||||
|
// The number of lines should be an integer
|
||||||
|
return 'Invalid data file';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format: http://www.sco.ca.gov/Files-21C/Bank_Master_Interface_Information_Package.pdf
|
||||||
|
$file = fopen($dataPath, 'r');
|
||||||
|
|
||||||
|
// Binary search
|
||||||
|
$low = 0;
|
||||||
|
$high = $numLines - 1;
|
||||||
|
while ($low <= $high) {
|
||||||
|
$mid = floor(($low + $high) / 2);
|
||||||
|
|
||||||
|
fseek($file, $mid * $lineSize);
|
||||||
|
$thisNumber = fread($file, 9);
|
||||||
|
|
||||||
|
if ($thisNumber > $routingNumber) {
|
||||||
|
$high = $mid - 1;
|
||||||
|
} else if ($thisNumber < $routingNumber) {
|
||||||
|
$low = $mid + 1;
|
||||||
|
} else {
|
||||||
|
$data = array('routing_number' => $thisNumber);
|
||||||
|
fseek($file, 26, SEEK_CUR);
|
||||||
|
$data['name'] = trim(fread($file, 36));
|
||||||
|
$data['address'] = trim(fread($file, 36));
|
||||||
|
$data['city'] = trim(fread($file, 20));
|
||||||
|
$data['state'] = fread($file, 2);
|
||||||
|
$data['zip'] = fread($file, 5).'-'.fread($file, 4);
|
||||||
|
$data['phone'] = fread($file, 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data)) {
|
||||||
|
Cache::put('bankData:'.$routingNumber, $data, 5);
|
||||||
|
return $data;
|
||||||
|
} else {
|
||||||
|
Cache::put('bankData:'.$routingNumber, false, 5);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ use Request;
|
|||||||
use Response;
|
use Response;
|
||||||
use Session;
|
use Session;
|
||||||
use Datatable;
|
use Datatable;
|
||||||
|
use Validator;
|
||||||
|
use Cache;
|
||||||
use App\Models\Gateway;
|
use App\Models\Gateway;
|
||||||
use App\Models\Invitation;
|
use App\Models\Invitation;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
@ -94,7 +96,7 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
$paymentTypes = $this->getPaymentTypes($client, $invitation);
|
$paymentTypes = $this->getPaymentTypes($client, $invitation);
|
||||||
$paymentURL = '';
|
$paymentURL = '';
|
||||||
if (count($paymentTypes)) {
|
if (count($paymentTypes) == 1) {
|
||||||
$paymentURL = $paymentTypes[0]['url'];
|
$paymentURL = $paymentTypes[0]['url'];
|
||||||
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
|
if (!$account->isGatewayConfigured(GATEWAY_PAYPAL_EXPRESS)) {
|
||||||
$paymentURL = URL::to($paymentURL);
|
$paymentURL = URL::to($paymentURL);
|
||||||
@ -126,11 +128,6 @@ class PublicClientController extends BaseController
|
|||||||
'account' => $account,
|
'account' => $account,
|
||||||
'showApprove' => $showApprove,
|
'showApprove' => $showApprove,
|
||||||
'showBreadcrumbs' => false,
|
'showBreadcrumbs' => false,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
|
||||||
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
|
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'invoice' => $invoice->hidePrivateFields(),
|
'invoice' => $invoice->hidePrivateFields(),
|
||||||
'invitation' => $invitation,
|
'invitation' => $invitation,
|
||||||
@ -161,23 +158,67 @@ class PublicClientController extends BaseController
|
|||||||
$paymentTypes = [];
|
$paymentTypes = [];
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
if ($client->getGatewayToken()) {
|
$paymentMethods = $this->paymentService->getClientPaymentMethods($client);
|
||||||
$paymentTypes[] = [
|
|
||||||
'url' => URL::to("payment/{$invitation->invitation_key}/token"), 'label' => trans('texts.use_card_on_file')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
foreach(Gateway::$paymentTypes as $type) {
|
|
||||||
if ($account->getGatewayByType($type)) {
|
|
||||||
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
|
|
||||||
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
|
|
||||||
|
|
||||||
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
if ($paymentMethods) {
|
||||||
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
|
foreach ($paymentMethods as $paymentMethod) {
|
||||||
$url = 'javascript:window.open("'.$url.'", "_blank")';
|
if ($paymentMethod['type']->id != PAYMENT_TYPE_ACH || $paymentMethod['status'] == 'verified') {
|
||||||
|
|
||||||
|
if ($paymentMethod['type']->id == PAYMENT_TYPE_ACH) {
|
||||||
|
$html = '<div>'.htmlentities($paymentMethod['bank_name']).'</div>';
|
||||||
|
} else {
|
||||||
|
$code = htmlentities(str_replace(' ', '', strtolower($paymentMethod['type']->name)));
|
||||||
|
$html = '<img height="22" src="'.URL::to('/images/credit_cards/'.$code.'.png').'" alt="'.trans("texts.card_".$code).'">';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($paymentMethod['type']->id != PAYMENT_TYPE_ACH) {
|
||||||
|
$html .= '<div class="pull-right" style="text-align:right">'.trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($paymentMethod['expiration'], false)->format('m/y'))).'<br>';
|
||||||
|
} else {
|
||||||
|
$html .= '<div style="text-align:right">';
|
||||||
|
}
|
||||||
|
$html .= '•••'.$paymentMethod['last4'].'</div>';
|
||||||
|
|
||||||
|
$paymentTypes[] = [
|
||||||
|
'url' => URL::to("/payment/{$invitation->invitation_key}/token/".$paymentMethod['id']),
|
||||||
|
'label' => $html,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach(Gateway::$paymentTypes as $type) {
|
||||||
|
if ($gateway = $account->getGatewayByType($type)) {
|
||||||
|
$types = array($type);
|
||||||
|
|
||||||
|
if ($type == PAYMENT_TYPE_STRIPE) {
|
||||||
|
$types = array(PAYMENT_TYPE_STRIPE_CREDIT_CARD);
|
||||||
|
if ($gateway->getAchEnabled()) {
|
||||||
|
$types[] = PAYMENT_TYPE_STRIPE_ACH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach($types as $type) {
|
||||||
|
$typeLink = strtolower(str_replace('PAYMENT_TYPE_', '', $type));
|
||||||
|
$url = URL::to("/payment/{$invitation->invitation_key}/{$typeLink}");
|
||||||
|
|
||||||
|
// PayPal doesn't allow being run in an iframe so we need to open in new tab
|
||||||
|
if ($type === PAYMENT_TYPE_PAYPAL && $account->iframe_url) {
|
||||||
|
$url = 'javascript:window.open("' . $url . '", "_blank")';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type == PAYMENT_TYPE_STRIPE_CREDIT_CARD) {
|
||||||
|
$label = trans('texts.' . strtolower(PAYMENT_TYPE_CREDIT_CARD));
|
||||||
|
} elseif ($type == PAYMENT_TYPE_STRIPE_ACH) {
|
||||||
|
$label = trans('texts.' . strtolower(PAYMENT_TYPE_DIRECT_DEBIT));
|
||||||
|
} else {
|
||||||
|
$label = trans('texts.' . strtolower($type));
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentTypes[] = [
|
||||||
|
'url' => $url, 'label' => $label
|
||||||
|
];
|
||||||
}
|
}
|
||||||
$paymentTypes[] = [
|
|
||||||
'url' => $url, 'label' => trans('texts.'.strtolower($type))
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,9 +265,6 @@ class PublicClientController extends BaseController
|
|||||||
'color' => $color,
|
'color' => $color,
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'client' => $client,
|
'client' => $client,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -248,7 +286,7 @@ class PublicClientController extends BaseController
|
|||||||
->addColumn('activity_type_id', function ($model) {
|
->addColumn('activity_type_id', function ($model) {
|
||||||
$data = [
|
$data = [
|
||||||
'client' => Utils::getClientDisplayName($model),
|
'client' => Utils::getClientDisplayName($model),
|
||||||
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->user_first_name . ' ' . $model->user_last_name),
|
'user' => $model->is_system ? ('<i>' . trans('texts.system') . '</i>') : ($model->user_first_name . ' ' . $model->user_last_name),
|
||||||
'invoice' => trans('texts.invoice') . ' ' . $model->invoice,
|
'invoice' => trans('texts.invoice') . ' ' . $model->invoice,
|
||||||
'contact' => Utils::getClientDisplayName($model),
|
'contact' => Utils::getClientDisplayName($model),
|
||||||
'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''),
|
'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''),
|
||||||
@ -280,10 +318,7 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
'account' => $account,
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.invoices'),
|
'title' => trans('texts.invoices'),
|
||||||
'entityType' => ENTITY_INVOICE,
|
'entityType' => ENTITY_INVOICE,
|
||||||
@ -317,10 +352,7 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
'account' => $account,
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'entityType' => ENTITY_PAYMENT,
|
'entityType' => ENTITY_PAYMENT,
|
||||||
'title' => trans('texts.payments'),
|
'title' => trans('texts.payments'),
|
||||||
@ -345,8 +377,17 @@ class PublicClientController extends BaseController
|
|||||||
if (!$model->last4) return '';
|
if (!$model->last4) return '';
|
||||||
$code = str_replace(' ', '', strtolower($model->payment_type));
|
$code = str_replace(' ', '', strtolower($model->payment_type));
|
||||||
$card_type = trans("texts.card_" . $code);
|
$card_type = trans("texts.card_" . $code);
|
||||||
$expiration = trans('texts.card_expiration', array('expires'=>Utils::fromSqlDate($model->expiration, false)->format('m/y')));
|
if ($model->payment_type_id != PAYMENT_TYPE_ACH) {
|
||||||
return '<img height="22" src="'.URL::to('/images/credit_cards/'.$code.'.png').'" alt="'.htmlentities($card_type).'"> •••'.$model->last4.' '.$expiration;
|
$expiration = trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($model->expiration, false)->format('m/y')));
|
||||||
|
return '<img height="22" src="' . URL::to('/images/credit_cards/' . $code . '.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4 . ' ' . $expiration;
|
||||||
|
} else {
|
||||||
|
$bankData = PaymentController::getBankData($model->routing_number);
|
||||||
|
if (is_array($bankData)) {
|
||||||
|
return $bankData['name'].' •••' . $model->last4;
|
||||||
|
} else {
|
||||||
|
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); })
|
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id); })
|
||||||
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
|
->addColumn('payment_date', function ($model) { return Utils::dateToString($model->payment_date); })
|
||||||
@ -397,10 +438,7 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
'account' => $account,
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.quotes'),
|
'title' => trans('texts.quotes'),
|
||||||
'entityType' => ENTITY_QUOTE,
|
'entityType' => ENTITY_QUOTE,
|
||||||
@ -435,10 +473,7 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
'account' => $account,
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
|
||||||
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.documents'),
|
'title' => trans('texts.documents'),
|
||||||
'entityType' => ENTITY_DOCUMENT,
|
'entityType' => ENTITY_DOCUMENT,
|
||||||
@ -632,4 +667,169 @@ class PublicClientController extends BaseController
|
|||||||
return DocumentController::getDownloadResponse($document);
|
return DocumentController::getDownloadResponse($document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function paymentMethods()
|
||||||
|
{
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$account = $client->account;
|
||||||
|
$paymentMethods = $this->paymentService->getClientPaymentMethods($client);
|
||||||
|
|
||||||
|
$data = array(
|
||||||
|
'account' => $account,
|
||||||
|
'color' => $account->primary_color ? $account->primary_color : '#0b4d78',
|
||||||
|
'client' => $client,
|
||||||
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
|
'paymentMethods' => $paymentMethods,
|
||||||
|
'gateway' => $account->getTokenGateway(),
|
||||||
|
'title' => trans('texts.payment_methods')
|
||||||
|
);
|
||||||
|
|
||||||
|
return response()->view('payments.paymentmethods', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyPaymentMethod()
|
||||||
|
{
|
||||||
|
$sourceId = Input::get('source_id');
|
||||||
|
$amount1 = Input::get('verification1');
|
||||||
|
$amount2 = Input::get('verification2');
|
||||||
|
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$result = $this->paymentService->verifyClientPaymentMethod($client, $sourceId, $amount1, $amount2);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
Session::flash('error', $result);
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.payment_method_verified'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('/client/paymentmethods/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removePaymentMethod($sourceId)
|
||||||
|
{
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$result = $this->paymentService->removeClientPaymentMethod($client, $sourceId);
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
Session::flash('error', $result);
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.payment_method_removed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('/client/paymentmethods/');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addPaymentMethod($paymentType)
|
||||||
|
{
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice = $invitation->invoice;
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$account = $client->account;
|
||||||
|
|
||||||
|
$typeLink = $paymentType;
|
||||||
|
$paymentType = 'PAYMENT_TYPE_' . strtoupper($paymentType);
|
||||||
|
$accountGateway = $invoice->client->account->getTokenGateway();
|
||||||
|
$gateway = $accountGateway->gateway;
|
||||||
|
$acceptedCreditCardTypes = $accountGateway->getCreditcardTypes();
|
||||||
|
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'showBreadcrumbs' => false,
|
||||||
|
'client' => $client,
|
||||||
|
'contact' => $invitation->contact,
|
||||||
|
'gateway' => $gateway,
|
||||||
|
'accountGateway' => $accountGateway,
|
||||||
|
'acceptedCreditCardTypes' => $acceptedCreditCardTypes,
|
||||||
|
'paymentType' => $paymentType,
|
||||||
|
'countries' => Cache::get('countries'),
|
||||||
|
'currencyId' => $client->getCurrencyId(),
|
||||||
|
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
||||||
|
'account' => $account,
|
||||||
|
'url' => URL::to('client/paymentmethods/add/'.$typeLink),
|
||||||
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
|
'showAddress' => $accountGateway->show_address,
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH) {
|
||||||
|
|
||||||
|
$data['currencies'] = Cache::get('currencies');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($gateway->id == GATEWAY_BRAINTREE) {
|
||||||
|
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
|
||||||
|
}
|
||||||
|
|
||||||
|
return View::make('payments.add_paymentmethod', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postAddPaymentMethod($paymentType)
|
||||||
|
{
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentType = 'PAYMENT_TYPE_' . strtoupper($paymentType);
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$account = $client->account;
|
||||||
|
|
||||||
|
$accountGateway = $account->getGatewayByType($paymentType);
|
||||||
|
$sourceToken = $accountGateway->gateway_id == GATEWAY_STRIPE ? Input::get('stripeToken'):Input::get('payment_method_nonce');
|
||||||
|
|
||||||
|
if ($sourceToken) {
|
||||||
|
$details = array('token' => $sourceToken);
|
||||||
|
$gateway = $this->paymentService->createGateway($accountGateway);
|
||||||
|
$sourceId = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id);
|
||||||
|
} else {
|
||||||
|
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(empty($sourceId)) {
|
||||||
|
$this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
||||||
|
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
|
||||||
|
} else if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty($usingPlaid) ) {
|
||||||
|
// The user needs to complete verification
|
||||||
|
Session::flash('message', trans('texts.bank_account_verification_next_steps'));
|
||||||
|
return Redirect::to('client/paymentmethods/add/' . $paymentType);
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.payment_method_added'));
|
||||||
|
return redirect()->to('/client/paymentmethods/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDefaultPaymentMethod(){
|
||||||
|
if (!$invitation = $this->getInvitation()) {
|
||||||
|
return $this->returnError();
|
||||||
|
}
|
||||||
|
|
||||||
|
$validator = Validator::make(Input::all(), array('source' => 'required'));
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return Redirect::to('client/paymentmethods');
|
||||||
|
}
|
||||||
|
|
||||||
|
$client = $invitation->invoice->client;
|
||||||
|
$result = $this->paymentService->setClientDefaultPaymentMethod($client, Input::get('source'));
|
||||||
|
|
||||||
|
if (is_string($result)) {
|
||||||
|
Session::flash('error', $result);
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.payment_method_set_as_default'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('/client/paymentmethods/');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,15 @@ Route::group(['middleware' => 'auth:client'], function() {
|
|||||||
Route::get('download/{invitation_key}', 'PublicClientController@download');
|
Route::get('download/{invitation_key}', 'PublicClientController@download');
|
||||||
Route::get('view', 'HomeController@viewLogo');
|
Route::get('view', 'HomeController@viewLogo');
|
||||||
Route::get('approve/{invitation_key}', 'QuoteController@approve');
|
Route::get('approve/{invitation_key}', 'QuoteController@approve');
|
||||||
Route::get('payment/{invitation_key}/{payment_type?}', 'PaymentController@show_payment');
|
Route::get('payment/{invitation_key}/{payment_type?}/{source_id?}', 'PaymentController@show_payment');
|
||||||
Route::post('payment/{invitation_key}', 'PaymentController@do_payment');
|
Route::post('payment/{invitation_key}', 'PaymentController@do_payment');
|
||||||
Route::match(['GET', 'POST'], 'complete', 'PaymentController@offsite_payment');
|
Route::match(['GET', 'POST'], 'complete', 'PaymentController@offsite_payment');
|
||||||
|
Route::get('client/paymentmethods', 'PublicClientController@paymentMethods');
|
||||||
|
Route::post('client/paymentmethods/verify', 'PublicClientController@verifyPaymentMethod');
|
||||||
|
Route::get('client/paymentmethods/add/{payment_type}', 'PublicClientController@addPaymentMethod');
|
||||||
|
Route::post('client/paymentmethods/add/{payment_type}', 'PublicClientController@postAddPaymentMethod');
|
||||||
|
Route::post('client/paymentmethods/default', 'PublicClientController@setDefaultPaymentMethod');
|
||||||
|
Route::post('client/paymentmethods/{source_id}/remove', 'PublicClientController@removePaymentMethod');
|
||||||
Route::get('client/quotes', 'PublicClientController@quoteIndex');
|
Route::get('client/quotes', 'PublicClientController@quoteIndex');
|
||||||
Route::get('client/invoices', 'PublicClientController@invoiceIndex');
|
Route::get('client/invoices', 'PublicClientController@invoiceIndex');
|
||||||
Route::get('client/documents', 'PublicClientController@documentIndex');
|
Route::get('client/documents', 'PublicClientController@documentIndex');
|
||||||
@ -60,6 +66,7 @@ Route::group(['middleware' => 'auth:client'], function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Route::get('bank/{routing_number}', 'PaymentController@getBankInfo');
|
||||||
Route::get('license', 'PaymentController@show_license_payment');
|
Route::get('license', 'PaymentController@show_license_payment');
|
||||||
Route::post('license', 'PaymentController@do_license_payment');
|
Route::post('license', 'PaymentController@do_license_payment');
|
||||||
Route::get('claim_license', 'PaymentController@claim_license');
|
Route::get('claim_license', 'PaymentController@claim_license');
|
||||||
@ -615,6 +622,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('TOKEN_BILLING_ALWAYS', 4);
|
define('TOKEN_BILLING_ALWAYS', 4);
|
||||||
|
|
||||||
define('PAYMENT_TYPE_CREDIT', 1);
|
define('PAYMENT_TYPE_CREDIT', 1);
|
||||||
|
define('PAYMENT_TYPE_ACH', 5);
|
||||||
define('PAYMENT_TYPE_VISA', 6);
|
define('PAYMENT_TYPE_VISA', 6);
|
||||||
define('PAYMENT_TYPE_MASTERCARD', 7);
|
define('PAYMENT_TYPE_MASTERCARD', 7);
|
||||||
define('PAYMENT_TYPE_AMERICAN_EXPRESS', 8);
|
define('PAYMENT_TYPE_AMERICAN_EXPRESS', 8);
|
||||||
@ -633,6 +641,8 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
|
|
||||||
define('PAYMENT_TYPE_PAYPAL', 'PAYMENT_TYPE_PAYPAL');
|
define('PAYMENT_TYPE_PAYPAL', 'PAYMENT_TYPE_PAYPAL');
|
||||||
define('PAYMENT_TYPE_STRIPE', 'PAYMENT_TYPE_STRIPE');
|
define('PAYMENT_TYPE_STRIPE', 'PAYMENT_TYPE_STRIPE');
|
||||||
|
define('PAYMENT_TYPE_STRIPE_CREDIT_CARD', 'PAYMENT_TYPE_STRIPE_CREDIT_CARD');
|
||||||
|
define('PAYMENT_TYPE_STRIPE_ACH', 'PAYMENT_TYPE_STRIPE_ACH');
|
||||||
define('PAYMENT_TYPE_CREDIT_CARD', 'PAYMENT_TYPE_CREDIT_CARD');
|
define('PAYMENT_TYPE_CREDIT_CARD', 'PAYMENT_TYPE_CREDIT_CARD');
|
||||||
define('PAYMENT_TYPE_DIRECT_DEBIT', 'PAYMENT_TYPE_DIRECT_DEBIT');
|
define('PAYMENT_TYPE_DIRECT_DEBIT', 'PAYMENT_TYPE_DIRECT_DEBIT');
|
||||||
define('PAYMENT_TYPE_BITCOIN', 'PAYMENT_TYPE_BITCOIN');
|
define('PAYMENT_TYPE_BITCOIN', 'PAYMENT_TYPE_BITCOIN');
|
||||||
|
@ -379,6 +379,10 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function getGatewayByType($type = PAYMENT_TYPE_ANY)
|
public function getGatewayByType($type = PAYMENT_TYPE_ANY)
|
||||||
{
|
{
|
||||||
|
if ($type == PAYMENT_TYPE_STRIPE_ACH || $type == PAYMENT_TYPE_STRIPE_CREDIT_CARD) {
|
||||||
|
$type = PAYMENT_TYPE_STRIPE;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->account_gateways as $gateway) {
|
foreach ($this->account_gateways as $gateway) {
|
||||||
if (!$type || $type == PAYMENT_TYPE_ANY) {
|
if (!$type || $type == PAYMENT_TYPE_ANY) {
|
||||||
return $gateway;
|
return $gateway;
|
||||||
|
@ -56,6 +56,7 @@ class PaymentRepository extends BaseRepository
|
|||||||
'payments.refunded',
|
'payments.refunded',
|
||||||
'payments.expiration',
|
'payments.expiration',
|
||||||
'payments.last4',
|
'payments.last4',
|
||||||
|
'payments.routing_number',
|
||||||
'invoices.is_deleted as invoice_is_deleted',
|
'invoices.is_deleted as invoice_is_deleted',
|
||||||
'gateways.name as gateway_name',
|
'gateways.name as gateway_name',
|
||||||
'gateways.id as gateway_id',
|
'gateways.id as gateway_id',
|
||||||
@ -107,6 +108,7 @@ class PaymentRepository extends BaseRepository
|
|||||||
'clients.public_id as client_public_id',
|
'clients.public_id as client_public_id',
|
||||||
'payments.amount',
|
'payments.amount',
|
||||||
'payments.payment_date',
|
'payments.payment_date',
|
||||||
|
'payments.payment_type_id',
|
||||||
'invoices.public_id as invoice_public_id',
|
'invoices.public_id as invoice_public_id',
|
||||||
'invoices.invoice_number',
|
'invoices.invoice_number',
|
||||||
'contacts.first_name',
|
'contacts.first_name',
|
||||||
@ -117,6 +119,7 @@ class PaymentRepository extends BaseRepository
|
|||||||
'payments.refunded',
|
'payments.refunded',
|
||||||
'payments.expiration',
|
'payments.expiration',
|
||||||
'payments.last4',
|
'payments.last4',
|
||||||
|
'payments.routing_number',
|
||||||
'payments.payment_status_id',
|
'payments.payment_status_id',
|
||||||
'payment_statuses.name as payment_status_name'
|
'payment_statuses.name as payment_status_name'
|
||||||
);
|
);
|
||||||
|
@ -5,6 +5,7 @@ use Auth;
|
|||||||
use URL;
|
use URL;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Event;
|
use Event;
|
||||||
|
use Cache;
|
||||||
use Omnipay;
|
use Omnipay;
|
||||||
use Session;
|
use Session;
|
||||||
use CreditCard;
|
use CreditCard;
|
||||||
@ -13,6 +14,7 @@ use App\Models\Account;
|
|||||||
use App\Models\Country;
|
use App\Models\Country;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
use App\Models\Invoice;
|
use App\Models\Invoice;
|
||||||
|
use App\Http\Controllers\PaymentController;
|
||||||
use App\Models\AccountGatewayToken;
|
use App\Models\AccountGatewayToken;
|
||||||
use App\Ninja\Repositories\PaymentRepository;
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
@ -155,8 +157,159 @@ class PaymentService extends BaseService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getClientPaymentMethods($client) {
|
||||||
|
$token = $client->getGatewayToken($accountGateway);
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway = $this->createGateway($accountGateway);
|
||||||
|
|
||||||
|
$paymentMethods = array();
|
||||||
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
$response = $gateway->fetchCustomer(array('customerReference' => $token))->send();
|
||||||
|
if (!$response->isSuccessful()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $response->getData();
|
||||||
|
$default_source = $data['default_source'];
|
||||||
|
$sources = isset($data['sources']) ? $data['sources']['data'] : $data['cards']['data'];
|
||||||
|
|
||||||
|
$paymentTypes = Cache::get('paymentTypes');
|
||||||
|
$currencies = Cache::get('currencies');
|
||||||
|
foreach ($sources as $source) {
|
||||||
|
if ($source['object'] == 'bank_account') {
|
||||||
|
$paymentMethods[] = array(
|
||||||
|
'id' => $source['id'],
|
||||||
|
'default' => $source['id'] == $default_source,
|
||||||
|
'type' => $paymentTypes->find(PAYMENT_TYPE_ACH),
|
||||||
|
'currency' => $currencies->where('code', strtoupper($source['currency']))->first(),
|
||||||
|
'last4' => $source['last4'],
|
||||||
|
'routing_number' => $source['routing_number'],
|
||||||
|
'bank_name' => $source['bank_name'],
|
||||||
|
'status' => $source['status'],
|
||||||
|
);
|
||||||
|
} elseif ($source['object'] == 'card') {
|
||||||
|
$paymentMethods[] = array(
|
||||||
|
'id' => $source['id'],
|
||||||
|
'default' => $source['id'] == $default_source,
|
||||||
|
'type' => $paymentTypes->find($this->parseCardType($source['brand'])),
|
||||||
|
'last4' => $source['last4'],
|
||||||
|
'expiration' => $source['exp_year'] . '-' . $source['exp_month'] . '-00',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $paymentMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyClientPaymentMethod($client, $sourceId, $amount1, $amount2) {
|
||||||
|
$token = $client->getGatewayToken($accountGateway);
|
||||||
|
if ($accountGateway->gateway_id != GATEWAY_STRIPE) {
|
||||||
|
return 'Unsupported gateway';
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
// Omnipay doesn't support verifying payment methods
|
||||||
|
// Also, it doesn't want to urlencode without putting numbers inside the brackets
|
||||||
|
$response = (new \GuzzleHttp\Client(['base_uri'=>'https://api.stripe.com/v1/']))->request(
|
||||||
|
'POST',
|
||||||
|
'customers/'.$token.'/sources/'.$sourceId.'/verify',
|
||||||
|
[
|
||||||
|
'body' => 'amounts[]='.intval($amount1).'&amounts[]='.intval($amount2),
|
||||||
|
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
|
||||||
|
'auth' => [$accountGateway->getConfig()->apiKey,''],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return json_decode($response->getBody(), true);
|
||||||
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
|
$response = $e->getResponse();
|
||||||
|
$body = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
if ($body && $body['error'] && $body['error']['type'] == 'invalid_request_error') {
|
||||||
|
return $body['error']['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeClientPaymentMethod($client, $sourceId) {
|
||||||
|
$token = $client->getGatewayToken($accountGateway/* return parameter */);
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway = $this->createGateway($accountGateway);
|
||||||
|
|
||||||
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
$response = $gateway->deleteCard(array('customerReference' => $token, 'cardReference'=>$sourceId))->send();
|
||||||
|
if (!$response->isSuccessful()) {
|
||||||
|
return $response->getMessage();
|
||||||
|
}
|
||||||
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setClientDefaultPaymentMethod($client, $sourceId) {
|
||||||
|
$token = $client->getGatewayToken($accountGateway/* return parameter */);
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gateway = $this->createGateway($accountGateway);
|
||||||
|
|
||||||
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
try{
|
||||||
|
// Omnipay doesn't support setting a default source
|
||||||
|
$response = (new \GuzzleHttp\Client(['base_uri'=>'https://api.stripe.com/v1/']))->request(
|
||||||
|
'POST',
|
||||||
|
'customers/'.$token,
|
||||||
|
[
|
||||||
|
'body' => 'default_card='.$sourceId,
|
||||||
|
'headers' => ['content-type' => 'application/x-www-form-urlencoded'],
|
||||||
|
'auth' => [$accountGateway->getConfig()->apiKey,''],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
|
||||||
|
$response = $e->getResponse();
|
||||||
|
$body = json_decode($response->getBody(), true);
|
||||||
|
|
||||||
|
if ($body && $body['error'] && $body['error']['type'] == 'invalid_request_error') {
|
||||||
|
return $body['error']['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $e->getMessage();
|
||||||
|
}
|
||||||
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function createToken($gateway, $details, $accountGateway, $client, $contactId, &$customerReference = null)
|
public function createToken($gateway, $details, $accountGateway, $client, $contactId, &$customerReference = null)
|
||||||
{
|
{
|
||||||
|
$customerReference = $client->getGatewayToken();
|
||||||
|
|
||||||
|
if ($customerReference) {
|
||||||
|
$details['customerReference'] = $customerReference;
|
||||||
|
|
||||||
|
$customerResponse = $gateway->fetchCustomer(array('customerReference'=>$customerReference))->send();
|
||||||
|
|
||||||
|
if (!$customerResponse->isSuccessful()){
|
||||||
|
$customerReference = null; // The customer might not exist anymore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
|
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
|
||||||
$tokenResponse = $gateway->createCard($details)->send();
|
$tokenResponse = $gateway->createCard($details)->send();
|
||||||
$cardReference = $tokenResponse->getCardReference();
|
$cardReference = $tokenResponse->getCardReference();
|
||||||
@ -170,10 +323,15 @@ class PaymentService extends BaseService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
|
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
|
||||||
$tokenResponse = $gateway->createCustomer(array('customerData'=>array()))->send();
|
if (!$customerReference) {
|
||||||
|
$tokenResponse = $gateway->createCustomer(array('customerData' => array()))->send();
|
||||||
|
if ($tokenResponse->isSuccessful()) {
|
||||||
|
$customerReference = $tokenResponse->getCustomerData()->id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($tokenResponse->isSuccessful()) {
|
if ($customerReference) {
|
||||||
$details['customerId'] = $customerReference = $tokenResponse->getCustomerData()->id;
|
$details['customerId'] = $customerReference;
|
||||||
|
|
||||||
$tokenResponse = $gateway->createPaymentMethod($details)->send();
|
$tokenResponse = $gateway->createPaymentMethod($details)->send();
|
||||||
$cardReference = $tokenResponse->getData()->paymentMethod->token;
|
$cardReference = $tokenResponse->getData()->paymentMethod->token;
|
||||||
@ -264,54 +422,26 @@ class PaymentService extends BaseService
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
$card = $purchaseResponse->getSource();
|
$data = $purchaseResponse->getData();
|
||||||
if (!$card) {
|
$source = !empty($data['source'])?$data['source']:$data['card'];
|
||||||
$card = $purchaseResponse->getCard();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($card) {
|
if ($source) {
|
||||||
$payment->last4 = $card['last4'];
|
$payment->last4 = $source['last4'];
|
||||||
$payment->expiration = $card['exp_year'] . '-' . $card['exp_month'] . '-00';
|
|
||||||
$stripe_card_types = array(
|
|
||||||
'Visa' => PAYMENT_TYPE_VISA,
|
|
||||||
'American Express' => PAYMENT_TYPE_AMERICAN_EXPRESS,
|
|
||||||
'MasterCard' => PAYMENT_TYPE_MASTERCARD,
|
|
||||||
'Discover' => PAYMENT_TYPE_DISCOVER,
|
|
||||||
'JCB' => PAYMENT_TYPE_JCB,
|
|
||||||
'Diners Club' => PAYMENT_TYPE_DINERS,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!empty($stripe_card_types[$card['brand']])) {
|
if ($source['object'] == 'bank_account') {
|
||||||
$payment->payment_type_id = $stripe_card_types[$card['brand']];
|
$payment->routing_number = $source['routing_number'];
|
||||||
} else {
|
$payment->payment_type_id = PAYMENT_TYPE_ACH;
|
||||||
$payment->payment_type_id = PAYMENT_TYPE_CREDIT_CARD_OTHER;
|
}
|
||||||
|
else{
|
||||||
|
$payment->expiration = $card['exp_year'] . '-' . $card['exp_month'] . '-00';
|
||||||
|
$payment->payment_type_id = $this->parseCardType($card['brand']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
$card = $purchaseResponse->getData()->transaction->creditCardDetails;
|
$card = $purchaseResponse->getData()->transaction->creditCardDetails;
|
||||||
$payment->last4 = $card->last4;
|
$payment->last4 = $card->last4;
|
||||||
$payment->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
|
$payment->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
|
||||||
|
$payment->payment_type_id = $this->parseCardType($card->cardType);
|
||||||
$braintree_card_types = array(
|
|
||||||
'Visa' => PAYMENT_TYPE_VISA,
|
|
||||||
'American Express' => PAYMENT_TYPE_AMERICAN_EXPRESS,
|
|
||||||
'MasterCard' => PAYMENT_TYPE_MASTERCARD,
|
|
||||||
'Discover' => PAYMENT_TYPE_DISCOVER,
|
|
||||||
'JCB' => PAYMENT_TYPE_JCB,
|
|
||||||
'Diners Club' => PAYMENT_TYPE_DINERS,
|
|
||||||
'Carte Blanche' => PAYMENT_TYPE_CARTE_BLANCHE,
|
|
||||||
'China UnionPay' => PAYMENT_TYPE_UNIONPAY,
|
|
||||||
'Laser' => PAYMENT_TYPE_LASER,
|
|
||||||
'Maestro' => PAYMENT_TYPE_MAESTRO,
|
|
||||||
'Solo' => PAYMENT_TYPE_SOLO,
|
|
||||||
'Switch' => PAYMENT_TYPE_SWITCH,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!empty($braintree_card_types[$card->cardType])) {
|
|
||||||
$payment->payment_type_id = $braintree_card_types[$card->cardType];
|
|
||||||
} else {
|
|
||||||
$payment->payment_type_id = PAYMENT_TYPE_CREDIT_CARD_OTHER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($payerId) {
|
if ($payerId) {
|
||||||
@ -375,6 +505,29 @@ class PaymentService extends BaseService
|
|||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function parseCardType($cardName) {
|
||||||
|
$cardTypes = array(
|
||||||
|
'Visa' => PAYMENT_TYPE_VISA,
|
||||||
|
'American Express' => PAYMENT_TYPE_AMERICAN_EXPRESS,
|
||||||
|
'MasterCard' => PAYMENT_TYPE_MASTERCARD,
|
||||||
|
'Discover' => PAYMENT_TYPE_DISCOVER,
|
||||||
|
'JCB' => PAYMENT_TYPE_JCB,
|
||||||
|
'Diners Club' => PAYMENT_TYPE_DINERS,
|
||||||
|
'Carte Blanche' => PAYMENT_TYPE_CARTE_BLANCHE,
|
||||||
|
'China UnionPay' => PAYMENT_TYPE_UNIONPAY,
|
||||||
|
'Laser' => PAYMENT_TYPE_LASER,
|
||||||
|
'Maestro' => PAYMENT_TYPE_MAESTRO,
|
||||||
|
'Solo' => PAYMENT_TYPE_SOLO,
|
||||||
|
'Switch' => PAYMENT_TYPE_SWITCH
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!empty($cardTypes[$cardName])) {
|
||||||
|
return $cardTypes[$cardName];
|
||||||
|
} else {
|
||||||
|
return PAYMENT_TYPE_CREDIT_CARD_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function detectCardType($number)
|
private function detectCardType($number)
|
||||||
{
|
{
|
||||||
@ -493,12 +646,21 @@ class PaymentService extends BaseService
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'source',
|
'source',
|
||||||
function ($model) {
|
function ($model) {
|
||||||
if (!$model->last4) return '';
|
if (!$model->last4) return '';
|
||||||
$code = str_replace(' ', '', strtolower($model->payment_type));
|
$code = str_replace(' ', '', strtolower($model->payment_type));
|
||||||
$card_type = trans("texts.card_" . $code);
|
$card_type = trans("texts.card_" . $code);
|
||||||
$expiration = trans('texts.card_expiration', array('expires'=>Utils::fromSqlDate($model->expiration, false)->format('m/y')));
|
if ($model->payment_type_id != PAYMENT_TYPE_ACH) {
|
||||||
return '<img height="22" src="'.URL::to('/images/credit_cards/'.$code.'.png').'" alt="'.htmlentities($card_type).'"> •••'.$model->last4.' '.$expiration;
|
$expiration = trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($model->expiration, false)->format('m/y')));
|
||||||
|
return '<img height="22" src="' . URL::to('/images/credit_cards/' . $code . '.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4 . ' ' . $expiration;
|
||||||
|
} else {
|
||||||
|
$bankData = PaymentController::getBankData($model->routing_number);
|
||||||
|
if (is_array($bankData)) {
|
||||||
|
return $bankData['name'].' •••' . $model->last4;
|
||||||
|
} else {
|
||||||
|
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
"omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
|
||||||
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
"omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
|
||||||
"omnipay/gocardless": "dev-master",
|
"omnipay/gocardless": "dev-master",
|
||||||
"omnipay/stripe": "2.3.2",
|
"omnipay/stripe": "dev-master",
|
||||||
"laravel/framework": "5.2.*",
|
"laravel/framework": "5.2.*",
|
||||||
"laravelcollective/html": "5.2.*",
|
"laravelcollective/html": "5.2.*",
|
||||||
"laravelcollective/bus": "5.2.*",
|
"laravelcollective/bus": "5.2.*",
|
||||||
@ -73,7 +73,8 @@
|
|||||||
"league/flysystem-aws-s3-v3": "~1.0",
|
"league/flysystem-aws-s3-v3": "~1.0",
|
||||||
"league/flysystem-rackspace": "~1.0",
|
"league/flysystem-rackspace": "~1.0",
|
||||||
"barracudanetworks/archivestream-php": "^1.0",
|
"barracudanetworks/archivestream-php": "^1.0",
|
||||||
"omnipay/braintree": "~2.0@dev"
|
"omnipay/braintree": "~2.0@dev",
|
||||||
|
"gatepay/FedACHdir": "dev-master@dev"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~4.0",
|
"phpunit/phpunit": "~4.0",
|
||||||
@ -122,5 +123,23 @@
|
|||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"preferred-install": "dist"
|
"preferred-install": "dist"
|
||||||
}
|
},
|
||||||
|
"repositories": [
|
||||||
|
{
|
||||||
|
"type": "package",
|
||||||
|
"package": {
|
||||||
|
"name": "gatepay/FedACHdir",
|
||||||
|
"version": "dev-master",
|
||||||
|
"dist": {
|
||||||
|
"url": "https://github.com/gatepay/FedACHdir/archive/master.zip",
|
||||||
|
"type": "zip"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"url": "git@github.com:gatepay/FedACHdir.git",
|
||||||
|
"type": "git",
|
||||||
|
"reference": "origin/master"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
29
composer.lock
generated
29
composer.lock
generated
@ -4,8 +4,8 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "e2b43d6bd5e87dfb9b3be07e89a2bd9f",
|
"hash": "039f9d8f2e342f6c05dadb3523883a47",
|
||||||
"content-hash": "480134957ff37fd0f46b5d90909da660",
|
"content-hash": "fd558fd1e187969baf015eab8e288e5b",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "agmscode/omnipay-agms",
|
"name": "agmscode/omnipay-agms",
|
||||||
@ -2011,6 +2011,17 @@
|
|||||||
],
|
],
|
||||||
"time": "2015-01-16 08:41:13"
|
"time": "2015-01-16 08:41:13"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "gatepay/FedACHdir",
|
||||||
|
"version": "dev-master",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git@github.com:gatepay/FedACHdir.git",
|
||||||
|
"reference": "origin/master"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"time": "2016-04-29 12:01:22"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzle/guzzle",
|
"name": "guzzle/guzzle",
|
||||||
"version": "v3.8.1",
|
"version": "v3.8.1",
|
||||||
@ -5771,16 +5782,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "omnipay/stripe",
|
"name": "omnipay/stripe",
|
||||||
"version": "v2.3.2",
|
"version": "dev-master",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/omnipay-stripe.git",
|
"url": "https://github.com/thephpleague/omnipay-stripe.git",
|
||||||
"reference": "fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4"
|
"reference": "0ea7a647ee01e29c152814e11c2ea6307e5b0db9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4",
|
"url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/0ea7a647ee01e29c152814e11c2ea6307e5b0db9",
|
||||||
"reference": "fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4",
|
"reference": "0ea7a647ee01e29c152814e11c2ea6307e5b0db9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -5824,7 +5835,7 @@
|
|||||||
"payment",
|
"payment",
|
||||||
"stripe"
|
"stripe"
|
||||||
],
|
],
|
||||||
"time": "2016-03-19 08:35:06"
|
"time": "2016-04-26 08:34:50"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "omnipay/targetpay",
|
"name": "omnipay/targetpay",
|
||||||
@ -9985,6 +9996,7 @@
|
|||||||
"omnipay/mollie": 20,
|
"omnipay/mollie": 20,
|
||||||
"omnipay/2checkout": 20,
|
"omnipay/2checkout": 20,
|
||||||
"omnipay/gocardless": 20,
|
"omnipay/gocardless": 20,
|
||||||
|
"omnipay/stripe": 20,
|
||||||
"anahkiasen/former": 20,
|
"anahkiasen/former": 20,
|
||||||
"chumper/datatable": 20,
|
"chumper/datatable": 20,
|
||||||
"intervention/image": 20,
|
"intervention/image": 20,
|
||||||
@ -10005,7 +10017,8 @@
|
|||||||
"labs7in0/omnipay-wechat": 20,
|
"labs7in0/omnipay-wechat": 20,
|
||||||
"laracasts/presenter": 20,
|
"laracasts/presenter": 20,
|
||||||
"jlapp/swaggervel": 20,
|
"jlapp/swaggervel": 20,
|
||||||
"omnipay/braintree": 20
|
"omnipay/braintree": 20,
|
||||||
|
"gatepay/fedachdir": 20
|
||||||
},
|
},
|
||||||
"prefer-stable": false,
|
"prefer-stable": false,
|
||||||
"prefer-lowest": false,
|
"prefer-lowest": false,
|
||||||
|
BIN
public/images/credit_cards/ach.png
Normal file
BIN
public/images/credit_cards/ach.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
@ -502,7 +502,7 @@ $LANG = array(
|
|||||||
'resend_confirmation' => 'Resend confirmation email',
|
'resend_confirmation' => 'Resend confirmation email',
|
||||||
'confirmation_resent' => 'The confirmation email was resent',
|
'confirmation_resent' => 'The confirmation email was resent',
|
||||||
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
'gateway_help_42' => ':link to sign up for BitPay.<br/>Note: use a Legacy API Key, not an API token.',
|
||||||
'payment_type_credit_card' => 'Other Providers',
|
'payment_type_credit_card' => 'Credit Card',
|
||||||
'payment_type_paypal' => 'PayPal',
|
'payment_type_paypal' => 'PayPal',
|
||||||
'payment_type_bitcoin' => 'Bitcoin',
|
'payment_type_bitcoin' => 'Bitcoin',
|
||||||
'knowledge_base' => 'Knowledge Base',
|
'knowledge_base' => 'Knowledge Base',
|
||||||
@ -1205,6 +1205,7 @@ $LANG = array(
|
|||||||
'card_solo' => 'Solo',
|
'card_solo' => 'Solo',
|
||||||
'card_switch' => 'Switch',
|
'card_switch' => 'Switch',
|
||||||
'card_visacard' => 'Visa',
|
'card_visacard' => 'Visa',
|
||||||
|
'card_ach' => 'ACH',
|
||||||
|
|
||||||
'payment_type_stripe' => 'Stripe',
|
'payment_type_stripe' => 'Stripe',
|
||||||
'ach' => 'ACH',
|
'ach' => 'ACH',
|
||||||
@ -1218,6 +1219,39 @@ $LANG = array(
|
|||||||
'public_key' => 'Public Key',
|
'public_key' => 'Public Key',
|
||||||
'plaid_optional' => '(optional)',
|
'plaid_optional' => '(optional)',
|
||||||
'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.',
|
'plaid_environment_help' => 'When a Stripe test key is given, Plaid\'s development environement (tartan) will be used.',
|
||||||
|
'other_providers' => 'Other Providers',
|
||||||
|
'country_not_supported' => 'That country is not supported.',
|
||||||
|
'invalid_routing_number' => 'The routing number is not valid.',
|
||||||
|
'invalid_account_number' => 'The account number is not valid.',
|
||||||
|
'account_number_mismatch' => 'The account numbers do not match.',
|
||||||
|
'missing_account_holder_type' => 'Please select an individual or company account.',
|
||||||
|
'missing_account_holder_name' => 'Please enter the account holder\'s name.',
|
||||||
|
'routing_number' => 'Routing Number',
|
||||||
|
'confirm_account_number' => 'Confirm Account Number',
|
||||||
|
'individual_account' => 'Individual Account',
|
||||||
|
'company_account' => 'Company Account',
|
||||||
|
'account_holder_name' => 'Account Holder Name',
|
||||||
|
'add_account' => 'Add Account',
|
||||||
|
'payment_methods' => 'Payment Methods',
|
||||||
|
'complete_verification' => 'Complete Verification',
|
||||||
|
'verification_amount1' => 'Amount 1',
|
||||||
|
'verification_amount2' => 'Amount 2',
|
||||||
|
'payment_method_verified' => 'Verification completed successfully',
|
||||||
|
'verification_failed' => 'Verification Failed',
|
||||||
|
'remove_payment_method' => 'Remove Payment Method',
|
||||||
|
'confirm_remove_payment_method' => 'Are you sure you want to remove this payment method?',
|
||||||
|
'remove' => 'Remove',
|
||||||
|
'payment_method_removed' => 'Removed payment method.',
|
||||||
|
'bank_account_verification_help' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement. Please enter the amounts below.',
|
||||||
|
'bank_account_verification_next_steps' => 'We have made two deposits into your account with the description "VERIFICATION". These deposits will take 1-2 business days to appear on your statement.
|
||||||
|
Once you have the amounts, come back to this payment methods page and click "Complete Verification" next to the account.',
|
||||||
|
'unknown_bank' => 'Unknown Bank',
|
||||||
|
'ach_verification_delay_help' => 'You will be able to use the account after completing verification. Verification usually takes 1-2 business days.',
|
||||||
|
'add_credit_card' => 'Add Credit Card',
|
||||||
|
'payment_method_added' => 'Added payment method.',
|
||||||
|
'use_for_auto_bill' => 'Use For Autobill',
|
||||||
|
'used_for_auto_bill' => 'Autobill Payment Method',
|
||||||
|
'payment_method_set_as_default' => 'Set Autobill payment method.'
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -69,7 +69,7 @@
|
|||||||
{{ Former::populateField('remember', 'true') }}
|
{{ Former::populateField('remember', 'true') }}
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
||||||
<img src="{{ asset('images/icon-login.png') }}" />
|
<img src="{{ asset('images/icon-login.png') }}" />
|
||||||
<h4>Invoice Ninja | {{ trans('texts.account_login') }}</h4>
|
<h4>Invoice Ninja | {{ trans('texts.account_login') }}</h4>
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
{!! Former::open('client/recover_password')->addClass('form-signin') !!}
|
{!! Former::open('client/recover_password')->addClass('form-signin') !!}
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
||||||
<img src="{{ asset('images/icon-login.png') }}" />
|
<img src="{{ asset('images/icon-login.png') }}" />
|
||||||
<h4>Invoice Ninja | {{ trans('texts.password_recovery') }}</h4>
|
<h4>Invoice Ninja | {{ trans('texts.password_recovery') }}</h4>
|
||||||
|
@ -58,7 +58,7 @@
|
|||||||
)) !!}
|
)) !!}
|
||||||
|
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
<a href="{{ NINJA_WEB_URL }}" target="_blank">
|
||||||
<img src="{{ asset('images/icon-login.png') }}" />
|
<img src="{{ asset('images/icon-login.png') }}" />
|
||||||
<h4>Invoice Ninja | {{ trans('texts.set_password') }}</h4>
|
<h4>Invoice Ninja | {{ trans('texts.set_password') }}</h4>
|
||||||
|
@ -14,6 +14,12 @@
|
|||||||
body {
|
body {
|
||||||
background-color: #f8f8f8;
|
background-color: #f8f8f8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dropdown-menu li a{
|
||||||
|
overflow:hidden;
|
||||||
|
margin-top:5px;
|
||||||
|
margin-bottom:5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{App::getLocale()}}">
|
<html lang="{{App::getLocale()}}">
|
||||||
<head>
|
<head>
|
||||||
@if (isset($hideLogo) && $hideLogo)
|
@if (isset($account) && $account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<title>{{ trans('texts.client_portal') }}</title>
|
<title>{{ trans('texts.client_portal') }}</title>
|
||||||
@else
|
@else
|
||||||
<title>{{ isset($title) ? ($title . ' | Invoice Ninja') : ('Invoice Ninja | ' . trans('texts.app_title')) }}</title>
|
<title>{{ isset($title) ? ($title . ' | Invoice Ninja') : ('Invoice Ninja | ' . trans('texts.app_title')) }}</title>
|
||||||
|
611
resources/views/payments/add_paymentmethod.blade.php
Normal file
611
resources/views/payments/add_paymentmethod.blade.php
Normal file
@ -0,0 +1,611 @@
|
|||||||
|
@extends('public.header')
|
||||||
|
|
||||||
|
@section('head')
|
||||||
|
@parent
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<script type="text/javascript" src="https://js.braintreegateway.com/js/braintree-2.23.0.min.js"></script>
|
||||||
|
<script type="text/javascript" >
|
||||||
|
$(function() {
|
||||||
|
braintree.setup("{{ $braintreeClientToken }}", "custom", {
|
||||||
|
id: "payment-form",
|
||||||
|
hostedFields: {
|
||||||
|
number: {
|
||||||
|
selector: "#card_number",
|
||||||
|
placeholder: "{{ trans('texts.card_number') }}"
|
||||||
|
},
|
||||||
|
cvv: {
|
||||||
|
selector: "#cvv",
|
||||||
|
placeholder: "{{ trans('texts.cvv') }}"
|
||||||
|
},
|
||||||
|
expirationMonth: {
|
||||||
|
selector: "#expiration_month",
|
||||||
|
placeholder: "{{ trans('texts.expiration_month') }}"
|
||||||
|
},
|
||||||
|
expirationYear: {
|
||||||
|
selector: "#expiration_year",
|
||||||
|
placeholder: "{{ trans('texts.expiration_year') }}"
|
||||||
|
},
|
||||||
|
styles: {
|
||||||
|
'input': {
|
||||||
|
'font-family': {!! json_encode(Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_stack']) !!},
|
||||||
|
'font-weight': "{{ Utils::getFromCache($account->getBodyFontId(), 'fonts')['css_weight'] }}",
|
||||||
|
'font-size': '16px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: function(e) {
|
||||||
|
// Show the errors on the form
|
||||||
|
if (e.details && e.details.invalidFieldKeys.length) {
|
||||||
|
var invalidField = e.details.invalidFieldKeys[0];
|
||||||
|
|
||||||
|
if (invalidField == 'number') {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
|
||||||
|
}
|
||||||
|
else if (invalidField == 'expirationDate' || invalidField == 'expirationYear' || invalidField == 'expirationMonth') {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
|
||||||
|
}
|
||||||
|
else if (invalidField == 'cvv') {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$('#js-error-message').html(e.message).fadeIn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('.payment-form').submit(function(event) {
|
||||||
|
$('#js-error-message').hide();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@elseif ($accountGateway->getPublishableStripeKey())
|
||||||
|
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
Stripe.setPublishableKey('{{ $accountGateway->getPublishableStripeKey() }}');
|
||||||
|
$(function() {
|
||||||
|
$('.payment-form').submit(function(event) {
|
||||||
|
var $form = $(this);
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
account_holder_name: $('#account_holder_name').val(),
|
||||||
|
account_holder_type: $('[name=account_holder_type]:checked').val(),
|
||||||
|
currency: $("#currency").val(),
|
||||||
|
country: $("#country").val(),
|
||||||
|
routing_number: $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''),
|
||||||
|
account_number: $('#account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
|
||||||
|
@else
|
||||||
|
name: $('#first_name').val() + ' ' + $('#last_name').val(),
|
||||||
|
address_line1: $('#address1').val(),
|
||||||
|
address_line2: $('#address2').val(),
|
||||||
|
address_city: $('#city').val(),
|
||||||
|
address_state: $('#state').val(),
|
||||||
|
address_zip: $('#postal_code').val(),
|
||||||
|
address_country: $("#country_id option:selected").text(),
|
||||||
|
number: $('#card_number').val(),
|
||||||
|
cvc: $('#cvv').val(),
|
||||||
|
exp_month: $('#expiration_month').val(),
|
||||||
|
exp_year: $('#expiration_year').val()
|
||||||
|
@endif
|
||||||
|
};
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
// Validate the account details
|
||||||
|
if (!data.account_holder_type) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.missing_account_holder_type') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!data.account_holder_name) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.missing_account_holder_name') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!data.routing_number || !Stripe.bankAccount.validateRoutingNumber(data.routing_number, data.country)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_routing_number') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (data.account_number != $('#confirm_account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.account_number_mismatch') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!data.account_number || !Stripe.bankAccount.validateAccountNumber(data.account_number, data.country)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_account_number') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@else
|
||||||
|
// Validate the card details
|
||||||
|
if (!Stripe.card.validateCardNumber(data.number)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Stripe.card.validateExpiry(data.exp_month, data.exp_year)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Stripe.card.validateCVC(data.cvc)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
// Disable the submit button to prevent repeated clicks
|
||||||
|
$form.find('button').prop('disabled', true);
|
||||||
|
$('#js-error-message').hide();
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
Stripe.bankAccount.createToken(data, stripeResponseHandler);
|
||||||
|
@else
|
||||||
|
Stripe.card.createToken(data, stripeResponseHandler);
|
||||||
|
@endif
|
||||||
|
|
||||||
|
// Prevent the form from submitting with the default action
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function stripeResponseHandler(status, response) {
|
||||||
|
var $form = $('.payment-form');
|
||||||
|
|
||||||
|
if (response.error) {
|
||||||
|
// Show the errors on the form
|
||||||
|
var error = response.error.message;
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
if(response.error.param == 'bank_account[country]') {
|
||||||
|
error = "{{trans('texts.country_not_supported')}}";
|
||||||
|
}
|
||||||
|
@endif
|
||||||
|
$form.find('button').prop('disabled', false);
|
||||||
|
$('#js-error-message').html(error).fadeIn();
|
||||||
|
} else {
|
||||||
|
// response contains id and card, which contains additional card details
|
||||||
|
var token = response.id;
|
||||||
|
// Insert the token into the form so it gets submitted to the server
|
||||||
|
$form.append($('<input type="hidden" name="stripeToken"/>').val(token));
|
||||||
|
// and submit
|
||||||
|
$form.get(0).submit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
@else
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
$('.payment-form').submit(function(event) {
|
||||||
|
var $form = $(this);
|
||||||
|
|
||||||
|
// Disable the submit button to prevent repeated clicks
|
||||||
|
$form.find('button').prop('disabled', true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
@include('payments.payment_css')
|
||||||
|
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
{!! Former::vertical_open($url)
|
||||||
|
->autocomplete('on')
|
||||||
|
->addClass('payment-form')
|
||||||
|
->id('payment-form')
|
||||||
|
->rules(array(
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'account_number' => 'required',
|
||||||
|
'routing_number' => 'required',
|
||||||
|
'account_holder_name' => 'required',
|
||||||
|
'account_holder_type' => 'required'
|
||||||
|
)) !!}
|
||||||
|
@else
|
||||||
|
{!! Former::vertical_open($url)
|
||||||
|
->autocomplete('on')
|
||||||
|
->addClass('payment-form')
|
||||||
|
->id('payment-form')
|
||||||
|
->rules(array(
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'card_number' => 'required',
|
||||||
|
'expiration_month' => 'required',
|
||||||
|
'expiration_year' => 'required',
|
||||||
|
'cvv' => 'required',
|
||||||
|
'address1' => 'required',
|
||||||
|
'city' => 'required',
|
||||||
|
'state' => 'required',
|
||||||
|
'postal_code' => 'required',
|
||||||
|
'country_id' => 'required',
|
||||||
|
'phone' => 'required',
|
||||||
|
'email' => 'required|email'
|
||||||
|
)) !!}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if ($client)
|
||||||
|
{{ Former::populate($client) }}
|
||||||
|
{{ Former::populateField('first_name', $contact->first_name) }}
|
||||||
|
{{ Former::populateField('last_name', $contact->last_name) }}
|
||||||
|
@if (!$client->country_id && $client->account->country_id)
|
||||||
|
{{ Former::populateField('country_id', $client->account->country_id) }}
|
||||||
|
{{ Former::populateField('country', $client->account->country->iso_3166_2) }}
|
||||||
|
@endif
|
||||||
|
@if (!$client->currency_id && $client->account->currency_id)
|
||||||
|
{{ Former::populateField('currency_id', $client->account->currency_id) }}
|
||||||
|
{{ Former::populateField('currency', $client->account->currency->code) }}
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if (Utils::isNinjaDev())
|
||||||
|
{{ Former::populateField('first_name', 'Test') }}
|
||||||
|
{{ Former::populateField('last_name', 'Test') }}
|
||||||
|
{{ Former::populateField('address1', '350 5th Ave') }}
|
||||||
|
{{ Former::populateField('city', 'New York') }}
|
||||||
|
{{ Former::populateField('state', 'NY') }}
|
||||||
|
{{ Former::populateField('postal_code', '10118') }}
|
||||||
|
{{ Former::populateField('country_id', 840) }}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<p> </p>
|
||||||
|
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-7">
|
||||||
|
<header>
|
||||||
|
@if ($client)
|
||||||
|
<h2>{{ $client->getDisplayName() }}</h2>
|
||||||
|
@if(isset($invoiceNumber))
|
||||||
|
<h3>{{ trans('texts.invoice') . ' ' . $invoiceNumber }}<span>| {{ trans('texts.amount_due') }}: <em>{{ $account->formatMoney($amount, $client, true) }}</em></span></h3>
|
||||||
|
@endif
|
||||||
|
@elseif ($paymentTitle)
|
||||||
|
<h2>{{ $paymentTitle }}<br/><small>{{ $paymentSubtitle }}</small></h2>
|
||||||
|
@endif
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-5">
|
||||||
|
@if (Request::secure() || Utils::isNinjaDev())
|
||||||
|
<div class="secure">
|
||||||
|
<h3>{{ trans('texts.secure_payment') }}</h3>
|
||||||
|
<div>{{ trans('texts.256_encryption') }}</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p> <br/> </p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h3>{{ trans('texts.contact_information') }}</h3>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('first_name')
|
||||||
|
->placeholder(trans('texts.first_name'))
|
||||||
|
->autocomplete('given-name')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('last_name')
|
||||||
|
->placeholder(trans('texts.last_name'))
|
||||||
|
->autocomplete('family-name')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (isset($paymentTitle))
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{!! Former::text('email')
|
||||||
|
->placeholder(trans('texts.email'))
|
||||||
|
->autocomplete('email')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<p> <br/> </p>
|
||||||
|
|
||||||
|
@if ($showAddress)
|
||||||
|
<h3>{{ trans('texts.billing_address') }}
|
||||||
|
@if($paymentType != PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
<span class="help">{{ trans('texts.payment_footer1') }}</span></h3>
|
||||||
|
@endif
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('address1')
|
||||||
|
->autocomplete('address-line1')
|
||||||
|
->placeholder(trans('texts.address1'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('address2')
|
||||||
|
->autocomplete('address-line2')
|
||||||
|
->placeholder(trans('texts.address2'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('city')
|
||||||
|
->autocomplete('address-level2')
|
||||||
|
->placeholder(trans('texts.city'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('state')
|
||||||
|
->autocomplete('address-level1')
|
||||||
|
->placeholder(trans('texts.state'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('postal_code')
|
||||||
|
->autocomplete('postal-code')
|
||||||
|
->placeholder(trans('texts.postal_code'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::select('country_id')
|
||||||
|
->placeholder(trans('texts.country_id'))
|
||||||
|
->fromQuery($countries, 'name', 'id')
|
||||||
|
->addGroupClass('country-select')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p> <br/> </p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<h3>{{ trans('texts.billing_method') }}</h3>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
<p>{{ trans('texts.ach_verification_delay_help') }}</p>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="radio">
|
||||||
|
{!! Former::radios('account_holder_type')->radios(array(
|
||||||
|
trans('texts.individual_account') => array('value' => 'individual'),
|
||||||
|
trans('texts.company_account') => array('value' => 'company'),
|
||||||
|
))->inline()->label(''); !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('account_holder_name')
|
||||||
|
->placeholder(trans('texts.account_holder_name'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::select('country')
|
||||||
|
->placeholder(trans('texts.country_id'))
|
||||||
|
->fromQuery($countries, 'name', 'iso_3166_2')
|
||||||
|
->addGroupClass('country-select')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::select('currency')
|
||||||
|
->placeholder(trans('texts.currency_id'))
|
||||||
|
->fromQuery($currencies, 'name', 'code')
|
||||||
|
->addGroupClass('currency-select')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('routing_number')
|
||||||
|
->placeholder(trans('texts.routing_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div id="bank_name"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('account_number')
|
||||||
|
->placeholder(trans('texts.account_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('confirm_account_number')
|
||||||
|
->placeholder(trans('texts.confirm_account_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<center>
|
||||||
|
{!! Button::success(strtoupper(trans('texts.add_account')))
|
||||||
|
->submit()
|
||||||
|
->large() !!}
|
||||||
|
</center>
|
||||||
|
@else
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="card_number" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'card_number')
|
||||||
|
->id('card_number')
|
||||||
|
->placeholder(trans('texts.card_number'))
|
||||||
|
->autocomplete('cc-number')
|
||||||
|
->label('') !!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="cvv" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'cvv')
|
||||||
|
->id('cvv')
|
||||||
|
->placeholder(trans('texts.cvv'))
|
||||||
|
->autocomplete('off')
|
||||||
|
->label('') !!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="expiration_month" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_month')
|
||||||
|
->id('expiration_month')
|
||||||
|
->autocomplete('cc-exp-month')
|
||||||
|
->placeholder(trans('texts.expiration_month'))
|
||||||
|
->addOption('01 - January', '1')
|
||||||
|
->addOption('02 - February', '2')
|
||||||
|
->addOption('03 - March', '3')
|
||||||
|
->addOption('04 - April', '4')
|
||||||
|
->addOption('05 - May', '5')
|
||||||
|
->addOption('06 - June', '6')
|
||||||
|
->addOption('07 - July', '7')
|
||||||
|
->addOption('08 - August', '8')
|
||||||
|
->addOption('09 - September', '9')
|
||||||
|
->addOption('10 - October', '10')
|
||||||
|
->addOption('11 - November', '11')
|
||||||
|
->addOption('12 - December', '12')->label('')
|
||||||
|
!!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="expiration_year" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_year')
|
||||||
|
->id('expiration_year')
|
||||||
|
->autocomplete('cc-exp-year')
|
||||||
|
->placeholder(trans('texts.expiration_year'))
|
||||||
|
->addOption('2016', '2016')
|
||||||
|
->addOption('2017', '2017')
|
||||||
|
->addOption('2018', '2018')
|
||||||
|
->addOption('2019', '2019')
|
||||||
|
->addOption('2020', '2020')
|
||||||
|
->addOption('2021', '2021')
|
||||||
|
->addOption('2022', '2022')
|
||||||
|
->addOption('2023', '2023')
|
||||||
|
->addOption('2024', '2024')
|
||||||
|
->addOption('2025', '2025')
|
||||||
|
->addOption('2026', '2026')->label('')
|
||||||
|
!!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="padding-top:18px">
|
||||||
|
<div class="col-md-5">
|
||||||
|
@if (isset($amount) && $client && $account->showTokenCheckbox($storageGateway/* will contain gateway id */))
|
||||||
|
<input id="token_billing" type="checkbox" name="token_billing" {{ $account->selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top">
|
||||||
|
<label for="token_billing" class="checkbox" style="display: inline;">{{ trans('texts.token_billing') }}</label>
|
||||||
|
<span class="help-block" style="font-size:15px">
|
||||||
|
@if ($storageGateway == GATEWAY_STRIPE)
|
||||||
|
{!! trans('texts.token_billing_secure', ['link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) !!}
|
||||||
|
@elseif ($storageGateway == GATEWAY_BRAINTREE)
|
||||||
|
{!! trans('texts.token_billing_secure', ['link' => link_to('https://www.braintreepayments.com/', 'Braintree', ['target' => '_blank'])]) !!}
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-7">
|
||||||
|
@if (isset($acceptedCreditCardTypes))
|
||||||
|
<div class="pull-right">
|
||||||
|
@foreach ($acceptedCreditCardTypes as $card)
|
||||||
|
<img src="{{ $card['source'] }}" alt="{{ $card['alt'] }}" style="width: 70px; display: inline; margin-right: 6px;"/>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p> </p>
|
||||||
|
<center>
|
||||||
|
@if(isset($amount))
|
||||||
|
{!! Button::success(strtoupper(trans('texts.pay_now') . ' - ' . $account->formatMoney($amount, $client, true) ))
|
||||||
|
->submit()
|
||||||
|
->large() !!}
|
||||||
|
@else
|
||||||
|
{!! Button::success(strtoupper(trans('texts.add_credit_card') ))
|
||||||
|
->submit()
|
||||||
|
->large() !!}
|
||||||
|
@endif
|
||||||
|
</center>
|
||||||
|
<p> </p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div id="js-error-message" style="display:none" class="alert alert-danger"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<p> </p>
|
||||||
|
<p> </p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{!! Former::close() !!}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
$('select').change(function() {
|
||||||
|
$(this).css({color:'#444444'});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#country_id').combobox();
|
||||||
|
$('#country').combobox();
|
||||||
|
$('#currency').combobox();
|
||||||
|
$('#first_name').focus();
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
var routingNumberCache = {};
|
||||||
|
$('#routing_number, #country').on('change keypress keyup keydown paste', function(){setTimeout(function () {
|
||||||
|
var routingNumber = $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
||||||
|
|
||||||
|
if (routingNumber.length != 9 || $("#country").val() != 'US' || routingNumberCache[routingNumber] === false) {
|
||||||
|
$('#bank_name').hide();
|
||||||
|
} else if (routingNumberCache[routingNumber]) {
|
||||||
|
$('#bank_name').empty().append(routingNumberCache[routingNumber]).show();
|
||||||
|
} else {
|
||||||
|
routingNumberCache[routingNumber] = false;
|
||||||
|
$('#bank_name').hide();
|
||||||
|
$.ajax({
|
||||||
|
url:"{{ URL::to('/bank') }}/" + routingNumber,
|
||||||
|
success:function(data) {
|
||||||
|
var els = $().add(document.createTextNode(data.name)).add('<br>').add(document.createTextNode(data.city + ", " + data.state));
|
||||||
|
routingNumberCache[routingNumber] = els;
|
||||||
|
|
||||||
|
// Still the same number?
|
||||||
|
if (routingNumber == $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#bank_name').empty().append(els).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(xhr) {
|
||||||
|
if (xhr.status == 404) {
|
||||||
|
var els = $(document.createTextNode('{{trans('texts.unknown_bank')}}'));
|
||||||
|
;
|
||||||
|
routingNumberCache[routingNumber] = els;
|
||||||
|
|
||||||
|
// Still the same number?
|
||||||
|
if (routingNumber == $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#bank_name').empty().append(els).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},10)})
|
||||||
|
@endif
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@stop
|
@ -67,6 +67,14 @@
|
|||||||
var $form = $(this);
|
var $form = $(this);
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
account_holder_name: $('#account_holder_name').val(),
|
||||||
|
account_holder_type: $('[name=account_holder_type]:checked').val(),
|
||||||
|
currency: $("#currency").val(),
|
||||||
|
country: $("#country").val(),
|
||||||
|
routing_number: $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''),
|
||||||
|
account_number: $('#account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
|
||||||
|
@else
|
||||||
name: $('#first_name').val() + ' ' + $('#last_name').val(),
|
name: $('#first_name').val() + ' ' + $('#last_name').val(),
|
||||||
address_line1: $('#address1').val(),
|
address_line1: $('#address1').val(),
|
||||||
address_line2: $('#address2').val(),
|
address_line2: $('#address2').val(),
|
||||||
@ -78,27 +86,56 @@
|
|||||||
cvc: $('#cvv').val(),
|
cvc: $('#cvv').val(),
|
||||||
exp_month: $('#expiration_month').val(),
|
exp_month: $('#expiration_month').val(),
|
||||||
exp_year: $('#expiration_year').val()
|
exp_year: $('#expiration_year').val()
|
||||||
|
@endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the card details
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
if (!Stripe.card.validateCardNumber(data.number)) {
|
// Validate the account details
|
||||||
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
|
if (!data.account_holder_type) {
|
||||||
return false;
|
$('#js-error-message').html('{{ trans('texts.missing_account_holder_type') }}').fadeIn();
|
||||||
}
|
return false;
|
||||||
if (!Stripe.card.validateExpiry(data.exp_month, data.exp_year)) {
|
}
|
||||||
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
|
if (!data.account_holder_name) {
|
||||||
return false;
|
$('#js-error-message').html('{{ trans('texts.missing_account_holder_name') }}').fadeIn();
|
||||||
}
|
return false;
|
||||||
if (!Stripe.card.validateCVC(data.cvc)) {
|
}
|
||||||
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
|
if (!data.routing_number || !Stripe.bankAccount.validateRoutingNumber(data.routing_number, data.country)) {
|
||||||
return false;
|
$('#js-error-message').html('{{ trans('texts.invalid_routing_number') }}').fadeIn();
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
if (data.account_number != $('#confirm_account_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.account_number_mismatch') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!data.account_number || !Stripe.bankAccount.validateAccountNumber(data.account_number, data.country)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_account_number') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@else
|
||||||
|
// Validate the card details
|
||||||
|
if (!Stripe.card.validateCardNumber(data.number)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_card_number') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Stripe.card.validateExpiry(data.exp_month, data.exp_year)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_expiry') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!Stripe.card.validateCVC(data.cvc)) {
|
||||||
|
$('#js-error-message').html('{{ trans('texts.invalid_cvv') }}').fadeIn();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@endif
|
||||||
|
|
||||||
// Disable the submit button to prevent repeated clicks
|
// Disable the submit button to prevent repeated clicks
|
||||||
$form.find('button').prop('disabled', true);
|
$form.find('button').prop('disabled', true);
|
||||||
$('#js-error-message').hide();
|
$('#js-error-message').hide();
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
Stripe.bankAccount.createToken(data, stripeResponseHandler);
|
||||||
|
@else
|
||||||
Stripe.card.createToken(data, stripeResponseHandler);
|
Stripe.card.createToken(data, stripeResponseHandler);
|
||||||
|
@endif
|
||||||
|
|
||||||
// Prevent the form from submitting with the default action
|
// Prevent the form from submitting with the default action
|
||||||
return false;
|
return false;
|
||||||
@ -111,6 +148,11 @@
|
|||||||
if (response.error) {
|
if (response.error) {
|
||||||
// Show the errors on the form
|
// Show the errors on the form
|
||||||
var error = response.error.message;
|
var error = response.error.message;
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
if(response.error.param == 'bank_account[country]') {
|
||||||
|
error = "{{trans('texts.country_not_supported')}}";
|
||||||
|
}
|
||||||
|
@endif
|
||||||
$form.find('button').prop('disabled', false);
|
$form.find('button').prop('disabled', false);
|
||||||
$('#js-error-message').html(error).fadeIn();
|
$('#js-error-message').html(error).fadeIn();
|
||||||
} else {
|
} else {
|
||||||
@ -144,6 +186,21 @@
|
|||||||
|
|
||||||
@include('payments.payment_css')
|
@include('payments.payment_css')
|
||||||
|
|
||||||
|
|
||||||
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
{!! Former::vertical_open($url)
|
||||||
|
->autocomplete('on')
|
||||||
|
->addClass('payment-form')
|
||||||
|
->id('payment-form')
|
||||||
|
->rules(array(
|
||||||
|
'first_name' => 'required',
|
||||||
|
'last_name' => 'required',
|
||||||
|
'account_number' => 'required',
|
||||||
|
'routing_number' => 'required',
|
||||||
|
'account_holder_name' => 'required',
|
||||||
|
'account_holder_type' => 'required'
|
||||||
|
)) !!}
|
||||||
|
@else
|
||||||
{!! Former::vertical_open($url)
|
{!! Former::vertical_open($url)
|
||||||
->autocomplete('on')
|
->autocomplete('on')
|
||||||
->addClass('payment-form')
|
->addClass('payment-form')
|
||||||
@ -163,6 +220,7 @@
|
|||||||
'phone' => 'required',
|
'phone' => 'required',
|
||||||
'email' => 'required|email'
|
'email' => 'required|email'
|
||||||
)) !!}
|
)) !!}
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($client)
|
@if ($client)
|
||||||
{{ Former::populate($client) }}
|
{{ Former::populate($client) }}
|
||||||
@ -170,6 +228,11 @@
|
|||||||
{{ Former::populateField('last_name', $contact->last_name) }}
|
{{ Former::populateField('last_name', $contact->last_name) }}
|
||||||
@if (!$client->country_id && $client->account->country_id)
|
@if (!$client->country_id && $client->account->country_id)
|
||||||
{{ Former::populateField('country_id', $client->account->country_id) }}
|
{{ Former::populateField('country_id', $client->account->country_id) }}
|
||||||
|
{{ Former::populateField('country', $client->account->country->iso_3166_2) }}
|
||||||
|
@endif
|
||||||
|
@if (!$client->currency_id && $client->account->currency_id)
|
||||||
|
{{ Former::populateField('currency_id', $client->account->currency_id) }}
|
||||||
|
{{ Former::populateField('currency', $client->account->currency->code) }}
|
||||||
@endif
|
@endif
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@ -243,7 +306,10 @@
|
|||||||
<p> <br/> </p>
|
<p> <br/> </p>
|
||||||
|
|
||||||
@if ($showAddress)
|
@if ($showAddress)
|
||||||
<h3>{{ trans('texts.billing_address') }} <span class="help">{{ trans('texts.payment_footer1') }}</span></h3>
|
<h3>{{ trans('texts.billing_address') }}
|
||||||
|
@if($paymentType != PAYMENT_TYPE_STRIPE_ACH)
|
||||||
|
<span class="help">{{ trans('texts.payment_footer1') }}</span></h3>
|
||||||
|
@endif
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
{!! Former::text('address1')
|
{!! Former::text('address1')
|
||||||
@ -292,113 +358,178 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
<h3>{{ trans('texts.billing_method') }}</h3>
|
<h3>{{ trans('texts.billing_method') }}</h3>
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-9">
|
|
||||||
@if (!empty($braintreeClientToken))
|
|
||||||
<div id="card_number" class="braintree-hosted form-control"></div>
|
|
||||||
@else
|
|
||||||
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'card_number')
|
|
||||||
->id('card_number')
|
|
||||||
->placeholder(trans('texts.card_number'))
|
|
||||||
->autocomplete('cc-number')
|
|
||||||
->label('') !!}
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
@if (!empty($braintreeClientToken))
|
|
||||||
<div id="cvv" class="braintree-hosted form-control"></div>
|
|
||||||
@else
|
|
||||||
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'cvv')
|
|
||||||
->id('cvv')
|
|
||||||
->placeholder(trans('texts.cvv'))
|
|
||||||
->autocomplete('off')
|
|
||||||
->label('') !!}
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
@if (!empty($braintreeClientToken))
|
|
||||||
<div id="expiration_month" class="braintree-hosted form-control"></div>
|
|
||||||
@else
|
|
||||||
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_month')
|
|
||||||
->id('expiration_month')
|
|
||||||
->autocomplete('cc-exp-month')
|
|
||||||
->placeholder(trans('texts.expiration_month'))
|
|
||||||
->addOption('01 - January', '1')
|
|
||||||
->addOption('02 - February', '2')
|
|
||||||
->addOption('03 - March', '3')
|
|
||||||
->addOption('04 - April', '4')
|
|
||||||
->addOption('05 - May', '5')
|
|
||||||
->addOption('06 - June', '6')
|
|
||||||
->addOption('07 - July', '7')
|
|
||||||
->addOption('08 - August', '8')
|
|
||||||
->addOption('09 - September', '9')
|
|
||||||
->addOption('10 - October', '10')
|
|
||||||
->addOption('11 - November', '11')
|
|
||||||
->addOption('12 - December', '12')->label('')
|
|
||||||
!!}
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
@if (!empty($braintreeClientToken))
|
|
||||||
<div id="expiration_year" class="braintree-hosted form-control"></div>
|
|
||||||
@else
|
|
||||||
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_year')
|
|
||||||
->id('expiration_year')
|
|
||||||
->autocomplete('cc-exp-year')
|
|
||||||
->placeholder(trans('texts.expiration_year'))
|
|
||||||
->addOption('2016', '2016')
|
|
||||||
->addOption('2017', '2017')
|
|
||||||
->addOption('2018', '2018')
|
|
||||||
->addOption('2019', '2019')
|
|
||||||
->addOption('2020', '2020')
|
|
||||||
->addOption('2021', '2021')
|
|
||||||
->addOption('2022', '2022')
|
|
||||||
->addOption('2023', '2023')
|
|
||||||
->addOption('2024', '2024')
|
|
||||||
->addOption('2025', '2025')
|
|
||||||
->addOption('2026', '2026')->label('')
|
|
||||||
!!}
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row" style="padding-top:18px">
|
|
||||||
<div class="col-md-5">
|
|
||||||
@if ($client && $account->showTokenCheckbox($storageGateway/* will contain gateway id */))
|
|
||||||
<input id="token_billing" type="checkbox" name="token_billing" {{ $account->selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top">
|
|
||||||
<label for="token_billing" class="checkbox" style="display: inline;">{{ trans('texts.token_billing') }}</label>
|
|
||||||
<span class="help-block" style="font-size:15px">
|
|
||||||
@if ($storageGateway == GATEWAY_STRIPE)
|
|
||||||
{!! trans('texts.token_billing_secure', ['link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) !!}
|
|
||||||
@elseif ($storageGateway == GATEWAY_BRAINTREE)
|
|
||||||
{!! trans('texts.token_billing_secure', ['link' => link_to('https://www.braintreepayments.com/', 'Braintree', ['target' => '_blank'])]) !!}
|
|
||||||
@endif
|
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-md-7">
|
@if($paymentType == PAYMENT_TYPE_STRIPE_ACH)
|
||||||
@if (isset($acceptedCreditCardTypes))
|
<p>{{ trans('texts.ach_verification_delay_help') }}</p>
|
||||||
<div class="pull-right">
|
<div class="row">
|
||||||
@foreach ($acceptedCreditCardTypes as $card)
|
<div class="col-md-6">
|
||||||
<img src="{{ $card['source'] }}" alt="{{ $card['alt'] }}" style="width: 70px; display: inline; margin-right: 6px;"/>
|
<div class="radio">
|
||||||
@endforeach
|
{!! Former::radios('account_holder_type')->radios(array(
|
||||||
|
trans('texts.individual_account') => array('value' => 'individual'),
|
||||||
|
trans('texts.company_account') => array('value' => 'company'),
|
||||||
|
))->inline()->label(''); !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('account_holder_name')
|
||||||
|
->placeholder(trans('texts.account_holder_name'))
|
||||||
|
->label('') !!}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::select('country')
|
||||||
|
->placeholder(trans('texts.country_id'))
|
||||||
|
->fromQuery($countries, 'name', 'iso_3166_2')
|
||||||
|
->addGroupClass('country-select')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::select('currency')
|
||||||
|
->placeholder(trans('texts.currency_id'))
|
||||||
|
->fromQuery($currencies, 'name', 'code')
|
||||||
|
->addGroupClass('currency-select')
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('routing_number')
|
||||||
|
->placeholder(trans('texts.routing_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div id="bank_name"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('account_number')
|
||||||
|
->placeholder(trans('texts.account_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
{!! Former::text('')
|
||||||
|
->id('confirm_account_number')
|
||||||
|
->placeholder(trans('texts.confirm_account_number'))
|
||||||
|
->label('') !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<center>
|
||||||
|
{!! Button::success(strtoupper(trans('texts.add_account')))
|
||||||
|
->submit()
|
||||||
|
->large() !!}
|
||||||
|
</center>
|
||||||
|
@else
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-9">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="card_number" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'card_number')
|
||||||
|
->id('card_number')
|
||||||
|
->placeholder(trans('texts.card_number'))
|
||||||
|
->autocomplete('cc-number')
|
||||||
|
->label('') !!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="cvv" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::text($accountGateway->getPublishableStripeKey() ? '' : 'cvv')
|
||||||
|
->id('cvv')
|
||||||
|
->placeholder(trans('texts.cvv'))
|
||||||
|
->autocomplete('off')
|
||||||
|
->label('') !!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="expiration_month" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_month')
|
||||||
|
->id('expiration_month')
|
||||||
|
->autocomplete('cc-exp-month')
|
||||||
|
->placeholder(trans('texts.expiration_month'))
|
||||||
|
->addOption('01 - January', '1')
|
||||||
|
->addOption('02 - February', '2')
|
||||||
|
->addOption('03 - March', '3')
|
||||||
|
->addOption('04 - April', '4')
|
||||||
|
->addOption('05 - May', '5')
|
||||||
|
->addOption('06 - June', '6')
|
||||||
|
->addOption('07 - July', '7')
|
||||||
|
->addOption('08 - August', '8')
|
||||||
|
->addOption('09 - September', '9')
|
||||||
|
->addOption('10 - October', '10')
|
||||||
|
->addOption('11 - November', '11')
|
||||||
|
->addOption('12 - December', '12')->label('')
|
||||||
|
!!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
@if (!empty($braintreeClientToken))
|
||||||
|
<div id="expiration_year" class="braintree-hosted form-control"></div>
|
||||||
|
@else
|
||||||
|
{!! Former::select($accountGateway->getPublishableStripeKey() ? '' : 'expiration_year')
|
||||||
|
->id('expiration_year')
|
||||||
|
->autocomplete('cc-exp-year')
|
||||||
|
->placeholder(trans('texts.expiration_year'))
|
||||||
|
->addOption('2016', '2016')
|
||||||
|
->addOption('2017', '2017')
|
||||||
|
->addOption('2018', '2018')
|
||||||
|
->addOption('2019', '2019')
|
||||||
|
->addOption('2020', '2020')
|
||||||
|
->addOption('2021', '2021')
|
||||||
|
->addOption('2022', '2022')
|
||||||
|
->addOption('2023', '2023')
|
||||||
|
->addOption('2024', '2024')
|
||||||
|
->addOption('2025', '2025')
|
||||||
|
->addOption('2026', '2026')->label('')
|
||||||
|
!!}
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row" style="padding-top:18px">
|
||||||
|
<div class="col-md-5">
|
||||||
|
@if ($client && $account->showTokenCheckbox($storageGateway/* will contain gateway id */))
|
||||||
|
<input id="token_billing" type="checkbox" name="token_billing" {{ $account->selectTokenCheckbox() ? 'CHECKED' : '' }} value="1" style="margin-left:0px; vertical-align:top">
|
||||||
|
<label for="token_billing" class="checkbox" style="display: inline;">{{ trans('texts.token_billing') }}</label>
|
||||||
|
<span class="help-block" style="font-size:15px">
|
||||||
|
@if ($storageGateway == GATEWAY_STRIPE)
|
||||||
|
{!! trans('texts.token_billing_secure', ['link' => link_to('https://stripe.com/', 'Stripe.com', ['target' => '_blank'])]) !!}
|
||||||
|
@elseif ($storageGateway == GATEWAY_BRAINTREE)
|
||||||
|
{!! trans('texts.token_billing_secure', ['link' => link_to('https://www.braintreepayments.com/', 'Braintree', ['target' => '_blank'])]) !!}
|
||||||
|
@endif
|
||||||
|
</span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-7">
|
||||||
|
@if (isset($acceptedCreditCardTypes))
|
||||||
|
<div class="pull-right">
|
||||||
|
@foreach ($acceptedCreditCardTypes as $card)
|
||||||
|
<img src="{{ $card['source'] }}" alt="{{ $card['alt'] }}" style="width: 70px; display: inline; margin-right: 6px;"/>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p> </p>
|
<p> </p>
|
||||||
<center>
|
<center>
|
||||||
{!! Button::success(strtoupper(trans('texts.pay_now') . ' - ' . $account->formatMoney($amount, $client, true) ))
|
{!! Button::success(strtoupper(trans('texts.pay_now') . ' - ' . $account->formatMoney($amount, $client, true) ))
|
||||||
->submit()
|
->submit()
|
||||||
->large() !!}
|
->large() !!}
|
||||||
</center>
|
</center>
|
||||||
<p> </p>
|
<p> </p>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div id="js-error-message" style="display:none" class="alert alert-danger"></div>
|
<div id="js-error-message" style="display:none" class="alert alert-danger"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -422,7 +553,47 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#country_id').combobox();
|
$('#country_id').combobox();
|
||||||
|
$('#country').combobox();
|
||||||
|
$('#currency').combobox();
|
||||||
$('#first_name').focus();
|
$('#first_name').focus();
|
||||||
|
|
||||||
|
var routingNumberCache = {};
|
||||||
|
$('#routing_number, #country').on('change keypress keyup keydown paste', function(){setTimeout(function () {
|
||||||
|
var routingNumber = $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
||||||
|
|
||||||
|
if (routingNumber.length != 9 || $("#country").val() != 'US' || routingNumberCache[routingNumber] === false) {
|
||||||
|
$('#bank_name').hide();
|
||||||
|
} else if (routingNumberCache[routingNumber]) {
|
||||||
|
$('#bank_name').empty().append(routingNumberCache[routingNumber]).show();
|
||||||
|
} else {
|
||||||
|
routingNumberCache[routingNumber] = false;
|
||||||
|
$('#bank_name').hide();
|
||||||
|
$.ajax({
|
||||||
|
url:"{{ URL::to('/bank') }}/" + routingNumber,
|
||||||
|
success:function(data) {
|
||||||
|
var els = $().add(document.createTextNode(data.name)).add('<br>').add(document.createTextNode(data.city + ", " + data.state));
|
||||||
|
routingNumberCache[routingNumber] = els;
|
||||||
|
|
||||||
|
// Still the same number?
|
||||||
|
if (routingNumber == $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#bank_name').empty().append(els).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(xhr) {
|
||||||
|
if (xhr.status == 404) {
|
||||||
|
var els = $(document.createTextNode('{{trans('texts.unknown_bank')}}'));
|
||||||
|
;
|
||||||
|
routingNumberCache[routingNumber] = els;
|
||||||
|
|
||||||
|
// Still the same number?
|
||||||
|
if (routingNumber == $('#routing_number').val().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')) {
|
||||||
|
$('#bank_name').empty().append(els).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},10)})
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
149
resources/views/payments/paymentmethods.blade.php
Normal file
149
resources/views/payments/paymentmethods.blade.php
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
@extends('public.header')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<style type="text/css">
|
||||||
|
.payment_method_img_container{
|
||||||
|
width:37px;
|
||||||
|
text-align: center;
|
||||||
|
display:inline-block;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment_method{
|
||||||
|
margin:20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.payment_method_number{
|
||||||
|
margin-right:10px;
|
||||||
|
width:65px;
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="container main-container">
|
||||||
|
|
||||||
|
<h3>{{ $title }}</h3>
|
||||||
|
|
||||||
|
@foreach ($paymentMethods as $paymentMethod)
|
||||||
|
<div class="payment_method">
|
||||||
|
<span class="payment_method_img_container">
|
||||||
|
<img height="22" src="{{URL::to('/images/credit_cards/'.str_replace(' ', '', strtolower($paymentMethod['type']->name).'.png'))}}" alt="{{trans("texts.card_" . str_replace(' ', '', strtolower($paymentMethod['type']->name)))}}">
|
||||||
|
</span>
|
||||||
|
<span class="payment_method_number">•••••{{$paymentMethod['last4']}}</span>
|
||||||
|
|
||||||
|
@if($paymentMethod['type']->id == PAYMENT_TYPE_ACH)
|
||||||
|
{{ $paymentMethod['bank_name'] }}
|
||||||
|
@if($paymentMethod['status'] == 'new')
|
||||||
|
<a href="javasript::void" onclick="completeVerification('{{$paymentMethod['id']}}','{{$paymentMethod['currency']->symbol}}')">({{trans('texts.complete_verification')}})</a>
|
||||||
|
@elseif($paymentMethod['status'] == 'verification_failed')
|
||||||
|
({{trans('texts.verification_failed')}})
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
{!! trans('texts.card_expiration', array('expires'=>Utils::fromSqlDate($paymentMethod['expiration'], false)->format('m/y'))) !!}
|
||||||
|
@endif
|
||||||
|
@if($paymentMethod['default'])
|
||||||
|
({{trans('texts.used_for_auto_bill')}})
|
||||||
|
@elseif($paymentMethod['type']->id != PAYMENT_TYPE_ACH || $paymentMethod['status'] == 'verified')
|
||||||
|
<a href="#" onclick="setDefault('{{$paymentMethod['id']}}')">({{trans('texts.use_for_auto_bill')}})</a>
|
||||||
|
@endif
|
||||||
|
<a href="javasript::void" class="payment_method_remove" onclick="removePaymentMethod('{{$paymentMethod['id']}}')">×</a>
|
||||||
|
</div>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
<center>
|
||||||
|
{!! Button::success(strtoupper(trans('texts.add_credit_card')))
|
||||||
|
->asLinkTo(URL::to('/client/paymentmethods/add/'.($gateway->getPaymentType() == PAYMENT_TYPE_STRIPE ? 'stripe_credit_card' : 'credit_card'))) !!}
|
||||||
|
@if($gateway->getACHEnabled())
|
||||||
|
|
||||||
|
{!! Button::success(strtoupper(trans('texts.add_bank_account')))
|
||||||
|
->asLinkTo(URL::to('/client/paymentmethods/add/stripe_ach')) !!}
|
||||||
|
@endif
|
||||||
|
</center>
|
||||||
|
<p></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="completeVerificationModal" tabindex="-1" role="dialog" aria-labelledby="completeVerificationModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" style="min-width:150px">
|
||||||
|
<div class="modal-content">
|
||||||
|
{!! Former::open('/client/paymentmethods/verify') !!}
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" id="completeVerificationModalLabel">{{ trans('texts.complete_verification') }}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div style="display:none">
|
||||||
|
{!! Former::text('source_id') !!}
|
||||||
|
</div>
|
||||||
|
<p>{{ trans('texts.bank_account_verification_help') }}</p>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="verification1" class="control-label col-sm-5">{{ trans('texts.verification_amount1') }}</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><span class="payment_method_currenct_symbol"></span>0.</span>
|
||||||
|
<input type="number" min="0" max="99" required class="form-control" id="verification1" name="verification1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="verification2" class="control-label col-sm-5">{{ trans('texts.verification_amount2') }}</label>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="input-group">
|
||||||
|
<span class="input-group-addon"><span class="payment_method_currenct_symbol"></span>0.</span>
|
||||||
|
<input type="number" min="0" max="99" required class="form-control" id="verification2" name="verification2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" style="margin-top: 0px">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{{ trans('texts.complete_verification') }}</button>
|
||||||
|
</div>
|
||||||
|
{!! Former::close() !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="removePaymentMethodModal" tabindex="-1" role="dialog" aria-labelledby="removePaymentMethodModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" style="min-width:150px">
|
||||||
|
<div class="modal-content">
|
||||||
|
{!! Former::open()->id('removeForm') !!}
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" id="removePaymentMethodModalLabel">{{ trans('texts.remove_payment_method') }}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>{{ trans('texts.confirm_remove_payment_method') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" style="margin-top: 0px">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.cancel') }}</button>
|
||||||
|
<button type="submit" class="btn btn-primary">{{ trans('texts.remove') }}</button>
|
||||||
|
</div>
|
||||||
|
{!! Former::close() !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!! Former::open(URL::to('/client/paymentmethods/default'))->id('defaultSourceForm') !!}
|
||||||
|
<input type="hidden" name="source" id="default_id">
|
||||||
|
{!! Former::close() !!}
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
function completeVerification(sourceId, currencySymbol) {
|
||||||
|
$('#source_id').val(sourceId);
|
||||||
|
$('.payment_method_currenct_symbol').text(currencySymbol);
|
||||||
|
$('#completeVerificationModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function removePaymentMethod(sourceId) {
|
||||||
|
$('#removeForm').attr('action', '{{ URL::to('/client/paymentmethods/%s/remove') }}'.replace('%s', sourceId))
|
||||||
|
$('#removePaymentMethodModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function setDefault(sourceId) {
|
||||||
|
$('#default_id').val(sourceId);
|
||||||
|
$('#defaultSourceForm').submit()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
@stop
|
@ -7,9 +7,7 @@
|
|||||||
<link href="//fonts.googleapis.com/css?family=Roboto:400,700,900,100" rel="stylesheet" type="text/css">
|
<link href="//fonts.googleapis.com/css?family=Roboto:400,700,900,100" rel="stylesheet" type="text/css">
|
||||||
@endif
|
@endif
|
||||||
<link href="{{ asset('css/built.public.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
|
<link href="{{ asset('css/built.public.css') }}?no_cache={{ NINJA_VERSION }}" rel="stylesheet" type="text/css"/>
|
||||||
@if (!empty($clientViewCSS))
|
<style type="text/css">{!! isset($account)?$account->clientViewCSS():'' !!}</style>
|
||||||
<style type="text/css">{!! $clientViewCSS !!}</style>
|
|
||||||
@endif
|
|
||||||
@stop
|
@stop
|
||||||
|
|
||||||
@section('body')
|
@section('body')
|
||||||
@ -68,15 +66,15 @@
|
|||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
<span class="icon-bar"></span>
|
<span class="icon-bar"></span>
|
||||||
</button>
|
</button>
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
{{-- Per our license, please do not remove or modify this link. --}}
|
{{-- Per our license, please do not remove or modify this link. --}}
|
||||||
<a class="navbar-brand" href="{{ URL::to(NINJA_WEB_URL) }}" target="_blank"><img src="{{ asset('images/invoiceninja-logo.png') }}" style="height:20px"></a>
|
<a class="navbar-brand" href="{{ URL::to(NINJA_WEB_URL) }}" target="_blank"><img src="{{ asset('images/invoiceninja-logo.png') }}" style="height:20px"></a>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div id="navbar" class="collapse navbar-collapse">
|
<div id="navbar" class="collapse navbar-collapse">
|
||||||
@if (!isset($hideHeader) || !$hideHeader)
|
@if (!isset($account) || $account->isNinjaAccount() || $account->enable_client_portal)
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
@if (!isset($hideDashboard) || !$hideDashboard)
|
@if (!isset($account) || $account->enable_client_portal_dashboard)
|
||||||
<li {{ Request::is('*client/dashboard') ? 'class="active"' : '' }}>
|
<li {{ Request::is('*client/dashboard') ? 'class="active"' : '' }}>
|
||||||
{!! link_to('/client/dashboard', trans('texts.dashboard') ) !!}
|
{!! link_to('/client/dashboard', trans('texts.dashboard') ) !!}
|
||||||
</li>
|
</li>
|
||||||
@ -87,11 +85,16 @@
|
|||||||
<li {{ Request::is('*client/invoices') ? 'class="active"' : '' }}>
|
<li {{ Request::is('*client/invoices') ? 'class="active"' : '' }}>
|
||||||
{!! link_to('/client/invoices', trans('texts.invoices') ) !!}
|
{!! link_to('/client/invoices', trans('texts.invoices') ) !!}
|
||||||
</li>
|
</li>
|
||||||
@if (!empty($showDocuments))
|
@if ($account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
<li {{ Request::is('*client/documents') ? 'class="active"' : '' }}>
|
<li {{ Request::is('*client/documents') ? 'class="active"' : '' }}>
|
||||||
{!! link_to('/client/documents', trans('texts.documents') ) !!}
|
{!! link_to('/client/documents', trans('texts.documents') ) !!}
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
@if ($account->getTokenGatewayId())
|
||||||
|
<li {{ Request::is('*client/paymentmethods') ? 'class="active"' : '' }}>
|
||||||
|
{!! link_to('/client/paymentmethods', trans('texts.payment_methods') ) !!}
|
||||||
|
</li>
|
||||||
|
@endif
|
||||||
<li {{ Request::is('*client/payments') ? 'class="active"' : '' }}>
|
<li {{ Request::is('*client/payments') ? 'class="active"' : '' }}>
|
||||||
{!! link_to('/client/payments', trans('texts.payments') ) !!}
|
{!! link_to('/client/payments', trans('texts.payments') ) !!}
|
||||||
</li>
|
</li>
|
||||||
@ -123,7 +126,7 @@
|
|||||||
<footer id="footer" role="contentinfo">
|
<footer id="footer" role="contentinfo">
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<div id="footer-menu" class="menu-wrap">
|
<div id="footer-menu" class="menu-wrap">
|
||||||
<ul id="menu-footer-menu" class="menu">
|
<ul id="menu-footer-menu" class="menu">
|
||||||
<li id="menu-item-31" class="menu-item-31">
|
<li id="menu-item-31" class="menu-item-31">
|
||||||
@ -146,7 +149,7 @@
|
|||||||
|
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
@if (!isset($hideLogo) || !$hideLogo)
|
@if (!isset($account) || !$account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<div class="copy">Copyright ©{{ date('Y') }} <a href="{{ NINJA_WEB_URL }}" target="_blank">Invoice Ninja</a>. All rights reserved.</div>
|
<div class="copy">Copyright ©{{ date('Y') }} <a href="{{ NINJA_WEB_URL }}" target="_blank">Invoice Ninja</a>. All rights reserved.</div>
|
||||||
@endif
|
@endif
|
||||||
</div><!-- .wrap -->
|
</div><!-- .wrap -->
|
||||||
|
Loading…
Reference in New Issue
Block a user