mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-09-20 16:31:33 +02:00
Merge branch 'v5-develop' of https://github.com/turbo124/invoiceninja into v5-develop
This commit is contained in:
commit
0e4e088757
@ -1 +1 @@
|
||||
5.2.17
|
||||
5.2.18
|
@ -14,6 +14,7 @@ namespace App\Exceptions;
|
||||
use App\Exceptions\FilePermissionsFailure;
|
||||
use App\Exceptions\InternalPDFFailure;
|
||||
use App\Exceptions\PhantomPDFFailure;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Utils\Ninja;
|
||||
use Exception;
|
||||
use Illuminate\Auth\Access\AuthorizationException;
|
||||
@ -197,6 +198,8 @@ class Handler extends ExceptionHandler
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof GenericPaymentDriverFailure) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
} elseif ($exception instanceof StripeConnectFailure) {
|
||||
return response()->json(['message' => $exception->getMessage()], 400);
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
|
10
app/Exceptions/StripeConnectFailure.php
Normal file
10
app/Exceptions/StripeConnectFailure.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class StripeConnectFailure extends Exception
|
||||
{
|
||||
// ..
|
||||
}
|
@ -795,6 +795,10 @@ class InvoiceController extends BaseController
|
||||
public function downloadPdf($invitation_key)
|
||||
{
|
||||
$invitation = $this->invoice_repo->getInvitationByKey($invitation_key);
|
||||
|
||||
if(!$invitation)
|
||||
return response()->json(["message" => "no record found"], 400);
|
||||
|
||||
$contact = $invitation->contact;
|
||||
$invoice = $invitation->invoice;
|
||||
|
||||
|
@ -14,10 +14,14 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\Util\ImportStripeCustomers;
|
||||
use App\Jobs\Util\StripeUpdatePaymentMethods;
|
||||
use App\Models\Client;
|
||||
use App\Models\CompanyGateway;
|
||||
|
||||
class StripeController extends BaseController
|
||||
{
|
||||
|
||||
private $stripe_keys = ['d14dd26a47cecc30fdd65700bfb67b34', 'd14dd26a37cecc30fdd65700bfb55b23'];
|
||||
|
||||
public function update()
|
||||
{
|
||||
if(auth()->user()->isAdmin())
|
||||
@ -50,4 +54,22 @@ class StripeController extends BaseController
|
||||
return response()->json(['message' => 'Unauthorized'], 403);
|
||||
}
|
||||
|
||||
public function verify()
|
||||
{
|
||||
|
||||
if(auth()->user()->isAdmin())
|
||||
{
|
||||
|
||||
$company_gateway = CompanyGateway::where('company_id', auth()->user()->company()->id)
|
||||
->where('is_deleted',0)
|
||||
->whereIn('gateway_key', $this->stripe_keys)
|
||||
->first();
|
||||
|
||||
return $company_gateway->driver(new Client)->verifyConnect();
|
||||
|
||||
}
|
||||
|
||||
return response()->json(['message' => 'Unauthorized'], 403);
|
||||
|
||||
}
|
||||
}
|
@ -54,6 +54,7 @@ class StoreClientRequest extends Request
|
||||
/* Ensure we have a client name, and that all emails are unique*/
|
||||
//$rules['name'] = 'required|min:1';
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
$rules['contacts'] = 'array';
|
||||
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';
|
||||
$rules['contacts.*.password'] = [
|
||||
'nullable',
|
||||
|
@ -62,6 +62,7 @@ class UpdateClientRequest extends Request
|
||||
$rules['number'] = Rule::unique('clients')->where('company_id', auth()->user()->company()->id)->ignore($this->client->id);
|
||||
|
||||
$rules['settings'] = new ValidClientGroupSettingsRule();
|
||||
$rules['contacts'] = 'array';
|
||||
$rules['contacts.*.email'] = 'bail|nullable|distinct|sometimes|email';
|
||||
$rules['contacts.*.password'] = [
|
||||
'nullable',
|
||||
|
@ -39,6 +39,7 @@ class ClientTransformer extends BaseTransformer
|
||||
'work_phone' => $this->getString( $data, 'client.phone' ),
|
||||
'address1' => $this->getString( $data, 'client.address1' ),
|
||||
'address2' => $this->getString( $data, 'client.address2' ),
|
||||
'postal_code' => $this->getString( $data, 'client.postal_code'),
|
||||
'city' => $this->getString( $data, 'client.city' ),
|
||||
'state' => $this->getString( $data, 'client.state' ),
|
||||
'shipping_address1' => $this->getString( $data, 'client.shipping_address1' ),
|
||||
|
@ -49,6 +49,7 @@ class ImportStripeCustomers implements ShouldQueue
|
||||
MultiDB::setDb($this->company->db);
|
||||
|
||||
$cgs = CompanyGateway::where('company_id', $this->company->id)
|
||||
->where('is_deleted',0)
|
||||
->whereIn('gateway_key', $this->stripe_keys)
|
||||
->get();
|
||||
|
||||
|
76
app/PaymentDrivers/Stripe/Connect/Verify.php
Normal file
76
app/PaymentDrivers/Stripe/Connect/Verify.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
namespace App\PaymentDrivers\Stripe\Connect;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Http\Requests\ClientPortal\PaymentMethod\VerifyPaymentMethodRequest;
|
||||
use App\Http\Requests\Request;
|
||||
use App\Jobs\Mail\NinjaMailerJob;
|
||||
use App\Jobs\Mail\NinjaMailerObject;
|
||||
use App\Jobs\Mail\PaymentFailureMailer;
|
||||
use App\Jobs\Util\SystemLogger;
|
||||
use App\Mail\Gateways\ACHVerificationNotification;
|
||||
use App\Models\ClientGatewayToken;
|
||||
use App\Models\GatewayType;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentType;
|
||||
use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Exception;
|
||||
use Stripe\Customer;
|
||||
use Stripe\Exception\CardException;
|
||||
use Stripe\Exception\InvalidRequestException;
|
||||
|
||||
class Verify
|
||||
{
|
||||
use MakesHash;
|
||||
|
||||
/** @var StripePaymentDriver */
|
||||
|
||||
public $stripe;
|
||||
|
||||
public function __construct(StripePaymentDriver $stripe)
|
||||
{
|
||||
$this->stripe = $stripe;
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->stripe->init();
|
||||
|
||||
if($this->stripe->stripe_connect && strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1)
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
|
||||
$customers = Customer::all([], $this->stripe->stripe_connect_auth);
|
||||
|
||||
$stripe_customers = $this->stripe->company_gateway->client_gateway_tokens->map(function ($cgt){
|
||||
|
||||
$customer = Customer::retrieve($cgt->gateway_customer_reference, $this->stripe->stripe_connect_auth);
|
||||
|
||||
return [
|
||||
'customer' => $cgt->gateway_customer_reference,
|
||||
'record' => $customer
|
||||
];
|
||||
|
||||
});
|
||||
|
||||
$data = [
|
||||
'stripe_customer_count' => count($customers),
|
||||
'stripe_customers' => $stripe_customers,
|
||||
];
|
||||
|
||||
return response()->json($data, 200);
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
|
||||
namespace App\PaymentDrivers\Stripe;
|
||||
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Factory\ClientContactFactory;
|
||||
use App\Factory\ClientFactory;
|
||||
use App\Factory\ClientGatewayTokenFactory;
|
||||
@ -22,6 +23,7 @@ use App\Models\Currency;
|
||||
use App\Models\GatewayType;
|
||||
use App\PaymentDrivers\StripePaymentDriver;
|
||||
use App\PaymentDrivers\Stripe\UpdatePaymentMethods;
|
||||
use App\Utils\Traits\GeneratesCounter;
|
||||
use App\Utils\Traits\MakesHash;
|
||||
use Stripe\Customer;
|
||||
use Stripe\PaymentMethod;
|
||||
@ -29,6 +31,7 @@ use Stripe\PaymentMethod;
|
||||
class ImportCustomers
|
||||
{
|
||||
use MakesHash;
|
||||
use GeneratesCounter;
|
||||
|
||||
/** @var StripePaymentDriver */
|
||||
public $stripe;
|
||||
@ -48,6 +51,9 @@ class ImportCustomers
|
||||
|
||||
$this->update_payment_methods = new UpdatePaymentMethods($this->stripe);
|
||||
|
||||
if(strlen($this->stripe->company_gateway->getConfigField('account_id')) < 1)
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
|
||||
$customers = Customer::all([], $this->stripe->stripe_connect_auth);
|
||||
|
||||
foreach($customers as $customer)
|
||||
@ -120,6 +126,10 @@ class ImportCustomers
|
||||
|
||||
$client->name = property_exists($customer, 'name') ? $customer->name : $customer->email;
|
||||
|
||||
if (!isset($client->number) || empty($client->number)) {
|
||||
$client->number = $this->getNextClientNumber($client);
|
||||
}
|
||||
|
||||
$client->save();
|
||||
|
||||
$contact = ClientContactFactory::create($client->company_id, $client->user_id);
|
||||
|
@ -13,6 +13,7 @@
|
||||
namespace App\PaymentDrivers;
|
||||
|
||||
use App\Exceptions\PaymentFailed;
|
||||
use App\Exceptions\StripeConnectFailure;
|
||||
use App\Factory\PaymentFactory;
|
||||
use App\Http\Requests\Payments\PaymentWebhookRequest;
|
||||
use App\Http\Requests\Request;
|
||||
@ -25,6 +26,7 @@ use App\Models\SystemLog;
|
||||
use App\PaymentDrivers\Stripe\ACH;
|
||||
use App\PaymentDrivers\Stripe\Alipay;
|
||||
use App\PaymentDrivers\Stripe\Charge;
|
||||
use App\PaymentDrivers\Stripe\Connect\Verify;
|
||||
use App\PaymentDrivers\Stripe\CreditCard;
|
||||
use App\PaymentDrivers\Stripe\ImportCustomers;
|
||||
use App\PaymentDrivers\Stripe\SOFORT;
|
||||
@ -86,7 +88,10 @@ class StripePaymentDriver extends BaseDriver
|
||||
{
|
||||
Stripe::setApiKey(config('ninja.ninja_stripe_key'));
|
||||
|
||||
if(strlen($this->company_gateway->getConfigField('account_id')) > 1)
|
||||
$this->stripe_connect_auth = ["stripe_account" => $this->company_gateway->getConfigField('account_id')];
|
||||
else
|
||||
throw new StripeConnectFailure('Stripe Connect has not been configured');
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -533,4 +538,9 @@ class StripePaymentDriver extends BaseDriver
|
||||
//match clients based on the gateway_customer_reference column
|
||||
|
||||
}
|
||||
|
||||
public function verifyConnect()
|
||||
{
|
||||
return (new Verify($this))->run();
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ class HandleReversal extends AbstractService
|
||||
|
||||
/* Generate a credit for the $total_paid amount */
|
||||
$notes = 'Credit for reversal of '.$this->invoice->number;
|
||||
$credit = false;
|
||||
|
||||
if ($total_paid > 0) {
|
||||
|
||||
|
@ -14,8 +14,8 @@ return [
|
||||
'require_https' => env('REQUIRE_HTTPS', true),
|
||||
'app_url' => rtrim(env('APP_URL', ''), '/'),
|
||||
'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
|
||||
'app_version' => '5.2.17',
|
||||
'app_tag' => '5.2.17',
|
||||
'app_version' => '5.2.18',
|
||||
'app_tag' => '5.2.18',
|
||||
'minimum_client_version' => '5.0.16',
|
||||
'terms_version' => '1.0.1',
|
||||
'api_secret' => env('API_SECRET', ''),
|
||||
|
6
public/flutter_service_worker.js
vendored
6
public/flutter_service_worker.js
vendored
@ -29,11 +29,11 @@ const RESOURCES = {
|
||||
"icons/Icon-192.png": "bb1cf5f6982006952211c7c8404ffbed",
|
||||
"icons/Icon-512.png": "0f9aff01367f0a0c69773d25ca16ef35",
|
||||
"favicon.png": "dca91c54388f52eded692718d5a98b8b",
|
||||
"manifest.json": "ce1b79950eb917ea619a0a30da27c6a3",
|
||||
"manifest.json": "ef43d90e57aa7682d7e2cfba2f484a40",
|
||||
"version.json": "46d4015fc9abcefe5371cafcf2084173",
|
||||
"favicon.ico": "51636d3a390451561744c42188ccd628",
|
||||
"main.dart.js": "e9b7d139cde42fcfdf5912f3a609aeaf",
|
||||
"/": "d389ab59423a76b2aaaa683ed382c78e"
|
||||
"main.dart.js": "add7e30c6238e86fc427de122d4afe88",
|
||||
"/": "8053b7209448f6fb8856c36a523c9f66"
|
||||
};
|
||||
|
||||
// The application shell files that are downloaded before a service worker can
|
||||
|
111366
public/main.dart.js
vendored
111366
public/main.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
111902
public/main.foss.dart.js
vendored
111902
public/main.foss.dart.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,7 +5,7 @@
|
||||
"display": "standalone",
|
||||
"background_color": "#0175C2",
|
||||
"theme_color": "#0175C2",
|
||||
"description": "The leading open-source invoicing app",
|
||||
"description": "Invoice Clients, Track Work-Time, Get Paid Online.",
|
||||
"orientation": "portrait-primary",
|
||||
"prefer_related_applications": true,
|
||||
"related_applications": [
|
||||
|
@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<!-- Source: https://github.com/invoiceninja/invoiceninja -->
|
||||
<!-- Version: {{ config('ninja.app_version') }} -->
|
||||
<base href="/">
|
||||
<base href="{{ $_SERVER['REQUEST_URI'] }}">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="google-signin-client_id" content="{{ config('services.google.client_id') }}">
|
||||
<link rel="manifest" href="manifest.json?v={{ config('ninja.app_version') }}">
|
||||
|
@ -190,6 +190,8 @@ Route::group(['middleware' => ['api_db', 'token_auth', 'locale'], 'prefix' => 'a
|
||||
Route::post('stripe/update_payment_methods', 'StripeController@update')->middleware('password_protected')->name('stripe.update');
|
||||
Route::post('stripe/import_customers', 'StripeController@import')->middleware('password_protected')->name('stripe.import');
|
||||
|
||||
Route::post('stripe/verify', 'StripeController@verify')->middleware('password_protected')->name('stripe.verify');
|
||||
|
||||
Route::resource('subscriptions', 'SubscriptionController');
|
||||
Route::post('subscriptions/bulk', 'SubscriptionController@bulk')->name('subscriptions.bulk');
|
||||
|
||||
|
@ -263,6 +263,63 @@ class ClientTest extends TestCase
|
||||
$this->assertEquals($this->client->contacts->count(), 3);
|
||||
}
|
||||
|
||||
public function testClientCreationWithIllegalContactObject()
|
||||
{
|
||||
|
||||
$account = Account::factory()->create();
|
||||
$company = Company::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
]);
|
||||
|
||||
$account->default_company_id = $company->id;
|
||||
$account->save();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'account_id' => $account->id,
|
||||
'confirmation_code' => $this->createDbHash(config('database.default')),
|
||||
'email' => 'whiz@gmail.com',
|
||||
|
||||
]);
|
||||
|
||||
$user->companies()->attach($company->id, [
|
||||
'account_id' => $account->id,
|
||||
'is_owner' => 1,
|
||||
'is_admin' => 1,
|
||||
'notifications' => CompanySettings::notificationDefaults(),
|
||||
'permissions' => '',
|
||||
'settings' => '',
|
||||
'is_locked' => 0,
|
||||
]);
|
||||
|
||||
$company_token = new CompanyToken;
|
||||
$company_token->user_id = $user->id;
|
||||
$company_token->company_id = $company->id;
|
||||
$company_token->account_id = $account->id;
|
||||
$company_token->name = $user->first_name.' '.$user->last_name;
|
||||
$company_token->token = Str::random(64);
|
||||
$company_token->save();
|
||||
|
||||
$this->token = $company_token->token;
|
||||
|
||||
|
||||
$data = [
|
||||
'name' => 'A loyal Client',
|
||||
'contacts' => $this->faker->unique()->safeEmail,
|
||||
];
|
||||
|
||||
try{
|
||||
$response = $this->withHeaders([
|
||||
'X-API-SECRET' => config('ninja.api_secret'),
|
||||
'X-API-TOKEN' => $this->token,
|
||||
])->post('/api/v1/clients/', $data);
|
||||
}catch (ValidationException $e) {
|
||||
$message = json_decode($e->validator->getMessageBag(), 1);
|
||||
$this->assertNotNull($message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function testCreatingClientAndContacts()
|
||||
{
|
||||
$account = Account::factory()->create();
|
||||
|
Loading…
Reference in New Issue
Block a user