From 3e5e915acc934df96f0c33149f57a17b76c7f847 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 6 Jul 2022 15:18:41 +1000 Subject: [PATCH] Uploads for purchase orders --- app/DataMapper/CompanySettings.php | 3 + .../Controllers/PurchaseOrderController.php | 69 +++++++++++++++++++ .../VendorPortal/UploadController.php | 41 +++++++++++ .../Uploads/StoreUploadRequest.php | 10 +++ .../UploadPurchaseOrderRequest.php | 39 +++++++++++ .../Uploads/StoreUploadRequest.php | 55 +++++++++++++++ app/Transformers/PurchaseOrderTransformer.php | 10 +++ .../purchase_orders/includes/upload.blade.php | 20 ++++++ .../ninja2020/purchase_orders/show.blade.php | 5 ++ .../ninja2020/vendor_profile/edit.blade.php | 10 ++- routes/api.php | 2 + routes/vendor.php | 2 + 12 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/VendorPortal/UploadController.php create mode 100644 app/Http/Requests/PurchaseOrder/UploadPurchaseOrderRequest.php create mode 100644 app/Http/Requests/VendorPortal/Uploads/StoreUploadRequest.php create mode 100644 resources/views/portal/ninja2020/purchase_orders/includes/upload.blade.php diff --git a/app/DataMapper/CompanySettings.php b/app/DataMapper/CompanySettings.php index 241751974daf..758c494e15c8 100644 --- a/app/DataMapper/CompanySettings.php +++ b/app/DataMapper/CompanySettings.php @@ -291,7 +291,10 @@ class CompanySettings extends BaseSettings public $email_from_name = ''; public $auto_archive_invoice_cancelled = false; + public $vendor_portal_enable_uploads=false; + public static $casts = [ + 'vendor_portal_enable_uploads' => 'bool', 'besr_id' => 'string', 'qr_iban' => 'string', 'email_subject_purchase_order' => 'string', diff --git a/app/Http/Controllers/PurchaseOrderController.php b/app/Http/Controllers/PurchaseOrderController.php index 77027d0789db..e7ec463ab6c2 100644 --- a/app/Http/Controllers/PurchaseOrderController.php +++ b/app/Http/Controllers/PurchaseOrderController.php @@ -23,21 +23,25 @@ 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\Http\Requests\PurchaseOrder\UploadPurchaseOrderRequest; use App\Jobs\Invoice\ZipInvoices; use App\Jobs\PurchaseOrder\PurchaseOrderEmail; use App\Jobs\PurchaseOrder\ZipPurchaseOrders; +use App\Models\Account; use App\Models\Client; use App\Models\PurchaseOrder; use App\Repositories\PurchaseOrderRepository; use App\Transformers\PurchaseOrderTransformer; use App\Utils\Ninja; use App\Utils\Traits\MakesHash; +use App\Utils\Traits\SavesDocuments; use Illuminate\Http\Response; use Illuminate\Support\Facades\Storage; class PurchaseOrderController extends BaseController { use MakesHash; + use SavesDocuments; protected $entity_type = PurchaseOrder::class; protected $entity_transformer = PurchaseOrderTransformer::class; @@ -655,4 +659,69 @@ class PurchaseOrderController extends BaseController break; } } + + /** + * Update the specified resource in storage. + * + * @param UploadPurchaseOrderRequest $request + * @param PurchaseOrder $purchase_order + * @return Response + * + * + * + * @OA\Put( + * path="/api/v1/purchase_orders/{id}/upload", + * operationId="uploadPurchaseOrder", + * tags={"purchase_orders"}, + * summary="Uploads a document to a purchase_orders", + * description="Handles the uploading of a document to a purchase_order", + * @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\Response( + * response=200, + * description="Returns the Purchase Order 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/Vendor"), + * ), + * @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 upload(UploadPurchaseOrderRequest $request, PurchaseOrder $purchase_order) + { + + if(!$this->checkFeature(Account::FEATURE_DOCUMENTS)) + return $this->featureFailure(); + + if ($request->has('documents')) + $this->saveDocuments($request->file('documents'), $purchase_order); + + return $this->itemResponse($purchase_order->fresh()); + + } + } diff --git a/app/Http/Controllers/VendorPortal/UploadController.php b/app/Http/Controllers/VendorPortal/UploadController.php new file mode 100644 index 000000000000..23f11e4827a2 --- /dev/null +++ b/app/Http/Controllers/VendorPortal/UploadController.php @@ -0,0 +1,41 @@ +saveDocuments($request->getFile(), $purchase_order, true); + + return response([], 200); + } +} diff --git a/app/Http/Requests/ClientPortal/Uploads/StoreUploadRequest.php b/app/Http/Requests/ClientPortal/Uploads/StoreUploadRequest.php index a106df59e9ab..27cce5800c2e 100644 --- a/app/Http/Requests/ClientPortal/Uploads/StoreUploadRequest.php +++ b/app/Http/Requests/ClientPortal/Uploads/StoreUploadRequest.php @@ -1,4 +1,14 @@ user()->can('edit', $this->purchase_order); + } + + public function rules() + { + + $rules = []; + + if($this->input('documents')) + $rules['documents'] = 'file|mimes:csv,png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:2000000'; + + return $rules; + + } +} diff --git a/app/Http/Requests/VendorPortal/Uploads/StoreUploadRequest.php b/app/Http/Requests/VendorPortal/Uploads/StoreUploadRequest.php new file mode 100644 index 000000000000..686e8dab6d09 --- /dev/null +++ b/app/Http/Requests/VendorPortal/Uploads/StoreUploadRequest.php @@ -0,0 +1,55 @@ +guard('vendor')->user()->vendor->company->getSetting('vendor_portal_enable_uploads'); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'file' => ['file', 'mimes:png,ai,jpeg,tiff,pdf,gif,psd,txt,doc,xls,ppt,xlsx,docx,pptx|max:20000'], + ]; + } + + /** + * Since saveDocuments() expects an array of uploaded files, + * we need to convert it to an array before uploading. + * + * @return mixed + */ + public function getFile() + { + if (gettype($this->file) !== 'array') { + return [$this->file]; + } + + return $this->file; + } +} diff --git a/app/Transformers/PurchaseOrderTransformer.php b/app/Transformers/PurchaseOrderTransformer.php index 0163714e6009..5364a534c24e 100644 --- a/app/Transformers/PurchaseOrderTransformer.php +++ b/app/Transformers/PurchaseOrderTransformer.php @@ -14,6 +14,7 @@ namespace App\Transformers; use App\Models\PurchaseOrder; use App\Models\PurchaseOrderInvitation; +use App\Transformers\DocumentTransformer; use App\Utils\Traits\MakesHash; class PurchaseOrderTransformer extends EntityTransformer @@ -22,6 +23,7 @@ class PurchaseOrderTransformer extends EntityTransformer protected $defaultIncludes = [ 'invitations', + 'documents' ]; public function includeInvitations(PurchaseOrder $purchase_order) @@ -31,6 +33,14 @@ class PurchaseOrderTransformer extends EntityTransformer return $this->includeCollection($purchase_order->invitations, $transformer, PurchaseOrderInvitation::class); } + + public function includeDocuments(PurchaseOrder $purchase_order) + { + $transformer = new DocumentTransformer($this->serializer); + + return $this->includeCollection($purchase_order->documents, $transformer, Document::class); + } + public function transform(PurchaseOrder $purchase_order) { return [ diff --git a/resources/views/portal/ninja2020/purchase_orders/includes/upload.blade.php b/resources/views/portal/ninja2020/purchase_orders/includes/upload.blade.php new file mode 100644 index 000000000000..3828defc83a7 --- /dev/null +++ b/resources/views/portal/ninja2020/purchase_orders/includes/upload.blade.php @@ -0,0 +1,20 @@ + + + +{{-- TODO: HOSTED --}} +
+ {{ ctrans('texts.allowed_file_types' )}} png, ai, svg, jpeg, tiff, pdf, gif, psd, txt, doc, xls, ppt, xlsx, docx, pptx +
+ @csrf +
+ + +
+
+
+ + \ No newline at end of file diff --git a/resources/views/portal/ninja2020/purchase_orders/show.blade.php b/resources/views/portal/ninja2020/purchase_orders/show.blade.php index 50f5cc77a4fe..ec4d83f9e178 100644 --- a/resources/views/portal/ninja2020/purchase_orders/show.blade.php +++ b/resources/views/portal/ninja2020/purchase_orders/show.blade.php @@ -12,11 +12,16 @@ @section('body') + @if($purchase_order->company->getSetting('vendor_portal_enable_uploads') || true) + @component('portal.ninja2020.purchase_orders.includes.upload', ['purchase_order' => $purchase_order]) @endcomponent + @endif + @if(in_array($purchase_order->status_id, [\App\Models\PurchaseOrder::STATUS_SENT, \App\Models\PurchaseOrder::STATUS_DRAFT]))
@include('portal.ninja2020.purchase_orders.includes.actions', ['purchase_order' => $purchase_order])
@else +
diff --git a/resources/views/portal/ninja2020/vendor_profile/edit.blade.php b/resources/views/portal/ninja2020/vendor_profile/edit.blade.php index f7fb6a6d1289..c7cb866f0031 100644 --- a/resources/views/portal/ninja2020/vendor_profile/edit.blade.php +++ b/resources/views/portal/ninja2020/vendor_profile/edit.blade.php @@ -83,7 +83,6 @@ @enderror
-
@@ -163,6 +162,15 @@ @enderror +
+ + + @error('public_notes') +
+ {{ $message }} +
+ @enderror +
diff --git a/routes/api.php b/routes/api.php index b605901d8f73..d83687a4ea9a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -212,6 +212,8 @@ Route::group(['middleware' => ['throttle:100,1', 'api_db', 'token_auth', 'locale Route::resource('purchase_orders', 'PurchaseOrderController'); Route::post('purchase_orders/bulk', 'PurchaseOrderController@bulk')->name('purchase_orders.bulk'); + Route::put('purchase_orders/{purchase_order}/upload', 'PurchaseOrderController@upload'); + Route::get('purchase_orders/{purchase_order}/{action}', 'PurchaseOrderController@action')->name('purchase_orders.action'); Route::get('users', 'UserController@index'); diff --git a/routes/vendor.php b/routes/vendor.php index f807deb1548d..b4b501391c33 100644 --- a/routes/vendor.php +++ b/routes/vendor.php @@ -12,6 +12,7 @@ use App\Http\Controllers\Auth\VendorContactLoginController; use App\Http\Controllers\VendorPortal\InvitationController; use App\Http\Controllers\VendorPortal\PurchaseOrderController; +use App\Http\Controllers\VendorPortal\UploadController; use App\Http\Controllers\VendorPortal\VendorContactController; use Illuminate\Support\Facades\Route; @@ -39,6 +40,7 @@ Route::group(['middleware' => ['auth:vendor', 'vendor_locale', 'domain_db'], 'pr Route::post('purchase_orders/bulk', [PurchaseOrderController::class, 'bulk'])->name('purchase_orders.bulk'); Route::get('logout', [VendorContactLoginController::class, 'logout'])->name('logout'); + Route::post('purchase_order/upload/{purchase_order}', [UploadController::class,'upload'])->name('upload.store'); });