diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index fdef16cfcbb7..da7261308716 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -25,11 +25,11 @@ use App\Models\InvoiceInvitation; use App\Models\Payment; use App\Models\Paymentable; use App\Utils\Ninja; -use DB; use Exception; use Illuminate\Console\Command; +use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Mail; use Illuminate\Support\Str; -use Mail; use Symfony\Component\Console\Input\InputOption; /* @@ -103,6 +103,7 @@ class CheckData extends Command // $this->checkPaidToCompanyDates(); $this->checkClientBalances(); $this->checkContacts(); + $this->checkEntityInvitations(); $this->checkCompanyData(); @@ -307,13 +308,63 @@ class CheckData extends Command $invitation->company_id = $invoice->company_id; $invitation->user_id = $invoice->user_id; $invitation->invoice_id = $invoice->id; - $invitation->contact_id = ClientContact::whereClientId($invoice->client_id)->whereIsPrimary(true)->first()->id; - $invitation->invitation_key = str_random(config('ninja.key_length')); + $invitation->contact_id = ClientContact::whereClientId($invoice->client_id)->first()->id; + $invitation->invitation_key = Str::random(config('ninja.key_length')); $invitation->save(); } } } + + private function checkEntityInvitations() + { + + $entities = ['invoice', 'quote', 'credit', 'recurring_invoice']; + + foreach($entities as $entity) + { + $table = "{$entity}s"; + $invitation_table = "{$entity}_invitations"; + + $entities = DB::table($table) + ->leftJoin($invitation_table, function ($join) use($invitation_table, $table, $entity){ + $join->on("{$invitation_table}.{$entity}_id", '=', "{$table}.id") + ->whereNull("{$invitation_table}.deleted_at"); + }) + ->groupBy("{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id") + ->havingRaw("count({$invitation_table}.id) = 0") + ->get(["{$table}.id", "{$table}.user_id", "{$table}.company_id", "{$table}.client_id"]); + + + $this->logMessage($entities->count()." {$table} without any invitations"); + + if ($this->option('fix') == 'true') + $this->fixInvitations($entities, $entity); + + } + + } + + private function fixInvitations($entities, $entity) + { + $entity_key = "{$entity}_id"; + + $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; + + foreach($entities as $entity) + { + $invitation = new $entity_obj(); + $invitation->company_id = $entity->company_id; + $invitation->user_id = $entity->user_id; + $invitation->{$entity_key} = $entity->id; + $invitation->client_contact_id = ClientContact::whereClientId($entity->client_id)->first()->id; + $invitation->key = Str::random(config('ninja.key_length')); + $invitation->save(); + + } + + } + // private function checkPaidToCompanyDates() // { // Company::cursor()->each(function ($company){ diff --git a/app/Http/Controllers/ClientPortal/DocumentController.php b/app/Http/Controllers/ClientPortal/DocumentController.php index e8a10a04b31e..f58001ac35ff 100644 --- a/app/Http/Controllers/ClientPortal/DocumentController.php +++ b/app/Http/Controllers/ClientPortal/DocumentController.php @@ -79,7 +79,7 @@ class DocumentController extends Controller $zip = new ZipStream(now() . '-documents.zip', $options); foreach ($documents as $document) { - $zip->addFileFromPath(basename($document->diskPath()), TempFile::path($document->diskPath())); + $zip->addFileFromPath(basename($document->diskPath()), TempFile::path($document->filePath())); } $zip->finish(); diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index bbff9eafe394..8954722e7796 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -121,18 +121,29 @@ class NinjaMailerJob implements ShouldQueue $message = $e->getMessage(); + /** + * Post mark buries the proper message in a a guzzle response + * this merges a text string with a json object + * need to harvest the ->Message property using the following + */ if($e instanceof ClientException) { //postmark specific failure $response = $e->getResponse(); + $message_body = json_decode($response->getBody()->getContents()); + + if(property_exists($message_body, 'Message')){ + $message = $message_body->Message; + nlog($message); + } - nlog($response); - // $message = $response->Message; } + /* If the is an entity attached to the message send a failure mailer */ if($this->nmo->entity) $this->entityEmailFailed($message); - if(Ninja::isHosted() && (!$e instanceof ClientException)) // Don't send postmark failures to Sentry + /* Don't send postmark failures to Sentry */ + if(Ninja::isHosted() && (!$e instanceof ClientException)) app('sentry')->captureException($e); } } diff --git a/app/Listeners/Payment/PaymentNotification.php b/app/Listeners/Payment/PaymentNotification.php index c23346341139..ca9bb0d3bf48 100644 --- a/app/Listeners/Payment/PaymentNotification.php +++ b/app/Listeners/Payment/PaymentNotification.php @@ -88,7 +88,7 @@ class PaymentNotification implements ShouldQueue $client = $payment->client; $amount = $payment->amount; - if ($invoice) { + if ($invoice && $invoice->line_items) { $items = $invoice->line_items; $item = end($items)->product_key; $entity_number = $invoice->number; diff --git a/app/Models/Client.php b/app/Models/Client.php index 6092c8c6bfc6..9241a6f80767 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -90,7 +90,7 @@ class Client extends BaseModel implements HasLocalePreference 'contacts.company', // 'currency', // 'primary_contact', - // 'country', + 'country', // 'contacts', // 'shipping_country', // 'company', @@ -218,7 +218,7 @@ class Client extends BaseModel implements HasLocalePreference public function assigned_user() { - return $this->belongsTo(User::class, 'assigned_user_id', 'id'); + return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function country() diff --git a/app/Models/CompanyLedger.php b/app/Models/CompanyLedger.php index 07adeaf12df6..f2c6581835e3 100644 --- a/app/Models/CompanyLedger.php +++ b/app/Models/CompanyLedger.php @@ -36,7 +36,7 @@ class CompanyLedger extends Model public function user() { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function company() diff --git a/app/Models/CompanyToken.php b/app/Models/CompanyToken.php index b450bb2a788a..1c332e4d55fd 100644 --- a/app/Models/CompanyToken.php +++ b/app/Models/CompanyToken.php @@ -23,6 +23,8 @@ class CompanyToken extends BaseModel ]; protected $with = [ + 'company', + 'user' ]; protected $touches = []; diff --git a/app/Models/CompanyUser.php b/app/Models/CompanyUser.php index 0626b84b4de6..1e9df041c5a1 100644 --- a/app/Models/CompanyUser.php +++ b/app/Models/CompanyUser.php @@ -78,7 +78,7 @@ class CompanyUser extends Pivot public function user() { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function company() diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 064c808337a2..291a815baebb 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -120,7 +120,7 @@ class Credit extends BaseModel public function assigned_user() { - return $this->belongsTo(User::class, 'assigned_user_id', 'id'); + return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function history() diff --git a/app/Models/Expense.php b/app/Models/Expense.php index e4fda0b82e12..d9a09f6c2c54 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -84,7 +84,7 @@ class Expense extends BaseModel public function assigned_user() { - return $this->belongsTo(User::class, 'assigned_user_id', 'id'); + return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function company() diff --git a/app/Models/GroupSetting.php b/app/Models/GroupSetting.php index 5fe53afdac76..653941de9c86 100644 --- a/app/Models/GroupSetting.php +++ b/app/Models/GroupSetting.php @@ -52,7 +52,7 @@ class GroupSetting extends StaticModel public function user() { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function clients() diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php index e098380bcfcd..790442df757d 100644 --- a/app/Models/Proposal.php +++ b/app/Models/Proposal.php @@ -45,6 +45,11 @@ class Proposal extends BaseModel return $this->morphMany(Document::class, 'documentable'); } + public function user() + { + return $this->belongsTo(User::class)->withTrashed(); + } + public function assigned_user() { return $this->belongsTo(User::class, 'assigned_user_id', 'id'); diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index 7f48c5cd8fd4..f125d8fc7eb2 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -76,7 +76,7 @@ class Subscription extends BaseModel public function user(): \Illuminate\Database\Eloquent\Relations\BelongsTo { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function nextDateByInterval($date, $frequency_id) diff --git a/app/Models/Task.php b/app/Models/Task.php index 7c0998f477b2..96d169d965e3 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -66,7 +66,7 @@ class Task extends BaseModel public function user() { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function client() diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index f02f68a0a894..b7505d680a25 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -82,7 +82,7 @@ class Vendor extends BaseModel public function assigned_user() { - return $this->belongsTo(User::class, 'assigned_user_id', 'id'); + return $this->belongsTo(User::class, 'assigned_user_id', 'id')->withTrashed(); } public function contacts() diff --git a/app/Models/Webhook.php b/app/Models/Webhook.php index 862f7ce94855..69bd78692c42 100644 --- a/app/Models/Webhook.php +++ b/app/Models/Webhook.php @@ -87,7 +87,7 @@ class Webhook extends BaseModel public function user() { - return $this->belongsTo(User::class); + return $this->belongsTo(User::class)->withTrashed(); } public function company() diff --git a/app/Services/Subscription/SubscriptionService.php b/app/Services/Subscription/SubscriptionService.php index 85dde2d02b01..eff83c90f644 100644 --- a/app/Services/Subscription/SubscriptionService.php +++ b/app/Services/Subscription/SubscriptionService.php @@ -38,6 +38,7 @@ use App\Utils\Traits\MakesHash; use App\Utils\Traits\SubscriptionHooker; use Carbon\Carbon; use GuzzleHttp\RequestOptions; +use Illuminate\Contracts\Container\BindingResolutionException; class SubscriptionService { @@ -950,7 +951,12 @@ class SubscriptionService return redirect($default_redirect); } - public function planPaid($invoice) + /** + * @param Invoice $invoice + * @return true + * @throws BindingResolutionException + */ + public function planPaid(Invoice $invoice) { $recurring_invoice_hashed_id = $invoice->recurring_invoice()->exists() ? $invoice->recurring_invoice->hashed_id : null; @@ -959,12 +965,14 @@ class SubscriptionService 'subscription' => $this->subscription->hashed_id, 'recurring_invoice' => $recurring_invoice_hashed_id, 'client' => $invoice->client->hashed_id, - 'contact' => $invoice->client->primary_contact()->first() ? $invoice->client->contacts->first() : false, + 'contact' => $invoice->client->primary_contact()->first() ? $invoice->client->primary_contact()->first(): $invoice->client->contacts->first(), 'invoice' => $invoice->hashed_id, ]; $response = $this->triggerWebhook($context); + nlog($response); + return true; } } diff --git a/tests/MockAccountData.php b/tests/MockAccountData.php index 0e566900ad80..c1325fa854f8 100644 --- a/tests/MockAccountData.php +++ b/tests/MockAccountData.php @@ -208,6 +208,7 @@ trait MockAccountData $this->cu = CompanyUserFactory::create($user->id, $this->company->id, $this->account->id); $this->cu->is_owner = true; $this->cu->is_admin = true; + $this->cu->is_locked = false; $this->cu->save(); $this->token = \Illuminate\Support\Str::random(64);