diff --git a/app/Constants.php b/app/Constants.php
index 36c480065839..dea9f2936848 100644
--- a/app/Constants.php
+++ b/app/Constants.php
@@ -2,6 +2,7 @@
if (! defined('APP_NAME')) {
define('APP_NAME', env('APP_NAME', 'Invoice Ninja'));
+ define('APP_DOMAIN', env('APP_DOMAIN', 'invoiceninja.com'));
define('CONTACT_EMAIL', env('MAIL_FROM_ADDRESS', env('MAIL_USERNAME')));
define('CONTACT_NAME', env('MAIL_FROM_NAME'));
define('SITE_URL', env('APP_URL'));
@@ -431,6 +432,7 @@ if (! defined('APP_NAME')) {
define('GATEWAY_TYPE_SOFORT', 8);
define('GATEWAY_TYPE_SEPA', 9);
define('GATEWAY_TYPE_GOCARDLESS', 10);
+ define('GATEWAY_TYPE_APPLE_PAY', 11);
define('GATEWAY_TYPE_TOKEN', 'token');
define('TEMPLATE_INVOICE', 'invoice');
diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php
index e4b907d33dbe..559840caaa2b 100644
--- a/app/Http/Controllers/AccountGatewayController.php
+++ b/app/Http/Controllers/AccountGatewayController.php
@@ -17,6 +17,7 @@ use Utils;
use Validator;
use View;
use WePay;
+use File;
class AccountGatewayController extends BaseController
{
@@ -297,6 +298,13 @@ class AccountGatewayController extends BaseController
$config->enableSofort = boolval(Input::get('enable_sofort'));
$config->enableSepa = boolval(Input::get('enable_sepa'));
$config->enableBitcoin = boolval(Input::get('enable_bitcoin'));
+ $config->enableApplePay = boolval(Input::get('enable_apple_pay'));
+
+ if ($config->enableApplePay && $uploadedFile = request()->file('apple_merchant_id')) {
+ $config->appleMerchantId = File::get($uploadedFile);
+ } elseif ($oldConfig && ! empty($oldConfig->appleMerchantId)) {
+ $config->appleMerchantId = $oldConfig->appleMerchantId;
+ }
}
if ($gatewayId == GATEWAY_STRIPE || $gatewayId == GATEWAY_WEPAY) {
diff --git a/app/Http/Controllers/OnlinePaymentController.php b/app/Http/Controllers/OnlinePaymentController.php
index 4a490add165e..852f0f7bc1e6 100644
--- a/app/Http/Controllers/OnlinePaymentController.php
+++ b/app/Http/Controllers/OnlinePaymentController.php
@@ -114,10 +114,16 @@ class OnlinePaymentController extends BaseController
*
* @return \Illuminate\Http\RedirectResponse
*/
- public function doPayment(CreateOnlinePaymentRequest $request)
+ public function doPayment(CreateOnlinePaymentRequest $request, $invitationKey, $gatewayTypeAlias = false)
{
$invitation = $request->invitation;
- $gatewayTypeId = Session::get($invitation->id . 'gateway_type');
+
+ if ($gatewayTypeAlias) {
+ $gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
+ } else {
+ $gatewayTypeId = Session::get($invitation->id . 'gateway_type');
+ }
+
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId);
if (! $invitation->invoice->canBePaid() && ! request()->update) {
@@ -184,7 +190,9 @@ class OnlinePaymentController extends BaseController
private function completePurchase($invitation, $isOffsite = false)
{
- if ($redirectUrl = session('redirect_url:' . $invitation->invitation_key)) {
+ if (request()->wantsJson()) {
+ return response()->json(RESULT_SUCCESS);
+ } elseif ($redirectUrl = session('redirect_url:' . $invitation->invitation_key)) {
$separator = strpos($redirectUrl, '?') === false ? '?' : '&';
return redirect()->to($redirectUrl . $separator . 'invoice_id=' . $invitation->invoice->public_id);
@@ -412,4 +420,28 @@ class OnlinePaymentController extends BaseController
return redirect()->to($link);
}
}
+
+ public function showAppleMerchantId()
+ {
+ if (Utils::isNinja()) {
+ $subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST'));
+ $account = Account::whereSubdomain($subdomain)->first();
+ } else {
+ $account = Account::first();
+ }
+
+ if (! $account) {
+ exit("Account not found");
+ }
+
+ $accountGateway = $account->account_gateways()
+ ->whereGatewayId(GATEWAY_STRIPE)->first();
+
+ if (! $account) {
+ exit("Apple merchant id not set");
+ }
+
+ echo $accountGateway->getConfigField('appleMerchantId');
+ exit;
+ }
}
diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php
index 4091667352e4..2ca566196da6 100644
--- a/app/Http/Controllers/TaskController.php
+++ b/app/Http/Controllers/TaskController.php
@@ -308,7 +308,6 @@ class TaskController extends BaseController
}
} else {
$count = $this->taskService->bulk($ids, $action);
-
if (request()->wantsJson()) {
return response()->json($count);
} else {
diff --git a/app/Http/Requests/CreateOnlinePaymentRequest.php b/app/Http/Requests/CreateOnlinePaymentRequest.php
index 1e9910082b9d..387f25c0f84c 100644
--- a/app/Http/Requests/CreateOnlinePaymentRequest.php
+++ b/app/Http/Requests/CreateOnlinePaymentRequest.php
@@ -3,6 +3,7 @@
namespace App\Http\Requests;
use App\Models\Invitation;
+use App\Models\GatewayType;
class CreateOnlinePaymentRequest extends Request
{
@@ -26,7 +27,7 @@ class CreateOnlinePaymentRequest extends Request
$account = $this->invitation->account;
$paymentDriver = $account->paymentDriver($this->invitation, $this->gateway_type);
-
+
return $paymentDriver->rules();
}
@@ -39,7 +40,12 @@ class CreateOnlinePaymentRequest extends Request
->firstOrFail();
$input['invitation'] = $invitation;
- $input['gateway_type'] = session($invitation->id . 'gateway_type');
+
+ if ($gatewayTypeAlias = request()->gateway_type) {
+ $input['gateway_type'] = GatewayType::getIdFromAlias($gatewayTypeAlias);
+ } else {
+ $input['gateway_type'] = session($invitation->id . 'gateway_type');
+ }
$this->replace($input);
diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php
index 10173e56ab78..afab900eee0c 100644
--- a/app/Libraries/Utils.php
+++ b/app/Libraries/Utils.php
@@ -108,6 +108,11 @@ class Utils
return self::getResllerType() ? true : false;
}
+ public static function isRootFolder()
+ {
+ return strlen(preg_replace('/[^\/]/', '', url('/'))) == 2;
+ }
+
public static function clientViewCSS()
{
$account = false;
diff --git a/app/Models/AccountGateway.php b/app/Models/AccountGateway.php
index 5e78f4aca62c..a5757ad7448e 100644
--- a/app/Models/AccountGateway.php
+++ b/app/Models/AccountGateway.php
@@ -136,6 +136,15 @@ class AccountGateway extends EntityModel
return $this->getConfigField('publishableKey');
}
+ public function getAppleMerchantId()
+ {
+ if (! $this->isGateway(GATEWAY_STRIPE)) {
+ return false;
+ }
+
+ return $this->getConfigField('appleMerchantId');
+ }
+
/**
* @return bool
*/
@@ -144,6 +153,14 @@ class AccountGateway extends EntityModel
return ! empty($this->getConfigField('enableAch'));
}
+ /**
+ * @return bool
+ */
+ public function getApplePayEnabled()
+ {
+ return ! empty($this->getConfigField('enableApplePay'));
+ }
+
/**
* @return bool
*/
diff --git a/app/Models/Client.php b/app/Models/Client.php
index 10ef1a1510c9..44c43e378c01 100644
--- a/app/Models/Client.php
+++ b/app/Models/Client.php
@@ -502,6 +502,20 @@ class Client extends EntityModel
return $this->account->currency ? $this->account->currency->code : 'USD';
}
+ public function getCountryCode()
+ {
+ if ($country = $this->country) {
+ return $country->iso_3166_2;
+ }
+
+ if (! $this->account) {
+ $this->load('account');
+ }
+
+ return $this->account->country ? $this->account->country->iso_3166_2 : 'US';
+ }
+
+
/**
* @param $isQuote
*
diff --git a/app/Ninja/PaymentDrivers/StripePaymentDriver.php b/app/Ninja/PaymentDrivers/StripePaymentDriver.php
index 6024b0d0c72f..ae0622238327 100644
--- a/app/Ninja/PaymentDrivers/StripePaymentDriver.php
+++ b/app/Ninja/PaymentDrivers/StripePaymentDriver.php
@@ -53,6 +53,9 @@ class StripePaymentDriver extends BasePaymentDriver
if ($gateway->getAlipayEnabled()) {
$types[] = GATEWAY_TYPE_ALIPAY;
}
+ if ($gateway->getApplePayEnabled()) {
+ $types[] = GATEWAY_TYPE_APPLE_PAY;
+ }
}
return $types;
@@ -67,6 +70,10 @@ class StripePaymentDriver extends BasePaymentDriver
{
$rules = parent::rules();
+ if ($this->isGatewayType(GATEWAY_TYPE_APPLE_PAY)) {
+ return ['sourceToken' => 'required'];
+ }
+
if ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) {
$rules['authorize_ach'] = 'required';
}
@@ -224,7 +231,9 @@ class StripePaymentDriver extends BasePaymentDriver
// For older users the Stripe account may just have the customer token but not the card version
// In that case we'd use GATEWAY_TYPE_TOKEN even though we're creating the credit card
- if ($this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD) || $this->isGatewayType(GATEWAY_TYPE_TOKEN)) {
+ if ($this->isGatewayType(GATEWAY_TYPE_CREDIT_CARD)
+ || $this->isGatewayType(GATEWAY_TYPE_APPLE_PAY)
+ || $this->isGatewayType(GATEWAY_TYPE_TOKEN)) {
$paymentMethod->expiration = $source['exp_year'] . '-' . $source['exp_month'] . '-01';
$paymentMethod->payment_type_id = PaymentType::parseCardType($source['brand']);
} elseif ($this->isGatewayType(GATEWAY_TYPE_BANK_TRANSFER)) {
diff --git a/database/seeds/GatewayTypesSeeder.php b/database/seeds/GatewayTypesSeeder.php
index c7a3075a4cfa..7e4bbf6cb961 100644
--- a/database/seeds/GatewayTypesSeeder.php
+++ b/database/seeds/GatewayTypesSeeder.php
@@ -19,6 +19,7 @@ class GatewayTypesSeeder extends Seeder
['alias' => 'sofort', 'name' => 'Sofort'],
['alias' => 'sepa', 'name' => 'SEPA'],
['alias' => 'gocardless', 'name' => 'GoCardless'],
+ ['alias' => 'apple_pay', 'name' => 'Apple Pay'],
];
foreach ($gateway_types as $gateway_type) {
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index 5534a3965ea2..44f0fccf1b77 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -2558,6 +2558,15 @@ $LANG = array(
'scheduled_report_attached' => 'Your scheduled :type report is attached.',
'scheduled_report_error' => 'Failed to create schedule report',
'invalid_one_time_password' => 'Invalid one time password',
+ 'apple_pay' => 'Apple/Google Pay',
+ 'enable_apple_pay' => 'Accept Apple Pay and Pay with Google',
+ 'requires_subdomain' => 'This payment type requires that a :link.',
+ 'subdomain_is_set' => 'subdomain is set',
+ 'verification_file' => 'Verification File',
+ 'verification_file_missing' => 'The verification file is needed to accept payments.',
+ 'apple_pay_domain' => 'Use :domain
as the domain in :link.',
+ 'apple_pay_not_supported' => 'Sorry, Apple/Google Pay isn\'t supported',
+
);
return $LANG;
diff --git a/resources/views/accounts/account_gateway.blade.php b/resources/views/accounts/account_gateway.blade.php
index 2d1b570c849d..76cdded0d343 100644
--- a/resources/views/accounts/account_gateway.blade.php
+++ b/resources/views/accounts/account_gateway.blade.php
@@ -32,7 +32,9 @@
+ +