Merge remote-tracking branch 'upstream/v5-develop' into v5-1103-billing-landing-page

This commit is contained in:
Benjamin Beganović 2021-03-17 07:34:23 +01:00
commit eb2cfde303
28 changed files with 87749 additions and 87455 deletions

View File

@ -68,7 +68,7 @@ class Kernel extends ConsoleKernel
/* Run queue's with this*/ /* Run queue's with this*/
if (Ninja::isSelfHost()) { if (Ninja::isSelfHost()) {
$schedule->command('queue:work')->everyMinute()->withoutOverlapping(); $schedule->command('queue:work --daemon')->everyMinute()->withoutOverlapping();
//we need to add this as we are seeing cached queues mess up the system on first load. //we need to add this as we are seeing cached queues mess up the system on first load.
$schedule->command('queue:restart')->everyFiveMinutes()->withoutOverlapping(); $schedule->command('queue:restart')->everyFiveMinutes()->withoutOverlapping();

View File

@ -28,6 +28,9 @@ use Google_Client;
use Illuminate\Foundation\Auth\AuthenticatesUsers; use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Str;
use PragmaRX\Google2FA\Google2FA;
use Turbo124\Beacon\Facades\LightLogs; use Turbo124\Beacon\Facades\LightLogs;
class LoginController extends BaseController class LoginController extends BaseController
@ -159,19 +162,40 @@ class LoginController extends BaseController
} }
if ($this->attemptLogin($request)) { if ($this->attemptLogin($request)) {
LightLogs::create(new LoginSuccess()) LightLogs::create(new LoginSuccess())
->increment() ->increment()
->batch(); ->batch();
$user = $this->guard()->user(); $user = $this->guard()->user();
//if user has 2fa enabled - lets check this now:
if($user->google_2fa_secret)
{
$google2fa = new Google2FA();
if(!$google2fa->verifyKey(decrypt($user->google_2fa_secret), $request->input('one_time_password')))
{
return response()
->json(['message' => ctrans('texts.invalid_one_time_password')], 401)
->header('X-App-Version', config('ninja.app_version'))
->header('X-Api-Version', config('ninja.minimum_client_version'));
}
}
$user->setCompany($user->account->default_company); $user->setCompany($user->account->default_company);
$timeout = auth()->user()->company()->default_password_timeout;
Cache::put(auth()->user()->hashed_id.'_logged_in', Str::random(64), $timeout);
$cu = CompanyUser::query() $cu = CompanyUser::query()
->where('user_id', auth()->user()->id); ->where('user_id', auth()->user()->id);
return $this->listResponse($cu); return $this->listResponse($cu);
} else { } else {
LightLogs::create(new LoginFailure()) LightLogs::create(new LoginFailure())
->increment() ->increment()
->batch(); ->batch();
@ -182,6 +206,7 @@ class LoginController extends BaseController
->json(['message' => ctrans('texts.invalid_credentials')], 401) ->json(['message' => ctrans('texts.invalid_credentials')], 401)
->header('X-App-Version', config('ninja.app_version')) ->header('X-App-Version', config('ninja.app_version'))
->header('X-Api-Version', config('ninja.minimum_client_version')); ->header('X-Api-Version', config('ninja.minimum_client_version'));
} }
} }
@ -269,12 +294,14 @@ class LoginController extends BaseController
$user = $google->getTokenResponse(request()->input('id_token')); $user = $google->getTokenResponse(request()->input('id_token'));
if (is_array($user)) { if (is_array($user)) {
$query = [ $query = [
'oauth_user_id' => $google->harvestSubField($user), 'oauth_user_id' => $google->harvestSubField($user),
'oauth_provider_id'=> 'google', 'oauth_provider_id'=> 'google',
]; ];
if ($existing_user = MultiDB::hasUser($query)) { if ($existing_user = MultiDB::hasUser($query)) {
Auth::login($existing_user, true); Auth::login($existing_user, true);
$existing_user->setCompany($existing_user->account->default_company); $existing_user->setCompany($existing_user->account->default_company);
@ -282,6 +309,7 @@ class LoginController extends BaseController
->where('user_id', auth()->user()->id); ->where('user_id', auth()->user()->id);
return $this->listResponse($cu); return $this->listResponse($cu);
} }
} }

