Browse Source

Use single SubscriptionFormRequest class to handle subscription CRUD

Add some helper method to subscription model
Move subscription insert and update script from SubscriptionController
to SubscriptionFormRequest class
Move subscription delete view to edit view file
Add breadcrumbs to subscription pages
pull/1/head
Nafies Luthfi 8 years ago
parent
commit
d408d77f72
  1. 21
      app/Entities/Subscriptions/Subscription.php
  2. 46
      app/Http/Controllers/SubscriptionsController.php
  3. 117
      app/Http/Requests/SubscriptionRequest.php
  4. 39
      app/Http/Requests/Subscriptions/CreateRequest.php
  5. 31
      app/Http/Requests/Subscriptions/DeleteRequest.php
  6. 39
      app/Http/Requests/Subscriptions/UpdateRequest.php
  7. 4
      resources/lang/id/subscription.php
  8. 18
      resources/views/subscriptions/delete.blade.php
  9. 29
      resources/views/subscriptions/edit.blade.php
  10. 17
      resources/views/subscriptions/index.blade.php
  11. 5
      resources/views/subscriptions/partials/breadcrumb.blade.php
  12. 20
      resources/views/subscriptions/partials/delete.blade.php
  13. 7
      resources/views/subscriptions/partials/subscription-show.blade.php
  14. 13
      resources/views/subscriptions/show.blade.php
  15. 6
      routes/web.php
  16. 9
      routes/web/subscriptions.php
  17. 1
      tests/Feature/ManageSubscriptionsTest.php
  18. 49
      tests/Unit/Models/SubscriptionTest.php

21
app/Entities/Subscriptions/Subscription.php

@ -2,6 +2,7 @@
namespace App\Entities\Subscriptions;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Laracasts\Presenter\PresentableTrait;
@ -12,6 +13,26 @@ class Subscription extends Model
protected $presenter = 'App\Entities\Subscriptions\SubscriptionPresenter';
protected $guarded = ['id', 'created_at', 'updated_at'];
public function nameLink()
{
return link_to_route('subscriptions.show', $this->name, [$this->id], [
'title' => trans(
'app.show_detail_title',
['name' => $this->name, 'type' => trans('subscription.subscription')]
),
]);
}
public function nearOfDueDate()
{
return Carbon::parse($this->due_date)->diffInDays(Carbon::now()) < 60;
}
public function nearOfDueDateSign()
{
return $this->nearOfDueDate() ? '<i class="fa fa-exclamation-circle" style="color: red"></i>' : '';
}
public function project()
{
return $this->belongsTo('App\Entities\Projects\Project');

46
app/Http/Controllers/SubscriptionsController.php

@ -5,9 +5,7 @@ namespace App\Http\Controllers;
use App\Entities\Subscriptions\Subscription;
use App\Entities\Subscriptions\SubscriptionsRepository;
use App\Http\Controllers\Controller;
use App\Http\Requests\Subscriptions\CreateRequest;
use App\Http\Requests\Subscriptions\DeleteRequest;
use App\Http\Requests\Subscriptions\UpdateRequest;
use App\Http\Requests\SubscriptionRequest as FormRequest;
use Illuminate\Http\Request;
class SubscriptionsController extends Controller
@ -36,21 +34,9 @@ class SubscriptionsController extends Controller
return view('subscriptions.create', compact('projects', 'vendors', 'subscriptionTypes'));
}
public function store(CreateRequest $request)
public function store(FormRequest $subscriptionCreateRequest)
{
$project = \App\Entities\Projects\Project::findOrFail($request->get('project_id'));
$subscription = new Subscription;
$subscription->project_id = $project->id;
$subscription->vendor_id = $request->get('vendor_id');
$subscription->customer_id = $project->customer_id;
$subscription->name = $request->get('name');
$subscription->price = $request->get('price');
$subscription->start_date = $request->get('start_date');
$subscription->due_date = $request->get('due_date');
$subscription->type_id = $request->get('type_id');
$subscription->notes = $request->get('notes');
$subscription->save();
$subscriptionCreateRequest->approveFor(new Subscription);
flash()->success(trans('subscription.created'));
return redirect()->route('subscriptions.index');
@ -67,36 +53,24 @@ class SubscriptionsController extends Controller
$vendors = $this->repo->getVendorsList();
$subscriptionTypes = $this->getSubscriptionTypes();
return view('subscriptions.edit', compact('subscription', 'projects', 'vendors', 'subscriptionTypes'));
$pageTitle = trans('subscription.edit').' - '.$subscription->name.' - '.$subscription->customer->name;
return view('subscriptions.edit', compact('subscription', 'projects', 'vendors', 'subscriptionTypes', 'pageTitle'));
}
public function update(UpdateRequest $request, Subscription $subscription)
public function update(FormRequest $subscriptionUpdateRequest, Subscription $subscription)
{
$project = \App\Entities\Projects\Project::findOrFail($request->get('project_id'));
$subscriptionData = $request->except(['_method', '_token']);
$subscriptionData['customer_id'] = $project->customer_id;
$subscription->update($subscriptionData);
$subscriptionUpdateRequest->approveFor($subscription);
flash()->success(trans('subscription.updated'));
return redirect()->route('subscriptions.edit', $subscription->id);
}
public function delete(Subscription $subscription)
public function destroy(FormRequest $subscriptionDeleteRequest, Subscription $subscription)
{
return view('subscriptions.delete', compact('subscription'));
}
$subscriptionDeleteRequest->approveToDelete($subscription);
public function destroy(DeleteRequest $request, Subscription $subscription)
{
if ($subscription->id == $request->get('subscription_id')) {
$subscription->delete();
flash()->success(trans('subscription.deleted'));
} else {
flash()->error(trans('subscription.undeleted'));
}
return redirect()->route('subscriptions.index');
}

