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

Fixes for company_user (#3477)

* Minor fixes for user delete

* Working on notifications

* Refactor for notifications

* Fix for checking settings withe negative integers

* Set payment id to 0

* Move pdf download to client side routes

* fixes for company_user

* Fixes for company_user
This commit is contained in:
David Bomba 2020-03-11 22:05:05 +11:00 committed by GitHub
parent ee0a529118
commit dc8ecbeeed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 287 additions and 92 deletions

View File

@ -24,39 +24,39 @@ class CompanySettings extends BaseSettings {
/*Group settings based on functionality*/
/*Invoice*/
public $auto_archive_invoice = false;
public $lock_sent_invoices = false;
public $auto_archive_invoice = false;
public $lock_sent_invoices = false;
public $enable_client_portal_tasks = false;
public $enable_client_portal_password = false;
public $enable_client_portal = true;//implemented
public $enable_client_portal_dashboard = true;//implemented
public $signature_on_pdf = false;
public $document_email_attachment = false;
public $send_portal_password = false;
public $enable_client_portal_tasks = false;
public $enable_client_portal_password = false;
public $enable_client_portal = true;//implemented
public $enable_client_portal_dashboard = true;//implemented
public $signature_on_pdf = false;
public $document_email_attachment = false;
public $send_portal_password = false;
public $portal_design_id = '1';
public $portal_design_id = '1';
public $timezone_id = '';
public $date_format_id = '';
public $military_time = false;
public $timezone_id = '';
public $date_format_id = '';
public $military_time = false;
public $language_id = '';
public $show_currency_code = false;
public $language_id = '';
public $show_currency_code = false;
public $company_gateway_ids = '';
public $company_gateway_ids = '';
public $currency_id = '1';
public $currency_id = '1';
public $custom_value1 = '';
public $custom_value2 = '';
public $custom_value3 = '';
public $custom_value4 = '';
public $custom_value1 = '';
public $custom_value2 = '';
public $custom_value3 = '';
public $custom_value4 = '';
public $default_task_rate = 0;
public $default_task_rate = 0;
public $payment_terms = 1;
public $send_reminders = false;
public $payment_terms = 1;
public $send_reminders = false;
public $custom_message_dashboard = '';
public $custom_message_unpaid_invoice = '';
@ -116,10 +116,10 @@ class CompanySettings extends BaseSettings {
public $enabled_item_tax_rates = 0;
public $invoice_design_id = 'VolejRejNm';
public $quote_design_id = 'VolejRejNm';
public $credit_design_id = 'VolejRejNm';
public $credit_design_id = 'VolejRejNm';
public $invoice_footer = '';
public $credit_footer = '';
public $credit_terms = '';
public $credit_footer = '';
public $credit_terms = '';
public $invoice_labels = '';
public $tax_name1 = '';
public $tax_rate1 = 0;
@ -127,7 +127,7 @@ class CompanySettings extends BaseSettings {
public $tax_rate2 = 0;
public $tax_name3 = '';
public $tax_rate3 = 0;
public $payment_type_id = '1';
public $payment_type_id = '0';
public $invoice_fields = '';
public $show_accept_invoice_terms = false;

View File

@ -146,12 +146,14 @@ class AccountController extends BaseController
public function store(CreateAccountRequest $request)
{
$account = CreateAccount::dispatchNow($request->all());
if(!($account instanceof Account))
return $account;
$ct = CompanyUser::whereUserId(auth()->user()->id);
config(['ninja.company_id' => $ct->first()->company->id]);
return $this->listResponse($ct);
}

View File

@ -62,7 +62,7 @@ class InvitationController extends Controller
public function routerForDownload(string $entity, string $invitation_key)
{
return redirect('/'.$entity.'/'.$invitation_key.'/download_pdf');
return redirect('client/'.$entity.'/'.$invitation_key.'/download_pdf');
}
public function routerForIframe(string $entity, string $client_hash, string $invitation_key)

View File

@ -36,7 +36,7 @@ class SetInviteDb
$entity = null;
if(!$request->route('entity'))
$entity = $request->segment(1);
$entity = $request->segment(2);
else
$entity = $request->route('entity');

View File

@ -29,6 +29,8 @@ class VersionCheck implements ShouldQueue
$version_file = file_get_contents(config('ninja.version_url'));
\Log::error($version_file);
if($version_file)
Account::whereNotNull('id')->update(['latest_version' => $version_file]);

View File

@ -14,9 +14,11 @@ namespace App\Listeners\Invoice;
use App\Models\Activity;
use App\Models\ClientContact;
use App\Models\InvoiceInvitation;
use App\Notifications\Admin\EntitySentNotification;
use App\Notifications\Admin\InvoiceSentNotification;
use App\Repositories\ActivityRepository;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Log;
@ -25,6 +27,8 @@ use Illuminate\Support\Facades\Notification;
class InvoiceEmailedNotification implements ShouldQueue
{
use UserNotifies;
public function __construct()
{
}
@ -41,16 +45,23 @@ class InvoiceEmailedNotification implements ShouldQueue
foreach($invitation->company->company_users as $company_user)
{
$user = $company_user->user;
$company_user->user->notify(new InvoiceSentNotification($invitation, $invitation->company));
$notification = new EntitySentNotification($invitation, 'invoice');
$notification->method = $this->findUserNotificationTypes($invitation, $company_user, 'invoice', ['all_notifications', 'invoice_sent']);
$user->notify($notification);
}
if(isset($invitation->company->slack_webhook_url)){
// if(isset($invitation->company->slack_webhook_url)){
Notification::route('slack', $invitation->company->slack_webhook_url)
->notify(new InvoiceSentNotification($invitation, $invitation->company, true));
// Notification::route('slack', $invitation->company->slack_webhook_url)
// ->notify(new EntitySentNotification($invitation, $invitation->company, true));
}
// }
}
}

View File

@ -12,12 +12,15 @@
namespace App\Listeners\Misc;
use App\Notifications\Admin\EntityViewedNotification;
use App\Utils\Traits\Notifications\UserNotifies;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Notification;
class InvitationViewedListener implements ShouldQueue
{
use UserNotifies;
/**
* Create the event listener.
*
@ -40,36 +43,10 @@ class InvitationViewedListener implements ShouldQueue
foreach($invitation->company->company_users as $company_user)
{
$notifiable_methods = [];
$notifications = $company_user->notifications;
$entity_viewed = "{$entity_name}_viewed";
/*** Check for Mail notifications***/
$all_user_notifications = '';
if($invitation->{$entity_name}->user_id == $company_user->user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id)
$all_user_notifications = "all_user_notifications";
$possible_permissions = [$entity_viewed, "all_notifications", $all_user_notifications];
$permission_count = array_intersect($possible_permissions, $notifications->email);
if(count($permission_count) >=1)
array_push($notifiable_methods, 'mail');
/*** Check for Mail notifications***/
/*** Check for Slack notifications***/
//@TODO when hillel implements this we can uncomment this.
// $permission_count = array_intersect($possible_permissions, $notifications->slack);
// if(count($permission_count) >=1)
// array_push($notifiable_methods, 'slack');
/*** Check for Slack notifications***/
$notification->method = $notifiable_methods;
$notification->method = $this->findUserNotificationTypes($invitation, $company_user, $entity_name, ['all_notifications', $entity_viewed]);
$company_user->user->notify($notification);
}

View File

@ -107,4 +107,11 @@ class CompanyUser extends Pivot
return $this->hasMany(CompanyToken::class, 'user_id', 'user_id');
}
public function scopeAuthCompany($query)
{
$query->where('company_id', auth()->user()->companyId());
return $query;
}
}

View File

@ -187,7 +187,10 @@ class User extends Authenticatable implements MustVerifyEmail
$this->id = auth()->user()->id;
}
return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id')->where('company_user.user_id', $this->id)->withTrashed();
return $this->hasOneThrough(CompanyUser::class, CompanyToken::class, 'user_id', 'company_id', 'id', 'company_id')
->where('company_user.user_id', $this->id)
->where('company_user.company_id', auth()->user()->company()->id)
->withTrashed();
}
/**

View File

@ -0,0 +1,151 @@
<?php
namespace App\Notifications\Admin;
use App\Utils\Number;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Messages\SlackMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class EntitySentNotification extends Notification implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new notification instance.
*
* @return void
*/
protected $invitation;
protected $entity;
protected $entity_name;
protected $settings;
public $is_system;
public $method;
protected $contact;
protected $company;
public function __construct($invitation, $entity_name, $is_system = false, $settings = null)
{
$this->invitation = $invitation;
$this->entity_name = $entity_name;
$this->entity = $invitation->{$entity_name};
$this->contact = $invitation->contact;
$this->company = $invitation->company;
$this->settings = $this->entity->client->getMergedSettings();
$this->is_system = $is_system;
$this->method = null;
}
/**
* Get the notification's delivery channels.
*
* @param mixed $notifiable
* @return array
*/
public function via($notifiable)
{
return $this->method ?: [];
}
/**
* Get the mail representation of the notification.
*
* @param mixed $notifiable
* @return \Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
{
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
$subject = ctrans("texts.notification_{$this->entity_name}_sent_subject",
[
'client' => $this->contact->present()->name(),
'invoice' => $this->entity->number,
]);
$data = [
'title' => $subject,
'message' => ctrans("texts.notification_{$this->entity_name}_sent",
[
'amount' => $amount,
'client' => $this->contact->present()->name(),
'invoice' => $this->entity->number,
]),
'url' => $this->invitation->getAdminLink(),
'button' => ctrans("texts.view_{$this->entity_name}"),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),
];
return (new MailMessage)
->subject($subject)
->markdown('email.admin.generic', $data);
}
/**
* Get the array representation of the notification.
*
* @param mixed $notifiable
* @return array
*/
public function toArray($notifiable)
{
return [
//
];
}
public function toSlack($notifiable)
{
$logo = $this->invitation->company->present()->logo();
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
// return (new SlackMessage)
// ->success()
// ->from(ctrans('texts.notification_bot'))
// ->image($logo)
// ->content(ctrans('texts.notification_invoice_sent',
// [
// 'amount' => $amount,
// 'client' => $this->contact->present()->name(),
// 'invoice' => $this->invoice->number
// ]));
return (new SlackMessage)
->from(ctrans('texts.notification_bot'))
->success()
->image('https://app.invoiceninja.com/favicon-v2.png')
->content(trans("texts.notification_{$this->entity_name}_sent_subject",
[
'amount' => $amount,
'client' => $this->contact->present()->name(),
'invoice' => $this->entity->number
]))
->attachment(function ($attachment) use($amount){
$attachment->title(ctrans('texts.invoice_number_placeholder', ['invoice' => $this->entity->number]), $this->invitation->getAdminLink())
->fields([
ctrans('texts.client') => $this->contact->present()->name(),
ctrans('texts.amount') => $amount,
]);
});
}
}

