Browse Source

Update 2016-07-11.15.10

Use autoNumeric thousand separator for payment and feature prices entry
Reformat Project Payments View to count payment status are closed or not
Add current credit report
Add projects count summary based on status on dashboard page
Fix Features, Payments, Projects, and subscriptions test fiel
pull/1/head
Nafies Luthfi 10 years ago
parent
commit
2121e32131
  1. 20
      app/Entities/Payments/PaymentsRepository.php
  2. 13
      app/Entities/Projects/FeaturesRepository.php
  3. 14
      app/Entities/Projects/Project.php
  4. 9
      app/Entities/Reports/ReportsRepository.php
  5. 5
      app/Http/Controllers/PagesController.php
  6. 10
      app/Http/Controllers/PaymentsController.php
  7. 3
      app/Http/Controllers/Projects/ProjectsController.php
  8. 6
      app/Http/Controllers/ReportsController.php
  9. 2
      app/Http/Requests/Features/CreateRequest.php
  10. 2
      app/Http/Requests/Features/UpdateRequest.php
  11. 2
      app/Http/Requests/Payments/CreateRequest.php
  12. 2
      app/Http/Requests/Payments/UpdateRequest.php
  13. 1
      app/Http/routes/reports.php
  14. 4
      app/Providers/AppServiceProvider.php
  15. 2
      app/Services/FormField.php
  16. 22
      public/assets/css/app.css
  17. 2
      public/assets/css/app.css.map
  18. 32
      public/assets/js/sb-admin-2.js
  19. 6
      resources/assets/sass/_sb-admin-2.scss
  20. 25
      resources/assets/sass/app.scss
  21. 2
      resources/lang/id/payment.php
  22. 3
      resources/lang/id/project.php
  23. 2
      resources/views/auth/login.blade.php
  24. 16
      resources/views/features/create.blade.php
  25. 16
      resources/views/features/edit.blade.php
  26. 22
      resources/views/features/partials/feature-show.blade.php
  27. 2
      resources/views/layouts/app.blade.php
  28. 15
      resources/views/layouts/partials/sidebar.blade.php
  29. 122
      resources/views/pages/home.blade.php
  30. 38
      resources/views/payments/create.blade.php
  31. 28
      resources/views/payments/edit.blade.php
  32. 2
      resources/views/payments/index.blade.php
  33. 3
      resources/views/payments/partials/payment-show.blade.php
  34. 7
      resources/views/payments/show.blade.php
  35. 2
      resources/views/projects/edit.blade.php
  36. 4
      resources/views/projects/partials/nav-tabs.blade.php
  37. 1
      resources/views/projects/partials/project-show.blade.php
  38. 101
      resources/views/projects/payments.blade.php
  39. 43
      resources/views/reports/current-credits.blade.php
  40. 1
      resources/views/reports/payments/daily.blade.php
  41. 14
      resources/views/subscriptions/index.blade.php
  42. 2
      resources/views/subscriptions/show.blade.php
  43. 4
      tests/ManageFeaturesTest.php
  44. 51
      tests/ManagePaymentsTest.php
  45. 2
      tests/ManageProjectsTest.php
  46. 18
      tests/ManageSubscriptionsTest.php

20
app/Entities/Payments/PaymentsRepository.php

@ -19,6 +19,26 @@ class PaymentsRepository extends BaseRepository
public function getAll($q)
{
return $this->model->orderBy('date','desc')
->with('customer','project')
->paginate($this->_paginate);
}
public function create($paymentData)
{
$paymentData['owner_id'] = auth()->id();
$paymentData['amount'] = str_replace('.', '', $paymentData['amount']);
return $this->storeArray($paymentData);
}
public function update($paymentData = [], $paymentId)
{
foreach ($paymentData as $key => $value) {
if (!$paymentData[$key]) $paymentData[$key] = null;
}
$paymentData['amount'] = str_replace('.', '', $paymentData['amount']);
$payment = $this->requireById($paymentId);
$payment->update($paymentData);
return $payment;
}
}

13
app/Entities/Projects/FeaturesRepository.php

@ -25,6 +25,7 @@ class FeaturesRepository extends BaseRepository
public function createFeature($featureData, $projectId)
{
$featureData['project_id'] = $projectId;
$featureData['price'] = str_replace('.', '', $featureData['price']);
return $this->storeArray($featureData);
}
@ -37,4 +38,16 @@ class FeaturesRepository extends BaseRepository
{
return Task::findOrFail($taskId);
}
public function update($featureData = [], $featureId)
{
foreach ($featureData as $key => $value) {
if (!$featureData[$key]) $featureData[$key] = null;
}
$featureData['price'] = str_replace('.', '', $featureData['price']);
$feature = $this->requireById($featureId);
$feature->update($featureData);
return $feature;
}
}

14
app/Entities/Projects/Project.php

@ -31,4 +31,18 @@ class Project extends Model {
return $this->belongsTo(User::class,'customer_id');
}
public function cashInTotal()
{
return $this->payments->sum(function($payment) {
return $payment->type == 1 ? $payment->amount : 0;
});
}
public function cashOutTotal()
{
return $this->payments->sum(function($payment) {
return $payment->type == 0 ? $payment->amount : 0;
});
}
}

9
app/Entities/Reports/ReportsRepository.php