117
app/Http/Requests/SubscriptionRequest.php

@ -0,0 +1,117 @@
<?php
namespace App\Http\Requests;
use App\Entities\Projects\Project;
use App\Entities\Subscriptions\Subscription;
use App\Http\Requests\Request;
class SubscriptionRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return auth()->user()->can('manage_subscriptions');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->method()) {
case 'POST':
return $this->getCreateRules();
break;
case 'PATCH':
return $this->getUpdateRules();
break;
case 'DELETE':
return $this->getDeleteRules();
break;
default:
break;
}
}
public function getCreateRules()
{
return [
'name' => 'required|max:60',
'price' => 'required|numeric',
'start_date' => 'required|date|date_format:Y-m-d',
'due_date' => 'required|date|date_format:Y-m-d',
'project_id' => 'required|numeric|exists:projects,id',
'vendor_id' => 'required|numeric|exists:vendors,id',
'type_id' => 'required|numeric',
'remark' => 'max:255',
];
}
public function getUpdateRules()
{
return [
'name' => 'required|max:60',
'price' => 'required|numeric',
'start_date' => 'required|date|date_format:Y-m-d',
'due_date' => 'required|date|date_format:Y-m-d',
'project_id' => 'required|numeric|exists:projects,id',
'vendor_id' => 'required|numeric|exists:vendors,id',
'type_id' => 'required|numeric',
'remark' => 'max:255',
];
}
public function getDeleteRules()
{
// dd($this->route('subscription'));
// dd($this->all(), $this->segment(2));
return [
'subscription_id' => 'required|in:'.$this->segment(2),
];
}
public function approveFor(Subscription $subscription)
{
$project = Project::findOrFail($this->get('project_id'));
if ($subscription->exists) {
$subscriptionData = $this->except(['_method', '_token']);
$subscriptionData['customer_id'] = $project->customer_id;
$subscription->update($subscriptionData);
} else {
$subscription->project_id = $project->id;
$subscription->vendor_id = $this->get('vendor_id');
$subscription->customer_id = $project->customer_id;
$subscription->name = $this->get('name');
$subscription->price = $this->get('price');
$subscription->start_date = $this->get('start_date');
$subscription->due_date = $this->get('due_date');
$subscription->type_id = $this->get('type_id');
$subscription->notes = $this->get('notes');
$subscription->save();
}
return $subscription;
}
public function approveToDelete(Subscription $subscription)
{
$subscription->delete();
}
}

39
app/Http/Requests/Subscriptions/CreateRequest.php

@ -1,39 +0,0 @@
<?php
namespace App\Http\Requests\Subscriptions;
use App\Http\Requests\Request;
class CreateRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return auth()->user()->can('manage_subscriptions');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:60',
'price' => 'required|numeric',
'start_date' => 'required|date|date_format:Y-m-d',
'due_date' => 'required|date|date_format:Y-m-d',
'project_id' => 'required|numeric|exists:projects,id',
'vendor_id' => 'required|numeric|exists:vendors,id',
'type_id' => 'required|numeric',
'remark' => 'max:255',
];
}
}

31
app/Http/Requests/Subscriptions/DeleteRequest.php