View File

@ -97,17 +97,6 @@ class EntityViewedNotification extends Notification implements ShouldQueue
$logo = $this->company->present()->logo();
$amount = Number::formatMoney($this->entity->amount, $this->entity->client);
// return (new SlackMessage)
// ->success()
// ->from(ctrans('texts.notification_bot'))
// ->image($logo)
// ->content(ctrans("texts.notification_{$this->entity_name}_viewed",
// [
// 'amount' => $amount,
// 'client' => $this->contact->present()->name(),
// $this->entity_name => $this->entity->number
// ]));
return (new SlackMessage)
->from(ctrans('texts.notification_bot'))
->success()
@ -142,7 +131,7 @@ class EntityViewedNotification extends Notification implements ShouldQueue
'client' => $this->contact->present()->name(),
$this->entity_name => $this->entity->number,
]),
'url' => config('ninja.site_url') . "/client/{$this->entity_name}/" . $this->invitation->key . "?silent=true",
'url' => $this->invitation->getAdminLink(),
'button' => ctrans("texts.view_{$this->entity_name}"),
'signature' => $this->settings->email_signature,
'logo' => $this->company->present()->logo(),

View File

@ -41,7 +41,7 @@ class UserPolicy extends EntityPolicy
*/
public function edit(User $user, $user_entity) : bool
{
$company_user = CompanyUser::whereUserId($user->id)->company()->first();
$company_user = CompanyUser::whereUserId($user->id)->AuthCompany()->first();
return ($user->isAdmin() && $company_user);
}