@ -4,6 +4,7 @@ namespace App\Entities\Reports;
use App\Entities\BaseRepository;
use App\Entities\Payments\Payment;
use App\Entities\Projects\Project;
use DB;
/**
@ -46,4 +47,12 @@ class ReportsRepository extends BaseRepository
->get();
}
public function getCurrentCredits()
{
$projects = Project::whereIn('status_id',[3,6])->with('payments')->get();
return $projects->filter(function($project) {
return $project->cashInTotal() < $project->project_value;
})->values();
}
}

5
app/Http/Controllers/PagesController.php

@ -15,10 +15,7 @@ class PagesController extends Controller {
public function home()
{
$totalIncome = $this->repo->getTotalIncome();
$totalExpenditure = $this->repo->getTotalExpenditure();
return view('pages.home', compact('totalIncome','totalExpenditure'));
return view('pages.home');
}
public function about()

10
app/Http/Controllers/PaymentsController.php

@ -36,7 +36,7 @@ class PaymentsController extends Controller {
{
$payment = $this->repo->create($req->except('_token'));
flash()->success(trans('payment.created'));
return redirect()->route('payments.show', $payment->id);
return redirect()->route('projects.payments', $payment->project_id);
}
public function show($paymentId)
@ -57,7 +57,7 @@ class PaymentsController extends Controller {
{
$payment = $this->repo->update($req->except(['_method','_token']), $paymentId);
flash()->success(trans('payment.updated'));
return redirect()->route('payments.edit', $paymentId);
return redirect()->route('payments.show', $paymentId);
}
public function delete($paymentId)
@ -68,15 +68,17 @@ class PaymentsController extends Controller {
public function destroy(DeleteRequest $req, $paymentId)
{
$payment = $this->repo->requireById($paymentId);
$projectId = $payment->project_id;
if ($paymentId == $req->get('payment_id'))
{
$this->repo->delete($paymentId);
$payment->delete();
flash()->success(trans('payment.deleted'));
}
else
flash()->error(trans('payment.undeleted'));
return redirect()->route('payments.index');
return redirect()->route('projects.payments', $projectId);
}
}

3
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');
$statusId = $req->get('status', 3);
if ($statusId) {
$status = $this->repo->getStatusName($statusId);
}
@ -94,6 +94,7 @@ class ProjectsController extends Controller {
public function payments($projectId)
{
$project = $this->repo->requireById($projectId);
$project->load('payments.customer');
return view('projects.payments', compact('project'));
}

6
app/Http/Controllers/ReportsController.php

@ -55,4 +55,10 @@ class ReportsController extends Controller {
return view('reports.payments.yearly', compact('reports','years','year'));
}
public function currentCredits()
{
$projects = $this->repo->getCurrentCredits();
return view('reports.current-credits', compact('projects'));
}
}

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

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

2
app/Http/Requests/Features/UpdateRequest.php

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

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

@ -26,7 +26,7 @@ class CreateRequest extends Request {
return [
'date' => 'required|date|date_format:Y-m-d',
'type' => 'required|numeric',
'amount' => 'required|numeric',
'amount' => 'required',
'project_id' => 'required|numeric',
'customer_id' => 'required|numeric',
'description' => 'required|max:255',

2
app/Http/Requests/Payments/UpdateRequest.php

@ -26,7 +26,7 @@ class UpdateRequest extends Request {
return [
'date' => 'required|date|date_format:Y-m-d',
'type' => 'required|numeric',
'amount' => 'required|numeric',
'amount' => 'required',
'project_id' => 'required|numeric',
'customer_id' => 'required|numeric',
'description' => 'required|max:255',

1
app/Http/routes/reports.php

@ -8,4 +8,5 @@ Route::group(['middleware' => ['web','role:admin'],'prefix' => 'reports'], funct
Route::get('payments/daily', ['as'=>'reports.payments.daily', 'uses' => 'ReportsController@daily']);
Route::get('payments/monthly', ['as'=>'reports.payments.monthly', 'uses' => 'ReportsController@monthly']);
Route::get('payments/yearly', ['as'=>'reports.payments.yearly', 'uses' => 'ReportsController@yearly']);
Route::get('current-credits', ['as'=>'reports.current-credits', 'uses' => 'ReportsController@currentCredits']);
});

4
app/Providers/AppServiceProvider.php

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

2
app/Services/FormField.php

@ -291,10 +291,8 @@ class FormField
public function price($name, $options = [])
{
$options['type'] = 'number';
$options['addon'] = ['before' => isset($options['currency']) ? $options['currency'] : 'Rp'];
$options['class'] = 'text-right';
$options['min'] = '0';
return $this->text($name, $options);
}

22
public/assets/css/app.css

@ -6452,11 +6452,15 @@ body {
.sidebar .active > a > .fa.arrow:before {
content: "\f107"; }
.sidebar .nav-second-level li,
.sidebar .nav-third-level li {
border-bottom: 0 !important; }
.sidebar .nav-second-level li a {
padding-left: 37px; }
padding-left: 30px; }
.sidebar .nav-third-level li a {
padding-left: 52px; }
padding-left: 45px; }
@media (min-width: 768px) {
.sidebar {
@ -6666,7 +6670,7 @@ h1.page-header {
font-weight: bold; }
.sidebar-logo {
width: 150px;
width: 100px;
margin: auto; }
.nav > li > a {
@ -6686,7 +6690,7 @@ label.control-label {
@media (min-width: 768px) {
#page-wrapper {
margin-left: 220px;
margin-left: 200px;
padding: 0; }
/*
.hidden-xs {
@ -6698,7 +6702,7 @@ label.control-label {
margin-left: 0; }
.sidebar {
margin-top: 0px;
width: 220px;
width: 200px;
box-shadow: none; }
.index-search-form {
width: 50%; }
@ -6741,13 +6745,15 @@ h3.site-description {
.panel .table {
margin-bottom: 0; }
.panel .lead {
margin-bottom: 0; }
@media (max-width: 480px) {
.guest-header {
text-align: center; } }
.nav .nav-second-level > li.active {
text-decoration: none;
background-color: #eee; }
.nav .nav-second-level li.active {
text-decoration: none; }
.form-control {
height: 30px;

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

32
public/assets/js/sb-admin-2.js

@ -8,21 +8,21 @@ $(function() {
//collapses the sidebar on window resize.
// Sets the min-height of #page-wrapper to window size
$(function() {
$(window).bind("load resize", function() {
topOffset = 50;
width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
if (width < 768) {
$('div.navbar-collapse').addClass('collapse')
topOffset = 100; // 2-row-menu
} else {
$('div.navbar-collapse').removeClass('collapse')
}
// $(window).bind("load resize", function() {
// topOffset = 50;
// width = (this.window.innerWidth > 0) ? this.window.innerWidth : this.screen.width;
// if (width < 768) {
// $('div.navbar-collapse').addClass('collapse')
// topOffset = 100; // 2-row-menu
// } else {
// $('div.navbar-collapse').removeClass('collapse')
// }
height = (this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height;
height = height - topOffset;
if (height < 1) height = 1;
if (height > topOffset) {
$("#page-wrapper").css("min-height", (height) + "px");
}
})
// height = (this.window.innerHeight > 0) ? this.window.innerHeight : this.screen.height;
// height = height - topOffset;
// if (height < 1) height = 1;
// if (height > topOffset) {
// $("#page-wrapper").css("min-height", (height) + "px");
// }
// })
});

6
resources/assets/sass/_sb-admin-2.scss

@ -116,15 +116,15 @@ body {
.sidebar .nav-second-level li,
.sidebar .nav-third-level li {
// border-bottom: 0!important;
border-bottom: 0!important;
}
.sidebar .nav-second-level li a {
padding-left: 37px;
padding-left: 30px;
}
.sidebar .nav-third-level li a {
padding-left: 52px;
padding-left: 45px;
}
@media(min-width:768px) {

25
resources/assets/sass/app.scss

@ -20,7 +20,6 @@ ul, ol {
}
#wrapper {
// border-top: 2px solid #e7e7e7;
}
.breadcrumb {
@ -45,7 +44,7 @@ h1.page-header {
}
.sidebar-logo {
width: 150px;
width: 100px;
margin: auto;
}
@ -70,7 +69,7 @@ label.control-label {
@media(min-width:768px) {
#page-wrapper {
margin-left: 220px;
margin-left: 200px;
padding: 0;
}
/*
@ -88,7 +87,7 @@ label.control-label {
.sidebar {
margin-top: 0px;
width: 220px;
width: 200px;
box-shadow: none;
}
@ -141,8 +140,13 @@ h3.site-description {
padding: 0 10px;
}
.panel .table {
margin-bottom: 0;
.panel {
.table {
margin-bottom: 0;
}
.lead {
margin-bottom: 0;
}
}
@media (max-width: 480px) {
@ -151,9 +155,12 @@ h3.site-description {
}
}
.nav .nav-second-level>li.active {
text-decoration: none;
background-color: #eee;
.nav {
.nav-second-level {
li.active {
text-decoration: none;
}
}
}
.form-control {

2
resources/lang/id/payment.php

@ -24,5 +24,7 @@ return [
'project' => 'Project',
'customer' => 'Dari/Kepada',
'amount' => 'Jumlah',
'cash_in' => 'Pemasukan',
'cash_out' => 'Pengeluaran',
'payer' => 'Pembayar',
];

3
resources/lang/id/project.php

@ -20,9 +20,12 @@ return [
'project_value' => 'Nilai Project',
'proposal_value' => 'Nilai Proposal',
'work_duration' => 'Durasi',
'cash_in_total' => 'Total Pemasukan',
'cash_out_total' => 'Total Pengeluaran',
'customer' => 'Customer',
'features' => 'Daftar Fitur',
'worker' => 'Pekerja',
'status' => 'Status Project',
'payments' => 'Pembayaran',
'search' => 'Cari Project',
'found' => 'Project ditemukan',

2
resources/views/auth/login.blade.php

@ -7,7 +7,7 @@
<div class="text-center">
<img src="{{ url('assets/imgs/logo.png') }}" alt="Logo {{ Option::get('app_owner') }}">
</div>
<h3 class="text-center">{{ Option::get('app_title','Aplikasi Laravel') }}</h3>
<h3 class="text-center">{{ Option::get('app_name','Aplikasi Laravel') }}</h3>
<div class="panel panel-default">
<div class="panel-body">
@include('flash::message')

16
resources/views/features/create.blade.php

@ -34,4 +34,20 @@
@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

16
resources/views/features/edit.blade.php

@ -35,4 +35,20 @@
@include('projects.partials.project-show', ['project' => $feature->project])
</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

22
resources/views/features/partials/feature-show.blade.php

@ -1,17 +1,15 @@
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('feature.show') }}</h3></div>
<div class="panel-body">
<table class="table table-condensed">
<tbody>
<tr><th>{{ trans('feature.name') }}</th><td>{{ $feature->name }}</td></tr>
<tr><th>{{ trans('feature.price') }}</th><td>{{ formatRp($feature->price) }}</td></tr>
<tr><th>{{ trans('feature.tasks_count') }}</th><td>{{ $feature->tasks->count() }}</td></tr>
<tr><th>{{ trans('feature.progress') }}</th><td>{{ formatDecimal($feature->tasks->avg('progress')) }}%</td></tr>
<tr><th>{{ trans('feature.worker') }}</th><td>{{ $feature->worker->name }}</td></tr>
<tr><th>{{ trans('feature.description') }}</th><td>{!! nl2br($feature->description) !!}</td></tr>
</tbody>
</table>
</div>
<table class="table table-condensed">
<tbody>
<tr><th>{{ trans('feature.name') }}</th><td>{{ $feature->name }}</td></tr>
<tr><th>{{ trans('feature.price') }}</th><td>{{ formatRp($feature->price) }}</td></tr>
<tr><th>{{ trans('feature.tasks_count') }}</th><td>{{ $feature->tasks->count() }}</td></tr>
<tr><th>{{ trans('feature.progress') }}</th><td>{{ formatDecimal($feature->tasks->avg('progress')) }}%</td></tr>
<tr><th>{{ trans('feature.worker') }}</th><td>{{ $feature->worker->name }}</td></tr>
<tr><th>{{ trans('feature.description') }}</th><td>{!! nl2br($feature->description) !!}</td></tr>
</tbody>
</table>
<div class="panel-footer">
{!! link_to_route('features.edit', trans('feature.edit'), [$feature->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('projects.features', trans('feature.back_to_index'), [$feature->project_id], ['class' => 'btn btn-default']) !!}

2
resources/views/layouts/app.blade.php

@ -27,7 +27,7 @@
<!-- /.container-fluid -->
</div>
<!-- /#page-wrapper -->
{{-- @include('layouts.partials.footer') --}}
@include('layouts.partials.footer')
</div>
<!-- /#wrapper -->

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

@ -4,20 +4,19 @@
{!! Html::image(url('assets/imgs/logo.png'),'Logo ' . Option::get('app_name','Laravel'), ['class' => 'sidebar-logo']) !!}
</a>
<ul class="nav" id="side-menu">
<li>{!! html_link_to_route('home', 'Home', [], ['icon' => 'home']) !!}</li>
<li>{!! html_link_to_route('home', 'Dashboard', [], ['icon' => 'dashboard']) !!}</li>
@can('manage_projects')
<li>
{!! html_link_to_route('projects.index', trans('project.projects') . ' <span class="fa arrow"></span>', [], ['icon' => 'table']) !!}
<ul class="nav nav-second-level in">
<ul class="nav nav-second-level">
@foreach(getProjectStatusesList() as $key => $status)
<li>
<a href="{{ route('projects.index', ['status' => $key]) }}">
{{ $status }}
<span class="badge pull-right">{{ in_array($key, array_keys($projectCounts)) ? $projectCounts[$key] : 0 }}</span>
<span class="badge pull-right">{{ array_key_exists($key, $projectsCount) ? $projectsCount[$key] : 0 }}</span>
</a>
</li>
@endforeach
<li>{!! html_link_to_route('projects.index', 'Semua Project') !!}</li>
</ul>
</li>
@endcan
@ -33,6 +32,7 @@
<li>{!! link_to_route('reports.payments.daily', 'Harian') !!}</li>
</ul>
</li>
<li>{!! html_link_to_route('reports.current-credits', 'Piutang') !!}</li>
</ul>
</li>
@endcan
@ -40,12 +40,7 @@
<li>{!! html_link_to_route('subscriptions.index', trans('subscription.subscription'), [], ['icon' => 'retweet']) !!}</li>
@endcan
@can('manage_payments')
<li>
{!! html_link_to_route('payments.index', trans('payment.payments') . ' <span class="fa arrow"></span>', [], ['icon' => 'money']) !!}
<ul class="nav nav-second-level">
<li>{!! link_to_route('payments.index', trans('payment.payments')) !!}</li>
</ul>
</li>
<li>{!! html_link_to_route('payments.index', trans('payment.payments'), [], ['icon' => 'money']) !!}</li>
@endcan
@can('manage_users')
<li>

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

@ -1,66 +1,116 @@
@extends('layouts.app')
@section('content')
<br>
<div class="alert alert-info">
{{ trans('app.welcome') }}
<strong>{{ auth()->user()->name }}</strong> | {{ auth()->user()->present()->usernameRoles }}
</div>
<h1 class="page-header">Dashboard</h1>
<div class="row">
<div class="col-md-4">
<div class="panel panel-primary">
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 1]) }}">
<div class="panel panel-default">
<div class="panel-heading">
<div class="row">
<div class="col-xs-12 text-right">
<div class="huge">{{ formatRp($totalIncome) }}</div>
<div class="col-xs-3"><i class="fa fa-thumb-tack 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>
</div>
</div>
</div>
<a href="#">
<div class="panel-footer">
<span class="pull-left">Income Total</span>
<span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
<div class="clearfix"></div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 2]) }}">
<div class="panel panel-yellow">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3"><i class="fa fa-tasks fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(2, $projectsCount) ? $projectsCount[2] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(2) }}</div>
</div>
</div>
</a>
</div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
<div class="col-md-4">
<div class="panel panel-info">
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 3]) }}">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<div class="col-xs-12 text-right">
<div class="huge">{{ formatRp($totalExpenditure) }}</div>
<div class="col-xs-3"><i class="fa fa-thumbs-o-up fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(3, $projectsCount) ? $projectsCount[3] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(3) }}</div>
</div>
</div>
</div>
<a href="#">
<div class="panel-footer">
<span class="pull-left">Expenditure Total</span>
<span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
<div class="clearfix"></div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 4]) }}">
<div class="panel panel-green">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3"><i class="fa fa-money fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(4, $projectsCount) ? $projectsCount[4] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(4) }}</div>
</div>
</div>
</a>
</div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
<div class="col-md-4">
<div class="panel panel-success">
<div class="col-lg-3 col-md-6 col-lg-offset-3">
<a href="{{ route('projects.index',['status' => 5]) }}">
<div class="panel panel-danger">
<div class="panel-heading">
<div class="row">
<div class="col-xs-12 text-right">
<div class="huge">{{ formatRp($totalIncome - $totalExpenditure) }}</div>
<div class="col-xs-3"><i class="fa fa-thumbs-o-down fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(5, $projectsCount) ? $projectsCount[5] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(5) }}</div>
</div>
</div>
</div>
<a href="#">
<div class="panel-footer">
<span class="pull-left">Profit Total</span>
<span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
<div class="clearfix"></div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
<div class="col-lg-3 col-md-6">
<a href="{{ route('projects.index',['status' => 6]) }}">
<div class="panel panel-warning">
<div class="panel-heading">
<div class="row">
<div class="col-xs-3"><i class="fa fa-hand-stop-o fa-5x"></i></div>
<div class="col-xs-9 text-right">
<div class="huge">{{ array_key_exists(6, $projectsCount) ? $projectsCount[6] : 0 }}</div>
<div class="lead">{{ getProjectStatusesList(6) }}</div>
</div>
</div>
</a>
</div>
<div class="panel-footer">
View Details <span class="pull-right"><i class="fa fa-arrow-circle-right"></i></span>
</div>
</div>
</a>
</div>
</div>
</div>
@endsection

38
resources/views/payments/create.blade.php

@ -5,7 +5,7 @@
@section('content')
<div class="row">
<div class="col-md-4">
<div class="col-md-6">
{!! Form::open(['route'=>'payments.store']) !!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('payment.create') }}</h3></div>
@ -19,8 +19,14 @@
{!! FormField::price('amount', ['label'=> trans('payment.amount')]) !!}
</div>
</div>
{!! FormField::select('project_id', $projects, ['label'=> trans('payment.project'),'value' => Request::get('project_id')]) !!}
{!! FormField::select('customer_id', $customers, ['label'=> trans('payment.customer'),'value' => Request::get('customer_id')]) !!}
<div class="row">
<div class="col-md-6">
{!! FormField::select('project_id', $projects, ['label'=> trans('payment.project'),'value' => Request::get('project_id')]) !!}
</div>
<div class="col-md-6">
{!! FormField::select('customer_id', $customers, ['label'=> trans('payment.customer'),'value' => Request::get('customer_id')]) !!}
</div>
</div>
{!! FormField::textarea('description',['label'=> trans('payment.description'),'rows' => 3]) !!}
</div>
@ -32,4 +38,30 @@
{!! Form::close() !!}
</div>
</div>
@endsection
@section('ext_css')
{!! Html::style(url('assets/css/plugins/jquery.datetimepicker.css')) !!}
@endsection
@section('ext_js')
{!! Html::script(url('assets/js/plugins/jquery.datetimepicker.js')) !!}
{!! Html::script(url('assets/js/plugins/autoNumeric.min.js')) !!}
@endsection
@section('script')
<script>
(function() {
$('#date').datetimepicker({
timepicker:false,
format:'Y-m-d',
closeOnDateSelect: true
});
$('#amount').autoNumeric("init",{
aSep: '.',
aDec: ',',
mDec: '0'
});
})();
</script>
@endsection

28
resources/views/payments/edit.blade.php

@ -17,7 +17,7 @@
{!! FormField::text('date',['label'=> trans('app.date')]) !!}
</div>
<div class="col-md-6">
{!! FormField::text('amount',['label'=> trans('payment.amount'),'addon' => ['before'=>'Rp'],'type' => 'number','class' => 'text-right']) !!}
{!! FormField::price('amount',['label'=> trans('payment.amount')]) !!}
</div>
</div>
<div class="row">
@ -40,4 +40,30 @@
{!! Form::close() !!}
</div>
</div>
@endsection
@section('ext_css')
{!! Html::style(url('assets/css/plugins/jquery.datetimepicker.css')) !!}
@endsection
@section('ext_js')
{!! Html::script(url('assets/js/plugins/jquery.datetimepicker.js')) !!}
{!! Html::script(url('assets/js/plugins/autoNumeric.min.js')) !!}
@endsection
@section('script')
<script>
(function() {
$('#date').datetimepicker({
timepicker:false,
format:'Y-m-d',
closeOnDateSelect: true
});
$('#amount').autoNumeric("init",{
aSep: '.',
aDec: ',',
mDec: '0'
});
})();
</script>
@endsection

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

@ -28,7 +28,7 @@
@forelse($payments as $key => $payment)
<tr>
<td>{{ $payments->firstItem() + $key }}</td>
<td>{{ $payment->project->name }}</td>
<td>{!! link_to_route('projects.payments', $payment->project->name, [$payment->project_id], ['title' => 'Lihat seluruh Pembayaran Project ini']) !!}</td>
<td class="text-center">{{ $payment->date }}</td>
<td class="text-right">{{ formatRp($payment->amount) }}</td>
<td>{{ $payment->description }}</td>

3
resources/views/payments/partials/payment-show.blade.php

@ -3,6 +3,7 @@
<table class="table table-condensed">
<tbody>
<tr><th>{{ trans('payment.date') }}</th><td>{{ $payment->date }}</td></tr>
<tr><th>{{ trans('payment.type') }}</th><td>{{ $payment->type ? trans('payment.cash_in') : trans('payment.cash_out') }}</td></tr>
<tr><th>{{ trans('payment.amount') }}</th><td class="text-right">{{ $payment->present()->amount }}</td></tr>
<tr><th>{{ trans('payment.description') }}</th><td>{{ $payment->description }}</td></tr>
<tr><th>{{ trans('payment.customer') }}</th><td>{{ $payment->customer->name }}</td></tr>
@ -10,6 +11,6 @@
</table>
<div class="panel-footer">
{!! link_to_route('payments.edit', trans('payment.edit'), [$payment->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('payments.index', trans('payment.back_to_index'), [], ['class' => 'btn btn-default']) !!}
{!! link_to_route('projects.payments', 'Kembali ke Daftar Pembayaran Project', [$payment->project_id], ['class' => 'btn btn-default']) !!}
</div>
</div>

7
resources/views/payments/show.blade.php

@ -4,7 +4,12 @@
@section('content')
@include('payments.partials.breadcrumb')
<h1 class="page-header">{{ trans('payment.show') }}</h1>
<h1 class="page-header">
<div class="pull-right">
{!! link_to_route('payments.index', 'Lihat Semua Pembayaran', [], ['class' => 'btn btn-default']) !!}
</div>
{{ trans('payment.show') }}
</h1>
<div class="row">
<div class="col-md-5">
@include('payments.partials.payment-show')

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

@ -7,7 +7,7 @@
@include('projects.partials.breadcrumb',['title' => trans('project.edit')])
<div class="row">
<div class="col-md-6 col-md-offset-2">
<div class="col-md-7 col-md-offset-2">
{!! Form::model($project, ['route'=>['projects.update', $project->id], 'method' => 'patch']) !!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ $project->name }}</h3></div>

4
resources/views/projects/partials/nav-tabs.blade.php

@ -4,10 +4,10 @@
{!! link_to_route('projects.show', trans('project.show'), [$project->id]) !!}
</li>
<li class="{{ Request::segment(3) == 'features' ? 'active' : '' }}">
{!! link_to_route('projects.features', trans('project.features'), [$project->id]) !!}
{!! link_to_route('projects.features', trans('project.features') . ' (' . $project->features->count() . ')', [$project->id]) !!}
</li>
<li class="{{ Request::segment(3) == 'payments' ? 'active' : '' }}">
{!! link_to_route('projects.payments', trans('project.payments'), [$project->id]) !!}
{!! link_to_route('projects.payments', trans('project.payments') . ' (' . $project->payments->count() . ')', [$project->id]) !!}
</li>
</ul>
<br>

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

@ -10,6 +10,7 @@
<tr><td>{{ trans('project.project_value') }}</td><td class="text-right">{{ formatRp($project->project_value) }}</td></tr>
<tr><td>{{ trans('project.start_date') }}</td><td>{{ dateId($project->start_date) }}</td></tr>
<tr><td>{{ trans('project.end_date') }}</td><td>{{ dateId($project->end_date) }}</td></tr>
<tr><td>{{ trans('app.status') }}</td><td>{{ $project->present()->status }}</td></tr>
<tr>
<td>{{ trans('project.customer') }}</td>
<td>

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

@ -5,48 +5,69 @@
@section('content')
@include('projects.partials.breadcrumb',['title' => trans('project.payments')])
<h1 class="page-header">{{ $project->name }} <small>{{ trans('project.payments') }}</small></h1>
<h1 class="page-header">
<div class="pull-right">
{!! html_link_to_route('payments.create', trans('payment.create'), ['project_id' => $project->id,'customer_id' => $project->customer_id], ['class' => 'btn btn-primary','icon' => 'plus']) !!}
</div>
{{ $project->name }} <small>{{ trans('project.payments') }}</small>
</h1>
@include('projects.partials.nav-tabs')
<div class="panel panel-default">
<table class="table table-condensed">
<thead>
<th>{{ trans('app.table_no') }}</th>
<th class="text-center">{{ trans('payment.date') }}</th>
<th class="text-right">{{ trans('payment.amount') }}</th>
<th>{{ trans('payment.description') }}</th>
<th>{{ trans('payment.customer') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
<tbody>
<?php $total = 0; ?>
@forelse($project->payments as $key => $payment)
<tr>
<td>{{ 1 + $key }}</td>
<td class="text-center">{{ $payment->date }}</td>
<td class="text-right">{{ $payment->present()->amount }}</td>
<td>{{ $payment->description }}</td>
<td>{{ $payment->customer->name }}</td>
<td>{!! html_link_to_route('payments.show',trans('app.show'),[$payment->id],['class' => 'btn btn-info btn-xs']) !!}</td>
</tr>
<?php $total = $payment->type == 0 ? $total - $payment->amount : $total + $payment->amount ?>
@empty
<tr><td colspan="6">{{ trans('payment.empty') }}</td></tr>
@endforelse
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-right">{{ trans('app.total') }}</th>
<th class="text-right">{{ formatRp($total) }}</th>
<th colspan="5"></th>
</tr>
<tr>
<td colspan="6">
{!! html_link_to_route('payments.create', trans('payment.create'), ['project_id' => $project->id,'customer_id' => $project->customer_id], ['class' => 'btn btn-primary','icon' => 'plus']) !!}
</td>
</tr>
</tfoot>
</table>
<div class="row">
<div class="col-md-9">
<?php $groupedPayments = $project->payments->groupBy('type'); ?>
@foreach ($groupedPayments as $key => $payments)
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ $key == 1 ? 'Pemasukan' : 'Pengeluaran' }}</h3></div>
<table class="table table-condensed">
<thead>
<th>{{ trans('app.table_no') }}</th>
<th class="col-md-2 text-center">{{ trans('app.date') }}</th>
<th class="col-md-2 text-right">{{ trans('payment.amount') }}</th>
<th class="col-md-2">{{ $key == 1 ? 'Dari' : 'Ke' }}</th>
<th class="col-md-5">{{ trans('payment.description') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
<tbody>
@forelse($payments as $key => $payment)
<tr>
<td>{{ 1 + $key }}</td>
<td class="text-center">{{ $payment->date }}</td>
<td class="text-right">{{ formatRp($payment->amount) }}</td>
<td>{{ $payment->customer->name }}</td>
<td>{{ $payment->description }}</td>
<td>{!! html_link_to_route('payments.show','',[$payment->id],['class' => 'btn btn-info btn-xs','icon' => 'search','title' => 'Lihat ' . trans('payment.show')]) !!}</td>
</tr>
@empty
<tr><td colspan="6">{{ trans('payment.empty') }}</td></tr>
@endforelse
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-right">{{ trans('app.total') }}</th>
<th class="text-right">{{ formatRp($payments->sum('amount')) }}</th>
<th colspan="5"></th>
</tr>
</tfoot>
</table>
</div>
@endforeach
</div>
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Summary</h3></div>
<table class="table table-condensed">
<tbody>
<tr><th>{{ trans('project.project_value') }}</th><td class="text-right">{{ formatRp($project->project_value) }}</td></tr>
<tr><th>{{ trans('project.cash_in_total') }}</th><td class="text-right">{{ formatRp($project->cashInTotal()) }}</td></tr>
<tr><th>{{ trans('project.cash_out_total') }}</th><td class="text-right">{{ formatRp($project->cashOutTotal()) }}</td></tr>
<tr><th>Sisa</th><td class="text-right">{{ formatRp($balance = $project->project_value - $project->cashInTotal()) }}</td></tr>
<tr><th>{{ trans('app.status') }}</th><td>{{ $balance > 0 ? 'Belum Lunas' : 'Lunas' }}</td></tr>
</tbody>
</table>
</div>
</div>
</div>
@endsection

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

@ -0,0 +1,43 @@
@extends('layouts.app')
@section('title', 'Piutang Saat Ini')
@section('content')
<h1 class="page-header">Piutang Saat Ini</h1>
<table class="table table-condensed table-hover">
<thead>
<th>{{ trans('app.table_no') }}</th>
<th class="col-md-2">{{ trans('project.project') }}</th>
<th class="col-md-2 text-right">{{ trans('project.project_value') }}</th>
<th class="col-md-2 text-right">{{ trans('project.cash_in_total') }}</th>
<th class="col-md-2 text-right">Sisa</th>
<th class="col-md-2">{{ trans('project.customer') }}</th>
<th class="col-md-2 text-center">{{ trans('project.status') }}</th>
</thead>
<tbody>
<?php $total = 0 ?>
@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 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>
<td>{{ $project->customer->name }}</td>
<td class="text-center">{{ $project->present()->status }}</td>
</tr>
@empty
<tr><td colspan="8">{{ trans('project.not_found') }}</td></tr>
@endforelse
</tbody>
<tfoot>
<tr>
<th class="text-right" colspan="4">Jumlah</th>
<th class="text-right">{{ formatRp($projects->sum('balance')) }}</th>
<th colspan="3"></th>
</tr>
</tfoot>
</table>
@endsection

1
resources/views/reports/payments/daily.blade.php

@ -59,7 +59,6 @@
</table>
@endsection
@section('ext_css')
{!! Html::style(url('assets/css/plugins/jquery.datetimepicker.css')) !!}
@endsection

14
resources/views/subscriptions/index.blade.php

@ -18,23 +18,21 @@
<thead>
<th>{{ trans('app.table_no') }}</th>
<th>{{ trans('subscription.domain_name') }}</th>
<th>{{ trans('subscription.hosting_capacity') }}</th>
<th class="text-center">{{ trans('subscription.hosting_capacity') }}</th>
<th>{{ trans('subscription.start_date') }}</th>
<th>{{ trans('subscription.due_date') }}</th>
<th>{{ trans('subscription.extension_price') }}</th>
<th class="text-right">{{ trans('subscription.extension_price') }}</th>
<th>{{ trans('app.action') }}</th>
</thead>
<tbody>
@forelse($subscriptions as $key => $subscription)
<tr {{ Carbon::parse($subscription->due_date)->diffInDays(Carbon::now()) < 60 ? 'class=bg-danger' : '' }}>
<td>
{{ $subscriptions->firstItem() + $key }}
</td>
<td>{{ $subscriptions->firstItem() + $key }}</td>
<td>{{ $subscription->domain_name }}</td>
<td>{{ $subscription->hosting_capacity }}</td>
<td class="text-center">{{ $subscription->hosting_capacity }}</td>
<td>{{ dateId($subscription->start_date) }}</td>
<td>{{ dateId($subscription->due_date) }}</td>
<td>{{ formatRp($subscription->domain_price + $subscription->hosting_price) }}</td>
<td class="text-right">{{ formatRp($subscription->domain_price + $subscription->hosting_price) }}</td>
<td>
{!! link_to_route('subscriptions.show',trans('app.show'),[$subscription->id],['class'=>'btn btn-info btn-xs']) !!}
{!! link_to_route('subscriptions.edit',trans('app.edit'),[$subscription->id],['class'=>'btn btn-warning btn-xs']) !!}
@ -42,7 +40,7 @@
</tr>
@empty
<tr>
<td colspan="5">{{ trans('subscription.not_found') }}</td>
<td colspan="7">{{ trans('subscription.not_found') }}</td>
</tr>
@endforelse
</tbody>

2
resources/views/subscriptions/show.blade.php

@ -5,7 +5,7 @@
@section('content')
<h1 class="page-header">{{ $subscription->domain_name }} <small>{{ trans('subscription.show') }}</small></h1>
<div class="row">
<div class="col-md-4">
<div class="col-md-6">
@include('subscriptions.partials.subscription-show')
</div>
</div>

4
tests/ManageFeaturesTest.php

@ -124,8 +124,8 @@ class ManageFeaturesTest extends TestCase
$this->actingAs($user);
$project = factory(Project::class)->create(['owner_id' => $user->id]);
$features = factory(Feature::class, 10)->create(['project_id' => $project->id]);
$this->assertEquals(10, $features->count());
$features = factory(Feature::class, 5)->create(['project_id' => $project->id]);
$this->assertEquals(5, $features->count());
$this->visit('projects/' . $project->id . '/features');
$this->see($features[1]->name);

51
tests/ManagePaymentsTest.php

@ -12,7 +12,7 @@ class ManagePaymentsTest extends TestCase
use DatabaseTransactions;
/** @test */
public function admin_can_entry_project_a_payment()
public function admin_can_entry_project_a_cashin_payment()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
@ -41,6 +41,37 @@ class ManagePaymentsTest extends TestCase
$this->seeInDatabase('payments', ['project_id' => $project->id,'amount' => 1000000,'type' => 1,'date' => '2015-05-01']);
}
/** @test */
public function admin_can_entry_project_a_cashout_payment()
{
$user = factory(User::class)->create();
$user->assignRole('admin');
$this->actingAs($user);
$project = factory(Project::class)->create();
$customer = factory(User::class)->create();
$customer->assignRole('customer');
$this->visit('payments');
$this->seePageIs('payments');
$this->click(trans('payment.create'));
// Fill Form
$this->seePageIs('payments/create');
$this->type('2015-05-01','date');
$this->select(0,'type');
$this->type(1000000,'amount');
$this->select($project->id, 'project_id');
$this->select($customer->id, 'customer_id');
$this->type('Pembayaran DP','description');
$this->press(trans('payment.create'));
$this->see(trans('payment.created'));
$this->seeInDatabase('payments', ['project_id' => $project->id,'amount' => 1000000,'type' => 0,'date' => '2015-05-01']);
}
/** @test */
public function admin_can_edit_payment_data()
{
@ -62,7 +93,7 @@ class ManagePaymentsTest extends TestCase
$this->type(1234567890,'amount');
$this->press(trans('payment.update'));
$this->seePageIs('payments/' . $payment->id . '/edit');
$this->seePageIs('payments/' . $payment->id);
$this->see(trans('payment.updated'));
$this->seeInDatabase('payments', [
'customer_id' => $customer->id,
@ -84,7 +115,7 @@ class ManagePaymentsTest extends TestCase
$this->click(trans('app.edit'));
$this->click(trans('payment.delete'));
$this->press(trans('app.delete_confirm_button'));
$this->seePageIs('payments');
$this->seePageIs('projects/' . $payment->project_id . '/payments');
$this->see(trans('payment.deleted'));
}
@ -115,14 +146,14 @@ class ManagePaymentsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$payments = factory(Payment::class, 10)->create();
$this->assertEquals(10, $payments->count());
$payments = factory(Payment::class, 5)->create();
$this->assertEquals(5, $payments->count());
$this->visit('/payments');
$this->see($payments[9]->project->name);
$this->see($payments[9]->date);
$this->see(formatRp($payments[9]->amount));
$this->see($payments[9]->description);
$this->see($payments[9]->customer->name);
$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);
}
}

