From 7b48da0cff7d617bea7ca6e1e99e073f5dd975d4 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 08:31:21 +1000 Subject: [PATCH 01/17] Minor fixes for scheduler --- .../Controllers/TaskSchedulerController.php | 253 +----------------- .../TaskScheduler/StoreSchedulerRequest.php | 2 - .../TaskScheduler/UpdateSchedulerRequest.php | 1 - app/Jobs/Invoice/CheckGatewayFee.php | 14 +- app/Models/Client.php | 1 + app/Repositories/SchedulerRepository.php | 6 +- app/Services/Scheduler/SchedulerService.php | 2 - app/Transformers/AccountTransformer.php | 2 +- app/Transformers/SchedulerTransformer.php | 1 - 9 files changed, 19 insertions(+), 263 deletions(-) diff --git a/app/Http/Controllers/TaskSchedulerController.php b/app/Http/Controllers/TaskSchedulerController.php index 195065f62f21..24e19e955991 100644 --- a/app/Http/Controllers/TaskSchedulerController.php +++ b/app/Http/Controllers/TaskSchedulerController.php @@ -37,28 +37,6 @@ class TaskSchedulerController extends BaseController parent::__construct(); } - /** - * @OA\GET( - * path="/api/v1/task_schedulers/", - * operationId="getTaskSchedulers", - * tags={"task_schedulers"}, - * summary="Task Scheduler Index", - * description="Get all schedulers with associated jobs", - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Response( - * response=200, - * description="success", - * @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\Response( - * response="default", - * description="Unexpected Error", - * @OA\JsonContent(ref="#/components/schemas/Error"), - * ), - * ) - */ public function index(SchedulerFilters $filters) { $schedulers = Scheduler::filter($filters); @@ -66,44 +44,6 @@ class TaskSchedulerController extends BaseController 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-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); @@ -111,39 +51,6 @@ class TaskSchedulerController extends BaseController return $this->itemResponse($scheduler); } - /** - * @OA\Post( - * path="/api/v1/task_schedulers/", - * operationId="createTaskScheduler", - * tags={"task_schedulers"}, - * 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 - * multiple times, we should send the same parameters in the request as we would send if we wanted to get report, see example", - * @OA\Parameter(ref="#/components/parameters/X-API-SECRET"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\RequestBody( - * required=true, - * @OA\JsonContent(ref="#/components/schemas/TaskSchedulerSchema") - * ), - * @OA\Response( - * response=200, - * description="success", - * @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\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 store(StoreSchedulerRequest $request) { $scheduler = $this->scheduler_repository->save($request->all(), SchedulerFactory::create(auth()->user()->company()->id, auth()->user()->id)); @@ -151,86 +58,12 @@ class TaskSchedulerController extends BaseController return $this->itemResponse($scheduler); } - /** - * @OA\GET( - * path="/api/v1/task_schedulers/{id}", - * operationId="showTaskScheduler", - * tags={"task_schedulers"}, - * summary="Show given scheduler", - * description="Get scheduler with associated job", - * @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", - * @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\Response( - * response="default", - * description="Unexpected Error", - * @OA\JsonContent(ref="#/components/schemas/Error"), - * ), - * ) - */ + public function show(ShowSchedulerRequest $request, Scheduler $scheduler) { return $this->itemResponse($scheduler); } - /** - * @OA\PUT( - * path="/api/v1/task_schedulers/{id}", - * operationId="updateTaskScheduler", - * tags={"task_schedulers"}, - * 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\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/TaskSchedulerSchema") - * ), - * @OA\Response( - * response=200, - * description="success", - * @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\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 update(UpdateSchedulerRequest $request, Scheduler $scheduler) { $this->scheduler_repository->save($request->all(), $scheduler); @@ -238,39 +71,6 @@ class TaskSchedulerController extends BaseController return $this->itemResponse($scheduler); } - /** - * @OA\DELETE( - * path="/api/v1/task_schedulers/{id}", - * operationId="destroyTaskScheduler", - * tags={"task_schedulers"}, - * summary="Destroy Task Scheduler", - * description="Destroy task scheduler and its associated job", - * @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", - * @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\Response( - * response="default", - * description="Unexpected Error", - * @OA\JsonContent(ref="#/components/schemas/Error"), - * ), - * ) - */ public function destroy(DestroySchedulerRequest $request, Scheduler $scheduler) { $this->scheduler_repository->delete($scheduler); @@ -278,57 +78,6 @@ class TaskSchedulerController extends BaseController 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-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/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 bulk() { $action = request()->input('action'); diff --git a/app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php b/app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php index f613c7881a55..724576ef5b16 100644 --- a/app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php +++ b/app/Http/Requests/TaskScheduler/StoreSchedulerRequest.php @@ -60,7 +60,5 @@ class StoreSchedulerRequest extends Request $this->merge(['next_run_client' => $input['next_run']]); } - $this->replace($input); - } } diff --git a/app/Http/Requests/TaskScheduler/UpdateSchedulerRequest.php b/app/Http/Requests/TaskScheduler/UpdateSchedulerRequest.php index 48c52a3e3e0f..2480758e9520 100644 --- a/app/Http/Requests/TaskScheduler/UpdateSchedulerRequest.php +++ b/app/Http/Requests/TaskScheduler/UpdateSchedulerRequest.php @@ -57,6 +57,5 @@ class UpdateSchedulerRequest extends Request $this->merge(['next_run_client' => $input['next_run']]); } - $this->replace($input); } } diff --git a/app/Jobs/Invoice/CheckGatewayFee.php b/app/Jobs/Invoice/CheckGatewayFee.php index e888f38489aa..32ee5ad30a10 100644 --- a/app/Jobs/Invoice/CheckGatewayFee.php +++ b/app/Jobs/Invoice/CheckGatewayFee.php @@ -11,13 +11,14 @@ namespace App\Jobs\Invoice; -use App\Libraries\MultiDB; use App\Models\Invoice; +use App\Libraries\MultiDB; use Illuminate\Bus\Queueable; +use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; +use Illuminate\Queue\Middleware\WithoutOverlapping; class CheckGatewayFee implements ShouldQueue { @@ -40,6 +41,8 @@ class CheckGatewayFee implements ShouldQueue */ public function handle() { + nlog("Checking Gateway Fees for Invoice Id = {$this->invoice_id}"); + MultiDB::setDb($this->db); $i = Invoice::withTrashed()->find($this->invoice_id); @@ -52,4 +55,9 @@ class CheckGatewayFee implements ShouldQueue $i->service()->removeUnpaidGatewayFees(); } } + + public function middleware() + { + return [(new WithoutOverlapping($this->invoice_id.$this->db))]; + } } diff --git a/app/Models/Client.php b/app/Models/Client.php index fa7e6f577f0d..18890a81dab9 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -250,6 +250,7 @@ class Client extends BaseModel implements HasLocalePreference 'phone', 'number', 'routing_id', + 'is_tax_exempt', ]; protected $with = [ diff --git a/app/Repositories/SchedulerRepository.php b/app/Repositories/SchedulerRepository.php index f067984b1027..016957940f53 100644 --- a/app/Repositories/SchedulerRepository.php +++ b/app/Repositories/SchedulerRepository.php @@ -25,10 +25,14 @@ class SchedulerRepository extends BaseRepository */ public function save(array $data, Scheduler $scheduler): Scheduler { + $scheduler->fill($data); $scheduler->save(); - return $scheduler; + /** 18-5-2023 set client specific send times. */ + $scheduler->calculateNextRun(); + + return $scheduler->fresh(); } } diff --git a/app/Services/Scheduler/SchedulerService.php b/app/Services/Scheduler/SchedulerService.php index 1089b882d572..ddf327ab35a1 100644 --- a/app/Services/Scheduler/SchedulerService.php +++ b/app/Services/Scheduler/SchedulerService.php @@ -21,8 +21,6 @@ class SchedulerService use MakesHash; use MakesDates; - private string $method; - public function __construct(public Scheduler $scheduler) { } diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index 032324a0a23e..d7eaeb9d3fe2 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -56,7 +56,7 @@ class AccountTransformer extends EntityTransformer 'key' => (string) $account->key, 'default_url' => config('ninja.app_url'), 'plan' => $account->getPlan(), - 'plan_term' => (string) $account->plan_terms, + 'plan_term' => (string) $account->plan_term, 'plan_started' => (string) $account->plan_started, 'plan_paid' => (string) $account->plan_paid, 'plan_expires' => (string) $account->plan_expires, diff --git a/app/Transformers/SchedulerTransformer.php b/app/Transformers/SchedulerTransformer.php index ddef7bb15b51..cbc4af3d7e1e 100644 --- a/app/Transformers/SchedulerTransformer.php +++ b/app/Transformers/SchedulerTransformer.php @@ -27,7 +27,6 @@ class SchedulerTransformer extends EntityTransformer 'next_run' => $scheduler->next_run_client->format('Y-m-d'), '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, 'updated_at' => (int) $scheduler->updated_at, From c95327eab6280a6f6c8f7ada2b5a64ebc7d085e3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 08:36:08 +1000 Subject: [PATCH 02/17] Only notify once per day on loging --- app/Listeners/User/UpdateUserLastLogin.php | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/Listeners/User/UpdateUserLastLogin.php b/app/Listeners/User/UpdateUserLastLogin.php index 4882cfa26554..9fc383db207f 100644 --- a/app/Listeners/User/UpdateUserLastLogin.php +++ b/app/Listeners/User/UpdateUserLastLogin.php @@ -11,16 +11,17 @@ namespace App\Listeners\User; +use App\Models\SystemLog; +use App\Libraries\MultiDB; +use App\Jobs\Util\SystemLogger; +use App\Mail\User\UserLoggedIn; use App\Jobs\Mail\NinjaMailerJob; use App\Jobs\Mail\NinjaMailerObject; -use App\Jobs\Util\SystemLogger; -use App\Libraries\MultiDB; -use App\Mail\User\UserLoggedIn; -use App\Models\SystemLog; -use Illuminate\Broadcasting\InteractsWithSockets; +use Illuminate\Support\Facades\Cache; +use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Events\Dispatchable; -use Illuminate\Queue\SerializesModels; +use Illuminate\Broadcasting\InteractsWithSockets; class UpdateUserLastLogin implements ShouldQueue { @@ -51,8 +52,10 @@ class UpdateUserLastLogin implements ShouldQueue $event_vars = $event->event_vars; $ip = array_key_exists('ip', $event->event_vars) ? $event->event_vars['ip'] : 'IP address not resolved'; + $key = "user_logged_in_{$user->id}{$event->company->db}"; - if ($user->ip != $ip) { + + if ($user->ip != $ip && is_null(Cache::get($key))) { $nmo = new NinjaMailerObject; $nmo->mailable = new UserLoggedIn($user, $user->account->companies->first(), $ip); $nmo->company = $user->account->companies->first(); @@ -63,7 +66,8 @@ class UpdateUserLastLogin implements ShouldQueue $user->ip = $ip; $user->save(); } - + + Cache::put($key, true, 60 * 24); $arr = json_encode(['ip' => $ip]); SystemLogger::dispatch( From 9bd1946bc4c53942ef041f942a4957ef0ccc613f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 09:12:12 +1000 Subject: [PATCH 03/17] Update task statuses on reorder --- app/Http/Controllers/TaskStatusController.php | 348 ++---------------- .../TaskStatus/UpdateTaskStatusRequest.php | 5 - app/Models/TaskStatus.php | 2 +- app/Repositories/TaskStatusRepository.php | 14 + tests/Feature/TaskStatusApiTest.php | 35 ++ 5 files changed, 77 insertions(+), 327 deletions(-) diff --git a/app/Http/Controllers/TaskStatusController.php b/app/Http/Controllers/TaskStatusController.php index 188312faa512..01f6756a3970 100644 --- a/app/Http/Controllers/TaskStatusController.php +++ b/app/Http/Controllers/TaskStatusController.php @@ -1,4 +1,13 @@ task_status_repo = $task_status_repo; } - + /** - * @OA\Get( - * path="/api/v1/task_statuses", - * operationId="getTaskStatuses", - * tags={"task_status"}, - * summary="Gets a list of task statuses", - * description="Lists task statuses", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter(ref="#/components/parameters/index"), - * @OA\Response( - * response=200, - * description="A list of task statuses", - * @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/TaskStatus"), - * ), - * @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"), - * ), - * ) + * index + * + * @param TaskStatusFilters $filters + * @return Response */ public function index(TaskStatusFilters $filters) { @@ -82,44 +63,12 @@ class TaskStatusController extends BaseController return $this->listResponse($task_status); } + /** - * Show the form for creating a new resource. - * - * @param CreateTaskStatusRequest $request The request + * create * + * @param CreateTaskStatusRequest $request * @return Response - * - * - * - * @OA\Get( - * path="/api/v1/task_statuses/create", - * operationId="getTaskStatussCreate", - * tags={"task_status"}, - * summary="Gets a new blank TaskStatus object", - * description="Returns a blank object with default values", - * @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 TaskStatus 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/TaskStatus"), - * ), - * @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(CreateTaskStatusRequest $request) { @@ -132,49 +81,11 @@ class TaskStatusController extends BaseController * Store a newly created resource in storage. * * @param StoreTaskStatusRequest $request The request - * * @return Response * - * - * - * @OA\Post( - * path="/api/v1/task_statuses", - * operationId="storeTaskStatus", - * tags={"task_status"}, - * summary="Adds a TaskStatus", - * description="Adds a TaskStatusto the system", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\RequestBody( - * description="The task_status request", - * required=true, - * @OA\JsonContent(ref="#/components/schemas/TaskStatus"), - * ), - * @OA\Response( - * response=200, - * description="Returns the saved TaskStatus 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/TaskStatus"), - * ), - * @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 store(StoreTaskStatusRequest $request) { - // nlog($request->all()); $task_status = TaskStatusFactory::create(auth()->user()->company()->id, auth()->user()->id); $task_status->fill($request->all()); @@ -185,46 +96,6 @@ class TaskStatusController extends BaseController } /** - * @OA\Get( - * path="/api/v1/task_statuses/{id}", - * operationId="showTaskStatus", - * tags={"task_status"}, - * summary="Shows a TaskStatus Term", - * description="Displays an TaskStatusby id", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter( - * name="id", - * in="path", - * description="The TaskStatusHashed ID", - * example="D2J234DFA", - * required=true, - * @OA\Schema( - * type="string", - * format="string", - * ), - * ), - * @OA\Response( - * response=200, - * description="Returns the TaskStatusobject", - * @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/TaskStatus"), - * ), - * @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"), - * ), - * ) * @param ShowTaskStatusRequest $request * @param TaskStatus $task_status * @return Response|mixed @@ -235,46 +106,6 @@ class TaskStatusController extends BaseController } /** - * @OA\Get( - * path="/api/v1/task_statuses/{id}/edit", - * operationId="editTaskStatuss", - * tags={"task_status"}, - * summary="Shows an TaskStatusfor editting", - * description="Displays an TaskStatusby id", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter( - * name="id", - * in="path", - * description="The TaskStatusHashed ID", - * example="D2J234DFA", - * required=true, - * @OA\Schema( - * type="string", - * format="string", - * ), - * ), - * @OA\Response( - * response=200, - * description="Returns the TaskStatus 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/TaskStatus"), - * ), - * @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"), - * ), - * ) * @param EditTaskStatusRequest $request * @param TaskStatus $payment * @return Response|mixed @@ -289,56 +120,18 @@ class TaskStatusController extends BaseController * * @param UpdateTaskStatusRequest $request The request * @param TaskStatus $task_status The payment term - * * @return Response - * - * - * @OA\Put( - * path="/api/v1/task_statuses/{id}", - * operationId="updateTaskStatus", - * tags={"task_status"}, - * summary="Updates a TaskStatus Term", - * description="Handles the updating of an TaskStatus Termby id", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter( - * name="id", - * in="path", - * description="The TaskStatusHashed ID", - * example="D2J234DFA", - * required=true, - * @OA\Schema( - * type="string", - * format="string", - * ), - * ), - * @OA\Response( - * response=200, - * description="Returns the TaskStatusobject", - * @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/TaskStatus"), - * ), - * @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 update(UpdateTaskStatusRequest $request, TaskStatus $task_status) { + $task_status->fill($request->all()); + $reorder = $task_status->isDirty('status_order'); $task_status->save(); + if ($reorder) + $this->task_status_repo->reorder($task_status); + return $this->itemResponse($task_status->fresh()); } @@ -347,50 +140,9 @@ class TaskStatusController extends BaseController * * @param DestroyTaskStatusRequest $request * @param TaskStatus $task_status - * - * @return Response - * - * + * @return Response + * * @throws \Exception - * @OA\Delete( - * path="/api/v1/task_statuses/{id}", - * operationId="deleteTaskStatus", - * tags={"task_statuss"}, - * summary="Deletes a TaskStatus Term", - * description="Handles the deletion of an TaskStatus by id", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter( - * name="id", - * in="path", - * description="The TaskStatusHashed ID", - * example="D2J234DFA", - * required=true, - * @OA\Schema( - * type="string", - * format="string", - * ), - * ), - * @OA\Response( - * response=200, - * description="Returns a HTTP status", - * @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\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 destroy(DestroyTaskStatusRequest $request, TaskStatus $task_status) { @@ -401,54 +153,8 @@ class TaskStatusController extends BaseController /** * Perform bulk actions on the list view. - * - * @return Collection - * - * - * @OA\Post( - * path="/api/v1/task_statuses/bulk", - * operationId="bulkTaskStatuss", - * tags={"task_status"}, - * summary="Performs bulk actions on an array of task statuses", - * description="", - * @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="TaskStatus Ter,s", - * 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 TaskStatus Terms 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/TaskStatus"), - * ), - * @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"), - * ), - * ) + * @param ActionTaskStatusRequest $request + * @return Response */ public function bulk(ActionTaskStatusRequest $request) { diff --git a/app/Http/Requests/TaskStatus/UpdateTaskStatusRequest.php b/app/Http/Requests/TaskStatus/UpdateTaskStatusRequest.php index 2861bb1a9551..e7a0b757c9ef 100644 --- a/app/Http/Requests/TaskStatus/UpdateTaskStatusRequest.php +++ b/app/Http/Requests/TaskStatus/UpdateTaskStatusRequest.php @@ -33,11 +33,6 @@ class UpdateTaskStatusRequest extends Request { $rules = []; - // 26/10/2021 we disable this as it prevent updating existing task status meta data where the same name already exists - // if ($this->input('name')) { - // $rules['name'] = Rule::unique('task_statuses')->where('company_id', auth()->user()->company()->id)->ignore($this->task_status->id); - // } - return $rules; } diff --git a/app/Models/TaskStatus.php b/app/Models/TaskStatus.php index 8e30f5fa43ac..3b23281de1c0 100644 --- a/app/Models/TaskStatus.php +++ b/app/Models/TaskStatus.php @@ -63,7 +63,7 @@ class TaskStatus extends BaseModel public $timestamps = true; /** - * @var array + * @var array */ protected $fillable = [ 'name', diff --git a/app/Repositories/TaskStatusRepository.php b/app/Repositories/TaskStatusRepository.php index 8692ed51fd35..0ff8904d0c79 100644 --- a/app/Repositories/TaskStatusRepository.php +++ b/app/Repositories/TaskStatusRepository.php @@ -53,4 +53,18 @@ class TaskStatusRepository extends BaseRepository return $task_status; } + + public function reorder(TaskStatus $task_status) + { + + TaskStatus::query() + ->where('company_id', $task_status->company_id) + ->orderByRaw('ISNULL(status_order), status_order ASC') + ->orderBy('updated_at', 'DESC') + ->cursor() + ->each(function ($task_status, $index) { + $task_status->update(['status_order' => $index+1]); + }); + + } } diff --git a/tests/Feature/TaskStatusApiTest.php b/tests/Feature/TaskStatusApiTest.php index 4ce96974699c..780ba4c12e0c 100644 --- a/tests/Feature/TaskStatusApiTest.php +++ b/tests/Feature/TaskStatusApiTest.php @@ -11,6 +11,7 @@ namespace Tests\Feature; +use App\Models\TaskStatus; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\Model; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -28,6 +29,8 @@ class TaskStatusApiTest extends TestCase use DatabaseTransactions; use MockAccountData; + public $faker; + protected function setUp() :void { parent::setUp(); @@ -41,6 +44,38 @@ class TaskStatusApiTest extends TestCase Model::reguard(); } + public function testSorting() + { + TaskStatus::factory()->count(5)->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id + ]); + + + $t = TaskStatus::where('company_id', '=', $this->company->id)->orderBy('id', 'desc'); + + $this->assertEquals(10, $t->count()); + $task_status = $t->first(); + + $id = $task_status->id; + + nlog("setting {$id} to index 1"); + + $data = [ + 'status_order' => 1, + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->put('/api/v1/task_statuses/'.$task_status->hashed_id, $data); + + $t = TaskStatus::where('company_id', '=', $this->company->id)->orderBy('status_order', 'asc')->first(); + + $this->assertEquals($id, $t->id); + + } + public function testTaskStatusGetFilter() { $response = $this->withHeaders([ From dd59cb6de6c46f1dbfed351e0c712502d00cc941 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 09:19:01 +1000 Subject: [PATCH 04/17] Fixes for recurring expense payment dates --- app/Factory/RecurringExpenseToExpenseFactory.php | 2 +- app/Http/Controllers/DocumentController.php | 7 +++++-- app/Http/Requests/Document/UpdateDocumentRequest.php | 4 +++- app/Jobs/Cron/RecurringExpensesCron.php | 7 +------ app/Transformers/AccountTransformer.php | 2 ++ 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/Factory/RecurringExpenseToExpenseFactory.php b/app/Factory/RecurringExpenseToExpenseFactory.php index 1fc9626aa72e..98c2a7beee6f 100644 --- a/app/Factory/RecurringExpenseToExpenseFactory.php +++ b/app/Factory/RecurringExpenseToExpenseFactory.php @@ -40,7 +40,7 @@ class RecurringExpenseToExpenseFactory $expense->tax_name3 = $recurring_expense->tax_name3; $expense->tax_rate3 = $recurring_expense->tax_rate3; $expense->date = now()->format('Y-m-d'); - $expense->payment_date = $recurring_expense->payment_date; + $expense->payment_date = $recurring_expense->payment_date ?: now()->format('Y-m-d'); $expense->amount = $recurring_expense->amount; $expense->foreign_amount = $recurring_expense->foreign_amount ?: 0; diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 20263da9d34b..7997de5101d0 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -145,8 +145,11 @@ class DocumentController extends BaseController * @return Response */ public function update(UpdateDocumentRequest $request, Document $document) - { - return $this->itemResponse($document); + { + $document->fill($request->all()); + $document->save(); + + return $this->itemResponse($document->fresh()); } /** diff --git a/app/Http/Requests/Document/UpdateDocumentRequest.php b/app/Http/Requests/Document/UpdateDocumentRequest.php index ff93a634cb37..9fc24354dfa0 100644 --- a/app/Http/Requests/Document/UpdateDocumentRequest.php +++ b/app/Http/Requests/Document/UpdateDocumentRequest.php @@ -30,7 +30,9 @@ class UpdateDocumentRequest extends Request public function rules() { - return []; + return [ + 'name' => 'sometimes|alpha_num' + ]; } public function prepareForValidation() diff --git a/app/Jobs/Cron/RecurringExpensesCron.php b/app/Jobs/Cron/RecurringExpensesCron.php index 476f57e7ba81..796d38a3c49d 100644 --- a/app/Jobs/Cron/RecurringExpensesCron.php +++ b/app/Jobs/Cron/RecurringExpensesCron.php @@ -98,15 +98,10 @@ class RecurringExpensesCron } } - private function getRecurringExpenses() - { - //extracting this back to the if/else block to test duplicate crons - } - private function generateExpense(RecurringExpense $recurring_expense) { $expense = RecurringExpenseToExpenseFactory::create($recurring_expense); - $expense->save(); + $expense->saveQuietly(); $expense->number = $this->getNextExpenseNumber($expense); $expense->save(); diff --git a/app/Transformers/AccountTransformer.php b/app/Transformers/AccountTransformer.php index d7eaeb9d3fe2..6d433715c40a 100644 --- a/app/Transformers/AccountTransformer.php +++ b/app/Transformers/AccountTransformer.php @@ -90,6 +90,8 @@ class AccountTransformer extends EntityTransformer 'set_react_as_default_ap' => (bool) $account->set_react_as_default_ap, 'trial_days_left' => Ninja::isHosted() ? (int) $account->getTrialDays() : 0, 'account_sms_verified' => (bool) $account->account_sms_verified, + 'has_iap_plan' => (bool)$account->inapp_transaction_id, + ]; } From 7099ab1c5dc0ccf0c88f96437d66bf03759961c7 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 09:26:57 +1000 Subject: [PATCH 05/17] Fixes for scheduler --- app/Models/Scheduler.php | 3 +++ app/Repositories/SchedulerRepository.php | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/app/Models/Scheduler.php b/app/Models/Scheduler.php index 09c403781a6e..c9451b76cb8b 100644 --- a/app/Models/Scheduler.php +++ b/app/Models/Scheduler.php @@ -153,6 +153,9 @@ class Scheduler extends BaseModel $offset = $this->company->timezone_offset(); switch ($this->frequency_id) { + case 0: //used only for email entities + $next_run = now()->startOfDay(); + break; case RecurringInvoice::FREQUENCY_DAILY: $next_run = now()->startOfDay()->addDay(); break; diff --git a/app/Repositories/SchedulerRepository.php b/app/Repositories/SchedulerRepository.php index 016957940f53..c0f852615632 100644 --- a/app/Repositories/SchedulerRepository.php +++ b/app/Repositories/SchedulerRepository.php @@ -25,13 +25,18 @@ class SchedulerRepository extends BaseRepository */ public function save(array $data, Scheduler $scheduler): Scheduler { + nlog($data); $scheduler->fill($data); $scheduler->save(); + nlog($scheduler->withoutRelations()->toArray()); + /** 18-5-2023 set client specific send times. */ $scheduler->calculateNextRun(); + + nlog($scheduler->withoutRelations()->toArray()); return $scheduler->fresh(); } From b27c77324e3ccd3f0315d0592ded1b3294fd32d2 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 09:32:04 +1000 Subject: [PATCH 06/17] better logging for webhooks --- app/Jobs/Util/WebhookSingle.php | 4 ++-- app/Repositories/SchedulerRepository.php | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index 8e83e018a9f0..d322738601c0 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -170,9 +170,9 @@ class WebhookSingle implements ShouldQueue } if ($e->getResponse()->getStatusCode() >= 500) { - nlog("endpoint returned a 500, failing"); + nlog("{$subscription->target_url} returned a 500, failing"); - $message = "The was a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode(). " no retry attempted."; + $message = "There was a problem when connecting to {$subscription->target_url} => status code ". $e->getResponse()->getStatusCode(). " no retry attempted."; (new SystemLogger( ['message' => $message], diff --git a/app/Repositories/SchedulerRepository.php b/app/Repositories/SchedulerRepository.php index c0f852615632..2f2f314cb5c4 100644 --- a/app/Repositories/SchedulerRepository.php +++ b/app/Repositories/SchedulerRepository.php @@ -25,19 +25,14 @@ class SchedulerRepository extends BaseRepository */ public function save(array $data, Scheduler $scheduler): Scheduler { - nlog($data); $scheduler->fill($data); $scheduler->save(); - nlog($scheduler->withoutRelations()->toArray()); - /** 18-5-2023 set client specific send times. */ $scheduler->calculateNextRun(); - nlog($scheduler->withoutRelations()->toArray()); - return $scheduler->fresh(); } } From 3e8171f2a8dba1f31c3f6b3762970bee9fbe5d9f Mon Sep 17 00:00:00 2001 From: David Bomba Date: Thu, 18 May 2023 16:25:38 +1000 Subject: [PATCH 07/17] Minor fixes for translations --- app/Http/Requests/Company/UpdateCompanyRequest.php | 2 +- lang/en/texts.php | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Http/Requests/Company/UpdateCompanyRequest.php b/app/Http/Requests/Company/UpdateCompanyRequest.php index 4b72c48ee8bf..d4ce94df41e7 100644 --- a/app/Http/Requests/Company/UpdateCompanyRequest.php +++ b/app/Http/Requests/Company/UpdateCompanyRequest.php @@ -63,7 +63,7 @@ class UpdateCompanyRequest extends Request if (Ninja::isHosted()) { $rules['subdomain'] = ['nullable', 'regex:/^[a-zA-Z0-9.-]+[a-zA-Z0-9]$/', new ValidSubdomain($this->all())]; } else { - $rules['subdomain'] = 'nullable|alpha_num'; + $rules['subdomain'] = 'nullable|regex:/^[a-zA-Z0-9.-]+[a-zA-Z0-9]$/'; } } diff --git a/lang/en/texts.php b/lang/en/texts.php index 009e9dee94e6..17055985e0f0 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5087,6 +5087,8 @@ $LANG = array( 'light_dark_mode' => 'Light/Dark Mode', 'activities' => 'Activities', 'recent_transactions' => "Here are your company's most recent transactions:", + 'country_Palestine' => "Palestine", + 'country_Taiwan' => 'Taiwan', ); From 402b725909a410b9d0685e91aedbeda01ed61c80 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 19 May 2023 14:06:57 +1000 Subject: [PATCH 08/17] Updates for translations --- lang/en/texts.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lang/en/texts.php b/lang/en/texts.php index 17055985e0f0..c503256f927b 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5089,6 +5089,9 @@ $LANG = array( 'recent_transactions' => "Here are your company's most recent transactions:", 'country_Palestine' => "Palestine", 'country_Taiwan' => 'Taiwan', + 'duties' => 'Duties', + 'order_number' => 'Order Number', + 'order_id' => 'Order', ); From ea0975d41cb3dd72834b87ec5264be7d85aa1764 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 19 May 2023 19:43:11 +1000 Subject: [PATCH 09/17] Additional translations --- lang/en/texts.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/en/texts.php b/lang/en/texts.php index c503256f927b..a8b645e600af 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5092,6 +5092,7 @@ $LANG = array( 'duties' => 'Duties', 'order_number' => 'Order Number', 'order_id' => 'Order', + 'total_invoices_outstanding' => 'Total Invoices Outstanding', ); From 4706d756ed6207758397a5738b2f71892d84e0ab Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 19 May 2023 19:49:06 +1000 Subject: [PATCH 10/17] additional translations --- lang/en/texts.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/en/texts.php b/lang/en/texts.php index a8b645e600af..0d420fe76aea 100644 --- a/lang/en/texts.php +++ b/lang/en/texts.php @@ -5093,6 +5093,7 @@ $LANG = array( 'order_number' => 'Order Number', 'order_id' => 'Order', 'total_invoices_outstanding' => 'Total Invoices Outstanding', + 'recent_activity' => 'Recent Activity', ); From 33acfeae9e4a9295b00000c7e0a5072865156eb5 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 May 2023 11:06:14 +1000 Subject: [PATCH 11/17] Add additiona entropy to Backoff method --- app/Jobs/Mail/NinjaMailerJob.php | 4 +++- app/Jobs/Util/WebhookSingle.php | 4 +++- app/Services/Email/Email.php | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/Jobs/Mail/NinjaMailerJob.php b/app/Jobs/Mail/NinjaMailerJob.php index 437cc7233fe9..3b8611bb3f1e 100644 --- a/app/Jobs/Mail/NinjaMailerJob.php +++ b/app/Jobs/Mail/NinjaMailerJob.php @@ -72,7 +72,9 @@ class NinjaMailerJob implements ShouldQueue public function backoff() { - return [5, 10, 30, 240]; + // return [5, 10, 30, 240]; + return [rand(5, 10), rand(30, 40), rand(60, 79), rand(160, 400)]; + } public function handle() diff --git a/app/Jobs/Util/WebhookSingle.php b/app/Jobs/Util/WebhookSingle.php index d322738601c0..d840d8544359 100644 --- a/app/Jobs/Util/WebhookSingle.php +++ b/app/Jobs/Util/WebhookSingle.php @@ -63,7 +63,9 @@ class WebhookSingle implements ShouldQueue public function backoff() { - return [15, 35, 65, 185, 3605]; + // return [15, 35, 65, 185, 3605]; + return [rand(10, 15), rand(30, 40), rand(60, 79), rand(160, 200), rand(3000, 5000)]; + } /** diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index ddbfee25fb92..6f0488c2be96 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -75,7 +75,8 @@ class Email implements ShouldQueue */ public function backoff() { - return [10, 30, 60, 240]; + // return [10, 30, 60, 240]; + return [rand(5, 10), rand(30, 40), rand(60, 79), rand(160, 400)]; } public function handle() From b1e0718a89b5ac7b3778b37b0cd0928aa1a0ce07 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 May 2023 12:04:07 +1000 Subject: [PATCH 12/17] Fixes for AR Summary reports --- app/Exceptions/Handler.php | 12 ++++++------ app/Services/Report/ARDetailReport.php | 2 -- app/Services/Report/ARSummaryReport.php | 5 ++++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 2df86c581f9d..a62b73c89ed0 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -44,12 +44,12 @@ class Handler extends ExceptionHandler * @var array */ protected $dontReport = [ - PDOException::class, - MaxAttemptsExceededException::class, - CommandNotFoundException::class, - ValidationException::class, - ModelNotFoundException::class, - NotFoundHttpException::class, + // PDOException::class, + // MaxAttemptsExceededException::class, + // CommandNotFoundException::class, + // ValidationException::class, + // ModelNotFoundException::class, + // NotFoundHttpException::class, ]; protected $selfHostDontReport = [ diff --git a/app/Services/Report/ARDetailReport.php b/app/Services/Report/ARDetailReport.php index c283a0a84ab0..3787acd07cd5 100644 --- a/app/Services/Report/ARDetailReport.php +++ b/app/Services/Report/ARDetailReport.php @@ -100,8 +100,6 @@ class ARDetailReport extends BaseExport $query = $this->filterByClients($query); - $this->csv->insertOne($this->buildHeader()); - $query->cursor() ->each(function ($invoice) { $this->csv->insertOne($this->buildRow($invoice)); diff --git a/app/Services/Report/ARSummaryReport.php b/app/Services/Report/ARSummaryReport.php index 58d509fbcf78..b561d0fbf538 100644 --- a/app/Services/Report/ARSummaryReport.php +++ b/app/Services/Report/ARSummaryReport.php @@ -122,7 +122,10 @@ class ARSummaryReport extends BaseExport ->whereIn('status_id', [Invoice::STATUS_SENT, Invoice::STATUS_PARTIAL]) ->where('balance', '>', 0) ->where('is_deleted', 0) - ->where('due_date', '<', now()->startOfDay()) + ->where(function ($query){ + $query->where('due_date', '<', now()->startOfDay()) + ->orWhereNull('due_date'); + }) ->sum('balance'); return Number::formatMoney($amount, $this->client); From 4409c40053707746b45406978f60a9118696f216 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 May 2023 19:27:10 +1000 Subject: [PATCH 13/17] Fixes for backoff --- app/Services/Email/Email.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php index 6f0488c2be96..ac606a0b2e9e 100644 --- a/app/Services/Email/Email.php +++ b/app/Services/Email/Email.php @@ -76,7 +76,7 @@ class Email implements ShouldQueue public function backoff() { // return [10, 30, 60, 240]; - return [rand(5, 10), rand(30, 40), rand(60, 79), rand(160, 400)]; + return [rand(10, 20), rand(30, 45), rand(60, 79), rand(160, 400)]; } public function handle() From b896c2c59066da837139e9e572f7a7639b3e90dd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 May 2023 19:33:37 +1000 Subject: [PATCH 14/17] Shuffle reportable exceptions --- app/Exceptions/Handler.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index a62b73c89ed0..0d34120a66f5 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -17,7 +17,6 @@ use App\Utils\Ninja; use Sentry\State\Scope; use Illuminate\Support\Arr; use Illuminate\Http\Request; -use Illuminate\Http\Response; use Sentry\Laravel\Integration; use Illuminate\Support\Facades\Schema; use GuzzleHttp\Exception\ConnectException; @@ -35,21 +34,22 @@ use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Illuminate\Database\Eloquent\ModelNotFoundException as ModelNotFoundException; +use InvalidArgumentException; class Handler extends ExceptionHandler { /** * A list of the exception types that are not reported. * - * @var array + * @var array> */ protected $dontReport = [ // PDOException::class, - // MaxAttemptsExceededException::class, - // CommandNotFoundException::class, - // ValidationException::class, + MaxAttemptsExceededException::class, + CommandNotFoundException::class, + ValidationException::class, // ModelNotFoundException::class, - // NotFoundHttpException::class, + NotFoundHttpException::class, ]; protected $selfHostDontReport = [ From 4b16e2dabffb50bbe006068fb5f12f1f19110a6d Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sat, 20 May 2023 19:40:17 +1000 Subject: [PATCH 15/17] Minor fixes for design variable declarations --- app/Services/PdfMaker/Design.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Services/PdfMaker/Design.php b/app/Services/PdfMaker/Design.php index 0ca327ce1572..51c58ce1c532 100644 --- a/app/Services/PdfMaker/Design.php +++ b/app/Services/PdfMaker/Design.php @@ -26,13 +26,13 @@ class Design extends BaseDesign { use MakesInvoiceValues, DesignHelpers, MakesDates; - /** @var App\Models\Invoice || @var App\Models\Quote */ + /** @var \App\Models\Invoice | \App\Models\Quote | \App\Models\Credit | \App\Models\PurchaseOrder | \App\Models\RecurringInvoice */ public $entity; - /** @var App\Models\Client */ + /** @var \App\Models\Client */ public $client; - /** @var App\Models\Vendor */ + /** @var \App\Models\Vendor */ public $vendor; /** Global state of the design, @var array */ From 855e20b6b2fd5f3ad90f118bfdef8fd7bcdb03fd Mon Sep 17 00:00:00 2001 From: David Bomba Date: Sun, 21 May 2023 20:31:55 +1000 Subject: [PATCH 16/17] Version Chart queries --- app/Http/Controllers/ChartController.php | 63 +++----- app/Services/Chart/ChartQueriesLegacy.php | 169 ++++++++++++++++++++++ app/Services/Chart/ChartServiceLegacy.php | 162 +++++++++++++++++++++ config/liap.php | 22 ++- routes/api.php | 3 + 5 files changed, 378 insertions(+), 41 deletions(-) create mode 100644 app/Services/Chart/ChartQueriesLegacy.php create mode 100644 app/Services/Chart/ChartServiceLegacy.php diff --git a/app/Http/Controllers/ChartController.php b/app/Http/Controllers/ChartController.php index 651ded493fbb..85b387d30202 100644 --- a/app/Http/Controllers/ChartController.php +++ b/app/Http/Controllers/ChartController.php @@ -22,45 +22,6 @@ class ChartController extends BaseController } /** - * @OA\Post( - * path="/api/v1/charts/totals", - * operationId="getChartTotals", - * tags={"charts"}, - * summary="Get chart data", - * description="Get chart data", - * @OA\Parameter(ref="#/components/parameters/X-API-TOKEN"), - * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), - * @OA\Parameter(ref="#/components/parameters/include"), - * @OA\Parameter(ref="#/components/parameters/index"), - * @OA\Parameter( - * name="rows", - * in="query", - * description="The number of activities to return", - * example="50", - * required=false, - * @OA\Schema( - * type="number", - * format="integer", - * ), - * ), - * @OA\Response( - * response=200, - * description="json dataset of chart data", - * @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\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"), - * ), - * ) * @param ShowChartRequest $request */ public function totals(ShowChartRequest $request) @@ -81,4 +42,28 @@ class ChartController extends BaseController return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200); } + + /** + * @param ShowChartRequest $request + */ + public function totalsV2(ShowChartRequest $request) + { + /** @var \App\Models\User auth()->user() */ + $user = auth()->user(); + $cs = new ChartService($user->company(), $user, $user->isAdmin()); + + return response()->json($cs->totals($request->input('start_date'), $request->input('end_date')), 200); + } + + public function chart_summaryV2(ShowChartRequest $request) + { + + /** @var \App\Models\User auth()->user() */ + $user = auth()->user(); + $cs = new ChartService($user->company(), $user, $user->isAdmin()); + + return response()->json($cs->chart_summary($request->input('start_date'), $request->input('end_date')), 200); + } + + } diff --git a/app/Services/Chart/ChartQueriesLegacy.php b/app/Services/Chart/ChartQueriesLegacy.php new file mode 100644 index 000000000000..2e03bca4abee --- /dev/null +++ b/app/Services/Chart/ChartQueriesLegacy.php @@ -0,0 +1,169 @@ + $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]); + } + + public function getExpenseChartQuery($start_date, $end_date, $currency_id) + { + return DB::select(DB::raw(' + SELECT + sum(expenses.amount) as total, + expenses.date, + IFNULL(expenses.currency_id, :company_currency) AS currency_id + FROM expenses + WHERE (expenses.date BETWEEN :start_date AND :end_date) + AND expenses.company_id = :company_id + AND expenses.is_deleted = 0 + GROUP BY expenses.date + HAVING currency_id = :currency_id + '), [ + 'company_currency' => $this->company->settings->currency_id, + 'currency_id' => $currency_id, + 'company_id' => $this->company->id, + 'start_date' => $start_date, + 'end_date' => $end_date, + ]); + } + + /** + * Payments + */ + public function getPaymentQuery($start_date, $end_date) + { + return DB::select(DB::raw(' + SELECT sum(payments.amount) as amount, + IFNULL(payments.currency_id, :company_currency) as currency_id + FROM payments + WHERE payments.is_deleted = 0 + AND payments.company_id = :company_id + AND (payments.date BETWEEN :start_date AND :end_date) + GROUP BY currency_id + '), [ + 'company_currency' => $this->company->settings->currency_id, + 'company_id' => $this->company->id, + 'start_date' => $start_date, + 'end_date' => $end_date, + ]); + } + + public function getPaymentChartQuery($start_date, $end_date, $currency_id) + { + return DB::select(DB::raw(' + SELECT + sum(payments.amount - payments.refunded) as total, + payments.date, + IFNULL(payments.currency_id, :company_currency) AS currency_id + FROM payments + WHERE payments.status_id IN (4,5,6) + AND (payments.date BETWEEN :start_date AND :end_date) + AND payments.company_id = :company_id + AND payments.is_deleted = 0 + GROUP BY payments.date + HAVING currency_id = :currency_id + '), [ + 'company_currency' => $this->company->settings->currency_id, + 'currency_id' => $currency_id, + 'company_id' => $this->company->id, + 'start_date' => $start_date, + 'end_date' => $end_date, + ]); + } + + /** + * Invoices + */ + public function getOutstandingQuery($start_date, $end_date) + { + return DB::select(DB::raw(" + SELECT + sum(invoices.balance) as amount, + IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id + FROM clients + JOIN invoices + on invoices.client_id = clients.id + WHERE invoices.status_id IN (2,3) + AND invoices.company_id = :company_id + AND invoices.balance > 0 + AND clients.is_deleted = 0 + AND invoices.is_deleted = 0 + AND (invoices.date BETWEEN :start_date AND :end_date) + GROUP BY currency_id + "), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]); + } + + public function getRevenueQuery($start_date, $end_date) + { + return DB::select(DB::raw(" + SELECT + sum(invoices.paid_to_date) as paid_to_date, + IFNULL(JSON_EXTRACT( settings, '$.currency_id' ), :company_currency) AS currency_id + FROM clients + JOIN invoices + on invoices.client_id = clients.id + WHERE invoices.status_id IN (3,4) + AND invoices.company_id = :company_id + AND invoices.amount > 0 + AND clients.is_deleted = 0 + AND invoices.is_deleted = 0 + AND (invoices.date BETWEEN :start_date AND :end_date) + GROUP BY currency_id + "), ['company_currency' => $this->company->settings->currency_id, 'company_id' => $this->company->id, 'start_date' => $start_date, 'end_date' => $end_date]); + } + + public function getInvoiceChartQuery($start_date, $end_date, $currency_id) + { + return DB::select(DB::raw(" + SELECT + sum(invoices.amount) as total, + invoices.date, + IFNULL(CAST(JSON_EXTRACT( settings, '$.currency_id' ) AS SIGNED), :company_currency) AS currency_id + FROM clients + JOIN invoices + on invoices.client_id = clients.id + WHERE invoices.status_id IN (2,3,4) + AND (invoices.date BETWEEN :start_date AND :end_date) + AND invoices.company_id = :company_id + AND clients.is_deleted = 0 + AND invoices.is_deleted = 0 + GROUP BY invoices.date + HAVING currency_id = :currency_id + "), [ + 'company_currency' => (int) $this->company->settings->currency_id, + 'currency_id' => $currency_id, + 'company_id' => $this->company->id, + 'start_date' => $start_date, + 'end_date' => $end_date, + ]); + } +} diff --git a/app/Services/Chart/ChartServiceLegacy.php b/app/Services/Chart/ChartServiceLegacy.php new file mode 100644 index 000000000000..84e53cec935c --- /dev/null +++ b/app/Services/Chart/ChartServiceLegacy.php @@ -0,0 +1,162 @@ +company = $company; + } + + /** + * Returns an array of currencies that have + * transacted with a company + */ + public function getCurrencyCodes() :array + { + /* Get all the distinct client currencies */ + $currencies = Client::withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0) + ->distinct() + ->pluck('settings->currency_id as id'); + + /* Push the company currency on also */ + $currencies->push((int) $this->company->settings->currency_id); + + /* Add our expense currencies*/ + $expense_currencies = Expense::withTrashed() + ->where('company_id', $this->company->id) + ->where('is_deleted', 0) + ->distinct() + ->pluck('currency_id as id'); + + /* Merge and filter by unique */ + $currencies = $currencies->merge($expense_currencies)->unique(); + + $cache_currencies = Cache::get('currencies'); + + $filtered_currencies = $cache_currencies->whereIn('id', $currencies)->all(); + + $final_currencies = []; + + foreach ($filtered_currencies as $c_currency) { + $final_currencies[$c_currency['id']] = $c_currency['code']; + } + + return $final_currencies; + } + + /* Chart Data */ + public function chart_summary($start_date, $end_date) :array + { + $currencies = $this->getCurrencyCodes(); + + $data = []; + + foreach ($currencies as $key => $value) { + $data[$key]['invoices'] = $this->getInvoiceChartQuery($start_date, $end_date, $key); + $data[$key]['payments'] = $this->getPaymentChartQuery($start_date, $end_date, $key); + $data[$key]['expenses'] = $this->getExpenseChartQuery($start_date, $end_date, $key); + } + + return $data; + } + + /* Chart Data */ + + /* Totals */ + + public function totals($start_date, $end_date) :array + { + $data = []; + + $data['currencies'] = $this->getCurrencyCodes(); + + foreach ($data['currencies'] as $key => $value) { + $revenue = $this->getRevenue($start_date, $end_date); + $outstanding = $this->getOutstanding($start_date, $end_date); + $expenses = $this->getExpenses($start_date, $end_date); + + $data[$key]['revenue'] = count($revenue) > 0 ? $revenue[array_search($key, array_column($revenue, 'currency_id'))] : new \stdClass; + $data[$key]['outstanding'] = count($outstanding) > 0 ? $outstanding[array_search($key, array_column($outstanding, 'currency_id'))] : new \stdClass; + $data[$key]['expenses'] = count($expenses) > 0 ? $expenses[array_search($key, array_column($expenses, 'currency_id'))] : new \stdClass; + } + + return $data; + } + + public function getRevenue($start_date, $end_date) :array + { + $revenue = $this->getRevenueQuery($start_date, $end_date); + $revenue = $this->addCurrencyCodes($revenue); + + return $revenue; + } + + public function getOutstanding($start_date, $end_date) :array + { + $outstanding = $this->getOutstandingQuery($start_date, $end_date); + $outstanding = $this->addCurrencyCodes($outstanding); + + return $outstanding; + } + + public function getExpenses($start_date, $end_date) :array + { + $expenses = $this->getExpenseQuery($start_date, $end_date); + $expenses = $this->addCurrencyCodes($expenses); + + return $expenses; + } + + /* Totals */ + + /* Helpers */ + + private function addCurrencyCodes($data_set) :array + { + $currencies = Cache::get('currencies'); + + foreach ($data_set as $key => $value) { + $data_set[$key]->currency_id = str_replace('"', '', $value->currency_id); + $data_set[$key]->code = $this->getCode($currencies, $data_set[$key]->currency_id); + } + + return $data_set; + } + + private function getCode($currencies, $currency_id) :string + { + $currency_id = str_replace('"', '', $currency_id); + + $currency = $currencies->filter(function ($item) use ($currency_id) { + return $item->id == $currency_id; + })->first(); + + if ($currency) { + return $currency->code; + } + + return ''; + } +} diff --git a/config/liap.php b/config/liap.php index cbc569b294b0..6a57acf72901 100644 --- a/config/liap.php +++ b/config/liap.php @@ -1,8 +1,17 @@ class_exists(\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\AppleAutoRenew::class] : [], SubscriptionRenewed::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleAutoRenew::class] : [], - + DidChangeRenewalStatus::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class) ? [\Modules\Admin\Listeners\Subscription\GoogleChangeRenewalStaus::class] : [], + DidFailToRenew::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class) ? [\Modules\Admin\Listeners\Subscription\GoogleFailedToRenew::class] : [], + Refund::class => class_exists(\Modules\Admin\Listeners\Subscription\AppleRefund::class) ? [\Modules\Admin\Listeners\Subscription\AppleRefund::class] : [], + SubscriptionRecovered::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRecovered::class] : [], + SubscriptionCanceled::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionCanceled::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionCanceled::class] : [], + SubscriptionPurchased::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPurchased::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPurchased::class] : [], + SubscriptionRestarted::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRestarted::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRestarted::class] : [], + SubscriptionPaused::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionPaused::class] : [], + SubscriptionRevoked::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionRevoked::class] : [], + SubscriptionExpired::class => class_exists(\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class) ? [\Modules\Admin\Listeners\Subscription\GoogleSubscriptionExpired::class] : [], ], /* diff --git a/routes/api.php b/routes/api.php index 0806d44c6ac5..1ce3e7136379 100644 --- a/routes/api.php +++ b/routes/api.php @@ -142,6 +142,9 @@ Route::group(['middleware' => ['throttle:api', 'api_db', 'token_auth', 'locale'] Route::post('charts/totals', [ChartController::class, 'totals'])->name('chart.totals'); Route::post('charts/chart_summary', [ChartController::class, 'chart_summary'])->name('chart.chart_summary'); + Route::post('charts/totals_v2', [ChartController::class, 'totalsV2'])->name('chart.totals_v2'); + Route::post('charts/chart_summary_v2', [ChartController::class, 'chart_summaryV2'])->name('chart.chart_summary_v2'); + Route::post('claim_license', [LicenseController::class, 'index'])->name('license.index'); Route::resource('clients', ClientController::class); // name = (clients. index / create / show / update / destroy / edit From 0de255216a1767ab9c2cdf9c75ec9bbb37a14bc3 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Mon, 22 May 2023 07:35:09 +1000 Subject: [PATCH 17/17] v5.5.119 --- VERSION.txt | 2 +- config/ninja.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index fec0973fe321..ec9ff787c070 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.5.118 \ No newline at end of file +5.5.119 \ No newline at end of file diff --git a/config/ninja.php b/config/ninja.php index 420f57681116..c0a09c9c87d9 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -15,8 +15,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.5.118', - 'app_tag' => '5.5.118', + 'app_version' => '5.5.119', + 'app_tag' => '5.5.119', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''),