View File

@ -91,12 +91,14 @@ class UserRepository extends BaseRepository
->whereCompanyId($company->id)
->first();
$cu->tokens()->delete();
$cu->delete();
$cu->tokens()->forceDelete();
$cu->forceDelete();
}
else
$user->delete();
$user->delete();
return $user->fresh();
}
}

View File

@ -99,6 +99,8 @@ class UserTransformer extends EntityTransformer
{
$transformer = new CompanyUserTransformer($this->serializer);
return $this->includeItem($user->company_user, $transformer, CompanyUser::class);
$cu = $user->company_users()->whereCompanyId(config('ninja.company_id'))->first();
return $this->includeItem($cu, $transformer, CompanyUser::class);
}
}

View File

@ -197,7 +197,7 @@ trait ClientGroupSettingsSaver
switch ($key) {
case 'int':
case 'integer':
return ctype_digit(strval($value));
return ctype_digit(strval(abs($value)));
case 'real':
case 'float':
case 'double':

View File

@ -214,7 +214,7 @@ trait CompanySettingsSaver
switch ($key) {
case 'int':
case 'integer':
return ctype_digit(strval($value));
return ctype_digit(strval(abs($value)));
case 'real':
case 'float':
case 'double':

View File

@ -0,0 +1,40 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\Utils\Traits\Notifications;
/**
* Class UserNotifies
* @package App\Utils\Traits
*/
trait UserNotifies
{
public function findUserNotificationTypes($invitation, $company_user, $entity_name, $required_permissions) :array
{
$notifiable_methods = [];
$notifications = $company_user->notifications;
if($invitation->{$entity_name}->user_id == $company_user->_user_id || $invitation->{$entity_name}->assigned_user_id == $company_user->user_id)
array_push($required_permissions, "all_user_notifications");
if(count(array_intersect($required_permissions, $notifications->email)) >=1)
array_push($notifiable_methods, 'mail');
// if(count(array_intersect($required_permissions, $notifications->slack)) >=1)
// array_push($notifiable_methods, 'slack');
return $notifiable_methods;
}
}

View File

@ -190,7 +190,7 @@ trait SettingsSaver
switch ($key) {
case 'int':
case 'integer':
return ctype_digit(strval($value));
return ctype_digit(strval(abs($value)));
case 'real':
case 'float':
case 'double':

View File

@ -250,11 +250,15 @@ $LANG = array(
'invoice_link_message' => 'To view the invoice click the link below:',
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_credit_sent_subject' => 'Credit :invoice was sent to :client',
'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client',
'notification_credit_viewed_subject' => 'Credit :credit was viewed by :client',
'notification_quote_viewed_subject' => 'Quote :quote was viewed by :client',
'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_credit_sent' => 'The following client :client was emailed Credit :invoice for :amount.',
'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'notification_credit_viewed' => 'The following client :client viewed Credit :credit for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :quote for :amount.',

View File

@ -46,11 +46,19 @@ Route::group(['middleware' => ['auth:contact','locale'], 'prefix' => 'client', '
Route::group(['middleware' => ['invite_db'], 'prefix' => 'client', 'as' => 'client.'], function () {
Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf')->name('invoice.download_pdf');
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_pdf');
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_pdf');
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
/*Invitation catches*/
Route::get('{entity}/{invitation_key}','ClientPortal\InvitationController@router');
Route::get('{entity}/{client_hash}/{invitation_key}','ClientPortal\InvitationController@routerForIframe'); //should never need this
Route::get('payment_hook/{company_gateway_id}/{gateway_type_id}','ClientPortal\PaymentHookController@process');
});
Route::fallback('BaseController@notFoundClient');

View File

@ -18,10 +18,7 @@ Route::group(['middleware' => ['invite_db'], 'prefix' => '', 'as' => ''], functi
/*Invitation catches*/
Route::get('{entity}/{invitation_key}/download', 'ClientPortal\InvitationController@routerForDownload');
Route::get('invoice/{invitation_key}/download_pdf', 'InvoiceController@downloadPdf')->name('invoice.download_pdf');
Route::get('quote/{invitation_key}/download_pdf', 'QuoteController@downloadPdf')->name('quote.download_pdf');
Route::get('credit/{invitation_key}/download_pdf', 'CreditController@downloadPdf')->name('credit.download_pdf');
});

View File

@ -41,7 +41,7 @@ class CompanySettingsTest extends TestCase
Session::start();
$this->faker = \Faker\Factory::create();
$this->withoutExceptionHandling();
Model::reguard();
@ -68,7 +68,7 @@ class CompanySettingsTest extends TestCase
catch(ValidationException $e) {
$message = json_decode($e->validator->getMessageBag(),1);
// \Log::error($message);
\Log::error($message);
}
if($response) {