1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 12:42:36 +01:00

Working on proposals

This commit is contained in:
Hillel Coren 2018-01-31 11:10:15 +02:00
parent 7c3cbc3a7e
commit ea06b60294
18 changed files with 1066 additions and 28 deletions

View File

@ -0,0 +1,123 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CreateProposalCategoryRequest;
use App\Http\Requests\ProposalCategoryRequest;
use App\Http\Requests\UpdateProposalCategoryRequest;
use App\Models\Invoice;
use App\Models\ProposalCategory;
use App\Ninja\Datatables\ProposalCategoryDatatable;
use App\Ninja\Repositories\ProposalCategoryRepository;
use App\Services\ProposalCategoryService;
use Auth;
use Input;
use Session;
use View;
class ProposalCategoryController extends BaseController
{
protected $proposalCategoryRepo;
protected $proposalCategoryService;
protected $entityType = ENTITY_PROPOSAL_CATEGORY;
public function __construct(ProposalCategoryRepository $proposalCategoryRepo, ProposalCategoryService $proposalCategoryService)
{
$this->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');
}
}

View File

@ -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 = [

View File

@ -0,0 +1,124 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CreateProposalSnippetRequest;
use App\Http\Requests\ProposalSnippetRequest;
use App\Http\Requests\UpdateProposalSnippetRequest;
use App\Models\Invoice;
use App\Models\ProposalSnippet;
use App\Models\ProposalSnippetTemplate;
use App\Ninja\Datatables\ProposalSnippetDatatable;
use App\Ninja\Repositories\ProposalSnippetRepository;
use App\Services\ProposalSnippetService;
use Auth;
use Input;
use Session;
use View;
class ProposalSnippetController extends BaseController
{
protected $proposalSnippetRepo;
protected $proposalSnippetService;
protected $entityType = ENTITY_PROPOSAL_SNIPPET;
public function __construct(ProposalSnippetRepository $proposalSnippetRepo, ProposalSnippetService $proposalSnippetService)
{
$this->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');
}
}

View File

@ -0,0 +1,124 @@
<?php
namespace App\Http\Controllers;
use App\Http\Requests\CreateProposalTemplateRequest;
use App\Http\Requests\ProposalTemplateRequest;
use App\Http\Requests\UpdateProposalTemplateRequest;
use App\Models\Invoice;
use App\Models\ProposalTemplate;
use App\Models\ProposalTemplateTemplate;
use App\Ninja\Datatables\ProposalTemplateDatatable;
use App\Ninja\Repositories\ProposalTemplateRepository;
use App\Services\ProposalTemplateService;
use Auth;
use Input;
use Session;
use View;
class ProposalTemplateController extends BaseController
{
protected $proposalTemplateRepo;
protected $proposalTemplateService;
protected $entityType = ENTITY_PROPOSAL_TEMPLATE;
public function __construct(ProposalTemplateRepository $proposalTemplateRepo, ProposalTemplateService $proposalTemplateService)
{
$this->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');
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Http\Requests;
class ProposalCategoryRequest extends EntityRequest
{
protected $entityType = ENTITY_PROPOSAL_CATEGORY;
}

View File

@ -564,6 +564,8 @@ class Utils
if ($type === ENTITY_EXPENSE_CATEGORY) {
return 'expense_categories';
} elseif ($type === ENTITY_PROPOSAL_CATEGORY) {
return 'proposal_categories';
} else {
return $type . 's';
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Ninja\Repositories;
use App\Models\ProposalCategory;
use Auth;
use DB;
use Utils;
class ProposalCategoryRepository extends BaseRepository
{
public function getClassName()
{
return 'App\Models\ProposalCategory';
}
public function all()
{
return ProposalCategory::scope()->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;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Ninja\Repositories;
use App\Models\Proposal;
use Auth;
use DB;
use Utils;
class ProposalRepository extends BaseRepository
{
public function getClassName()
{
return 'App\Models\Proposal';
}
public function all()
{
return Proposal::scope()->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;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Ninja\Repositories;
use App\Models\ProposalSnippet;
use Auth;
use DB;
use Utils;
class ProposalSnippetRepository extends BaseRepository
{
public function getClassName()
{
return 'App\Models\ProposalSnippet';
}
public function all()
{
return ProposalSnippet::scope()->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;
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Ninja\Repositories;
use App\Models\ProposalTemplate;
use Auth;
use DB;
use Utils;
class ProposalTemplateRepository extends BaseRepository
{
public function getClassName()
{
return 'App\Models\ProposalTemplate';
}
public function all()
{
return ProposalTemplate::scope()->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;
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Services;
use App\Models\Client;
use App\Ninja\Datatables\ProposalCategoryDatatable;
use App\Ninja\Repositories\ProposalCategoryRepository;
/**
* Class ProposalCategoryService.
*/
class ProposalCategoryService extends BaseService
{
/**
* @var ProposalCategoryRepository
*/
protected $proposalCategoryRepo;
/**
* @var DatatableService
*/
protected $datatableService;
/**
* CreditService constructor.
*
* @param ProposalCategoryRepository $creditRepo
* @param DatatableService $datatableService
*/
public function __construct(ProposalCategoryRepository $proposalCategoryRepo, DatatableService $datatableService)
{
$this->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);
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Services;
use App\Models\Client;
use App\Ninja\Datatables\ProposalDatatable;
use App\Ninja\Repositories\ProposalRepository;
/**
* Class ProposalService.
*/
class ProposalService extends BaseService
{
/**
* @var ProposalRepository
*/
protected $proposalRepo;
/**
* @var DatatableService
*/
protected $datatableService;
/**
* CreditService constructor.
*
* @param ProposalRepository $creditRepo
* @param DatatableService $datatableService
*/
public function __construct(ProposalRepository $proposalRepo, DatatableService $datatableService)
{
$this->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);
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Services;
use App\Models\Client;
use App\Ninja\Datatables\ProposalSnippetDatatable;
use App\Ninja\Repositories\ProposalSnippetRepository;
/**
* Class ProposalSnippetService.
*/
class ProposalSnippetService extends BaseService
{
/**
* @var ProposalSnippetRepository
*/
protected $proposalSnippetRepo;
/**
* @var DatatableService
*/
protected $datatableService;
/**
* CreditService constructor.
*
* @param ProposalSnippetRepository $creditRepo
* @param DatatableService $datatableService
*/
public function __construct(ProposalSnippetRepository $proposalSnippetRepo, DatatableService $datatableService)
{
$this->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);
}
}

View File

@ -0,0 +1,71 @@
<?php
namespace App\Services;
use App\Models\Client;
use App\Ninja\Datatables\ProposalTemplateDatatable;
use App\Ninja\Repositories\ProposalTemplateRepository;
/**
* Class ProposalTemplateService.
*/
class ProposalTemplateService extends BaseService
{
/**
* @var ProposalTemplateRepository
*/
protected $proposalTemplateRepo;
/**
* @var DatatableService
*/
protected $datatableService;
/**
* CreditService constructor.
*
* @param ProposalTemplateRepository $creditRepo
* @param DatatableService $datatableService
*/
public function __construct(ProposalTemplateRepository $proposalTemplateRepo, DatatableService $datatableService)
{
$this->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);
}
}

View File

@ -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');

View File

@ -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',
);

View File

@ -46,17 +46,40 @@
<input id="tableFilter_{{ $entityType }}" type="text" style="width:180px;margin-right:17px;background-color: white !important"
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
@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() !!}
<script type="text/javascript">
$(function() {
$('.templatesDropdown:not(.dropdown-toggle)').click(function(event) {
openUrlOnClick('{{ url('/proposal_templates') }}', event);
});
$('.snippetsDropdown:not(.dropdown-toggle)').click(function(event) {
openUrlOnClick('{{ url('/proposal_snippets') }}', event);
});
});
</script>
@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() !!}
<script type="text/javascript">
$(function() {
$('.recurringDropdown:not(.dropdown-toggle)').click(function(event) {
openUrlOnClick('{{ url('/recurring_invoices') }}', event);
$('.categoriesDropdown:not(.dropdown-toggle)').click(function(event) {
openUrlOnClick('{{ url('/proposal_categories') }}', event);
});
});
</script>

View File

@ -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');