Browse Source

Update 2016-08-02.11.34

Search payments by project name
List On Progress Project by features list
Refactor project work duration to ProjectPresenter class
Project deletation also remove its payments, features and tasks
Show Current Credit on On Progress, Done, and On Hold project status
Add form error notification
Add route name on a task of feature
Add Project status update on project detail page
Add pagination on top of payment and project index page
Fix missing line break on project detail description
pull/1/head
Nafies Luthfi 10 years ago
parent
commit
c2b313780a
  1. 3
      app/Entities/Payments/PaymentsRepository.php
  2. 9
      app/Entities/Projects/FeaturesRepository.php
  3. 12
      app/Entities/Projects/ProjectPresenter.php
  4. 26
      app/Entities/Projects/ProjectsRepository.php
  5. 3
      app/Entities/Reports/ReportsRepository.php
  6. 8
      app/Http/Controllers/Projects/FeaturesController.php
  7. 11
      app/Http/Controllers/Projects/ProjectsController.php
  8. 2
      app/Http/Requests/Request.php
  9. 3
      app/Http/Requests/Tasks/CreateRequest.php
  10. 3
      app/Http/Requests/Tasks/UpdateRequest.php
  11. 3
      app/Http/routes/projects.php
  12. 4
      app/Services/FormField.php
  13. 2
      app/helpers.php
  14. 1
      database/factories/ModelFactory.php
  15. 3
      public/assets/css/app.css
  16. 2
      public/assets/css/app.css.map
  17. 4
      resources/assets/sass/app.scss
  18. 1
      resources/lang/id/task.php
  19. 2
      resources/views/features/add-from-other-project.blade.php
  20. 53
      resources/views/features/partials/feature-tasks-operation.blade.php
  21. 64
      resources/views/features/partials/feature-tasks.blade.php
  22. 5
      resources/views/features/show.blade.php
  23. 63
      resources/views/features/unfinished.blade.php
  24. 5
      resources/views/layouts/partials/sidebar.blade.php
  25. 7
      resources/views/pages/home.blade.php
  26. 3
      resources/views/payments/index.blade.php
  27. 1
      resources/views/projects/create.blade.php
  28. 8
      resources/views/projects/features.blade.php
  29. 19
      resources/views/projects/index.blade.php
  30. 6
      resources/views/projects/partials/project-show.blade.php
  31. 2
      resources/views/projects/payments.blade.php
  32. 16
      resources/views/projects/show.blade.php
  33. 2
      resources/views/reports/current-credits.blade.php
  34. 6
      resources/views/reports/payments/yearly.blade.php
  35. 33
      tests/ManageFeaturesTest.php
  36. 23
      tests/ManagePaymentsTest.php
  37. 71
      tests/ManageProjectsTest.php
  38. 10
      tests/ManageTasksTest.php

3
app/Entities/Payments/PaymentsRepository.php

@ -19,6 +19,9 @@ class PaymentsRepository extends BaseRepository
public function getAll($q)
{
return $this->model->orderBy('date','desc')
->whereHas('project', function($query) use ($q) {
$query->where('name', 'like', '%' . $q . '%');
})
->with('customer','project')
->whereOwnerId(auth()->id())
->paginate($this->_paginate);

9
app/Entities/Projects/FeaturesRepository.php

@ -18,6 +18,15 @@ class FeaturesRepository extends BaseRepository
parent::__construct($model);
}
public function getUnfinishedFeatures()
{
return $this->model->whereHas('tasks', function($query) {
return $query->where('progress','<',100);
})
->with(['tasks','project','worker'])
->get();
}
public function requireProjectById($projectId)
{
return Project::findOrFail($projectId);

12
app/Entities/Projects/ProjectPresenter.php

@ -21,4 +21,16 @@ class ProjectPresenter extends Presenter
return getProjectStatusesList($this->entity->status_id);
}
public function workDuration()
{
if (is_null($this->entity->end_date))
return '-';
$workDuration = dateDifference($this->entity->start_date,$this->entity->end_date);
if ((int) $workDuration > 30)
return dateDifference($this->entity->start_date,$this->entity->end_date, '%m Bulan %d Hari');
return $workDuration . ' Hari';
}
}

26
app/Entities/Projects/ProjectsRepository.php

@ -30,6 +30,7 @@ class ProjectsRepository extends BaseRepository
$query->where('status_id', $statusId);
})
->withCount('payments')
->with('customer')
->whereOwnerId(auth()->id())
->paginate($this->_paginate);
}
@ -73,14 +74,37 @@ class ProjectsRepository extends BaseRepository
public function delete($projectId)
{
$project = $this->requireById($projectId);
DB::beginTransaction();
// Delete project payments
$project->payments()->delete();
// Delete features tasks
$featureIds = $project->features->lists('id')->all();
DB::table('tasks')->whereIn('feature_id', $featureIds)->delete();
// Delete features
$project->features()->delete();
return $project->delete();
// Delete project
$project->delete();
DB::commit();
return 'deleted';
}
public function getProjectFeatures($projectId)
{
return Feature::whereProjectId($projectId)->with('worker','tasks')->get();
}
public function updateStatus($statusId, $projectId)
{
$project = $this->requireById($projectId);
$project->status_id = $statusId;
$project->save();
// die('hit');
return $project;
}
}

