1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 13:12:50 +01:00

Merge pull request #6944 from turbo124/v5-develop

Fixes for User Add rules in hosted
This commit is contained in:
David Bomba 2021-11-09 21:15:35 +11:00 committed by GitHub
commit c5516fcb87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 235 additions and 88 deletions

View File

@ -51,9 +51,9 @@ class RecurringExpenseToExpenseFactory
$expense->payment_type_id = $recurring_expense->payment_type_id;
$expense->project_id = $recurring_expense->project_id;
$expense->invoice_documents = $recurring_expense->invoice_documents;
$expense->tax_amount1 = $recurring_expense->tax_amount1;
$expense->tax_amount2 = $recurring_expense->tax_amount2;
$expense->tax_amount3 = $recurring_expense->tax_amount3;
$expense->tax_amount1 = $recurring_expense->tax_amount1 ?: 0;
$expense->tax_amount2 = $recurring_expense->tax_amount2 ?: 0;
$expense->tax_amount3 = $recurring_expense->tax_amount3 ?: 0;
$expense->uses_inclusive_taxes = $recurring_expense->uses_inclusive_taxes;
$expense->calculate_tax_by_amount = $recurring_expense->calculate_tax_by_amount;

View File

@ -80,7 +80,10 @@ class InvitationController extends Controller
$query->where('is_deleted',0);
})
->with('contact.client')
->firstOrFail();
->first();
if(!$invitation)
return abort(404,'The resource is no longer available.');
/* Return early if we have the correct client_hash embedded */
$client_contact = $invitation->contact;

View File

@ -13,8 +13,12 @@ namespace App\Http\Controllers;
use App\Jobs\Account\CreateAccount;
use App\Libraries\MultiDB;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Company;
use App\Models\CompanyToken;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
class HostedMigrationController extends Controller
{
@ -49,4 +53,39 @@ class HostedMigrationController extends Controller
}
public function confirmForwarding(Request $request)
{
if($request->header('X-API-HOSTED-SECRET') != config('ninja.ninja_hosted_secret'))
return;
$input = $request->all();
MultiDB::findAndSetDbByCompanyKey($input['account_key']);
$company = Company::with('account')->where('company_key', $input['account_key'])->first();
$account = $company->account;
$client_id = false;
if($contact = ClientContact::on('db-ninja-01')->where(['email' => $input['email'], 'company_id' => config('ninja.ninja_default_company_id')])->first()){
$client_id = $contact->client_id;
}
else if($client = Client::on('db-ninja-01')->where(['custom_value2' => $account->key, 'company_id' => config('ninja.ninja_default_company_id')])->first()){
$client_id = $client->id;
}
//get ninja client_id;
if(strlen($input['gateway_reference']) >1 && $client_id){
Artisan::call('ninja:add-token', [
'--customer' => $input['gateway_reference'], '--client_id' => 1
]);
}
$forward_url = $company->domain();
return response()->json(['forward_url' => $forward_url], 200);
}
}

View File

@ -522,6 +522,9 @@ class InvoiceController extends BaseController
$ids = request()->input('ids');
nlog($action);
nlog($ids);
$invoices = Invoice::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get();
if (! $invoices) {
@ -532,13 +535,14 @@ class InvoiceController extends BaseController
* Download Invoice/s
*/
if ($action == 'download' && $invoices->count() > 1) {
if ($action == 'bulk_download' && $invoices->count() > 1) {
$invoices->each(function ($invoice) {
if (auth()->user()->cannot('view', $invoice)) {
nlog("access denied");
return response()->json(['message' => ctrans('text.access_denied')]);
}
});
nlog("bulky");
ZipInvoices::dispatch($invoices, $invoices->first()->company, auth()->user());
return response()->json(['message' => ctrans('texts.sent_message')], 200);
@ -713,13 +717,13 @@ class InvoiceController extends BaseController
$this->itemResponse($invoice);
}
break;
case 'reverse':
$invoice = $invoice->service()->handleReversal()->deletePdf()->save();
// case 'reverse':
// $invoice = $invoice->service()->handleReversal()->deletePdf()->save();
if (! $bulk) {
$this->itemResponse($invoice);
}
break;
// if (! $bulk) {
// $this->itemResponse($invoice);
// }
// break;
case 'email':
//check query parameter for email_type and set the template else use calculateTemplate

View File

@ -217,8 +217,6 @@ class PreviewController extends BaseController
if(!$request->has('entity_id'))
$entity_obj->service()->fillDefaults()->save();
// $entity_obj->load('client.contacts','client.company');
App::forgetInstance('translator');
$t = app('translator');
App::setLocale($entity_obj->client->locale());

View File

@ -31,6 +31,7 @@ class SubdomainController extends BaseController
'cname',
'sandbox',
'stage',
'html',
];
public function __construct()

View File

@ -26,6 +26,8 @@ use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use App\DataMapper\ClientSettings;
use Livewire\Component;
class BillingPortalPurchase extends Component
@ -241,7 +243,8 @@ class BillingPortalPurchase extends Component
'contacts' => [
['email' => $this->email],
],
'settings' => [],
'client_hash' => Str::random(40),
'settings' => ClientSettings::defaults(),
];
foreach ($this->request_data as $field => $value) {

View File

@ -74,7 +74,7 @@ class SetInviteDb
if (request()->json) {
return response()->json($error, 403);
} else {
abort(404,'I could not find the database for this object.');
abort(404,'I could not find this resource.');
}
}

