1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-11 05:32:39 +01:00

Merge pull request #8620 from turbo124/v5-develop

v5.6.14
This commit is contained in:
David Bomba 2023-07-07 16:45:23 +10:00 committed by GitHub
commit 281bb47684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 378 additions and 515 deletions

View File

@ -4,6 +4,7 @@ APP_KEY=base64:RR++yx2rJ9kdxbdh3+AmbHLDQu+Q76i++co9Y8ybbno=
APP_DEBUG=false APP_DEBUG=false
APP_URL=http://localhost APP_URL=http://localhost
REACT_URL=http://localhost:3001
DB_CONNECTION=mysql DB_CONNECTION=mysql
MULTI_DB_ENABLED=false MULTI_DB_ENABLED=false
@ -33,8 +34,8 @@ MAIL_PORT=2525
MAIL_USERNAME=null MAIL_USERNAME=null
MAIL_PASSWORD=null MAIL_PASSWORD=null
MAIL_ENCRYPTION=null MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS='user@example.com' MAIL_FROM_ADDRESS="user@example.com"
MAIL_FROM_NAME='Self Hosted User' MAIL_FROM_NAME="Self Hosted User"
POSTMARK_API_TOKEN= POSTMARK_API_TOKEN=
REQUIRE_HTTPS=false REQUIRE_HTTPS=false

View File

@ -1 +1 @@
5.6.13 5.6.14

View File

@ -64,8 +64,6 @@ class ImportMigrations extends Command
*/ */
public function __construct() public function __construct()
{ {
$this->faker = Factory::create();
parent::__construct(); parent::__construct();
} }
@ -76,6 +74,8 @@ class ImportMigrations extends Command
*/ */
public function handle() public function handle()
{ {
$this->faker = Factory::create();
$this->buildCache(); $this->buildCache();
$path = $this->option('path') ?? public_path('storage/migrations/import'); $path = $this->option('path') ?? public_path('storage/migrations/import');

View File

@ -93,17 +93,6 @@ class MobileLocalization extends Command
$text = str_replace(['<i>', '</i>'], '', $text); $text = str_replace(['<i>', '</i>'], '', $text);
$text = str_replace(['<strong>', '</strong>'], '', $text); $text = str_replace(['<strong>', '</strong>'], '', $text);
//replace the three lines above with this
// if($language->locale == 'ar') {
// $text = str_replace('\n', " ", $text);
// }
// $text = str_replace(['<strong>', '</strong>','<i>', '</i>','<b>', '</b>'], '', $text);
// $text = str_replace('"', "'", $text);
echo "'$key': '$text',\n"; echo "'$key': '$text',\n";
} }

View File

@ -11,10 +11,12 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\Export\StoreExportRequest; use Illuminate\Support\Str;
use App\Jobs\Company\CompanyExport;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use App\Utils\Traits\MakesHash;
use App\Jobs\Company\CompanyExport;
use Illuminate\Support\Facades\Cache;
use App\Http\Requests\Export\StoreExportRequest;
class ExportController extends BaseController class ExportController extends BaseController
{ {
@ -54,8 +56,12 @@ class ExportController extends BaseController
*/ */
public function index(StoreExportRequest $request) public function index(StoreExportRequest $request)
{ {
CompanyExport::dispatch(auth()->user()->getCompany(), auth()->user()); $hash = Str::uuid();
$url = \Illuminate\Support\Facades\URL::temporarySignedRoute('protected_download', now()->addHour(), ['hash' => $hash]);
Cache::put($hash, $url, now()->addHour());
return response()->json(['message' => 'Processing'], 200); CompanyExport::dispatch(auth()->user()->getCompany(), auth()->user(), $hash);
return response()->json(['message' => 'Processing', 'url' => $url], 200);
} }
} }

View File

@ -0,0 +1,41 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Jobs\Util\UnlinkFile;
use App\Exceptions\SystemError;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;
class ProtectedDownloadController extends BaseController
{
public function index(Request $request)
{
$hashed_path = Cache::pull($request->hash);
if (!$hashed_path) {
throw new SystemError('File no longer available', 404);
abort(404, 'File no longer available');
}
UnlinkFile::dispatch(config('filesystems.default'), $hashed_path)->delay(now()->addSeconds(10));
return response()->streamDownload(function () use ($hashed_path) {
echo Storage::get($hashed_path);
}, basename($hashed_path), []);
}
}

View File

@ -83,4 +83,5 @@ class PaymentReportController extends BaseController
echo $csv; echo $csv;
}, $this->filename, $headers); }, $this->filename, $headers);
} }
} }

View File

@ -41,6 +41,7 @@ use App\Http\Middleware\VerifyCsrfToken;
use App\Http\Middleware\ContactTokenAuth; use App\Http\Middleware\ContactTokenAuth;
use Illuminate\Auth\Middleware\Authorize; use Illuminate\Auth\Middleware\Authorize;
use App\Http\Middleware\SetDbByCompanyKey; use App\Http\Middleware\SetDbByCompanyKey;
use App\Http\Middleware\ValidateSignature;
use App\Http\Middleware\PasswordProtection; use App\Http\Middleware\PasswordProtection;
use App\Http\Middleware\ClientPortalEnabled; use App\Http\Middleware\ClientPortalEnabled;
use App\Http\Middleware\CheckClientExistence; use App\Http\Middleware\CheckClientExistence;
@ -49,16 +50,13 @@ use Illuminate\Http\Middleware\SetCacheHeaders;
use Illuminate\Session\Middleware\StartSession; use Illuminate\Session\Middleware\StartSession;
use App\Http\Middleware\CheckForMaintenanceMode; use App\Http\Middleware\CheckForMaintenanceMode;
use App\Http\Middleware\RedirectIfAuthenticated; use App\Http\Middleware\RedirectIfAuthenticated;
use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Foundation\Http\Kernel as HttpKernel; use Illuminate\Foundation\Http\Kernel as HttpKernel;
use Illuminate\Routing\Middleware\ValidateSignature;
use Illuminate\Auth\Middleware\EnsureEmailIsVerified; use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
use Illuminate\Routing\Middleware\SubstituteBindings; use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\View\Middleware\ShareErrorsFromSession; use Illuminate\View\Middleware\ShareErrorsFromSession;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth; use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
use Illuminate\Foundation\Http\Middleware\ValidatePostSize; use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse; use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull; use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
class Kernel extends HttpKernel class Kernel extends HttpKernel

