Merge pull request #5603 from turbo124/v5-stable

v5.1.60
This commit is contained in:
David Bomba 2021-05-04 22:51:07 +10:00 committed by GitHub
commit e6482064eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 486 additions and 92 deletions

4
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,4 @@
# Invoice Ninja Code of Conduct
The development team has invested a tremendous amount of time and energy into this project. While we appreciate that bugs can be frustrating we ask that our community refrain from insults and snide remarks. We're happy to provide support to both our hosted and selfhosted communities but ask that feedback is always polite.

View File

@ -1 +1 @@
5.1.59 5.1.60

View File

@ -0,0 +1,120 @@
<?php
namespace App\Console\Commands;
use App\Models\Company;
use App\Models\User;
use App\Utils\CurlUtils;
use Illuminate\Console\Command;
class MobileLocalization extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ninja:mobile-localization {--type=}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Generate mobile localization resources';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$type = strtolower($this->option('type'));
switch ($type) {
case 'laravel':
$this->laravelResources();
break;
default:
$this->flutterResources();
break;
}
}
private function laravelResources()
{
$resources = $this->getResources();
foreach ($resources as $key => $val) {
$transKey = "texts.{$key}";
if (trans($transKey) == $transKey) {
echo "'$key' => '$val',\n";
}
}
}
private function flutterResources()
{
$languages = cache('languages');
$resources = $this->getResources();
foreach ($languages as $language) {
if ($language->locale == 'en') {
continue;
}
echo "'{$language->locale}': {\n";
foreach ($resources as $key => $val) {
$text = trim(addslashes(trans("texts.{$key}", [], $language->locale)));
if (substr($text, 0, 6) == 'texts.') {
$text = $resources->$key;
}
$text = str_replace(array('<b>', '</b>'), '', $text);
$text = str_replace(array('<i>', '</i>'), '', $text);
$text = str_replace(array('<strong>', '</strong>'), '', $text);
echo "'$key': '$text',\n";
}
echo "},\n";
}
}
private function getResources()
{
$url = 'https://raw.githubusercontent.com/invoiceninja/flutter-client/develop/lib/utils/i18n.dart';
$data = CurlUtils::get($url);
$start = strpos($data, 'do not remove comment') + 25;
$end = strpos($data, '},', $start);
$data = substr($data, $start, $end - $start - 5);
$data = str_replace("\n", "", $data);
$data = str_replace("\"", "\'", $data);
$data = str_replace("'", "\"", $data);
return json_decode('{' . rtrim($data, ',') . '}');
}
protected function getOptions()
{
return [
['type', null, InputOption::VALUE_OPTIONAL, 'Type', null],
];
}
}

View File