3
app/Entities/Reports/ReportsRepository.php

@ -52,7 +52,8 @@ class ReportsRepository extends BaseRepository
public function getCurrentCredits()
{
$projects = Project::whereIn('status_id',[3,6])->with('payments')->get();
// On Progress, Done, On Hold
$projects = Project::whereIn('status_id',[2,3,6])->with('payments','customer')->get();
return $projects->filter(function($project) {
return $project->cashInTotal() < $project->project_value;
})->values();

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

@ -19,6 +19,12 @@ class FeaturesController extends Controller {
$this->repo = $repo;
}
public function index()
{
$features = $this->repo->getUnfinishedFeatures();
return view('features.unfinished', compact('features'));
}
public function create($projectId)
{
$project = $this->repo->requireProjectById($projectId);
@ -95,7 +101,7 @@ class FeaturesController extends Controller {
$projectId = $feature->project_id;
if ($featureId == $req->get('feature_id'))
{
// $feature->tasks()->delete();
$feature->tasks()->delete();
$feature->delete();
flash()->success(trans('feature.deleted'));
}

11
app/Http/Controllers/Projects/ProjectsController.php

@ -22,7 +22,7 @@ class ProjectsController extends Controller {
public function index(Request $req)
{
$status = null;
$statusId = $req->get('status', 3);
$statusId = $req->get('status');
if ($statusId) {
$status = $this->repo->getStatusName($statusId);
}
@ -41,7 +41,7 @@ class ProjectsController extends Controller {
{
$project = $this->repo->create($req->except('_token'));
flash()->success(trans('project.created'));
return redirect()->route('projects.index');
return redirect()->route('projects.show', $project->id);
}
public function show($projectId)
@ -98,4 +98,11 @@ class ProjectsController extends Controller {
return view('projects.payments', compact('project'));
}
public function statusUpdate(Request $req, $projectId)
{
$project = $this->repo->updateStatus($req->get('status_id'), $projectId);
flash()->success(trans('project.updated'));
return redirect()->route('projects.show', $projectId);
}
}

2
app/Http/Requests/Request.php

@ -13,6 +13,6 @@ abstract class Request extends FormRequest
protected function formatErrors(Validator $validator)
{
flash()->error('Mohon periksa kembali form isian Anda.');
return $validator->errors()->all();
return $validator->getMessageBag()->toArray();
}
}

3
app/Http/Requests/Tasks/CreateRequest.php

@ -28,7 +28,8 @@ class CreateRequest extends Request {
return [
'name' => 'required|max:60',
'description' => 'max:255',
'progress' => 'numeric',
'progress' => 'numeric|max:100',
'route_name' => 'max:255',
];
}

3
app/Http/Requests/Tasks/UpdateRequest.php

@ -28,7 +28,8 @@ class UpdateRequest extends Request {
return [
'name' => 'required|max:60',
'description' => 'max:255',
'progress' => 'required|numeric|max:100',
'progress' => 'numeric|max:100',
'route_name' => 'max:255',
];
}

3
app/Http/routes/projects.php

@ -7,6 +7,7 @@ Route::group(['middleware' => ['web','role:admin'], 'namespace' => 'Projects'],
Route::get('projects/{id}/delete', ['as'=>'projects.delete', 'uses'=>'ProjectsController@delete']);
Route::get('projects/{id}/features', ['as'=>'projects.features', 'uses'=>'ProjectsController@features']);
Route::get('projects/{id}/payments', ['as'=>'projects.payments', 'uses'=>'ProjectsController@payments']);
Route::patch('projects/{id}/status-update', ['as'=>'projects.status-update', 'uses'=>'ProjectsController@statusUpdate']);
Route::resource('projects','ProjectsController');
/**
@ -18,7 +19,7 @@ Route::group(['middleware' => ['web','role:admin'], 'namespace' => 'Projects'],
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']]);
Route::resource('features','FeaturesController',['except' => ['create','store']]);
/**
* Tasks Routes

4
app/Services/FormField.php

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

2
app/helpers.php

@ -208,7 +208,7 @@ function getProjectStatusesList($statusId = null) {
return null;
}
function dateDifference($date1 , $date2 , $differenceFormat = '%m Bulan %d Hari' )
function dateDifference($date1 , $date2 , $differenceFormat = '%a' )
{
$datetime1 = date_create($date1);
$datetime2 = date_create($date2);

1
database/factories/ModelFactory.php

@ -106,5 +106,6 @@ $factory->define(Task::class, function (Faker\Generator $faker) {
'name' => $faker->sentence(3),
'description' => $faker->paragraph,
'progress' => rand(40,100),
'route_name' => implode('.', $faker->words(3))
];
});

3
public/assets/css/app.css

@ -7170,6 +7170,9 @@ h1.page-header {
label.control-label {
color: #428bca; }
.well .pagination {
margin: -2px 0 0 -2px; }
@media (min-width: 768px) {
#page-wrapper {
margin-left: 200px;

2
public/assets/css/app.css.map
File diff suppressed because it is too large
View File

4
resources/assets/sass/app.scss

@ -67,6 +67,10 @@ label.control-label {
color: #428bca;
}
.well .pagination {
margin: -2px 0 0 -2px;
}
@media(min-width:768px) {
#page-wrapper {
margin-left: 200px;

1
resources/lang/id/task.php

@ -18,5 +18,6 @@ return [
'not_found' => 'Task tidak ditemukan',
'progress' => 'Progress',
'empty' => 'Belum ada Task',
'route_name' => 'Route Aplikasi',
'back_to_index' => 'Kembali ke daftar Task',
];

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

@ -1,6 +1,6 @@
@extends('layouts.app')
@section('title', trans('feature.add_from_other_project'))
@section('title', trans('feature.add_from_other_project') . ' | ' . $project->name)
@section('content')
@include('projects.partials.breadcrumb',['title' => trans('feature.add_from_other_project')])

53
resources/views/features/partials/feature-tasks-operation.blade.php

@ -0,0 +1,53 @@
@if (Request::has('action') == false)
{!! Form::open(['route' => ['tasks.store', $feature->id]])!!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.create') }}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-5">{!! FormField::text('name') !!}</div>
<div class="col-sm-5">{!! FormField::text('route_name') !!}</div>
<div class="col-sm-2">{!! FormField::text('progress', ['addon' => ['after' => '%'],'value' => 0]) !!}</div>
</div>
{!! FormField::text('description') !!}
{!! Form::submit(trans('task.create'), ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!}
</div>
</div>
@endif
@if (Request::get('action') == 'task_edit' && $editableTask)
{!! Form::model($editableTask, ['route' => ['tasks.update', $editableTask->id],'method' =>'patch'])!!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.edit') }}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-5">{!! FormField::text('name') !!}</div>
<div class="col-sm-5">{!! FormField::text('route_name') !!}</div>
<div class="col-sm-2">{!! FormField::text('progress', ['addon' => ['after' => '%']]) !!}</div>
</div>
{!! FormField::text('description') !!}
{!! Form::hidden('feature_id', $editableTask->feature_id) !!}
{!! Form::submit(trans('task.update'), ['class' => 'btn btn-warning']) !!}
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!}
{!! Form::close() !!}
</div>
</div>
@endif
@if (Request::get('action') == 'task_delete' && $editableTask)
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.delete') }}</h3></div>
<div class="panel-body">
{{ trans('app.delete_confirm') }}
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!}
<div class="pull-right">
{!! FormField::delete([
'route'=>['tasks.destroy',$editableTask->id]],
trans('app.delete_confirm_button'),
['class'=>'btn btn-danger'],
[
'task_id' => $editableTask->id,
'feature_id' => $editableTask->feature_id,
]) !!}
</div>
</div>
</div>
@endif

64
resources/views/features/partials/feature-tasks.blade.php

@ -1,65 +1,10 @@
@if (Request::has('action') == false)
{!! Form::open(['route' => ['tasks.store', $feature->id]])!!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.create') }}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-4">{!! FormField::text('name') !!}</div>
<div class="col-sm-6">{!! FormField::text('description') !!}</div>
<div class="col-sm-2">
{!! FormField::text('progress', ['addon' => ['after' => '%'],'value' => 0]) !!}
</div>
</div>
{!! Form::submit(trans('task.create'), ['class' => 'btn btn-primary']) !!}
{!! Form::close() !!}
</div>
</div>
@endif
@if (Request::get('action') == 'task_edit' && $editableTask)
{!! Form::model($editableTask, ['route' => ['tasks.update', $editableTask->id],'method' =>'patch'])!!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.edit') }}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-sm-4">{!! FormField::text('name') !!}</div>
<div class="col-sm-6">{!! FormField::text('description') !!}</div>
<div class="col-sm-2">
{!! FormField::text('progress', ['addon' => ['after' => '%']]) !!}
</div>
</div>
{!! Form::hidden('feature_id', $editableTask->feature_id) !!}
{!! Form::submit(trans('task.update'), ['class' => 'btn btn-warning']) !!}
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!}
{!! Form::close() !!}
</div>
</div>
@endif
@if (Request::get('action') == 'task_delete' && $editableTask)
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('task.delete') }}</h3></div>
<div class="panel-body">
{{ trans('app.delete_confirm') }}
{!! link_to_route('features.show', trans('app.cancel'), [$feature->id], ['class' => 'btn btn-default']) !!}
<div class="pull-right">
{!! FormField::delete([
'route'=>['tasks.destroy',$editableTask->id]],
trans('app.delete_confirm_button'),
['class'=>'btn btn-danger'],
[
'task_id' => $editableTask->id,
'feature_id' => $editableTask->feature_id,
]) !!}
</div>
</div>
</div>
@endif
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('feature.tasks') }}</h3></div>
<table class="table table-condensed">
<thead>
<th>{{ trans('app.table_no') }}</th>
<th>{{ trans('task.name') }}</th>
<th>{{ trans('app.description') }}</th>
<th>{{ trans('task.route_name') }}</th>
<th class="text-center">{{ trans('task.progress') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
@ -67,8 +12,11 @@
@forelse($feature->tasks as $key => $task)
<tr>
<td>{{ 1 + $key }}</td>
<td>{{ $task->name }}</td>
<td>{{ $task->description }}</td>
<td>
<div>{{ $task->name }}</div>
<div class="small text-info">{{ $task->description }}</div>
</td>
<td>{{ $task->route_name }}</td>
<td class="text-center">{{ $task->progress }} %</td>
<td>
{{ link_to_route('features.show', trans('task.edit'), [

5
resources/views/features/show.blade.php

@ -1,6 +1,6 @@
@extends('layouts.app')
@section('title', trans('feature.show'))
@section('title', trans('feature.show') . ' | ' . $feature->name . ' | ' . $feature->project->name)
@section('content')
@include('features.partials.breadcrumb')
@ -17,7 +17,8 @@
@include('features.partials.feature-show')
</div>
<div class="col-sm-8">
@include('features.partials.feature-tasks')
@include('features.partials.feature-tasks-operation')
</div>
</div>
@include('features.partials.feature-tasks')
@endsection

63
resources/views/features/unfinished.blade.php

@ -0,0 +1,63 @@
@extends('layouts.app')
@section('title', trans('project.features'))
@section('content')
<h1 class="page-header">
Daftar Fitur on Progress
</h1>
<div class="panel panel-default">
<table class="table table-condensed">
<thead>
<th>{{ trans('app.table_no') }}</th>
<th>{{ trans('project.name') }}</th>
<th>{{ trans('feature.name') }}</th>
<th class="text-center">{{ trans('feature.tasks_count') }}</th>
<th class="text-center">{{ trans('feature.progress') }}</th>
<th class="text-right">{{ trans('feature.price') }}</th>
<th>{{ trans('feature.worker') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
<tbody>
@forelse($features as $key => $feature)
<tr>
<td>{{ 1 + $key }}</td>
<td>{{ $feature->project->name }}</td>
<td>
{{ $feature->name }}
@if ($feature->tasks->isEmpty() == false)
<ul>
@foreach($feature->tasks as $task)
<li style="cursor:pointer" title="{{ $task->progress }} %">
<i class="fa fa-battery-{{ ceil(4 * $task->progress/100) }}"></i>
{{ $task->name }}
</li>
@endforeach
</ul>
@endif
</td>
<td class="text-center">{{ $feature->tasks_count = $feature->tasks->count() }}</td>
<td class="text-center">{{ formatDecimal($feature->progress = $feature->tasks->avg('progress')) }} %</td>
<td class="text-right">{{ formatRp($feature->price) }}</td>
<td>{{ $feature->worker->name }}</td>
<td>
{!! link_to_route('features.show', trans('app.show'),[$feature->id],['class' => 'btn btn-info btn-xs']) !!}
</td>
</tr>
@empty
<tr><td colspan="7">{{ trans('feature.empty') }}</td></tr>
@endforelse
</tbody>
<tfoot>
<tr>
<th class="text-right" colspan="3">Total</th>
<th class="text-center">{{ $features->sum('tasks_count') }}</th>
<th class="text-center">{{ formatDecimal($features->avg('progress')) }} %</th>
<th class="text-right">{{ formatRp($features->sum('price')) }}</th>
<th colspan="2"></th>
</tr>
</tfoot>
</table>
</div>
@endsection

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

@ -6,6 +6,7 @@
<ul class="nav" id="side-menu">
<li>{!! html_link_to_route('home', 'Dashboard', [], ['icon' => 'dashboard']) !!}</li>
@can('add_project')
<li>{!! html_link_to_route('features.index', 'On Progress Features', [], ['icon' => 'tasks']) !!}</li>
<li>
<?php $projectsCount = App\Entities\Projects\Project::select(DB::raw('status_id, count(id) as count'))
->groupBy('status_id')
@ -26,6 +27,9 @@
</li>
@endcan
@can('see_reports')
<li>{!! html_link_to_route('reports.payments.yearly', 'Penghasilan', [], ['icon' => 'line-chart']) !!}</li>
<li>{!! html_link_to_route('reports.current-credits', 'Piutang', [], ['icon' => 'money']) !!}</li>
{{--
<li>
{!! html_link_to_route('reports.payments.index', 'Laporan <span class="fa arrow"></span>', [], ['icon' => 'line-chart']) !!}
<ul class="nav nav-second-level">
@ -40,6 +44,7 @@
<li>{!! html_link_to_route('reports.current-credits', 'Piutang') !!}</li>
</ul>
</li>
--}}
@endcan
@can('manage_subscriptions')
<li>{!! html_link_to_route('subscriptions.index', trans('subscription.subscription'), [], ['icon' => 'retweet']) !!}</li>

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

@ -3,6 +3,13 @@
@section('content')
<h1 class="page-header">Dashboard</h1>
<div class="well well-sm">
{!! Form::open(['route' => 'projects.index','method'=>'get','class'=>'form-inline']) !!}
{!! Form::text('q', Request::get('q'), ['class'=>'form-control index-search-field','placeholder'=>trans('project.search'),'style' => 'width:350px']) !!}
{!! Form::submit(trans('project.search'), ['class' => 'btn btn-info btn-sm']) !!}
{!! Form::close() !!}
</div>
<div class="row">
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 1]) }}">

3
resources/views/payments/index.blade.php

@ -7,7 +7,8 @@
{!! link_to_route('payments.create', trans('payment.create'), [], ['class'=>'btn btn-success pull-right']) !!}
{{ trans('payment.payments') }} <small>{{ $payments->total() }} {{ trans('payment.found') }}</small>
</h1>
<div class="well well-sm">
<div class="well well-sm text-right">
<div class="pull-left hidden-xs">{!! str_replace('/?', '?', $payments->appends(Request::except('page'))->render()) !!}</div>
{!! Form::open(['method'=>'get','class'=>'form-inline']) !!}
{!! Form::text('q', Request::get('q'), ['class'=>'form-control index-search-field','placeholder'=>trans('payment.search'),'style' => 'width:350px']) !!}
{!! Form::submit(trans('payment.search'), ['class' => 'btn btn-info btn-sm']) !!}

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

@ -44,5 +44,4 @@
</div>
{!! Form::close() !!}
<?php // echo '<pre>$errors->toArray() : ', print_r($errors->toArray(), true), '</pre>' ?>
@endsection

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

@ -1,6 +1,6 @@
@extends('layouts.app')
@section('title', trans('project.features'))
@section('title', trans('project.features') . ' | ' . $project->name)
@section('content')
@include('projects.partials.breadcrumb',['title' => trans('project.features')])
@ -35,7 +35,10 @@
@if ($feature->tasks->isEmpty() == false)
<ul>
@foreach($feature->tasks as $task)
<li style="cursor:pointer" title="{{ $task->description }}">{{ $task->name }}</li>
<li style="cursor:pointer" title="{{ $task->progress }} %">
<i class="fa fa-battery-{{ ceil(4 * $task->progress/100) }}"></i>
{{ $task->name }}
</li>
@endforeach
</ul>
@endif
@ -45,6 +48,7 @@
<td class="text-right">{{ formatRp($feature->price) }}</td>
<td>{{ $feature->worker->name }}</td>
<td>
{!! link_to_route('features.show', trans('task.create'),[$feature->id],['class' => 'btn btn-default btn-xs']) !!}
{!! link_to_route('features.show', trans('app.show'),[$feature->id],['class' => 'btn btn-info btn-xs']) !!}
{!! link_to_route('features.edit', trans('app.edit'),[$feature->id],['class' => 'btn btn-warning btn-xs']) !!}
</td>

19
resources/views/projects/index.blade.php

@ -1,13 +1,14 @@
@extends('layouts.app')
@section('title', trans('project.projects'))
@section('title', 'Daftar ' . $status . ' Project')
@section('content')
<h1 class="page-header">
{!! link_to_route('projects.create', trans('project.create'), [], ['class'=>'btn btn-success pull-right']) !!}
Daftar {{ $status }} Project <small>{{ $projects->total() }} {{ trans('project.found') }}</small>
</h1>
<div class="well well-sm">
<div class="well well-sm text-right">
<div class="pull-left hidden-xs">{!! str_replace('/?', '?', $projects->appends(Request::except('page'))->render()) !!}</div>
{!! Form::open(['method'=>'get','class'=>'form-inline']) !!}
{!! Form::text('q', Request::get('q'), ['class'=>'form-control index-search-field','placeholder'=>trans('project.search'),'style' => 'width:350px']) !!}
{!! Form::submit(trans('project.search'), ['class' => 'btn btn-info btn-sm']) !!}
@ -19,11 +20,11 @@
<th>{{ trans('app.table_no') }}</th>
<th>{{ trans('project.name') }}</th>
<th class="text-center">{{ trans('project.start_date') }}</th>
<th class="text-center">{{ trans('project.end_date') }}</th>
<th class="text-center">{{ trans('project.work_duration') }}</th>
<th class="text-center">{{ trans('project.payments') }}</th>
<th class="text-right">{{ trans('project.project_value') }}</th>
{{-- <th class="text-center">{{ trans('project.payments') }}</th> --}}
{{-- <th class="text-right">{{ trans('project.project_value') }}</th> --}}
<th class="text-center">{{ trans('app.status') }}</th>
<th>{{ trans('project.customer') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
<tbody>
@ -32,11 +33,11 @@
<td>{{ $projects->firstItem() + $key }}</td>
<td>{{ $project->name }}</td>
<td class="text-center">{{ $project->start_date }}</td>
<td class="text-center">{{ $project->end_date }}</td>
<td class="text-right">{{ dateDifference($project->start_date,$project->end_date) }}</td>
<td class="text-center">{{ $project->payments_count }}</td>
<td class="text-right">{{ formatRp($project->project_value) }}</td>
<td class="text-right">{{ $project->present()->workDuration }}</td>
{{-- <td class="text-center">{{ $project->payments_count }}</td> --}}
{{-- <td class="text-right">{{ formatRp($project->project_value) }}</td> --}}
<td class="text-center">{{ $project->present()->status }}</td>
<td>{{ $project->customer->name }}</td>
<td>
{!! link_to_route('projects.show',trans('app.show'),[$project->id],['class'=>'btn btn-info btn-xs']) !!}
{!! link_to_route('projects.edit',trans('app.edit'),[$project->id],['class'=>'btn btn-warning btn-xs']) !!}

6
resources/views/projects/partials/project-show.blade.php

@ -4,7 +4,7 @@
<table class="table table-condensed">
<tbody>
<tr><td>{{ trans('project.name') }}</td><td>{{ $project->name }}</td></tr>
<tr><td>{{ trans('project.description') }}</td><td>{{ $project->description }}</td></tr>
<tr><td>{{ trans('project.description') }}</td><td>{!! nl2br($project->description) !!}</td></tr>
<tr><td>{{ trans('project.proposal_date') }}</td><td>{{ dateId($project->proposal_date) }}</td></tr>
<tr><td>{{ trans('project.proposal_value') }}</td><td class="text-right">{{ formatRp($project->proposal_value) }}</td></tr>
<tr><td>{{ trans('project.project_value') }}</td><td class="text-right">{{ formatRp($project->project_value) }}</td></tr>
@ -23,8 +23,4 @@
</tbody>
</table>
</div>
<div class="panel-footer">
{!! link_to_route('projects.edit', trans('project.edit'), [$project->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('projects.index', trans('project.back_to_index'), ['status' => $project->status_id], ['class' => 'btn btn-default']) !!}
</div>
</div>

2
resources/views/projects/payments.blade.php

@ -1,6 +1,6 @@
@extends('layouts.app')
@section('title', trans('project.payments'))
@section('title', trans('project.payments') . ' | ' . $project->name)
@section('content')
@include('projects.partials.breadcrumb',['title' => trans('project.payments')])

16
resources/views/projects/show.blade.php

@ -1,11 +1,17 @@
@extends('layouts.app')
@section('title', trans('project.show'))
@section('title', trans('project.show') . ' | ' . $project->name)
@section('content')
@include('projects.partials.breadcrumb')
<h1 class="page-header">{{ $project->name }} <small>{{ trans('project.show') }}</small></h1>
<h1 class="page-header">
<div class="pull-right">
{!! link_to_route('projects.edit', trans('project.edit'), [$project->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('projects.index', trans('project.back_to_index'), ['status' => $project->status_id], ['class' => 'btn btn-default']) !!}
</div>
{{ $project->name }} <small>{{ trans('project.show') }}</small>
</h1>
@include('projects.partials.nav-tabs')
@ -13,5 +19,11 @@
<div class="col-md-6">
@include('projects.partials.project-show')
</div>
<div class="col-md-6">
{!! Form::model($project, ['route' => ['projects.status-update', $project->id], 'method' => 'patch','class' => 'well well-sm form-inline']) !!}
{!! FormField::select('status_id', getProjectStatusesList(), ['label' => trans('project.status')]) !!}
{!! Form::submit('Update Project Status', ['class' => 'btn btn-info']) !!}
{!! Form::close() !!}
</div>
</div>
@endsection

2
resources/views/reports/current-credits.blade.php

@ -21,7 +21,7 @@
@forelse($projects as $key => $project)
<tr>
<td>{{ 1 + $key }}</td>
<td>{!! link_to_route('projects.payments',$project->name,[$project->id],['title' => 'Lihat Detail Pembayaran','target' => '_blank']) !!}</td>
<td>{!! link_to_route('projects.payments',$project->name,[$project->id],['title' => 'Lihat Daftar Pembayaran','target' => '_blank']) !!}</td>
<td class="text-right">{{ formatRp($project->project_value) }}</td>
<td class="text-right">{{ formatRp($project->cashInTotal()) }}</td>
<td class="text-right">{{ formatRp($project->balance = $project->project_value - $project->cashInTotal()) }}</td>

6
resources/views/reports/payments/yearly.blade.php

@ -51,7 +51,7 @@
<td class="text-right">{{ formatRp($report->cashin) }}</td>
<td class="text-right">{{ formatRp($report->cashout) }}</td>
<td class="text-right">{{ formatRp(($report->cashin - $report->cashout)) }}</td>
<td class="text-center">{!! link_to_route('reports.payments.monthly','Lihat Bulanan',['month' => monthNumber($report->month), 'year' => $year] , ['class'=>'btn btn-info btn-xs','title'=>'Lihat laporan bulanan ' . monthId($report->month)]) !!}</td>
<td class="text-center">{!! link_to_route('reports.payments.monthly','Lihat Bulanan', ['month' => monthNumber($report->month), 'year' => $year], ['class'=>'btn btn-info btn-xs','title'=>'Lihat laporan bulanan ' . monthId($report->month)]) !!}</td>
</tr>
<?php
$invoicesCount += $report->count;
@ -97,7 +97,9 @@
xkey: 'month',
ykeys: ['value'],
labels: ['Profit'],
parseTime:false
parseTime:false,
goals: [0],
goalLineColors : ['red'],
});
})();
</script>

33
tests/ManageFeaturesTest.php

@ -92,6 +92,13 @@ class ManageFeaturesTest extends TestCase
$project = factory(Project::class)->create(['owner_id' => $user->id]);
$feature = factory(Feature::class)->create(['project_id' => $project->id]);
$tasks = factory(Task::class, 2)->create(['feature_id' => $feature->id]);
$this->seeInDatabase('features', [
'name' => $feature->name,
'price' => $feature->price,
'project_id' => $project->id,
]);
$this->visit('projects/' . $feature->project_id . '/features');
$this->click(trans('app.show'));
@ -100,6 +107,16 @@ class ManageFeaturesTest extends TestCase
$this->press(trans('app.delete_confirm_button'));
$this->seePageIs('projects/' . $project->id . '/features');
$this->see(trans('feature.deleted'));
$this->notSeeInDatabase('features', [
'name' => $feature->name,
'price' => $feature->price,
'project_id' => $project->id,
]);
$this->notSeeInDatabase('tasks', [
'feature_id' => $feature->id,
]);
}
/** @test */
@ -206,4 +223,20 @@ class ManageFeaturesTest extends TestCase
// 'worker_id' => $features[1]->worker_id,
// ]);
}
/** @test */
public function admin_can_see_unfinished_features_list()
{
$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'=> array_rand($projects->lists('id','id')->all())]);
// $tasks = factory(Task::class, 10)->create(['feature_id'=> array_rand($features->lists('id','id')->all())]);
$this->visit('features');
$this->seePageIs('features');
}
}

23
tests/ManagePaymentsTest.php

@ -151,11 +151,32 @@ class ManagePaymentsTest extends TestCase
$payments = factory(Payment::class, 5)->create(['owner_id' => $user->id]);
$this->assertEquals(5, $payments->count());
$this->visit('/payments');
$this->visit(route('payments.index'));
$this->seePageIs(route('payments.index'));
$this->see($payments[4]->project->name);
$this->see($payments[4]->date);
$this->see(formatRp($payments[4]->amount));
$this->see($payments[4]->description);
$this->see($payments[4]->customer->name);
}
/** @test */
public function admin_can_search_payment_by_customer_name()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
$this->actingAs($user);
$payments = factory(Payment::class, 5)->create(['owner_id' => $user->id]);
$this->assertEquals(5, $payments->count());
$this->visit(route('payments.index'));
$firstName = explode(' ', $payments[0]->project->name)[0];
$this->type($firstName, 'q');
$this->press(trans('payment.search'));
$this->seePageIs(route('payments.index', ['q' => $firstName]));
$this->see($payments[0]->project->name);
}
}