View File

@ -0,0 +1,49 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Http\Middleware;
use Closure;
use Illuminate\Routing\Exceptions\InvalidSignatureException;
class ValidateSignature
{
/**
* The names of the parameters that should be ignored.
*
* @var array<int, string>
*/
protected $ignore = [
'q'
];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $relative
* @return \Illuminate\Http\Response
*
* @throws \Illuminate\Routing\Exceptions\InvalidSignatureException
*/
public function handle($request, Closure $next, $relative = null)
{
$ignore = property_exists($this, 'except') ? $this->except : $this->ignore;
if ($request->hasValidSignatureWhileIgnoring($ignore, $relative !== 'relative')) {
return $next($request);
}
throw new InvalidSignatureException;
}
}

View File

@ -11,39 +11,39 @@
namespace App\Jobs\Company; namespace App\Jobs\Company;
use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject;
use App\Libraries\MultiDB;
use App\Mail\DownloadBackup;
use App\Models\Company;
use App\Models\CreditInvitation;
use App\Models\InvoiceInvitation;
use App\Models\PurchaseOrderInvitation;
use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation;
use App\Models\User; use App\Models\User;
use App\Models\VendorContact;
use App\Utils\Ninja; use App\Utils\Ninja;
use App\Utils\Traits\MakesHash; use App\Models\Company;
use App\Libraries\MultiDB;
use Illuminate\Support\Str;
use App\Mail\DownloadBackup;
use App\Jobs\Util\UnlinkFile;
use App\Models\VendorContact;
use Illuminate\Bus\Queueable; use Illuminate\Bus\Queueable;
use App\Models\QuoteInvitation;
use App\Utils\Traits\MakesHash;
use App\Models\CreditInvitation;
use App\Jobs\Mail\NinjaMailerJob;
use App\Models\InvoiceInvitation;
use Illuminate\Support\Facades\App;
use App\Jobs\Mail\NinjaMailerObject;
use Illuminate\Support\Facades\Cache;
use Illuminate\Queue\SerializesModels;
use App\Models\PurchaseOrderInvitation;
use Illuminate\Support\Facades\Storage;
use Illuminate\Queue\InteractsWithQueue;
use App\Models\RecurringInvoiceInvitation;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Storage;
class CompanyExport implements ShouldQueue class CompanyExport implements ShouldQueue
{ {
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, MakesHash;
public $company; private $export_format = 'json';
private $export_format;
private $export_data = []; private $export_data = [];
public $user;
/** /**
* Create a new job instance. * Create a new job instance.
@ -52,11 +52,8 @@ class CompanyExport implements ShouldQueue
* @param User $user * @param User $user
* @param string $custom_token_name * @param string $custom_token_name
*/ */
public function __construct(Company $company, User $user, $export_format = 'json') public function __construct(public Company $company, private User $user, public string $hash)
{ {
$this->company = $company;
$this->user = $user;
$this->export_format = $export_format;
} }
/** /**
@ -467,6 +464,10 @@ class CompanyExport implements ShouldQueue
} }
$storage_file_path = Storage::disk(config('filesystems.default'))->url('backups/'.$file_name); $storage_file_path = Storage::disk(config('filesystems.default'))->url('backups/'.$file_name);
$storage_path = Storage::disk(config('filesystems.default'))->path('backups/'.$file_name);
$url = Cache::get($this->hash);
Cache::put($this->hash, $storage_path, now()->addHour());
App::forgetInstance('translator'); App::forgetInstance('translator');
$t = app('translator'); $t = app('translator');
@ -475,13 +476,15 @@ class CompanyExport implements ShouldQueue
$company_reference = Company::find($this->company->id); $company_reference = Company::find($this->company->id);
$nmo = new NinjaMailerObject; $nmo = new NinjaMailerObject;
$nmo->mailable = new DownloadBackup($storage_file_path, $company_reference); $nmo->mailable = new DownloadBackup($url, $company_reference);
$nmo->to_user = $this->user; $nmo->to_user = $this->user;
$nmo->company = $company_reference; $nmo->company = $company_reference;
$nmo->settings = $this->company->settings; $nmo->settings = $this->company->settings;
NinjaMailerJob::dispatch($nmo, true); NinjaMailerJob::dispatch($nmo, true);
UnlinkFile::dispatch(config('filesystems.default'), $storage_path)->delay(now()->addHours(1));
if (Ninja::isHosted()) { if (Ninja::isHosted()) {
sleep(3); sleep(3);
unlink($zip_path); unlink($zip_path);

View File

@ -21,6 +21,7 @@ use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\Middleware\WithoutOverlapping;
class SendToAdmin implements ShouldQueue class SendToAdmin implements ShouldQueue
{ {
@ -59,4 +60,9 @@ class SendToAdmin implements ShouldQueue
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
} }
public function middleware()
{
return [new WithoutOverlapping("report-{$this->company->company_key}")];
}
} }

View File

@ -12,6 +12,7 @@
namespace App\PaymentDrivers\Square; namespace App\PaymentDrivers\Square;
use App\Exceptions\PaymentFailed;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest; use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Models\ClientGatewayToken; use App\Models\ClientGatewayToken;
use App\Models\GatewayType; use App\Models\GatewayType;
@ -113,18 +114,23 @@ class CreditCard implements MethodInterface
$body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId')); $body->setLocationId($this->square_driver->company_gateway->getConfigField('locationId'));
$body->setReferenceId(Str::random(16)); $body->setReferenceId(Str::random(16));
if ($request->has('verificationToken') && $request->input('verificationToken')) {
$body->setVerificationToken($request->input('verificationToken'));
}
if ($request->shouldUseToken()) { if ($request->shouldUseToken()) {
$body->setCustomerId($cgt->gateway_customer_reference); $body->setCustomerId($cgt->gateway_customer_reference);
}elseif ($request->has('verificationToken') && $request->input('verificationToken')) {
$body->setVerificationToken($request->input('verificationToken'));
} }
/** @var ApiResponse */ /** @var ApiResponse */
$response = $this->square_driver->square->getPaymentsApi()->createPayment($body); $response = $this->square_driver->square->getPaymentsApi()->createPayment($body);
if ($response->isSuccess()) { if ($response->isSuccess()) {
$body = json_decode($response->getBody());
if($request->store_card){
$this->createCard($body->payment->id);
}
return $this->processSuccessfulPayment($response); return $this->processSuccessfulPayment($response);
} }
@ -161,6 +167,52 @@ class CreditCard implements MethodInterface
return $this->square_driver->processUnsuccessfulTransaction($data); return $this->square_driver->processUnsuccessfulTransaction($data);
} }
private function createCard($source_id)
{
$square_card = new \Square\Models\Card();
$square_card->setCustomerId($this->findOrCreateClient());
$body = new \Square\Models\CreateCardRequest(uniqid("st", true), $source_id, $square_card);
$api_response = $this->square_driver
->init()
->square
->getCardsApi()
->createCard($body);
$body = json_decode($api_response->getBody());
if ($api_response->isSuccess()) {
try {
$payment_meta = new \stdClass;
$payment_meta->exp_month = (string) $body->card->exp_month;
$payment_meta->exp_year = (string) $body->card->exp_year;
$payment_meta->brand = (string) $body->card->card_brand;
$payment_meta->last4 = (string) $body->card->last_4;
$payment_meta->type = GatewayType::CREDIT_CARD;
$data = [
'payment_meta' => $payment_meta,
'token' => $body->card->id,
'payment_method_id' => GatewayType::CREDIT_CARD,
];
$this->square_driver->storeGatewayToken($data, ['gateway_customer_reference' => $body->card->customer_id]);
} catch (\Exception $e) {
return $this->square_driver->processInternallyFailedPayment($this->square_driver, $e);
}
}
else {
throw new PaymentFailed($body->errors[0]->detail, 500);
}
return false;
}
private function findOrCreateClient() private function findOrCreateClient()
{ {
$email_address = new \Square\Models\CustomerTextFilter(); $email_address = new \Square\Models\CustomerTextFilter();

View File

@ -113,13 +113,6 @@ class AppServiceProvider extends ServiceProvider
return $this; return $this;
}); });
/* Extension for custom mailers */
/* Convenience helper for testing s*/
ParallelTesting::setUpTestDatabase(function ($database, $token) {
Artisan::call('db:seed');
});
} }
public function register(): void public function register(): void