View File

@ -33,25 +33,16 @@ class CanAddUserRule implements Rule
public function passes($attribute, $value)
{
// $count = CompanyUser::query()
// ->with('user')
// ->where('account_id', auth()->user()->account_id)
// ->distinct()
// ->select('user_id')
// ->count();
$count = User::query()
->with(['company_user' => function ($query){
return $query->whereNull('company_user.deleted_at');
}])
->where('account_id', auth()->user()->account_id)
->distinct()
->select('users.id')
->count();
$count = CompanyUser::query()
->where('company_user.account_id', auth()->user()->account_id)
->join('users', 'users.id', '=', 'company_user.user_id')
->whereNull('users.deleted_at')
->whereNull('company_user.deleted_at')
->distinct()
->count('company_user.user_id');
return $count < auth()->user()->company()->account->num_users;
//return auth()->user()->company()->account->users->count() < auth()->user()->company()->account->num_users;
}
/**

View File

@ -33,17 +33,16 @@ class CanRestoreUserRule implements Rule
public function passes($attribute, $value)
{
$count = User::query()
->with(['company_user' => function ($query){
return $query->whereNull('company_user.deleted_at');
}])
->where('account_id', 1)
->distinct()
->select('users.id')
->count();
$count = CompanyUser::query()
->where('company_user.account_id', auth()->user()->account_id)
->join('users', 'users.id', '=', 'company_user.user_id')
->whereNull('users.deleted_at')
->whereNull('company_user.deleted_at')
->distinct()
->count('company_user.user_id');
return $count < auth()->user()->company()->account->num_users;
//return auth()->user()->company()->account->users->count() < auth()->user()->company()->account->num_users;
}
/**

View File

@ -24,6 +24,8 @@ class ValidProjectForClient implements Rule
public $input;
public $message;
public function __construct($input)
{
$this->input = $input;
@ -35,15 +37,20 @@ class ValidProjectForClient implements Rule
*/
public function passes($attribute, $value)
{
$this->message = ctrans('texts.project_client_do_not_match');
if (empty($this->input['project_id'])) {
return true;
}
if (is_string($this->input['project_id'])) {
$this->input['project_id'] = $this->decodePrimaryKey($this->input['project_id']);
}
// if (is_string($this->input['project_id'])) {
// $this->input['project_id'] = $this->decodePrimaryKey($this->input['project_id']);
// }
$project = Project::findOrFail($this->input['project_id']);
$project = Project::find($this->input['project_id']);
if(!$project)
$this->message = "Project not found";
return $project->client_id == $this->input['client_id'];
}
@ -53,6 +60,6 @@ class ValidProjectForClient implements Rule
*/
public function message()
{
return ctrans('texts.project_client_do_not_match');
return $this->message;
}
}

View File

@ -338,14 +338,14 @@ class CompanyImport implements ShouldQueue
if($this->account->plan == 'enterprise'){
$total_import_users = count($backup_users_emails);
// $total_import_users = count($backup_users_emails);
$account_plan_num_user = $this->account->num_users;
// $account_plan_num_user = $this->account->num_users;
if($total_import_users > $account_plan_num_user){
$this->message = "Total user count ({$total_import_users}) greater than your plan allows ({$account_plan_num_user})";
$this->pre_flight_checks_pass = false;
}
// if($total_import_users > $account_plan_num_user){
// $this->message = "Total user count ({$total_import_users}) greater than your plan allows ({$account_plan_num_user})";
// $this->pre_flight_checks_pass = false;
// }
}
}

View File

@ -134,10 +134,6 @@ class CSVImport implements ShouldQueue {
'company' => $this->company,
];
App::forgetInstance('translator');
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
$nmo = new NinjaMailerObject;
$nmo->mailable = new ImportCompleted($this->company, $data);
$nmo->company = $this->company;

View File

