Browse Source

Update 2016-07-19.20.56

Filter Payments only for logged in owner
Create feature from other project's feature
Filter project only for logged in owner
Filter Report only for logged in owner
Filter Home dashboard project summary only for logged in owner
Add flash error on validator fails redirection
Fix ManageProjectsTest and ManagPaymentsTest to manage only by owner
pull/1/head
Nafies Luthfi 10 years ago
parent
commit
275bc149bd
  1. 1
      app/Entities/Payments/PaymentsRepository.php
  2. 25
      app/Entities/Projects/FeaturesRepository.php
  3. 1
      app/Entities/Projects/ProjectsRepository.php
  4. 3
      app/Entities/Reports/ReportsRepository.php
  5. 9
      app/Http/Controllers/PagesController.php
  6. 20
      app/Http/Controllers/Projects/FeaturesController.php
  7. 2
      app/Http/Requests/Projects/CreateRequest.php
  8. 4
      app/Http/Requests/Projects/DeleteRequest.php
  9. 4
      app/Http/Requests/Projects/UpdateRequest.php
  10. 10
      app/Http/Requests/Request.php
  11. 3
      app/Http/routes/projects.php
  12. 5
      app/Providers/AppServiceProvider.php
  13. 8
      app/Providers/AuthServiceProvider.php
  14. 2
      app/Providers/FormFieldServiceProvider.php
  15. 3
      app/Services/FormField.php
  16. 1
      resources/lang/id/feature.php
  17. 80
      resources/views/features/add-from-other-project.blade.php
  18. 9
      resources/views/layouts/partials/sidebar.blade.php
  19. 2
      resources/views/pages/home.blade.php
  20. 10
      resources/views/projects/create.blade.php
  21. 1
      resources/views/projects/features.blade.php
  22. 70
      tests/ManageFeaturesTest.php
  23. 4
      tests/ManagePaymentsTest.php
  24. 72
      tests/ManageProjectsTest.php

1
app/Entities/Payments/PaymentsRepository.php

@ -20,6 +20,7 @@ class PaymentsRepository extends BaseRepository
{
return $this->model->orderBy('date','desc')
->with('customer','project')
->whereOwnerId(auth()->id())
->paginate($this->_paginate);
}

25
app/Entities/Projects/FeaturesRepository.php