2
tests/ManageProjectsTest.php

@ -77,7 +77,7 @@ class ManageProjectsTest extends TestCase
$this->actingAs($user);
$project = factory(Project::class)->create();
$this->visit('/projects');
$this->visit('/projects?status=' . $project->status_id);
$this->click(trans('app.edit'));
$this->click(trans('app.delete'));
$this->press(trans('app.delete_confirm_button'));

18
tests/ManageSubscriptionsTest.php

@ -130,17 +130,15 @@ class ManageSubscriptionsTest extends TestCase
$user->assignRole('admin');
$this->actingAs($user);
$subscriptions = factory(Subscription::class, 30)->create();
$this->assertEquals(30, $subscriptions->count());
$subscriptions = factory(Subscription::class, 5)->create();
$this->assertEquals(5, $subscriptions->count());
$this->visit('/subscriptions');
$this->see($subscriptions[1]->domain_name);
$this->see($subscriptions[1]->hosting_capacity);
$this->see(dateId($subscriptions[1]->start_date));
$this->see(dateId($subscriptions[1]->due_date));
$this->see(formatRp($subscriptions[1]->domain_price + $subscriptions[1]->hosting_price));
$this->click('2');
$this->seePageIs('/subscriptions?page=2');
$this->see($subscriptions[4]->domain_name);
$this->see($subscriptions[4]->hosting_capacity);
$this->see(dateId($subscriptions[4]->start_date));
$this->see(dateId($subscriptions[4]->due_date));
$this->see(formatRp($subscriptions[4]->domain_price + $subscriptions[4]->hosting_price));
}
}
Loading…
Cancel
Save