View File

@ -89,23 +89,8 @@ class ConnectedAccountController extends BaseController
$user = $google->getTokenResponse(request()->input('id_token')); $user = $google->getTokenResponse(request()->input('id_token'));
if (is_array($user)) {
$query = [
'oauth_user_id' => $google->harvestSubField($user),
'oauth_provider_id'=> 'google',
];
/* Cannot allow duplicates! */
if ($existing_user = MultiDB::hasUser($query)) {
return response()
->json(['message' => 'User already exists in system.'], 401)
->header('X-App-Version', config('ninja.app_version'))
->header('X-Api-Version', config('ninja.minimum_client_version'));
}
}
if ($user) { if ($user) {
$client = new Google_Client(); $client = new Google_Client();
$client->setClientId(config('ninja.auth.google.client_id')); $client->setClientId(config('ninja.auth.google.client_id'));
$client->setClientSecret(config('ninja.auth.google.client_secret')); $client->setClientSecret(config('ninja.auth.google.client_secret'));
@ -118,7 +103,6 @@ class ConnectedAccountController extends BaseController
$refresh_token = $token['refresh_token']; $refresh_token = $token['refresh_token'];
} }
$connected_account = [ $connected_account = [
'password' => '', 'password' => '',
'email' => $google->harvestEmail($user), 'email' => $google->harvestEmail($user),

View File

@ -53,13 +53,21 @@ class TwoFactorController extends BaseController
$secret = request()->input('secret'); $secret = request()->input('secret');
$oneTimePassword = request()->input('one_time_password'); $oneTimePassword = request()->input('one_time_password');
if (! $secret || ! $google2fa->verifyKey($secret, $oneTimePassword)) { if($google2fa->verifyKey($secret, $oneTimePassword) && $user->phone && $user->email_verified_at){
return response()->json('message' > ctrans('texts.invalid_one_time_password'));
} elseif (! $user->google_2fa_secret && $user->phone && $user->confirmed) {
$user->google_2fa_secret = encrypt($secret); $user->google_2fa_secret = encrypt($secret);
$user->save(); $user->save();
}
return response()->json(['message' => ctrans('texts.enabled_two_factor')], 200);
return response()->json(['message' => ctrans('texts.enabled_two_factor')], 200); } elseif (! $secret || ! $google2fa->verifyKey($secret, $oneTimePassword)) {
return response()->json(['message' => ctrans('texts.invalid_one_time_password')], 400);
}
return response()->json(['message' => 'No phone record or user is not confirmed'], 400);
} }
} }

View File

@ -68,9 +68,9 @@ class UpdatePaymentRequest extends Request
unset($input['amount']); unset($input['amount']);
} }
if (isset($input['number'])) { // if (isset($input['number'])) {
unset($input['number']); // unset($input['number']);
} // }
if (isset($input['invoices']) && is_array($input['invoices']) !== false) { if (isset($input['invoices']) && is_array($input['invoices']) !== false) {
foreach ($input['invoices'] as $key => $value) { foreach ($input['invoices'] as $key => $value) {

View File

@ -23,6 +23,6 @@ class ReconfirmUserRequest extends Request
*/ */
public function authorize() : bool public function authorize() : bool
{ {
return auth()->user()->id == $this->user->id; return auth()->user()->id == $this->user->id || auth()->user()->isAdmin();
} }
} }

View File

@ -12,6 +12,7 @@
namespace App\Jobs\Entity; namespace App\Jobs\Entity;
use App\Models\Account;
use App\Models\Credit; use App\Models\Credit;
use App\Models\CreditInvitation; use App\Models\CreditInvitation;
use App\Models\Design; use App\Models\Design;
@ -118,6 +119,9 @@ class CreateEntityPdf implements ShouldQueue
$entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id)); $entity_design_id = $this->entity->design_id ? $this->entity->design_id : $this->decodePrimaryKey($this->entity->client->getSetting($entity_design_id));
if(!$this->company->account->hasFeature(Account::FEATURE_DIFFERENT_DESIGNS))
$entity_design_id = 2;
$design = Design::find($entity_design_id); $design = Design::find($entity_design_id);
$html = new HtmlEngine($this->invitation); $html = new HtmlEngine($this->invitation);

