diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 4eb8e06b2e67..bd202b8a9141 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -180,6 +180,8 @@ class CompanySettings extends BaseSettings public $email_subject_payment = ''; //@implemented public $email_subject_payment_partial = ''; //@implemented public $email_subject_statement = ''; //@implemented + public $email_subject_purchase_order = ''; //@implemented + public $email_template_purchase_order = ''; //@implemented public $email_template_invoice = ''; //@implemented public $email_template_credit = ''; //@implemented public $email_template_quote = ''; //@implemented diff --git a/app/Http/Controllers/PurchaseOrderController.php b/app/Http/Controllers/PurchaseOrderController.php index b07f068aec3b..60c8a33138c0 100644 --- a/app/Http/Controllers/PurchaseOrderController.php +++ b/app/Http/Controllers/PurchaseOrderController.php @@ -14,12 +14,14 @@ namespace App\Http\Controllers; use App\Factory\PurchaseOrderFactory; use App\Filters\PurchaseOrderFilters; +use App\Http\Requests\PurchaseOrder\ActionPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\CreatePurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\DestroyPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\EditPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\ShowPurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\StorePurchaseOrderRequest; use App\Http\Requests\PurchaseOrder\UpdatePurchaseOrderRequest; +use App\Jobs\Invoice\ZipInvoices; use App\Models\Client; use App\Models\PurchaseOrder; use App\Repositories\PurchaseOrderRepository; @@ -408,4 +410,221 @@ class PurchaseOrderController extends BaseController return $this->itemResponse($purchase_order->fresh()); } + + /** + * Perform bulk actions on the list view. + * + * @return Collection + * + * @OA\Post( + * path="/api/v1/purchase_orders/bulk", + * operationId="bulkPurchaseOrderss", + * tags={"purchase_orders"}, + * summary="Performs bulk actions on an array of purchase_orders", + * 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="Purchase Order 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 Bulk Action 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\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'); + + $ids = request()->input('ids'); + + $purchase_orders = PurchaseOrder::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()->get(); + + if (! $invoices) { + return response()->json(['message' => 'No Purchase Orders Found']); + } + + /* + * Download Purchase Order/s + */ + + if ($action == 'bulk_download' && $purchase_orders->count() > 1) { + $purchase_orders->each(function ($purchase_order) { + if (auth()->user()->cannot('view', $purchase_order)) { + nlog("access denied"); + return response()->json(['message' => ctrans('text.access_denied')]); + } + }); + + ZipInvoices::dispatch($purchase_orders, $purchase_orders->first()->company, auth()->user()); + + return response()->json(['message' => ctrans('texts.sent_message')], 200); + } + + /* + * Send the other actions to the switch + */ + $purchase_orders->each(function ($purchase_order, $key) use ($action) { + if (auth()->user()->can('edit', $purchase_order)) { + $this->performAction($purchase_order, $action, true); + } + }); + + /* Need to understand which permission are required for the given bulk action ie. view / edit */ + + return $this->listResponse(PurchaseOrder::withTrashed()->whereIn('id', $this->transformKeys($ids))->company()); + } + + /** + * @OA\Get( + * path="/api/v1/purchase_orders/{id}/{action}", + * operationId="actionPurchaseOrder", + * tags={"purchase_orders"}, + * summary="Performs a custom action on an purchase order", + * description="Performs a custom action on an purchase order. + * + * The current range of actions are as follows + * - mark_paid + * - download + * - archive + * - delete + * - email", + * @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\Parameter( + * name="id", + * in="path", + * description="The Purchase Order Hashed ID", + * example="D2J234DFA", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Parameter( + * name="action", + * in="path", + * description="The action string to be performed", + * example="clone_to_quote", + * required=true, + * @OA\Schema( + * type="string", + * format="string", + * ), + * ), + * @OA\Response( + * response=200, + * description="Returns the invoice 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/Invoice"), + * ), + * @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 ActionPurchaseOrderRequest $request + * @param PurchaseOrder $purchase_order + * @param $action + * @return \App\Http\Controllers\Response|\Illuminate\Http\JsonResponse|Response|mixed|\Symfony\Component\HttpFoundation\StreamedResponse + */ + public function action(ActionPurchaseOrderRequest $request, PurchaseOrder $purchase_order, $action) + { + return $this->performAction($invoice, $action); + } + + private function performAction(PurchaseOrder $purchase_order, $action, $bulk = false) + { + /*If we are using bulk actions, we don't want to return anything */ + switch ($action) { + case 'mark_sent': + $purchase_order->service()->markSent()->save(); + + if (! $bulk) { + return $this->itemResponse($purchase_order); + } + break; + case 'download': + + $file = $purchase_order->service()->getPurchaseOrderPdf(); + + return response()->streamDownload(function () use($file) { + echo Storage::get($file); + }, basename($file), ['Content-Type' => 'application/pdf']); + + break; + case 'restore': + $this->purchase_order_repository->restore($purchase_order); + + if (! $bulk) { + return $this->listResponse($purchase_order); + } + break; + case 'archive': + $this->purchase_order_repository->archive($purchase_order); + + if (! $bulk) { + return $this->listResponse($purchase_order); + } + break; + case 'delete': + + $this->purchase_order_repository->delete($purchase_order); + + if (! $bulk) { + return $this->listResponse($purchase_order); + } + break; + + case 'email': + //check query parameter for email_type and set the template else use calculateTemplate + + + default: + return response()->json(['message' => ctrans('texts.action_unavailable', ['action' => $action])], 400); + break; + } + } } diff --git a/app/Http/Requests/PurchaseOrder/ActionPurchaseOrderRequest.php b/app/Http/Requests/PurchaseOrder/ActionPurchaseOrderRequest.php new file mode 100644 index 000000000000..6768f171316d --- /dev/null +++ b/app/Http/Requests/PurchaseOrder/ActionPurchaseOrderRequest.php @@ -0,0 +1,61 @@ +user()->can('edit', $this->purchase_order); + } + + public function rules() + { + return [ + 'action' => 'required' + ]; + } + + protected function prepareForValidation() + { + $input = $this->all(); + + if($this->action){ + $input['action'] = $this->action; + } elseif (!array_key_exists('action', $input) ) { + $this->error_msg = 'Action is a required field'; + } + + $this->replace($input); + } + + public function messages() + { + return [ + 'action' => $this->error_msg, + ]; + } +} diff --git a/app/Jobs/Ninja/SystemMaintenance.php b/app/Jobs/Ninja/SystemMaintenance.php index b2221aad93a9..003dd172972d 100644 --- a/app/Jobs/Ninja/SystemMaintenance.php +++ b/app/Jobs/Ninja/SystemMaintenance.php @@ -49,8 +49,8 @@ class SystemMaintenance implements ShouldQueue nlog("Starting System Maintenance"); - // if(Ninja::isHosted()) - // return; + if(Ninja::isHosted()) + return; $delete_pdf_days = config('ninja.maintenance.delete_pdfs'); diff --git a/database/migrations/2022_06_01_224339_create_purchase_order_invitations_table.php b/database/migrations/2022_06_01_224339_create_purchase_order_invitations_table.php index 0412abb708ec..fc01d62b5a28 100644 --- a/database/migrations/2022_06_01_224339_create_purchase_order_invitations_table.php +++ b/database/migrations/2022_06_01_224339_create_purchase_order_invitations_table.php @@ -58,7 +58,8 @@ class CreatePurchaseOrderInvitationsTable extends Migration $settings->purchase_order_public_notes = ''; //@implemented $settings->purchase_order_number_pattern = ''; //@implemented $settings->purchase_order_number_counter = 1; //@implemented - + $settings->email_subject_purchase_order = ''; + $settings->email_template_purchase_order = ''; $company->settings = $settings; $company->save(); }); diff --git a/routes/api.php b/routes/api.php index b0fcc58d0045..4c4b07fab02e 100644 --- a/routes/api.php +++ b/routes/api.php @@ -207,6 +207,8 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale Route::put('vendors/{vendor}/upload', 'VendorController@upload'); Route::resource('purchase_orders', 'PurchaseOrderController'); + Route::post('purchase_orders/bulk', 'PurchaseOrderController@bulk')->name('purchase_orders.bulk'); + Route::get('purchase_orders/{purchase_order}/{action}', 'PurchaseOrderController@action')->name('purchase_orders.action'); Route::get('users', 'UserController@index'); Route::get('users/{user}', 'UserController@show')->middleware('password_protected');