@ -70,7 +70,7 @@ class ZipInvoices implements ShouldQueue
*/
public function handle()
{
{nlog("bulky");
# create new zip object
$zip = new ZipArchive();

View File

@ -120,6 +120,7 @@ class SendRecurring implements ShouldQueue
*/
event('eloquent.created: App\Models\Invoice', $invoice);
//Admin notification for recurring invoice sent.
if ($invoice->invitations->count() >= 1 ) {

View File

@ -127,8 +127,8 @@ class WebhookHandler implements ShouldQueue
$this->company
);
// if ($response->getStatusCode() == 410 || $response->getStatusCode() == 200)
// return true;// $subscription->delete();
// if ($response->getStatusCode() == 410)
// return true; $subscription->delete();
}
catch(\Exception $e){

View File

@ -56,6 +56,10 @@ class ClientPaymentFailureObject
public function build()
{
if(!$this->payment_hash){
nlog("no payment has for failure notification - ClientPaymentFailureObject");
return;
}
App::forgetInstance('translator');
/* Init a new copy of the translator*/

View File

@ -13,9 +13,11 @@
namespace App\Mail\Import;
use App\Models\Company;
use App\Utils\Ninja;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\App;
class ImportCompleted extends Mailable
{
@ -45,6 +47,11 @@ class ImportCompleted extends Mailable
*/
public function build()
{
App::forgetInstance('translator');
$t = app('translator');
$t->replace(Ninja::transformTranslations($this->company->settings));
$data = array_merge($this->data, [
'logo' => $this->company->present()->logo(),
'settings' => $this->company->settings,

View File

@ -65,9 +65,10 @@ class SupportMessageSent extends Mailable
$is_large = $company->is_large ? "L" : "S";
$platform = array_key_exists('platform', $this->data) ? $this->data['platform'] : "U";
$migrated = strlen($company->company_key) == 32 ? "M" : "";
$trial = $account->isTrial() ? "T" : "";
if(Ninja::isHosted())
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated} :: {$plan} :: ".date('M jS, g:ia');
$subject = "{$priority}Hosted-{$db}-{$is_large}{$platform}{$migrated}{$trial} :: {$plan} :: ".date('M jS, g:ia');
else
$subject = "{$priority}Self Hosted :: {$plan} :: {$is_large}{$platform}{$migrated} :: ".date('M jS, g:ia');

View File

@ -88,7 +88,7 @@ class CompanyUser extends Pivot
public function users()
{
return $this->hasMany(User::class);
return $this->hasMany(User::class)->withTrashed();
}
/*todo monitor this function - may fail under certain conditions*/

View File

@ -71,7 +71,7 @@ class BaseDriver extends AbstractPaymentDriver
public $payment_method;
/* PaymentHash */
public ?PaymentHash $payment_hash;
public $payment_hash;
/* Array of payment methods */
public static $methods = [];

View File

@ -304,7 +304,7 @@ class MolliePaymentDriver extends BaseDriver
try {
$payment = $this->gateway->payments->get($request->id);
$record = Payment::where('transaction_reference', $payment->id)->firstOrFail();
$record = Payment::withTrashed()->where('transaction_reference', $request->id)->firstOrFail();
$record->status_id = $codes[$payment->status];
$record->save();

View File

@ -23,7 +23,7 @@ class CreateInvitations extends AbstractService
{
use MakesHash;
private $credit;
public $credit;
public function __construct(Credit $credit)
{
@ -45,6 +45,7 @@ class CreateInvitations extends AbstractService
$invitation = CreditInvitation::whereCompanyId($this->credit->company_id)
->whereClientContactId($contact->id)
->whereCreditId($this->credit->id)
->withTrashed()
->first();
if (! $invitation) {
@ -58,6 +59,34 @@ class CreateInvitations extends AbstractService
}
});
if($this->credit->invitations()->count() == 0) {
if($contacts->count() == 0){
$contact = $this->createBlankContact();
}
else{
$contact = $contacts->first();
$invitation = CreditInvitation::where('company_id', $this->credit->company_id)
->where('client_contact_id', $contact->id)
->where('credit_id', $this->credit->id)
->withTrashed()
->first();
if($invitation){
$invitation->restore();
return $this->credit;
}
}
$ii = CreditInvitationFactory::create($this->credit->company_id, $this->credit->user_id);
$ii->key = $this->createDbHash($this->credit->company->db);
$ii->credit_id = $this->credit->id;
$ii->client_contact_id = $contact->id;
$ii->save();
}
return $this->credit;
}

View File

@ -13,13 +13,14 @@ namespace App\Services\Credit;
use App\Jobs\Util\UnlinkFile;
use App\Models\Credit;
use App\Services\Credit\CreateInvitations;
use App\Utils\Traits\MakesHash;
class CreditService
{
use MakesHash;
protected $credit;
public $credit;
public function __construct($credit)
{

View File

@ -62,7 +62,23 @@ class CreateInvitations extends AbstractService
if($this->invoice->invitations()->count() == 0) {
$contact = $this->createBlankContact();
if($contacts->count() == 0){
$contact = $this->createBlankContact();
}
else{
$contact = $contacts->first();
$invitation = InvoiceInvitation::where('company_id', $this->invoice->company_id)
->where('client_contact_id', $contact->id)
->where('invoice_id', $this->invoice->id)
->withTrashed()
->first();
if($invitation){
$invitation->restore();
return $this->invoice;
}
}
$ii = InvoiceInvitationFactory::create($this->invoice->company_id, $this->invoice->user_id);
$ii->key = $this->createDbHash($this->invoice->company->db);

View File

@ -33,7 +33,7 @@ class InvoiceService
{
use MakesHash;
private $invoice;
public $invoice;
public function __construct($invoice)
{

View File

@ -59,6 +59,33 @@ class CreateInvitations
}
});
if($this->quote->invitations()->count() == 0) {
if($contacts->count() == 0){
$contact = $this->createBlankContact();
}
else{
$contact = $contacts->first();
$invitation = QuoteInvitation::where('company_id', $this->quote->company_id)
->where('client_contact_id', $contact->id)
->where('quote_id', $this->quote->id)
->withTrashed()
->first();
if($invitation){
$invitation->restore();
return $this->quote;
}
}
$ii = QuoteInvitationFactory::create($this->quote->company_id, $this->quote->user_id);
$ii->key = $this->createDbHash($this->quote->company->db);
$ii->quote_id = $this->quote->id;
$ii->client_contact_id = $contact->id;
$ii->save();
}
return $this->quote->fresh();
}

View File

@ -151,6 +151,7 @@ class HtmlEngine
if($this->entity->project) {
$data['$project.name'] = ['value' => $this->entity->project->name, 'label' => ctrans('texts.project_name')];
$data['$invoice.project'] = &$data['$project.name'];
}
}

View File

@ -16,6 +16,8 @@ use App\Models\Client;
use App\Models\ClientContact;
use App\Models\Invoice;
use App\Models\InvoiceInvitation;
use App\Models\Quote;
use App\Models\QuoteInvitation;
use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
use App\Utils\Ninja;
use App\Utils\Traits\MakesHash;
@ -254,18 +256,38 @@ class TemplateEngine
'send_email' => true,
]);
$this->entity_obj = Invoice::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'client_id' => $client->id,
]);
$invitation = InvoiceInvitation::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'invoice_id' => $this->entity_obj->id,
'client_contact_id' => $contact->id,
]);
if($this->entity == 'invoice')
{
$this->entity_obj = Invoice::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'client_id' => $client->id,
]);
$invitation = InvoiceInvitation::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'invoice_id' => $this->entity_obj->id,
'client_contact_id' => $contact->id,
]);
}
if($this->entity == 'quote')
{
$this->entity_obj = Quote::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'client_id' => $client->id,
]);
$invitation = QuoteInvitation::factory()->create([
'user_id' => auth()->user()->id,
'company_id' => auth()->user()->company()->id,
'quote_id' => $this->entity_obj->id,
'client_contact_id' => $contact->id,
]);
}
$this->entity_obj->setRelation('invitations', $invitation);
$this->entity_obj->setRelation('client', $client);