View File

@ -16,6 +16,7 @@ use App\Events\Invoice\InvoiceWasEmailed;
use App\Jobs\Entity\EmailEntity; use App\Jobs\Entity\EmailEntity;
use App\Jobs\Util\WebHookHandler; use App\Jobs\Util\WebHookHandler;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\Account;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\Webhook; use App\Models\Webhook;
use App\Utils\Ninja; use App\Utils\Ninja;
@ -207,7 +208,7 @@ class SendReminders implements ShouldQueue
$invoice->invitations->each(function ($invitation) use ($template, $invoice) { $invoice->invitations->each(function ($invitation) use ($template, $invoice) {
//only send if enable_reminder setting is toggled to yes //only send if enable_reminder setting is toggled to yes
if ($this->checkSendSetting($invoice, $template)) { if ($this->checkSendSetting($invoice, $template) && $invoice->company->account->hasFeature(Account::FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
nlog("firing email"); nlog("firing email");
EmailEntity::dispatchNow($invitation, $invitation->company, $template); EmailEntity::dispatchNow($invitation, $invitation->company, $template);

View File

@ -80,9 +80,10 @@ class UserEmailChanged implements ShouldQueue
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
$nmo->to_user = $this->new_user; // $nmo->to_user = $this->new_user;
// NinjaMailerJob::dispatch($nmo);
NinjaMailerJob::dispatch($nmo);
$this->new_user->service()->invite($this->company);
} }

View File

@ -214,9 +214,14 @@ class Import implements ShouldQueue
// if($check_data['status'] == 'errors') // if($check_data['status'] == 'errors')
// throw new ProcessingMigrationArchiveFailed(implode("\n", $check_data)); // throw new ProcessingMigrationArchiveFailed(implode("\n", $check_data));
Mail::to($this->user->email, $this->user->name()) try{
->send(new MigrationCompleted($this->company, implode("<br>",$check_data))); Mail::to($this->user->email, $this->user->name())
->send(new MigrationCompleted($this->company, implode("<br>",$check_data)));
}
catch(\Exception $e) {
nlog($e->getMessage());
}
/*After a migration first some basic jobs to ensure the system is up to date*/ /*After a migration first some basic jobs to ensure the system is up to date*/
VersionCheck::dispatch(); VersionCheck::dispatch();
CompanySizeCheck::dispatch(); CompanySizeCheck::dispatch();

View File

@ -88,14 +88,14 @@ class CreditEmailEngine extends BaseEmailEngine
->setViewText(ctrans('texts.view_credit')) ->setViewText(ctrans('texts.view_credit'))
->setInvitation($this->invitation); ->setInvitation($this->invitation);
if ($this->client->getSetting('pdf_email_attachment') !== false) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$this->setAttachments([$this->credit->pdf_file_path()]); $this->setAttachments([$this->credit->pdf_file_path()]);
// $this->setAttachments(['path' => $this->credit->pdf_file_path(), 'name' => basename($this->credit->pdf_file_path())]); // $this->setAttachments(['path' => $this->credit->pdf_file_path(), 'name' => basename($this->credit->pdf_file_path())]);
} }
//attach third party documents //attach third party documents
if($this->client->getSetting('document_email_attachment') !== false){ if($this->client->getSetting('document_email_attachment') !== false && $this->credit->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){
// Storage::url // Storage::url
foreach($this->credit->documents as $document){ foreach($this->credit->documents as $document){

View File

@ -12,6 +12,7 @@
namespace App\Mail\Engine; namespace App\Mail\Engine;
use App\DataMapper\EmailTemplateDefaults; use App\DataMapper\EmailTemplateDefaults;
use App\Models\Account;
use App\Utils\HtmlEngine; use App\Utils\HtmlEngine;
use App\Utils\Number; use App\Utils\Number;
@ -97,14 +98,14 @@ class InvoiceEmailEngine extends BaseEmailEngine
->setViewText(ctrans('texts.view_invoice')) ->setViewText(ctrans('texts.view_invoice'))
->setInvitation($this->invitation); ->setInvitation($this->invitation);
if ($this->client->getSetting('pdf_email_attachment') !== false) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$this->setAttachments([$this->invoice->pdf_file_path()]); $this->setAttachments([$this->invoice->pdf_file_path()]);
// $this->setAttachments(['path' => $this->invoice->pdf_file_path(), 'name' => basename($this->invoice->pdf_file_path())]); // $this->setAttachments(['path' => $this->invoice->pdf_file_path(), 'name' => basename($this->invoice->pdf_file_path())]);
} }
//attach third party documents //attach third party documents
if($this->client->getSetting('document_email_attachment') !== false){ if($this->client->getSetting('document_email_attachment') !== false && $this->invoice->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){
// Storage::url // Storage::url
foreach($this->invoice->documents as $document){ foreach($this->invoice->documents as $document){

View File

@ -89,14 +89,14 @@ class QuoteEmailEngine extends BaseEmailEngine
->setInvitation($this->invitation); ->setInvitation($this->invitation);
if ($this->client->getSetting('pdf_email_attachment') !== false) { if ($this->client->getSetting('pdf_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_PDF_ATTACHMENT)) {
$this->setAttachments([$this->quote->pdf_file_path()]); $this->setAttachments([$this->quote->pdf_file_path()]);
//$this->setAttachments(['path' => $this->quote->pdf_file_path(), 'name' => basename($this->quote->pdf_file_path())]); //$this->setAttachments(['path' => $this->quote->pdf_file_path(), 'name' => basename($this->quote->pdf_file_path())]);
} }
//attach third party documents //attach third party documents
if($this->client->getSetting('document_email_attachment') !== false){ if($this->client->getSetting('document_email_attachment') !== false && $this->quote->company->account->hasFeature(Account::FEATURE_DOCUMENTS)){
// Storage::url // Storage::url
foreach($this->quote->documents as $document){ foreach($this->quote->documents as $document){

View File

@ -74,7 +74,7 @@ class Gateway extends StaticModel
* Returns an array of methods and the gatewaytypes possible * Returns an array of methods and the gatewaytypes possible
* *
* @return array * @return array
*///todo remove methods replace with gatewaytype:: and then nest refund / token billing */
public function getMethods() public function getMethods()
{ {
switch ($this->id) { switch ($this->id) {

View File

@ -31,7 +31,7 @@ class DriverTemplate extends BaseDriver
GatewayType::CREDIT_CARD => CreditCard::class, //maps GatewayType => Implementation class GatewayType::CREDIT_CARD => CreditCard::class, //maps GatewayType => Implementation class
]; ];
const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; const SYSTEM_LOG_TYPE = SystemLog::TYPE_STRIPE; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
public function setPaymentMethod($payment_method_id) public function setPaymentMethod($payment_method_id)
{ {

View File

@ -11,6 +11,12 @@
namespace App\Services\BillingSubscription; namespace App\Services\BillingSubscription;
use App\DataMapper\InvoiceItem;
use App\Factory\InvoiceFactory;
use App\Models\ClientSubscription;
use App\Models\Product;
use App\Repositories\InvoiceRepository;
class BillingSubscriptionService class BillingSubscriptionService
{ {
@ -21,14 +27,75 @@ class BillingSubscriptionService
$this->billing_subscription = $billing_subscription; $this->billing_subscription = $billing_subscription;
} }
public function createInvoice($payment_hash) public function createInvoice($data)
{ {
//create the invoice if necessary ie. only is a payment was actually processed
$invoice_repo = new InvoiceRepository();
// $data = [
// 'client_id' =>,
// 'date' => Y-m-d,
// 'invitations' => [
// 'client_contact_id' => hashed_id
// ],
// 'line_items' => [],
// ];
$invoice = $invoice_repo->save($data, InvoiceFactory::create($billing_subscription->company_id, $billing_subscription->user_id));
/*
If trial_enabled -> return early
-- what we need to know that we don't already
-- Has a promo code been entered, and does it match
-- Is this a recurring subscription
--
1. Is this a recurring product?
2. What is the quantity? ie is this a multi seat product ( does this mean we need this value stored in the client sub?)
*/
return $invoice;
} }
public function createClientSubscription($payment_hash) private function createLineItems($quantity)
{
$line_items = [];
$product = $this->billing_subscription->product;
$item = new InvoiceItem;
$item->quantity = $quantity;
$item->product_key = $product->product_key;
$item->notes = $product->notes;
$item->cost = $product->price;
//$item->type_id need to switch whether the subscription is a service or product
$line_items[] = $item;
//do we have a promocode? enter this as a line item.
return $line_items;
}
private function convertInvoiceToRecurring()
{
//The first invoice is a plain invoice - the second is fired on the recurring schedule.
}
public function createClientSubscription($payment_hash, $recurring_invoice_id = null)
{ {
//create the client sub record //create the client sub record
//?trial enabled?
$cs = new ClientSubscription();
$cs->subscription_id = $this->billing_subscription->id;
$cs->company_id = $this->billing_subscription->company_id;
// client_id
$cs->save();
} }
public function triggerWebhook($payment_hash) public function triggerWebhook($payment_hash)

View File

@ -78,6 +78,7 @@ class AccountTransformer extends EntityTransformer
'is_docker' => (bool) config('ninja.is_docker'), 'is_docker' => (bool) config('ninja.is_docker'),
'is_scheduler_running' => (bool) $account->is_scheduler_running, 'is_scheduler_running' => (bool) $account->is_scheduler_running,
'default_company_id' => (string) $this->encodePrimaryKey($account->default_company_id), 'default_company_id' => (string) $this->encodePrimaryKey($account->default_company_id),
'disable_auto_update' => (bool) config('ninja.disable_auto_update'),
]; ];
} }

View File

@ -16,6 +16,7 @@ use App\Models\Client;
use App\Models\Document; use App\Models\Document;
use App\Models\Invoice; use App\Models\Invoice;
use App\Models\InvoiceInvitation; use App\Models\InvoiceInvitation;
use App\Models\Payment;
use App\Utils\Traits\MakesHash; use App\Utils\Traits\MakesHash;
class InvoiceTransformer extends EntityTransformer class InvoiceTransformer extends EntityTransformer
@ -30,7 +31,7 @@ class InvoiceTransformer extends EntityTransformer
protected $availableIncludes = [ protected $availableIncludes = [
// 'invitations', // 'invitations',
'history', 'history',
// 'payments', 'payments',
'client', 'client',
// 'documents', // 'documents',
]; ];
@ -56,15 +57,15 @@ class InvoiceTransformer extends EntityTransformer
return $this->includeItem($invoice->client, $transformer, Client::class); return $this->includeItem($invoice->client, $transformer, Client::class);
} }
public function includePayments(Invoice $invoice)
{
$transformer = new PaymentTransformer( $this->serializer);
return $this->includeCollection($invoice->payments, $transformer, Payment::class);
}
/* /*
public function includePayments(Invoice $invoice)
{
$transformer = new PaymentTransformer($this->account, $this->serializer, $invoice);
return $this->includeCollection($invoice->payments, $transformer, ENTITY_PAYMENT);
}
public function includeExpenses(Invoice $invoice) public function includeExpenses(Invoice $invoice)
{ {
$transformer = new ExpenseTransformer($this->account, $this->serializer); $transformer = new ExpenseTransformer($this->account, $this->serializer);

View File

@ -34,7 +34,7 @@ trait UserNotifies
array_push($required_permissions, 'all_user_notifications'); array_push($required_permissions, 'all_user_notifications');
} }
if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect($required_permissions, 'all_user_notifications')) >= 1 || count(array_intersect($required_permissions, 'all_notifications')) >= 1) { if (count(array_intersect($required_permissions, $notifications->email)) >= 1 || count(array_intersect($required_permissions, ['all_user_notifications'])) >= 1 || count(array_intersect($required_permissions, 'all_notifications')) >= 1) {
array_push($notifiable_methods, 'mail'); array_push($notifiable_methods, 'mail');
} }

View File

@ -19,6 +19,7 @@ trait SavesDocuments
{ {
public function saveDocuments($document_array, $entity, $is_public = true) public function saveDocuments($document_array, $entity, $is_public = true)
{ {
if ($entity instanceof Company) { if ($entity instanceof Company) {
$account = $entity->account; $account = $entity->account;
$company = $entity; $company = $entity;

View File

@ -71,7 +71,7 @@
"wildbit/swiftmailer-postmark": "^3.3" "wildbit/swiftmailer-postmark": "^3.3"
}, },
"require-dev": { "require-dev": {
"php": "^7.4", "php": "^7.3|^7.4",
"anahkiasen/former": "^4.2", "anahkiasen/former": "^4.2",
"barryvdh/laravel-debugbar": "^3.4", "barryvdh/laravel-debugbar": "^3.4",
"brianium/paratest": "^6.1", "brianium/paratest": "^6.1",

View File

@ -143,4 +143,5 @@ return [
'v4_migration_version' => '4.5.31', 'v4_migration_version' => '4.5.31',
'flutter_canvas_kit' => env('FLUTTER_CANVAS_KIT', false), 'flutter_canvas_kit' => env('FLUTTER_CANVAS_KIT', false),
'webcron_secret' => env('WEBCRON_SECRET', false), 'webcron_secret' => env('WEBCRON_SECRET', false),
'disable_auto_update' => env('DISABLE_AUTO_UPDATE', false),
]; ];

View File

@ -30,7 +30,7 @@ const RESOURCES = {
"assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "3e722fd57a6db80ee119f0e2c230ccff", "assets/packages/material_design_icons_flutter/lib/fonts/materialdesignicons-webfont.ttf": "3e722fd57a6db80ee119f0e2c230ccff",
"assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f", "assets/FontManifest.json": "cf3c681641169319e61b61bd0277378f",
"/": "23224b5e03519aaa87594403d54412cf", "/": "23224b5e03519aaa87594403d54412cf",
"main.dart.js": "0c23e414413fb1fc8aa4a898cd035a38", "main.dart.js": "57f8c85038156cb9798fe4f15263a6dc",
"version.json": "b7c8971e1ab5b627fd2a4317c52b843e", "version.json": "b7c8971e1ab5b627fd2a4317c52b843e",
"favicon.png": "dca91c54388f52eded692718d5a98b8b" "favicon.png": "dca91c54388f52eded692718d5a98b8b"
}; };

174976
public/main.dart.js vendored

File diff suppressed because one or more lines are too long

View File

@ -4160,13 +4160,16 @@ $LANG = array(
'security_settings' => 'Security Settings', 'security_settings' => 'Security Settings',
'resend_email' => 'Resend Email', 'resend_email' => 'Resend Email',
'confirm_your_email_address' => 'Please confirm your email address', 'confirm_your_email_address' => 'Please confirm your email address',
'freshbooks' => 'FreshBooks', 'freshbooks' => 'FreshBooks',
'invoice2go' => 'Invoice2go', 'invoice2go' => 'Invoice2go',
'invoicely' => 'Invoicely', 'invoicely' => 'Invoicely',
'waveaccounting' => 'Wave Accounting', 'waveaccounting' => 'Wave Accounting',
'zoho' => 'Zoho', 'zoho' => 'Zoho',
'accounting' => 'Accounting', 'accounting' => 'Accounting',
'required_files_missing' => 'Please provide all CSVs.', 'required_files_missing' => 'Please provide all CSVs.',
'migration_auth_label' => 'Let\'s continue by authenticating.',
'api_secret' => 'API secret',
'migration_api_secret_notice' => 'You can find API_SECRET in the .env file or Invoice Ninja v5. If property is missing, leave field blank.',
); );
return $LANG; return $LANG;

View File

@ -10,7 +10,7 @@
<br> <br>
<br> <br>
<p> <p>
{{ $signature }} {!! $signature !!}
</p> </p>
@endif @endif

View File

@ -10,7 +10,7 @@
<br> <br>
<br> <br>
<p> <p>
{{ $signature }} {!! $signature !!}
</p> </p>
@endif @endif

View File

@ -27,7 +27,7 @@
@if($signature) @if($signature)
<tr> <tr>
<td> <td>
<p>{{ $signature }}</p> <p>{!! $signature !!}</p>
</td> </td>
</tr> </tr>
@endif @endif