mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-03 10:54:34 -04:00
Working on Invitations
This commit is contained in:
parent
e364bcf6ec
commit
86d123ff9a
@ -93,9 +93,9 @@ class CompanySettings extends BaseSettings
|
|||||||
$config = json_decode(config('ninja.settings'));
|
$config = json_decode(config('ninja.settings'));
|
||||||
|
|
||||||
return (object) [
|
return (object) [
|
||||||
'timezone_id' => config('ninja.i18n.timezone'),
|
'timezone_id' => config('ninja.i18n.timezone_id'),
|
||||||
'language_id' => config('ninja.i18n.language'),
|
'language_id' => config('ninja.i18n.language_id'),
|
||||||
'currency_id' => config('ninja.i18n.currency'),
|
'currency_id' => config('ninja.i18n.currency_id'),
|
||||||
'payment_terms' => config('ninja.i18n.payment_terms'),
|
'payment_terms' => config('ninja.i18n.payment_terms'),
|
||||||
'datetime_format_id' => config('ninja.i18n.datetime_format'),
|
'datetime_format_id' => config('ninja.i18n.datetime_format'),
|
||||||
'military_time' => config('ninja.i18n.military_time'),
|
'military_time' => config('ninja.i18n.military_time'),
|
||||||
|
@ -6,6 +6,7 @@ use App\DataMapper\ClientSettings;
|
|||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\Country;
|
use App\Models\Country;
|
||||||
use App\Models\Filterable;
|
use App\Models\Filterable;
|
||||||
|
use App\Models\Timezone;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Hashids\Hashids;
|
use Hashids\Hashids;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
@ -43,8 +44,6 @@ class Client extends BaseModel
|
|||||||
'settings' => 'object'
|
'settings' => 'object'
|
||||||
];
|
];
|
||||||
|
|
||||||
//protected $dates = ['deleted_at'];
|
|
||||||
|
|
||||||
public function getClientSettingsObjectAttribute()
|
public function getClientSettingsObjectAttribute()
|
||||||
{
|
{
|
||||||
return new ClientSettings($this->settings);
|
return new ClientSettings($this->settings);
|
||||||
@ -80,4 +79,16 @@ class Client extends BaseModel
|
|||||||
return $this->belongsTo(Country::class, 'shipping_country_id', 'id');
|
return $this->belongsTo(Country::class, 'shipping_country_id', 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function timezone()
|
||||||
|
{
|
||||||
|
return Timezone::find($this->getSettings()->timezone_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSettings()
|
||||||
|
{
|
||||||
|
return ClientSettings::buildClientSettings($this->company->settings, $this->settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Models;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Invitation extends BaseModel
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
public function invoices()
|
|
||||||
{
|
|
||||||
return $this->morphedByMany(Invoice::class, 'inviteable');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function proposals()
|
|
||||||
{
|
|
||||||
return $this->morphedByMany(Proposal::class, 'inviteable');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -42,6 +42,6 @@ class Invoice extends BaseModel
|
|||||||
|
|
||||||
public function invitations()
|
public function invitations()
|
||||||
{
|
{
|
||||||
$this->morphMany(Invitation::class, 'inviteable');
|
return $this->hasMany(InvoiceInvitation::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
app/Models/InvoiceInvitation.php
Normal file
54
app/Models/InvoiceInvitation.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class InvoiceInvitation extends BaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
use MakesDates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Invoice::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function contact()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ClientContact::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signatureDiv()
|
||||||
|
{
|
||||||
|
if (! $this->signature_base64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -30,6 +30,7 @@ class Quote extends BaseModel
|
|||||||
|
|
||||||
public function invitations()
|
public function invitations()
|
||||||
{
|
{
|
||||||
$this->morphMany(Invitation::class, 'inviteable');
|
return $this->hasMany(QuoteInvitation::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
54
app/Models/QuoteInvitation.php
Normal file
54
app/Models/QuoteInvitation.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QuoteInvitation extends BaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
use MakesDates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function quote()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Quote::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function contact()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ClientContact::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signatureDiv()
|
||||||
|
{
|
||||||
|
if (! $this->signature_base64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -33,6 +33,6 @@ class RecurringInvoice extends BaseModel
|
|||||||
|
|
||||||
public function invitations()
|
public function invitations()
|
||||||
{
|
{
|
||||||
$this->morphMany(Invitation::class, 'inviteable');
|
$this->morphMany(RecurringInvoiceInvitation::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
app/Models/RecurringInvoiceInvitation.php
Normal file
54
app/Models/RecurringInvoiceInvitation.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Utils\Traits\MakesDates;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class RecurringInvoiceInvitation extends BaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
use MakesDates;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function recurring_invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(RecurringInvoice::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function contact()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(ClientContact::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function user()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(User::class)->withTrashed();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
|
*/
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Company::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signatureDiv()
|
||||||
|
{
|
||||||
|
if (! $this->signature_base64) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf('<img src="data:image/svg+xml;base64,%s"></img><p/>%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Models\InvoiceInvitation;
|
||||||
|
use App\Models\QuoteInvitation;
|
||||||
|
use App\Models\RecurringInvoiceInvitation;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
@ -63,8 +66,16 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
return \App\Models\Expense::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
return \App\Models\Expense::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::bind('invitation', function ($value) {
|
Route::bind('invoice_invitation', function ($value) {
|
||||||
return \App\Models\Invitation::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
return \App\Models\InvoiceInvitation::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('recurring_invoice_invitation', function ($value) {
|
||||||
|
return \App\Models\RecurringInvoiceInvitation::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::bind('quote_invitation', function ($value) {
|
||||||
|
return \App\Models\QuoteInvitation::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::bind('task', function ($value) {
|
Route::bind('task', function ($value) {
|
||||||
|
@ -33,10 +33,10 @@ return [
|
|||||||
],
|
],
|
||||||
|
|
||||||
'i18n' => [
|
'i18n' => [
|
||||||
'timezone' => env('DEFAULT_TIMEZONE', 15),
|
'timezone_id' => env('DEFAULT_TIMEZONE', 15),
|
||||||
'country' => env('DEFAULT_COUNTRY', 840), // United Stated
|
'country_id' => env('DEFAULT_COUNTRY', 840), // United Stated
|
||||||
'currency' => env('DEFAULT_CURRENCY', 1), //USD
|
'currency_id' => env('DEFAULT_CURRENCY', 1), //USD
|
||||||
'language' => env('DEFAULT_LANGUAGE', 1), //en
|
'language_id' => env('DEFAULT_LANGUAGE', 1), //en
|
||||||
'date_format' => env('DEFAULT_DATE_FORMAT', 'M j, Y'),
|
'date_format' => env('DEFAULT_DATE_FORMAT', 'M j, Y'),
|
||||||
'date_picker_format' => env('DEFAULT_DATE_PICKER_FORMAT', 'M d, yyyy'),
|
'date_picker_format' => env('DEFAULT_DATE_PICKER_FORMAT', 'M d, yyyy'),
|
||||||
'datetime_format' => env('DEFAULT_DATETIME_FORMAT', 'F j, Y g:i a'),
|
'datetime_format' => env('DEFAULT_DATETIME_FORMAT', 'F j, Y g:i a'),
|
||||||
|
@ -506,26 +506,33 @@ class CreateUsersTable extends Migration
|
|||||||
$t->unique(['company_id', 'quote_number']);
|
$t->unique(['company_id', 'quote_number']);
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::create('invitations', function ($t) {
|
Schema::create('invoice_invitations', function ($t) {
|
||||||
$t->increments('id');
|
$t->increments('id');
|
||||||
$t->unsignedInteger('company_id');
|
$t->unsignedInteger('company_id');
|
||||||
$t->unsignedInteger('inviteable_id');
|
|
||||||
$t->string('inviteable_type');
|
|
||||||
$t->unsignedInteger('user_id');
|
$t->unsignedInteger('user_id');
|
||||||
$t->unsignedInteger('client_contact_id');
|
$t->unsignedInteger('client_contact_id');
|
||||||
$t->unsignedInteger('invoice_id')->index();
|
$t->unsignedInteger('invoice_id')->index();
|
||||||
$t->string('invitation_key',100)->index()->unique();
|
$t->string('invitation_key')->index()->unique();
|
||||||
$t->timestamps();
|
$t->timestamps();
|
||||||
$t->softDeletes();
|
$t->softDeletes();
|
||||||
|
|
||||||
$t->string('transaction_reference')->nullable();
|
$t->string('transaction_reference')->nullable();
|
||||||
|
$t->string('message_id')->nullable();
|
||||||
|
$t->text('email_error');
|
||||||
|
$t->text('signature_base64');
|
||||||
|
$t->timestamp('signature_date')->nullable();
|
||||||
|
|
||||||
$t->timestamp('sent_date')->nullable();
|
$t->timestamp('sent_date')->nullable();
|
||||||
$t->timestamp('viewed_date')->nullable();
|
$t->timestamp('viewed_date')->nullable();
|
||||||
|
$t->timestamp('opened_date')->nullable();
|
||||||
|
|
||||||
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
$t->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
$t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade');
|
$t->foreign('client_contact_id')->references('id')->on('client_contacts')->onDelete('cascade');
|
||||||
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
$t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
|
||||||
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
$t->foreign('company_id')->references('id')->on('companies')->onDelete('cascade');
|
||||||
|
|
||||||
|
$t->index(['deleted_at', 'invoice_id']);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Client;
|
||||||
use App\Models\Company;
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
@ -179,4 +180,34 @@ class ClientTest extends TestCase
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testDefaultTimeZoneFromClientModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
$user = User::all()->first();
|
||||||
|
$company = Company::all()->first();
|
||||||
|
|
||||||
|
factory(\App\Models\Client::class, 3)->create(['user_id' => $user->id, 'company_id' => $company->id])->each(function ($c) use ($user, $company){
|
||||||
|
|
||||||
|
factory(\App\Models\ClientContact::class,1)->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'client_id' => $c->id,
|
||||||
|
'company_id' => $company->id,
|
||||||
|
'is_primary' => 1
|
||||||
|
]);
|
||||||
|
|
||||||
|
factory(\App\Models\ClientContact::class,2)->create([
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'client_id' => $c->id,
|
||||||
|
'company_id' => $company->id
|
||||||
|
]);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$client = Client::all()->first();
|
||||||
|
|
||||||
|
$this->assertEquals($client->getSettings()->timezone_id, 15);
|
||||||
|
|
||||||
|
$this->assertEquals($client->timezone()->name, 'US/Eastern');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,9 +20,9 @@ use Tests\TestCase;
|
|||||||
class LoginTest extends TestCase
|
class LoginTest extends TestCase
|
||||||
{
|
{
|
||||||
|
|
||||||
//use DatabaseTransactions;
|
use DatabaseTransactions;
|
||||||
use UserSessionAttributes;
|
//use UserSessionAttributes;
|
||||||
use RefreshDatabase;
|
//use RefreshDatabase;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user