@ -4,6 +4,7 @@ namespace App\Entities\Projects;
use App\Entities\BaseRepository;
use App\Entities\Projects\Project;
use DB;
/**
* Features Repository Class
@ -29,6 +30,30 @@ class FeaturesRepository extends BaseRepository
return $this->storeArray($featureData);
}
public function createFeatures($featuresData, $projectId)
{
$selectedFeatures = $this->model->whereIn('id', $featuresData['feature_ids'])->get();
DB::beginTransaction();
foreach ($selectedFeatures as $feature) {
$newFeature = $feature->replicate();
$newFeature->project_id = $projectId;
$newFeature->save();
$selectedTasks = $feature->tasks()->whereIn('id', $featuresData[$feature->id . '_task_ids'])->get();
foreach ($selectedTasks as $task) {
$newTask = $task->replicate();
$newTask->progress = 0;
$newTask->feature_id = $newFeature->id;
$newTask->save();
}
}
DB::commit();
return 'ok';
}
public function getTasksByFeatureId($featureId)
{
return Task::whereFeatureId($featureId)->get();

1
app/Entities/Projects/ProjectsRepository.php

@ -30,6 +30,7 @@ class ProjectsRepository extends BaseRepository
$query->where('status_id', $statusId);
})
->withCount('payments')
->whereOwnerId(auth()->id())
->paginate($this->_paginate);
}

3
app/Entities/Reports/ReportsRepository.php

@ -24,6 +24,7 @@ class ReportsRepository extends BaseRepository
return Payment::orderBy('date','desc')
->where('date', $date)
->with('customer','project')
->where('owner_id',auth()->id())
->get();
}
@ -34,6 +35,7 @@ class ReportsRepository extends BaseRepository
->where(DB::raw('MONTH(date)'), $month)
->groupBy('date')
->orderBy('date','asc')
->where('owner_id',auth()->id())
->get();
}
@ -44,6 +46,7 @@ class ReportsRepository extends BaseRepository
->groupBy(DB::raw('YEAR(date)'))
->groupBy(DB::raw('MONTH(date)'))
->orderBy('date','asc')
->where('owner_id',auth()->id())
->get();
}

9
app/Http/Controllers/PagesController.php

@ -3,6 +3,8 @@
namespace App\Http\Controllers;
use App\Entities\Pages\PagesRepository;
use App\Entities\Projects\Project;
use DB;
class PagesController extends Controller {
private $repo;
@ -15,7 +17,12 @@ class PagesController extends Controller {
public function home()
{
return view('pages.home');
$projectsCount = Project::select(DB::raw('status_id, count(id) as count'))
->groupBy('status_id')
->where('owner_id', auth()->id())
->lists('count','status_id')
->all();
return view('pages.home', compact('projectsCount'));
}
public function about()

20
app/Http/Controllers/Projects/FeaturesController.php

@ -26,6 +26,19 @@ class FeaturesController extends Controller {
return view('features.create',compact('project','workers'));
}
public function addFromOtherProject(Request $req, $projectId)
{
$selectedProject = null;
$project = $this->repo->requireProjectById($projectId);
$workers = $this->repo->getWorkersList();
$projects = $this->repo->getProjectsList();
if ($req->has('project_id')) {
$selectedProject = $this->repo->requireProjectById($req->get('project_id'));
}
return view('features.add-from-other-project',compact('project','workers','projects','selectedProject'));
}
public function store(CreateRequest $req, $projectId)
{
$feature = $this->repo->createFeature($req->except('_token'), $projectId);
@ -33,6 +46,13 @@ class FeaturesController extends Controller {
return redirect()->route('projects.features', $feature->project_id);
}
public function storeFromOtherProject(Request $req, $projectId)
{
$this->repo->createFeatures($req->except('_token'), $projectId);
flash()->success(trans('feature.created_from_other_project'));
return redirect()->route('projects.features', $projectId);
}
public function show(Request $req, $featureId)
{
$editableTask = null;

2
app/Http/Requests/Projects/CreateRequest.php

@ -13,7 +13,7 @@ class CreateRequest extends Request {
*/
public function authorize()
{
return auth()->user()->can('manage_projects');
return auth()->user()->can('add_project');
}
/**

4
app/Http/Requests/Projects/DeleteRequest.php

@ -2,6 +2,7 @@
namespace App\Http\Requests\Projects;
use App\Entities\Projects\Project;
use App\Http\Requests\Request;
class DeleteRequest extends Request {
@ -13,7 +14,8 @@ class DeleteRequest extends Request {
*/
public function authorize()
{
return auth()->user()->can('manage_projects');
$project = Project::findOrFail($this->segment(2));
return auth()->user()->can('manage_project', $project);
}
/**

4
app/Http/Requests/Projects/UpdateRequest.php

@ -2,6 +2,7 @@
namespace App\Http\Requests\Projects;
use App\Entities\Projects\Project;
use App\Http\Requests\Request;
class UpdateRequest extends Request {
@ -13,7 +14,8 @@ class UpdateRequest extends Request {
*/
public function authorize()
{
return auth()->user()->can('manage_projects');
$project = Project::findOrFail($this->segment(2));
return auth()->user()->can('manage_project', $project);
}
/**

10
app/Http/Requests/Request.php

@ -2,9 +2,17 @@
namespace App\Http\Requests;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
abstract class Request extends FormRequest
{
//
/**
* {@inheritdoc}
*/
protected function formatErrors(Validator $validator)
{
flash()->error('Mohon periksa kembali form isian Anda.');
return $validator->errors()->all();
}
}