@ -1,31 +0,0 @@
<?php
namespace App\Http\Requests\Subscriptions;
use App\Http\Requests\Request;
class DeleteRequest extends Request {
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return auth()->user()->can('manage_subscriptions');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'subscription_id' => 'required'
];
}
}

39
app/Http/Requests/Subscriptions/UpdateRequest.php

@ -1,39 +0,0 @@
<?php
namespace App\Http\Requests\Subscriptions;
use App\Http\Requests\Request;
class UpdateRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return auth()->user()->can('manage_subscriptions');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:60',
'price' => 'required|numeric',
'start_date' => 'required|date|date_format:Y-m-d',
'due_date' => 'required|date|date_format:Y-m-d',
'project_id' => 'required|numeric',
'vendor_id' => 'required|numeric',
'type_id' => 'required|numeric',
'remark' => 'max:255',
];
}
}

4
resources/lang/id/subscription.php

@ -5,6 +5,8 @@ return [
// Labels
'subscription' => 'Langganan',
'subscriptions' => 'Daftar Langganan',
'list' => 'Daftar Langganan',
'detail' => 'Detail Langganan',
'search' => 'Cari Langganan',
'found' => 'Langganan ditemukan',
'not_found' => 'Langganan tidak ditemukan',
@ -14,7 +16,7 @@ return [
// Actions
'create' => 'Input Langganan Baru',
'created' => 'Input Langganan baru telah berhasil.',
'show' => 'Detail Langganan',
'show' => 'Lihat Detail Langganan',
'edit' => 'Edit Langganan',
'update' => 'Update Langganan',
'updated' => 'Update data Langganan telah berhasil.',

18
resources/views/subscriptions/delete.blade.php

@ -1,18 +0,0 @@
@extends('layouts.app')
@section('title', trans('subscription.delete'))
@section('content')
<h1 class="page-header">
<div class="pull-right">
{!! delete_button(['route'=>['subscriptions.destroy',$subscription->id]], trans('app.delete_confirm_button'), ['class'=>'btn btn-danger'], ['subscription_id'=>$subscription->id]) !!}
</div>
{{ trans('app.delete_confirm') }}
{!! link_to_route('subscriptions.show', trans('app.cancel'), [$subscription->id], ['class' => 'btn btn-default']) !!}
</h1>
<div class="row">
<div class="col-md-4">
@include('subscriptions.partials.subscription-show')
</div>
</div>
@endsection

29
resources/views/subscriptions/edit.blade.php

@ -1,15 +1,24 @@
@extends('layouts.app')
@section('title', trans('subscription.edit'))
@section('title', $pageTitle)
@section('content')
<div class="row"><br>
<div class="col-md-4">
@include('subscriptions.partials.breadcrumb', ['title' => $pageTitle])
@includeWhen(request('action') == 'delete', 'subscriptions.partials.delete')
@if (request('action') == null)
<div class="row">
<div class="col-md-6 col-md-offset-3">
{!! Form::model($subscription, ['route'=>['subscriptions.update', $subscription->id], 'method' => 'patch']) !!}
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ $subscription->domain_name }} <small>{{ trans('subscription.edit') }}</small></h3></div>
<div class="panel-heading"><h3 class="panel-title">{{ $pageTitle }}</h3></div>
<div class="panel-body">
<div class="row">
<div class="col-md-6">{!! FormField::radios('type_id', $subscriptionTypes, ['label' => trans('subscription.type'), 'value' => Request::get('type_id')]) !!}</div>
<div class="col-md-6">{!! FormField::radios('status_id', [trans('app.in_active'), trans('app.active')],['label' => trans('app.status')]) !!}</div>
</div>
<div class="row">
<div class="col-sm-6">
{!! FormField::text('name',['label' => trans('subscription.name')]) !!}
</div>
@ -27,19 +36,21 @@
</div>
{!! FormField::select('project_id', $projects,['label' => trans('subscription.project')]) !!}
{!! FormField::select('vendor_id', $vendors,['label' => trans('subscription.vendor')]) !!}
{!! FormField::radios('status_id', ['Non Active','Active'],['label'=> trans('app.status')]) !!}
{!! FormField::radios('type_id', $subscriptionTypes, ['label' => trans('subscription.type'), 'value' => Request::get('type_id')]) !!}
{!! FormField::textarea('notes',['label' => trans('subscription.notes')]) !!}
</div>
<div class="panel-footer">
{!! Form::submit(trans('subscription.update'), ['class'=>'btn btn-primary']) !!}
{!! link_to_route('subscriptions.show', trans('app.show'), [$subscription->id], ['class' => 'btn btn-info']) !!}
{!! link_to_route('subscriptions.index', trans('subscription.back_to_index'), [], ['class' => 'btn btn-default']) !!}
{!! link_to_route('subscriptions.delete', trans('subscription.delete'), [$subscription->id], ['class'=>'btn btn-danger pull-right']) !!}
</div>
</div>
{!! Form::close() !!}
</div>
<div class="col-md-3 text-center">
<legend>@lang('app.action')</legend>
<p>{!! link_to_route('subscriptions.show', trans('subscription.show'), [$subscription->id], ['class' => 'btn btn-info']) !!}</p>
<p>{!! link_to_route('subscriptions.index', trans('subscription.back_to_index'), [], ['class' => 'btn btn-default']) !!}</p>
<p>{!! link_to_route('subscriptions.edit', trans('subscription.delete'), [$subscription->id, 'action' => 'delete'], ['class'=>'btn btn-danger']) !!}</p>
</div>
</div>
@endif
@endsection

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