@ -0,0 +1,77 @@
<?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://opensource.org/licenses/AAL
*/
namespace App\DataMapper\Analytics\Mail;
class EmailBounce
{
/**
* The type of Sample.
*
* Monotonically incrementing counter
*
* - counter
*
* @var string
*/
public $type = 'mixed_metric';
/**
* The name of the counter.
* @var string
*/
public $name = 'job.bounce.email';
/**
* The datetime of the counter measurement.
*
* date("Y-m-d H:i:s")
*
* @var DateTime
*/
public $datetime;
/**
* The Class failure name
* set to 0.
*
* @var string
*/
public $string_metric5 = 'tag';
/**
* The exception string
* set to 0.
*
* @var string
*/
public $string_metric6 = 'from';
/**
* Company Key
* @var string
*/
public $string_metric7 = 'messageid';
/**
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;
public function __construct($string_metric5,$string_metric6,$string_metric7) {
$this->string_metric5 = $string_metric5;
$this->string_metric6 = $string_metric6;
$this->string_metric7 = $string_metric7;
}
}

View File

@ -0,0 +1,77 @@
<?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://opensource.org/licenses/AAL
*/
namespace App\DataMapper\Analytics\Mail;
class EmailSpam
{
/**
* The type of Sample.
*
* Monotonically incrementing counter
*
* - counter
*
* @var string
*/
public $type = 'mixed_metric';
/**
* The name of the counter.
* @var string
*/
public $name = 'job.spam.email';
/**
* The datetime of the counter measurement.
*
* date("Y-m-d H:i:s")
*
* @var DateTime
*/
public $datetime;
/**
* The Class failure name
* set to 0.
*
* @var string
*/
public $string_metric5 = 'tag';
/**
* The exception string
* set to 0.
*
* @var string
*/
public $string_metric6 = 'from';
/**
* Company Key
* @var string
*/
public $string_metric7 = 'messageid';
/**
* The counter
* set to 1.
*
* @var string
*/
public $int_metric1 = 1;
public function __construct($string_metric5,$string_metric6,$string_metric7) {
$this->string_metric5 = $string_metric5;
$this->string_metric6 = $string_metric6;
$this->string_metric7 = $string_metric7;
}
}

View File

@ -14,12 +14,14 @@ namespace App\Http\Controllers;
use App\Http\Requests\Activity\DownloadHistoricalEntityRequest; use App\Http\Requests\Activity\DownloadHistoricalEntityRequest;
use App\Models\Activity; use App\Models\Activity;
use App\Transformers\ActivityTransformer; use App\Transformers\ActivityTransformer;
use App\Utils\HostedPDF\NinjaPdf;
use App\Utils\PhantomJS\Phantom;
use App\Utils\Traits\Pdf\PdfMaker; use App\Utils\Traits\Pdf\PdfMaker;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use stdClass;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
use stdClass;
class ActivityController extends BaseController class ActivityController extends BaseController
{ {
@ -139,7 +141,15 @@ class ActivityController extends BaseController
return response()->json(['message'=> ctrans('texts.no_backup_exists'), 'errors' => new stdClass], 404); return response()->json(['message'=> ctrans('texts.no_backup_exists'), 'errors' => new stdClass], 404);
} }
if (config('ninja.phantomjs_pdf_generation')) {
$pdf = (new Phantom)->convertHtmlToPdf($backup->html_backup);
}
elseif(config('ninja.invoiceninja_hosted_pdf_generation')){
$pdf = (new NinjaPdf())->build($backup->html_backup);
}
else {
$pdf = $this->makePdf(null, null, $backup->html_backup); $pdf = $this->makePdf(null, null, $backup->html_backup);
}
if (isset($activity->invoice_id)) { if (isset($activity->invoice_id)) {
$filename = $activity->invoice->numberFormatter().'.pdf'; $filename = $activity->invoice->numberFormatter().'.pdf';

View File

@ -395,7 +395,8 @@ class BaseController extends Controller
'company' => function ($query) use ($created_at, $user) { 'company' => function ($query) use ($created_at, $user) {
$query->whereNotNull('created_at')->with('documents'); $query->whereNotNull('created_at')->with('documents');
}, },
'company.clients' => function ($query) use ($user) { 'company.clients' => function ($query) use ($created_at, $user) {
$query->where('clients.created_at', '>=', $created_at)->with('contacts.company', 'gateway_tokens', 'documents');
if(!$user->hasPermission('view_client')) if(!$user->hasPermission('view_client'))
$query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id); $query->where('clients.user_id', $user->id)->orWhere('clients.assigned_user_id', $user->id);

View File

@ -50,6 +50,8 @@ class InvoiceController extends Controller
{ {
set_time_limit(0); set_time_limit(0);
$invoice->service()->removeUnpaidGatewayFees()->save();
$data = [ $data = [
'invoice' => $invoice, 'invoice' => $invoice,
]; ];

View File

@ -97,6 +97,10 @@ class PaymentController extends Controller
$payable_invoices = collect($request->payable_invoices); $payable_invoices = collect($request->payable_invoices);
$invoices = Invoice::whereIn('id', $this->transformKeys($payable_invoices->pluck('invoice_id')->toArray()))->get(); $invoices = Invoice::whereIn('id', $this->transformKeys($payable_invoices->pluck('invoice_id')->toArray()))->get();
$invoices->each(function($invoice){
$invoice->service()->removeUnpaidGatewayFees()->save();
});
/* pop non payable invoice from the $payable_invoices array */ /* pop non payable invoice from the $payable_invoices array */
$payable_invoices = $payable_invoices->filter(function ($payable_invoice) use ($invoices) { $payable_invoices = $payable_invoices->filter(function ($payable_invoice) use ($invoices) {

View File

@ -18,6 +18,7 @@ use App\Jobs\Mail\NinjaMailerJob;
use App\Jobs\Mail\NinjaMailerObject; use App\Jobs\Mail\NinjaMailerObject;
use App\Jobs\Util\StartMigration; use App\Jobs\Util\StartMigration;
use App\Mail\ExistingMigration; use App\Mail\ExistingMigration;
use App\Mail\Migration\MaxCompanies;
use App\Models\Company; use App\Models\Company;
use App\Models\CompanyToken; use App\Models\CompanyToken;
use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Bus\DispatchesJobs;
@ -231,19 +232,51 @@ class MigrationController extends BaseController
nlog($request->all()); nlog($request->all());
} }
try {
return response()->json([
'_id' => Str::uuid(),
'method' => config('queue.default'),
'started_at' => now(),
], 200);
} finally {
// Controller logic here
foreach ($companies as $company) { foreach ($companies as $company) {
$is_valid = $request->file($company->company_index)->isValid(); $is_valid = $request->file($company->company_index)->isValid();
if (!$is_valid) { if (!$is_valid) {
// We might want to send user something's wrong with migration or nope?
continue; continue;
} }
$user = auth()->user(); $user = auth()->user();
$company_count = $user->account->companies()->count();
// Look for possible existing company (based on company keys). // Look for possible existing company (based on company keys).
$existing_company = Company::whereRaw('BINARY `company_key` = ?', [$company->company_key])->first(); $existing_company = Company::whereRaw('BINARY `company_key` = ?', [$company->company_key])->first();
if(!$existing_company && $company_count >=10) {
$nmo = new NinjaMailerObject;
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
return;
}
elseif($existing_company && $company_count > 10 ){
$nmo = new NinjaMailerObject;
$nmo->mailable = new MaxCompanies($user->account->companies()->first());
$nmo->company = $user->account->companies()->first();
$nmo->settings = $user->account->companies()->first()->settings;
$nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo);
return;
}
$checks = [ $checks = [
'existing_company' => $existing_company ? (bool)1 : false, 'existing_company' => $existing_company ? (bool)1 : false,
'force' => property_exists($company, 'force') ? (bool) $company->force : false, 'force' => property_exists($company, 'force') ? (bool) $company->force : false,
@ -254,9 +287,9 @@ class MigrationController extends BaseController
nlog('Migrating: Existing company without force. (CASE_01)'); nlog('Migrating: Existing company without force. (CASE_01)');
$nmo = new NinjaMailerObject; $nmo = new NinjaMailerObject;
$nmo->mailable = new ExistingMigration(); $nmo->mailable = new ExistingMigration($existing_company);
$nmo->company = $existing_company; $nmo->company = $user->account->companies()->first();
$nmo->settings = $existing_company->settings; $nmo->settings = $user->account->companies()->first();
$nmo->to_user = $user; $nmo->to_user = $user;
NinjaMailerJob::dispatch($nmo); NinjaMailerJob::dispatch($nmo);
@ -355,10 +388,7 @@ class MigrationController extends BaseController
// } // }
} }
return response()->json([ }
'_id' => Str::uuid(),
'method' => config('queue.default'),
'started_at' => now(),
], 200);
} }
} }

View File

@ -11,6 +11,8 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\DataMapper\Analytics\EmailBounce;
use App\DataMapper\Analytics\EmailSpam;
use App\Jobs\Util\SystemLogger; use App\Jobs\Util\SystemLogger;
use App\Libraries\MultiDB; use App\Libraries\MultiDB;
use App\Models\CreditInvitation; use App\Models\CreditInvitation;
@ -19,6 +21,7 @@ use App\Models\QuoteInvitation;
use App\Models\RecurringInvoiceInvitation; use App\Models\RecurringInvoiceInvitation;
use App\Models\SystemLog; use App\Models\SystemLog;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Turbo124\Beacon\Facades\LightLogs;
/** /**
* Class PostMarkController. * Class PostMarkController.
@ -71,8 +74,7 @@ class PostMarkController extends BaseController
if($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('postmark.secret')) if($request->header('X-API-SECURITY') && $request->header('X-API-SECURITY') == config('postmark.secret'))
{ {
// nlog($request->all());
nlog($request->all());
MultiDB::findAndSetDbByCompanyKey($request->input('Tag')); MultiDB::findAndSetDbByCompanyKey($request->input('Tag'));
@ -157,6 +159,14 @@ class PostMarkController extends BaseController
$this->invitation->email_status = 'bounced'; $this->invitation->email_status = 'bounced';
$this->invitation->save(); $this->invitation->save();
$bounce = new EmailBounce(
$request->input('Tag'),
$request->input('From'),
$request->input('MessageID')
);
LightLogs::create($bounce)->batch();
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client); SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_BOUNCED, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
} }
@ -191,6 +201,14 @@ class PostMarkController extends BaseController
$this->invitation->email_status = 'spam'; $this->invitation->email_status = 'spam';
$this->invitation->save(); $this->invitation->save();
$spam = new EmailSpam(
$request->input('Tag'),
$request->input('From'),
$request->input('MessageID')
);
LightLogs::create($bounce)->batch();
SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client); SystemLogger::dispatch($request->all(), SystemLog::CATEGORY_MAIL, SystemLog::EVENT_MAIL_SPAM_COMPLAINT, SystemLog::TYPE_WEBHOOK_RESPONSE, $this->invitation->contact->client);
} }

View File

@ -31,6 +31,7 @@ use App\Factory\VendorFactory;
use App\Http\Requests\Company\UpdateCompanyRequest; use App\Http\Requests\Company\UpdateCompanyRequest;
use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule; use App\Http\ValidationRules\ValidCompanyGatewayFeesAndLimitsRule;
use App\Http\ValidationRules\ValidUserForCompany; use App\Http\ValidationRules\ValidUserForCompany;
use App\Jobs\Company\CreateCompanyTaskStatuses;
use App\Jobs\Company\CreateCompanyToken; use App\Jobs\Company\CreateCompanyToken;
use App\Jobs\Ninja\CheckCompanyData; use App\Jobs\Ninja\CheckCompanyData;
use App\Jobs\Ninja\CompanySizeCheck; use App\Jobs\Ninja\CompanySizeCheck;
@ -82,10 +83,10 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\UploadedFile; use Illuminate\Http\UploadedFile;
use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Validator; use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use Turbo124\Beacon\Facades\LightLogs; use Turbo124\Beacon\Facades\LightLogs;
use Illuminate\Support\Facades\Mail;
class Import implements ShouldQueue class Import implements ShouldQueue
{ {
@ -230,6 +231,9 @@ class Import implements ShouldQueue
$this->company->save(); $this->company->save();
} }
// CreateCompanyPaymentTerms::dispatchNow($sp035a66, $spaa9f78);
CreateCompanyTaskStatuses::dispatchNow($this->company, $this->user);
info('Completed🚀🚀🚀🚀🚀 at '.now()); info('Completed🚀🚀🚀🚀🚀 at '.now());
unlink($this->file_path); unlink($this->file_path);

View File

@ -109,7 +109,7 @@ class StartMigration implements ShouldQueue
throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.'); throw new NonExistingMigrationFile('Migration file does not exist, or it is corrupted.');
} }
Import::dispatchNow($file, $this->company, $this->user)->onQueue('migration'); Import::dispatchNow($file, $this->company, $this->user);
Storage::deleteDirectory(public_path("storage/migrations/{$filename}")); Storage::deleteDirectory(public_path("storage/migrations/{$filename}"));

View File

@ -62,20 +62,20 @@ class EntityCreatedObject
switch ($this->entity_type) { switch ($this->entity_type) {
case 'invoice': case 'invoice':
$this->template_subject = "texts.notification_invoice_created_subject"; $this->template_subject = "texts.notification_invoice_created_subject";
$this->template_body = "texts.notification_invoice_sent"; $this->template_body = "texts.notification_invoice_created_body";
break; break;
case 'quote': case 'quote':
$this->template_subject = "texts.notification_quote_created_subject"; $this->template_subject = "texts.notification_quote_created_subject";
$this->template_body = "texts.notification_quote_sent"; $this->template_body = "texts.notification_quote_created_body";
break; break;
case 'credit': case 'credit':
$this->template_subject = "texts.notification_credit_created_subject"; $this->template_subject = "texts.notification_credit_created_subject";
$this->template_body = "texts.notification_credit_sent"; $this->template_body = "texts.notification_credit_created_body";
break; break;
default: default:
$this->template_subject = "texts.notification_invoice_created_subject"; $this->template_subject = "texts.notification_invoice_created_subject";
$this->template_body = "texts.notification_invoice_sent"; $this->template_body = "texts.notification_invoice_created_body";
break; break;
} }
} }

View File

@ -10,14 +10,22 @@ class ExistingMigration extends Mailable
{ {
// use Queueable, SerializesModels; // use Queueable, SerializesModels;
public $company;
public $settings;
public $logo;
public $company_name;
/** /**
* Create a new message instance. * Create a new message instance.
* *
* @return void * @return void
*/ */
public function __construct() public function __construct($company)
{ {
// $this->company = $company;
} }
/** /**
@ -27,8 +35,11 @@ class ExistingMigration extends Mailable
*/ */
public function build() public function build()
{ {
return $this->from(config('mail.from.address'), config('mail.from.name')) $this->settings = $this->company->settings;
$this->logo = $this->company->present()->logo();
$this->company_name = $this->company->present()->name();
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.existing'); ->view('email.migration.existing');
} }
} }

View File

@ -0,0 +1,51 @@
<?php
namespace App\Mail\Migration;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
class MaxCompanies extends Mailable
{
// use Queueable, SerializesModels;
public $company;
public $settings;
public $logo;
public $title;
public $message;
public $whitelabel;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($company)
{
$this->company = $company;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
$this->settings = $this->company->settings;
$this->logo = $this->company->present()->logo();
$this->title = ctrans('texts.max_companies');
$this->message = ctrans('texts.max_companies_desc');
$this->whitelabel = $this->company->account->isPaid();
return $this->from(config('mail.from.address'), config('mail.from.name'))
->view('email.migration.max_companies');
}
}

View File

@ -79,8 +79,9 @@ class Client extends BaseModel implements HasLocalePreference
protected $with = [ protected $with = [
'gateway_tokens', 'gateway_tokens',
'documents' 'documents',
//'currency', 'contacts.company',
// 'currency',
// 'primary_contact', // 'primary_contact',
// 'country', // 'country',
// 'contacts', // 'contacts',

View File

@ -65,6 +65,7 @@ class CompanyGateway extends BaseModel
'3758e7f7c6f4cecf0f4f348b9a00f456' => 304, '3758e7f7c6f4cecf0f4f348b9a00f456' => 304,
'3b6621f970ab18887c4f6dca78d3f8bb' => 305, '3b6621f970ab18887c4f6dca78d3f8bb' => 305,
'54faab2ab6e3223dbe848b1686490baa' => 306, '54faab2ab6e3223dbe848b1686490baa' => 306,
'd14dd26a47cecc30fdd65700bfb67b34' => 301,
]; ];
protected $touches = []; protected $touches = [];
@ -225,7 +226,7 @@ class CompanyGateway extends BaseModel
{ {
$config = $this->getConfig(); $config = $this->getConfig();
if ($this->gateway->provider == 'Stripe' && strpos($config->publishableKey, 'test')) { if ($this->gateway->provider == 'Stripe' && property_exists($config, 'publishableKey') && strpos($config->publishableKey, 'test')) {
return true; return true;
} }

View File

@ -85,6 +85,7 @@ class Gateway extends StaticModel
return [GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]]; //Paypal return [GatewayType::PAYPAL => ['refund' => true, 'token_billing' => false]]; //Paypal
break; break;
case 20: case 20:
case 56:
return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true], return [GatewayType::CREDIT_CARD => ['refund' => true, 'token_billing' => true],
GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable']], GatewayType::BANK_TRANSFER => ['refund' => true, 'token_billing' => true, 'webhooks' => ['source.chargeable']],
GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false], GatewayType::ALIPAY => ['refund' => false, 'token_billing' => false],

View File

@ -27,7 +27,8 @@ class ClientPresenter extends EntityPresenter
return $this->entity->name; return $this->entity->name;
} }
$contact = $this->entity->primary_contact->first(); //$contact = $this->entity->primary_contact->first();
$contact = $this->entity->contacts->first();
$contact_name = 'No Contact Set'; $contact_name = 'No Contact Set';

View File

@ -107,35 +107,7 @@ class InvoiceMigrationRepository extends BaseRepository
InvoiceInvitation::reguard(); InvoiceInvitation::reguard();
RecurringInvoiceInvitation::reguard(); RecurringInvoiceInvitation::reguard();
/*
if (isset($data['invitations'])) {
$invitations = collect($data['invitations']);
$model->invitations->pluck('key')->diff($invitations->pluck('key'))->each(function ($invitation) use ($resource) {
$this->getInvitation($invitation, $resource)->delete();
});
foreach ($data['invitations'] as $invitation) {
//if no invitations are present - create one.
if (! $this->getInvitation($invitation, $resource)) {
if (isset($invitation['id'])) {
unset($invitation['id']);
}
//make sure we are creating an invite for a contact who belongs to the client only!
$contact = ClientContact::find($invitation['client_contact_id']);
if ($contact && $model->client_id == $contact->client_id) {
$new_invitation = $invitation_factory_class::create($model->company_id, $model->user_id);
$new_invitation->{$lcfirst_resource_id} = $model->id;
$new_invitation->client_contact_id = $contact->id;
$new_invitation->save();
}
}
}
}
*/
$model->load('invitations'); $model->load('invitations');
/* If no invitations have been created, this is our fail safe to maintain state*/ /* If no invitations have been created, this is our fail safe to maintain state*/
@ -152,8 +124,6 @@ class InvoiceMigrationRepository extends BaseRepository
if ($class->name == Invoice::class || $class->name == RecurringInvoice::class) { if ($class->name == Invoice::class || $class->name == RecurringInvoice::class) {
if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) { if (($state['finished_amount'] != $state['starting_amount']) && ($model->status_id != Invoice::STATUS_DRAFT)) {
// $model->ledger()->updateInvoiceBalance(($state['finished_amount'] - $state['starting_amount']));
// $model->client->service()->updateBalance(($state['finished_amount'] - $state['starting_amount']))->save();
} }
if (! $model->design_id) { if (! $model->design_id) {
@ -162,7 +132,7 @@ class InvoiceMigrationRepository extends BaseRepository
if ($model->company->update_products) { if ($model->company->update_products) {
UpdateOrCreateProduct::dispatchNow($model->line_items, $model, $model->company); //UpdateOrCreateProduct::dispatchNow($model->line_items, $model, $model->company);
} }
} }

View File

@ -110,6 +110,7 @@ class InvoiceService
public function addGatewayFee(CompanyGateway $company_gateway, $gateway_type_id, float $amount) public function addGatewayFee(CompanyGateway $company_gateway, $gateway_type_id, float $amount)
{ {
$this->invoice = (new AddGatewayFee($company_gateway, $gateway_type_id, $this->invoice, $amount))->run(); $this->invoice = (new AddGatewayFee($company_gateway, $gateway_type_id, $this->invoice, $amount))->run();
return $this; return $this;

View File

@ -14,8 +14,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.1.59', 'app_version' => '5.1.60',
'app_tag' => '5.1.59-release', 'app_tag' => '5.1.60-release',
'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', false), 'api_secret' => env('API_SECRET', false),

View File

@ -30,8 +30,8 @@ class StripeConnectGateway extends Migration
Gateway::create($gateway); Gateway::create($gateway);
if (Ninja::isNinja()) { if (Ninja::isNinja()) {
Gateway::where('id', 20)->update(['visible' => 0]); Gateway::whereIn('id', [20])->update(['visible' => 0]);
Gateway::where('id', 56)->update(['visible' => 1]); Gateway::whereIn('id', [56])->update(['visible' => 1]);
} }
} }

View File

@ -4229,12 +4229,17 @@ $LANG = array(
'amount_greater_than_balance_v5' => 'The amount is greater than the invoice balance. You cannot overpay an invoice.', 'amount_greater_than_balance_v5' => 'The amount is greater than the invoice balance. You cannot overpay an invoice.',
'click_to_continue' => 'Click to continue', 'click_to_continue' => 'Click to continue',
'notification_invoice_created_subject' => 'Invoice :invoice was created to :client', 'notification_invoice_created_body' => 'The following invoice :invoice was created for client :client for :amount.',
'notification_invoice_created_subject' => 'Invoice :invoice was created for :client', 'notification_invoice_created_subject' => 'Invoice :invoice was created for :client',
'notification_quote_created_subject' => 'Quote :invoice was created to :client', 'notification_quote_created_body' => 'The following quote :invoice was created for client :client for :amount.',
'notification_quote_created_subject' => 'Quote :invoice was created for :client', 'notification_quote_created_subject' => 'Quote :invoice was created for :client',
'notification_credit_created_subject' => 'Credit :invoice was created to :client', 'notification_credit_created_body' => 'The following credit :invoice was created for client :client for :amount.',
'notification_credit_created_subject' => 'Credit :invoice was created for :client', 'notification_credit_created_subject' => 'Credit :invoice was created for :client',
'max_companies' => 'Maximum companies migrated',
'max_companies_desc' => 'You have reached your maximum number of companies. Delete existing companies to migrate new ones.',
'migration_already_completed' => 'Company already migrated',
'migration_already_completed_desc' => 'Looks like you already migrated <b> :company_name </b>to the V5 version of the Invoice Ninja. In case you want to start over, you can force migrate to wipe existing data.',
); );
return $LANG; return $LANG;

