diff --git a/app/Events/Invoice/InvoiceWasUpdated.php b/app/Events/Invoice/InvoiceWasUpdated.php index b3da877b4e47..1c5dda316834 100644 --- a/app/Events/Invoice/InvoiceWasUpdated.php +++ b/app/Events/Invoice/InvoiceWasUpdated.php @@ -13,6 +13,8 @@ namespace App\Events\Invoice; use App\Models\Company; use App\Models\Invoice; +use Illuminate\Broadcasting\InteractsWithSockets; +use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; /** @@ -20,7 +22,7 @@ use Illuminate\Queue\SerializesModels; */ class InvoiceWasUpdated { - use SerializesModels; + use Dispatchable, InteractsWithSockets, SerializesModels; /** * @var Invoice diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index cef903d81f98..549468bf5a41 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -153,19 +153,22 @@ class BaseController extends Controller 'company.clients' =>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.tax_rates'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.groups'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.company_gateways'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.company_gateways.gateway'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.clients.contacts'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.products'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.invoices.company'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.invoices.invitations.contact'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.invoices.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.invoices.invitations.company'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.invoices.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.payments.paymentables'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.quotes.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.quotes.invitations.contact'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.quotes.invitations.company'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.quotes.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.credits.invitations'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.credits'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.payment_terms'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, - 'company.vendors'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.credits.documents'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.credits.invitations.contact'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.credits.invitations.company'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.payment_terms.company'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, + 'company.vendors.contacts'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.expenses'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.tasks'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, 'company.projects'=>function ($query) use($updated_at){$query->where('updated_at', '>=', $updated_at);}, diff --git a/app/Http/Middleware/QueryLogging.php b/app/Http/Middleware/QueryLogging.php index 0c29045eeeef..0447f3b35605 100644 --- a/app/Http/Middleware/QueryLogging.php +++ b/app/Http/Middleware/QueryLogging.php @@ -50,8 +50,8 @@ class QueryLogging Log::info($request->method() . ' - ' . $request->url() . ": $count queries - " . $time); - //if($count > 10) - // Log::info($queries); + // if($count > 100) + // Log::info($queries); } } diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index 1fb9292e41fc..7dba25743d38 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -39,7 +39,7 @@ class UpdateInvoiceRequest extends Request public function rules() { - + $rules = []; if ($this->input('documents') && is_array($this->input('documents'))) { @@ -60,7 +60,7 @@ class UpdateInvoiceRequest extends Request protected function prepareForValidation() { $input = $this->all(); - + if (array_key_exists('design_id', $input) && is_string($input['design_id'])) { $input['design_id'] = $this->decodePrimaryKey($input['design_id']); } @@ -75,9 +75,8 @@ class UpdateInvoiceRequest extends Request if (isset($input['invitations'])) { foreach ($input['invitations'] as $key => $value) { - if (is_numeric($input['invitations'][$key]['id'])) { + if (array_key_exists('id', $input['invitations'][$key]) && is_numeric($input['invitations'][$key]['id'])) { unset($input['invitations'][$key]['id']); - } if (array_key_exists('id', $input['invitations'][$key]) && is_string($input['invitations'][$key]['id'])) { diff --git a/app/Models/Client.php b/app/Models/Client.php index 3ad2876eaff6..574571c2febf 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -116,7 +116,7 @@ class Client extends BaseModel implements HasLocalePreference 'deleted_at' => 'timestamp', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/CompanyGateway.php b/app/Models/CompanyGateway.php index dd1ba7c35551..0ac92321b71d 100644 --- a/app/Models/CompanyGateway.php +++ b/app/Models/CompanyGateway.php @@ -58,7 +58,7 @@ class CompanyGateway extends BaseModel // return json_decode($this->attributes['fees_and_limits']); // } - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/CompanyLedger.php b/app/Models/CompanyLedger.php index 9d0bc73d4991..94b349097a18 100644 --- a/app/Models/CompanyLedger.php +++ b/app/Models/CompanyLedger.php @@ -27,7 +27,7 @@ class CompanyLedger extends Model 'deleted_at' => 'timestamp', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/CompanyToken.php b/app/Models/CompanyToken.php index ddbb7b0ef53e..432f6717d6fe 100644 --- a/app/Models/CompanyToken.php +++ b/app/Models/CompanyToken.php @@ -27,7 +27,7 @@ class CompanyToken extends BaseModel protected $with = [ ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() diff --git a/app/Models/CompanyUser.php b/app/Models/CompanyUser.php index 1eef8f3e0a70..5ce07b3efdc7 100644 --- a/app/Models/CompanyUser.php +++ b/app/Models/CompanyUser.php @@ -48,7 +48,7 @@ class CompanyUser extends Pivot 'slack_webhook_url', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 9a1d2485bd13..137bb861ff24 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -78,7 +78,7 @@ class Credit extends BaseModel 'deleted_at' => 'timestamp', ]; - protected $touches = ['company']; + protected $touches = []; const STATUS_DRAFT = 1; const STATUS_SENT = 2; diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 131b9ab07a17..a1633ce2d5a5 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -60,7 +60,7 @@ class Expense extends BaseModel 'deleted_at' => 'timestamp', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/GroupSetting.php b/app/Models/GroupSetting.php index 41f5d6ac663f..e9bc09a2f5ce 100644 --- a/app/Models/GroupSetting.php +++ b/app/Models/GroupSetting.php @@ -40,7 +40,7 @@ class GroupSetting extends StaticModel 'settings' ]; - protected $touches = ['company']; + protected $touches = []; public function company() { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index a77a5d89a38a..fe8ba22a5ec9 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -56,7 +56,7 @@ class Invoice extends BaseModel protected $presenter = 'App\Models\Presenters\InvoicePresenter'; - protected $touches = ['company']; + protected $touches = []; protected $hidden = [ 'id', diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php index 7ecbed228fa8..f6fa671ff5ba 100644 --- a/app/Models/InvoiceInvitation.php +++ b/app/Models/InvoiceInvitation.php @@ -29,7 +29,7 @@ class InvoiceInvitation extends BaseModel protected $fillable = [ //'key', - //'client_contact_id', + 'client_contact_id', ]; protected $with = [ diff --git a/app/Models/Payment.php b/app/Models/Payment.php index cc161528a9f1..38353eddb229 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -82,7 +82,7 @@ class Payment extends BaseModel 'paymentables', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/Product.php b/app/Models/Product.php index bc965b062358..900068b3538a 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -40,7 +40,7 @@ class Product extends BaseModel 'tax_rate3', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/Project.php b/app/Models/Project.php index 8b262b628049..bf6c8874efb0 100644 --- a/app/Models/Project.php +++ b/app/Models/Project.php @@ -42,7 +42,7 @@ class Project extends BaseModel return Project::class; } - protected $touches = ['company']; + protected $touches = []; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php index b6c40696b390..02a142fd9caa 100644 --- a/app/Models/Proposal.php +++ b/app/Models/Proposal.php @@ -22,7 +22,7 @@ class Proposal extends BaseModel 'id', ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/Quote.php b/app/Models/Quote.php index e5a42b45c0da..4efb3d35cd99 100644 --- a/app/Models/Quote.php +++ b/app/Models/Quote.php @@ -42,7 +42,7 @@ class Quote extends BaseModel protected $presenter = 'App\Models\Presenters\QuotePresenter'; - protected $touches = ['company']; + protected $touches = []; protected $fillable = [ 'assigned_user_id', diff --git a/app/Models/RecurringInvoice.php b/app/Models/RecurringInvoice.php index a3ee5cbcb858..3415a2c857ad 100644 --- a/app/Models/RecurringInvoice.php +++ b/app/Models/RecurringInvoice.php @@ -112,7 +112,7 @@ class RecurringInvoice extends BaseModel 'status' ]; - protected $touches = ['company']; + protected $touches = []; public function getEntityType() { diff --git a/app/Models/RecurringInvoiceInvitation.php b/app/Models/RecurringInvoiceInvitation.php index 7c43225a030a..055d289486d6 100644 --- a/app/Models/RecurringInvoiceInvitation.php +++ b/app/Models/RecurringInvoiceInvitation.php @@ -18,6 +18,8 @@ class RecurringInvoiceInvitation extends BaseModel { use MakesDates; + protected $fillable = ['client_contact_id']; + protected $touches = ['recurring_invoice']; public function getEntityType() diff --git a/app/Models/RecurringQuote.php b/app/Models/RecurringQuote.php index eec9dc473c6d..0d7f880d7929 100644 --- a/app/Models/RecurringQuote.php +++ b/app/Models/RecurringQuote.php @@ -81,7 +81,7 @@ class RecurringQuote extends BaseModel 'start_date', ]; - protected $touches = ['company']; + protected $touches = []; protected $casts = [ 'line_items' => 'object', diff --git a/app/Models/Task.php b/app/Models/Task.php index 5974c24ad000..1b95095ed16d 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -30,7 +30,7 @@ class Task extends BaseModel 'time_log', ]; - protected $touches = ['company']; + protected $touches = []; protected $casts = [ 'updated_at' => 'timestamp', diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index 5594e5e23db1..f473cb290dc4 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -53,7 +53,7 @@ class Vendor extends BaseModel 'deleted_at' => 'timestamp', ]; - protected $touches = ['company']; + protected $touches = []; protected $with = [ // 'contacts', diff --git a/app/Repositories/BaseRepository.php b/app/Repositories/BaseRepository.php index 05858f8c83b2..eda78fa63fff 100644 --- a/app/Repositories/BaseRepository.php +++ b/app/Repositories/BaseRepository.php @@ -256,7 +256,6 @@ class BaseRepository // $this->getInvitation($invitation, $resource)->delete(); $invitation_class = sprintf("App\\Models\\%sInvitation", $resource); - $invitation = $invitation_class::whereRaw("BINARY `key`= ?", [$invitation])->first(); if($invitation) @@ -277,10 +276,28 @@ class BaseRepository 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(); + + $invitation_class = sprintf("App\\Models\\%sInvitation", $resource); + + $new_invitation = $invitation_class::withTrashed() + ->where('client_contact_id', $contact->id) + ->where($lcfirst_resource_id, $model->id) + ->first(); + + if($new_invitation && $new_invitation->trashed()){ + + $new_invitation->restore(); + + } + else { + + $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(); + + } + } } } @@ -322,7 +339,6 @@ class BaseRepository if(!$model->design_id) $model->design_id = $this->decodePrimaryKey($client->getSetting('credit_design_id')); - } if ($class->name == Quote::class) { @@ -331,13 +347,12 @@ class BaseRepository if(!$model->design_id) $model->design_id = $this->decodePrimaryKey($client->getSetting('quote_design_id')); - - } $model->save(); return $model->fresh(); + } } diff --git a/app/Services/Invoice/MarkSent.php b/app/Services/Invoice/MarkSent.php index 50348669a9cf..b42831d83a0f 100644 --- a/app/Services/Invoice/MarkSent.php +++ b/app/Services/Invoice/MarkSent.php @@ -12,17 +12,18 @@ namespace App\Services\Invoice; use App\Events\Invoice\InvoiceWasMarkedSent; +use App\Models\Client; use App\Models\Invoice; use App\Services\AbstractService; use App\Utils\Ninja; class MarkSent extends AbstractService { - private $client; + public $client; - private $invoice; + public $invoice; - public function __construct($client, $invoice) + public function __construct(Client $client, Invoice $invoice) { $this->client = $client; $this->invoice = $invoice; diff --git a/tests/Unit/InvitationTest.php b/tests/Unit/InvitationTest.php new file mode 100644 index 000000000000..68ab59206886 --- /dev/null +++ b/tests/Unit/InvitationTest.php @@ -0,0 +1,84 @@ +makeTestData(); + + $this->withoutMiddleware( + ThrottleRequests::class + ); + } + + public function testInvitationSanity() + { + + $this->assertEquals($this->invoice->invitations->count(), 2); + + $invitations = $this->invoice->invitations()->get(); + + $invites = $invitations->reject(function ($invitation){ + return $invitation->contact->is_primary == false; + })->toArray(); + + $this->invoice->invitations = $invites; + + $this->invoice->line_items = []; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/invoices/'.$this->encodePrimaryKey($this->invoice->id), $this->invoice->toArray()) + ->assertStatus(200); + + $arr = $response->json(); + + $this->assertEquals(1, count($arr['data']['invitations'])); + + //test pushing a contact invitation back on + + + + $contact = $this->invoice->client->contacts->where('is_primary', false)->first(); + + $new_invite = InvoiceInvitationFactory::create($this->invoice->company_id, $this->invoice->user_id); + $new_invite->client_contact_id = $contact->hashed_id; + + $invitations = $this->invoice->invitations()->get(); + + $invitations->push($new_invite); + + $this->invoice->invitations = $invitations->toArray(); + $this->invoice->line_items = []; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/invoices/'.$this->encodePrimaryKey($this->invoice->id), $this->invoice->toArray()) + ->assertStatus(200); + + $arr = $response->json(); + + $this->assertEquals(2, count($arr['data']['invitations'])); + + //Now test that adding a contact back on works!! + } +}