@ -9,7 +9,7 @@
</h1>
<div class="well well-sm">
{!! Form::open(['method'=>'get','class'=>'form-inline']) !!}
{!! Form::text('q', Request::get('q'), ['class'=>'form-control index-search-field','placeholder'=>trans('subscription.search'),'style' => 'width:350px']) !!}
{!! Form::text('q', request('q'), ['class'=>'form-control index-search-field','placeholder'=>trans('subscription.search'),'style' => 'width:350px']) !!}
{!! Form::submit(trans('subscription.search'), ['class' => 'btn btn-info btn-sm']) !!}
{!! link_to_route('subscriptions.index','Reset',[],['class' => 'btn btn-default btn-sm']) !!}
{!! Form::close() !!}
@ -24,25 +24,22 @@
<th class="text-right">{{ trans('subscription.extension_price') }}</th>
<th>{{ trans('subscription.vendor') }}</th>
<th class="text-center">{{ trans('app.status') }}</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' : '' }}>
<tr>
<td>{{ $subscriptions->firstItem() + $key }}</td>
<td>{{ $subscription->name }}</td>
<td>{{ $subscription->nameLink() }}</td>
<td>{{ $subscription->customer->name }}</td>
<td class="text-right" title="
{{ trans('subscription.start_date') }} : {{ dateId($subscription->start_date) }} \n
{{ trans('subscription.start_date') }} : {{ dateId($subscription->start_date) }}
{{ trans('subscription.due_date') }} : {{ dateId($subscription->due_date) }}
">{{ dateId($subscription->due_date) }}</td>
">
{{ dateId($subscription->due_date) }} {!! $subscription->nearOfDueDateSign() !!}
</td>
<td class="text-right">{{ formatRp($subscription->price) }}</td>
<td>{{ $subscription->vendor->name }}</td>
<td class="text-center">{{ $subscription->status() }}</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']) !!}
</td>
</tr>
@empty
<tr>

5
resources/views/subscriptions/partials/breadcrumb.blade.php

@ -0,0 +1,5 @@
<ul class="breadcrumb hidden-print">
<li>{{ link_to_route('subscriptions.index',trans('subscription.list')) }}</li>
<li>{{ $subscription->nameLink() }}</li>
<li class="active">{{ isset($title) ? $title : trans('subscription.detail') }}</li>
</ul>

20
resources/views/subscriptions/partials/delete.blade.php

@ -0,0 +1,20 @@
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('subscription.delete') }}</h3></div>
@include('subscriptions.partials.subscription-show')
<div class="panel-body">
{{ trans('app.delete_confirm') }}
</div>
<div class="panel-footer">
{!! link_to_route('subscriptions.edit', trans('app.cancel'), [$subscription->id], ['class' => 'btn btn-default']) !!}
{!! FormField::delete(
['route' => ['subscriptions.destroy', $subscription->id]],
trans('app.delete_confirm_button'),
['class' => 'btn btn-danger'],
['subscription_id' => $subscription->id]
) !!}
</div>
</div>
</div>
</div>

7
resources/views/subscriptions/partials/subscription-show.blade.php