View File

@ -17,6 +17,7 @@ class ClientPortalServiceProvider extends ServiceProvider
app()->bind('customMessage', function () { app()->bind('customMessage', function () {
return new CustomMessage(); return new CustomMessage();
}); });
} }
/** /**
@ -26,6 +27,6 @@ class ClientPortalServiceProvider extends ServiceProvider
*/ */
public function boot() public function boot()
{ {
//
} }
} }

View File

@ -1,277 +0,0 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Providers;
use App\Libraries\MultiDB;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Contracts\Hashing\Hasher as HasherContract;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Str;
class MultiDatabaseUserProvider implements UserProvider
{
/**
* The hasher implementation.
*
* @var HasherContract
*/
protected $hasher;
/**
* The Eloquent user model.
*
* @var string
*/
protected $model;
/**
* Create a new database user provider.
*
* @param HasherContract $hasher
* @param string $model
* @return void
*/
public function __construct(HasherContract $hasher, $model)
{
$this->model = $model;
$this->hasher = $hasher;
}
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return UserContract|null
*/
public function retrieveById($identifier)
{
$this->setDefaultDatabase($identifier);
$model = $this->createModel();
return $model->newQuery()
->where($model->getAuthIdentifierName(), $identifier)
->first();
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixed $identifier
* @param string $token
* @return UserContract|null
*/
public function retrieveByToken($identifier, $token)
{
$this->setDefaultDatabase($identifier, $token);
$model = $this->createModel();
$model = $model->where($model->getAuthIdentifierName(), $identifier)->first();
if (! $model) {
return null;
}
$rememberToken = $model->getRememberToken();
return $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
}
/**
* Update the "remember me" token for the given user in storage.
*
* @param UserContract|Model $user
* @param string $token
* @return void
*/
public function updateRememberToken(UserContract $user, $token)
{
$user->setRememberToken($token);
$timestamps = $user->timestamps;
$user->timestamps = false;
$user->save();
$user->timestamps = $timestamps;
}
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return UserContract|null
*/
public function retrieveByCredentials(array $credentials)
{
if (empty($credentials) ||
(count($credentials) === 1 &&
array_key_exists('password', $credentials))) {
return;
}
$this->setDefaultDatabase(false, $credentials['email'], false);
// First we will add each credential element to the query as a where clause.
// Then we can execute the query and, if we found a user, return it in a
// Eloquent User "model" that will be utilized by the Guard instances.
$query = $this->createModel()->newQuery();
foreach ($credentials as $key => $value) {
if (Str::contains($key, 'password')) {
continue;
}
if (is_array($value) || $value instanceof Arrayable) {
$query->whereIn($key, $value);
} else {
$query->where($key, $value);
}
}
return $query->first();
}
/**
* Validate a user against the given credentials.
*
* @param UserContract $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
/**
* Create a new instance of the model.
*
* @return Model
*/
public function createModel()
{
$class = '\\'.ltrim($this->model, '\\');
return new $class;
}
/**
* Gets the hasher implementation.
*
* @return HasherContract
*/
public function getHasher()
{
return $this->hasher;
}
/**
* Sets the hasher implementation.
*
* @param HasherContract $hasher
* @return $this
*/
public function setHasher(HasherContract $hasher)
{
$this->hasher = $hasher;
return $this;
}
/**
* Gets the name of the Eloquent user model.
*
* @return string
*/
public function getModel()
{
return $this->model;
}
/**
* Sets the name of the Eloquent user model.
*
* @param string $model
* @return $this
*/
public function setModel($model)
{
$this->model = $model;
return $this;
}
/**
* Sets correct database by variable.
* @param bool $id
* @param bool $email
* @param bool $token
*/
private function setDefaultDatabase($id = false, $email = false, $token = false) : void
{
foreach (MultiDB::getDbs() as $database) {
$this->setDB($database);
/** Make sure we hook into the correct guard class */
$query = $this->conn->table((new $this->model)->getTable());
if ($id) {
$query->where('id', '=', $id);
}
if ($email) {
$query->where('email', '=', $email);
}
$user = $query->get();
if (count($user) >= 1) {
break;
}
$query = $this->conn->table('company_tokens');
if ($token) {
$query->whereRaw('BINARY `token`= ?', $token);
$token = $query->get();
if (count($token) >= 1) {
break;
}
}
}
}
/**
* Sets the database at runtime.
* @param $database
*/
private function setDB($database)
{
/** Get the database name we want to switch to*/
$db_name = config('database.connections.'.$database.'.database');
/* This will set the default configuration for the request / session?*/
config(['database.default' => $database]);
/* Set the connection to complete the user authentication */
$this->conn = app('db')->connection(config('database.connections.database.'.$database));
}
}

View File

@ -20,7 +20,6 @@ use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter; use Illuminate\Support\Facades\RateLimiter;
use App\Http\Middleware\ThrottleRequestsWithPredis; use App\Http\Middleware\ThrottleRequestsWithPredis;
use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Routing\Middleware\ThrottleRequests;
use Illuminate\Routing\Middleware\ThrottleRequestsWithRedis;
use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

View File

@ -101,7 +101,6 @@
"php": "^8.1", "php": "^8.1",
"barryvdh/laravel-debugbar": "^3.6", "barryvdh/laravel-debugbar": "^3.6",
"barryvdh/laravel-ide-helper": "^2.13", "barryvdh/laravel-ide-helper": "^2.13",
"beyondcode/laravel-query-detector": "^1.6",
"brianium/paratest": "^6.1", "brianium/paratest": "^6.1",
"fakerphp/faker": "^1.14", "fakerphp/faker": "^1.14",
"filp/whoops": "^2.7", "filp/whoops": "^2.7",
@ -136,7 +135,7 @@
}, },
"extra": { "extra": {
"laravel": { "laravel": {
"dont-discover": ["invoiceninja/inspector"] "dont-discover": []
} }
}, },
"scripts": { "scripts": {

84
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "5119232ad274b24801da947fcbd4f884", "content-hash": "135eec9ab7a1e8c0ab3820ff27cf1488",
"packages": [ "packages": [
{ {
"name": "adrienrn/php-mimetyper", "name": "adrienrn/php-mimetyper",
@ -14410,16 +14410,16 @@
}, },
{ {
"name": "barryvdh/reflection-docblock", "name": "barryvdh/reflection-docblock",
"version": "v2.1.0", "version": "v2.1.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/barryvdh/ReflectionDocBlock.git", "url": "https://github.com/barryvdh/ReflectionDocBlock.git",
"reference": "bf44b757feb8ba1734659029357646466ded673e" "reference": "e6811e927f0ecc37cc4deaa6627033150343e597"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/bf44b757feb8ba1734659029357646466ded673e", "url": "https://api.github.com/repos/barryvdh/ReflectionDocBlock/zipball/e6811e927f0ecc37cc4deaa6627033150343e597",
"reference": "bf44b757feb8ba1734659029357646466ded673e", "reference": "e6811e927f0ecc37cc4deaa6627033150343e597",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -14456,69 +14456,9 @@
} }
], ],
"support": { "support": {
"source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.0" "source": "https://github.com/barryvdh/ReflectionDocBlock/tree/v2.1.1"
}, },
"time": "2022-10-31T15:35:43+00:00" "time": "2023-06-14T05:06:27+00:00"
},
{
"name": "beyondcode/laravel-query-detector",
"version": "1.7.0",
"source": {
"type": "git",
"url": "https://github.com/beyondcode/laravel-query-detector.git",
"reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/beyondcode/laravel-query-detector/zipball/40c7e168fcf7eeb80d8e96f7922e05ab194269c8",
"reference": "40c7e168fcf7eeb80d8e96f7922e05ab194269c8",
"shasum": ""
},
"require": {
"illuminate/support": "^5.5 || ^6.0 || ^7.0 || ^8.0 || ^9.0|^10.0",
"php": "^7.1 || ^8.0"
},
"require-dev": {
"laravel/legacy-factories": "^1.0",
"orchestra/testbench": "^3.0 || ^4.0 || ^5.0 || ^6.0|^8.0",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"BeyondCode\\QueryDetector\\QueryDetectorServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"BeyondCode\\QueryDetector\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Marcel Pociot",
"email": "marcel@beyondco.de",
"homepage": "https://beyondcode.de",
"role": "Developer"
}
],
"description": "Laravel N+1 Query Detector",
"homepage": "https://github.com/beyondcode/laravel-query-detector",
"keywords": [
"beyondcode",
"laravel-query-detector"
],
"support": {
"issues": "https://github.com/beyondcode/laravel-query-detector/issues",
"source": "https://github.com/beyondcode/laravel-query-detector/tree/1.7.0"
},
"time": "2023-02-15T10:37:22+00:00"
}, },
{ {
"name": "brianium/paratest", "name": "brianium/paratest",
@ -16339,16 +16279,16 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.10.24", "version": "1.10.25",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "360ecc90569e9a60c2954ee209ec04fa0d958e14" "reference": "578f4e70d117f9a90699324c555922800ac38d8c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/360ecc90569e9a60c2954ee209ec04fa0d958e14", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/578f4e70d117f9a90699324c555922800ac38d8c",
"reference": "360ecc90569e9a60c2954ee209ec04fa0d958e14", "reference": "578f4e70d117f9a90699324c555922800ac38d8c",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -16397,7 +16337,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2023-07-05T12:32:13+00:00" "time": "2023-07-06T12:11:37+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",

View File

@ -15,8 +15,8 @@ return [
'require_https' => env('REQUIRE_HTTPS', true), 'require_https' => env('REQUIRE_HTTPS', true),
'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_url' => rtrim(env('APP_URL', ''), '/'),
'app_domain' => env('APP_DOMAIN', 'invoicing.co'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'),
'app_version' => '5.6.13', 'app_version' => '5.6.14',
'app_tag' => '5.6.13', 'app_tag' => '5.6.14',
'minimum_client_version' => '5.0.16', 'minimum_client_version' => '5.0.16',
'terms_version' => '1.0.1', 'terms_version' => '1.0.1',
'api_secret' => env('API_SECRET', ''), 'api_secret' => env('API_SECRET', ''),

View File

@ -176,18 +176,15 @@ var SquareCreditCard = /*#__PURE__*/function () {
}, { }, {
key: "handle", key: "handle",
value: function () { value: function () {
var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6() { var _handle = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee7() {
var _document$getElementB, var _this = this;
_this = this, return _regeneratorRuntime().wrap(function _callee7$(_context7) {
_document$getElementB2, while (1) switch (_context7.prev = _context7.next) {
_document$getElementB3;
var toggleWithToken, _document$getElementB4;
return _regeneratorRuntime().wrap(function _callee6$(_context6) {
while (1) switch (_context6.prev = _context6.next) {
case 0: case 0:
_context6.next = 2; document.getElementById('payment-list').classList.add('hidden');
return this.init(); _context7.next = 3;
case 2: return this.init().then(function () {
var _document$getElementB, _document$getElementB2, _document$getElementB3, _document$getElementB4;
(_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) { (_document$getElementB = document.getElementById('authorize-card')) === null || _document$getElementB === void 0 ? void 0 : _document$getElementB.addEventListener('click', function (e) {
return _this.completePaymentWithoutToken(e); return _this.completePaymentWithoutToken(e);
}); });
@ -199,20 +196,14 @@ var SquareCreditCard = /*#__PURE__*/function () {
return _this.completePaymentWithoutToken(e); return _this.completePaymentWithoutToken(e);
}); });
Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) { Array.from(document.getElementsByClassName('toggle-payment-with-token')).forEach(function (element) {
return element.addEventListener('click', function (element) { return element.addEventListener('click', /*#__PURE__*/function () {
document.getElementById('card-container').classList.add('hidden');
document.getElementById('save-card--container').style.display = 'none';
document.querySelector('input[name=token]').value = element.target.dataset.token;
});
});
(_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) { var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee5(element) {
return _regeneratorRuntime().wrap(function _callee5$(_context5) { return _regeneratorRuntime().wrap(function _callee5$(_context5) {
while (1) switch (_context5.prev = _context5.next) { while (1) switch (_context5.prev = _context5.next) {
case 0: case 0:
document.getElementById('card-container').classList.remove('hidden'); document.getElementById('card-container').classList.add('hidden');
document.getElementById('save-card--container').style.display = 'grid'; document.getElementById('save-card--container').style.display = 'none';
document.querySelector('input[name=token]').value = ''; document.querySelector('input[name=token]').value = element.target.dataset.token;
case 3: case 3:
case "end": case "end":
return _context5.stop(); return _context5.stop();
@ -223,15 +214,41 @@ var SquareCreditCard = /*#__PURE__*/function () {
return _ref.apply(this, arguments); return _ref.apply(this, arguments);
}; };
}()); }());
toggleWithToken = document.querySelector('.toggle-payment-with-token'); });
if (!toggleWithToken) { (_document$getElementB3 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB3 === void 0 ? void 0 : _document$getElementB3.addEventListener('click', /*#__PURE__*/function () {
(_document$getElementB4 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.click(); var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee6(element) {
} return _regeneratorRuntime().wrap(function _callee6$(_context6) {
case 8: while (1) switch (_context6.prev = _context6.next) {
case 0:
document.getElementById('card-container').classList.remove('hidden');
document.getElementById('save-card--container').style.display = 'grid';
document.querySelector('input[name=token]').value = '';
case 3:
case "end": case "end":
return _context6.stop(); return _context6.stop();
} }
}, _callee6, this); }, _callee6);
}));
return function (_x5) {
return _ref2.apply(this, arguments);
};
}());
// let toggleWithToken = document.querySelector(
// '.toggle-payment-with-token'
// );
// if (!toggleWithToken) {
document.getElementById('loader').classList.add('hidden');
document.getElementById('payment-list').classList.remove('hidden');
(_document$getElementB4 = document.getElementById('toggle-payment-with-credit-card')) === null || _document$getElementB4 === void 0 ? void 0 : _document$getElementB4.click();
// }
});
case 3:
case "end":
return _context7.stop();
}
}, _callee7, this);
})); }));
function handle() { function handle() {
return _handle.apply(this, arguments); return _handle.apply(this, arguments);

View File

@ -31,8 +31,6 @@ var StripeCreditCard = /*#__PURE__*/function () {
key: "setupStripe", key: "setupStripe",
value: function setupStripe() { value: function setupStripe() {
if (this.stripeConnect) { if (this.stripeConnect) {
// this.stripe.stripeAccount = this.stripeConnect;
this.stripe = Stripe(this.key, { this.stripe = Stripe(this.key, {
stripeAccount: this.stripeConnect stripeAccount: this.stripeConnect
}); });

View File

@ -16,7 +16,7 @@
"/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=a2168c43060a7de40da20b5fc599bcab", "/js/clients/payments/checkout-credit-card.js": "/js/clients/payments/checkout-credit-card.js?id=a2168c43060a7de40da20b5fc599bcab",
"/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=4158693089b29ee8e13cb7d9ce4480a9", "/js/clients/quotes/action-selectors.js": "/js/clients/quotes/action-selectors.js?id=4158693089b29ee8e13cb7d9ce4480a9",
"/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=4e596cec23cdd6487534e6ed5499d791", "/js/clients/quotes/approve.js": "/js/clients/quotes/approve.js?id=4e596cec23cdd6487534e6ed5499d791",
"/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=b483e14d15000c04edfe4c9c80fb97c9", "/js/clients/payments/stripe-credit-card.js": "/js/clients/payments/stripe-credit-card.js?id=bfa116c1df42c641bc7a3ff4fa8d50dd",
"/js/setup/setup.js": "/js/setup/setup.js?id=086b9e114b0b9ee01f909d686f489162", "/js/setup/setup.js": "/js/setup/setup.js?id=086b9e114b0b9ee01f909d686f489162",
"/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=cf50b5ba1fcd1d184bf0c10d710672c8", "/js/clients/payments/card-js.min.js": "/js/clients/payments/card-js.min.js?id=cf50b5ba1fcd1d184bf0c10d710672c8",
"/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=c9593b44d66f89874d13f99bc3e6ff33", "/js/clients/shared/pdf.js": "/js/clients/shared/pdf.js?id=c9593b44d66f89874d13f99bc3e6ff33",
@ -30,7 +30,7 @@
"/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=2f72b969507e6135b5c52a65522ab3ae", "/js/clients/payments/mollie-credit-card.js": "/js/clients/payments/mollie-credit-card.js?id=2f72b969507e6135b5c52a65522ab3ae",
"/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=0d1c8957b02c5601b7d57c39740bff75", "/js/clients/payments/eway-credit-card.js": "/js/clients/payments/eway-credit-card.js?id=0d1c8957b02c5601b7d57c39740bff75",
"/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=2f8e5af9ba5ce266d2ee49b084fbe291", "/js/clients/payment_methods/braintree-ach.js": "/js/clients/payment_methods/braintree-ach.js?id=2f8e5af9ba5ce266d2ee49b084fbe291",
"/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=dbd7a15777def575562153c984dee08a", "/js/clients/payments/square-credit-card.js": "/js/clients/payments/square-credit-card.js?id=a5e1407a161c3c72545d125dd1100571",
"/js/clients/statements/view.js": "/js/clients/statements/view.js?id=bd92ab50acabf1cc5232912d53edc5e1", "/js/clients/statements/view.js": "/js/clients/statements/view.js?id=bd92ab50acabf1cc5232912d53edc5e1",
"/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=46e14d31acaf3adf58444a5de4b4122c", "/js/clients/payments/razorpay-aio.js": "/js/clients/payments/razorpay-aio.js?id=46e14d31acaf3adf58444a5de4b4122c",
"/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=ef15c0865a29c3c17f2ad185cad0d28e", "/js/clients/payments/stripe-sepa.js": "/js/clients/payments/stripe-sepa.js?id=ef15c0865a29c3c17f2ad185cad0d28e",

View File

@ -125,7 +125,10 @@ class SquareCreditCard {
} }
async handle() { async handle() {
await this.init();
document.getElementById('payment-list').classList.add('hidden');
await this.init().then(() => {
document document
.getElementById('authorize-card') .getElementById('authorize-card')
@ -146,7 +149,7 @@ class SquareCreditCard {
Array.from( Array.from(
document.getElementsByClassName('toggle-payment-with-token') document.getElementsByClassName('toggle-payment-with-token')
).forEach((element) => ).forEach((element) =>
element.addEventListener('click', (element) => { element.addEventListener('click', async (element) => {
document document
.getElementById('card-container') .getElementById('card-container')
.classList.add('hidden'); .classList.add('hidden');
@ -168,13 +171,17 @@ class SquareCreditCard {
document.querySelector('input[name=token]').value = ''; document.querySelector('input[name=token]').value = '';
}); });
let toggleWithToken = document.querySelector( // let toggleWithToken = document.querySelector(
'.toggle-payment-with-token' // '.toggle-payment-with-token'
); // );
if (!toggleWithToken) { // if (!toggleWithToken) {
document.getElementById('loader').classList.add('hidden');
document.getElementById('payment-list').classList.remove('hidden');
document.getElementById('toggle-payment-with-credit-card')?.click(); document.getElementById('toggle-payment-with-credit-card')?.click();
} // }
});
} }
} }

View File

@ -19,7 +19,6 @@ class StripeCreditCard {
setupStripe() { setupStripe() {
if (this.stripeConnect){ if (this.stripeConnect){
// this.stripe.stripeAccount = this.stripeConnect;
this.stripe = Stripe(this.key, { this.stripe = Stripe(this.key, {
stripeAccount: this.stripeConnect, stripeAccount: this.stripeConnect,

View File

@ -1,5 +1,5 @@
@extends('portal.ninja2020.layout.error') @extends('portal.ninja2020.layout.error')
@section('title', __($title) ?? 'Server Error') @section('title', $title ?? 'Error')
@section('code', __($code) ?? '500') @section('code', __($code) ?? '500')
@section('message', __($message) ?? 'System Error') @section('message', __($message) ?? 'System Error')

View File

@ -7,7 +7,32 @@
<meta name="square_contact" content="{{ json_encode($square_contact) }}"> <meta name="square_contact" content="{{ json_encode($square_contact) }}">
<meta name="amount" content="{{ $amount }}"> <meta name="amount" content="{{ $amount }}">
<meta name="currencyCode" content="{{ $currencyCode }}"> <meta name="currencyCode" content="{{ $currencyCode }}">
<style>
.loader {
border-top-color: #3498db;
-webkit-animation: spinner 1.5s linear infinite;
animation: spinner 1.5s linear infinite;
}
@-webkit-keyframes spinner {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
@endsection @endsection
@section('gateway_content') @section('gateway_content')
@ -33,23 +58,41 @@
@include('portal.ninja2020.gateways.includes.payment_details') @include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
<div class="flex flex-col" id="loader">
<div class="loader ease-linear rounded-full border-4 border-t-4 border-gray-200 h-12 w-12 mb-4"></div>
</div>
<ul class="list-none hover:list-disc " id="payment-list">
@if (count($tokens) > 0) @if (count($tokens) > 0)
@foreach ($tokens as $token) @foreach($tokens as $token)
<li class="py-2 hover:text-blue hover:bg-blue-600">
<label class="mr-4"> <label class="mr-4">
<input type="radio" data-token="{{ $token->token }}" name="payment-type" <input
class="form-radio cursor-pointer toggle-payment-with-token" /> type="radio"
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }}</span> data-token="{{ $token->token }}"
name="payment-type"
class="form-check-input text-indigo-600 rounded-full cursor-pointer toggle-payment-with-token toggle-payment-with-token"
/>
<span class="ml-1 cursor-pointer">**** {{ $token->meta?->last4 }} - {{ $token->meta?->exp_month ?? 'xx' }}/{{ $token->meta?->exp_year ?? 'xx' }}</span>
</label> </label>
</li>
@endforeach @endforeach
@endisset @endisset
<li class="py-2 hover:text-blue hover:bg-blue-600">
<label> <label>
<input type="radio" id="toggle-payment-with-credit-card" class="form-radio cursor-pointer" name="payment-type" <input
checked /> type="radio"
id="toggle-payment-with-credit-card"
class="form-check-input text-indigo-600 rounded-full cursor-pointer"
name="payment-type"
checked/>
<span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span> <span class="ml-1 cursor-pointer">{{ __('texts.new_card') }}</span>
</label> </label>
</li>
</ul>
@endcomponent @endcomponent
@include('portal.ninja2020.gateways.includes.save_card') @include('portal.ninja2020.gateways.includes.save_card')

View File

@ -101,6 +101,7 @@ use App\Http\Controllers\Support\Messages\SendingController;
use App\Http\Controllers\Reports\ClientSalesReportController; use App\Http\Controllers\Reports\ClientSalesReportController;
use App\Http\Controllers\Reports\InvoiceItemReportController; use App\Http\Controllers\Reports\InvoiceItemReportController;
use App\Http\Controllers\PaymentNotificationWebhookController; use App\Http\Controllers\PaymentNotificationWebhookController;
use App\Http\Controllers\ProtectedDownloadController;
use App\Http\Controllers\Reports\ProductSalesReportController; use App\Http\Controllers\Reports\ProductSalesReportController;
use App\Http\Controllers\Reports\ClientBalanceReportController; use App\Http\Controllers\Reports\ClientBalanceReportController;
use App\Http\Controllers\Reports\ClientContactReportController; use App\Http\Controllers\Reports\ClientContactReportController;
@ -141,7 +142,6 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
Route::get('activities', [ActivityController::class, 'index']); Route::get('activities', [ActivityController::class, 'index']);
Route::get('activities/download_entity/{activity}', [ActivityController::class, 'downloadHistoricalEntity']); Route::get('activities/download_entity/{activity}', [ActivityController::class, 'downloadHistoricalEntity']);
Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals'); Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals');
Route::post('charts/chart_summary', [ChartController::class, 'chart_summary'])->name('chart.chart_summary'); Route::post('charts/chart_summary', [ChartController::class, 'chart_summary'])->name('chart.chart_summary');
@ -280,26 +280,26 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale']
Route::post('recurring_quotes/bulk', [RecurringQuoteController::class, 'bulk'])->name('recurring_quotes.bulk'); Route::post('recurring_quotes/bulk', [RecurringQuoteController::class, 'bulk'])->name('recurring_quotes.bulk');
Route::put('recurring_quotes/{recurring_quote}/upload', [RecurringQuoteController::class, 'upload']); Route::put('recurring_quotes/{recurring_quote}/upload', [RecurringQuoteController::class, 'upload']);
Route::post('refresh', [LoginController::class, 'refresh'])->middleware('throttle:refresh'); Route::post('refresh', [LoginController::class, 'refresh'])->middleware('throttle:refr2sh');
Route::post('reports/clients', ClientReportController::class)->middleware('throttle:20,1');
Route::post('reports/activities', ActivityReportController::class)->middleware('throttle:20,1');
Route::post('reports/client_contacts', ClientContactReportController::class)->middleware('throttle:20,1');
Route::post('reports/contacts', ClientContactReportController::class)->middleware('throttle:20,1');
Route::post('reports/credits', CreditReportController::class)->middleware('throttle:20,1');
Route::post('reports/documents', DocumentReportController::class)->middleware('throttle:20,1');
Route::post('reports/expenses', ExpenseReportController::class)->middleware('throttle:20,1');
Route::post('reports/invoices', InvoiceReportController::class)->middleware('throttle:20,1');
Route::post('reports/invoice_items', InvoiceItemReportController::class)->middleware('throttle:20,1');
Route::post('reports/quotes', QuoteReportController::class)->middleware('throttle:20,1');
Route::post('reports/quote_items', QuoteItemReportController::class)->middleware('throttle:20,1');
Route::post('reports/recurring_invoices', RecurringInvoiceReportController::class)->middleware('throttle:20,1');
Route::post('reports/payments', PaymentReportController::class)->middleware('throttle:20,1');
Route::post('reports/products', ProductReportController::class)->middleware('throttle:20,1');
Route::post('reports/product_sales', ProductSalesReportController::class)->middleware('throttle:20,1');
Route::post('reports/tasks', TaskReportController::class)->middleware('throttle:20,1');
Route::post('reports/clients', ClientReportController::class);
Route::post('reports/activities', ActivityReportController::class);
Route::post('reports/client_contacts', ClientContactReportController::class);
Route::post('reports/contacts', ClientContactReportController::class);
Route::post('reports/credits', CreditReportController::class);
Route::post('reports/documents', DocumentReportController::class);
Route::post('reports/expenses', ExpenseReportController::class);
Route::post('reports/invoices', InvoiceReportController::class);
Route::post('reports/invoice_items', InvoiceItemReportController::class);
Route::post('reports/quotes', QuoteReportController::class);
Route::post('reports/quote_items', QuoteItemReportController::class);
Route::post('reports/recurring_invoices', RecurringInvoiceReportController::class);
Route::post('reports/payments', PaymentReportController::class);
Route::post('reports/products', ProductReportController::class);
Route::post('reports/product_sales', ProductSalesReportController::class);
Route::post('reports/tasks', TaskReportController::class);
Route::post('reports/profitloss', ProfitAndLossController::class); Route::post('reports/profitloss', ProfitAndLossController::class);
Route::post('reports/ar_detail_report', ARDetailReportController::class); Route::post('reports/ar_detail_report', ARDetailReportController::class);
Route::post('reports/ar_summary_report', ARSummaryReportController::class); Route::post('reports/ar_summary_report', ARSummaryReportController::class);
Route::post('reports/client_balance_report', ClientBalanceReportController::class); Route::post('reports/client_balance_report', ClientBalanceReportController::class);
@ -402,4 +402,6 @@ Route::post('api/v1/yodlee/data_updates', [YodleeController::class, 'dataUpdates
Route::post('api/v1/yodlee/refresh_updates', [YodleeController::class, 'refreshUpdatesWebhook'])->middleware('throttle:100,1'); Route::post('api/v1/yodlee/refresh_updates', [YodleeController::class, 'refreshUpdatesWebhook'])->middleware('throttle:100,1');
Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'])->middleware('throttle:100,1'); Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'])->middleware('throttle:100,1');
Route::get('api/v1/protected_download/{hash}', [ProtectedDownloadController::class, 'index'])->name('protected_download')->middleware('signed')->middleware('throttle:300,1');
Route::fallback([BaseController::class, 'notFound'])->middleware('throttle:404'); Route::fallback([BaseController::class, 'notFound'])->middleware('throttle:404');

View File

@ -12,7 +12,3 @@ use Illuminate\Foundation\Inspiring;
| simple approach to interacting with each command's IO methods. | simple approach to interacting with each command's IO methods.
| |
*/ */
Artisan::command('inspire', function () {
$this->comment(Inspiring::quote());
})->describe('Display an inspiring quote');