3
app/Http/routes/projects.php

@ -12,8 +12,11 @@ Route::group(['middleware' => ['web','role:admin'], 'namespace' => 'Projects'],
/**
* Features Routes
*/
Route::get('projects/{id}/features/create', ['as'=>'features.create', 'uses'=>'FeaturesController@create']);
Route::get('projects/{id}/features/add-from-other-project', ['as'=>'features.add-from-other-project', 'uses'=>'FeaturesController@addFromOtherProject']);
Route::post('projects/{id}/features', ['as'=>'features.store', 'uses'=>'FeaturesController@store']);
Route::post('projects/{id}/features/store-from-other-project', ['as'=>'features.store-from-other-project', 'uses'=>'FeaturesController@storeFromOtherProject']);
Route::get('features/{id}/delete', ['as'=>'features.delete', 'uses'=>'FeaturesController@delete']);
Route::resource('features','FeaturesController',['except' => ['index','create','store']]);

5
app/Providers/AppServiceProvider.php

@ -16,11 +16,6 @@ class AppServiceProvider extends ServiceProvider
public function boot()
{
require_once app_path() . '/helpers.php';
$projectsCount = Project::select(DB::raw('status_id, count(id) as count'))
->groupBy('status_id')
->lists('count','status_id')
->all();
view()->share('projectsCount', $projectsCount);
}
/**

8
app/Providers/AuthServiceProvider.php

@ -34,6 +34,14 @@ class AuthServiceProvider extends ServiceProvider
});
}
$gate->define('add_project', function ($user) {
return $user->hasRole('admin');
});
$gate->define('manage_project', function ($user, $project) {
return $user->id == $project->owner_id;
});
$gate->define('manage_features', function ($user, $project) {
return $user->id == $project->owner_id;
});

2
app/Providers/FormFieldServiceProvider.php

@ -2,8 +2,8 @@
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\FormField;
use Illuminate\Support\ServiceProvider;
class FormFieldServiceProvider extends ServiceProvider
{

3
app/Services/FormField.php

@ -4,7 +4,6 @@ namespace App\Services;
use Form;
use Illuminate\Support\Collection;
use Illuminate\Support\MessageBag;
use Session;
/**
* FormField Class (Site FormField Service)
@ -18,7 +17,7 @@ class FormField
public function __construct()
{
$this->errorBag = Session::get('errors', new MessageBag);;
$this->errorBag = session()->get('errors', new MessageBag);
}
public function text($name, $options = [])

1
resources/lang/id/feature.php

@ -26,4 +26,5 @@ return [
'price_total' => 'Nilai Fitur Total',
'empty' => 'Belum ada Fitur',
'back_to_index' => 'Kembali ke daftar Fitur',
'add_from_other_project' => 'Tambah Fitur dari Project Lain',
];

80
resources/views/features/add-from-other-project.blade.php

@ -0,0 +1,80 @@
@extends('layouts.app')
@section('title', trans('feature.add_from_other_project'))
@section('content')
@include('projects.partials.breadcrumb',['title' => trans('feature.add_from_other_project')])
<div class="row">
<div class="col-sm-6">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('feature.add_from_other_project') }}</h3></div>
<div class="panel-body">
{!! Form::open(['method'=>'get']) !!}
<?php // echo '<pre>$selectedProject : ', print_r($selectedProject, true), '</pre>'; ?>
<div class="form-group">
<label for="project_id" class="text-primary">{{ trans('project.project') }}</label>
<div class="input-group">
{!! Form::select('project_id', $projects, Request::get('project_id'), [
'class' => 'form-control customer-select',
'placeholder' => '-- Pilih Project --'
]) !!}
<span class="input-group-btn"><button class="btn btn-default btn-sm" type="submit">Lihat Fitur</button></span>
</div>
</div>
{!! Form::close() !!}
@if ($selectedProject)
{!! Form::open(['route'=>['features.store-from-other-project', $project->id]]) !!}
<ul class="list-unstyled">
@forelse($selectedProject->features as $key => $feature)
<li>
<label for="feature_id_{{ $feature->id }}">
{!! Form::checkbox('feature_ids[' . $feature->id . ']', $feature->id, null, ['id' => 'feature_id_' . $feature->id]) !!}
{{ $feature->name }}</label>
<ul style="list-style-type:none">
@foreach($feature->tasks as $task)
<li>
<label for="{{ $feature->id }}_task_id_{{ $task->id }}" style="font-weight:normal">
{!! Form::checkbox($feature->id . '_task_ids[' . $task->id . ']', $task->id, null, ['id' => $feature->id . '_task_id_' . $task->id]) !!}
{{ $task->name }}</label>
</li>
@endforeach
</ul>
</li>
@empty
<li><div class="alert alert-info">Tidak ada fitur</div></li>
@endforelse
</ul>
@else
<div class="alert alert-info">Pilih salah satu project</div>
@endif
{!! Form::submit(trans('feature.create'), ['class'=>'btn btn-primary']) !!}
{!! Form::close() !!}
</div>
<div class="panel-footer">
{!! link_to_route('projects.features', trans('app.cancel'), [$project->id], ['class'=>'btn btn-default']) !!}
</div>
</div>
</div>
<div class="col-sm-6">
@include('projects.partials.project-show')
</div>
</div>
@endsection
@section('ext_js')
{!! Html::script(url('assets/js/plugins/autoNumeric.min.js')) !!}
@endsection
@section('script')
<script>
(function() {
$('#price').autoNumeric("init",{
aSep: '.',
aDec: ',',
mDec: '0'
});
})();
</script>
@endsection

9
resources/views/layouts/partials/sidebar.blade.php

@ -5,10 +5,15 @@
</a>
<ul class="nav" id="side-menu">
<li>{!! html_link_to_route('home', 'Dashboard', [], ['icon' => 'dashboard']) !!}</li>
@can('manage_projects')
@can('add_project')
<li>
<?php $projectsCount = App\Entities\Projects\Project::select(DB::raw('status_id, count(id) as count'))
->groupBy('status_id')
->where('owner_id', auth()->id())
->lists('count','status_id')
->all(); ?>
{!! html_link_to_route('projects.index', trans('project.projects') . ' <span class="fa arrow"></span>', [], ['icon' => 'table']) !!}
<ul class="nav nav-second-level">
<ul class="nav nav-second-level in">
@foreach(getProjectStatusesList() as $key => $status)
<li>
<a href="{{ route('projects.index', ['status' => $key]) }}">

2
resources/views/pages/home.blade.php

@ -9,7 +9,7 @@
<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3"><i class="fa fa-thumb-tack fa-5x"></i></div>
<div class="col-xs-3"><i class="fa fa-paperclip fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(1, $projectsCount) ? $projectsCount[1] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(1) }}</div>

10
resources/views/projects/create.blade.php

@ -10,10 +10,10 @@
<div class="row">
<div class="col-md-4 col-md-offset-3">
{!! Form::open(['route'=>'projects.store']) !!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('project.create') }}</h3></div>
<div class="panel-body">
{!! Form::open(['route'=>'projects.store']) !!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('project.create') }}</h3></div>
<div class="panel-body">
{!! FormField::text('name',['label'=> trans('project.name')]) !!}
{!! FormField::select('customer_id', $customers,['placeholder' => '-- Customer Baru --']) !!}
<div class="row">
@ -42,5 +42,7 @@
</div>
</div>
</div>
{!! Form::close() !!}
<?php // echo '<pre>$errors->toArray() : ', print_r($errors->toArray(), true), '</pre>' ?>
@endsection

1
resources/views/projects/features.blade.php

@ -8,6 +8,7 @@
<h1 class="page-header">
<div class="pull-right">
{!! html_link_to_route('features.create', trans('feature.create'), [$project->id], ['class' => 'btn btn-primary','icon' => 'plus']) !!}
{!! html_link_to_route('features.add-from-other-project', trans('feature.add_from_other_project'), [$project->id], ['class' => 'btn btn-primary','icon' => 'plus']) !!}
</div>
{{ $project->name }} <small>{{ trans('project.features') }}</small>
</h1>

70
tests/ManageFeaturesTest.php

@ -2,6 +2,7 @@
use App\Entities\Projects\Feature;
use App\Entities\Projects\Project;
use App\Entities\Projects\Task;
use App\Entities\Users\User;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
@ -136,4 +137,73 @@ class ManageFeaturesTest extends TestCase
$this->see($features[1]->worker->name);
$this->see(formatRp($features[1]->price));
}
/** @test */
public function admin_may_clone_many_features_from_other_projects()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
$this->actingAs($user);
$projects = factory(Project::class, 2)->create(['owner_id' => $user->id]);
$features = factory(Feature::class, 3)->create(['project_id' => $projects[0]->id]);
$tasks1 = factory(Task::class, 3)->create(['feature_id' => $features[0]->id]);
$tasks2 = factory(Task::class, 3)->create(['feature_id' => $features[1]->id]);
$this->visit('projects/' . $projects[1]->id . '/features');
$this->seePageIs('projects/' . $projects[1]->id . '/features');
$this->click(trans('feature.add_from_other_project'));
$this->seePageIs('projects/' . $projects[1]->id . '/features/add-from-other-project');
$this->select($projects[0]->id, 'project_id');
$this->press('Lihat Fitur');
$this->seePageIs('projects/' . $projects[1]->id . '/features/add-from-other-project?project_id=' . $projects[0]->id);
// $this->submitForm(trans('feature.create'), [
// 'feature_ids' => [$features[0]->id,$features[1]->id],
// $features[0]->id . '_task_ids' => [$tasks1[0]->id,$tasks1[1]->id,$tasks1[2]->id],
// $features[1]->id . '_task_ids' => [$tasks2[0]->id,$tasks2[1]->id,$tasks2[2]->id],
// ]);
// $this->check('feature_ids[0]');
// $this->check('feature_ids[1]');
// $this->check($features[0]->id . '_task_ids[0]');
// $this->check($features[0]->id . '_task_ids[1]');
// $this->check($features[0]->id . '_task_ids[2]');
// $this->check($features[1]->id . '_task_ids[0]');
// $this->check($features[1]->id . '_task_ids[1]');
// $this->check($features[1]->id . '_task_ids[2]');
// $this->press(trans('feature.create'));
$form = $this->getForm(trans('feature.create'));
$form['feature_ids'][$features[0]->id]->tick();
$form['feature_ids'][$features[1]->id]->tick();
$form[$features[0]->id . '_task_ids'][$tasks1[0]->id]->tick();
$form[$features[0]->id . '_task_ids'][$tasks1[1]->id]->tick();
$form[$features[0]->id . '_task_ids'][$tasks1[2]->id]->tick();
$form[$features[1]->id . '_task_ids'][$tasks2[0]->id]->tick();
$form[$features[1]->id . '_task_ids'][$tasks2[1]->id]->tick();
$form[$features[1]->id . '_task_ids'][$tasks2[2]->id]->tick();
$this->makeRequestUsingForm($form);
$this->seePageIs('projects/' . $projects[1]->id . '/features');
$this->see(trans('feature.created_from_other_project'));
$this->seeInDatabase('features', [
'project_id' => $projects[1]->id,
'name' => $features[0]->name,
'price' => $features[0]->price,
'worker_id' => $features[0]->worker_id,
]);
$this->seeInDatabase('features', [
'project_id' => $projects[1]->id,
'name' => $features[1]->name,
'price' => $features[1]->price,
'worker_id' => $features[1]->worker_id,
]);
// $this->seeInDatabase('tasks', [
// 'feature_id' => $features[1]->id,
// 'name' => $tasks1[0]->name,
// 'price' => $features[1]->price,
// 'worker_id' => $features[1]->worker_id,
// ]);
}
}