View File

@ -1,31 +1,18 @@
@component('email.template.master', ['design' => 'light', 'settings' => $settings]) @component('email.template.master', ['design' => 'light', 'settings' => $settings])
@slot('header') @slot('header')
@component('email.components.header') @include('email.components.header', ['logo' => $logo])
Migration already completed @endslot
@endcomponent
@endslot
@slot('greeting') <h2>{{ctrans('texts.migration_already_completed')}}</h2>
Hello,
@endslot
Looks like you already migrated your data to V2 version of the Invoice Ninja. In case you want to start over, you can 'force' migrate to wipe existing data. <p>{{ctrans('texts.migration_already_completed_desc', ['company_name' => $company_name])}}</p>
@component('email.components.button', ['url' => url('/')]) @if(isset($whitelabel) && !$whitelabel)
Visit portal @slot('footer')
@endcomponent
@slot('signature')
Thank you, <br>
Invoice Ninja
@endslot
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja']) @component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja. For any info, please visit InvoiceNinja.
@endcomponent @endcomponent
@endslot @endslot
@endif
@endcomponent @endcomponent

View File

@ -0,0 +1,18 @@
@component('email.template.master', ['design' => 'light', 'settings' => $settings])
@slot('header')
@include('email.components.header', ['logo' => $logo])
@endslot
<h2>{{ctrans('texts.max_companies')}}</h2>
<p>{{ctrans('texts.max_companies_desc')}}</p>
@if(isset($whitelabel) && !$whitelabel)
@slot('footer')
@component('email.components.footer', ['url' => 'https://invoiceninja.com', 'url_text' => '&copy; InvoiceNinja'])
For any info, please visit InvoiceNinja.
@endcomponent
@endslot
@endif
@endcomponent