From ea06b60294a213e7ec7081fbc2ce5eb24247b61c Mon Sep 17 00:00:00 2001 From: Hillel Coren Date: Wed, 31 Jan 2018 11:10:15 +0200 Subject: [PATCH] Working on proposals --- .../ProposalCategoryController.php | 123 +++++++++++++++++ app/Http/Controllers/ProposalController.php | 20 --- .../Controllers/ProposalSnippetController.php | 124 ++++++++++++++++++ .../ProposalTemplateController.php | 124 ++++++++++++++++++ app/Http/Requests/ProposalCategoryRequest.php | 8 ++ app/Libraries/Utils.php | 2 + .../ProposalCategoryRepository.php | 76 +++++++++++ app/Ninja/Repositories/ProposalRepository.php | 76 +++++++++++ .../ProposalSnippetRepository.php | 76 +++++++++++ .../ProposalTemplateRepository.php | 76 +++++++++++ app/Services/ProposalCategoryService.php | 71 ++++++++++ app/Services/ProposalService.php | 71 ++++++++++ app/Services/ProposalSnippetService.php | 71 ++++++++++ app/Services/ProposalTemplateService.php | 71 ++++++++++ ...8_01_10_073825_add_subscription_format.php | 9 +- resources/lang/en/texts.php | 55 ++++++++ resources/views/list.blade.php | 35 ++++- routes/web.php | 6 +- 18 files changed, 1066 insertions(+), 28 deletions(-) create mode 100644 app/Http/Controllers/ProposalCategoryController.php create mode 100644 app/Http/Controllers/ProposalSnippetController.php create mode 100644 app/Http/Controllers/ProposalTemplateController.php create mode 100644 app/Http/Requests/ProposalCategoryRequest.php create mode 100644 app/Ninja/Repositories/ProposalCategoryRepository.php create mode 100644 app/Ninja/Repositories/ProposalRepository.php create mode 100644 app/Ninja/Repositories/ProposalSnippetRepository.php create mode 100644 app/Ninja/Repositories/ProposalTemplateRepository.php create mode 100644 app/Services/ProposalCategoryService.php create mode 100644 app/Services/ProposalService.php create mode 100644 app/Services/ProposalSnippetService.php create mode 100644 app/Services/ProposalTemplateService.php diff --git a/app/Http/Controllers/ProposalCategoryController.php b/app/Http/Controllers/ProposalCategoryController.php new file mode 100644 index 0000000000..556b12c47e --- /dev/null +++ b/app/Http/Controllers/ProposalCategoryController.php @@ -0,0 +1,123 @@ +proposalCategoryRepo = $proposalCategoryRepo; + $this->proposalCategoryService = $proposalCategoryService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_CATEGORY, + 'datatable' => new ProposalCategoryDatatable(), + 'title' => trans('texts.proposal_categories'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalCategoryService->getDatatable($search, $userId); + } + + public function create(ProposalCategoryRequest $request) + { + $data = [ + 'account' => auth()->user()->account, + 'proposalCategory' => null, + 'method' => 'POST', + 'url' => 'proposal_categories', + 'title' => trans('texts.new_proposal_category'), + 'quotes' => Invoice::scope()->with('client.contacts')->quotes()->orderBy('id')->get(), + 'templates' => ProposalCategory::scope()->orderBy('name')->get(), + 'quotePublicId' => $request->quote_id, + ]; + + return View::make('proposal_categories.edit', $data); + } + + public function edit(ProposalCategoryRequest $request) + { + $proposalCategory = $request->entity(); + + $data = [ + 'account' => auth()->user()->account, + 'proposalCategory' => $proposalCategory, + 'method' => 'PUT', + 'url' => 'proposal_categories/' . $proposalCategory->public_id, + 'title' => trans('texts.edit_proposal_category'), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), + 'clientPublicId' => $proposalCategory->client ? $proposalCategory->client->public_id : null, + ]; + + return View::make('proposal_categories.edit', $data); + } + + public function store(CreateProposalCategoryRequest $request) + { + $proposalCategory = $this->proposalCategoryService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_category')); + + return redirect()->to($proposalCategory->getRoute()); + } + + public function update(UpdateProposalCategoryRequest $request) + { + $proposalCategory = $this->proposalCategoryService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_category')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalCategory->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalCategoryService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_category" : "{$action}d_proposal_categories"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposal_categories'); + } +} diff --git a/app/Http/Controllers/ProposalController.php b/app/Http/Controllers/ProposalController.php index cc76d4b9a6..9ead6fdf6f 100644 --- a/app/Http/Controllers/ProposalController.php +++ b/app/Http/Controllers/ProposalController.php @@ -2,7 +2,6 @@ namespace App\Http\Controllers; -use App\Jobs\GenerateProposalChartData; use App\Http\Requests\CreateProposalRequest; use App\Http\Requests\ProposalRequest; use App\Http\Requests\UpdateProposalRequest; @@ -23,13 +22,11 @@ class ProposalController extends BaseController protected $proposalService; protected $entityType = ENTITY_PROPOSAL; - /* public function __construct(ProposalRepository $proposalRepo, ProposalService $proposalService) { $this->proposalRepo = $proposalRepo; $this->proposalService = $proposalService; } - */ /** * Display a listing of the resource. @@ -53,23 +50,6 @@ class ProposalController extends BaseController return $this->proposalService->getDatatable($search, $userId); } - /* - public function show(ProposalRequest $request) - { - $account = auth()->user()->account; - $proposal = $request->entity(); - - $data = [ - 'account' => auth()->user()->account, - 'proposal' => $proposal, - 'title' => trans('texts.view_proposal'), - 'showBreadcrumbs' => false, - ]; - - return View::make('proposals.show', $data); - } - */ - public function create(ProposalRequest $request) { $data = [ diff --git a/app/Http/Controllers/ProposalSnippetController.php b/app/Http/Controllers/ProposalSnippetController.php new file mode 100644 index 0000000000..c61547928c --- /dev/null +++ b/app/Http/Controllers/ProposalSnippetController.php @@ -0,0 +1,124 @@ +proposalSnippetRepo = $proposalSnippetRepo; + $this->proposalSnippetService = $proposalSnippetService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_SNIPPET, + 'datatable' => new ProposalSnippetDatatable(), + 'title' => trans('texts.proposal_snippets'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalSnippetService->getDatatable($search, $userId); + } + + public function create(ProposalSnippetRequest $request) + { + $data = [ + 'account' => auth()->user()->account, + 'proposalSnippet' => null, + 'method' => 'POST', + 'url' => 'proposal_snippets', + 'title' => trans('texts.new_proposal_snippet'), + 'quotes' => Invoice::scope()->with('client.contacts')->quotes()->orderBy('id')->get(), + 'templates' => ProposalSnippetTemplate::scope()->orderBy('name')->get(), + 'quotePublicId' => $request->quote_id, + ]; + + return View::make('proposal_snippets.edit', $data); + } + + public function edit(ProposalSnippetRequest $request) + { + $proposalSnippet = $request->entity(); + + $data = [ + 'account' => auth()->user()->account, + 'proposalSnippet' => $proposalSnippet, + 'method' => 'PUT', + 'url' => 'proposal_snippets/' . $proposalSnippet->public_id, + 'title' => trans('texts.edit_proposal_snippet'), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), + 'clientPublicId' => $proposalSnippet->client ? $proposalSnippet->client->public_id : null, + ]; + + return View::make('proposal_snippets.edit', $data); + } + + public function store(CreateProposalSnippetRequest $request) + { + $proposalSnippet = $this->proposalSnippetService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_snippet')); + + return redirect()->to($proposalSnippet->getRoute()); + } + + public function update(UpdateProposalSnippetRequest $request) + { + $proposalSnippet = $this->proposalSnippetService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_snippet')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalSnippet->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalSnippetService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_snippet" : "{$action}d_proposal_snippets"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposal_snippets'); + } +} diff --git a/app/Http/Controllers/ProposalTemplateController.php b/app/Http/Controllers/ProposalTemplateController.php new file mode 100644 index 0000000000..c7b792c57f --- /dev/null +++ b/app/Http/Controllers/ProposalTemplateController.php @@ -0,0 +1,124 @@ +proposalTemplateRepo = $proposalTemplateRepo; + $this->proposalTemplateService = $proposalTemplateService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_TEMPLATE, + 'datatable' => new ProposalTemplateDatatable(), + 'title' => trans('texts.proposal_templates'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalTemplateService->getDatatable($search, $userId); + } + + public function create(ProposalTemplateRequest $request) + { + $data = [ + 'account' => auth()->user()->account, + 'proposalTemplate' => null, + 'method' => 'POST', + 'url' => 'proposal_templates', + 'title' => trans('texts.new_proposal_template'), + 'quotes' => Invoice::scope()->with('client.contacts')->quotes()->orderBy('id')->get(), + 'templates' => ProposalTemplateTemplate::scope()->orderBy('name')->get(), + 'quotePublicId' => $request->quote_id, + ]; + + return View::make('proposal_templates.edit', $data); + } + + public function edit(ProposalTemplateRequest $request) + { + $proposalTemplate = $request->entity(); + + $data = [ + 'account' => auth()->user()->account, + 'proposalTemplate' => $proposalTemplate, + 'method' => 'PUT', + 'url' => 'proposal_templates/' . $proposalTemplate->public_id, + 'title' => trans('texts.edit_proposal_template'), + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), + 'clientPublicId' => $proposalTemplate->client ? $proposalTemplate->client->public_id : null, + ]; + + return View::make('proposal_templates.edit', $data); + } + + public function store(CreateProposalTemplateRequest $request) + { + $proposalTemplate = $this->proposalTemplateService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_template')); + + return redirect()->to($proposalTemplate->getRoute()); + } + + public function update(UpdateProposalTemplateRequest $request) + { + $proposalTemplate = $this->proposalTemplateService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_template')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalTemplate->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalTemplateService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_template" : "{$action}d_proposal_templates"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposal_templates'); + } +} diff --git a/app/Http/Requests/ProposalCategoryRequest.php b/app/Http/Requests/ProposalCategoryRequest.php new file mode 100644 index 0000000000..debc35c5c4 --- /dev/null +++ b/app/Http/Requests/ProposalCategoryRequest.php @@ -0,0 +1,8 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_categories') + ->where('proposal_categories.account_id', '=', Auth::user()->account_id) + ->leftjoin('invoices', 'invoices.id', '=', 'proposal_categories.quote_id') + ->leftjoin('clients', 'clients.id', '=', 'invoices.client_id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select( + 'proposal_categories.name as proposal', + 'proposal_categories.public_id', + 'proposal_categories.user_id', + 'proposal_categories.deleted_at', + 'proposal_categories.is_deleted', + 'proposal_categories.private_notes', + DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"), + 'clients.user_id as client_user_id', + 'clients.public_id as client_public_id' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_CATEGORY); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('proposal_categories.name', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposal_categories.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalCategory::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/ProposalRepository.php b/app/Ninja/Repositories/ProposalRepository.php new file mode 100644 index 0000000000..00c2fbe9eb --- /dev/null +++ b/app/Ninja/Repositories/ProposalRepository.php @@ -0,0 +1,76 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposals') + ->where('proposals.account_id', '=', Auth::user()->account_id) + ->leftjoin('invoices', 'invoices.id', '=', 'proposals.quote_id') + ->leftjoin('clients', 'clients.id', '=', 'invoices.client_id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select( + 'proposals.public_id', + 'proposals.user_id', + 'proposals.deleted_at', + 'proposals.is_deleted', + 'proposals.private_notes', + DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"), + 'clients.user_id as client_user_id', + 'clients.public_id as client_public_id', + 'invoices.invoice_number as quote' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposals.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = Proposal::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/ProposalSnippetRepository.php b/app/Ninja/Repositories/ProposalSnippetRepository.php new file mode 100644 index 0000000000..e6b293a4a9 --- /dev/null +++ b/app/Ninja/Repositories/ProposalSnippetRepository.php @@ -0,0 +1,76 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_snippets') + ->where('proposal_snippets.account_id', '=', Auth::user()->account_id) + ->leftjoin('invoices', 'invoices.id', '=', 'proposal_snippets.quote_id') + ->leftjoin('clients', 'clients.id', '=', 'invoices.client_id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select( + 'proposal_snippets.name as proposal', + 'proposal_snippets.public_id', + 'proposal_snippets.user_id', + 'proposal_snippets.deleted_at', + 'proposal_snippets.is_deleted', + 'proposal_snippets.private_notes', + DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"), + 'clients.user_id as client_user_id', + 'clients.public_id as client_public_id' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_SNIPPET); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('proposal_snippets.name', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposal_snippets.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalSnippet::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/ProposalTemplateRepository.php b/app/Ninja/Repositories/ProposalTemplateRepository.php new file mode 100644 index 0000000000..450d72f55f --- /dev/null +++ b/app/Ninja/Repositories/ProposalTemplateRepository.php @@ -0,0 +1,76 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_templates') + ->where('proposal_templates.account_id', '=', Auth::user()->account_id) + ->leftjoin('invoices', 'invoices.id', '=', 'proposal_templates.quote_id') + ->leftjoin('clients', 'clients.id', '=', 'invoices.client_id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select( + 'proposal_templates.name as proposal', + 'proposal_templates.public_id', + 'proposal_templates.user_id', + 'proposal_templates.deleted_at', + 'proposal_templates.is_deleted', + 'proposal_templates.private_notes', + DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"), + 'clients.user_id as client_user_id', + 'clients.public_id as client_public_id' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_TEMPLATE); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('proposal_templates.name', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposal_templates.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalTemplate::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Services/ProposalCategoryService.php b/app/Services/ProposalCategoryService.php new file mode 100644 index 0000000000..5fff796958 --- /dev/null +++ b/app/Services/ProposalCategoryService.php @@ -0,0 +1,71 @@ +proposalCategoryRepo = $proposalCategoryRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalCategoryRepo; + } + + /** + * @param $data + * @param mixed $proposalCategory + * + * @return mixed|null + */ + public function save($data, $proposalCategory = false) + { + return $this->proposalCategoryRepo->save($data, $proposalCategory); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalCategoryDatatable(); + + $query = $this->proposalCategoryRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalService.php b/app/Services/ProposalService.php new file mode 100644 index 0000000000..eb7542738f --- /dev/null +++ b/app/Services/ProposalService.php @@ -0,0 +1,71 @@ +proposalRepo = $proposalRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalRepo; + } + + /** + * @param $data + * @param mixed $proposal + * + * @return mixed|null + */ + public function save($data, $proposal = false) + { + return $this->proposalRepo->save($data, $proposal); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalDatatable(); + + $query = $this->proposalRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalSnippetService.php b/app/Services/ProposalSnippetService.php new file mode 100644 index 0000000000..981ac8c341 --- /dev/null +++ b/app/Services/ProposalSnippetService.php @@ -0,0 +1,71 @@ +proposalSnippetRepo = $proposalSnippetRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalSnippetRepo; + } + + /** + * @param $data + * @param mixed $proposalSnippet + * + * @return mixed|null + */ + public function save($data, $proposalSnippet = false) + { + return $this->proposalSnippetRepo->save($data, $proposalSnippet); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalSnippetDatatable(); + + $query = $this->proposalSnippetRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalTemplateService.php b/app/Services/ProposalTemplateService.php new file mode 100644 index 0000000000..c367051b0e --- /dev/null +++ b/app/Services/ProposalTemplateService.php @@ -0,0 +1,71 @@ +proposalTemplateRepo = $proposalTemplateRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalTemplateRepo; + } + + /** + * @param $data + * @param mixed $proposalTemplate + * + * @return mixed|null + */ + public function save($data, $proposalTemplate = false) + { + return $this->proposalTemplateRepo->save($data, $proposalTemplate); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalTemplateDatatable(); + + $query = $this->proposalTemplateRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/database/migrations/2018_01_10_073825_add_subscription_format.php b/database/migrations/2018_01_10_073825_add_subscription_format.php index 7f1bc5bfd3..8b48211c7b 100644 --- a/database/migrations/2018_01_10_073825_add_subscription_format.php +++ b/database/migrations/2018_01_10_073825_add_subscription_format.php @@ -27,6 +27,7 @@ class AddSubscriptionFormat extends Migration $table->unsignedInteger('user_id'); $table->timestamps(); $table->softDeletes(); + $table->boolean('is_deleted')->default(false); $table->string('name'); @@ -43,10 +44,12 @@ class AddSubscriptionFormat extends Migration $table->unsignedInteger('user_id'); $table->timestamps(); $table->softDeletes(); + $table->boolean('is_deleted')->default(false); $table->unsignedInteger('proposal_category_id'); $table->string('name'); - + $table->text('private_notes'); + $table->mediumText('html'); $table->mediumText('css'); @@ -63,6 +66,8 @@ class AddSubscriptionFormat extends Migration $table->unsignedInteger('user_id'); $table->timestamps(); $table->softDeletes(); + $table->boolean('is_deleted')->default(false); + $table->text('private_notes'); $table->string('name'); $table->text('tags'); @@ -82,9 +87,11 @@ class AddSubscriptionFormat extends Migration $table->unsignedInteger('user_id'); $table->timestamps(); $table->softDeletes(); + $table->boolean('is_deleted')->default(false); $table->unsignedInteger('quote_id')->index(); $table->unsignedInteger('temlate_id')->index(); + $table->text('private_notes'); $table->mediumText('html'); $table->mediumText('css'); diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php index 52cb8c279e..ffe3f03c97 100644 --- a/resources/lang/en/texts.php +++ b/resources/lang/en/texts.php @@ -2659,8 +2659,63 @@ $LANG = array( 'tax_amount' => 'Tax Amount', 'tax_paid' => 'Tax Paid', 'none' => 'None', + + 'proposal' => 'Proposal', 'proposals' => 'Proposals', 'new_proposal' => 'New Proposal', + 'edit_proposal' => 'Edit Proposal', + 'archive_proposal' => 'Archive Proposal', + 'delete_proposal' => 'Delete Proposal', + 'restored_proposal' => 'Restore Proposal', + 'created_proposal' => 'Successfully created proposal', + 'updated_proposal' => 'Successfully updated proposal', + 'archived_proposal' => 'Successfully archived proposal', + 'deleted_proposal' => 'Successfully archived proposal', + 'archived_proposals' => 'Successfully archived :count proposals', + 'deleted_proposals' => 'Successfully archived :count proposals', + 'restored_proposal' => 'Successfully restored proposal', + 'proposal_snippet' => 'Snippet', + 'proposal_snippets' => 'Snippets', + 'new_proposal_snippet' => 'New Snippet', + 'edit_proposal_snippet' => 'Edit Snippet', + 'archive_proposal_snippet' => 'Archive Snippet', + 'delete_proposal_snippet' => 'Delete Snippet', + 'restored_proposal_snippet' => 'Restore Snippet', + 'created_proposal_snippet' => 'Successfully created snippet', + 'updated_proposal_snippet' => 'Successfully updated snippet', + 'archived_proposal_snippet' => 'Successfully archived snippet', + 'deleted_proposal_snippet' => 'Successfully archived snippet', + 'archived_proposal_snippets' => 'Successfully archived :count snippets', + 'deleted_proposal_snippets' => 'Successfully archived :count snippets', + 'restored_proposal_snippet' => 'Successfully restored snippet', + 'proposal_template' => 'Template', + 'proposal_templates' => 'Templates', + 'new_proposal_template' => 'New Template', + 'edit_proposal_template' => 'Edit Template', + 'archive_proposal_template' => 'Archive Template', + 'delete_proposal_template' => 'Delete Template', + 'restored_proposal_template' => 'Restore Template', + 'created_proposal_template' => 'Successfully created temlate', + 'updated_proposal_template' => 'Successfully updated temlate', + 'archived_proposal_template' => 'Successfully archived temlate', + 'deleted_proposal_template' => 'Successfully archived temlate', + 'archived_proposal_templates' => 'Successfully archived :count temlates', + 'deleted_proposal_templates' => 'Successfully archived :count temlates', + 'restored_proposal_template' => 'Successfully restored temlate', + 'proposal_category' => 'Proposal Category', + 'proposal_categories' => 'Proposal Categories', + 'new_proposal_category' => 'New Category', + 'edit_proposal_category' => 'Edit Category', + 'archive_proposal_category' => 'Archive Category', + 'delete_proposal_category' => 'Delete Category', + 'restored_proposal_category' => 'Restore Category', + 'created_proposal_category' => 'Successfully created category', + 'updated_proposal_category' => 'Successfully updated category', + 'archived_proposal_category' => 'Successfully archived category', + 'deleted_proposal_category' => 'Successfully archived category', + 'archived_proposal_categories' => 'Successfully archived :count categories', + 'deleted_proposal_categories' => 'Successfully archived :count categories', + 'restored_proposal_category' => 'Successfully restored category', ); diff --git a/resources/views/list.blade.php b/resources/views/list.blade.php index d67e36effd..9c9fd12a21 100644 --- a/resources/views/list.blade.php +++ b/resources/views/list.blade.php @@ -46,17 +46,40 @@ - @if (false && $entityType == ENTITY_INVOICE && auth()->user()->account->isModuleEnabled(ENTITY_RECURRING_INVOICE)) - {!! DropdownButton::normal(trans('texts.recurring')) - ->withAttributes(['class'=>'recurringDropdown']) + @if ($entityType == ENTITY_PROPOSAL) + {!! DropdownButton::normal(trans('texts.templates')) + ->withAttributes(['class'=>'templatesDropdown']) ->withContents([ - ['label' => trans('texts.new_recurring_invoice'), 'url' => url('/recurring_invoices/create')], + ['label' => trans('texts.new_template'), 'url' => url('/proposal_templates/create')], + ] + )->split() !!} + {!! DropdownButton::normal(trans('texts.snippets')) + ->withAttributes(['class'=>'snippetsDropdown']) + ->withContents([ + ['label' => trans('texts.new_snippet'), 'url' => url('/proposal_snippets/create')], + ] + )->split() !!} + + @elseif ($entityType == ENTITY_PROPOSAL_SNIPPET) + {!! DropdownButton::normal(trans('texts.categories')) + ->withAttributes(['class'=>'categoriesDropdown']) + ->withContents([ + ['label' => trans('texts.new_category'), 'url' => url('/proposal_categories/create')], ] )->split() !!} diff --git a/routes/web.php b/routes/web.php index d2314ba2dc..cc0aeabdf3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -207,15 +207,19 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () { Route::get('proposals/create/{quote_id?}', 'ProposalController@create'); Route::resource('proposals', 'ProposalController'); + Route::get('api/proposals', 'ProposalController@getDatatable'); Route::get('proposal_templates/create', 'ProposalTemplateController@create'); Route::resource('proposal_templates', 'ProposalTemplateController'); + Route::get('api/proposal_templates', 'ProposalTemplateController@getDatatable'); Route::get('proposal_snippets/create', 'ProposalSnippetController@create'); Route::resource('proposal_snippets', 'ProposalSnippetController'); + Route::get('api/proposal_snippets', 'ProposalSnippetController@getDatatable'); Route::get('proposal_categories/create', 'ProposalCategoryController@create'); - Route::resource('proposal_categories', 'ProposalController'); + Route::resource('proposal_categories', 'ProposalCategoryController'); + Route::get('api/proposal_categories', 'ProposalCategoryController@getDatatable'); Route::resource('payments', 'PaymentController'); Route::get('payments/create/{client_id?}/{invoice_id?}', 'PaymentController@create');