mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-09 03:14:30 -04:00
Store Stripe card summary locally
This commit is contained in:
parent
ad39f106db
commit
88ec714cd5
@ -20,6 +20,7 @@ use App\Models\PaymentType;
|
|||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
use App\Models\Affiliate;
|
use App\Models\Affiliate;
|
||||||
|
use App\Models\PaymentMethod;
|
||||||
use App\Ninja\Repositories\PaymentRepository;
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
@ -406,6 +407,7 @@ class PaymentController extends BaseController
|
|||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
$paymentType = Session::get($invitation->id . 'payment_type');
|
$paymentType = Session::get($invitation->id . 'payment_type');
|
||||||
$accountGateway = $account->getGatewayByType($paymentType);
|
$accountGateway = $account->getGatewayByType($paymentType);
|
||||||
|
$paymentMethod = null;
|
||||||
|
|
||||||
$rules = [
|
$rules = [
|
||||||
'first_name' => 'required',
|
'first_name' => 'required',
|
||||||
@ -436,6 +438,17 @@ class PaymentController extends BaseController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($useToken) {
|
||||||
|
if(!$sourceId) {
|
||||||
|
Session::flash('error', trans('texts.no_payment_method_specified'));
|
||||||
|
return Redirect::to('payment/' . $invitationKey)->withInput(Request::except('cvv'));
|
||||||
|
} else {
|
||||||
|
$customerReference = $client->getGatewayToken($accountGateway, $accountGatewayToken/* return parameter*/);
|
||||||
|
$paymentMethod = PaymentMethod::scope($sourceId, $account->id, $accountGatewayToken->id)->firstOrFail();
|
||||||
|
$sourceReference = $paymentMethod->source_reference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($onSite) {
|
if ($onSite) {
|
||||||
$validator = Validator::make(Input::all(), $rules);
|
$validator = Validator::make(Input::all(), $rules);
|
||||||
|
|
||||||
@ -476,11 +489,9 @@ class PaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($useToken) {
|
if ($useToken) {
|
||||||
$details['customerReference'] = $client->getGatewayToken();
|
$details['customerReference'] = $customerReference;
|
||||||
unset($details['token']);
|
unset($details['token']);
|
||||||
if ($sourceId) {
|
$details['cardReference'] = $sourceReference;
|
||||||
$details['cardReference'] = $sourceId;
|
|
||||||
}
|
|
||||||
} elseif ($account->token_billing_type_id == TOKEN_BILLING_ALWAYS || Input::get('token_billing') || $paymentType == PAYMENT_TYPE_STRIPE_ACH) {
|
} 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 */);
|
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */);
|
||||||
if ($token) {
|
if ($token) {
|
||||||
@ -509,13 +520,8 @@ class PaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($useToken) {
|
if ($useToken) {
|
||||||
$details['customerId'] = $customerId = $client->getGatewayToken();
|
$details['customerId'] = $customerReference;
|
||||||
if (!$sourceId) {
|
$details['paymentMethodToken'] = $sourceReference;
|
||||||
$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/* return parameter */);
|
$token = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id, $customerReference/* return parameter */);
|
||||||
@ -536,7 +542,6 @@ class PaymentController extends BaseController
|
|||||||
|
|
||||||
$response = $gateway->purchase($details)->send();
|
$response = $gateway->purchase($details)->send();
|
||||||
|
|
||||||
|
|
||||||
if ($accountGateway->gateway_id == GATEWAY_EWAY) {
|
if ($accountGateway->gateway_id == GATEWAY_EWAY) {
|
||||||
$ref = $response->getData()['AccessCode'];
|
$ref = $response->getData()['AccessCode'];
|
||||||
} elseif ($accountGateway->gateway_id == GATEWAY_TWO_CHECKOUT) {
|
} elseif ($accountGateway->gateway_id == GATEWAY_TWO_CHECKOUT) {
|
||||||
@ -563,7 +568,7 @@ class PaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($response->isSuccessful()) {
|
if ($response->isSuccessful()) {
|
||||||
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref, null, $details, $response);
|
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref, null, $details, $paymentMethod, $response);
|
||||||
Session::flash('message', trans('texts.applied_payment'));
|
Session::flash('message', trans('texts.applied_payment'));
|
||||||
|
|
||||||
if ($account->account_key == NINJA_ACCOUNT_KEY) {
|
if ($account->account_key == NINJA_ACCOUNT_KEY) {
|
||||||
@ -660,7 +665,7 @@ class PaymentController extends BaseController
|
|||||||
if ($response->isCancelled()) {
|
if ($response->isCancelled()) {
|
||||||
// do nothing
|
// do nothing
|
||||||
} elseif ($response->isSuccessful()) {
|
} elseif ($response->isSuccessful()) {
|
||||||
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref, $payerId, $details, $purchaseResponse);
|
$payment = $this->paymentService->createPayment($invitation, $accountGateway, $ref, $payerId, $details, null, $purchaseResponse);
|
||||||
Session::flash('message', trans('texts.applied_payment'));
|
Session::flash('message', trans('texts.applied_payment'));
|
||||||
} else {
|
} else {
|
||||||
$this->error('offsite', $response->getMessage(), $accountGateway);
|
$this->error('offsite', $response->getMessage(), $accountGateway);
|
||||||
@ -738,7 +743,7 @@ class PaymentController extends BaseController
|
|||||||
], 400);
|
], 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = static::getBankData($routingNumber);
|
$data = PaymentMethod::lookupBankData($routingNumber);
|
||||||
|
|
||||||
if (is_string($data)) {
|
if (is_string($data)) {
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -753,75 +758,10 @@ class PaymentController extends BaseController
|
|||||||
], 404);
|
], 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handlePaymentWebhook($accountKey, $gatewayId)
|
public function handlePaymentWebhook($accountKey, $gatewayId)
|
||||||
{
|
{
|
||||||
$gatewayId = intval($gatewayId);
|
$gatewayId = intval($gatewayId);
|
||||||
|
|
||||||
if ($gatewayId != GATEWAY_STRIPE) {
|
|
||||||
return response()->json([
|
|
||||||
'message' => 'Unsupported gateway',
|
|
||||||
], 404);
|
|
||||||
}
|
|
||||||
|
|
||||||
$account = Account::where('accounts.account_key', '=', $accountKey)->first();
|
$account = Account::where('accounts.account_key', '=', $accountKey)->first();
|
||||||
|
|
||||||
if (!$account) {
|
if (!$account) {
|
||||||
@ -830,27 +770,48 @@ class PaymentController extends BaseController
|
|||||||
], 404);
|
], 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$accountGateway = $account->getGatewayConfig(intval($gatewayId));
|
||||||
|
|
||||||
|
if (!$accountGateway) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Unknown gateway',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch($gatewayId) {
|
||||||
|
case GATEWAY_STRIPE:
|
||||||
|
return $this->handleStripeWebhook($accountGateway);
|
||||||
|
default:
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Unsupported gateway',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleStripeWebhook($accountGateway) {
|
||||||
$eventId = Input::get('id');
|
$eventId = Input::get('id');
|
||||||
$eventType= Input::get('type');
|
$eventType= Input::get('type');
|
||||||
|
$accountId = $accountGateway->account_id;
|
||||||
|
|
||||||
if (!$eventId) {
|
if (!$eventId) {
|
||||||
return response()->json([
|
return response()->json(['message' => 'Missing event id'], 400);
|
||||||
'message' => 'Missing event id',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$eventType) {
|
if (!$eventType) {
|
||||||
return response()->json([
|
return response()->json(['message' => 'Missing event type'], 400);
|
||||||
'message' => 'Missing event type',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!in_array($eventType, array('charge.failed', 'charge.succeeded'))) {
|
$supportedEvents = array(
|
||||||
|
'charge.failed',
|
||||||
|
'charge.succeeded',
|
||||||
|
'customer.source.updated',
|
||||||
|
'customer.source.deleted',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!in_array($eventType, $supportedEvents)) {
|
||||||
return array('message' => 'Ignoring event');
|
return array('message' => 'Ignoring event');
|
||||||
}
|
}
|
||||||
|
|
||||||
$accountGateway = $account->getGatewayConfig(intval($gatewayId));
|
|
||||||
|
|
||||||
// Fetch the event directly from Stripe for security
|
// Fetch the event directly from Stripe for security
|
||||||
$eventDetails = $this->paymentService->makeStripeCall($accountGateway, 'GET', 'events/'.$eventId);
|
$eventDetails = $this->paymentService->makeStripeCall($accountGateway, 'GET', 'events/'.$eventId);
|
||||||
|
|
||||||
@ -861,21 +822,19 @@ class PaymentController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($eventType != $eventDetails['type']) {
|
if ($eventType != $eventDetails['type']) {
|
||||||
return response()->json([
|
return response()->json(['message' => 'Event type mismatch'], 400);
|
||||||
'message' => 'Event type mismatch',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$eventDetails['pending_webhooks']) {
|
if (!$eventDetails['pending_webhooks']) {
|
||||||
return response()->json([
|
return response()->json(['message' => 'This is not a pending event'], 400);
|
||||||
'message' => 'This is not a pending event',
|
|
||||||
], 400);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($eventType == 'charge.failed' || $eventType == 'charge.succeeded') {
|
||||||
$charge = $eventDetails['data']['object'];
|
$charge = $eventDetails['data']['object'];
|
||||||
$transactionRef = $charge['id'];
|
$transactionRef = $charge['id'];
|
||||||
|
|
||||||
$payment = Payment::where('transaction_reference', '=', $transactionRef)->first();
|
$payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $transactionRef)->first();
|
||||||
|
|
||||||
if (!$payment) {
|
if (!$payment) {
|
||||||
return array('message' => 'Unknown payment');
|
return array('message' => 'Unknown payment');
|
||||||
@ -889,6 +848,22 @@ class PaymentController extends BaseController
|
|||||||
} elseif ($eventType == 'charge.succeeded') {
|
} elseif ($eventType == 'charge.succeeded') {
|
||||||
$payment->markComplete();
|
$payment->markComplete();
|
||||||
}
|
}
|
||||||
|
} elseif($eventType == 'customer.source.updated' || $eventType == 'customer.source.deleted') {
|
||||||
|
$source = $eventDetails['data']['object'];
|
||||||
|
$sourceRef = $source['id'];
|
||||||
|
|
||||||
|
$paymentMethod = PaymentMethod::scope(false, $accountId)->where('source_reference', '=', $sourceRef)->first();
|
||||||
|
|
||||||
|
if (!$paymentMethod) {
|
||||||
|
return array('message' => 'Unknown payment method');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($eventType == 'customer.source.deleted') {
|
||||||
|
$paymentMethod->delete();
|
||||||
|
} elseif ($eventType == 'customer.source.updated') {
|
||||||
|
$this->paymentService->convertPaymentMethodFromStripe($source, null, $paymentMethod)->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return array('message' => 'Processed successfully');
|
return array('message' => 'Processed successfully');
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use Redirect;
|
|||||||
use App\Models\Gateway;
|
use App\Models\Gateway;
|
||||||
use App\Models\Invitation;
|
use App\Models\Invitation;
|
||||||
use App\Models\Document;
|
use App\Models\Document;
|
||||||
|
use App\ModelsPaymentMethod;
|
||||||
use App\Ninja\Repositories\InvoiceRepository;
|
use App\Ninja\Repositories\InvoiceRepository;
|
||||||
use App\Ninja\Repositories\PaymentRepository;
|
use App\Ninja\Repositories\PaymentRepository;
|
||||||
use App\Ninja\Repositories\ActivityRepository;
|
use App\Ninja\Repositories\ActivityRepository;
|
||||||
@ -170,28 +171,30 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
if ($paymentMethods) {
|
if ($paymentMethods) {
|
||||||
foreach ($paymentMethods as $paymentMethod) {
|
foreach ($paymentMethods as $paymentMethod) {
|
||||||
if ($paymentMethod['type']->id != PAYMENT_TYPE_ACH || $paymentMethod['status'] == 'verified') {
|
if ($paymentMethod->payment_type_id != PAYMENT_TYPE_ACH || $paymentMethod->status == PAYMENT_METHOD_STATUS_VERIFIED) {
|
||||||
|
$code = htmlentities(str_replace(' ', '', strtolower($paymentMethod->payment_type->name)));
|
||||||
|
|
||||||
if ($paymentMethod['type']->id == PAYMENT_TYPE_ACH) {
|
if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) {
|
||||||
$html = '<div>'.htmlentities($paymentMethod['bank_name']).'</div>';
|
if($paymentMethod->bank_data) {
|
||||||
} elseif ($paymentMethod['type']->id == PAYMENT_TYPE_ID_PAYPAL) {
|
$html = '<div>' . htmlentities($paymentMethod->bank_data->name) . '</div>';
|
||||||
|
}
|
||||||
|
} elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_ID_PAYPAL) {
|
||||||
$html = '<img height="22" src="'.URL::to('/images/credit_cards/paypal.png').'" alt="'.trans("texts.card_".$code).'">';
|
$html = '<img height="22" src="'.URL::to('/images/credit_cards/paypal.png').'" alt="'.trans("texts.card_".$code).'">';
|
||||||
} else {
|
} 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).'">';
|
$html = '<img height="22" src="'.URL::to('/images/credit_cards/'.$code.'.png').'" alt="'.trans("texts.card_".$code).'">';
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = URL::to("/payment/{$invitation->invitation_key}/token/".$paymentMethod['id']);
|
$url = URL::to("/payment/{$invitation->invitation_key}/token/".$paymentMethod->public_id);
|
||||||
|
|
||||||
if ($paymentMethod['type']->id == PAYMENT_TYPE_ID_PAYPAL) {
|
if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ID_PAYPAL) {
|
||||||
$html .= ' <span>'.$paymentMethod['email'].'</span>';
|
$html .= ' <span>'.$paymentMethod->email.'</span>';
|
||||||
$url .= '#braintree_paypal';
|
$url .= '#braintree_paypal';
|
||||||
} elseif ($paymentMethod['type']->id != PAYMENT_TYPE_ACH) {
|
} elseif ($paymentMethod->payment_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>';
|
$html .= '<div class="pull-right" style="text-align:right">'.trans('texts.card_expiration', array('expires' => Utils::fromSqlDate($paymentMethod->expiration, false)->format('m/y'))).'<br>';
|
||||||
$html .= '•••'.$paymentMethod['last4'].'</div>';
|
$html .= '•••'.$paymentMethod->last4.'</div>';
|
||||||
} else {
|
} else {
|
||||||
$html .= '<div style="text-align:right">';
|
$html .= '<div style="text-align:right">';
|
||||||
$html .= '•••'.$paymentMethod['last4'].'</div>';
|
$html .= '•••'.$paymentMethod->last4.'</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
$paymentTypes[] = [
|
$paymentTypes[] = [
|
||||||
@ -452,9 +455,9 @@ class PublicClientController extends BaseController
|
|||||||
return $model->email;
|
return $model->email;
|
||||||
}
|
}
|
||||||
} elseif ($model->last4) {
|
} elseif ($model->last4) {
|
||||||
$bankData = PaymentController::getBankData($model->routing_number);
|
$bankData = PaymentMethod::lookupBankData($model->routing_number);
|
||||||
if (is_array($bankData)) {
|
if (is_object($bankData)) {
|
||||||
return $bankData['name'].' •••' . $model->last4;
|
return $bankData->name.' •••' . $model->last4;
|
||||||
} elseif($model->last4) {
|
} elseif($model->last4) {
|
||||||
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
||||||
}
|
}
|
||||||
@ -770,7 +773,7 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
public function verifyPaymentMethod()
|
public function verifyPaymentMethod()
|
||||||
{
|
{
|
||||||
$sourceId = Input::get('source_id');
|
$publicId = Input::get('source_id');
|
||||||
$amount1 = Input::get('verification1');
|
$amount1 = Input::get('verification1');
|
||||||
$amount2 = Input::get('verification2');
|
$amount2 = Input::get('verification2');
|
||||||
|
|
||||||
@ -779,7 +782,7 @@ class PublicClientController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
$client = $invitation->invoice->client;
|
$client = $invitation->invoice->client;
|
||||||
$result = $this->paymentService->verifyClientPaymentMethod($client, $sourceId, $amount1, $amount2);
|
$result = $this->paymentService->verifyClientPaymentMethod($client, $publicId, $amount1, $amount2);
|
||||||
|
|
||||||
if (is_string($result)) {
|
if (is_string($result)) {
|
||||||
Session::flash('error', $result);
|
Session::flash('error', $result);
|
||||||
@ -790,14 +793,14 @@ class PublicClientController extends BaseController
|
|||||||
return redirect()->to($client->account->enable_client_portal?'/client/dashboard':'/client/paymentmethods/');
|
return redirect()->to($client->account->enable_client_portal?'/client/dashboard':'/client/paymentmethods/');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function removePaymentMethod($sourceId)
|
public function removePaymentMethod($publicId)
|
||||||
{
|
{
|
||||||
if (!$invitation = $this->getInvitation()) {
|
if (!$invitation = $this->getInvitation()) {
|
||||||
return $this->returnError();
|
return $this->returnError();
|
||||||
}
|
}
|
||||||
|
|
||||||
$client = $invitation->invoice->client;
|
$client = $invitation->invoice->client;
|
||||||
$result = $this->paymentService->removeClientPaymentMethod($client, $sourceId);
|
$result = $this->paymentService->removeClientPaymentMethod($client, $publicId);
|
||||||
|
|
||||||
if (is_string($result)) {
|
if (is_string($result)) {
|
||||||
Session::flash('error', $result);
|
Session::flash('error', $result);
|
||||||
@ -824,9 +827,9 @@ class PublicClientController extends BaseController
|
|||||||
$gateway = $accountGateway->gateway;
|
$gateway = $accountGateway->gateway;
|
||||||
|
|
||||||
if ($token && $paymentType == PAYMENT_TYPE_BRAINTREE_PAYPAL) {
|
if ($token && $paymentType == PAYMENT_TYPE_BRAINTREE_PAYPAL) {
|
||||||
$sourceId = $this->paymentService->createToken($this->paymentService->createGateway($accountGateway), array('token'=>$token), $accountGateway, $client, $invitation->contact_id);
|
$sourceReference = $this->paymentService->createToken($this->paymentService->createGateway($accountGateway), array('token'=>$token), $accountGateway, $client, $invitation->contact_id);
|
||||||
|
|
||||||
if(empty($sourceId)) {
|
if(empty($sourceReference)) {
|
||||||
$this->paymentMethodError('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
$this->paymentMethodError('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
||||||
} else {
|
} else {
|
||||||
Session::flash('message', trans('texts.payment_method_added'));
|
Session::flash('message', trans('texts.payment_method_added'));
|
||||||
@ -895,12 +898,12 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
if (!empty($details)) {
|
if (!empty($details)) {
|
||||||
$gateway = $this->paymentService->createGateway($accountGateway);
|
$gateway = $this->paymentService->createGateway($accountGateway);
|
||||||
$sourceId = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id);
|
$sourceReference = $this->paymentService->createToken($gateway, $details, $accountGateway, $client, $invitation->contact_id);
|
||||||
} else {
|
} else {
|
||||||
return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));
|
return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($sourceId)) {
|
if(empty($sourceReference)) {
|
||||||
$this->paymentMethodError('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
$this->paymentMethodError('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
|
||||||
return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));
|
return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));
|
||||||
} else if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty($usingPlaid) ) {
|
} else if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty($usingPlaid) ) {
|
||||||
|
@ -647,6 +647,10 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('PAYMENT_TYPE_SOLO', 22);
|
define('PAYMENT_TYPE_SOLO', 22);
|
||||||
define('PAYMENT_TYPE_SWITCH', 23);
|
define('PAYMENT_TYPE_SWITCH', 23);
|
||||||
|
|
||||||
|
define('PAYMENT_METHOD_STATUS_NEW', 'new');
|
||||||
|
define('PAYMENT_METHOD_STATUS_VERIFICATION_FAILED', 'verification_failed');
|
||||||
|
define('PAYMENT_METHOD_STATUS_VERIFIED', 'verified');
|
||||||
|
|
||||||
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_CREDIT_CARD', 'PAYMENT_TYPE_STRIPE_CREDIT_CARD');
|
||||||
|
@ -8,4 +8,18 @@ class AccountGatewayToken extends Eloquent
|
|||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
public $timestamps = true;
|
public $timestamps = true;
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'uses_local_payment_methods' => 'boolean',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function payment_methods()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\PaymentMethod');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function default_payment_method()
|
||||||
|
{
|
||||||
|
return $this->hasOne('App\Models\PaymentMethod', 'id', 'default_payment_method_id');
|
||||||
|
}
|
||||||
}
|
}
|
@ -261,7 +261,7 @@ class Client extends EntityModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function getGatewayToken(&$accountGateway)
|
public function getGatewayToken(&$accountGateway = null, &$token = null)
|
||||||
{
|
{
|
||||||
$account = $this->account;
|
$account = $this->account;
|
||||||
|
|
||||||
@ -272,7 +272,10 @@ class Client extends EntityModel
|
|||||||
if (!count($account->account_gateways)) {
|
if (!count($account->account_gateways)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$accountGateway){
|
||||||
$accountGateway = $account->getTokenGateway();
|
$accountGateway = $account->getTokenGateway();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$accountGateway) {
|
if (!$accountGateway) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -8,6 +8,7 @@ use App\Events\PaymentWasVoided;
|
|||||||
use App\Events\PaymentCompleted;
|
use App\Events\PaymentCompleted;
|
||||||
use App\Events\PaymentVoided;
|
use App\Events\PaymentVoided;
|
||||||
use App\Events\PaymentFailed;
|
use App\Events\PaymentFailed;
|
||||||
|
use App\Models\PaymentMethod;
|
||||||
use Laracasts\Presenter\PresentableTrait;
|
use Laracasts\Presenter\PresentableTrait;
|
||||||
|
|
||||||
class Payment extends EntityModel
|
class Payment extends EntityModel
|
||||||
@ -58,6 +59,11 @@ class Payment extends EntityModel
|
|||||||
return $this->belongsTo('App\Models\PaymentType');
|
return $this->belongsTo('App\Models\PaymentType');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payment_method()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\PaymentMethod');
|
||||||
|
}
|
||||||
|
|
||||||
public function payment_status()
|
public function payment_status()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\PaymentStatus');
|
return $this->belongsTo('App\Models\PaymentStatus');
|
||||||
@ -160,6 +166,14 @@ class Payment extends EntityModel
|
|||||||
{
|
{
|
||||||
return ENTITY_PAYMENT;
|
return ENTITY_PAYMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getBankData()
|
||||||
|
{
|
||||||
|
if (!$this->routing_number) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PaymentMethod::lookupBankData($this->routing_number);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Payment::creating(function ($payment) {
|
Payment::creating(function ($payment) {
|
||||||
|
157
app/Models/PaymentMethod.php
Normal file
157
app/Models/PaymentMethod.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Cache;
|
||||||
|
use Eloquent;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class PaymentMethod extends EntityModel
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
|
protected $dates = ['deleted_at'];
|
||||||
|
public $timestamps = true;
|
||||||
|
protected $hidden = ['id'];
|
||||||
|
|
||||||
|
public static function createNew($accountGatewayToken = null)
|
||||||
|
{
|
||||||
|
$entity = new PaymentMethod();
|
||||||
|
|
||||||
|
$entity->account_id = $accountGatewayToken->account_id;
|
||||||
|
$entity->account_gateway_token_id = $accountGatewayToken->id;
|
||||||
|
|
||||||
|
$lastEntity = static::scope(false, $entity->account_id);
|
||||||
|
|
||||||
|
$lastEntity = $lastEntity->orderBy('public_id', 'DESC')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if ($lastEntity) {
|
||||||
|
$entity->public_id = $lastEntity->public_id + 1;
|
||||||
|
} else {
|
||||||
|
$entity->public_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function account()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Account');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function contact()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Contact');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function account_gateway_token()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\AccountGatewayToken');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function payment_type()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\PaymentType');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function currency()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Currency');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function payments()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Payments');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBankData()
|
||||||
|
{
|
||||||
|
if (!$this->routing_number) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return static::lookupBankData($this->routing_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeScope($query, $publicId = false, $accountId = false, $accountGatewayTokenId = false)
|
||||||
|
{
|
||||||
|
$query = parent::scopeScope($query, $publicId, $accountId);
|
||||||
|
|
||||||
|
if ($accountGatewayTokenId) {
|
||||||
|
$query->where($this->getTable() . '.account_gateway_token_id', '=', $accountGatewayTokenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function lookupBankData($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 = new \stdClass();
|
||||||
|
$data->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PaymentMethod::deleting(function($paymentMethod) {
|
||||||
|
$accountGatewayToken = $paymentMethod->account_gateway_token;
|
||||||
|
if ($accountGatewayToken->default_payment_method_id == $paymentMethod->id) {
|
||||||
|
$newDefault = $accountGatewayToken->payment_methods->first(function($i, $paymentMethdod) use ($accountGatewayToken){
|
||||||
|
return $paymentMethdod->id != $accountGatewayToken->default_payment_method_id;
|
||||||
|
});
|
||||||
|
$accountGatewayToken->default_payment_method_id = $newDefault ? $newDefault->id : null;
|
||||||
|
$accountGatewayToken->save();
|
||||||
|
}
|
||||||
|
});
|
@ -10,6 +10,7 @@ use Omnipay;
|
|||||||
use Session;
|
use Session;
|
||||||
use CreditCard;
|
use CreditCard;
|
||||||
use App\Models\Payment;
|
use App\Models\Payment;
|
||||||
|
use App\Models\PaymentMethod;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
use App\Models\Country;
|
use App\Models\Country;
|
||||||
use App\Models\Client;
|
use App\Models\Client;
|
||||||
@ -47,7 +48,7 @@ class PaymentService extends BaseService
|
|||||||
public function createGateway($accountGateway)
|
public function createGateway($accountGateway)
|
||||||
{
|
{
|
||||||
$gateway = Omnipay::create($accountGateway->gateway->provider);
|
$gateway = Omnipay::create($accountGateway->gateway->provider);
|
||||||
$gateway->initialize((array) $accountGateway->getConfig());
|
$gateway->initialize((array)$accountGateway->getConfig());
|
||||||
|
|
||||||
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
|
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
|
||||||
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
|
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
|
||||||
@ -66,7 +67,7 @@ class PaymentService extends BaseService
|
|||||||
{
|
{
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
$account = $invoice->account;
|
$account = $invoice->account;
|
||||||
$key = $invoice->account_id.'-'.$invoice->invoice_number;
|
$key = $invoice->account_id . '-' . $invoice->invoice_number;
|
||||||
$currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD');
|
$currencyCode = $invoice->client->currency ? $invoice->client->currency->code : ($invoice->account->currency ? $invoice->account->currency->code : 'USD');
|
||||||
|
|
||||||
if ($input) {
|
if ($input) {
|
||||||
@ -94,7 +95,7 @@ class PaymentService extends BaseService
|
|||||||
$data['ButtonSource'] = 'InvoiceNinja_SP';
|
$data['ButtonSource'] = 'InvoiceNinja_SP';
|
||||||
};
|
};
|
||||||
|
|
||||||
if($input && $accountGateway->isGateway(GATEWAY_STRIPE)) {
|
if ($input && $accountGateway->isGateway(GATEWAY_STRIPE)) {
|
||||||
if (!empty($input['stripeToken'])) {
|
if (!empty($input['stripeToken'])) {
|
||||||
$data['token'] = $input['stripeToken'];
|
$data['token'] = $input['stripeToken'];
|
||||||
unset($details['card']);
|
unset($details['card']);
|
||||||
@ -174,198 +175,134 @@ class PaymentService extends BaseService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClientPaymentMethods($client) {
|
public function getClientPaymentMethods($client)
|
||||||
$token = $client->getGatewayToken($accountGateway);
|
{
|
||||||
|
$token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
|
||||||
if (!$token) {
|
if (!$token) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$accountGatewayToken->uses_local_payment_methods && $accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
// Migrate Stripe data
|
||||||
$gateway = $this->createGateway($accountGateway);
|
$gateway = $this->createGateway($accountGateway);
|
||||||
|
|
||||||
$paymentMethods = array();
|
|
||||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
|
||||||
$response = $gateway->fetchCustomer(array('customerReference' => $token))->send();
|
$response = $gateway->fetchCustomer(array('customerReference' => $token))->send();
|
||||||
if (!$response->isSuccessful()) {
|
if (!$response->isSuccessful()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = $response->getData();
|
$data = $response->getData();
|
||||||
$default_source = $data['default_source'];
|
|
||||||
$sources = isset($data['sources']) ? $data['sources']['data'] : $data['cards']['data'];
|
$sources = isset($data['sources']) ? $data['sources']['data'] : $data['cards']['data'];
|
||||||
|
|
||||||
$paymentTypes = Cache::get('paymentTypes');
|
// Load
|
||||||
$currencies = Cache::get('currencies');
|
$accountGatewayToken->payment_methods();
|
||||||
foreach ($sources as $source) {
|
foreach ($sources as $source) {
|
||||||
if ($source['object'] == 'bank_account') {
|
$paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken);
|
||||||
$paymentMethods[] = array(
|
if ($paymentMethod) {
|
||||||
'id' => $source['id'],
|
$paymentMethod->save();
|
||||||
'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) {
|
|
||||||
$response = $gateway->findCustomer($token)->send();
|
|
||||||
$data = $response->getData();
|
|
||||||
|
|
||||||
if (!($data instanceof \Braintree\Customer)) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$sources = $data->paymentMethods;
|
if ($data['default_source'] == $source['id']) {
|
||||||
|
$accountGatewayToken->default_payment_method_id = $paymentMethod->id;
|
||||||
$paymentTypes = Cache::get('paymentTypes');
|
|
||||||
$currencies = Cache::get('currencies');
|
|
||||||
foreach ($sources as $source) {
|
|
||||||
if ($source instanceof \Braintree\CreditCard) {
|
|
||||||
$paymentMethods[] = array(
|
|
||||||
'id' => $source->token,
|
|
||||||
'default' => $source->isDefault(),
|
|
||||||
'type' => $paymentTypes->find($this->parseCardType($source->cardType)),
|
|
||||||
'last4' => $source->last4,
|
|
||||||
'expiration' => $source->expirationYear . '-' . $source->expirationMonth . '-00',
|
|
||||||
);
|
|
||||||
} elseif ($source instanceof \Braintree\PayPalAccount) {
|
|
||||||
$paymentMethods[] = array(
|
|
||||||
'id' => $source->token,
|
|
||||||
'default' => $source->isDefault(),
|
|
||||||
'type' => $paymentTypes->find(PAYMENT_TYPE_ID_PAYPAL),
|
|
||||||
'email' => $source->email,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $paymentMethods;
|
$accountGatewayToken->uses_local_payment_methods = true;
|
||||||
|
$accountGatewayToken->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function verifyClientPaymentMethod($client, $sourceId, $amount1, $amount2) {
|
return $accountGatewayToken->payment_methods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function verifyClientPaymentMethod($client, $publicId, $amount1, $amount2)
|
||||||
|
{
|
||||||
$token = $client->getGatewayToken($accountGateway);
|
$token = $client->getGatewayToken($accountGateway);
|
||||||
if ($accountGateway->gateway_id != GATEWAY_STRIPE) {
|
if ($accountGateway->gateway_id != GATEWAY_STRIPE) {
|
||||||
return 'Unsupported gateway';
|
return 'Unsupported gateway';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$paymentMethod = PaymentMethod::scope($publicId, $client->account_id, $accountGatewayToken->id)->firstOrFail();
|
||||||
|
|
||||||
// Omnipay doesn't support verifying payment methods
|
// Omnipay doesn't support verifying payment methods
|
||||||
// Also, it doesn't want to urlencode without putting numbers inside the brackets
|
// Also, it doesn't want to urlencode without putting numbers inside the brackets
|
||||||
return $this->makeStripeCall(
|
$result = $this->makeStripeCall(
|
||||||
$accountGateway,
|
$accountGateway,
|
||||||
'POST',
|
'POST',
|
||||||
'customers/'.$token.'/sources/'.$sourceId.'/verify',
|
'customers/' . $token . '/sources/' . $paymentMethod->source_reference . '/verify',
|
||||||
'amounts[]='.intval($amount1).'&amounts[]='.intval($amount2)
|
'amounts[]=' . intval($amount1) . '&amounts[]=' . intval($amount2)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
public function removeClientPaymentMethod($client, $sourceId) {
|
if (!is_string($result)) {
|
||||||
$token = $client->getGatewayToken($accountGateway/* return parameter */);
|
$paymentMethod->status = PAYMENT_METHOD_STATUS_VERIFIED;
|
||||||
if (!$token) {
|
$paymentMethod->save();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$gateway = $this->createGateway($accountGateway);
|
if (!$paymentMethod->account_gateway_token->default_payment_method_id) {
|
||||||
|
$paymentMethod->account_gateway_token->default_payment_method_id = $paymentMethod->id;
|
||||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
$paymentMethod->account_gateway_token->save();
|
||||||
$response = $gateway->deleteCard(array('customerReference' => $token, 'cardReference'=>$sourceId))->send();
|
|
||||||
if (!$response->isSuccessful()) {
|
|
||||||
return $response->getMessage();
|
|
||||||
}
|
|
||||||
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
|
||||||
// Make sure the source is owned by this client
|
|
||||||
$sources = $this->getClientPaymentMethods($client);
|
|
||||||
$ownsSource = false;
|
|
||||||
foreach ($sources as $source) {
|
|
||||||
if ($source['id'] == $sourceId) {
|
|
||||||
$ownsSource = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$ownsSource) {
|
|
||||||
return 'Unknown source';
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $gateway->deletePaymentMethod(array('token'=>$sourceId))->send();
|
|
||||||
|
|
||||||
if (!$response->isSuccessful()) {
|
|
||||||
return $response->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setClientDefaultPaymentMethod($client, $sourceId) {
|
public function removeClientPaymentMethod($client, $publicId)
|
||||||
$token = $client->getGatewayToken($accountGateway/* return parameter */);
|
|
||||||
if (!$token) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$gateway = $this->createGateway($accountGateway);
|
|
||||||
|
|
||||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
|
||||||
|
|
||||||
return $this->makeStripeCall(
|
|
||||||
$accountGateway,
|
|
||||||
'POST',
|
|
||||||
'customers/'.$token,
|
|
||||||
'default_card='.$sourceId
|
|
||||||
);
|
|
||||||
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
|
||||||
// Make sure the source is owned by this client
|
|
||||||
$sources = $this->getClientPaymentMethods($client);
|
|
||||||
$ownsSource = false;
|
|
||||||
foreach ($sources as $source) {
|
|
||||||
if ($source['id'] == $sourceId) {
|
|
||||||
$ownsSource = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$ownsSource) {
|
|
||||||
return 'Unknown source';
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = $gateway->updatePaymentMethod(array(
|
|
||||||
'token' => $sourceId,
|
|
||||||
'makeDefault' => true,
|
|
||||||
))->send();
|
|
||||||
|
|
||||||
if (!$response->isSuccessful()) {
|
|
||||||
return $response->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createToken($gateway, $details, $accountGateway, $client, $contactId, &$customerReference = null)
|
|
||||||
{
|
{
|
||||||
$customerReference = $client->getGatewayToken();
|
$token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod = PaymentMethod::scope($publicId, $client->account_id, $accountGatewayToken->id)->firstOrFail();
|
||||||
|
|
||||||
|
$gateway = $this->createGateway($accountGateway);
|
||||||
|
|
||||||
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
$response = $gateway->deleteCard(array('customerReference' => $token, 'cardReference' => $paymentMethod->source_reference))->send();
|
||||||
|
if (!$response->isSuccessful()) {
|
||||||
|
return $response->getMessage();
|
||||||
|
}
|
||||||
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
|
$response = $gateway->deletePaymentMethod(array('token' => $paymentMethod->source_reference))->send();
|
||||||
|
|
||||||
|
if (!$response->isSuccessful()) {
|
||||||
|
return $response->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->delete();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setClientDefaultPaymentMethod($client, $publicId)
|
||||||
|
{
|
||||||
|
$token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
|
||||||
|
if (!$token) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod = PaymentMethod::scope($publicId, $client->account_id, $accountGatewayToken->id)->firstOrFail();
|
||||||
|
$paymentMethod->account_gateway_token->default_payment_method_id = $paymentMethod->id;
|
||||||
|
$paymentMethod->account_gateway_token->save();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createToken($gateway, $details, $accountGateway, $client, $contactId, &$customerReference = null, &$paymentMethod = null)
|
||||||
|
{
|
||||||
|
$customerReference = $client->getGatewayToken($accountGateway, $accountGatewayToken/* return paramenter */);
|
||||||
|
|
||||||
if ($customerReference) {
|
if ($customerReference) {
|
||||||
$details['customerReference'] = $customerReference;
|
$details['customerReference'] = $customerReference;
|
||||||
|
|
||||||
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
|
if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
|
||||||
$customerResponse = $gateway->fetchCustomer(array('customerReference'=>$customerReference))->send();
|
$customerResponse = $gateway->fetchCustomer(array('customerReference' => $customerReference))->send();
|
||||||
|
|
||||||
if (!$customerResponse->isSuccessful()){
|
if (!$customerResponse->isSuccessful()) {
|
||||||
$customerReference = null; // The customer might not exist anymore
|
$customerReference = null; // The customer might not exist anymore
|
||||||
}
|
}
|
||||||
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
|
} elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
|
||||||
$customer = $gateway->findCustomer($customerReference)->send()->getData();
|
$customer = $gateway->findCustomer($customerReference)->send()->getData();
|
||||||
|
|
||||||
if (!($customer instanceof \Braintree\Customer)){
|
if (!($customer instanceof \Braintree\Customer)) {
|
||||||
$customerReference = null; // The customer might not exist anymore
|
$customerReference = null; // The customer might not exist anymore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,6 +384,9 @@ class PaymentService extends BaseService
|
|||||||
|
|
||||||
$token->token = $customerReference;
|
$token->token = $customerReference;
|
||||||
$token->save();
|
$token->save();
|
||||||
|
|
||||||
|
$paymentMethod = $this->createPaymentMethodFromGatewayResponse($tokenResponse, $accountGateway, $accountGatewayToken, $contactId);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->lastError = $tokenResponse->getMessage();
|
$this->lastError = $tokenResponse->getMessage();
|
||||||
}
|
}
|
||||||
@ -454,6 +394,104 @@ class PaymentService extends BaseService
|
|||||||
return $sourceReference;
|
return $sourceReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function convertPaymentMethodFromStripe($source, $accountGatewayToken = null, $paymentMethod = null) {
|
||||||
|
// Creating a new one or updating an existing one
|
||||||
|
if (!$paymentMethod) {
|
||||||
|
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->last4 = $source['last4'];
|
||||||
|
$paymentMethod->source_reference = $source['id'];
|
||||||
|
|
||||||
|
if ($source['object'] == 'bank_account') {
|
||||||
|
$paymentMethod->routing_number = $source['routing_number'];
|
||||||
|
$paymentMethod->payment_type_id = PAYMENT_TYPE_ACH;
|
||||||
|
$paymentMethod->status = $source['status'];
|
||||||
|
$currency = Cache::get('currencies')->where('code', strtoupper($source['currency']))->first();
|
||||||
|
if ($currency) {
|
||||||
|
$paymentMethod->currency_id = $currency->id;
|
||||||
|
$paymentMethod->setRelation('currency', $currency);
|
||||||
|
}
|
||||||
|
} elseif ($source['object'] == 'card') {
|
||||||
|
$paymentMethod->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-00';
|
||||||
|
$paymentMethod->payment_type_id = $this->parseCardType($source['brand']);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
|
||||||
|
|
||||||
|
return $paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function convertPaymentMethodFromBraintree($source, $accountGatewayToken = null, $paymentMethod = null) {
|
||||||
|
// Creating a new one or updating an existing one
|
||||||
|
if (!$paymentMethod) {
|
||||||
|
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($source instanceof \Braintree\CreditCard) {
|
||||||
|
$paymentMethod->payment_type_id = $this->parseCardType($source->cardType);
|
||||||
|
$paymentMethod->last4 = $source->last4;
|
||||||
|
$paymentMethod->expiration = $source->expirationYear . '-' . $source->expirationMonth . '-00';
|
||||||
|
} elseif ($source instanceof \Braintree\PayPalAccount) {
|
||||||
|
$paymentMethod->email = $source->email;
|
||||||
|
$paymentMethod->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
|
||||||
|
|
||||||
|
$paymentMethod->source_reference = $source->token;
|
||||||
|
|
||||||
|
return $paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null) {
|
||||||
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
|
$data = $gatewayResponse->getData();
|
||||||
|
if(!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) {
|
||||||
|
$source = $data;
|
||||||
|
} else {
|
||||||
|
$source = !empty($data['source']) ? $data['source'] : $data['card'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($source) {
|
||||||
|
$paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken);
|
||||||
|
}
|
||||||
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
|
$paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
|
||||||
|
|
||||||
|
$transaction = $sourceResponse->getData()->transaction;
|
||||||
|
if ($transaction->paymentInstrumentType == 'credit_card') {
|
||||||
|
$card = $transaction->creditCardDetails;
|
||||||
|
$paymentMethod->last4 = $card->last4;
|
||||||
|
$paymentMethod->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
|
||||||
|
$paymentMethod->payment_type_id = $this->parseCardType($card->cardType);
|
||||||
|
} elseif ($transaction->paymentInstrumentType == 'paypal_account') {
|
||||||
|
$paymentMethod->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
|
||||||
|
$paymentMethod->email = $transaction->paypalDetails->payerEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($paymentMethod) && $accountGatewayToken && $contactId) {
|
||||||
|
$paymentMethod->account_gateway_token_id = $accountGatewayToken->id;
|
||||||
|
$paymentMethod->account_id = $accountGatewayToken->account_id;
|
||||||
|
$paymentMethod->contact_id = $contactId;
|
||||||
|
$paymentMethod->save();
|
||||||
|
|
||||||
|
if (!$paymentMethod->account_gateway_token->default_payment_method_id) {
|
||||||
|
$paymentMethod->account_gateway_token->default_payment_method_id = $paymentMethod->id;
|
||||||
|
$paymentMethod->account_gateway_token->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $paymentMethod;
|
||||||
|
}
|
||||||
|
|
||||||
public function getCheckoutComToken($invitation)
|
public function getCheckoutComToken($invitation)
|
||||||
{
|
{
|
||||||
$token = false;
|
$token = false;
|
||||||
@ -490,7 +528,7 @@ class PaymentService extends BaseService
|
|||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createPayment($invitation, $accountGateway, $ref, $payerId = null, $paymentDetails = null, $purchaseResponse = null)
|
public function createPayment($invitation, $accountGateway, $ref, $payerId = null, $paymentDetails = null, $paymentMethod = null, $purchaseResponse = null)
|
||||||
{
|
{
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
|
||||||
@ -551,6 +589,10 @@ class PaymentService extends BaseService
|
|||||||
$payment->payer_id = $payerId;
|
$payment->payer_id = $payerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($paymentMethod) {
|
||||||
|
$payment->payment_method_id = $paymentMethod->id;
|
||||||
|
}
|
||||||
|
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
// enable pro plan for hosted users
|
// enable pro plan for hosted users
|
||||||
@ -665,28 +707,28 @@ class PaymentService extends BaseService
|
|||||||
public function autoBillInvoice($invoice)
|
public function autoBillInvoice($invoice)
|
||||||
{
|
{
|
||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $invoice->account;
|
|
||||||
$invitation = $invoice->invitations->first();
|
|
||||||
$accountGateway = $account->getTokenGateway();
|
|
||||||
$token = $client->getGatewayToken();
|
|
||||||
|
|
||||||
if (!$invitation || !$accountGateway || !$token) {
|
// Make sure we've migrated in data from Stripe
|
||||||
|
$this->getClientPaymentMethods($client);
|
||||||
|
|
||||||
|
$invitation = $invoice->invitations->first();
|
||||||
|
$token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
|
||||||
|
$defaultPaymentMethod = $accountGatewayToken->default_payment_method;
|
||||||
|
|
||||||
|
if (!$invitation || !$token || !$defaultPaymentMethod) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup the gateway/payment info
|
// setup the gateway/payment info
|
||||||
$gateway = $this->createGateway($accountGateway);
|
$gateway = $this->createGateway($accountGateway);
|
||||||
$details = $this->getPaymentDetails($invitation, $accountGateway);
|
$details = $this->getPaymentDetails($invitation, $accountGateway);
|
||||||
$details['customerReference'] = $token;
|
|
||||||
|
|
||||||
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
|
||||||
$details['customerReference'] = $token;
|
$details['customerReference'] = $token;
|
||||||
|
$details['cardReference'] = $defaultPaymentMethod->sourceReference;
|
||||||
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
|
||||||
$details['customerId'] = $token;
|
$details['customerId'] = $token;
|
||||||
$customer = $gateway->findCustomer($token)->send()->getData();
|
$details['paymentMethodToken'] = $defaultPaymentMethod->sourceReference;
|
||||||
$defaultPaymentMethod = $customer->defaultPaymentMethod();
|
|
||||||
$details['paymentMethodToken'] = $defaultPaymentMethod->token;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// submit purchase/get response
|
// submit purchase/get response
|
||||||
@ -694,7 +736,7 @@ class PaymentService extends BaseService
|
|||||||
|
|
||||||
if ($response->isSuccessful()) {
|
if ($response->isSuccessful()) {
|
||||||
$ref = $response->getTransactionReference();
|
$ref = $response->getTransactionReference();
|
||||||
return $this->createPayment($invitation, $accountGateway, $ref, null, $details, $response);
|
return $this->createPayment($invitation, $accountGateway, $ref, null, $details, $defaultPaymentMethod, $response);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -761,9 +803,9 @@ class PaymentService extends BaseService
|
|||||||
return $model->email;
|
return $model->email;
|
||||||
}
|
}
|
||||||
} elseif ($model->last4) {
|
} elseif ($model->last4) {
|
||||||
$bankData = PaymentController::getBankData($model->routing_number);
|
$bankData = PaymentMethod::lookupBankData($model->routing_number);
|
||||||
if (is_array($bankData)) {
|
if (is_object($bankData)) {
|
||||||
return $bankData['name'].' •••' . $model->last4;
|
return $bankData->name.' •••' . $model->last4;
|
||||||
} elseif($model->last4) {
|
} elseif($model->last4) {
|
||||||
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
return '<img height="22" src="' . URL::to('/images/credit_cards/ach.png') . '" alt="' . htmlentities($card_type) . '"> •••' . $model->last4;
|
||||||
}
|
}
|
||||||
|
83
database/migrations/2016_05_10_144219_wepay_integration.php
Normal file
83
database/migrations/2016_05_10_144219_wepay_integration.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class WePayIntegration extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('payment_methods', function($table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
$table->unsignedInteger('account_id');
|
||||||
|
$table->unsignedInteger('contact_id')->nullable();
|
||||||
|
$table->unsignedInteger('account_gateway_token_id');
|
||||||
|
$table->unsignedInteger('payment_type_id');
|
||||||
|
$table->string('source_reference');
|
||||||
|
|
||||||
|
$table->unsignedInteger('routing_number')->nullable();
|
||||||
|
$table->smallInteger('last4')->unsigned()->nullable();
|
||||||
|
$table->date('expiration')->nullable();
|
||||||
|
$table->string('email')->nullable();
|
||||||
|
$table->unsignedInteger('currency_id')->nullable();
|
||||||
|
$table->string('status')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
|
||||||
|
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||||
|
$table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade');
|
||||||
|
$table->foreign('account_gateway_token_id')->references('id')->on('account_gateway_tokens');
|
||||||
|
$table->foreign('payment_type_id')->references('id')->on('payment_types');
|
||||||
|
$table->foreign('currency_id')->references('id')->on('currencies');
|
||||||
|
|
||||||
|
$table->unsignedInteger('public_id')->index();
|
||||||
|
$table->unique( array('account_id','public_id') );
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('payments', function($table)
|
||||||
|
{
|
||||||
|
$table->unsignedInteger('payment_method_id')->nullable();
|
||||||
|
$table->foreign('payment_method_id')->references('id')->on('payment_methods');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('account_gateway_tokens', function($table)
|
||||||
|
{
|
||||||
|
$table->unsignedInteger('default_payment_method_id')->nullable();
|
||||||
|
$table->foreign('default_payment_method_id')->references('id')->on('payment_methods');
|
||||||
|
|
||||||
|
$table->boolean('uses_local_payment_methods')->defalut(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
\DB::table('account_gateway_tokens')->update(array('uses_local_payment_methods' => false));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('payments', function($table)
|
||||||
|
{
|
||||||
|
$table->dropForeign('payments_payment_method_id_foreign');
|
||||||
|
$table->dropColumn('payment_method_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('account_gateway_tokens', function($table)
|
||||||
|
{
|
||||||
|
$table->dropForeign('account_gateway_tokens_default_payment_method_id_foreign');
|
||||||
|
$table->dropColumn('default_payment_method_id');
|
||||||
|
$table->dropColumn('uses_local_payment_methods');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::dropIfExists('payment_methods');
|
||||||
|
}
|
||||||
|
}
|
@ -1259,7 +1259,7 @@ $LANG = array(
|
|||||||
'payment_method_set_as_default' => 'Set Autobill payment method.',
|
'payment_method_set_as_default' => 'Set Autobill payment method.',
|
||||||
'activity_41' => ':payment_amount payment (:payment) failed',
|
'activity_41' => ':payment_amount payment (:payment) failed',
|
||||||
'webhook_url' => 'Webhook URL',
|
'webhook_url' => 'Webhook URL',
|
||||||
'stripe_webhook_help' => 'You must :link for ACH payment status to be updated.',
|
'stripe_webhook_help' => 'You must :link.',
|
||||||
'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe',
|
'stripe_webhook_help_link_text' => 'add this URL as an endpoint at Stripe',
|
||||||
'payment_method_error' => 'There was an error adding your payment methd. Please try again later.',
|
'payment_method_error' => 'There was an error adding your payment methd. Please try again later.',
|
||||||
'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice',
|
'notification_invoice_payment_failed_subject' => 'Payment failed for Invoice :invoice',
|
||||||
@ -1286,7 +1286,10 @@ $LANG = array(
|
|||||||
'braintree_paypal_help' => 'You must also :link.',
|
'braintree_paypal_help' => 'You must also :link.',
|
||||||
'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account',
|
'braintree_paypal_help_link_text' => 'link PayPal to your BrainTree account',
|
||||||
'token_billing_braintree_paypal' => 'Save payment details',
|
'token_billing_braintree_paypal' => 'Save payment details',
|
||||||
'add_paypal_account' => 'Add PayPal Account'
|
'add_paypal_account' => 'Add PayPal Account',
|
||||||
|
|
||||||
|
|
||||||
|
'no_payment_method_specified' => 'No payment method specified',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $LANG;
|
return $LANG;
|
||||||
|
@ -97,6 +97,18 @@
|
|||||||
->help(trans('texts.token_billing_help')) !!}
|
->help(trans('texts.token_billing_help')) !!}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if ($gateway->id == GATEWAY_STRIPE)
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-lg-4 col-sm-4">{{ trans('texts.webhook_url') }}</label>
|
||||||
|
<div class="col-lg-8 col-sm-8 help-block">
|
||||||
|
<input type="text" class="form-control" onfocus="$(this).select()" readonly value="{{ URL::to('/paymenthook/'.$account->account_key.'/'.GATEWAY_STRIPE) }}">
|
||||||
|
<div class="help-block"><strong>{!! trans('texts.stripe_webhook_help', [
|
||||||
|
'link'=>'<a href="https://dashboard.stripe.com/account/webhooks" target="_blank">'.trans('texts.stripe_webhook_help_link_text').'</a>'
|
||||||
|
]) !!}</strong></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if ($gateway->id == GATEWAY_BRAINTREE)
|
@if ($gateway->id == GATEWAY_BRAINTREE)
|
||||||
@if ($account->getGatewayByType(PAYMENT_TYPE_PAYPAL))
|
@if ($account->getGatewayByType(PAYMENT_TYPE_PAYPAL))
|
||||||
{!! Former::checkbox('enable_paypal')
|
{!! Former::checkbox('enable_paypal')
|
||||||
@ -148,15 +160,6 @@
|
|||||||
->text(trans('texts.enable_ach'))
|
->text(trans('texts.enable_ach'))
|
||||||
->help(trans('texts.stripe_ach_help')) !!}
|
->help(trans('texts.stripe_ach_help')) !!}
|
||||||
<div class="stripe-ach-options">
|
<div class="stripe-ach-options">
|
||||||
<div class="form-group">
|
|
||||||
<label class="control-label col-lg-4 col-sm-4">{{ trans('texts.webhook_url') }}</label>
|
|
||||||
<div class="col-lg-8 col-sm-8 help-block">
|
|
||||||
<input type="text" class="form-control" onfocus="$(this).select()" readonly value="{{ URL::to('/paymenthook/'.$account->account_key.'/'.GATEWAY_STRIPE) }}">
|
|
||||||
<div class="help-block"><strong>{!! trans('texts.stripe_webhook_help', [
|
|
||||||
'link'=>'<a href="https://dashboard.stripe.com/account/webhooks" target="_blank">'.trans('texts.stripe_webhook_help_link_text').'</a>'
|
|
||||||
]) !!}</strong></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-8 col-sm-offset-4">
|
<div class="col-sm-8 col-sm-offset-4">
|
||||||
<h4>{{trans('texts.plaid')}}</h4>
|
<h4>{{trans('texts.plaid')}}</h4>
|
||||||
|
@ -53,30 +53,31 @@
|
|||||||
@foreach ($paymentMethods as $paymentMethod)
|
@foreach ($paymentMethods as $paymentMethod)
|
||||||
<div class="payment_method">
|
<div class="payment_method">
|
||||||
<span class="payment_method_img_container">
|
<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)))}}">
|
<img height="22" src="{{URL::to('/images/credit_cards/'.str_replace(' ', '', strtolower($paymentMethod->payment_type->name).'.png'))}}" alt="{{trans("texts.card_" . str_replace(' ', '', strtolower($paymentMethod->payment_type->name)))}}">
|
||||||
</span>
|
</span>
|
||||||
@if(!empty($paymentMethod['last4']))
|
@if(!empty($paymentMethod->last4))
|
||||||
<span class="payment_method_number">•••••{{$paymentMethod['last4']}}</span>
|
<span class="payment_method_number">•••••{{$paymentMethod->last4}}</span>
|
||||||
@endif
|
@endif
|
||||||
|
@if($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH)
|
||||||
@if($paymentMethod['type']->id == PAYMENT_TYPE_ACH)
|
@if($paymentMethod->bank())
|
||||||
{{ $paymentMethod['bank_name'] }}
|
{{ $paymentMethod->bank()->name }}
|
||||||
@if($paymentMethod['status'] == 'new')
|
@endif
|
||||||
<a href="javasript::void" onclick="completeVerification('{{$paymentMethod['id']}}','{{$paymentMethod['currency']->symbol}}')">({{trans('texts.complete_verification')}})</a>
|
@if($paymentMethod->status == PAYMENT_METHOD_STATUS_NEW)
|
||||||
@elseif($paymentMethod['status'] == 'verification_failed')
|
<a href="javasript::void" onclick="completeVerification('{{$paymentMethod->public_id}}','{{$paymentMethod->currency->symbol}}')">({{trans('texts.complete_verification')}})</a>
|
||||||
|
@elseif($paymentMethod->status == PAYMENT_METHOD_STATUS_VERIFICATION_FAILED)
|
||||||
({{trans('texts.verification_failed')}})
|
({{trans('texts.verification_failed')}})
|
||||||
@endif
|
@endif
|
||||||
@elseif($paymentMethod['type']->id == PAYMENT_TYPE_ID_PAYPAL)
|
@elseif($paymentMethod->type_id == PAYMENT_TYPE_ID_PAYPAL)
|
||||||
{{ $paymentMethod['email'] }}
|
{{ $paymentMethod->email }}
|
||||||
@else
|
@else
|
||||||
{!! trans('texts.card_expiration', array('expires'=>Utils::fromSqlDate($paymentMethod['expiration'], false)->format('m/y'))) !!}
|
{!! trans('texts.card_expiration', array('expires'=>Utils::fromSqlDate($paymentMethod->expiration, false)->format('m/y'))) !!}
|
||||||
@endif
|
@endif
|
||||||
@if($paymentMethod['default'])
|
@if($paymentMethod->id == $paymentMethod->account_gateway_token->default_payment_method_id)
|
||||||
({{trans('texts.used_for_auto_bill')}})
|
({{trans('texts.used_for_auto_bill')}})
|
||||||
@elseif($paymentMethod['type']->id != PAYMENT_TYPE_ACH || $paymentMethod['status'] == 'verified')
|
@elseif($paymentMethod->payment_type_id != PAYMENT_TYPE_ACH || $paymentMethod->status == PAYMENT_METHOD_STATUS_VERIFIED)
|
||||||
<a href="#" onclick="setDefault('{{$paymentMethod['id']}}')">({{trans('texts.use_for_auto_bill')}})</a>
|
<a href="#" onclick="setDefault('{{$paymentMethod->public_id}}')">({{trans('texts.use_for_auto_bill')}})</a>
|
||||||
@endif
|
@endif
|
||||||
<a href="javasript::void" class="payment_method_remove" onclick="removePaymentMethod('{{$paymentMethod['id']}}')">×</a>
|
<a href="javasript::void" class="payment_method_remove" onclick="removePaymentMethod('{{$paymentMethod->public_id}}')">×</a>
|
||||||
</div>
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@endif
|
@endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user