View File

@ -220,5 +220,6 @@ Route::post('api/v1/postmark_webhook', 'PostMarkController@webhook')->middleware
Route::get('token_hash_router', 'OneTimeTokenController@router');
Route::get('webcron', 'WebCronController@index');
Route::post('api/v1/get_migration_account', 'HostedMigrationController@getAccount')->middleware('guest');
Route::post('api/v1/confirm_forwarding', 'HostedMigrationController@confirmForwarding')->middleware('guest');
Route::fallback('BaseController@notFound');

View File

@ -33,18 +33,12 @@ use Tests\TestCase;
class InvitationTest extends TestCase
{
use MakesHash;
//use DatabaseTransactions;
//use RefreshDatabase;
use DatabaseTransactions;
// use RefreshDatabase;
public function setUp() :void
{
parent::setUp();
Session::start();
$this->faker = \Faker\Factory::create();
Model::reguard();
}
public function testInvoiceCreationAfterInvoiceMarkedSent()

View File

@ -677,7 +677,6 @@ class EventTest extends TestCase
{
$this->withoutMiddleware(PasswordProtection::class);
$this->expectsEvents([
UserWasCreated::class,
UserWasUpdated::class,

View File

@ -170,6 +170,9 @@ trait MockAccountData
}
$this->account = Account::factory()->create();
$this->account->num_users = 3;
$this->account->save();
$this->company = Company::factory()->create([
'account_id' => $this->account->id,
]);