71
tests/ManageProjectsTest.php

@ -1,6 +1,9 @@
<?php
use App\Entities\Payments\Payment;
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;
@ -19,17 +22,17 @@ class ManageProjectsTest extends TestCase
$users[1]->assignRole('customer');
$this->visit('/projects');
$this->seePageIs('/projects');
$this->visit(route('projects.index'));
$this->seePageIs(route('projects.index'));
$this->click(trans('project.create'));
$this->seePageIs('/projects/create');
$this->seePageIs(route('projects.create'));
$this->type('Project Baru','name');
$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');
$this->press(trans('project.create'));
$this->seePageIs('/projects');
$this->see(trans('project.created'));
$this->see('Project Baru');
$this->seeInDatabase('projects', ['name' => 'Project Baru', 'proposal_value' => '2000000']);
@ -42,10 +45,10 @@ class ManageProjectsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$this->visit('/projects');
$this->seePageIs('/projects');
$this->visit(route('projects.index'));
$this->seePageIs(route('projects.index'));
$this->click(trans('project.create'));
$this->seePageIs('/projects/create');
$this->seePageIs(route('projects.create'));
// Invalid entry
$this->type('Project Baru','name');
@ -54,13 +57,12 @@ class ManageProjectsTest extends TestCase
$this->type('2000000','proposal_value');
$this->type('Deskripsi project baru','description');
$this->press(trans('project.create'));
$this->seePageIs('/projects/create');
$this->seePageIs(route('projects.create'));
$this->notSeeInDatabase('projects', ['name' => 'Project Baru', 'proposal_value' => '2000000']);
$this->type('Customer Baru','customer_name');
$this->type('email@customer.baru','customer_email');
$this->press(trans('project.create'));
$this->seePageIs('/projects');
$this->see(trans('project.created'));
$this->see('Project Baru');
$this->seeInDatabase('users', ['name' => 'Customer Baru', 'email' => 'email@customer.baru']);
@ -76,12 +78,34 @@ class ManageProjectsTest extends TestCase
$this->actingAs($user);
$project = factory(Project::class)->create(['owner_id' => $user->id]);
$feature = factory(Feature::class)->create(['project_id' => $project->id]);
$task = factory(Task::class)->create(['feature_id' => $feature->id]);
$payment = factory(Payment::class)->create(['project_id' => $project->id]);
$this->visit('/projects?status=' . $project->status_id);
$this->click(trans('app.edit'));
$this->click(trans('app.delete'));
$this->press(trans('app.delete_confirm_button'));
$this->seePageIs('projects');
$this->see(trans('project.deleted'));
$this->notSeeInDatabase('projects', [
'name' => $project->name,
'proposal_value' => $project->proposal_value,
'owner_id' => $user->id,
]);
$this->notSeeInDatabase('payments', [
'project_id' => $project->id,
]);
$this->notSeeInDatabase('features', [
'project_id' => $project->id,
]);
$this->notSeeInDatabase('tasks', [
'feature_id' => $feature->id,
]);
}
/** @test */
@ -128,18 +152,39 @@ class ManageProjectsTest extends TestCase
$users[1]->assignRole('customer');
$this->visit('/projects');
$this->seePageIs('/projects');
$this->visit(route('projects.index'));
$this->seePageIs(route('projects.index'));
$this->click(trans('project.create'));
$this->seePageIs('/projects/create');
$this->seePageIs(route('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->seePageIs(route('projects.create'));
$this->see('Mohon periksa kembali form isian Anda.');
}
/** @test */
public function admin_can_update_project_status_on_project_detail_page()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
$this->actingAs($user);
$project = factory(Project::class)->create(['owner_id' => $user->id, 'status_id' => 1]);
$this->visit(route('projects.show', $project->id));
$this->seePageIs(route('projects.show', $project->id));
$this->select(2, 'status_id');
$this->press('Update Project Status');
$this->see(trans('project.updated'));
$this->seePageIs(route('projects.show', $project->id));
$this->seeInDatabase('projects', [
'id' => $project->id,
'status_id' => 2,
]);
}
}

