diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 0947acad3685..cdd1ff6c1338 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -93,9 +93,9 @@ class CompanySettings extends BaseSettings $config = json_decode(config('ninja.settings')); return (object) [ - 'timezone_id' => config('ninja.i18n.timezone'), - 'language_id' => config('ninja.i18n.language'), - 'currency_id' => config('ninja.i18n.currency'), + 'timezone_id' => config('ninja.i18n.timezone_id'), + 'language_id' => config('ninja.i18n.language_id'), + 'currency_id' => config('ninja.i18n.currency_id'), 'payment_terms' => config('ninja.i18n.payment_terms'), 'datetime_format_id' => config('ninja.i18n.datetime_format'), 'military_time' => config('ninja.i18n.military_time'), diff --git a/app/Models/Client.php b/app/Models/Client.php index 79ed5da1653f..f8ba50671913 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -6,6 +6,7 @@ use App\DataMapper\ClientSettings; use App\Models\Company; use App\Models\Country; use App\Models\Filterable; +use App\Models\Timezone; use App\Utils\Traits\MakesHash; use Hashids\Hashids; use Illuminate\Database\Eloquent\SoftDeletes; @@ -43,8 +44,6 @@ class Client extends BaseModel 'settings' => 'object' ]; - //protected $dates = ['deleted_at']; - public function getClientSettingsObjectAttribute() { return new ClientSettings($this->settings); @@ -80,4 +79,16 @@ class Client extends BaseModel 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); + } + + + } diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php deleted file mode 100644 index 7e0974406a65..000000000000 --- a/app/Models/Invitation.php +++ /dev/null @@ -1,22 +0,0 @@ -morphedByMany(Invoice::class, 'inviteable'); - } - - - public function proposals() - { - return $this->morphedByMany(Proposal::class, 'inviteable'); - } - -} diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 3bab2c4c3499..2cbf3b9b1219 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -42,6 +42,6 @@ class Invoice extends BaseModel public function invitations() { - $this->morphMany(Invitation::class, 'inviteable'); + return $this->hasMany(InvoiceInvitation::class); } } diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php new file mode 100644 index 000000000000..903814dcb5a9 --- /dev/null +++ b/app/Models/InvoiceInvitation.php @@ -0,0 +1,54 @@ +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('

%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name)); + } + +} diff --git a/app/Models/Quote.php b/app/Models/Quote.php index d3df7b803e42..d58997272dca 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -30,6 +30,7 @@ class Quote extends BaseModel public function invitations() { - $this->morphMany(Invitation::class, 'inviteable'); + return $this->hasMany(QuoteInvitation::class); } + } diff --git a/app/Models/QuoteInvitation.php b/app/Models/QuoteInvitation.php new file mode 100644 index 000000000000..3546fa98f933 --- /dev/null +++ b/app/Models/QuoteInvitation.php @@ -0,0 +1,54 @@ +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('

%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name)); + } + +} diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index 698c24b001f0..b84ce24c719b 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -33,6 +33,6 @@ class RecurringInvoice extends BaseModel public function invitations() { - $this->morphMany(Invitation::class, 'inviteable'); + $this->morphMany(RecurringInvoiceInvitation::class); } } diff --git a/app/Models/RecurringInvoiceInvitation.php b/app/Models/RecurringInvoiceInvitation.php new file mode 100644 index 000000000000..29f4b0ae0ef1 --- /dev/null +++ b/app/Models/RecurringInvoiceInvitation.php @@ -0,0 +1,54 @@ +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('

%s: %s', $this->signature_base64, ctrans('texts.signed'), $this->createClientDate($this->signature_date, $this->contact->client->timezone()->name)); + } + +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index e5319b7457a1..f5bb53a2f048 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -2,6 +2,9 @@ namespace App\Providers; +use App\Models\InvoiceInvitation; +use App\Models\QuoteInvitation; +use App\Models\RecurringInvoiceInvitation; use App\Utils\Traits\MakesHash; use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Route; @@ -63,8 +66,16 @@ class RouteServiceProvider extends ServiceProvider return \App\Models\Expense::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail(); }); - Route::bind('invitation', function ($value) { - return \App\Models\Invitation::withTrashed()->where('id', $this->decodePrimaryKey($value))->firstOrFail(); + Route::bind('invoice_invitation', function ($value) { + 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) { diff --git a/config/ninja.php b/config/ninja.php index d5972490a650..b80009de757e 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -33,10 +33,10 @@ return [ ], 'i18n' => [ - 'timezone' => env('DEFAULT_TIMEZONE', 15), - 'country' => env('DEFAULT_COUNTRY', 840), // United Stated - 'currency' => env('DEFAULT_CURRENCY', 1), //USD - 'language' => env('DEFAULT_LANGUAGE', 1), //en + 'timezone_id' => env('DEFAULT_TIMEZONE', 15), + 'country_id' => env('DEFAULT_COUNTRY', 840), // United Stated + 'currency_id' => env('DEFAULT_CURRENCY', 1), //USD + 'language_id' => env('DEFAULT_LANGUAGE', 1), //en 'date_format' => env('DEFAULT_DATE_FORMAT', 'M j, Y'), 'date_picker_format' => env('DEFAULT_DATE_PICKER_FORMAT', 'M d, yyyy'), 'datetime_format' => env('DEFAULT_DATETIME_FORMAT', 'F j, Y g:i a'), diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index cf3dda5aab5a..b3136af0f0fb 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -506,26 +506,33 @@ class CreateUsersTable extends Migration $t->unique(['company_id', 'quote_number']); }); - Schema::create('invitations', function ($t) { + Schema::create('invoice_invitations', function ($t) { $t->increments('id'); $t->unsignedInteger('company_id'); - $t->unsignedInteger('inviteable_id'); - $t->string('inviteable_type'); $t->unsignedInteger('user_id'); $t->unsignedInteger('client_contact_id'); $t->unsignedInteger('invoice_id')->index(); - $t->string('invitation_key',100)->index()->unique(); + $t->string('invitation_key')->index()->unique(); $t->timestamps(); $t->softDeletes(); $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('viewed_date')->nullable(); + $t->timestamp('opened_date')->nullable(); $t->foreign('user_id')->references('id')->on('users')->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('company_id')->references('id')->on('companies')->onDelete('cascade'); + + $t->index(['deleted_at', 'invoice_id']); + }); diff --git a/tests/Feature/ClientTest.php b/tests/Feature/ClientTest.php index 937b45c6837b..b3061cdaf32a 100644 --- a/tests/Feature/ClientTest.php +++ b/tests/Feature/ClientTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature; use App\Models\Account; +use App\Models\Client; use App\Models\Company; use App\Models\User; 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'); + } + } diff --git a/tests/Feature/LoginTest.php b/tests/Feature/LoginTest.php index 3d91c9d94123..ab0b305da423 100644 --- a/tests/Feature/LoginTest.php +++ b/tests/Feature/LoginTest.php @@ -20,9 +20,9 @@ use Tests\TestCase; class LoginTest extends TestCase { - //use DatabaseTransactions; - use UserSessionAttributes; - use RefreshDatabase; + use DatabaseTransactions; + //use UserSessionAttributes; + //use RefreshDatabase; public function setUp() {