4
tests/ManagePaymentsTest.php

@ -112,7 +112,7 @@ class ManagePaymentsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$payment = factory(Payment::class)->create();
$payment = factory(Payment::class)->create(['owner_id' => $user->id]);
$this->visit('/payments');
$this->click(trans('app.edit'));
$this->click(trans('payment.delete'));
@ -148,7 +148,7 @@ class ManagePaymentsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$payments = factory(Payment::class, 5)->create();
$payments = factory(Payment::class, 5)->create(['owner_id' => $user->id]);
$this->assertEquals(5, $payments->count());
$this->visit('/payments');

72
tests/ManageProjectsTest.php

@ -13,19 +13,18 @@ class ManageProjectsTest extends TestCase
/** @test */
public function admin_can_input_new_project_with_existing_customer()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
$this->actingAs($user);
$users = factory(User::class, 2)->create();
$users[0]->assignRole('admin');
$this->actingAs($users[0]);
$user = factory(User::class)->create();
$user->assignRole('customer');
$users[1]->assignRole('customer');
$this->visit('/projects');
$this->seePageIs('/projects');
$this->click(trans('project.create'));
$this->seePageIs('/projects/create');
$this->type('Project Baru','name');
$this->select($user->id,'customer_id');
$this->select($users[1]->id,'customer_id');
$this->type('2016-04-15','proposal_date');
$this->type('2000000','proposal_value');
$this->type('Deskripsi project baru','description');
@ -76,7 +75,7 @@ class ManageProjectsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$project = factory(Project::class)->create();
$project = factory(Project::class)->create(['owner_id' => $user->id]);
$this->visit('/projects?status=' . $project->status_id);
$this->click(trans('app.edit'));
$this->click(trans('app.delete'));
@ -84,4 +83,63 @@ class ManageProjectsTest extends TestCase
$this->seePageIs('projects');
$this->see(trans('project.deleted'));
}
/** @test */
public function admin_can_edit_a_project()
{
$users = factory(User::class, 2)->create();
$users[0]->assignRole('admin');
$this->actingAs($users[0]);
$project = factory(Project::class)->create(['owner_id' => $users[0]->id]);
$users[1]->assignRole('customer');
$this->visit('projects/' . $project->id . '/edit');
$this->seePageIs('projects/' . $project->id . '/edit');
$this->type('Edit Project','name');
$this->type('2016-04-15','proposal_date');
$this->type('2016-04-25','start_date');
$this->type('2016-05-05','end_date');
$this->type(2000000,'proposal_value');
$this->type(2000000,'project_value');
$this->select(4,'status_id');
$this->select($users[1]->id,'customer_id');
$this->type('Edit deskripsi project','description');
$this->press(trans('project.update'));
$this->seeInDatabase('projects',[
'id' => $project->id,
'name' => 'Edit Project',
'proposal_date' => '2016-04-15',
'start_date' => '2016-04-25',
'end_date' => '2016-05-05',
'customer_id' => $users[1]->id,
'description' => 'Edit deskripsi project',
]);
}
/** @test */
public function form_is_validated_on_invalid_project_entry()
{
$users = factory(User::class, 2)->create();
$users[0]->assignRole('admin');
$this->actingAs($users[0]);
$users[1]->assignRole('customer');
$this->visit('/projects');
$this->seePageIs('/projects');
$this->click(trans('project.create'));
$this->seePageIs('/projects/create');
$this->type('','name');
$this->select($users[1]->id,'customer_id');
$this->type('2016-04-15aa','proposal_date');
$this->type('','proposal_value');
$this->type('Deskripsi project baru','description');
$this->press(trans('project.create'));
$this->seePageIs('/projects/create');
$this->see('Mohon periksa kembali form isian Anda.');
}
}
Loading…
Cancel
Save