10
tests/ManageTasksTest.php

@ -29,6 +29,7 @@ class ManageTasksTest extends TestCase
$this->type('Nama Task Baru','name');
$this->type('Ipsam magnam laboriosam distinctio officia facere sapiente eius corporis','description');
$this->type(70,'progress');
$this->type('tasks/create','route_name');
$this->press(trans('task.create'));
$this->seePageIs('features/' . $feature->id);
@ -36,7 +37,8 @@ class ManageTasksTest extends TestCase
$this->seeInDatabase('tasks', [
'name' => 'Nama Task Baru',
'progress' => 70,
'feature_id' => $feature->id
'feature_id' => $feature->id,
'route_name' => 'tasks/create',
]);
}
@ -60,6 +62,7 @@ class ManageTasksTest extends TestCase
// Fill Form
$this->type('Nama Task Edit','name');
$this->type('tasks/{id}/edit','route_name');
$this->type(77,'progress');
$this->press(trans('task.update'));
@ -68,7 +71,8 @@ class ManageTasksTest extends TestCase
$this->seeInDatabase('tasks', [
'name' => 'Nama Task Edit',
'progress' => 77,
'feature_id' => $feature->id
'feature_id' => $feature->id,
'route_name' => 'tasks/{id}/edit',
]);
}
@ -109,8 +113,10 @@ class ManageTasksTest extends TestCase
$this->see($tasks[1]->name);
$this->see($tasks[1]->progress);
$this->see($tasks[1]->description);
$this->see($tasks[1]->route_name);
$this->see($tasks[4]->name);
$this->see($tasks[4]->progress);
$this->see($tasks[4]->description);
$this->see($tasks[4]->route_name);
}
}
Loading…
Cancel
Save