From d211e75c26f9af12f4c99f9c9e91b60a0ea79bf8 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 12:08:51 +1000 Subject: [PATCH 1/7] Prep for react --- app/Console/Commands/ReactBuilder.php | 88 +++++++++++ resources/views/react/head.blade.php | 207 ++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 app/Console/Commands/ReactBuilder.php create mode 100644 resources/views/react/head.blade.php diff --git a/app/Console/Commands/ReactBuilder.php b/app/Console/Commands/ReactBuilder.php new file mode 100644 index 000000000000..4081e76846e6 --- /dev/null +++ b/app/Console/Commands/ReactBuilder.php @@ -0,0 +1,88 @@ +getFileName(), '.js')) { + + if(str_contains($file->getFileName(), 'index.')){ + + $includes .= ''."\n"; + + } + else{ + + $includes .= ''."\n"; + } + + } + + + if(str_contains($file->getFileName(), '.css')) { + + $includes .= ''."\n"; + + } + + } + + file_put_contents(resource_path('views/react/head.blade.php'), $includes); + + } + + +} diff --git a/resources/views/react/head.blade.php b/resources/views/react/head.blade.php new file mode 100644 index 000000000000..3c3109448361 --- /dev/null +++ b/resources/views/react/head.blade.php @@ -0,0 +1,207 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 108aa22387eb54c56eface862f3a852e7bb0a931 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 12:17:06 +1000 Subject: [PATCH 2/7] Fixes for openAPI schema --- .../OpenAPI/TaskSchedulerSchema.php | 4 +- .../Controllers/TaskSchedulerController.php | 53 +++++++++++++++++-- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/OpenAPI/TaskSchedulerSchema.php b/app/Http/Controllers/OpenAPI/TaskSchedulerSchema.php index 7976fd475544..ead95fc277d4 100644 --- a/app/Http/Controllers/OpenAPI/TaskSchedulerSchema.php +++ b/app/Http/Controllers/OpenAPI/TaskSchedulerSchema.php @@ -7,7 +7,7 @@ * type="object", * * - * @OA\Property(property="paused",type="bool",example="false",description="The scheduler paused state"), + * @OA\Property(property="paused",type="boolean",example="false",description="The scheduler paused state"), * @OA\Property(property="repeat_every",type="string",example="DAY",description="Accepted values (DAY,WEEK,MONTH,3MONTHS,YEAR)"), * @OA\Property(property="start_from",type="integer",example="1652898504",description="Timestamp when we should start the scheduler, default is today"), * @OA\Property(property="date_range", type="string", example="last7", description="The string representation of the date range of data to be returned"), @@ -33,7 +33,7 @@ * schema="UpdateTaskSchedulerSchema", * type="object", * - * @OA\Property(property="paused",type="bool",example="false",description="The scheduler paused state"), + * @OA\Property(property="paused",type="boolean",example="false",description="The scheduler paused state"), * * @OA\Property(property="repeat_every",type="string",example="DAY",description="Accepted values (DAY,WEEK,MONTH,3MONTHS,YEAR)"), * @OA\Property(property="start_from",type="integer",example="1652898504",description="Timestamp when we should start the scheduler, default is today"), * diff --git a/app/Http/Controllers/TaskSchedulerController.php b/app/Http/Controllers/TaskSchedulerController.php index 7867137df920..97652e7e61b0 100644 --- a/app/Http/Controllers/TaskSchedulerController.php +++ b/app/Http/Controllers/TaskSchedulerController.php @@ -114,13 +114,24 @@ class TaskSchedulerController extends BaseController /** * @OA\GET( - * path="/api/v1/task_scheduler/{scheduler}", + * path="/api/v1/task_scheduler/{id}", * operationId="showTaskScheduler", * tags={"task_scheduler"}, * summary="Show given scheduler", * description="Get scheduler with associated job", * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Scheduler Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), * @OA\Response( * response=200, * description="success", @@ -143,14 +154,24 @@ class TaskSchedulerController extends BaseController /** * @OA\PUT( - * path="/api/v1/task_scheduler/{scheduler}", + * path="/api/v1/task_scheduler/{id}", * operationId="updateTaskScheduler", * tags={"task_scheduler"}, * summary="Update task scheduler ", * description="Update task scheduler", * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\RequestBody( + * @OA\Parameter( + * name="id", + * in="path", + * description="The Scheduler Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), * @OA\RequestBody( * required=true, * @OA\JsonContent(ref="#/components/schemas/UpdateTaskSchedulerSchema") * ), @@ -181,13 +202,24 @@ class TaskSchedulerController extends BaseController /** * @OA\PUT( - * path="/api/v1/task_scheduler/{scheduler}/update_job/", + * path="/api/v1/task_scheduler/{id}/update_job/", * operationId="updateTaskSchedulerJob", * tags={"task_scheduler"}, * summary="Update job for a task scheduler ", * description="Update job for a task scheduler | if we are changing action for a job, we should send the request for a new job same as we are creating new scheduler", * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Scheduler Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), * @OA\RequestBody( * required=true, * @OA\JsonContent(ref="#/components/schemas/UpdateJobForASchedulerSchema") @@ -219,13 +251,24 @@ class TaskSchedulerController extends BaseController /** * @OA\DELETE( - * path="/api/v1/task_scheduler/{scheduler}", + * path="/api/v1/task_scheduler/{id}", * operationId="destroyTaskScheduler", * tags={"task_scheduler"}, * summary="Destroy Task Scheduler", * description="Destroy task scheduler and its associated job", * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter( + * name="id", + * in="path", + * description="The Scheduler Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), * @OA\Response( * response=200, * description="success", From c08cdc4927a7e1ce80f0336c5d84894cd10a59a7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 12:17:59 +1000 Subject: [PATCH 3/7] Ensure query parameter is a string --- app/Filters/QueryFilters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Filters/QueryFilters.php b/app/Filters/QueryFilters.php index 70ee66016bce..d16619ce85a0 100644 --- a/app/Filters/QueryFilters.php +++ b/app/Filters/QueryFilters.php @@ -81,7 +81,7 @@ abstract class QueryFilters continue; } - if (strlen($value)) { + if (is_string($value) && strlen($value)) { $this->$name($value); } else { $this->$name(); From 13a1447b797297c5882b2336b09cac0e4a9fc1e7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 13:10:32 +1000 Subject: [PATCH 4/7] Padding out react application --- app/Console/Kernel.php | 3 +- app/Http/Controllers/BaseController.php | 5 +++- .../Controllers/TaskSchedulerController.php | 1 - app/Jobs/Ninja/TaskScheduler.php | 30 ++++++++++++------- app/Jobs/Report/SendToAdmin.php | 1 + app/Models/Scheduler.php | 2 +- .../TaskScheduler/TaskSchedulerService.php | 1 + config/ninja.php | 4 +-- resources/views/react/index.blade.php | 20 +++++++++++++ 9 files changed, 49 insertions(+), 18 deletions(-) create mode 100644 resources/views/react/index.blade.php diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index f77695f6b35b..5ef319102309 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -77,10 +77,9 @@ class Kernel extends ConsoleKernel $schedule->job(new TaskScheduler())->daily()->withoutOverlapping(); $schedule->job(new SystemMaintenance)->weekly()->withoutOverlapping(); + if(Ninja::isSelfHost()) { - - $schedule->call(function () { Account::whereNotNull('id')->update(['is_scheduler_running' => true]); })->everyFiveMinutes(); diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php index 93a4cbee114b..e048291d7230 100644 --- a/app/Http/Controllers/BaseController.php +++ b/app/Http/Controllers/BaseController.php @@ -780,7 +780,10 @@ class BaseController extends Controller $this->buildCache(); - return response()->view('index.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false); + if(config('ninja.react_app_enabled')) + return response()->view('react.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false); + else + return response()->view('index.index', $data)->header('X-Frame-Options', 'SAMEORIGIN', false); } diff --git a/app/Http/Controllers/TaskSchedulerController.php b/app/Http/Controllers/TaskSchedulerController.php index 97652e7e61b0..1961db6db8bd 100644 --- a/app/Http/Controllers/TaskSchedulerController.php +++ b/app/Http/Controllers/TaskSchedulerController.php @@ -63,7 +63,6 @@ class TaskSchedulerController extends BaseController public function index() { - set_time_limit(45); $schedulers = Scheduler::where('company_id', auth()->user()->company()->id); diff --git a/app/Jobs/Ninja/TaskScheduler.php b/app/Jobs/Ninja/TaskScheduler.php index af7f74efaf17..20a819ecbd05 100644 --- a/app/Jobs/Ninja/TaskScheduler.php +++ b/app/Jobs/Ninja/TaskScheduler.php @@ -46,24 +46,35 @@ class TaskScheduler implements ShouldQueue */ public function handle() { - foreach (MultiDB::$dbs as $db) { + foreach (MultiDB::$dbs as $db) + { MultiDB::setDB($db); + $pending_schedulers = $this->fetchJobs(); - foreach ($pending_schedulers as $scheduler) { - $this->doJob($scheduler); - } + + Scheduler::with('company','job') + ->where('paused', false) + ->where('is_deleted', false) + ->whereDate('scheduled_run', '<=', Carbon::now()) + ->cursor() + ->each(function ($scheduler){ + $this->doJob($scheduler); + + }); + } + } private function doJob(Scheduler $scheduler) { $job = $scheduler->job; + $company = $scheduler->company; - $company = Company::find($job->company_id); - if (!$job || !$company) { + if (!$job) return; - } + $parameters = $job->parameters; @@ -120,10 +131,7 @@ class TaskScheduler implements ShouldQueue private function fetchJobs() { - return Scheduler::where('paused', false) - ->where('is_deleted', false) - ->whereDate('scheduled_run', '<=', Carbon::now()) - ->cursor(); + return ; } } diff --git a/app/Jobs/Report/SendToAdmin.php b/app/Jobs/Report/SendToAdmin.php index 8c2e779f9294..a2624eeaf9d2 100644 --- a/app/Jobs/Report/SendToAdmin.php +++ b/app/Jobs/Report/SendToAdmin.php @@ -48,6 +48,7 @@ class SendToAdmin implements ShouldQueue public function handle() { + MultiDB::setDb($this->company->db); $export = new $this->report_class($this->company, $this->request); $csv = $export->run(); diff --git a/app/Models/Scheduler.php b/app/Models/Scheduler.php index 38943cb709b3..bc279d293b5e 100644 --- a/app/Models/Scheduler.php +++ b/app/Models/Scheduler.php @@ -37,8 +37,8 @@ class Scheduler extends BaseModel 'paused', 'repeat_every', 'scheduled_run', - 'company_id' ]; + protected $casts = [ 'start_from' => 'timestamp', 'scheduled_run' => 'timestamp', diff --git a/app/Services/TaskScheduler/TaskSchedulerService.php b/app/Services/TaskScheduler/TaskSchedulerService.php index 4bce031574c6..1d5e9a614d10 100644 --- a/app/Services/TaskScheduler/TaskSchedulerService.php +++ b/app/Services/TaskScheduler/TaskSchedulerService.php @@ -56,6 +56,7 @@ class TaskSchedulerService $scheduler->scheduled_run = $request->get('start_from') ? Carbon::parse((int)$request->get('start_from')) : Carbon::now();; $scheduler->company_id = auth()->user()->company()->id; $scheduler->save(); + $this->createJob($request, $scheduler); } diff --git a/config/ninja.php b/config/ninja.php index 37b48bac0f1b..12b380991949 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -187,7 +187,7 @@ return [ 'ninja_apple_api_key' => env('APPLE_API_KEY', false), 'ninja_apple_private_key' => env('APPLE_PRIVATE_KEY', false), 'ninja_apple_bundle_id' => env('APPLE_BUNDLE_ID', false), - 'ninja_apple_issuer_id' => env('APPLE_ISSUER_ID', false) - + 'ninja_apple_issuer_id' => env('APPLE_ISSUER_ID', false), + 'react_app_enabled' => env('REACT_APP_ENABLED', false), ]; diff --git a/resources/views/react/index.blade.php b/resources/views/react/index.blade.php new file mode 100644 index 000000000000..d490313bc340 --- /dev/null +++ b/resources/views/react/index.blade.php @@ -0,0 +1,20 @@ + + + + + + + {{ config('ninja.app_name') }} + + + @include('react.head') + + + + + +
+ + + + From cf141e36c8c7e5123bcb7cb0bed3b3654cd47462 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 17:01:15 +1000 Subject: [PATCH 5/7] Fixes for scheduler --- .../Requests/Report/GenericReportRequest.php | 3 + app/Http/Requests/RuntimeFormRequest.php | 7 --- .../CreateScheduledTaskRequest.php | 10 ++++ .../TaskScheduler/UpdateScheduleRequest.php | 10 ++-- .../TaskScheduler/TaskSchedulerService.php | 56 ++++++++++--------- tests/Feature/Scheduler/SchedulerTest.php | 54 ++++++++++++++---- 6 files changed, 91 insertions(+), 49 deletions(-) diff --git a/app/Http/Requests/Report/GenericReportRequest.php b/app/Http/Requests/Report/GenericReportRequest.php index b4de80751e83..5658942dc6dd 100644 --- a/app/Http/Requests/Report/GenericReportRequest.php +++ b/app/Http/Requests/Report/GenericReportRequest.php @@ -47,6 +47,9 @@ class GenericReportRequest extends Request if(!array_key_exists('report_keys', $input)) $input['report_keys'] = []; + if(!array_key_exists('send_email', $input)) + $input['send_email'] = true; + $this->replace($input); } } diff --git a/app/Http/Requests/RuntimeFormRequest.php b/app/Http/Requests/RuntimeFormRequest.php index 3f028fc2848a..680985c9d1b9 100644 --- a/app/Http/Requests/RuntimeFormRequest.php +++ b/app/Http/Requests/RuntimeFormRequest.php @@ -22,13 +22,6 @@ trait RuntimeFormRequest $instance = $validator->getValidatorInstance(); return $instance; - // if ($instance->fails()) { - // return $instance->errors(); - // } - - // $validator->passedValidation(); - - // return $validator->all(); } diff --git a/app/Http/Requests/TaskScheduler/CreateScheduledTaskRequest.php b/app/Http/Requests/TaskScheduler/CreateScheduledTaskRequest.php index bde04e199ced..b4710301ff7f 100644 --- a/app/Http/Requests/TaskScheduler/CreateScheduledTaskRequest.php +++ b/app/Http/Requests/TaskScheduler/CreateScheduledTaskRequest.php @@ -27,4 +27,14 @@ class CreateScheduledTaskRequest extends Request 'job' => 'required', ]; } + + public function prepareForValidation() + { + $input = $this->all(); + + if(!array_key_exists('start_from', $input)) + $input['start_from'] = now(); + + $this->replace($input); + } } diff --git a/app/Http/Requests/TaskScheduler/UpdateScheduleRequest.php b/app/Http/Requests/TaskScheduler/UpdateScheduleRequest.php index 643edbadee32..1f1d888ce75c 100644 --- a/app/Http/Requests/TaskScheduler/UpdateScheduleRequest.php +++ b/app/Http/Requests/TaskScheduler/UpdateScheduleRequest.php @@ -41,13 +41,13 @@ class UpdateScheduleRequest extends Request public function prepareForValidation() { - $request = $this->all(); + $input = $this->all(); - if (isset($request['start_from'])) { - $request['scheduled_run'] = Carbon::parse((int)$request['start_from']); - $request['start_from'] = Carbon::parse((int)$request['start_from']); + if (isset($input['start_from'])) { + $input['scheduled_run'] = Carbon::parse((int)$input['start_from']); + $input['start_from'] = Carbon::parse((int)$input['start_from']); } - $this->replace($request); + $this->replace($input); } } diff --git a/app/Services/TaskScheduler/TaskSchedulerService.php b/app/Services/TaskScheduler/TaskSchedulerService.php index 1d5e9a614d10..1219510aa12d 100644 --- a/app/Services/TaskScheduler/TaskSchedulerService.php +++ b/app/Services/TaskScheduler/TaskSchedulerService.php @@ -90,98 +90,100 @@ class TaskSchedulerService $rules = (new GenericReportRequest)->rules(); //custom rules for example here we require date_range but in genericRequest class we don't $rules['date_range'] = 'string|required'; - $validatedJobData = $request->validate($rules); + + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_CLIENT_REPORT; $job->action_class = $this->getClassPath(ClientExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_CLIENT_CONTACT_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_CLIENT_CONTACT_REPORT; $job->action_class = $this->getClassPath(ContactExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_CREDIT_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_CREDIT_REPORT; $job->action_class = $this->getClassPath(CreditExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_DOCUMENT_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_DOCUMENT_REPORT; $job->action_class = $this->getClassPath(DocumentExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_EXPENSE_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_EXPENSE_REPORT; $job->action_class = $this->getClassPath(ExpenseExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_INVOICE_ITEM_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_INVOICE_ITEM_REPORT; $job->action_class = $this->getClassPath(InvoiceItemExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_INVOICE_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_INVOICE_REPORT; $job->action_class = $this->getClassPath(InvoiceExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_PAYMENT_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_PAYMENT_REPORT; $job->action_class = $this->getClassPath(PaymentExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_PRODUCT_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_PRODUCT_REPORT; $job->action_class = $this->getClassPath(ProductExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_PROFIT_AND_LOSS_REPORT: - $rules = (new ProfitLossRequest())->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_PROFIT_AND_LOSS_REPORT; $job->action_class = $this->getClassPath(ProfitAndLoss::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_QUOTE_ITEM_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_QUOTE_ITEM_REPORT; $job->action_class = $this->getClassPath(QuoteItemExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_QUOTE_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_QUOTE_REPORT; $job->action_class = $this->getClassPath(QuoteExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_RECURRING_INVOICE_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_RECURRING_INVOICE_REPORT; $job->action_class = $this->getClassPath(RecurringInvoiceExport::class); $job->parameters = $validatedJobData; break; case ScheduledJob::CREATE_TASK_REPORT: - $rules = (new GenericReportRequest)->rules(); - $validatedJobData = $request->validate($rules); + $validator = GenericReportRequest::runFormRequest($request->all()); + $validatedJobData = $validator->validate(); $job->action_name = ScheduledJob::CREATE_TASK_REPORT; $job->action_class = $this->getClassPath(TaskExport::class); $job->parameters = $validatedJobData; diff --git a/tests/Feature/Scheduler/SchedulerTest.php b/tests/Feature/Scheduler/SchedulerTest.php index d9a616e564e5..3a981f2cda69 100644 --- a/tests/Feature/Scheduler/SchedulerTest.php +++ b/tests/Feature/Scheduler/SchedulerTest.php @@ -15,6 +15,7 @@ use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Support\Facades\Session; use Tests\MockUnitData; use Tests\TestCase; +use Illuminate\Validation\ValidationException; class SchedulerTest extends TestCase { @@ -35,10 +36,12 @@ class SchedulerTest extends TestCase $this->makeTestData(); - $this->withoutMiddleware( ThrottleRequests::class ); + + // $this->withoutExceptionHandling(); + } public function testSchedulerCantBeCreatedWithWrongData() @@ -48,13 +51,23 @@ class SchedulerTest extends TestCase 'job' => ScheduledJob::CREATE_CLIENT_REPORT, 'date_key' => '123', 'report_keys' => ['test'], - // 'date_range' => 'all', + 'date_range' => 'all', + // 'start_from' => '2022-01-01' ]; + $response = false; + + // try { $response = $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token, ])->post('/api/v1/task_scheduler/', $data); + // } catch (ValidationException $e) { + // $message = json_decode($e->validator->getMessageBag(), 1); + // nlog($message); + // } + // $response->assertStatus(200); + $response->assertSessionHasErrors(); @@ -62,10 +75,14 @@ class SchedulerTest extends TestCase public function testSchedulerCanBeUpdated() { - $this->createScheduler(); + $response = $this->createScheduler(); + nlog($response); + $arr = $response->json(); + $id = $arr['data']['id']; + + $scheduler = Scheduler::find($this->decodePrimaryKey($id)); - $scheduler = Scheduler::first(); $updateData = [ 'start_from' => 1655934741 ]; @@ -80,10 +97,12 @@ class SchedulerTest extends TestCase public function testSchedulerCanBeSeen() { - $this->createScheduler(); + $response = $this->createScheduler(); + $arr = $response->json(); + $id = $arr['data']['id']; - $scheduler = Scheduler::first(); + $scheduler = Scheduler::find($this->decodePrimaryKey($id)); $response = $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), @@ -98,9 +117,13 @@ class SchedulerTest extends TestCase public function testSchedulerCanBeDeleted() { - $this->createScheduler(); + $response = $this->createScheduler(); + + $arr = $response->json(); + $id = $arr['data']['id']; + + $scheduler = Scheduler::find($this->decodePrimaryKey($id)); - $scheduler = Scheduler::first(); $response = $this->withHeaders([ 'X-API-SECRET' => config('ninja.api_secret'), 'X-API-TOKEN' => $this->token, @@ -112,9 +135,13 @@ class SchedulerTest extends TestCase public function testSchedulerJobCanBeUpdated() { - $this->createScheduler(); + $response = $this->createScheduler(); + + $arr = $response->json(); + $id = $arr['data']['id']; + + $scheduler = Scheduler::find($this->decodePrimaryKey($id)); - $scheduler = Scheduler::first(); $this->assertSame('create_client_report', $scheduler->job->action_name); $updateData = [ @@ -130,6 +157,7 @@ class SchedulerTest extends TestCase $updatedSchedulerJob = Scheduler::first()->job->action_name; $arr = $response->json(); + $this->assertSame('create_credit_report', $arr['data']['job']['action_name']); } @@ -137,6 +165,11 @@ class SchedulerTest extends TestCase { $response = $this->createScheduler(); + $arr = $response->json(); + $id = $arr['data']['id']; + + $scheduler = Scheduler::find($this->decodePrimaryKey($id)); + $all_schedulers = Scheduler::count(); $this->assertSame(1, $all_schedulers); @@ -153,6 +186,7 @@ class SchedulerTest extends TestCase 'date_key' => '123', 'report_keys' => ['test'], 'date_range' => 'all', + 'start_from' => '2022-01-01' ]; return $response = $this->withHeaders([ From 1e43e172a7e526977c60518d074d41701cab511c Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 27 May 2022 18:25:32 +1000 Subject: [PATCH 6/7] Actitivity output for React --- app/Http/Controllers/ActivityController.php | 24 +++++ app/Jobs/Ninja/TaskScheduler.php | 5 +- app/Models/Activity.php | 28 +++--- app/Transformers/ActivityTransformer.php | 87 ++++++++++++++++++- app/Transformers/TaskSchedulerTransformer.php | 1 + resources/lang/en/texts.php | 38 ++++++-- 6 files changed, 163 insertions(+), 20 deletions(-) diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php index 01c432465659..a3605d22c947 100644 --- a/app/Http/Controllers/ActivityController.php +++ b/app/Http/Controllers/ActivityController.php @@ -91,6 +91,30 @@ class ActivityController extends BaseController $activities = Activity::orderBy('created_at', 'DESC')->company() ->take($default_activities); + if($request->has('react')){ + + $system = ctrans('texts.system'); + + $data = $activities->cursor()->map(function ($activity) use($system){ + + return ctrans('texts.activity_'.$activity->activity_type_id,[ + 'client' => $activity->client ? $activity->client->present()->name() : $system, + 'contact' => $activity->contact ? $activity->contact->first_name . " " .$activity->contact->last_name : $system, + 'quote' => $activity->quote ? $activity->quote->number : $system, + 'user' => $activity->user ? $activity->user->present()->name() : $system, + 'expense' => $activity->expense ? $activity->expense->number : $system, + 'invoice' => $activity->invoice ? $activity->invoice->number : $system, + 'recurring_invoice' => $activity->recurring_invoice ? $activity->recurring_invoice->number : $system, + 'payment' => $activity->payment ? $activity->payment->number : $system, + 'credit' => $activity->credit ? $activity->credit->number : $system, + 'task' => $activity->task ? $activity->task->number : $system, + ]); + + }); + + return response()->json(['data' => $data->toArray()], 200); + } + return $this->listResponse($activities); } diff --git a/app/Jobs/Ninja/TaskScheduler.php b/app/Jobs/Ninja/TaskScheduler.php index 20a819ecbd05..eaf80e608762 100644 --- a/app/Jobs/Ninja/TaskScheduler.php +++ b/app/Jobs/Ninja/TaskScheduler.php @@ -56,9 +56,10 @@ class TaskScheduler implements ShouldQueue Scheduler::with('company','job') ->where('paused', false) ->where('is_deleted', false) - ->whereDate('scheduled_run', '<=', Carbon::now()) + ->where('scheduled_run', '<', now()) ->cursor() ->each(function ($scheduler){ + $this->doJob($scheduler); }); @@ -69,6 +70,8 @@ class TaskScheduler implements ShouldQueue private function doJob(Scheduler $scheduler) { + nlog("Doing job {$scheduler->id}"); + $job = $scheduler->job; $company = $scheduler->company; diff --git a/app/Models/Activity.php b/app/Models/Activity.php index e53cc6b877ce..f00042dc8d74 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -70,6 +70,7 @@ class Activity extends StaticModel const ARCHIVE_USER = 50; const DELETE_USER = 51; const RESTORE_USER = 52; + const MARK_SENT_INVOICE = 53; // not needed? const PAID_INVOICE = 54; // const EMAIL_INVOICE_FAILED = 57; @@ -138,13 +139,11 @@ class Activity extends StaticModel return $this->hasOne(Backup::class); } - public function history() { return $this->hasOne(Backup::class); } - /** * @return mixed */ @@ -177,6 +176,14 @@ class Activity extends StaticModel return $this->belongsTo(Invoice::class)->withTrashed(); } + /** + * @return mixed + */ + public function recurring_invoice() + { + return $this->belongsTo(RecurringInvoice::class)->withTrashed(); + } + public function credit() { return $this->belongsTo(Credit::class)->withTrashed(); @@ -198,15 +205,16 @@ class Activity extends StaticModel return $this->belongsTo(Payment::class)->withTrashed(); } - // public function task() - // { - // return $this->belongsTo(Task::class)->withTrashed(); - // } + public function expense() + { + return $this->belongsTo(Expense::class)->withTrashed(); + } + + public function task() + { + return $this->belongsTo(Task::class)->withTrashed(); + } - // public function expense() - // { - // return $this->belongsTo(Expense::class)->withTrashed(); - // } public function company() { diff --git a/app/Transformers/ActivityTransformer.php b/app/Transformers/ActivityTransformer.php index f4ee220704d5..c49ae0038672 100644 --- a/app/Transformers/ActivityTransformer.php +++ b/app/Transformers/ActivityTransformer.php @@ -13,6 +13,10 @@ namespace App\Transformers; use App\Models\Activity; use App\Models\Backup; +use App\Models\ClientContact; +use App\Models\Invoice; +use App\Models\Task; +use App\Models\User; use App\Utils\Traits\MakesHash; class ActivityTransformer extends EntityTransformer @@ -25,7 +29,17 @@ class ActivityTransformer extends EntityTransformer * @var array */ protected $availableIncludes = [ - 'history' + 'history', + 'user', + 'client', + 'contact', + 'recurring_invoice', + 'invoice', + 'credit', + 'quote', + 'payment', + 'expense', + 'task', ]; /** @@ -66,4 +80,75 @@ class ActivityTransformer extends EntityTransformer return $this->includeItem($activity->backup, $transformer, Backup::class); } + + public function includeClient(Activity $activity) + { + $transformer = new ClientTransformer($this->serializer); + + return $this->includeItem($activity->client, $transformer, Client::class); + } + + public function includeContact(Activity $activity) + { + $transformer = new ClientContactTransformer($this->serializer); + + return $this->includeItem($activity->contact, $transformer, ClientContact::class); + } + + public function includeRecurringInvoice(Activity $activity) + { + $transformer = new RecurringInvoiceTransformer($this->serializer); + + return $this->includeItem($activity->recurring_invoice, $transformer, RecurringInvoice::class); + } + + public function includeQuote(Activity $activity) + { + $transformer = new RecurringInvoiceTransformer($this->serializer); + + return $this->includeItem($activity->quote, $transformer, Quote::class); + } + + public function includeInvoice(Activity $activity) + { + $transformer = new InvoiceTransformer($this->serializer); + + return $this->includeItem($activity->invoice, $transformer, Invoice::class); + } + + public function includeCredit(Activity $activity) + { + $transformer = new CreditTransformer($this->serializer); + + return $this->includeItem($activity->credit, $transformer, Credit::class); + } + + public function includePayment(Activity $activity) + { + $transformer = new PaymentTransformer($this->serializer); + + return $this->includeItem($activity->payment, $transformer, Payment::class); + } + + public function includeUser(Activity $activity) + { + $transformer = new UserTransformer($this->serializer); + + return $this->includeItem($activity->user, $transformer, User::class); + } + + public function includeExpense(Activity $activity) + { + $transformer = new ExpenseTransformer($this->serializer); + + return $this->includeItem($activity->expense, $transformer, Expense::class); + } + + public function includeTask(Activity $activity) + { + $transformer = new TaskTransformer($this->serializer); + + return $this->includeItem($activity->task, $transformer, Task::class); + } + } diff --git a/app/Transformers/TaskSchedulerTransformer.php b/app/Transformers/TaskSchedulerTransformer.php index bc36393e2db0..7cb96dc34293 100644 --- a/app/Transformers/TaskSchedulerTransformer.php +++ b/app/Transformers/TaskSchedulerTransformer.php @@ -35,6 +35,7 @@ class TaskSchedulerTransformer extends EntityTransformer { return [ 'id' => $this->encodePrimaryKey($scheduler->id), + 'is_deleted' => (bool)$scheduler->is_deleted, 'paused' => (bool)$scheduler->paused, 'repeat_every' => (string)$scheduler->repeat_every, 'start_from' => (int)$scheduler->start_from, diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index edc9e2141401..bf22e6982ee8 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -794,12 +794,12 @@ $LANG = array( 'activity_45' => ':user deleted task :task', 'activity_46' => ':user restored task :task', 'activity_47' => ':user updated expense :expense', - 'activity_48' => ':user updated ticket :ticket', - 'activity_49' => ':user closed ticket :ticket', - 'activity_50' => ':user merged ticket :ticket', - 'activity_51' => ':user split ticket :ticket', - 'activity_52' => ':contact opened ticket :ticket', - 'activity_53' => ':contact reopened ticket :ticket', + 'activity_48' => ':user created user :user', + 'activity_49' => ':user updated user :user', + 'activity_50' => ':user archived user :user', + 'activity_51' => ':user deleted user :user', + 'activity_52' => ':user restored user :user', + 'activity_53' => ':user marked sent :invoice', 'activity_54' => ':user reopened ticket :ticket', 'activity_55' => ':contact replied ticket :ticket', 'activity_56' => ':user viewed ticket :ticket', @@ -4583,8 +4583,30 @@ $LANG = array( 'alternate_pdf_viewer' => 'Alternate PDF Viewer', 'alternate_pdf_viewer_help' => 'Improve scrolling over the PDF preview [BETA]', 'currency_cayman_island_dollar' => 'Cayman Island Dollar', - 'download_report_description' => 'Please see attached file to check your report.' - + 'download_report_description' => 'Please see attached file to check your report.', + 'left' => 'Left', + 'right' => 'Right', + 'center' => 'Center', + 'page_numbering' => 'Page Numbering', + 'page_numbering_alignment' => 'Page Numbering Alignment', + 'invoice_sent_notification_label' => 'Invoice Sent', + 'show_product_description' => 'Show Product Description', + 'show_product_description_help' => 'Include the description in the product dropdown', + 'invoice_items' => 'Invoice Items', + 'quote_items' => 'Quote Items', + 'profitloss' => 'Profit and Loss', + 'import_format' => 'Import Format', + 'export_format' => 'Export Format', + 'export_type' => 'Export Type', + 'stop_on_unpaid' => 'Stop On Unpaid', + 'stop_on_unpaid_help' => 'Stop creating recurring invoices if the last invoice is unpaid.', + 'use_quote_terms' => 'Use Quote Terms', + 'use_quote_terms_help' => 'When converting a quote to an invoice', + 'add_country' => 'Add Country', + 'enable_tooltips' => 'Enable Tooltips', + 'enable_tooltips_help' => 'Show tooltips when hovering the mouse', + 'multiple_client_error' => 'Error: records belong to more than one client', + 'login_label' => 'Login to an existing account', ); From df3a1832fe1c1b22a892bfb241e9c50749db8de4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 28 May 2022 10:20:32 +1000 Subject: [PATCH 7/7] Fixes for trial plans --- app/Http/Controllers/ClientPortal/NinjaPlanController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/ClientPortal/NinjaPlanController.php b/app/Http/Controllers/ClientPortal/NinjaPlanController.php index 1c8abd67003a..1f0544e5f753 100644 --- a/app/Http/Controllers/ClientPortal/NinjaPlanController.php +++ b/app/Http/Controllers/ClientPortal/NinjaPlanController.php @@ -125,13 +125,14 @@ class NinjaPlanController extends Controller $gateway_driver->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]); //set free trial - // $account = auth()->guard('contact')->user()->company->account; if(auth()->guard('contact')->user()->client->custom_value2){ MultiDB::findAndSetDbByAccountKey(auth()->guard('contact')->user()->client->custom_value2); $account = Account::where('key', auth()->guard('contact')->user()->client->custom_value2)->first(); $account->trial_started = now(); $account->trial_plan = 'pro'; $account->plan = 'pro'; + $account->plan_term = 'month'; + $account->plan_started = now(); $account->plan_expires = now()->addDays(14); $account->save(); }