diff --git a/.env.example b/.env.example
index 41ce2039f7e5..dd797f50d0ec 100644
--- a/.env.example
+++ b/.env.example
@@ -67,4 +67,12 @@ API_SECRET=password
#MAX_DOCUMENT_SIZE # KB
#MAX_EMAIL_DOCUMENTS_SIZE # Total KB
#MAX_ZIP_DOCUMENTS_SIZE # Total KB (uncompressed)
-#DOCUMENT_PREVIEW_SIZE # Pixels
\ No newline at end of file
+#DOCUMENT_PREVIEW_SIZE # Pixels
+
+WEPAY_CLIENT_ID=
+WEPAY_CLIENT_SECRET=
+WEPAY_AUTO_UPDATE=true # Requires permission from WePay
+WEPAY_ENVIRONMENT=production # production or stage
+
+# See https://www.wepay.com/developer/reference/structures#theme
+WEPAY_THEME={"name":"Invoice Ninja","primary_color":"0b4d78","secondary_color":"0b4d78","background_color":"f8f8f8","button_color":"33b753"}'));
\ No newline at end of file
diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php
index 3abaaadfd78c..be3ee331f403 100644
--- a/app/Http/Controllers/AccountController.php
+++ b/app/Http/Controllers/AccountController.php
@@ -1,5 +1,6 @@
account;
$account->load('account_gateways');
$count = count($account->account_gateways);
+ $trashedCount = AccountGateway::scope($account->id)->withTrashed()->count();
if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) {
if (! $accountGateway->getPublishableStripeKey()) {
@@ -419,10 +421,17 @@ class AccountController extends BaseController
}
}
- if ($count == 0) {
+ if ($trashedCount == 0) {
return Redirect::to('gateways/create');
} else {
+ $switchToWepay = WEPAY_CLIENT_ID && !$account->getGatewayConfig(GATEWAY_WEPAY);
+
+ if ($switchToWepay && $account->token_billing_type_id != TOKEN_BILLING_DISABLED) {
+ $switchToWepay = !$account->getGatewayConfig(GATEWAY_BRAINTREE) && !$account->getGatewayConfig(GATEWAY_STRIPE);
+ }
+
return View::make('accounts.payments', [
+ 'showSwitchToWepay' => $switchToWepay,
'showAdd' => $count < count(Gateway::$paymentTypes),
'title' => trans('texts.online_payments')
]);
diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php
index a4fd57c7e5f4..fef9a511636e 100644
--- a/app/Http/Controllers/AccountGatewayController.php
+++ b/app/Http/Controllers/AccountGatewayController.php
@@ -11,6 +11,7 @@ use Validator;
use stdClass;
use URL;
use Utils;
+use WePay;
use App\Models\Gateway;
use App\Models\Account;
use App\Models\AccountGateway;
@@ -57,7 +58,6 @@ class AccountGatewayController extends BaseController
$data['paymentTypeId'] = $accountGateway->getPaymentType();
$data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
-
return View::make('accounts.account_gateway', $data);
}
@@ -101,35 +101,12 @@ class AccountGatewayController extends BaseController
private function getViewModel($accountGateway = false)
{
$selectedCards = $accountGateway ? $accountGateway->accepted_credit_cards : 0;
- $account = Auth::user()->account;
+ $user = Auth::user();
+ $account =$user->account;
$paymentTypes = [];
foreach (Gateway::$paymentTypes as $type) {
- if ($accountGateway || !$account->getGatewayByType($type)) {
- if ($type == PAYMENT_TYPE_CREDIT_CARD && $account->getGatewayByType(PAYMENT_TYPE_STRIPE)) {
- // Stripe is already handling credit card payments
- continue;
- }
-
- if ($type == PAYMENT_TYPE_STRIPE && $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD)) {
- // Another gateway is already handling credit card payments
- continue;
- }
-
- if ($type == PAYMENT_TYPE_DIRECT_DEBIT && $stripeGateway = $account->getGatewayByType(PAYMENT_TYPE_STRIPE)) {
- if (!empty($stripeGateway->getAchEnabled())) {
- // Stripe is already handling ACH payments
- continue;
- }
- }
-
- if ($type == PAYMENT_TYPE_PAYPAL && $braintreeGateway = $account->getGatewayConfig(GATEWAY_BRAINTREE)) {
- if (!empty($braintreeGateway->getPayPalEnabled())) {
- // PayPal is already enabled
- continue;
- }
- }
-
+ if ($accountGateway || $account->canAddGateway($type)) {
$paymentTypes[$type] = $type == PAYMENT_TYPE_CREDIT_CARD ? trans('texts.other_providers'): trans('texts.'.strtolower($type));
if ($type == PAYMENT_TYPE_BITCOIN) {
@@ -158,7 +135,7 @@ class AccountGatewayController extends BaseController
foreach ($gateways as $gateway) {
$fields = $gateway->getFields();
asort($fields);
- $gateway->fields = $fields;
+ $gateway->fields = $gateway->id == GATEWAY_WEPAY ? [] : $fields;
if ($accountGateway && $accountGateway->gateway_id == $gateway->id) {
$accountGateway->fields = $gateway->fields;
}
@@ -172,6 +149,7 @@ class AccountGatewayController extends BaseController
return [
'paymentTypes' => $paymentTypes,
'account' => $account,
+ 'user' => $user,
'accountGateway' => $accountGateway,
'config' => false,
'gateways' => $gateways,
@@ -188,7 +166,7 @@ class AccountGatewayController extends BaseController
$ids = Input::get('bulk_public_id');
$count = $this->accountGatewayService->bulk($ids, $action);
- Session::flash('message', trans('texts.archived_account_gateway'));
+ Session::flash('message', trans("texts.{$action}d_account_gateway"));
return Redirect::to('settings/' . ACCOUNT_PAYMENTS);
}
@@ -236,14 +214,16 @@ class AccountGatewayController extends BaseController
}
}
- foreach ($fields as $field => $details) {
- if (!in_array($field, $optional)) {
- if (strtolower($gateway->name) == 'beanstream') {
- if (in_array($field, ['merchant_id', 'passCode'])) {
- $rules[$gateway->id.'_'.$field] = 'required';
+ if ($gatewayId != GATEWAY_WEPAY) {
+ foreach ($fields as $field => $details) {
+ if (!in_array($field, $optional)) {
+ if (strtolower($gateway->name) == 'beanstream') {
+ if (in_array($field, ['merchant_id', 'passCode'])) {
+ $rules[$gateway->id . '_' . $field] = 'required';
+ }
+ } else {
+ $rules[$gateway->id . '_' . $field] = 'required';
}
- } else {
- $rules[$gateway->id.'_'.$field] = 'required';
}
}
}
@@ -265,20 +245,32 @@ class AccountGatewayController extends BaseController
} else {
$accountGateway = AccountGateway::createNew();
$accountGateway->gateway_id = $gatewayId;
+
+ if ($gatewayId == GATEWAY_WEPAY) {
+ if(!$this->setupWePay($accountGateway, $wepayResponse)) {
+ return $wepayResponse;
+ }
+ $oldConfig = $accountGateway->getConfig();
+ }
}
$config = new stdClass();
- foreach ($fields as $field => $details) {
- $value = trim(Input::get($gateway->id.'_'.$field));
- // if the new value is masked use the original value
- if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) {
- $value = $oldConfig->$field;
- }
- if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
- // do nothing
- } else {
- $config->$field = $value;
+
+ if ($gatewayId != GATEWAY_WEPAY) {
+ foreach ($fields as $field => $details) {
+ $value = trim(Input::get($gateway->id . '_' . $field));
+ // if the new value is masked use the original value
+ if ($oldConfig && $value && $value === str_repeat('*', strlen($value))) {
+ $value = $oldConfig->$field;
+ }
+ if (!$value && ($field == 'testMode' || $field == 'developerMode')) {
+ // do nothing
+ } else {
+ $config->$field = $value;
+ }
}
+ } elseif($oldConfig) {
+ $config = clone $oldConfig;
}
$publishableKey = Input::get('publishable_key');
@@ -340,16 +332,163 @@ class AccountGatewayController extends BaseController
$account->save();
}
- if ($accountGatewayPublicId) {
- $message = trans('texts.updated_gateway');
+ if(isset($wepayResponse)) {
+ return $wepayResponse;
} else {
- $message = trans('texts.created_gateway');
+ if ($accountGatewayPublicId) {
+ $message = trans('texts.updated_gateway');
+ } else {
+ $message = trans('texts.created_gateway');
+ }
+
+ Session::flash('message', $message);
+ return Redirect::to("gateways/{$accountGateway->public_id}/edit");
}
-
- Session::flash('message', $message);
-
- return Redirect::to("gateways/{$accountGateway->public_id}/edit");
}
}
+ protected function getWePayUpdateUri($accountGateway)
+ {
+ if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
+ return null;
+ }
+
+ $wepay = Utils::setupWePay($accountGateway);
+
+ $update_uri_data = $wepay->request('account/get_update_uri', array(
+ 'account_id' => $accountGateway->getConfig()->accountId,
+ 'mode' => 'iframe',
+ 'redirect_uri' => URL::to('/gateways'),
+ ));
+
+ return $update_uri_data->uri;
+ }
+
+ protected function setupWePay($accountGateway, &$response)
+ {
+ $user = Auth::user();
+ $account = $user->account;
+
+ $validator = Validator::make(Input::all(), array(
+ 'company_name' => 'required',
+ 'description' => 'required',
+ 'tos_agree' => 'required',
+ 'first_name' => 'required',
+ 'last_name' => 'required',
+ 'email' => 'required',
+ ));
+
+ if ($validator->fails()) {
+ return Redirect::to('gateways/create')
+ ->withErrors($validator)
+ ->withInput();
+ }
+
+ try{
+ $wepay = Utils::setupWePay();
+
+ $wepayUser = $wepay->request('user/register/', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'email' => Input::get('email'),
+ 'first_name' => Input::get('first_name'),
+ 'last_name' => Input::get('last_name'),
+ 'original_ip' => \Request::getClientIp(true),
+ 'original_device' => \Request::server('HTTP_USER_AGENT'),
+ 'tos_acceptance_time' => time(),
+ 'redirect_uri' => URL::to('gateways'),
+ 'callback_uri' => URL::to(env('WEBHOOK_PREFIX','').'paymenthook/'.$account->account_key.'/'.GATEWAY_WEPAY),
+ 'scope' => 'manage_accounts,collect_payments,view_user,preapprove_payments,send_money',
+ ));
+
+ $accessToken = $wepayUser->access_token;
+ $accessTokenExpires = $wepayUser->expires_in ? (time() + $wepayUser->expires_in) : null;
+
+ $wepay = new WePay($accessToken);
+
+ $wepayAccount = $wepay->request('account/create/', array(
+ 'name' => Input::get('company_name'),
+ 'description' => Input::get('description'),
+ 'theme_object' => json_decode(WEPAY_THEME),
+ ));
+
+ try {
+ $wepay->request('user/send_confirmation/', []);
+ $confirmationRequired = true;
+ } catch(\WePayException $ex){
+ if ($ex->getMessage() == 'This access_token is already approved.') {
+ $confirmationRequired = false;
+ } else {
+ throw $ex;
+ }
+ }
+
+ if (($gateway = $account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD)) || ($gateway = $account->getGatewayByType(PAYMENT_TYPE_STRIPE))) {
+ $gateway->delete();
+ }
+
+ $accountGateway->gateway_id = GATEWAY_WEPAY;
+ $accountGateway->setConfig(array(
+ 'userId' => $wepayUser->user_id,
+ 'accessToken' => $accessToken,
+ 'tokenType' => $wepayUser->token_type,
+ 'tokenExpires' => $accessTokenExpires,
+ 'accountId' => $wepayAccount->account_id,
+ 'testMode' => WEPAY_ENVIRONMENT == WEPAY_STAGE,
+ ));
+
+ if ($confirmationRequired) {
+ Session::flash('message', trans('texts.created_wepay_confirmation_required'));
+ } else {
+ $updateUri = $wepay->request('/account/get_update_uri', array(
+ 'account_id' => $wepayAccount->account_id,
+ 'redirect_uri' => URL::to('gateways'),
+ ));
+
+ $response = Redirect::to($updateUri->uri);
+ return true;
+ }
+
+ $response = Redirect::to("gateways/{$accountGateway->public_id}/edit");
+ return true;
+ } catch (\WePayException $e) {
+ Session::flash('error', $e->getMessage());
+ $response = Redirect::to('gateways/create')
+ ->withInput();
+ return false;
+ }
+ }
+
+
+ public function resendConfirmation($publicId = false)
+ {
+ $accountGateway = AccountGateway::scope($publicId)->firstOrFail();
+
+ if ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ try {
+ $wepay = Utils::setupWePay($accountGateway);
+ $wepay->request('user/send_confirmation', []);
+
+ Session::flash('message', trans('texts.resent_confirmation_email'));
+ } catch (\WePayException $e) {
+ Session::flash('error', $e->getMessage());
+ }
+ }
+
+ return Redirect::to("gateways/{$accountGateway->public_id}/edit");
+ }
+
+ public function switchToWepay()
+ {
+ $data = self::getViewModel();
+ $data['url'] = 'gateways';
+ $data['method'] = 'POST';
+ unset($data['gateways']);
+
+ if ( ! \Request::secure() && ! Utils::isNinjaDev()) {
+ Session::flash('warning', trans('texts.enable_https'));
+ }
+
+ return View::make('accounts.account_gateway_switch_wepay', $data);
+ }
}
diff --git a/app/Http/Controllers/ExpenseApiController.php b/app/Http/Controllers/ExpenseApiController.php
index 725067aa1f2c..6d190c1a48c9 100644
--- a/app/Http/Controllers/ExpenseApiController.php
+++ b/app/Http/Controllers/ExpenseApiController.php
@@ -1,7 +1,7 @@
id.'payment_ref', $invoice->id.'_'.uniqid());
+
if ($paymentType != PAYMENT_TYPE_BRAINTREE_PAYPAL) {
if ($paymentType == PAYMENT_TYPE_TOKEN) {
$useToken = true;
@@ -198,6 +200,10 @@ class PaymentController extends BaseController
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
}
+ if(!empty($data['braintreeClientToken']) || $accountGateway->getPublishableStripeKey()|| $accountGateway->gateway_id == GATEWAY_WEPAY) {
+ $data['tokenize'] = true;
+ }
+
} else {
if ($deviceData = Input::get('details')) {
Session::put($invitation->id . 'device_data', $deviceData);
@@ -405,7 +411,7 @@ class PaymentController extends BaseController
'last_name' => 'required',
];
- if ( ! Input::get('stripeToken') && ! Input::get('payment_method_nonce') && !(Input::get('plaidPublicToken') && Input::get('plaidAccountId'))) {
+ if ( !Input::get('sourceToken') && !(Input::get('plaidPublicToken') && Input::get('plaidAccountId'))) {
$rules = array_merge(
$rules,
[
@@ -433,7 +439,7 @@ class PaymentController extends BaseController
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
- return false;
+ return $validator;
}
if ($requireAddress && $accountGateway->update_address) {
@@ -460,8 +466,6 @@ class PaymentController extends BaseController
$accountGateway = $account->getGatewayByType($paymentType);
$paymentMethod = null;
-
-
if ($useToken) {
if(!$sourceId) {
Session::flash('error', trans('texts.no_payment_method_specified'));
@@ -473,12 +477,13 @@ class PaymentController extends BaseController
}
}
- if (!static::processPaymentClientDetails($client, $accountGateway, $paymentType, $onSite)) {
+ if (($validator = static::processPaymentClientDetails($client, $accountGateway, $paymentType, $onSite)) !== true) {
return Redirect::to('payment/'.$invitationKey)
->withErrors($validator)
->withInput(Request::except('cvv'));
}
+
try {
// For offsite payments send the client's details on file
// If we're using a token then we don't need to send any other data
@@ -492,21 +497,48 @@ class PaymentController extends BaseController
$details = $this->paymentService->getPaymentDetails($invitation, $accountGateway, $data);
// check if we're creating/using a billing token
+ $tokenBillingSupported = false;
+ $sourceReferenceParam = 'token';
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
+ $tokenBillingSupported = true;
+ $customerReferenceParam = 'customerReference';
+
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && !Input::get('authorize_ach')) {
Session::flash('error', trans('texts.ach_authorization_required'));
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
}
+ } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
+ $tokenBillingSupported = true;
+ $sourceReferenceParam = 'paymentMethodToken';
+ $customerReferenceParam = 'customerId';
+ $deviceData = Input::get('device_data');
+ if (!$deviceData) {
+ $deviceData = Session::get($invitation->id . 'device_data');
+ }
+
+ if($deviceData) {
+ $details['device_data'] = $deviceData;
+ }
+ } elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ $tokenBillingSupported = true;
+ $customerReferenceParam = false;
+ }
+
+ if ($tokenBillingSupported) {
if ($useToken) {
- $details['customerReference'] = $customerReference;
- unset($details['token']);
- $details['cardReference'] = $sourceReference;
+ if ($customerReferenceParam) {
+ $details[$customerReferenceParam] = $customerReference;
+ }
+ $details[$sourceReferenceParam] = $sourceReference;
+ unset($details['card']);
} 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 */, $paymentMethod/* return parameter */);
if ($token) {
- $details['token'] = $token;
- $details['customerReference'] = $customerReference;
+ $details[$sourceReferenceParam] = $token;
+ if ($customerReferenceParam) {
+ $details[$customerReferenceParam] = $customerReference;
+ }
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH && empty(Input::get('plaidPublicToken')) ) {
// The user needs to complete verification
@@ -518,36 +550,6 @@ class PaymentController extends BaseController
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
}
}
- } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
- $deviceData = Input::get('device_data');
- if (!$deviceData) {
- $deviceData = Session::get($invitation->id . 'device_data');
- }
-
- if ($token = Input::get('payment_method_nonce')) {
- $details['token'] = $token;
- unset($details['card']);
- }
-
- if ($useToken) {
- $details['customerId'] = $customerReference;
- $details['paymentMethodToken'] = $sourceReference;
- unset($details['token']);
- } 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 */, $paymentMethod/* return parameter */);
- if ($token) {
- $details['paymentMethodToken'] = $token;
- $details['customerId'] = $customerReference;
- unset($details['token']);
- } else {
- $this->error('Token-No-Ref', $this->paymentService->lastError, $accountGateway);
- return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
- }
- }
-
- if($deviceData) {
- $details['deviceData'] = $deviceData;
- }
}
$response = $gateway->purchase($details)->send();
@@ -569,7 +571,7 @@ class PaymentController extends BaseController
if (!$ref) {
$this->error('No-Ref', $response->getMessage(), $accountGateway);
- if ($onSite) {
+ if ($onSite && $paymentType != PAYMENT_TYPE_BRAINTREE_PAYPAL) {
return Redirect::to('payment/'.$invitationKey)
->withInput(Request::except('cvv'));
} else {
@@ -597,7 +599,7 @@ class PaymentController extends BaseController
$response->redirect();
} else {
$this->error('Unknown', $response->getMessage(), $accountGateway);
- if ($onSite) {
+ if ($onSite && $paymentType != PAYMENT_TYPE_BRAINTREE_PAYPAL) {
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
} else {
return Redirect::to('view/'.$invitationKey);
@@ -605,7 +607,7 @@ class PaymentController extends BaseController
}
} catch (\Exception $e) {
$this->error('Uncaught', false, $accountGateway, $e);
- if ($onSite) {
+ if ($onSite && $paymentType != PAYMENT_TYPE_BRAINTREE_PAYPAL) {
return Redirect::to('payment/'.$invitationKey)->withInput(Request::except('cvv'));
} else {
return Redirect::to('view/'.$invitationKey);
@@ -760,7 +762,7 @@ class PaymentController extends BaseController
'message' => $data,
], 500);
} elseif (!empty($data)) {
- return $data;
+ return response()->json($data);
}
return response()->json([
@@ -791,6 +793,8 @@ class PaymentController extends BaseController
switch($gatewayId) {
case GATEWAY_STRIPE:
return $this->handleStripeWebhook($accountGateway);
+ case GATEWAY_WEPAY:
+ return $this->handleWePayWebhook($accountGateway);
default:
return response()->json([
'message' => 'Unsupported gateway',
@@ -798,6 +802,50 @@ class PaymentController extends BaseController
}
}
+ protected function handleWePayWebhook($accountGateway) {
+ $data = Input::all();
+ $accountId = $accountGateway->account_id;
+
+ foreach (array_keys($data) as $key) {
+ if ('_id' == substr($key, -3)) {
+ $objectType = substr($key, 0, -3);
+ $objectId = $data[$key];
+ break;
+ }
+ }
+
+ if (!isset($objectType)) {
+ return response()->json([
+ 'message' => 'Could not find object id parameter',
+ ], 400);
+ }
+
+ if ($objectType == 'credit_card') {
+ $paymentMethod = PaymentMethod::scope(false, $accountId)->where('source_reference', '=', $objectId)->first();
+
+ if (!$paymentMethod) {
+ return array('message' => 'Unknown payment method');
+ }
+
+ $wepay = \Utils::setupWePay($accountGateway);
+ $source = $wepay->request('credit_card', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => intval($objectId),
+ ));
+
+ if ($source->state == 'deleted') {
+ $paymentMethod->delete();
+ } else {
+ $this->paymentService->convertPaymentMethodFromWePay($source, null, $paymentMethod)->save();
+ }
+
+ return array('message' => 'Processed successfully');
+ } else {
+ return array('message' => 'Ignoring event');
+ }
+ }
+
protected function handleStripeWebhook($accountGateway) {
$eventId = Input::get('id');
$eventType= Input::get('type');
diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php
index 95f350dc04f0..79e236d70fc6 100644
--- a/app/Http/Controllers/PublicClientController.php
+++ b/app/Http/Controllers/PublicClientController.php
@@ -16,7 +16,7 @@ use Redirect;
use App\Models\Gateway;
use App\Models\Invitation;
use App\Models\Document;
-use App\ModelsPaymentMethod;
+use App\Models\PaymentMethod;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\ActivityRepository;
@@ -176,8 +176,10 @@ class PublicClientController extends BaseController
$html = '';
if ($paymentMethod->payment_type_id == PAYMENT_TYPE_ACH) {
- if($paymentMethod->bank_data) {
+ if ($paymentMethod->bank_data) {
$html = '
' . htmlentities($paymentMethod->bank_data->name) . '
';
+ } else {
+ $html = '
';
}
} elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_ID_PAYPAL) {
$html = '
';
@@ -860,7 +862,6 @@ class PublicClientController extends BaseController
];
if ($paymentType == PAYMENT_TYPE_STRIPE_ACH) {
-
$data['currencies'] = Cache::get('currencies');
}
@@ -868,6 +869,10 @@ class PublicClientController extends BaseController
$data['braintreeClientToken'] = $this->paymentService->getBraintreeClientToken($account);
}
+ if(!empty($data['braintreeClientToken']) || $accountGateway->getPublishableStripeKey()|| $accountGateway->gateway_id == GATEWAY_WEPAY) {
+ $data['tokenize'] = true;
+ }
+
return View::make('payments.add_paymentmethod', $data);
}
@@ -883,10 +888,12 @@ class PublicClientController extends BaseController
$account = $client->account;
$accountGateway = $account->getGatewayByType($paymentType);
- $sourceToken = $accountGateway->gateway_id == GATEWAY_STRIPE ? Input::get('stripeToken'):Input::get('payment_method_nonce');
+ $sourceToken = Input::get('sourceToken');
- if (!PaymentController::processPaymentClientDetails($client, $accountGateway, $paymentType)) {
- return Redirect::to('client/paymentmethods/add/' . $typeLink)->withInput(Request::except('cvv'));
+ if (($validator = PaymentController::processPaymentClientDetails($client, $accountGateway, $paymentType)) !== true) {
+ return Redirect::to('client/paymentmethods/add/' . $typeLink)
+ ->withErrors($validator)
+ ->withInput(Request::except('cvv'));
}
if ($sourceToken) {
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 47b1a28b1c4e..ca6268b355cb 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -242,6 +242,8 @@ Route::group([
Route::post('/import_csv', 'ImportController@doImportCSV');
Route::resource('gateways', 'AccountGatewayController');
+ Route::get('gateways/{public_id}/resend_confirmation', 'AccountGatewayController@resendConfirmation');
+ Route::get('gateways/switch/wepay', 'AccountGatewayController@switchToWepay');
Route::get('api/gateways', array('as'=>'api.gateways', 'uses'=>'AccountGatewayController@getDatatable'));
Route::post('account_gateways/bulk', 'AccountGatewayController@bulk');
@@ -563,6 +565,10 @@ if (!defined('CONTACT_EMAIL')) {
define('GATEWAY_WEPAY', 60);
define('GATEWAY_BRAINTREE', 61);
+ // The customer exists, but only as a local concept
+ // The remote gateway doesn't understand the concept of customers
+ define('CUSTOMER_REFERENCE_LOCAL', 'local');
+
define('EVENT_CREATE_CLIENT', 1);
define('EVENT_CREATE_INVOICE', 2);
define('EVENT_CREATE_QUOTE', 3);
@@ -704,10 +710,10 @@ if (!defined('CONTACT_EMAIL')) {
define('RESELLER_REVENUE_SHARE', 'A');
define('RESELLER_LIMITED_USERS', 'B');
- define('AUTO_BILL_OFF', 0);
- define('AUTO_BILL_OPT_IN', 1);
- define('AUTO_BILL_OPT_OUT', 2);
- define('AUTO_BILL_ALWAYS', 3);
+ define('AUTO_BILL_OFF', 1);
+ define('AUTO_BILL_OPT_IN', 2);
+ define('AUTO_BILL_OPT_OUT', 3);
+ define('AUTO_BILL_ALWAYS', 4);
// These must be lowercase
define('PLAN_FREE', 'free');
@@ -748,6 +754,15 @@ if (!defined('CONTACT_EMAIL')) {
// Pro users who started paying on or before this date will be able to manage users
define('PRO_USERS_GRANDFATHER_DEADLINE', '2016-05-15');
+ // WePay
+ define('WEPAY_PRODUCTION', 'production');
+ define('WEPAY_STAGE', 'stage');
+ define('WEPAY_CLIENT_ID', env('WEPAY_CLIENT_ID'));
+ define('WEPAY_CLIENT_SECRET', env('WEPAY_CLIENT_SECRET'));
+ define('WEPAY_AUTO_UPDATE', env('WEPAY_AUTO_UPDATE', false));
+ define('WEPAY_ENVIRONMENT', env('WEPAY_ENVIRONMENT', WEPAY_PRODUCTION));
+ define('WEPAY_THEME', env('WEPAY_THEME','{"name":"Invoice Ninja","primary_color":"0b4d78","secondary_color":"0b4d78","background_color":"f8f8f8","button_color":"33b753"}'));
+
$creditCards = [
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php
index 2ed2878a0878..e79d82643917 100644
--- a/app/Libraries/Utils.php
+++ b/app/Libraries/Utils.php
@@ -15,6 +15,7 @@ use Log;
use DateTime;
use stdClass;
use Carbon;
+use WePay;
use App\Models\Currency;
@@ -995,4 +996,21 @@ class Utils
return $url;
}
+
+ public static function setupWePay($accountGateway = null)
+ {
+ if (WePay::getEnvironment() == 'none') {
+ if (WEPAY_ENVIRONMENT == WEPAY_STAGE) {
+ WePay::useStaging(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET);
+ } else {
+ WePay::useProduction(WEPAY_CLIENT_ID, WEPAY_CLIENT_SECRET);
+ }
+ }
+
+ if ($accountGateway) {
+ return new WePay($accountGateway->getConfig()->accessToken);
+ } else {
+ return new WePay(null);
+ }
+ }
}
diff --git a/app/Listeners/ActivityListener.php b/app/Listeners/ActivityListener.php
index 1df8edeb6848..14ba0da50ec9 100644
--- a/app/Listeners/ActivityListener.php
+++ b/app/Listeners/ActivityListener.php
@@ -307,8 +307,8 @@ class ActivityListener
$this->activityRepo->create(
$payment,
ACTIVITY_TYPE_DELETE_PAYMENT,
- $payment->amount,
- $payment->amount * -1
+ $payment->amount - $payment->refunded,
+ ($payment->amount - $payment->refunded) * -1
);
}
@@ -343,8 +343,8 @@ class ActivityListener
$this->activityRepo->create(
$payment,
ACTIVITY_TYPE_FAILED_PAYMENT,
- $payment->amount,
- $payment->amount * -1
+ ($payment->amount - $payment->refunded),
+ ($payment->amount - $payment->refunded) * -1
);
}
@@ -367,8 +367,8 @@ class ActivityListener
$this->activityRepo->create(
$payment,
ACTIVITY_TYPE_RESTORE_PAYMENT,
- $event->fromDeleted ? $payment->amount * -1 : 0,
- $event->fromDeleted ? $payment->amount : 0
+ $event->fromDeleted ? ($payment->amount - $payment->refunded) * -1 : 0,
+ $event->fromDeleted ? ($payment->amount - $payment->refunded) : 0
);
}
}
diff --git a/app/Models/Account.php b/app/Models/Account.php
index 29a9abbd09be..c489d21b180b 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -1245,6 +1245,8 @@ class Account extends Eloquent
return GATEWAY_STRIPE;
} elseif ($this->isGatewayConfigured(GATEWAY_BRAINTREE)) {
return GATEWAY_BRAINTREE;
+ } elseif ($this->isGatewayConfigured(GATEWAY_WEPAY)) {
+ return GATEWAY_WEPAY;
} else {
return false;
}
@@ -1410,6 +1412,37 @@ class Account extends Eloquent
public function getFontFolders(){
return array_map(function($item){return $item['folder'];}, $this->getFontsData());
}
+
+ public function canAddGateway($type){
+ if($this->getGatewayByType($type)) {
+ return false;
+ }
+ if ($type == PAYMENT_TYPE_CREDIT_CARD && $this->getGatewayByType(PAYMENT_TYPE_STRIPE)) {
+ // Stripe is already handling credit card payments
+ return false;
+ }
+
+ if ($type == PAYMENT_TYPE_STRIPE && $this->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD)) {
+ // Another gateway is already handling credit card payments
+ return false;
+ }
+
+ if ($type == PAYMENT_TYPE_DIRECT_DEBIT && $stripeGateway = $this->getGatewayByType(PAYMENT_TYPE_STRIPE)) {
+ if (!empty($stripeGateway->getAchEnabled())) {
+ // Stripe is already handling ACH payments
+ return false;
+ }
+ }
+
+ if ($type == PAYMENT_TYPE_PAYPAL && $braintreeGateway = $this->getGatewayConfig(GATEWAY_BRAINTREE)) {
+ if (!empty($braintreeGateway->getPayPalEnabled())) {
+ // PayPal is already enabled
+ return false;
+ }
+ }
+
+ return true;
+ }
}
Account::updated(function ($account) {
diff --git a/app/Models/AccountGateway.php b/app/Models/AccountGateway.php
index 6de95e8593cf..0c281856be66 100644
--- a/app/Models/AccountGateway.php
+++ b/app/Models/AccountGateway.php
@@ -77,7 +77,7 @@ class AccountGateway extends EntityModel
return !empty($this->getConfigField('enableAch'));
}
- public function getPayPAlEnabled()
+ public function getPayPalEnabled()
{
return !empty($this->getConfigField('enablePayPal'));
}
diff --git a/app/Models/Payment.php b/app/Models/Payment.php
index 9171c9d22c69..85a10acafbbe 100644
--- a/app/Models/Payment.php
+++ b/app/Models/Payment.php
@@ -167,7 +167,7 @@ class Payment extends EntityModel
return ENTITY_PAYMENT;
}
- public function getBankData()
+ public function getBankDataAttribute()
{
if (!$this->routing_number) {
return null;
diff --git a/app/Models/PaymentMethod.php b/app/Models/PaymentMethod.php
index 07c6d2e19e1f..a2f17b722ae6 100644
--- a/app/Models/PaymentMethod.php
+++ b/app/Models/PaymentMethod.php
@@ -63,7 +63,7 @@ class PaymentMethod extends EntityModel
return $this->hasMany('App\Models\Payments');
}
- public function getBankData()
+ public function getBankDataAttribute()
{
if (!$this->routing_number) {
return null;
diff --git a/app/Ninja/Repositories/AccountGatewayRepository.php b/app/Ninja/Repositories/AccountGatewayRepository.php
index b61f854f2dc5..286c8416a21a 100644
--- a/app/Ninja/Repositories/AccountGatewayRepository.php
+++ b/app/Ninja/Repositories/AccountGatewayRepository.php
@@ -15,10 +15,14 @@ class AccountGatewayRepository extends BaseRepository
public function find($accountId)
{
- return DB::table('account_gateways')
+ $query = DB::table('account_gateways')
->join('gateways', 'gateways.id', '=', 'account_gateways.gateway_id')
- ->where('account_gateways.deleted_at', '=', null)
- ->where('account_gateways.account_id', '=', $accountId)
- ->select('account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at', 'account_gateways.gateway_id');
+ ->where('account_gateways.account_id', '=', $accountId);
+
+ if (!\Session::get('show_trash:gateway')) {
+ $query->where('account_gateways.deleted_at', '=', null);
+ }
+
+ return $query->select('account_gateways.id', 'account_gateways.public_id', 'gateways.name', 'account_gateways.deleted_at', 'account_gateways.gateway_id');
}
}
diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php
index fd493ba16d93..979304ed01a0 100644
--- a/app/Ninja/Repositories/InvoiceRepository.php
+++ b/app/Ninja/Repositories/InvoiceRepository.php
@@ -324,7 +324,7 @@ class InvoiceRepository extends BaseRepository
$invoice->start_date = Utils::toSqlDate($data['start_date']);
$invoice->end_date = Utils::toSqlDate($data['end_date']);
$invoice->client_enable_auto_bill = isset($data['client_enable_auto_bill']) && $data['client_enable_auto_bill'] ? true : false;
- $invoice->auto_bill = isset($data['auto_bill']) ? intval($data['auto_bill']) : 0;
+ $invoice->auto_bill = isset($data['auto_bill']) ? intval($data['auto_bill']) : AUTO_BILL_OFF;
if ($invoice->auto_bill < AUTO_BILL_OFF || $invoice->auto_bill > AUTO_BILL_ALWAYS ) {
$invoice->auto_bill = AUTO_BILL_OFF;
diff --git a/app/Services/AccountGatewayService.php b/app/Services/AccountGatewayService.php
index bd5635e0dd52..a992da5c82c9 100644
--- a/app/Services/AccountGatewayService.php
+++ b/app/Services/AccountGatewayService.php
@@ -2,6 +2,7 @@
use URL;
use App\Models\Gateway;
+use App\Models\AccountGateway;
use App\Services\BaseService;
use App\Ninja\Repositories\AccountGatewayRepository;
@@ -41,7 +42,40 @@ class AccountGatewayService extends BaseService
[
'name',
function ($model) {
- return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
+ if ($model->deleted_at) {
+ return $model->name;
+ } elseif ($model->gateway_id != GATEWAY_WEPAY) {
+ return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml();
+ } else {
+ $accountGateway = AccountGateway::find($model->id);
+ $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
+ $wepayAccountId = $accountGateway->getConfig()->accountId;
+ $linkText = $model->name;
+ $url = $endpoint.'account/'.$wepayAccountId;
+ $wepay = \Utils::setupWepay($accountGateway);
+ $html = link_to($url, $linkText, array('target'=>'_blank'))->toHtml();
+
+ try {
+ $wepayAccount = $wepay->request('/account', array('account_id' => $wepayAccountId));
+ if ($wepayAccount->state == 'action_required') {
+ $updateUri = $wepay->request('/account/get_update_uri', array(
+ 'account_id' => $wepayAccountId,
+ 'redirect_uri' => URL::to('gateways'),
+ ));
+
+ $linkText .= ' ('.trans('texts.action_required').')';
+ $url = $updateUri->uri;
+ $html = "{$linkText}";
+ $model->setupUrl = $url;
+ } elseif ($wepayAccount->state == 'pending') {
+ $linkText .= ' ('.trans('texts.resend_confirmation_email').')';
+ $model->resendConfirmationUrl = $url = URL::to("gateways/{$accountGateway->public_id}/resend_confirmation");
+ $html = link_to($url, $linkText)->toHtml();
+ }
+ } catch(\WePayException $ex){}
+
+ return $html;
+ }
}
],
[
@@ -57,9 +91,41 @@ class AccountGatewayService extends BaseService
{
return [
[
+ uctrans('texts.resend_confirmation_email'),
+ function ($model) {
+ return $model->resendConfirmationUrl;
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->resendConfirmationUrl);
+ }
+ ], [
+ uctrans('texts.finish_setup'),
+ function ($model) {
+ return $model->setupUrl;
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY && !empty($model->setupUrl);
+ }
+ ] , [
uctrans('texts.edit_gateway'),
function ($model) {
return URL::to("gateways/{$model->public_id}/edit");
+ },
+ function($model) {
+ return !$model->deleted_at;
+ }
+ ], [
+ uctrans('texts.manage_wepay_account'),
+ function ($model) {
+ $accountGateway = AccountGateway::find($model->id);
+ $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/';
+ return array(
+ 'url' => $endpoint.'account/'.$accountGateway->getConfig()->accountId,
+ 'attributes' => 'target="_blank"'
+ );
+ },
+ function($model) {
+ return !$model->deleted_at && $model->gateway_id == GATEWAY_WEPAY;
}
]
];
diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php
index 3d9001a095b7..df4c9d93d55d 100644
--- a/app/Services/DatatableService.php
+++ b/app/Services/DatatableService.php
@@ -60,11 +60,7 @@ class DatatableService
$str .= '';
}
- $str .= '
-
-
';
+ if (!empty($dropdown_contents)) {
+ $str .= '
+
+ ';
+ }
+
+ return $str.'
';
});
}
diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php
index b97bbbd67de4..d1a0a29a7154 100644
--- a/app/Services/PaymentService.php
+++ b/app/Services/PaymentService.php
@@ -9,6 +9,7 @@ use Cache;
use Omnipay;
use Session;
use CreditCard;
+use WePay;
use App\Models\Payment;
use App\Models\PaymentMethod;
use App\Models\Account;
@@ -30,7 +31,8 @@ class PaymentService extends BaseService
protected static $refundableGateways = array(
GATEWAY_STRIPE,
- GATEWAY_BRAINTREE
+ GATEWAY_BRAINTREE,
+ GATEWAY_WEPAY,
);
public function __construct(PaymentRepository $paymentRepo, AccountRepository $accountRepo, DatatableService $datatableService)
@@ -95,9 +97,9 @@ class PaymentService extends BaseService
$data['ButtonSource'] = 'InvoiceNinja_SP';
};
- if ($input && $accountGateway->isGateway(GATEWAY_STRIPE)) {
- if (!empty($input['stripeToken'])) {
- $data['token'] = $input['stripeToken'];
+ if ($input) {
+ if (!empty($input['sourceToken'])) {
+ $data['token'] = $input['sourceToken'];
unset($data['card']);
} elseif (!empty($input['plaidPublicToken'])) {
$data['plaidPublicToken'] = $input['plaidPublicToken'];
@@ -106,6 +108,10 @@ class PaymentService extends BaseService
}
}
+ if ($accountGateway->isGateway(GATEWAY_WEPAY) && $transactionId = Session::get($invitation->id.'payment_ref')) {
+ $data['transaction_id'] = $transactionId;
+ }
+
return $data;
}
@@ -125,7 +131,7 @@ class PaymentService extends BaseService
$data['cvv'] = $input['cvv'];
}
- if (isset($input['country_id'])) {
+ if (isset($input['address1'])) {
$country = Country::find($input['country_id']);
$data = array_merge($data, [
@@ -216,7 +222,7 @@ class PaymentService extends BaseService
public function verifyClientPaymentMethod($client, $publicId, $amount1, $amount2)
{
- $token = $client->getGatewayToken($accountGateway);
+ $token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
if ($accountGateway->gateway_id != GATEWAY_STRIPE) {
return 'Unsupported gateway';
}
@@ -232,15 +238,18 @@ class PaymentService extends BaseService
'amounts[]=' . intval($amount1) . '&amounts[]=' . intval($amount2)
);
- if (!is_string($result)) {
- $paymentMethod->status = PAYMENT_METHOD_STATUS_VERIFIED;
- $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();
- }
+ if (is_string($result)) {
+ return $result;
}
+
+ $paymentMethod->status = PAYMENT_METHOD_STATUS_VERIFIED;
+ $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 true;
}
@@ -266,6 +275,17 @@ class PaymentService extends BaseService
if (!$response->isSuccessful()) {
return $response->getMessage();
}
+ } elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ try {
+ $wepay = Utils::setupWePay($accountGateway);
+ $wepay->request('/credit_card/delete', [
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => intval($paymentMethod->source_reference),
+ ]);
+ } catch (\WePayException $ex){
+ return $ex->getMessage();
+ }
}
$paymentMethod->delete();
@@ -291,16 +311,16 @@ class PaymentService extends BaseService
{
$customerReference = $client->getGatewayToken($accountGateway, $accountGatewayToken/* return paramenter */);
- if ($customerReference) {
+ if ($customerReference && $customerReference != CUSTOMER_REFERENCE_LOCAL) {
$details['customerReference'] = $customerReference;
- if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
+ if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$customerResponse = $gateway->fetchCustomer(array('customerReference' => $customerReference))->send();
if (!$customerResponse->isSuccessful()) {
$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();
if (!($customer instanceof \Braintree\Customer)) {
@@ -309,7 +329,7 @@ class PaymentService extends BaseService
}
}
- if ($accountGateway->gateway->id == GATEWAY_STRIPE) {
+ if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
if (!empty($details['plaidPublicToken'])) {
$plaidResult = $this->getPlaidToken($accountGateway, $details['plaidPublicToken'], $details['plaidAccountId']);
@@ -355,7 +375,7 @@ class PaymentService extends BaseService
return;
}
}
- } elseif ($accountGateway->gateway->id == GATEWAY_BRAINTREE) {
+ } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
if (!$customerReference) {
$tokenResponse = $gateway->createCustomer(array('customerData' => array()))->send();
if ($tokenResponse->isSuccessful()) {
@@ -377,6 +397,38 @@ class PaymentService extends BaseService
return;
}
}
+ } elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ $wepay = Utils::setupWePay($accountGateway);
+
+ try {
+ $wepay->request('credit_card/authorize', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => intval($details['token']),
+ ));
+
+ // Update the callback uri and get the card details
+ $wepay->request('credit_card/modify', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => intval($details['token']),
+ 'auto_update' => WEPAY_AUTO_UPDATE,
+ 'callback_uri' => URL::to(env('WEBHOOK_PREFIX','').'paymenthook/'.$client->account->account_key.'/'.GATEWAY_WEPAY),
+ ));
+ $tokenResponse = $wepay->request('credit_card', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => intval($details['token']),
+ ));
+
+ $customerReference = CUSTOMER_REFERENCE_LOCAL;
+ $sourceReference = $details['token'];
+ } catch (\WePayException $ex) {
+ $this->lastError = $ex->getMessage();
+ return;
+ }
+ } else {
+ return null;
}
if ($customerReference) {
@@ -394,7 +446,7 @@ class PaymentService extends BaseService
$accountGatewayToken->token = $customerReference;
$accountGatewayToken->save();
- $paymentMethod = $this->createPaymentMethodFromGatewayResponse($tokenResponse, $accountGateway, $accountGatewayToken, $contactId);
+ $paymentMethod = $this->convertPaymentMethodFromGatewayResponse($tokenResponse, $accountGateway, $accountGatewayToken, $contactId);
} else {
$this->lastError = $tokenResponse->getMessage();
@@ -422,7 +474,7 @@ class PaymentService extends BaseService
$paymentMethod->setRelation('currency', $currency);
}
} elseif ($source['object'] == 'card') {
- $paymentMethod->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-00';
+ $paymentMethod->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-01';
$paymentMethod->payment_type_id = $this->parseCardType($source['brand']);
} else {
return null;
@@ -442,7 +494,7 @@ class PaymentService extends BaseService
if ($source instanceof \Braintree\CreditCard) {
$paymentMethod->payment_type_id = $this->parseCardType($source->cardType);
$paymentMethod->last4 = $source->last4;
- $paymentMethod->expiration = $source->expirationYear . '-' . $source->expirationMonth . '-00';
+ $paymentMethod->expiration = $source->expirationYear . '-' . $source->expirationMonth . '-01';
} elseif ($source instanceof \Braintree\PayPalAccount) {
$paymentMethod->email = $source->email;
$paymentMethod->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
@@ -456,8 +508,24 @@ class PaymentService extends BaseService
return $paymentMethod;
}
+
+ public function convertPaymentMethodFromWePay($source, $accountGatewayToken = null, $paymentMethod = null) {
+ // Creating a new one or updating an existing one
+ if (!$paymentMethod) {
+ $paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
+ }
+
+ $paymentMethod->payment_type_id = $this->parseCardType($source->credit_card_name);
+ $paymentMethod->last4 = $source->last_four;
+ $paymentMethod->expiration = $source->expiration_year . '-' . $source->expiration_month . '-01';
+ $paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
+
+ $paymentMethod->source_reference = $source->credit_card_id;
+
+ return $paymentMethod;
+ }
- public function createPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null) {
+ public function convertPaymentMethodFromGatewayResponse($gatewayResponse, $accountGateway, $accountGatewayToken = null, $contactId = null, $existingPaymentMethod = null) {
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$data = $gatewayResponse->getData();
if (!empty($data['object']) && ($data['object'] == 'card' || $data['object'] == 'bank_account')) {
@@ -470,7 +538,7 @@ class PaymentService extends BaseService
}
if ($source) {
- $paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken);
+ $paymentMethod = $this->convertPaymentMethodFromStripe($source, $accountGatewayToken, $existingPaymentMethod);
}
} elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
$data = $gatewayResponse->getData();
@@ -478,11 +546,16 @@ class PaymentService extends BaseService
if (!empty($data->transaction)) {
$transaction = $data->transaction;
- $paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
+ if ($existingPaymentMethod) {
+ $paymentMethod = $existingPaymentMethod;
+ } else {
+ $paymentMethod = $accountGatewayToken ? PaymentMethod::createNew($accountGatewayToken) : new PaymentMethod();
+ }
+
if ($transaction->paymentInstrumentType == 'credit_card') {
$card = $transaction->creditCardDetails;
$paymentMethod->last4 = $card->last4;
- $paymentMethod->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
+ $paymentMethod->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-01';
$paymentMethod->payment_type_id = $this->parseCardType($card->cardType);
} elseif ($transaction->paymentInstrumentType == 'paypal_account') {
$paymentMethod->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
@@ -490,9 +563,20 @@ class PaymentService extends BaseService
}
$paymentMethod->setRelation('payment_type', Cache::get('paymentTypes')->find($paymentMethod->payment_type_id));
} elseif (!empty($data->paymentMethod)) {
- $paymentMethod = $this->convertPaymentMethodFromBraintree($data->paymentMethod, $accountGatewayToken);
+ $paymentMethod = $this->convertPaymentMethodFromBraintree($data->paymentMethod, $accountGatewayToken, $existingPaymentMethod);
}
+ } elseif ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ if ($gatewayResponse instanceof \Omnipay\WePay\Message\CustomCheckoutResponse) {
+ $wepay = \Utils::setupWePay($accountGateway);
+ $gatewayResponse = $wepay->request('credit_card', array(
+ 'client_id' => WEPAY_CLIENT_ID,
+ 'client_secret' => WEPAY_CLIENT_SECRET,
+ 'credit_card_id' => $gatewayResponse->getData()['payment_method']['credit_card']['id'],
+ ));
+
+ }
+ $paymentMethod = $this->convertPaymentMethodFromWePay($gatewayResponse, $accountGatewayToken, $existingPaymentMethod);
}
if (!empty($paymentMethod) && $accountGatewayToken && $contactId) {
@@ -566,43 +650,49 @@ class PaymentService extends BaseService
$payment->payment_type_id = $this->detectCardType($card->getNumber());
}
+ $savePaymentMethod = !empty($paymentMethod);
+
+ // This will convert various gateway's formats to a known format
+ $paymentMethod = $this->convertPaymentMethodFromGatewayResponse($purchaseResponse, $accountGateway, null, null, $paymentMethod);
+
+ // If this is a stored payment method, we'll update it with the latest info
+ if ($savePaymentMethod) {
+ $paymentMethod->save();
+ }
+
if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
$data = $purchaseResponse->getData();
- $source = !empty($data['source'])?$data['source']:$data['card'];
-
$payment->payment_status_id = $data['status'] == 'succeeded' ? PAYMENT_STATUS_COMPLETED : PAYMENT_STATUS_PENDING;
-
- if ($source) {
- $payment->last4 = $source['last4'];
-
- if ($source['object'] == 'bank_account') {
- $payment->routing_number = $source['routing_number'];
- $payment->payment_type_id = PAYMENT_TYPE_ACH;
- }
- else{
- $payment->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-00';
- $payment->payment_type_id = $this->parseCardType($source['brand']);
- }
- }
- } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
- $transaction = $purchaseResponse->getData()->transaction;
- if ($transaction->paymentInstrumentType == 'credit_card') {
- $card = $transaction->creditCardDetails;
- $payment->last4 = $card->last4;
- $payment->expiration = $card->expirationYear . '-' . $card->expirationMonth . '-00';
- $payment->payment_type_id = $this->parseCardType($card->cardType);
- } elseif ($transaction->paymentInstrumentType == 'paypal_account') {
- $payment->payment_type_id = PAYMENT_TYPE_ID_PAYPAL;
- $payment->email = $transaction->paypalDetails->payerEmail;
- }
- }
-
- if ($payerId) {
- $payment->payer_id = $payerId;
}
if ($paymentMethod) {
- $payment->payment_method_id = $paymentMethod->id;
+ if ($paymentMethod->last4) {
+ $payment->last4 = $paymentMethod->last4;
+ }
+
+ if ($paymentMethod->expiration) {
+ $payment->expiration = $paymentMethod->expiration;
+ }
+
+ if ($paymentMethod->routing_number) {
+ $payment->routing_number = $paymentMethod->routing_number;
+ }
+
+ if ($paymentMethod->payment_type_id) {
+ $payment->payment_type_id = $paymentMethod->payment_type_id;
+ }
+
+ if ($paymentMethod->email) {
+ $payment->email = $paymentMethod->email;
+ }
+
+ if ($payerId) {
+ $payment->payer_id = $payerId;
+ }
+
+ if ($savePaymentMethod) {
+ $payment->payment_method_id = $paymentMethod->id;
+ }
}
$payment->save();
@@ -665,20 +755,29 @@ class PaymentService extends BaseService
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
+ 'visa' => PAYMENT_TYPE_VISA,
+ 'americanexpress' => PAYMENT_TYPE_AMERICAN_EXPRESS,
+ 'amex' => PAYMENT_TYPE_AMERICAN_EXPRESS,
+ 'mastercard' => PAYMENT_TYPE_MASTERCARD,
+ 'discover' => PAYMENT_TYPE_DISCOVER,
+ 'jcb' => PAYMENT_TYPE_JCB,
+ 'dinersclub' => PAYMENT_TYPE_DINERS,
+ 'carteblanche' => PAYMENT_TYPE_CARTE_BLANCHE,
+ 'chinaunionpay' => PAYMENT_TYPE_UNIONPAY,
+ 'unionpay' => PAYMENT_TYPE_UNIONPAY,
+ 'laser' => PAYMENT_TYPE_LASER,
+ 'maestro' => PAYMENT_TYPE_MAESTRO,
+ 'solo' => PAYMENT_TYPE_SOLO,
+ 'switch' => PAYMENT_TYPE_SWITCH
);
+ $cardName = strtolower(str_replace(array(' ', '-', '_'), '', $cardName));
+
+ if (empty($cardTypes[$cardName]) && 1 == preg_match('/^('.implode('|', array_keys($cardTypes)).')/', $cardName, $matches)) {
+ // Some gateways return extra stuff after the card name
+ $cardName = $matches[1];
+ }
+
if (!empty($cardTypes[$cardName])) {
return $cardTypes[$cardName];
} else {
@@ -725,6 +824,11 @@ class PaymentService extends BaseService
$invitation = $invoice->invitations->first();
$token = $client->getGatewayToken($accountGateway/* return parameter */, $accountGatewayToken/* return parameter */);
+
+ if (!$accountGatewayToken) {
+ return false;
+ }
+
$defaultPaymentMethod = $accountGatewayToken->default_payment_method;
if (!$invitation || !$token || !$defaultPaymentMethod) {
@@ -736,10 +840,9 @@ class PaymentService extends BaseService
$details = $this->getPaymentDetails($invitation, $accountGateway);
$details['customerReference'] = $token;
- if ($accountGateway->gateway_id == GATEWAY_STRIPE) {
- $details['cardReference'] = $defaultPaymentMethod->source_reference;
- } elseif ($accountGateway->gateway_id == GATEWAY_BRAINTREE) {
- $details['paymentMethodToken'] = $defaultPaymentMethod->source_reference;
+ $details['token'] = $defaultPaymentMethod->source_reference;
+ if ($accountGateway->gateway_id == GATEWAY_WEPAY) {
+ $details['transaction_id'] = 'autobill_'.$invoice->id;
}
// submit purchase/get response
@@ -948,41 +1051,76 @@ class PaymentService extends BaseService
if ($payment->payment_type_id != PAYMENT_TYPE_CREDIT) {
$gateway = $this->createGateway($accountGateway);
- $refund = $gateway->refund(array(
- 'transactionReference' => $payment->transaction_reference,
- 'amount' => $amount,
- ));
- $response = $refund->send();
-
- if ($response->isSuccessful()) {
- $payment->recordRefund($amount);
+
+ if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
+ $refund = $gateway->refund(array(
+ 'transactionReference' => $payment->transaction_reference,
+ 'amount' => $amount,
+ ));
+ $response = $refund->send();
+
+ if ($response->isSuccessful()) {
+ $payment->recordRefund($amount);
+ } else {
+ $data = $response->getData();
+
+ if ($data instanceof \Braintree\Result\Error) {
+ $error = $data->errors->deepAll()[0];
+ if ($error && $error->code == 91506) {
+ if ($amount == $payment->amount) {
+ // This is an unsettled transaction; try to void it
+ $void = $gateway->void(array(
+ 'transactionReference' => $payment->transaction_reference,
+ ));
+ $response = $void->send();
+
+ if ($response->isSuccessful()) {
+ $payment->markVoided();
+ }
+ } else {
+ $this->error('Unknown', 'Partial refund not allowed for unsettled transactions.', $accountGateway);
+ return false;
+ }
+ }
+ }
+
+ if (!$response->isSuccessful()) {
+ $this->error('Unknown', $response->getMessage(), $accountGateway);
+ return false;
+ }
+ }
} else {
- $data = $response->getData();
+ $wepay = \Utils::setupWePay($accountGateway);
- if ($data instanceof \Braintree\Result\Error) {
- $error = $data->errors->deepAll()[0];
- if ($error && $error->code == 91506) {
+ try {
+ $wepay->request('checkout/refund', array(
+ 'checkout_id' => intval($payment->transaction_reference),
+ 'refund_reason' => 'Refund issued by merchant.',
+ 'amount' => $amount,
+ ));
+ $payment->recordRefund($amount);
+ } catch (\WePayException $ex) {
+ if ($ex->getCode() == 4004) {
if ($amount == $payment->amount) {
- // This is an unsettled transaction; try to void it
- $void = $gateway->void(array(
- 'transactionReference' => $payment->transaction_reference,
- ));
- $response = $void->send();
-
- if ($response->isSuccessful()) {
+ try {
+ // This is an uncaptured transaction; try to cancel it
+ $wepay->request('checkout/cancel', array(
+ 'checkout_id' => intval($payment->transaction_reference),
+ 'cancel_reason' => 'Refund issued by merchant.',
+ ));
$payment->markVoided();
+ } catch (\WePayException $ex) {
+ $this->error('Unknown', $ex->getMessage(), $accountGateway);
}
} else {
$this->error('Unknown', 'Partial refund not allowed for unsettled transactions.', $accountGateway);
return false;
}
+ } else {
+ $this->error('Unknown', $ex->getMessage(), $accountGateway);
}
}
- if (!$response->isSuccessful()) {
- $this->error('Unknown', $response->getMessage(), $accountGateway);
- return false;
- }
}
} else {
$payment->recordRefund($amount);
diff --git a/composer.json b/composer.json
index 01c6a26f51cf..cff2d85bcbba 100644
--- a/composer.json
+++ b/composer.json
@@ -74,7 +74,8 @@
"league/flysystem-rackspace": "~1.0",
"barracudanetworks/archivestream-php": "^1.0",
"omnipay/braintree": "~2.0@dev",
- "gatepay/FedACHdir": "dev-master@dev"
+ "gatepay/FedACHdir": "dev-master@dev",
+ "wepay/php-sdk": "^0.2"
},
"require-dev": {
"phpunit/phpunit": "~4.0",
diff --git a/composer.lock b/composer.lock
index e167cfb38e9c..d694f04f6960 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "hash": "7139e4aedb2ac151079c50ee5c17f93c",
- "content-hash": "a314d6c0a16785dd2395a7fd73cdc76d",
+ "hash": "b2471aea1af5ef67a1379ad95b5138f7",
+ "content-hash": "df30a311df0341933d4ff2c3aa5974a6",
"packages": [
{
"name": "agmscode/omnipay-agms",
@@ -505,7 +505,7 @@
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/e97ed532f09e290b91ff7713b785ed7ab11d0812",
+ "url": "https://api.github.com/repos/barryvdh/laravel-ide-helper/zipball/f7b31bdbdceaaea930c71df20e4180b0b7172b4a",
"reference": "e97ed532f09e290b91ff7713b785ed7ab11d0812",
"shasum": ""
},
@@ -2785,7 +2785,7 @@
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/labs7in0/omnipay-wechat/zipball/40c9f86df6573ad98ae1dd0d29712ccbc789a74e",
+ "url": "https://api.github.com/repos/labs7in0/omnipay-wechat/zipball/c8d80c3b48bae2bab071f283f75b1cd8624ed3c7",
"reference": "40c9f86df6573ad98ae1dd0d29712ccbc789a74e",
"shasum": ""
},
@@ -8057,6 +8057,53 @@
],
"time": "2016-02-25 10:29:59"
},
+ {
+ "name": "wepay/php-sdk",
+ "version": "0.2.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/wepay/PHP-SDK.git",
+ "reference": "31bfcdd97d2c9c33c9c09129638ae31840822182"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/wepay/PHP-SDK/zipball/31bfcdd97d2c9c33c9c09129638ae31840822182",
+ "reference": "31bfcdd97d2c9c33c9c09129638ae31840822182",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "0.2.x-dev"
+ }
+ },
+ "autoload": {
+ "classmap": [
+ "wepay.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "WePay",
+ "email": "api@wepay.com"
+ }
+ ],
+ "description": "WePay APIv2 SDK for PHP",
+ "keywords": [
+ "payment",
+ "sdk",
+ "wepay"
+ ],
+ "time": "2015-08-14 19:42:37"
+ },
{
"name": "wildbit/laravel-postmark-provider",
"version": "3.0.0",
@@ -10024,4 +10071,4 @@
"prefer-lowest": false,
"platform": [],
"platform-dev": []
-}
\ No newline at end of file
+}
diff --git a/database/migrations/2016_04_23_182223_payments_changes.php b/database/migrations/2016_04_23_182223_payments_changes.php
index 1c277d8da6b2..35a1b6134e9b 100644
--- a/database/migrations/2016_04_23_182223_payments_changes.php
+++ b/database/migrations/2016_04_23_182223_payments_changes.php
@@ -78,6 +78,11 @@ class PaymentsChanges extends Migration
->where('auto_bill', '=', 1)
->update(array('client_enable_auto_bill' => 1, 'auto_bill' => AUTO_BILL_OPT_OUT));
+ \DB::table('invoices')
+ ->where('auto_bill', '=', 0)
+ ->where('is_recurring', '=', 1)
+ ->update(array('auto_bill' => AUTO_BILL_OFF));
+
Schema::table('account_gateway_tokens', function($table)
{
@@ -113,11 +118,15 @@ class PaymentsChanges extends Migration
$table->dropColumn('payment_method_id');
});
+ \DB::table('invoices')
+ ->where('auto_bill', '=', AUTO_BILL_OFF)
+ ->update(array('auto_bill' => 0));
+
\DB::table('invoices')
->where(function($query){
$query->where('auto_bill', '=', AUTO_BILL_ALWAYS);
$query->orwhere(function($query){
- $query->where('auto_bill', '!=', AUTO_BILL_OFF);
+ $query->where('auto_bill', '!=', 0);
$query->where('client_enable_auto_bill', '=', 1);
});
})
diff --git a/public/built.js b/public/built.js
index 14f82399435f..06790ce1e6ed 100644
--- a/public/built.js
+++ b/public/built.js
@@ -30933,7 +30933,7 @@ function truncate(string, length){
// Show/hide the 'Select' option in the datalists
function actionListHandler() {
- $('tbody tr').mouseover(function() {
+ $('tbody tr .tr-action').closest('tr').mouseover(function() {
$(this).closest('tr').find('.tr-action').show();
$(this).closest('tr').find('.tr-status').hide();
}).mouseout(function() {
diff --git a/public/js/script.js b/public/js/script.js
index a76e6d37cd0e..a66c48768bb6 100644
--- a/public/js/script.js
+++ b/public/js/script.js
@@ -1042,7 +1042,7 @@ function truncate(string, length){
// Show/hide the 'Select' option in the datalists
function actionListHandler() {
- $('tbody tr').mouseover(function() {
+ $('tbody tr .tr-action').closest('tr').mouseover(function() {
$(this).closest('tr').find('.tr-action').show();
$(this).closest('tr').find('.tr-status').hide();
}).mouseout(function() {
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index 920ff5dd7ca3..681640e2575b 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -1282,6 +1282,26 @@ $LANG = array(
'import_ofx' => 'Import OFX',
'ofx_file' => 'OFX File',
'ofx_parse_failed' => 'Failed to parse OFX file',
+
+ // WePay
+ 'wepay' => 'WePay',
+ 'sign_up_with_wepay' => 'Sign up with WePay',
+ 'use_another_provider' => 'Use another provider',
+ 'company_name' => 'Company Name',
+ 'wepay_company_name_help' => 'This will appear on client\'s credit card statements.',
+ 'wepay_description_help' => 'The purpose of this account.',
+ 'wepay_tos_agree' => 'I agree to the :link.',
+ 'wepay_tos_link_text' => 'WePay Terms of Service',
+ 'resend_confirmation_email' => 'Resend Confirmation Email',
+ 'manage_wepay_account' => 'Manage WePay Account',
+ 'action_required' => 'Action Required',
+ 'finish_setup' => 'Finish Setup',
+ 'created_wepay_confirmation_required' => 'Please check your email and confirm your email address with WePay.',
+ 'switch_to_wepay' => 'Switch to WePay',
+ 'switch' => 'Switch',
+ 'restore_account_gateway' => 'Restore Gateway',
+ 'restored_account_gateway' => 'Successfully restored gateway',
+
);
return $LANG;
diff --git a/resources/views/accounts/account_gateway.blade.php b/resources/views/accounts/account_gateway.blade.php
index ade161f5b65f..155ef6579f69 100644
--- a/resources/views/accounts/account_gateway.blade.php
+++ b/resources/views/accounts/account_gateway.blade.php
@@ -5,15 +5,18 @@
@include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS])
- {!! Former::open($url)->method($method)->rule()->addClass('warn-on-exit') !!}
- {!! Former::populateField('token_billing_type_id', $account->token_billing_type_id) !!}
-
+ @if(!$accountGateway && WEPAY_CLIENT_ID && !$account->getGatewayByType(PAYMENT_TYPE_CREDIT_CARD) && !$account->getGatewayByType(PAYMENT_TYPE_STRIPE))
+ @include('accounts.partials.account_gateway_wepay')
+ @endif
+
{!! trans($title) !!}
+ {!! Former::open($url)->method($method)->rule()->addClass('warn-on-exit') !!}
+ {!! Former::populateField('token_billing_type_id', $account->token_billing_type_id) !!}
@if ($accountGateway)
{!! Former::populateField('gateway_id', $accountGateway->gateway_id) !!}
@@ -91,7 +94,7 @@
{!! Former::text('publishable_key') !!}
@endif
- @if ($gateway->id == GATEWAY_STRIPE || $gateway->id == GATEWAY_BRAINTREE)
+ @if ($gateway->id == GATEWAY_STRIPE || $gateway->id == GATEWAY_BRAINTREE || $gateway->id == GATEWAY_WEPAY)
{!! Former::select('token_billing_type_id')
->options($tokenBillingOptions)
->help(trans('texts.token_billing_help')) !!}
@@ -101,7 +104,7 @@
-
@@ -183,6 +185,7 @@
$countGateways > 0 ? Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/online_payments'))->appendIcon(Icon::create('remove-circle')) : false,
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))) !!}
{!! Former::close() !!}
+
diff --git a/resources/views/accounts/account_gateway_switch_wepay.blade.php b/resources/views/accounts/account_gateway_switch_wepay.blade.php
new file mode 100644
index 000000000000..ae851881bed0
--- /dev/null
+++ b/resources/views/accounts/account_gateway_switch_wepay.blade.php
@@ -0,0 +1,7 @@
+@extends('header')
+
+@section('content')
+ @parent
+ @include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS])
+ @include('accounts.partials.account_gateway_wepay')
+@stop
\ No newline at end of file
diff --git a/resources/views/accounts/partials/account_gateway_wepay.blade.php b/resources/views/accounts/partials/account_gateway_wepay.blade.php
new file mode 100644
index 000000000000..803fc37ed103
--- /dev/null
+++ b/resources/views/accounts/partials/account_gateway_wepay.blade.php
@@ -0,0 +1,59 @@
+{!! Former::open($url)->method($method)->rules(array(
+ 'first_name' => 'required',
+ 'last_name' => 'required',
+ 'email' => 'required',
+ 'description' => 'required',
+ 'company_name' => 'required',
+ 'tos_agree' => 'required',
+ ))->addClass('warn-on-exit') !!}
+{!! Former::populateField('company_name', $account->getDisplayName()) !!}
+{!! Former::populateField('first_name', $user->first_name) !!}
+{!! Former::populateField('last_name', $user->last_name) !!}
+{!! Former::populateField('email', $user->email) !!}
+{!! Former::populateField('show_address', 1) !!}
+{!! Former::populateField('update_address', 1) !!}
+{!! Former::populateField('token_billing_type_id', $account->token_billing_type_id) !!}
+
+
+
{!! trans('texts.online_payments') !!}
+
+
+ {!! Former::text('first_name') !!}
+ {!! Former::text('last_name') !!}
+ {!! Former::text('email') !!}
+ {!! Former::text('company_name')->help('wepay_company_name_help')->maxlength(255) !!}
+ {!! Former::text('description')->help('wepay_description_help') !!}
+ {!! Former::select('token_billing_type_id')
+ ->options($tokenBillingOptions)
+ ->help(trans('texts.token_billing_help')) !!}
+ {!! Former::checkbox('show_address')
+ ->label(trans('texts.billing_address'))
+ ->text(trans('texts.show_address_help'))
+ ->addGroupClass('gateway-option') !!}
+ {!! Former::checkbox('update_address')
+ ->label(' ')
+ ->text(trans('texts.update_address_help'))
+ ->addGroupClass('gateway-option') !!}
+ {!! Former::checkboxes('creditCardTypes[]')
+ ->label('Accepted Credit Cards')
+ ->checkboxes($creditCardTypes)
+ ->class('creditcard-types')
+ ->addGroupClass('gateway-option')
+ !!}
+ {!! Former::checkbox('tos_agree')->label(' ')->text(trans('texts.wepay_tos_agree',
+ ['link'=>'
'.trans('texts.wepay_tos_link_text').'']
+ ))->value('true') !!}
+
+ {!! Button::primary(trans('texts.sign_up_with_wepay'))
+ ->submit()
+ ->large() !!}
+ @if(isset($gateways))
+
+ {{ trans('texts.use_another_provider') }}
+ @endif
+
+
+
+
+
+{!! Former::close() !!}
\ No newline at end of file
diff --git a/resources/views/accounts/payments.blade.php b/resources/views/accounts/payments.blade.php
index d2fcde895200..997190ec4f0a 100644
--- a/resources/views/accounts/payments.blade.php
+++ b/resources/views/accounts/payments.blade.php
@@ -4,6 +4,17 @@
@parent
@include('accounts.nav', ['selected' => ACCOUNT_PAYMENTS])
+ @if ($showSwitchToWepay)
+ {!! Button::success(trans('texts.switch_to_wepay'))
+ ->asLinkTo(URL::to('/gateways/switch/wepay'))
+ ->appendIcon(Icon::create('circle-arrow-up')) !!}
+
+ @endif
+
+
@if ($showAdd)
{!! Button::primary(trans('texts.add_gateway'))
->asLinkTo(URL::to('/gateways/create'))
@@ -28,6 +39,14 @@
@stop
\ No newline at end of file
diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php
index cf399d041253..9deb5322452a 100644
--- a/resources/views/invoices/edit.blade.php
+++ b/resources/views/invoices/edit.blade.php
@@ -166,24 +166,24 @@
@if($account->getTokenGatewayId())
-
+
{!! Former::select('auto_bill')
- ->data_bind("value: auto_bill, valueUpdate: 'afterkeydown', event:{change:function(){if(auto_bill()==1)client_enable_auto_bill(0);if(auto_bill()==2)client_enable_auto_bill(1)}}")
+ ->data_bind("value: auto_bill, valueUpdate: 'afterkeydown', event:{change:function(){if(auto_bill()==".AUTO_BILL_OPT_IN.")client_enable_auto_bill(0);if(auto_bill()==".AUTO_BILL_OPT_OUT.")client_enable_auto_bill(1)}}")
->options([
- 0 => trans('texts.off'),
- 1 => trans('texts.opt_in'),
- 2 => trans('texts.opt_out'),
- 3 => trans('texts.always'),
+ AUTO_BILL_OFF => trans('texts.off'),
+ AUTO_BILL_OPT_IN => trans('texts.opt_in'),
+ AUTO_BILL_OPT_OUT => trans('texts.opt_out'),
+ AUTO_BILL_ALWAYS => trans('texts.always'),
]) !!}
-