From 3da023c1a61cb5aa9e9b59ad8227120d6c26f7dd Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Thu, 8 Feb 2018 13:41:22 +0200 Subject: [PATCH] Proposals --- .../ProposalTemplateController.php | 27 +++++++++++++++---- .../CreateProposalCategoryRequest.php | 2 +- .../Requests/CreateProposalSnippetRequest.php | 2 +- .../CreateProposalTemplateRequest.php | 2 +- .../UpdateProposalCategoryRequest.php | 2 +- .../Requests/UpdateProposalSnippetRequest.php | 2 +- .../UpdateProposalTemplateRequest.php | 2 +- app/Libraries/HistoryUtils.php | 4 +++ app/Models/Proposal.php | 6 ++++- app/Ninja/Datatables/ExpenseDatatable.php | 2 +- app/Ninja/Datatables/InvoiceDatatable.php | 4 +-- .../Datatables/ProposalTemplateDatatable.php | 9 +++++++ app/Ninja/Presenters/ProposalPresenter.php | 13 +++++++++ resources/lang/en/texts.php | 1 + routes/web.php | 1 + 15 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 app/Ninja/Presenters/ProposalPresenter.php diff --git a/app/Http/Controllers/ProposalTemplateController.php b/app/Http/Controllers/ProposalTemplateController.php index 89d0c40587..2b7569eee1 100644 --- a/app/Http/Controllers/ProposalTemplateController.php +++ b/app/Http/Controllers/ProposalTemplateController.php @@ -70,15 +70,27 @@ class ProposalTemplateController extends BaseController return redirect("proposals/templates/$publicId/edit"); } - public function edit(ProposalTemplateRequest $request) + public function edit(ProposalTemplateRequest $request, $publicId = false, $clone = false) { - $proposalTemplate = $request->entity(); + $template = $request->entity(); + + if ($clone) { + $template->id = null; + $template->public_id = null; + $template->name = ''; + $template->private_notes = ''; + $method = 'POST'; + $url = 'proposals/templates'; + } else { + $method = 'PUT'; + $url = 'proposals/templates/' . $template->public_id; + } $data = [ 'account' => auth()->user()->account, - 'template' => $proposalTemplate, - 'method' => 'PUT', - 'url' => 'proposals/templates/' . $proposalTemplate->public_id, + 'template' => $template, + 'method' => $method, + 'url' => $url, 'title' => trans('texts.edit_proposal_template'), 'templates' => ProposalTemplate::scope()->orderBy('name')->get(), ]; @@ -86,6 +98,11 @@ class ProposalTemplateController extends BaseController return View::make('proposals/templates/edit', $data); } + public function cloneProposal(ProposalTemplateRequest $request, $publicId) + { + return self::edit($request, $publicId, true); + } + public function store(CreateProposalTemplateRequest $request) { $proposalTemplate = $this->proposalTemplateService->save($request->input()); diff --git a/app/Http/Requests/CreateProposalCategoryRequest.php b/app/Http/Requests/CreateProposalCategoryRequest.php index 7b55b446e1..3a11ddd73e 100644 --- a/app/Http/Requests/CreateProposalCategoryRequest.php +++ b/app/Http/Requests/CreateProposalCategoryRequest.php @@ -22,7 +22,7 @@ class CreateProposalCategoryRequest extends ProposalCategoryRequest public function rules() { return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_categories,name,,id,account_id,%s', $this->user()->account_id), ]; } } diff --git a/app/Http/Requests/CreateProposalSnippetRequest.php b/app/Http/Requests/CreateProposalSnippetRequest.php index 616cbb0130..b54d976e08 100644 --- a/app/Http/Requests/CreateProposalSnippetRequest.php +++ b/app/Http/Requests/CreateProposalSnippetRequest.php @@ -22,7 +22,7 @@ class CreateProposalSnippetRequest extends ProposalSnippetRequest public function rules() { return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_snippets,name,,id,account_id,%s', $this->user()->account_id), ]; } } diff --git a/app/Http/Requests/CreateProposalTemplateRequest.php b/app/Http/Requests/CreateProposalTemplateRequest.php index 8e8009709c..faebe4a157 100644 --- a/app/Http/Requests/CreateProposalTemplateRequest.php +++ b/app/Http/Requests/CreateProposalTemplateRequest.php @@ -22,7 +22,7 @@ class CreateProposalTemplateRequest extends ProposalTemplateRequest public function rules() { return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_templates,name,,id,account_id,%s', $this->user()->account_id), ]; } } diff --git a/app/Http/Requests/UpdateProposalCategoryRequest.php b/app/Http/Requests/UpdateProposalCategoryRequest.php index f2590045d1..274061fafe 100644 --- a/app/Http/Requests/UpdateProposalCategoryRequest.php +++ b/app/Http/Requests/UpdateProposalCategoryRequest.php @@ -26,7 +26,7 @@ class UpdateProposalCategoryRequest extends ProposalCategoryRequest } return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_categories,name,,id,account_id,%s', $this->user()->account_id), ]; } } diff --git a/app/Http/Requests/UpdateProposalSnippetRequest.php b/app/Http/Requests/UpdateProposalSnippetRequest.php index 5580db7c85..052d4e7a0b 100644 --- a/app/Http/Requests/UpdateProposalSnippetRequest.php +++ b/app/Http/Requests/UpdateProposalSnippetRequest.php @@ -26,7 +26,7 @@ class UpdateProposalSnippetRequest extends ProposalSnippetRequest } return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_snippets,name,%s,id,account_id,%s', $this->entity()->id, $this->user()->account_id), ]; } } diff --git a/app/Http/Requests/UpdateProposalTemplateRequest.php b/app/Http/Requests/UpdateProposalTemplateRequest.php index c7808b50d0..68cfde293e 100644 --- a/app/Http/Requests/UpdateProposalTemplateRequest.php +++ b/app/Http/Requests/UpdateProposalTemplateRequest.php @@ -26,7 +26,7 @@ class UpdateProposalTemplateRequest extends ProposalTemplateRequest } return [ - 'name' => 'required', + 'name' => sprintf('required|unique:proposal_templates,name,%s,id,account_id,%s', $this->entity()->id, $this->user()->account_id), ]; } } diff --git a/app/Libraries/HistoryUtils.php b/app/Libraries/HistoryUtils.php index 27f097ab96..bfce42ec7a 100644 --- a/app/Libraries/HistoryUtils.php +++ b/app/Libraries/HistoryUtils.php @@ -87,6 +87,7 @@ class HistoryUtils ENTITY_TASK, ENTITY_EXPENSE, ENTITY_PROJECT, + ENTITY_PROPOSAL, //ENTITY_RECURRING_EXPENSE, ]; @@ -142,6 +143,9 @@ class HistoryUtils } elseif (method_exists($entity, 'client') && $entity->client) { $object->client_id = $entity->client->public_id; $object->client_name = $entity->client->getDisplayName(); + } elseif (method_exists($entity, 'invoice') && $entity->invoice) { + $object->client_id = $entity->invoice->client->public_id; + $object->client_name = $entity->invoice->client->getDisplayName(); } else { $object->client_id = 0; $object->client_name = 0; diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php index 2b2b0f8928..ad8d4db5ee 100644 --- a/app/Models/Proposal.php +++ b/app/Models/Proposal.php @@ -17,6 +17,10 @@ class Proposal extends EntityModel * @var array */ protected $dates = ['deleted_at']; + /** + * @var string + */ + protected $presenter = 'App\Ninja\Presenters\ProposalPresenter'; /** * @var array @@ -82,7 +86,7 @@ class Proposal extends EntityModel public function getDisplayName() { - return 'TODO'; + return $this->invoice->invoice_number; } } diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php index 800bc56f7e..e489c89a71 100644 --- a/app/Ninja/Datatables/ExpenseDatatable.php +++ b/app/Ninja/Datatables/ExpenseDatatable.php @@ -115,7 +115,7 @@ class ExpenseDatatable extends EntityDatatable return URL::to("expenses/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_EXPENSE); + return Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); }, ], [ diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php index 5a59eda7b0..3cba7faf46 100644 --- a/app/Ninja/Datatables/InvoiceDatatable.php +++ b/app/Ninja/Datatables/InvoiceDatatable.php @@ -96,7 +96,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("invoices/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_INVOICE); + return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_INVOICE); }, ], [ @@ -105,7 +105,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("quotes/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_QUOTE); + return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_QUOTE); }, ], [ diff --git a/app/Ninja/Datatables/ProposalTemplateDatatable.php b/app/Ninja/Datatables/ProposalTemplateDatatable.php index 6597eaa3ac..b7564845e8 100644 --- a/app/Ninja/Datatables/ProposalTemplateDatatable.php +++ b/app/Ninja/Datatables/ProposalTemplateDatatable.php @@ -53,6 +53,15 @@ class ProposalTemplateDatatable extends EntityDatatable return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); }, ], + [ + trans('texts.clone_proposal_template'), + function ($model) { + return URL::to("proposals/templates/{$model->public_id}/clone"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); + }, + ], ]; } } diff --git a/app/Ninja/Presenters/ProposalPresenter.php b/app/Ninja/Presenters/ProposalPresenter.php new file mode 100644 index 0000000000..f2b43cf817 --- /dev/null +++ b/app/Ninja/Presenters/ProposalPresenter.php @@ -0,0 +1,13 @@ + 'Icon', 'proposal_not_found' => 'The requested proposal is not available', 'create_proposal_category' => 'Create category', + 'clone_proposal_template' => 'Clone Template', ); diff --git a/routes/web.php b/routes/web.php index 42d9090f6b..8798fe47db 100644 --- a/routes/web.php +++ b/routes/web.php @@ -218,6 +218,7 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () { Route::resource('proposals/snippets', 'ProposalSnippetController'); Route::get('api/proposal_snippets', 'ProposalSnippetController@getDatatable'); + Route::get('proposals/templates/{proposal_templates}/clone', 'ProposalTemplateController@cloneProposal'); Route::post('proposals/templates/bulk', 'ProposalTemplateController@bulk'); Route::get('proposals/templates/{proposal_templates}/edit', 'ProposalTemplateController@edit'); Route::get('proposals/templates/create', 'ProposalTemplateController@create');