mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-03 07:34:34 -04:00
Refactor for scheduled tasks
This commit is contained in:
parent
d1078e1ba1
commit
9e415b420c
32
app/Factory/SchedulerFactory.php
Normal file
32
app/Factory/SchedulerFactory.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Factory;
|
||||||
|
|
||||||
|
use App\Models\Scheduler;
|
||||||
|
|
||||||
|
class SchedulerFactory
|
||||||
|
{
|
||||||
|
public static function create($company_id, $user_id) :Scheduler
|
||||||
|
{
|
||||||
|
$scheduler = new Scheduler;
|
||||||
|
|
||||||
|
$scheduler->name = '';
|
||||||
|
$scheduler->company_id = $company_id;
|
||||||
|
$scheduler->user_id = $user_id;
|
||||||
|
$scheduler->parameters = [];
|
||||||
|
$scheduler->is_paused = false;
|
||||||
|
$scheduler->is_deleted = false;
|
||||||
|
$scheduler->template = '';
|
||||||
|
|
||||||
|
return $scheduler;
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
@ -11,37 +11,40 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Http\Requests\TaskScheduler\CreateScheduledTaskRequest;
|
use App\Factory\SchedulerFactory;
|
||||||
use App\Http\Requests\TaskScheduler\UpdateScheduleRequest;
|
use App\Http\Requests\TaskScheduler\CreateSchedulerRequest;
|
||||||
|
use App\Http\Requests\TaskScheduler\ShowSchedulerRequest;
|
||||||
|
use App\Http\Requests\TaskScheduler\StoreSchedulerRequest;
|
||||||
|
use App\Http\Requests\TaskScheduler\UpdateSchedulerRequest;
|
||||||
|
use App\Http\Requests\Task\DestroySchedulerRequest;
|
||||||
use App\Jobs\Ninja\TaskScheduler;
|
use App\Jobs\Ninja\TaskScheduler;
|
||||||
use App\Jobs\Report\ProfitAndLoss;
|
use App\Jobs\Report\ProfitAndLoss;
|
||||||
use App\Models\Scheduler;
|
use App\Models\Scheduler;
|
||||||
use App\Repositories\TaskSchedulerRepository;
|
use App\Repositories\SchedulerRepository;
|
||||||
use App\Transformers\TaskSchedulerTransformer;
|
use App\Transformers\SchedulerTransformer;
|
||||||
|
use App\Utils\Traits\MakesHash;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
class TaskSchedulerController extends BaseController
|
class TaskSchedulerController extends BaseController
|
||||||
{
|
{
|
||||||
|
use MakesHash;
|
||||||
|
|
||||||
protected $entity_type = Scheduler::class;
|
protected $entity_type = Scheduler::class;
|
||||||
|
|
||||||
protected $entity_transformer = TaskSchedulerTransformer::class;
|
protected $entity_transformer = SchedulerTransformer::class;
|
||||||
|
|
||||||
protected TaskSchedulerRepository $scheduler_repository;
|
public function __construct(protected SchedulerRepository $scheduler_repository)
|
||||||
|
|
||||||
public function __construct(TaskSchedulerRepository $scheduler_repository)
|
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this->scheduler_repository = $scheduler_repository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\GET(
|
* @OA\GET(
|
||||||
* path="/api/v1/task_scheduler/",
|
* path="/api/v1/task_schedulers/",
|
||||||
* operationId="getTaskSchedulers",
|
* operationId="getTaskSchedulers",
|
||||||
* tags={"task_scheduler"},
|
* tags={"task_schedulers"},
|
||||||
* summary="Task Scheduler Index",
|
* summary="Task Scheduler Index",
|
||||||
* description="Get all schedulers with associated jobs",
|
* description="Get all schedulers with associated jobs",
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
@ -67,11 +70,57 @@ class TaskSchedulerController extends BaseController
|
|||||||
return $this->listResponse($schedulers);
|
return $this->listResponse($schedulers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @param CreateSchedulerRequest $request The request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/api/v1/invoices/task_schedulers",
|
||||||
|
* operationId="getTaskScheduler",
|
||||||
|
* tags={"task_schedulers"},
|
||||||
|
* summary="Gets a new blank scheduler object",
|
||||||
|
* description="Returns a blank object with default values",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/include"),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="A blank scheduler object",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
*
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function create(CreateSchedulerRequest $request)
|
||||||
|
{
|
||||||
|
$scheduler = SchedulerFactory::create(auth()->user()->company()->id, auth()->user()->id);
|
||||||
|
|
||||||
|
return $this->itemResponse($scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\Post(
|
* @OA\Post(
|
||||||
* path="/api/v1/task_scheduler/",
|
* path="/api/v1/task_schedulers/",
|
||||||
* operationId="createTaskScheduler",
|
* operationId="createTaskScheduler",
|
||||||
* tags={"task_scheduler"},
|
* tags={"task_schedulers"},
|
||||||
* summary="Create task scheduler with job ",
|
* summary="Create task scheduler with job ",
|
||||||
* description="Create task scheduler with a job (action(job) request should be sent via request also. Example: We want client report to be job which will be run
|
* description="Create task scheduler with a job (action(job) request should be sent via request also. Example: We want client report to be job which will be run
|
||||||
* multiple times, we should send the same parameters in the request as we would send if we wanted to get report, see example",
|
* multiple times, we should send the same parameters in the request as we would send if we wanted to get report, see example",
|
||||||
@ -100,19 +149,18 @@ class TaskSchedulerController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function store(CreateScheduledTaskRequest $request)
|
public function store(StoreSchedulerRequest $request)
|
||||||
{
|
{
|
||||||
$scheduler = new Scheduler();
|
$scheduler = $this->scheduler_repository->save($request->all(), SchedulerFactory::create(auth()->user()->company()->id, auth()->user()->id));
|
||||||
$scheduler->service()->store($scheduler, $request);
|
|
||||||
|
|
||||||
return $this->itemResponse($scheduler);
|
return $this->itemResponse($scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\GET(
|
* @OA\GET(
|
||||||
* path="/api/v1/task_scheduler/{id}",
|
* path="/api/v1/task_schedulers/{id}",
|
||||||
* operationId="showTaskScheduler",
|
* operationId="showTaskScheduler",
|
||||||
* tags={"task_scheduler"},
|
* tags={"task_schedulers"},
|
||||||
* summary="Show given scheduler",
|
* summary="Show given scheduler",
|
||||||
* description="Get scheduler with associated job",
|
* description="Get scheduler with associated job",
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
@ -142,16 +190,16 @@ class TaskSchedulerController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function show(Scheduler $scheduler)
|
public function show(ShowSchedulerRequest $request, Scheduler $scheduler)
|
||||||
{
|
{
|
||||||
return $this->itemResponse($scheduler);
|
return $this->itemResponse($scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\PUT(
|
* @OA\PUT(
|
||||||
* path="/api/v1/task_scheduler/{id}",
|
* path="/api/v1/task_schedulers/{id}",
|
||||||
* operationId="updateTaskScheduler",
|
* operationId="updateTaskScheduler",
|
||||||
* tags={"task_scheduler"},
|
* tags={"task_schedulers"},
|
||||||
* summary="Update task scheduler ",
|
* summary="Update task scheduler ",
|
||||||
* description="Update task scheduler",
|
* description="Update task scheduler",
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
@ -168,7 +216,7 @@ class TaskSchedulerController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* ), * @OA\RequestBody(
|
* ), * @OA\RequestBody(
|
||||||
* required=true,
|
* required=true,
|
||||||
* @OA\JsonContent(ref="#/components/schemas/UpdateTaskSchedulerSchema")
|
* @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema")
|
||||||
* ),
|
* ),
|
||||||
* @OA\Response(
|
* @OA\Response(
|
||||||
* response=200,
|
* response=200,
|
||||||
@ -189,18 +237,18 @@ class TaskSchedulerController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function update(Scheduler $scheduler, UpdateScheduleRequest $request)
|
public function update(UpdateSchedulerRequest $request, Scheduler $scheduler)
|
||||||
{
|
{
|
||||||
$scheduler->service()->update($scheduler, $request);
|
$this->scheduler_repository->save($request->all(), $scheduler);
|
||||||
|
|
||||||
return $this->itemResponse($scheduler);
|
return $this->itemResponse($scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @OA\DELETE(
|
* @OA\DELETE(
|
||||||
* path="/api/v1/task_scheduler/{id}",
|
* path="/api/v1/task_schedulers/{id}",
|
||||||
* operationId="destroyTaskScheduler",
|
* operationId="destroyTaskScheduler",
|
||||||
* tags={"task_scheduler"},
|
* tags={"task_schedulers"},
|
||||||
* summary="Destroy Task Scheduler",
|
* summary="Destroy Task Scheduler",
|
||||||
* description="Destroy task scheduler and its associated job",
|
* description="Destroy task scheduler and its associated job",
|
||||||
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
@ -230,10 +278,83 @@ class TaskSchedulerController extends BaseController
|
|||||||
* ),
|
* ),
|
||||||
* )
|
* )
|
||||||
*/
|
*/
|
||||||
public function destroy(Scheduler $scheduler)
|
public function destroy(DestroySchedulerRequest $request, Scheduler $scheduler)
|
||||||
{
|
{
|
||||||
$this->scheduler_repository->delete($scheduler);
|
$this->scheduler_repository->delete($scheduler);
|
||||||
|
|
||||||
return $this->itemResponse($scheduler->fresh());
|
return $this->itemResponse($scheduler->fresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform bulk actions on the list view.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/api/v1/task_schedulers/bulk",
|
||||||
|
* operationId="bulkTaskSchedulerActions",
|
||||||
|
* tags={"task_schedulers"},
|
||||||
|
* summary="Performs bulk actions on an array of task_schedulers",
|
||||||
|
* description="",
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Secret"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Api-Token"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/X-Requested-With"),
|
||||||
|
* @OA\Parameter(ref="#/components/parameters/index"),
|
||||||
|
* @OA\RequestBody(
|
||||||
|
* description="array of ids",
|
||||||
|
* required=true,
|
||||||
|
* @OA\MediaType(
|
||||||
|
* mediaType="application/json",
|
||||||
|
* @OA\Schema(
|
||||||
|
* type="array",
|
||||||
|
* @OA\Items(
|
||||||
|
* type="integer",
|
||||||
|
* description="Array of hashed IDs to be bulk 'actioned",
|
||||||
|
* example="[0,1,2,3]",
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=200,
|
||||||
|
* description="The TaskSchedule response",
|
||||||
|
* @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"),
|
||||||
|
* @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"),
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/TaskScheduleSchema"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response=422,
|
||||||
|
* description="Validation error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/ValidationError"),
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="default",
|
||||||
|
* description="Unexpected Error",
|
||||||
|
* @OA\JsonContent(ref="#/components/schemas/Error"),
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function bulk()
|
||||||
|
{
|
||||||
|
$action = request()->input('action');
|
||||||
|
|
||||||
|
if(!in_array($action, ['archive', 'restore', 'delete']))
|
||||||
|
return response()->json(['message' => 'Bulk action does not exist'], 400);
|
||||||
|
|
||||||
|
$ids = request()->input('ids');
|
||||||
|
|
||||||
|
$task_schedulers = Scheduler::withTrashed()->find($this->transformKeys($ids));
|
||||||
|
|
||||||
|
$task_schedulers->each(function ($task_scheduler, $key) use ($action) {
|
||||||
|
if (auth()->user()->can('edit', $task_scheduler)) {
|
||||||
|
$this->scheduler_repository->{$action}($task_scheduler);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $this->listResponse(Scheduler::withTrashed()->whereIn('id', $this->transformKeys($ids)));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\TaskScheduler;
|
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
|
||||||
|
|
||||||
class CreateScheduledTaskRequest extends Request
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return auth()->user()->isAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'paused' => 'sometimes|bool',
|
|
||||||
'repeat_every' => 'required|string|in:DAY,WEEK,MONTH,3MONTHS,YEAR',
|
|
||||||
'start_from' => 'sometimes|string',
|
|
||||||
'job' => 'required',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareForValidation()
|
|
||||||
{
|
|
||||||
$input = $this->all();
|
|
||||||
|
|
||||||
if (! array_key_exists('start_from', $input)) {
|
|
||||||
$input['start_from'] = now();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->replace($input);
|
|
||||||
}
|
|
||||||
}
|
|
28
app/Http/Requests/TaskScheduler/CreateSchedulerRequest.php
Normal file
28
app/Http/Requests/TaskScheduler/CreateSchedulerRequest.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\TaskScheduler;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class CreateSchedulerRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
app/Http/Requests/TaskScheduler/DestroySchedulerRequest.php
Normal file
27
app/Http/Requests/TaskScheduler/DestroySchedulerRequest.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Task;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class DestroySchedulerRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
27
app/Http/Requests/TaskScheduler/ShowSchedulerRequest.php
Normal file
27
app/Http/Requests/TaskScheduler/ShowSchedulerRequest.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\TaskScheduler;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class ShowSchedulerRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize() : bool
|
||||||
|
{
|
||||||
|
return auth()->user()->can('view', $this->scheduler);
|
||||||
|
}
|
||||||
|
}
|
44
app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php
Normal file
44
app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Requests\TaskScheduler;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class StoreSchedulerRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
return auth()->user()->isAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
|
||||||
|
$rules = [
|
||||||
|
'name' => ['bail', 'required', Rule::unique('schedulers')->where('company_id', auth()->user()->company()->id)],
|
||||||
|
'is_paused' => 'bail|sometimes|boolean',
|
||||||
|
'frequency_id' => 'bail|required|integer|digits_between:1,12',
|
||||||
|
'next_run' => 'bail|required|date:Y-m-d',
|
||||||
|
'template' => 'bail|required|string',
|
||||||
|
'parameters' => 'bail|array',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $rules;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests\TaskScheduler;
|
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
|
||||||
|
|
||||||
class UpdateScheduledJobRequest extends Request
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize(): bool
|
|
||||||
{
|
|
||||||
return auth()->user()->isAdmin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function rules(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'action_name' => 'sometimes|string',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -8,14 +8,12 @@
|
|||||||
*
|
*
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Http\Requests\TaskScheduler;
|
namespace App\Http\Requests\TaskScheduler;
|
||||||
|
|
||||||
use App\Http\Requests\Request;
|
use App\Http\Requests\Request;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Illuminate\Validation\Rule;
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class UpdateScheduleRequest extends Request
|
class UpdateSchedulerRequest extends Request
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Determine if the user is authorized to make this request.
|
* Determine if the user is authorized to make this request.
|
||||||
@ -29,23 +27,17 @@ class UpdateScheduleRequest extends Request
|
|||||||
|
|
||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
|
||||||
'paused' => 'sometimes|bool',
|
$rules = [
|
||||||
'repeat_every' => 'sometimes|string|in:DAY,WEEK,BIWEEKLY,MONTH,3MONTHS,YEAR',
|
'name' => ['bail', 'sometimes', Rule::unique('schedulers')->where('company_id', auth()->user()->company()->id)->ignore($this->task_scheduler->id)],
|
||||||
'start_from' => 'sometimes',
|
'is_paused' => 'bail|sometimes|boolean',
|
||||||
'scheduled_run'=>'sometimes',
|
'frequency_id' => 'bail|required|integer|digits_between:1,12',
|
||||||
|
'next_run' => 'bail|required|date:Y-m-d',
|
||||||
|
'template' => 'bail|required|string',
|
||||||
|
'parameters' => 'bail|array',
|
||||||
];
|
];
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareForValidation()
|
return $rules;
|
||||||
{
|
|
||||||
$input = $this->all();
|
|
||||||
|
|
||||||
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($input);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -21,6 +21,7 @@ use Illuminate\Foundation\Bus\Dispatchable;
|
|||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
//@rebuild it
|
||||||
class TaskScheduler implements ShouldQueue
|
class TaskScheduler implements ShouldQueue
|
||||||
{
|
{
|
||||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
@ -170,6 +170,7 @@ class BaseModel extends Model
|
|||||||
*/
|
*/
|
||||||
public function resolveRouteBinding($value, $field = null)
|
public function resolveRouteBinding($value, $field = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (is_numeric($value)) {
|
if (is_numeric($value)) {
|
||||||
throw new ModelNotFoundException("Record with value {$value} not found");
|
throw new ModelNotFoundException("Record with value {$value} not found");
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use App\Services\TaskScheduler\TaskSchedulerService;
|
use App\Services\Scheduler\SchedulerService;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
@ -20,8 +20,8 @@ use Illuminate\Support\Carbon;
|
|||||||
* @property bool paused
|
* @property bool paused
|
||||||
* @property bool is_deleted
|
* @property bool is_deleted
|
||||||
* @property \Carbon\Carbon|mixed start_from
|
* @property \Carbon\Carbon|mixed start_from
|
||||||
* @property string repeat_every
|
* @property int frequency_id
|
||||||
* @property \Carbon\Carbon|mixed scheduled_run
|
* @property \Carbon\Carbon|mixed next_run
|
||||||
* @property int company_id
|
* @property int company_id
|
||||||
* @property int updated_at
|
* @property int updated_at
|
||||||
* @property int created_at
|
* @property int created_at
|
||||||
@ -33,22 +33,20 @@ use Illuminate\Support\Carbon;
|
|||||||
*/
|
*/
|
||||||
class Scheduler extends BaseModel
|
class Scheduler extends BaseModel
|
||||||
{
|
{
|
||||||
use HasFactory, SoftDeletes;
|
use SoftDeletes;
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
'start_from',
|
'start_from',
|
||||||
'paused',
|
'is_paused',
|
||||||
'repeat_every',
|
'repeat_every',
|
||||||
'scheduled_run',
|
'scheduled_run',
|
||||||
'action_class',
|
'action_class',
|
||||||
'action_name',
|
'action_name',
|
||||||
'parameters',
|
'parameters',
|
||||||
'company_id',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'start_from' => 'timestamp',
|
'next_run' => 'datetime',
|
||||||
'scheduled_run' => 'timestamp',
|
|
||||||
'created_at' => 'timestamp',
|
'created_at' => 'timestamp',
|
||||||
'updated_at' => 'timestamp',
|
'updated_at' => 'timestamp',
|
||||||
'deleted_at' => 'timestamp',
|
'deleted_at' => 'timestamp',
|
||||||
@ -57,6 +55,10 @@ class Scheduler extends BaseModel
|
|||||||
'parameters' => 'array',
|
'parameters' => 'array',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $appends = [
|
||||||
|
'hashed_id',
|
||||||
|
];
|
||||||
|
|
||||||
const DAILY = 'DAY';
|
const DAILY = 'DAY';
|
||||||
|
|
||||||
const WEEKLY = 'WEEK';
|
const WEEKLY = 'WEEK';
|
||||||
@ -100,9 +102,9 @@ class Scheduler extends BaseModel
|
|||||||
/**
|
/**
|
||||||
* Service entry points.
|
* Service entry points.
|
||||||
*/
|
*/
|
||||||
public function service(): TaskSchedulerService
|
public function service(): SchedulerService
|
||||||
{
|
{
|
||||||
return new TaskSchedulerService($this);
|
return new SchedulerService($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function company(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
public function company(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||||
@ -110,43 +112,43 @@ class Scheduler extends BaseModel
|
|||||||
return $this->belongsTo(Company::class);
|
return $this->belongsTo(Company::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function nextScheduledDate(): ?Carbon
|
// public function nextScheduledDate(): ?Carbon
|
||||||
{
|
// {
|
||||||
$offset = 0;
|
// $offset = 0;
|
||||||
|
|
||||||
$entity_send_time = $this->company->settings->entity_send_time;
|
// $entity_send_time = $this->company->settings->entity_send_time;
|
||||||
|
|
||||||
if ($entity_send_time != 0) {
|
// if ($entity_send_time != 0) {
|
||||||
$timezone = $this->company->timezone();
|
// $timezone = $this->company->timezone();
|
||||||
|
|
||||||
$offset -= $timezone->utc_offset;
|
// $offset -= $timezone->utc_offset;
|
||||||
$offset += ($entity_send_time * 3600);
|
// $offset += ($entity_send_time * 3600);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/*
|
// /*
|
||||||
As we are firing at UTC+0 if our offset is negative it is technically firing the day before so we always need
|
// As we are firing at UTC+0 if our offset is negative it is technically firing the day before so we always need
|
||||||
to add ON a day - a day = 86400 seconds
|
// to add ON a day - a day = 86400 seconds
|
||||||
*/
|
// */
|
||||||
|
|
||||||
if ($offset < 0) {
|
// if ($offset < 0) {
|
||||||
$offset += 86400;
|
// $offset += 86400;
|
||||||
}
|
// }
|
||||||
|
|
||||||
switch ($this->repeat_every) {
|
// switch ($this->repeat_every) {
|
||||||
case self::DAILY:
|
// case self::DAILY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addDay()->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addDay()->addSeconds($offset);
|
||||||
case self::WEEKLY:
|
// case self::WEEKLY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addWeek()->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addWeek()->addSeconds($offset);
|
||||||
case self::BIWEEKLY:
|
// case self::BIWEEKLY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addWeeks(2)->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addWeeks(2)->addSeconds($offset);
|
||||||
case self::MONTHLY:
|
// case self::MONTHLY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addMonthNoOverflow()->addSeconds($offset);
|
||||||
case self::QUARTERLY:
|
// case self::QUARTERLY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addMonthsNoOverflow(3)->addSeconds($offset);
|
||||||
case self::ANNUALLY:
|
// case self::ANNUALLY:
|
||||||
return Carbon::parse($this->scheduled_run)->startOfDay()->addYearNoOverflow()->addSeconds($offset);
|
// return Carbon::parse($this->scheduled_run)->startOfDay()->addYearNoOverflow()->addSeconds($offset);
|
||||||
default:
|
// default:
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
31
app/Policies/SchedulerPolicy.php
Normal file
31
app/Policies/SchedulerPolicy.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class SchedulerPolicy.
|
||||||
|
*/
|
||||||
|
class SchedulerPolicy extends EntityPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if the user has create permissions.
|
||||||
|
*
|
||||||
|
* @param User $user
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function create(User $user) : bool
|
||||||
|
{
|
||||||
|
return $user->isAdmin();
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ use App\Models\Quote;
|
|||||||
use App\Models\RecurringExpense;
|
use App\Models\RecurringExpense;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\RecurringQuote;
|
use App\Models\RecurringQuote;
|
||||||
|
use App\Models\Scheduler;
|
||||||
use App\Models\Subscription;
|
use App\Models\Subscription;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Models\TaskStatus;
|
use App\Models\TaskStatus;
|
||||||
@ -67,6 +68,7 @@ use App\Policies\QuotePolicy;
|
|||||||
use App\Policies\RecurringExpensePolicy;
|
use App\Policies\RecurringExpensePolicy;
|
||||||
use App\Policies\RecurringInvoicePolicy;
|
use App\Policies\RecurringInvoicePolicy;
|
||||||
use App\Policies\RecurringQuotePolicy;
|
use App\Policies\RecurringQuotePolicy;
|
||||||
|
use App\Policies\SchedulerPolicy;
|
||||||
use App\Policies\SubscriptionPolicy;
|
use App\Policies\SubscriptionPolicy;
|
||||||
use App\Policies\TaskPolicy;
|
use App\Policies\TaskPolicy;
|
||||||
use App\Policies\TaskStatusPolicy;
|
use App\Policies\TaskStatusPolicy;
|
||||||
@ -109,6 +111,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
RecurringExpense::class => RecurringExpensePolicy::class,
|
RecurringExpense::class => RecurringExpensePolicy::class,
|
||||||
RecurringInvoice::class => RecurringInvoicePolicy::class,
|
RecurringInvoice::class => RecurringInvoicePolicy::class,
|
||||||
RecurringQuote::class => RecurringQuotePolicy::class,
|
RecurringQuote::class => RecurringQuotePolicy::class,
|
||||||
|
Scheduler::class => SchedulerPolicy::class,
|
||||||
Subscription::class => SubscriptionPolicy::class,
|
Subscription::class => SubscriptionPolicy::class,
|
||||||
Task::class => TaskPolicy::class,
|
Task::class => TaskPolicy::class,
|
||||||
TaskStatus::class => TaskStatusPolicy::class,
|
TaskStatus::class => TaskStatusPolicy::class,
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
|
use App\Models\Scheduler;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||||
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
|
||||||
@ -27,6 +29,21 @@ class RouteServiceProvider extends ServiceProvider
|
|||||||
public function boot()
|
public function boot()
|
||||||
{
|
{
|
||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
||||||
|
|
||||||
|
Route::bind('task_scheduler', function ($value) {
|
||||||
|
|
||||||
|
if (is_numeric($value)) {
|
||||||
|
throw new ModelNotFoundException("Record with value {$value} not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scheduler::query()
|
||||||
|
->withTrashed()
|
||||||
|
->where('id', $this->decodePrimaryKey($value))->firstOrFail();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
38
app/Repositories/SchedulerRepository.php
Normal file
38
app/Repositories/SchedulerRepository.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Repositories;
|
||||||
|
|
||||||
|
use App\Models\Scheduler;
|
||||||
|
|
||||||
|
class SchedulerRepository extends BaseRepository
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the scheduler.
|
||||||
|
*
|
||||||
|
* @param array $data The data
|
||||||
|
* @param \App\Models\Scheduler $scheduler The scheduler
|
||||||
|
*
|
||||||
|
* @return \App\Models\Scheduler
|
||||||
|
*/
|
||||||
|
public function save(array $data, Scheduler $scheduler): Scheduler
|
||||||
|
{
|
||||||
|
|
||||||
|
$scheduler->fill($data);
|
||||||
|
|
||||||
|
$scheduler->save();
|
||||||
|
|
||||||
|
return $scheduler;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Invoice Ninja (https://invoiceninja.com).
|
|
||||||
*
|
|
||||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
|
||||||
*
|
|
||||||
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
|
||||||
*
|
|
||||||
* @license https://www.elastic.co/licensing/elastic-license
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Repositories;
|
|
||||||
|
|
||||||
class TaskSchedulerRepository extends BaseRepository
|
|
||||||
{
|
|
||||||
}
|
|
@ -35,12 +35,7 @@ class InvoiceService
|
|||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
public $invoice;
|
public function __construct(public Invoice $invoice){}
|
||||||
|
|
||||||
public function __construct($invoice)
|
|
||||||
{
|
|
||||||
$this->invoice = $invoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks as invoice as paid
|
* Marks as invoice as paid
|
||||||
|
@ -9,9 +9,11 @@
|
|||||||
* @license https://www.elastic.co/licensing/elastic-license
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace App\Services\Schedule;
|
namespace App\Services\Scheduler;
|
||||||
|
|
||||||
class ScheduleService
|
use App\Models\Scheduler;
|
||||||
|
|
||||||
|
class SchedulerServicer
|
||||||
{
|
{
|
||||||
|
|
||||||
public function __construct(public Scheduler $scheduler) {}
|
public function __construct(public Scheduler $scheduler) {}
|
@ -38,6 +38,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
|
||||||
|
|
||||||
|
//@deprecated - never used....
|
||||||
class TaskSchedulerService
|
class TaskSchedulerService
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace App\Transformers;
|
|||||||
use App\Models\Scheduler;
|
use App\Models\Scheduler;
|
||||||
use App\Utils\Traits\MakesHash;
|
use App\Utils\Traits\MakesHash;
|
||||||
|
|
||||||
class TaskSchedulerTransformer extends EntityTransformer
|
class SchedulerTransformer extends EntityTransformer
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
|
|
||||||
@ -22,17 +22,17 @@ class TaskSchedulerTransformer extends EntityTransformer
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'id' => $this->encodePrimaryKey($scheduler->id),
|
'id' => $this->encodePrimaryKey($scheduler->id),
|
||||||
|
'name' => (string) $scheduler->name,
|
||||||
|
'frequency_id' => (string) $scheduler->frequency_id,
|
||||||
|
'next_run' => $scheduler->next_run,
|
||||||
|
'template' => (string) $scheduler->template,
|
||||||
|
'is_paused' => (bool) $scheduler->is_paused,
|
||||||
|
'is_deleted' => (bool) $scheduler->is_deleted,
|
||||||
|
'parameters'=> (array) $scheduler->parameters,
|
||||||
'is_deleted' => (bool) $scheduler->is_deleted,
|
'is_deleted' => (bool) $scheduler->is_deleted,
|
||||||
'paused' => (bool) $scheduler->paused,
|
|
||||||
'repeat_every' => (string) $scheduler->repeat_every,
|
|
||||||
'start_from' => (int) $scheduler->start_from,
|
|
||||||
'scheduled_run' => (int) $scheduler->scheduled_run,
|
|
||||||
'updated_at' => (int) $scheduler->updated_at,
|
'updated_at' => (int) $scheduler->updated_at,
|
||||||
'created_at' => (int) $scheduler->created_at,
|
'created_at' => (int) $scheduler->created_at,
|
||||||
'archived_at' => (int) $scheduler->deleted_at,
|
'archived_at' => (int) $scheduler->deleted_at,
|
||||||
'action_name' => (string) $scheduler->action_name,
|
|
||||||
'action_class' => (string) $scheduler->action_class,
|
|
||||||
'parameters'=> (array) $scheduler->parameters,
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
37
database/factories/SchedulerFactory.php
Normal file
37
database/factories/SchedulerFactory.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\RecurringInvoice;
|
||||||
|
use App\Models\Scheduler;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
class SchedulerFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function definition()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'name' => $this->faker->name(),
|
||||||
|
'is_paused' => rand(0,1),
|
||||||
|
'is_deleted' => rand(0,1),
|
||||||
|
'parameters' => [],
|
||||||
|
'frequency_id' => RecurringInvoice::FREQUENCY_MONTHLY,
|
||||||
|
'next_run' => now()->addSeconds(rand(86400,8640000)),
|
||||||
|
'template' => 'statement_task',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,38 @@ return new class extends Migration
|
|||||||
$table->boolean('invoice_task_hours')->default(false);
|
$table->boolean('invoice_task_hours')->default(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Schema::table('schedulers', function (Blueprint $table)
|
||||||
|
{
|
||||||
|
|
||||||
|
$table->dropColumn('repeat_every');
|
||||||
|
$table->dropColumn('start_from');
|
||||||
|
$table->dropColumn('scheduled_run');
|
||||||
|
$table->dropColumn('action_name');
|
||||||
|
$table->dropColumn('action_class');
|
||||||
|
$table->dropColumn('paused');
|
||||||
|
$table->dropColumn('company_id');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Schema::table('schedulers', function (Blueprint $table)
|
||||||
|
{
|
||||||
|
|
||||||
|
$table->unsignedInteger('company_id');
|
||||||
|
$table->boolean('is_paused')->default(false);
|
||||||
|
$table->unsignedInteger('frequency_id')->nullable();
|
||||||
|
$table->datetime('next_run')->nullable();
|
||||||
|
$table->datetime('next_run_client')->nullable();
|
||||||
|
$table->unsignedInteger('user_id');
|
||||||
|
$table->string('name', 191);
|
||||||
|
$table->string('template', 191);
|
||||||
|
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies')->onDelete('cascade')->onUpdate('cascade');
|
||||||
|
|
||||||
|
$table->unique(['company_id', 'name']);
|
||||||
|
$table->index(['company_id', 'deleted_at']);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +275,8 @@ Route::group(['middleware' => ['throttle:300,1', 'api_db', 'token_auth', 'locale
|
|||||||
Route::post('reports/tasks', TaskReportController::class);
|
Route::post('reports/tasks', TaskReportController::class);
|
||||||
Route::post('reports/profitloss', ProfitAndLossController::class);
|
Route::post('reports/profitloss', ProfitAndLossController::class);
|
||||||
|
|
||||||
Route::resource('task_scheduler', TaskSchedulerController::class)->except('edit')->parameters(['task_scheduler' => 'scheduler']);
|
Route::resource('task_schedulers', TaskSchedulerController::class);
|
||||||
|
Route::post('task_schedulers/bulk', [TaskSchedulerController::class, 'bulk'])->name('task_schedulers.bulk');
|
||||||
|
|
||||||
Route::get('scheduler', [SchedulerController::class, 'index']);
|
Route::get('scheduler', [SchedulerController::class, 'index']);
|
||||||
Route::post('support/messages/send', SendingController::class);
|
Route::post('support/messages/send', SendingController::class);
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/**
|
||||||
|
* Invoice Ninja (https://invoiceninja.com).
|
||||||
|
*
|
||||||
|
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
|
||||||
|
*
|
||||||
|
* @license https://www.elastic.co/licensing/elastic-license
|
||||||
|
*/
|
||||||
|
|
||||||
namespace Tests\Feature\Scheduler;
|
namespace Tests\Feature\Scheduler;
|
||||||
|
|
||||||
@ -12,13 +21,14 @@ use Illuminate\Foundation\Testing\WithoutEvents;
|
|||||||
use Illuminate\Routing\Middleware\ThrottleRequests;
|
use Illuminate\Routing\Middleware\ThrottleRequests;
|
||||||
use Illuminate\Support\Facades\Session;
|
use Illuminate\Support\Facades\Session;
|
||||||
use Illuminate\Validation\ValidationException;
|
use Illuminate\Validation\ValidationException;
|
||||||
|
use Tests\MockAccountData;
|
||||||
use Tests\MockUnitData;
|
use Tests\MockUnitData;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
class SchedulerTest extends TestCase
|
class SchedulerTest extends TestCase
|
||||||
{
|
{
|
||||||
use MakesHash;
|
use MakesHash;
|
||||||
use MockUnitData;
|
use MockAccountData;
|
||||||
use WithoutEvents;
|
use WithoutEvents;
|
||||||
// use RefreshDatabase;
|
// use RefreshDatabase;
|
||||||
|
|
||||||
@ -38,111 +48,253 @@ class SchedulerTest extends TestCase
|
|||||||
ThrottleRequests::class
|
ThrottleRequests::class
|
||||||
);
|
);
|
||||||
|
|
||||||
// $this->withoutExceptionHandling();
|
$this->withoutExceptionHandling();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSchedulerCantBeCreatedWithWrongData()
|
public function testDeleteSchedule()
|
||||||
{
|
{
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'repeat_every' => Scheduler::DAILY,
|
'ids' => [$this->scheduler->hashed_id],
|
||||||
'job' => Scheduler::CREATE_CLIENT_REPORT,
|
|
||||||
'date_key' => '123',
|
|
||||||
'report_keys' => ['test'],
|
|
||||||
'date_range' => 'all',
|
|
||||||
// 'start_from' => '2022-01-01'
|
|
||||||
];
|
|
||||||
|
|
||||||
$response = false;
|
|
||||||
|
|
||||||
$response = $this->withHeaders([
|
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
|
||||||
'X-API-TOKEN' => $this->token,
|
|
||||||
])->post('/api/v1/task_scheduler/', $data);
|
|
||||||
|
|
||||||
$response->assertSessionHasErrors();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSchedulerCanBeUpdated()
|
|
||||||
{
|
|
||||||
$response = $this->createScheduler();
|
|
||||||
|
|
||||||
$arr = $response->json();
|
|
||||||
$id = $arr['data']['id'];
|
|
||||||
|
|
||||||
$scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
|
||||||
|
|
||||||
$updateData = [
|
|
||||||
'start_from' => 1655934741,
|
|
||||||
];
|
|
||||||
$response = $this->withHeaders([
|
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
|
||||||
'X-API-TOKEN' => $this->token,
|
|
||||||
])->put('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id), $updateData);
|
|
||||||
|
|
||||||
$responseData = $response->json();
|
|
||||||
$this->assertEquals($updateData['start_from'], $responseData['data']['start_from']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSchedulerCanBeSeen()
|
|
||||||
{
|
|
||||||
$response = $this->createScheduler();
|
|
||||||
|
|
||||||
$arr = $response->json();
|
|
||||||
$id = $arr['data']['id'];
|
|
||||||
|
|
||||||
$scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
|
||||||
|
|
||||||
$response = $this->withHeaders([
|
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
|
||||||
'X-API-TOKEN' => $this->token,
|
|
||||||
])->get('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id));
|
|
||||||
|
|
||||||
$arr = $response->json();
|
|
||||||
$this->assertEquals('create_client_report', $arr['data']['action_name']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSchedulerJobCanBeUpdated()
|
|
||||||
{
|
|
||||||
$response = $this->createScheduler();
|
|
||||||
|
|
||||||
$arr = $response->json();
|
|
||||||
$id = $arr['data']['id'];
|
|
||||||
|
|
||||||
$scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
|
||||||
|
|
||||||
$this->assertSame('create_client_report', $scheduler->action_name);
|
|
||||||
|
|
||||||
$updateData = [
|
|
||||||
'job' => Scheduler::CREATE_CREDIT_REPORT,
|
|
||||||
'date_range' => 'all',
|
|
||||||
'report_keys' => ['test1'],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-TOKEN' => $this->token,
|
'X-API-TOKEN' => $this->token,
|
||||||
])->put('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id), $updateData);
|
])->postJson('/api/v1/task_schedulers/bulk?action=delete', $data)
|
||||||
|
->assertStatus(200);
|
||||||
|
|
||||||
$updatedSchedulerJob = Scheduler::first()->action_name;
|
|
||||||
$arr = $response->json();
|
|
||||||
|
|
||||||
$this->assertSame('create_credit_report', $arr['data']['action_name']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createScheduler()
|
|
||||||
{
|
|
||||||
$data = [
|
$data = [
|
||||||
'repeat_every' => Scheduler::DAILY,
|
'ids' => [$this->scheduler->hashed_id],
|
||||||
'job' => Scheduler::CREATE_CLIENT_REPORT,
|
|
||||||
'date_key' => '123',
|
|
||||||
'report_keys' => ['test'],
|
|
||||||
'date_range' => 'all',
|
|
||||||
'start_from' => '2022-01-01',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return $response = $this->withHeaders([
|
$response = $this->withHeaders([
|
||||||
'X-API-SECRET' => config('ninja.api_secret'),
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
'X-API-TOKEN' => $this->token,
|
'X-API-TOKEN' => $this->token,
|
||||||
])->post('/api/v1/task_scheduler/', $data);
|
])->postJson('/api/v1/task_schedulers/bulk?action=restore', $data)
|
||||||
|
->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRestoreSchedule()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'ids' => [$this->scheduler->hashed_id],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/task_schedulers/bulk?action=archive', $data)
|
||||||
|
->assertStatus(200);
|
||||||
|
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'ids' => [$this->scheduler->hashed_id],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/task_schedulers/bulk?action=restore', $data)
|
||||||
|
->assertStatus(200);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testArchiveSchedule()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'ids' => [$this->scheduler->hashed_id],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/task_schedulers/bulk?action=archive', $data)
|
||||||
|
->assertStatus(200);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSchedulerPost()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => 'A different Name',
|
||||||
|
'frequency_id' => 5,
|
||||||
|
'next_run' => now()->addDays(2)->format('Y-m-d'),
|
||||||
|
'template' =>'statement',
|
||||||
|
'parameters' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->postJson('/api/v1/task_schedulers', $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchedulerPut()
|
||||||
|
{
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => 'A different Name',
|
||||||
|
'frequency_id' => 5,
|
||||||
|
'next_run' => now()->addDays(2)->format('Y-m-d'),
|
||||||
|
'template' =>'statement',
|
||||||
|
'parameters' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->putJson('/api/v1/task_schedulers/'.$this->scheduler->hashed_id, $data);
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchedulerGet()
|
||||||
|
{
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->get('/api/v1/task_schedulers');
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSchedulerCreate()
|
||||||
|
{
|
||||||
|
$response = $this->withHeaders([
|
||||||
|
'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
'X-API-TOKEN' => $this->token,
|
||||||
|
])->get('/api/v1/task_schedulers/create');
|
||||||
|
|
||||||
|
$response->assertStatus(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public function testSchedulerPut()
|
||||||
|
// {
|
||||||
|
// $data = [
|
||||||
|
// 'description' => $this->faker->firstName(),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->put('/api/v1/task_schedulers/'.$this->encodePrimaryKey($this->task->id), $data);
|
||||||
|
|
||||||
|
// $response->assertStatus(200);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public function testSchedulerCantBeCreatedWithWrongData()
|
||||||
|
// {
|
||||||
|
// $data = [
|
||||||
|
// 'repeat_every' => Scheduler::DAILY,
|
||||||
|
// 'job' => Scheduler::CREATE_CLIENT_REPORT,
|
||||||
|
// 'date_key' => '123',
|
||||||
|
// 'report_keys' => ['test'],
|
||||||
|
// 'date_range' => 'all',
|
||||||
|
// // 'start_from' => '2022-01-01'
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $response = false;
|
||||||
|
|
||||||
|
// $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->post('/api/v1/task_scheduler/', $data);
|
||||||
|
|
||||||
|
// $response->assertSessionHasErrors();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function testSchedulerCanBeUpdated()
|
||||||
|
// {
|
||||||
|
// $response = $this->createScheduler();
|
||||||
|
|
||||||
|
// $arr = $response->json();
|
||||||
|
// $id = $arr['data']['id'];
|
||||||
|
|
||||||
|
// $scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
||||||
|
|
||||||
|
// $updateData = [
|
||||||
|
// 'start_from' => 1655934741,
|
||||||
|
// ];
|
||||||
|
// $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->put('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id), $updateData);
|
||||||
|
|
||||||
|
// $responseData = $response->json();
|
||||||
|
// $this->assertEquals($updateData['start_from'], $responseData['data']['start_from']);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function testSchedulerCanBeSeen()
|
||||||
|
// {
|
||||||
|
// $response = $this->createScheduler();
|
||||||
|
|
||||||
|
// $arr = $response->json();
|
||||||
|
// $id = $arr['data']['id'];
|
||||||
|
|
||||||
|
// $scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
||||||
|
|
||||||
|
// $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->get('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id));
|
||||||
|
|
||||||
|
// $arr = $response->json();
|
||||||
|
// $this->assertEquals('create_client_report', $arr['data']['action_name']);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function testSchedulerJobCanBeUpdated()
|
||||||
|
// {
|
||||||
|
// $response = $this->createScheduler();
|
||||||
|
|
||||||
|
// $arr = $response->json();
|
||||||
|
// $id = $arr['data']['id'];
|
||||||
|
|
||||||
|
// $scheduler = Scheduler::find($this->decodePrimaryKey($id));
|
||||||
|
|
||||||
|
// $this->assertSame('create_client_report', $scheduler->action_name);
|
||||||
|
|
||||||
|
// $updateData = [
|
||||||
|
// 'job' => Scheduler::CREATE_CREDIT_REPORT,
|
||||||
|
// 'date_range' => 'all',
|
||||||
|
// 'report_keys' => ['test1'],
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->put('/api/v1/task_scheduler/'.$this->encodePrimaryKey($scheduler->id), $updateData);
|
||||||
|
|
||||||
|
// $updatedSchedulerJob = Scheduler::first()->action_name;
|
||||||
|
// $arr = $response->json();
|
||||||
|
|
||||||
|
// $this->assertSame('create_credit_report', $arr['data']['action_name']);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public function createScheduler()
|
||||||
|
// {
|
||||||
|
// $data = [
|
||||||
|
// 'repeat_every' => Scheduler::DAILY,
|
||||||
|
// 'job' => Scheduler::CREATE_CLIENT_REPORT,
|
||||||
|
// 'date_key' => '123',
|
||||||
|
// 'report_keys' => ['test'],
|
||||||
|
// 'date_range' => 'all',
|
||||||
|
// 'start_from' => '2022-01-01',
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// return $response = $this->withHeaders([
|
||||||
|
// 'X-API-SECRET' => config('ninja.api_secret'),
|
||||||
|
// 'X-API-TOKEN' => $this->token,
|
||||||
|
// ])->post('/api/v1/task_scheduler/', $data);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ use App\Models\QuoteInvitation;
|
|||||||
use App\Models\RecurringExpense;
|
use App\Models\RecurringExpense;
|
||||||
use App\Models\RecurringInvoice;
|
use App\Models\RecurringInvoice;
|
||||||
use App\Models\RecurringQuote;
|
use App\Models\RecurringQuote;
|
||||||
|
use App\Models\Scheduler;
|
||||||
use App\Models\Task;
|
use App\Models\Task;
|
||||||
use App\Models\TaskStatus;
|
use App\Models\TaskStatus;
|
||||||
use App\Models\TaxRate;
|
use App\Models\TaxRate;
|
||||||
@ -177,6 +178,11 @@ trait MockAccountData
|
|||||||
*/
|
*/
|
||||||
public $tax_rate;
|
public $tax_rate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $scheduler;
|
||||||
|
|
||||||
public function makeTestData()
|
public function makeTestData()
|
||||||
{
|
{
|
||||||
config(['database.default' => config('ninja.db.default')]);
|
config(['database.default' => config('ninja.db.default')]);
|
||||||
@ -804,6 +810,14 @@ trait MockAccountData
|
|||||||
|
|
||||||
$this->client = $this->client->fresh();
|
$this->client = $this->client->fresh();
|
||||||
$this->invoice = $this->invoice->fresh();
|
$this->invoice = $this->invoice->fresh();
|
||||||
|
|
||||||
|
$this->scheduler = Scheduler::factory()->create([
|
||||||
|
'user_id' => $user_id,
|
||||||
|
'company_id' => $this->company->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->scheduler->save();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user