@ -1,5 +1,3 @@
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('subscription.show') }}</h3></div>
<table class="table table-condensed">
<tbody>
<tr><td>{{ trans('subscription.project') }}</td><td>{{ $subscription->project->name }}</td></tr>
@ -18,8 +16,3 @@
<tr><td>{{ trans('subscription.notes') }}</td><td>{!! nl2br($subscription->notes) !!}</td></tr>
</tbody>
</table>
<div class="panel-footer">
{!! link_to_route('subscriptions.edit', trans('subscription.edit'), [$subscription->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('subscriptions.index', trans('subscription.back_to_index'), [], ['class' => 'btn btn-default']) !!}
</div>
</div>

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

@ -1,12 +1,21 @@
@extends('layouts.app')
@section('title', trans('subscription.show'))
@section('title', trans('subscription.detail'))
@section('content')
<h1 class="page-header">{{ $subscription->domain_name }} <small>{{ trans('subscription.show') }}</small></h1>
@include('subscriptions.partials.breadcrumb')
<h1 class="page-header">{{ $subscription->name }} <small>{{ trans('subscription.detail') }}</small></h1>
<div class="row">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">{{ trans('subscription.detail') }}</h3></div>
@include('subscriptions.partials.subscription-show')
<div class="panel-footer">
{!! link_to_route('subscriptions.edit', trans('subscription.edit'), [$subscription->id], ['class' => 'btn btn-warning']) !!}
{!! link_to_route('subscriptions.index', trans('subscription.back_to_index'), [], ['class' => 'btn btn-default']) !!}
</div>
</div>
</div>
</div>
@endsection

6
routes/web.php

@ -6,13 +6,17 @@ require __DIR__.'/web/references.php';
require __DIR__.'/web/account.php';
require __DIR__.'/web/projects.php';
require __DIR__.'/web/payments.php';
require __DIR__.'/web/subscriptions.php';
require __DIR__.'/web/reports.php';
require __DIR__.'/web/invoices.php';
require __DIR__.'/web/options-vue.php';
require __DIR__.'/web/calendar.php';
Route::group(['middleware' => ['web', 'auth']], function () {
/**
* Subscriptions Routes
*/
Route::resource('subscriptions', 'SubscriptionsController');
/*
* Backup Restore Database Routes
*/

9
routes/web/subscriptions.php

@ -1,9 +0,0 @@
<?php
Route::group(['middleware' => ['web', 'auth']], function () {
/**
* Subscriptions Routes
*/
Route::get('subscriptions/{subscription}/delete', ['as' => 'subscriptions.delete', 'uses' => 'SubscriptionsController@delete']);
Route::resource('subscriptions', 'SubscriptionsController');
});

1
tests/Feature/ManageSubscriptionsTest.php

@ -90,6 +90,7 @@ class ManageSubscriptionsTest extends TestCase
$this->visit(route('subscriptions.edit', $subscription->id));
$this->click(trans('subscription.delete'));
$this->press(trans('app.delete_confirm_button'));
$this->seePageIs(route('subscriptions.index'));

49
tests/Unit/Models/SubscriptionTest.php

@ -6,11 +6,60 @@ use App\Entities\Partners\Customer;
use App\Entities\Partners\Vendor;
use App\Entities\Projects\Project;
use App\Entities\Subscriptions\Subscription;
use Carbon\Carbon;
use Tests\TestCase as TestCase;
class SubscriptionTest extends TestCase
{
/** @test */
public function it_has_name_link_method()
{
$subscription = factory(Subscription::class)->create();
$this->assertEquals(
link_to_route('subscriptions.show', $subscription->name, [$subscription->id], [
'title' => trans(
'app.show_detail_title',
['name' => $subscription->name, 'type' => trans('subscription.subscription')]
),
]), $subscription->nameLink()
);
}
/** @test */
public function it_has_near_of_due_date_method()
{
$next3Months = Carbon::now()->addMonths(2)->format('Y-m-d');
$subscription = factory(Subscription::class)->make(['due_date' => $next3Months]);
$this->assertFalse($subscription->nearOfDueDate());
$next1Months = Carbon::now()->addMonth()->format('Y-m-d');
$subscription = factory(Subscription::class)->make(['due_date' => $next1Months]);
$this->assertTrue($subscription->nearOfDueDate());
}
/** @test */
public function it_has_near_of_due_date_sign_method()
{
// Due date within next 3 months
$next3Months = Carbon::now()->addMonths(2)->format('Y-m-d');
$subscription = factory(Subscription::class)->make(['due_date' => $next3Months]);
$this->assertEquals('', $subscription->nearOfDueDateSign());
// Due date within next month
$next1Months = Carbon::now()->addMonth()->format('Y-m-d');
$subscription = factory(Subscription::class)->make(['due_date' => $next1Months]);
$this->assertEquals(
'<i class="fa fa-exclamation-circle" style="color: red"></i>',
$subscription->nearOfDueDateSign()
);
}
/** @test */
public function it_has_project_relation()
{
$subscription = factory(Subscription::class)->create();

Loading…
Cancel
Save