From 28cbd75fcb3af441849eded0c723619810ebe4f2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 11 Nov 2020 11:13:39 +1100 Subject: [PATCH] Fixes for credit PDF --- app/Console/Commands/DemoMode.php | 6 +++- app/Console/Commands/SendRemindersCron.php | 33 +++++++++++++++++++ .../ClientPortal/InvitationController.php | 2 +- app/Http/Controllers/CreditController.php | 4 +-- app/Http/Controllers/InvoiceController.php | 9 ++++- .../Controllers/RecurringQuoteController.php | 9 +++-- app/Http/Controllers/SelfUpdateController.php | 5 +++ app/Http/Middleware/ContactTokenAuth.php | 2 +- .../Requests/Client/StoreClientRequest.php | 2 +- .../Requests/Payment/StorePaymentRequest.php | 2 +- .../StoreRecurringInvoiceRequest.php | 32 +++++++++--------- .../ValidCreditsPresentRule.php | 28 +++++++++++----- app/Jobs/Ninja/SendReminders.php | 7 +++- app/Jobs/Util/WebhookHandler.php | 12 +++++-- app/Models/Client.php | 2 +- app/Models/Credit.php | 6 ++-- app/Models/Webhook.php | 5 ++- app/Services/Credit/CreditService.php | 4 +-- app/Services/Credit/GetCreditPdf.php | 15 +++++---- app/Transformers/AccountTransformer.php | 2 +- composer.json | 3 +- 21 files changed, 136 insertions(+), 54 deletions(-) diff --git a/app/Console/Commands/DemoMode.php b/app/Console/Commands/DemoMode.php index dae42b242547..10b89a551b7c 100644 --- a/app/Console/Commands/DemoMode.php +++ b/app/Console/Commands/DemoMode.php @@ -364,10 +364,14 @@ class DemoMode extends Command private function createProject($client, $assigned_user_id = null) { - $vendor = Project::factory()->create([ + $project = Project::factory()->create([ 'user_id' => $client->user->id, 'company_id' => $client->company_id, + 'client_id' => $client->id, ]); + + $project->number = $this->getNextProjectNumber($project); + $project->save(); } private function createInvoice($client, $assigned_user_id = null) diff --git a/app/Console/Commands/SendRemindersCron.php b/app/Console/Commands/SendRemindersCron.php index 9eaefac5c0f3..3f64189f25f3 100644 --- a/app/Console/Commands/SendRemindersCron.php +++ b/app/Console/Commands/SendRemindersCron.php @@ -12,6 +12,10 @@ namespace App\Console\Commands; use App\Jobs\Ninja\SendReminders; +use App\Jobs\Util\WebHookHandler; +use App\Models\Invoice; +use App\Models\Quote; +use App\Models\Webhook; use Illuminate\Console\Command; class SendRemindersCron extends Command @@ -48,5 +52,34 @@ class SendRemindersCron extends Command public function handle() { SendReminders::dispatchNow(); + + $this->webHookOverdueInvoices(); + $this->webHookExpiredQuotes(); + } + + private function webHookOverdueInvoices() + { + $invoices = Invoice::where('is_deleted', 0) + ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) + ->where('balance', '>', 0) + ->whereDate('due_date', now()->subDays(1)->startOfDay()) + ->cursor(); + + $invoices->each(function ($invoice){ + WebHookHandler::dispatch(Webhook::EVENT_LATE_INVOICE, $invoice); + }); + + } + + private function webHookExpiredQuotes() + { + $quotes = Quote::where('is_deleted', 0) + ->where('status_id', Quote::STATUS_SENT) + ->whereDate('due_date', now()->subDays(1)->startOfDay()) + ->cursor(); + + $quotes->each(function ($quote){ + WebHookHandler::dispatch(Webhook::EVENT_EXPIRED_QUOTE, $quote); + }); } } diff --git a/app/Http/Controllers/ClientPortal/InvitationController.php b/app/Http/Controllers/ClientPortal/InvitationController.php index 4a1e29c45ffd..1e4e4efc22d4 100644 --- a/app/Http/Controllers/ClientPortal/InvitationController.php +++ b/app/Http/Controllers/ClientPortal/InvitationController.php @@ -40,7 +40,7 @@ class InvitationController extends Controller $key = $entity.'_id'; - $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; //todo sensitive to the route parameters here + $entity_obj = 'App\Models\\'.ucfirst(Str::camel($entity)).'Invitation'; $invitation = $entity_obj::whereRaw('BINARY `key`= ?', [$invitation_key]) ->with('contact.client') diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php index b69a79a2fa3d..acf081363458 100644 --- a/app/Http/Controllers/CreditController.php +++ b/app/Http/Controllers/CreditController.php @@ -572,10 +572,10 @@ class CreditController extends BaseController public function downloadPdf($invitation_key) { $invitation = $this->credit_repository->getInvitationByKey($invitation_key); - $contact = $invitation->contact; + // $contact = $invitation->contact; $credit = $invitation->credit; - $file_path = $credit->service()->getCreditPdf($contact); + $file_path = $credit->service()->getCreditPdf($invitation); return response()->download($file_path); } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 4bdb7a6bc22c..de858640af54 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -34,8 +34,10 @@ use App\Jobs\Util\UnlinkFile; use App\Models\Client; use App\Models\Invoice; use App\Models\InvoiceInvitation; +use App\Models\Quote; use App\Repositories\InvoiceRepository; use App\Transformers\InvoiceTransformer; +use App\Transformers\QuoteTransformer; use App\Utils\Ninja; use App\Utils\TempFile; use App\Utils\Traits\MakesHash; @@ -639,7 +641,12 @@ class InvoiceController extends BaseController break; case 'clone_to_quote': $quote = CloneInvoiceToQuoteFactory::create($invoice, auth()->user()->id); - // todo build the quote transformer and return response here + + $this->entity_transformer = QuoteTransformer::class; + $this->entity_type = Quote::class; + + return $this->itemResponse($quote); + break; case 'history': // code... diff --git a/app/Http/Controllers/RecurringQuoteController.php b/app/Http/Controllers/RecurringQuoteController.php index 164342c6164f..4f4fe111fd1c 100644 --- a/app/Http/Controllers/RecurringQuoteController.php +++ b/app/Http/Controllers/RecurringQuoteController.php @@ -23,9 +23,11 @@ use App\Http\Requests\RecurringQuote\ShowRecurringQuoteRequest; use App\Http\Requests\RecurringQuote\StoreRecurringQuoteRequest; use App\Http\Requests\RecurringQuote\UpdateRecurringQuoteRequest; use App\Jobs\Entity\ActionEntity; +use App\Models\Quote; use App\Models\RecurringQuote; use App\Repositories\BaseRepository; use App\Repositories\RecurringQuoteRepository; +use App\Transformers\QuoteTransformer; use App\Transformers\RecurringQuoteTransformer; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; @@ -583,8 +585,11 @@ class RecurringQuoteController extends BaseController // return $this->itemResponse($recurring_invoice); break; case 'clone_to_quote': - // $quote = CloneRecurringQuoteToQuoteFactory::create($recurring_invoice, auth()->user()->id); - // todo build the quote transformer and return response here + $quote = CloneRecurringQuoteToQuoteFactory::create($recurring_invoice, auth()->user()->id); + $this->entity_transformer = QuoteTransformer::class; + $this->entity_type = Quote::class; + + return $this->itemResponse($quote); break; case 'history': // code... diff --git a/app/Http/Controllers/SelfUpdateController.php b/app/Http/Controllers/SelfUpdateController.php index f3601b784bc8..338c79b2097f 100644 --- a/app/Http/Controllers/SelfUpdateController.php +++ b/app/Http/Controllers/SelfUpdateController.php @@ -84,4 +84,9 @@ class SelfUpdateController extends BaseController return response()->json(['message' => ''], 200); } + + public function checkVersion() + { + return trim(file_get_contents(config('ninja.version_url'))); + } } diff --git a/app/Http/Middleware/ContactTokenAuth.php b/app/Http/Middleware/ContactTokenAuth.php index 570d59b2bc76..86e6175fd299 100644 --- a/app/Http/Middleware/ContactTokenAuth.php +++ b/app/Http/Middleware/ContactTokenAuth.php @@ -55,7 +55,7 @@ class ContactTokenAuth //stateless, don't remember the contact. auth()->guard('contact')->login($client_contact, false); - event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars())); //todo + event(new ContactLoggedIn($client_contact, $client_contact->company, Ninja::eventVars())); } else { $error = [ 'message' => 'Invalid token', diff --git a/app/Http/Requests/Client/StoreClientRequest.php b/app/Http/Requests/Client/StoreClientRequest.php index 93c8877a22f1..5713f5b299be 100644 --- a/app/Http/Requests/Client/StoreClientRequest.php +++ b/app/Http/Requests/Client/StoreClientRequest.php @@ -75,7 +75,7 @@ class StoreClientRequest extends Request $input = $this->all(); //@todo implement feature permissions for > 100 clients - // + $settings = ClientSettings::defaults(); if (array_key_exists('settings', $input) && ! empty($input['settings'])) { diff --git a/app/Http/Requests/Payment/StorePaymentRequest.php b/app/Http/Requests/Payment/StorePaymentRequest.php index 8b6ebbd65882..93afbd206cdf 100644 --- a/app/Http/Requests/Payment/StorePaymentRequest.php +++ b/app/Http/Requests/Payment/StorePaymentRequest.php @@ -77,7 +77,7 @@ class StorePaymentRequest extends Request } if (! isset($input['amount']) || $input['amount'] == 0) { - $input['amount'] = $invoices_total - $credits_total; //todo the payment amount is always less the credit amount applied + $input['amount'] = $invoices_total - $credits_total; } $input['is_manual'] = true; diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php index 0e21a96e7802..6c5fca03ccda 100644 --- a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -109,22 +109,20 @@ class StoreRecurringInvoiceRequest extends Request } $this->replace($input); -} - -private function setAutoBillFlag($auto_bill) -{ - if($auto_bill == 'always') - return true; - - if($auto_bill == 'off') - return false; - - //todo do we need to handle optin / optout here? - -} - - public function messages() - { - return []; } + + private function setAutoBillFlag($auto_bill) + { + if($auto_bill == 'always') + return true; + + if($auto_bill == 'off') + return false; + + } + + public function messages() + { + return []; + } } diff --git a/app/Http/ValidationRules/ValidCreditsPresentRule.php b/app/Http/ValidationRules/ValidCreditsPresentRule.php index db9c7b2bb92e..46d1de283e51 100644 --- a/app/Http/ValidationRules/ValidCreditsPresentRule.php +++ b/app/Http/ValidationRules/ValidCreditsPresentRule.php @@ -46,16 +46,28 @@ class ValidCreditsPresentRule implements Rule { //todo need to ensure the clients credits are here not random ones! - if (request()->input('credits') && is_array(request()->input('credits'))) { - foreach (request()->input('credits') as $credit) { - $cred = Credit::find($this->decodePrimaryKey($credit['credit_id'])); + // if (request()->input('credits') && is_array(request()->input('credits'))) { + // foreach (request()->input('credits') as $credit) { + // $cred = Credit::find($this->decodePrimaryKey($credit['credit_id'])); - if (! $cred || $cred->balance == 0) { - return false; - } - } + // if (! $cred || $cred->balance == 0) { + // return false; + // } + // } + // } + + // return true; + + + if (request()->input('credits') && is_array(request()->input('credits'))) { + + $credit_collection = Credit::whereIn('id', $this->transformKeys(array_column(request()->input('credits'), 'credit_id'))) + ->where('balance', '>', 0) + ->get(); + + return $credit_collection->count() == count(request()->input('credits')); } - return true; + return true; } } diff --git a/app/Jobs/Ninja/SendReminders.php b/app/Jobs/Ninja/SendReminders.php index ec9d9aaf7e3a..6120332cd4c9 100644 --- a/app/Jobs/Ninja/SendReminders.php +++ b/app/Jobs/Ninja/SendReminders.php @@ -285,10 +285,13 @@ class SendReminders implements ShouldQueue * @param Invoice $invoice * @param float $amount The fee amount * @param float $percent The fee percentage amount + * * @return Invoice */ private function setLateFee($invoice, $amount, $percent) :Invoice { + $temp_invoice_balance = $invoice->balance; + if ($amount <= 0 && $percent <= 0) return $invoice; @@ -314,7 +317,9 @@ class SendReminders implements ShouldQueue /**Refresh Invoice values*/ $invoice = $invoice->calc()->getInvoice(); - //@todo update the ledger!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + $this->invoice->client->service()->updateBalance($this->invoice->balance - $temp_invoice_balance)->save(); + $this->invoice->ledger()->updateInvoiceBalance($this->invoice->balance - $temp_invoice_balance); + return $invoice; } diff --git a/app/Jobs/Util/WebhookHandler.php b/app/Jobs/Util/WebhookHandler.php index e4c947cac3e2..e607c930bc06 100644 --- a/app/Jobs/Util/WebhookHandler.php +++ b/app/Jobs/Util/WebhookHandler.php @@ -1,5 +1,13 @@ entity->company || $this->entity->company->is_disabled) { return true; } diff --git a/app/Models/Client.php b/app/Models/Client.php index b563c9fa82a0..b9aee73742cc 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -384,7 +384,7 @@ class Client extends BaseModel implements HasLocalePreference return array_search($model->id, $transformed_ids); }); } else { - $gateways = $this->company->company_gateways; //todo perhaps we can remove this or keep as a catch all. + $gateways = $this->company->company_gateways; } foreach ($gateways as $gateway) { diff --git a/app/Models/Credit.php b/app/Models/Credit.php index 9ad51f51605b..0c7632b40cf6 100644 --- a/app/Models/Credit.php +++ b/app/Models/Credit.php @@ -224,8 +224,6 @@ class Credit extends BaseModel if ($this->balance == 0) { $this->status_id = self::STATUS_APPLIED; $this->save(); - //event(new InvoiceWasPaid($this, $this->company));//todo - return; } @@ -248,10 +246,10 @@ class Credit extends BaseModel if (! $invitation) { event(new CreditWasUpdated($this, $this->company, Ninja::eventVars())); - CreateEntityPdf::dispatchNow($this, $this->company, $this->client->primary_contact()->first()); + CreateEntityPdf::dispatchNow($this->invitations->first()); } else { event(new CreditWasUpdated($this, $this->company, Ninja::eventVars())); - CreateEntityPdf::dispatchNow($invitation->credit, $invitation->company, $invitation->contact); + CreateEntityPdf::dispatchNow($invitation); } return $storage_path; diff --git a/app/Models/Webhook.php b/app/Models/Webhook.php index c7124fb9c3c2..7839b3d62da3 100644 --- a/app/Models/Webhook.php +++ b/app/Models/Webhook.php @@ -40,7 +40,10 @@ class Webhook extends BaseModel const EVENT_UPDATE_TASK = 19; const EVENT_DELETE_TASK = 20; const EVENT_APPROVE_QUOTE = 21; - + const EVENT_LATE_INVOICE = 22; + const EVENT_EXPIRED_QUOTE = 23; + const EVENT_REMIND_INVOICE = 24; + public static $valid_events = [ self::EVENT_CREATE_CLIENT, self::EVENT_CREATE_PAYMENT, diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index 4928b4d45178..cb2077378569 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -29,9 +29,9 @@ class CreditService $this->credit = $credit; } - public function getCreditPdf($contact) + public function getCreditPdf($invitation) { - return (new GetCreditPdf($this->credit, $contact))->run(); + return (new GetCreditPdf($invitation))->run(); } /** diff --git a/app/Services/Credit/GetCreditPdf.php b/app/Services/Credit/GetCreditPdf.php index 302a8dfca739..a531e593af74 100644 --- a/app/Services/Credit/GetCreditPdf.php +++ b/app/Services/Credit/GetCreditPdf.php @@ -19,14 +19,17 @@ use Illuminate\Support\Facades\Storage; class GetCreditPdf extends AbstractService { - private $credit; + public $credit; - private $contact; + public $contact; - public function __construct(Credit $credit, ClientContact $contact = null) + public $invitation; + + public function __construct($invitation) { - $this->credit = $credit; - $this->contact = $contact; + $this->invitation = $invitation; + $this->credit = $invitation->credit; + $this->contact = $invitation->contact; } public function run() @@ -44,7 +47,7 @@ class GetCreditPdf extends AbstractService $file = Storage::disk($disk)->exists($file_path); if (! $file) { - $file_path = CreateEntityPdf::dispatchNow($this->credit, $this->credit->company, $this->contact); + $file_path = CreateEntityPdf::dispatchNow($this->invitation); } return Storage::disk($disk)->path($file_path); diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 1a08165a5445..c5699a99b8c2 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -74,7 +74,7 @@ class AccountTransformer extends EntityTransformer 'utm_content' => (string) $account->utm_content, 'utm_term' => (string) $account->utm_term, 'referral_code' => (string) $account->referral_code, - 'latest_version' => (string) $account->latest_version, + 'latest_version' => (string) trim($account->latest_version), 'current_version' => (string) config('ninja.app_version'), 'updated_at' => (int) $account->updated_at, 'archived_at' => (int) $account->deleted_at, diff --git a/composer.json b/composer.json index 8f555cc18b6d..8b9865fa9164 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,8 @@ "expenses", "CRM", "Credit card billing", - "projects" + "projects", + "tasks" ], "license": "Attribution Assurance License", "authors": [