Add validation to service cancellation, and displaying cancellation costs if any
This commit is contained in:
parent
7a41dd803f
commit
6ac1b11864
@ -17,7 +17,7 @@ use Illuminate\Validation\ValidationException;
|
|||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
|
|
||||||
use App\Http\Requests\ServiceChangeRequest;
|
use App\Http\Requests\{ServiceCancel,ServiceChangeRequest};
|
||||||
use App\Mail\{CancelRequest,ChangeRequest};
|
use App\Mail\{CancelRequest,ChangeRequest};
|
||||||
use App\Models\{Charge,Invoice,Product,Service};
|
use App\Models\{Charge,Invoice,Product,Service};
|
||||||
|
|
||||||
@ -124,34 +124,29 @@ class ServiceController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Process a request to cancel a service
|
* Process a request to cancel a service
|
||||||
*
|
*
|
||||||
* @param Request $request
|
* @param ServiceCancel $request
|
||||||
* @param Service $o
|
* @param Service $o
|
||||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|RedirectResponse|\Illuminate\Routing\Redirector
|
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|RedirectResponse|\Illuminate\Routing\Redirector
|
||||||
*/
|
*/
|
||||||
public function cancel_request(Request $request,Service $o)
|
public function cancel_request(ServiceCancel $request,Service $o)
|
||||||
{
|
{
|
||||||
if ($request->post()) {
|
|
||||||
$request->validate([
|
|
||||||
'stop_at'=>'required|date',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (! $o->order_info)
|
if (! $o->order_info)
|
||||||
$o->order_info = collect();
|
$o->order_info = collect();
|
||||||
|
|
||||||
$o->stop_at = $request->stop_at;
|
$o->stop_at = $request->stop_at;
|
||||||
$o->order_info->put('cancel_note',$request->notes);
|
$o->order_info->put('cancel_note',$request->validated('notes'));
|
||||||
|
|
||||||
|
if ($request->validated('extra_charges'))
|
||||||
|
$o->order_info->put('cancel_extra_charges_accepted',$request->extra_charges_amount);
|
||||||
|
|
||||||
$o->order_status = 'CANCEL-REQUEST';
|
$o->order_status = 'CANCEL-REQUEST';
|
||||||
$o->save();
|
$o->save();
|
||||||
|
|
||||||
//@todo Get email from DB.
|
Mail::to(config('osb.ticket_admin'))
|
||||||
Mail::to('help@graytech.net.au')
|
|
||||||
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
||||||
|
|
||||||
return redirect('u/service/'.$o->id)->with('success','Cancellation lodged');
|
return redirect('u/service/'.$o->id)
|
||||||
}
|
->with('success','Cancellation lodged');
|
||||||
|
|
||||||
return view('theme.backend.adminlte.service.cancel_request')
|
|
||||||
->with('o',$o);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
54
app/Http/Requests/ServiceCancel.php
Normal file
54
app/Http/Requests/ServiceCancel.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editing Suppliers
|
||||||
|
*/
|
||||||
|
class ServiceCancel extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return Gate::allows('view',$this->route('o'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
//dd(request()->post());
|
||||||
|
return [
|
||||||
|
'stop_at'=> [
|
||||||
|
'required',
|
||||||
|
'date',
|
||||||
|
'after:today',
|
||||||
|
'exclude_unless:extra_charges,null',
|
||||||
|
function($attribute,$value,$fail) {
|
||||||
|
if ($this->route('o')->cancel_date->greaterThan($value))
|
||||||
|
$fail(sprintf('Service cannot be cancelled before: %s',$this->route('o')->cancel_date->format('Y-m-d')));
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'extra_charges_amount' => [
|
||||||
|
'nullable',
|
||||||
|
'exclude_unless:extra_charges,null',
|
||||||
|
function($attribute,$value,$fail) {
|
||||||
|
if ($this->route('o')->cancel_date->greaterThan(request('stop_at')) && (request('extra_charges') !== 1))
|
||||||
|
$fail('Extra charges must be accepted if cancelling before contract end');
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'extra_charges' => 'sometimes|required|accepted',
|
||||||
|
'notes' => 'nullable|min:5',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,9 @@ use Illuminate\Support\Facades\Log;
|
|||||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||||
use Leenooks\Casts\LeenooksCarbon;
|
use Leenooks\Casts\LeenooksCarbon;
|
||||||
|
|
||||||
use App\Models\Product\Type;
|
|
||||||
use App\Interfaces\IDs;
|
use App\Interfaces\IDs;
|
||||||
|
use App\Models\Product\Type;
|
||||||
|
use App\Models\Service\Broadband;
|
||||||
use App\Traits\{ScopeAccountUserAuthorised,ScopeServiceActive,SiteID};
|
use App\Traits\{ScopeAccountUserAuthorised,ScopeServiceActive,SiteID};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -565,6 +566,26 @@ class Service extends Model implements IDs
|
|||||||
return Invoice::billing_name($this->getBillingIntervalAttribute());
|
return Invoice::billing_name($this->getBillingIntervalAttribute());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the earliest date that the service can be cancelled
|
||||||
|
*
|
||||||
|
* @return Carbon
|
||||||
|
*/
|
||||||
|
public function getCancelDateAttribute(): Carbon
|
||||||
|
{
|
||||||
|
switch (get_class($this->type)) {
|
||||||
|
// Broadband needs 30 days notice
|
||||||
|
case Broadband::class:
|
||||||
|
$date = Carbon::now()->addMonth();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$date = Carbon::now()->addDay();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->getContractEndAttribute()->lessThan($date) ? $date : $this->getContractEndAttribute();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The date the contract ends
|
* The date the contract ends
|
||||||
*
|
*
|
||||||
@ -582,7 +603,7 @@ class Service extends Model implements IDs
|
|||||||
if (! $this->start_at)
|
if (! $this->start_at)
|
||||||
return $this->type->expire_at;
|
return $this->type->expire_at;
|
||||||
|
|
||||||
$end = $this->start_at->addMonths($this->getContractTermAttribute());
|
$end = $this->start_at->clone()->addMonths($this->getContractTermAttribute());
|
||||||
|
|
||||||
// If we dont have an expire date, use the start date + contract_term
|
// If we dont have an expire date, use the start date + contract_term
|
||||||
if (! $this->type->expire_at)
|
if (! $this->type->expire_at)
|
||||||
@ -892,6 +913,27 @@ class Service extends Model implements IDs
|
|||||||
: $this->price;
|
: $this->price;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide billing charge to a future date
|
||||||
|
*
|
||||||
|
* @param Carbon $date
|
||||||
|
* @return float
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function billing_charge_to(Carbon $date): float
|
||||||
|
{
|
||||||
|
// if the date is less than the paid to, but less than the cancel date to, return cancel-paid to charge
|
||||||
|
// If the date is greater than the paid to, and less than the cancel date to, return cancel-paid to charge
|
||||||
|
if ($this->getPaidToAttribute()->lessThan($this->getCancelDateAttribute())) {
|
||||||
|
$max = max($date,$this->getPaidToAttribute())->clone();
|
||||||
|
$d = $max->diffInDays($this->getCancelDateAttribute());
|
||||||
|
|
||||||
|
return $this->account->taxed($d/30*$this->getBillingChargeNormalisedAttribute());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the stage parameters
|
* Get the stage parameters
|
||||||
*
|
*
|
||||||
|
@ -36,5 +36,6 @@ class AppServiceProvider extends ServiceProvider
|
|||||||
Route::model('co',\App\Models\Checkout::class);
|
Route::model('co',\App\Models\Checkout::class);
|
||||||
Route::model('po',\App\Models\Payment::class);
|
Route::model('po',\App\Models\Payment::class);
|
||||||
Route::model('pdo',\App\Models\Product::class);
|
Route::model('pdo',\App\Models\Product::class);
|
||||||
|
Route::model('so',\App\Models\Service::class);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,4 +6,5 @@ return [
|
|||||||
'invoice_days' => 30, // Days in Advance to invoice
|
'invoice_days' => 30, // Days in Advance to invoice
|
||||||
'invoice_review' => 3, // Days to review an invoice before it is emailed
|
'invoice_review' => 3, // Days to review an invoice before it is emailed
|
||||||
'admin' => env('APP_ADMIN'),
|
'admin' => env('APP_ADMIN'),
|
||||||
|
'ticket_admin' => env('APP_TICKET_ADMIN',env('APP_ADMIN')),
|
||||||
];
|
];
|
@ -7,6 +7,7 @@ Please cancel the following...
|
|||||||
| Logged User | {{ Auth::user()->id ?? 'System' }} |
|
| Logged User | {{ Auth::user()->id ?? 'System' }} |
|
||||||
| Account | {{ $service->account->name }} |
|
| Account | {{ $service->account->name }} |
|
||||||
| Service ID | {{ $service->sid }} |
|
| Service ID | {{ $service->sid }} |
|
||||||
|
| Cancel Date | {{ $service->stop_at->format('Y-m-d') }} |
|
||||||
| Product | {{ $service->product->name }} |
|
| Product | {{ $service->product->name }} |
|
||||||
@switch($service->product->category)
|
@switch($service->product->category)
|
||||||
@case('broadband')
|
@case('broadband')
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
|
@use(Carbon\Carbon)
|
||||||
|
|
||||||
@extends('adminlte::layouts.app')
|
@extends('adminlte::layouts.app')
|
||||||
|
|
||||||
@section('htmlheader_title')
|
@section('htmlheader_title')
|
||||||
{{ $o->sid }}
|
{{ $so->sid }}
|
||||||
@endsection
|
@endsection
|
||||||
@section('page_title')
|
@section('page_title')
|
||||||
{{ $o->sid }}
|
{{ $so->sid }}
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('contentheader_title')
|
@section('contentheader_title')
|
||||||
Service: {{ $o->sid }} <strong>{{ $o->product->name }}</strong>
|
Service: {{ $so->sid }} <strong>{{ $so->product->name }}</strong>
|
||||||
@endsection
|
@endsection
|
||||||
@section('contentheader_description')
|
@section('contentheader_description')
|
||||||
{{ $o->name }}
|
{{ $so->name }}
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('main-content')
|
@section('main-content')
|
||||||
@ -27,14 +29,27 @@
|
|||||||
|
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-8 col-sm-5 col-md-12 col-lg-6">
|
<div class="col-8 col-sm-6 col-md-12 col-lg-6">
|
||||||
<x-leenooks::form.date name="stop_at" icon="fa-calendar" label="Cancel Date" :value="($x=$o->stop_at) ? $x->format('Y-m-d') : '' "/>
|
<x-leenooks::form.date name="stop_at" icon="fa-calendar" label="Cancel Date" :helper="sprintf('After %s',$so->cancel_date->format('Y-m-d'))" :value="($x=$so->stop_at) ? $x->format('Y-m-d') : ''"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-8 col-sm-6 col-md-12 col-lg-6">
|
||||||
|
<x-leenooks::form.date name="paid_to" icon="fa-money" label="Paid To" :value="$so->invoiced_to->format('Y-m-d')" readonly/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if(old('stop_at') && Carbon::now()->lessThan(old('stop_at')))
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-5 col-md-10 col-lg-6 col-xl-5">
|
||||||
|
<x-leenooks::form.text class="text-right" name="extra_charges_amount" icon="fa-dollar-sign" label="Estimated Extra Charges" :value="number_format($so->billing_charge_to(Carbon::create(old('stop_at'))),2)" :old="false" readonly/>
|
||||||
|
</div>
|
||||||
|
<div class="col-1">
|
||||||
|
<x-leenooks::form.checkbox name="extra_charges" label="Accept" value="1"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<x-leenooks::form.textarea name="notes" label="Notes" placeholder="Please let us know why you are cancelling" :value="$o->order_info_notes ?? ''"/>
|
<x-leenooks::form.textarea name="notes" label="Notes" placeholder="Please let us know why you are cancelling" :value="$so->order_info_notes ?? ''"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
|
|
||||||
<div class="card-body p-2">
|
<div class="card-body p-2">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
@if($x=! ($o->suspend_billing || $o->external_billing) && $o->next_invoice)
|
@if(($x=! ($o->suspend_billing || $o->external_billing)) && $o->invoice_next)
|
||||||
<div @class(['tab-pane','fade','show active'=>! (session()->has('service_update') || session()->has('charge_add'))]) id="pending_items">
|
<div @class(['tab-pane','fade','show active'=>! (session()->has('service_update') || session()->has('charge_add'))]) id="pending_items">
|
||||||
@include('theme.backend.adminlte.service.widget.invoice')
|
@include('theme.backend.adminlte.service.widget.invoice')
|
||||||
</div>
|
</div>
|
||||||
|
@ -193,7 +193,9 @@ Route::group(['middleware'=>['auth'],'prefix'=>'u'],function() {
|
|||||||
Route::get('service/{o}',[ServiceController::class,'home'])
|
Route::get('service/{o}',[ServiceController::class,'home'])
|
||||||
->middleware('can:view,o')
|
->middleware('can:view,o')
|
||||||
->where('o','[0-9]+');
|
->where('o','[0-9]+');
|
||||||
Route::match(['get','post'],'service/{o}/cancel-request',[ServiceController::class,'cancel_request'])
|
Route::view('service/{so}/cancel-request','theme.backend.adminlte.service.cancel_request')
|
||||||
|
->where('so','[0-9]+');
|
||||||
|
Route::post('service/{o}/cancel-request',[ServiceController::class,'cancel_request'])
|
||||||
->middleware('can:progress,o,"cancel-request"')
|
->middleware('can:progress,o,"cancel-request"')
|
||||||
->where('o','[0-9]+');
|
->where('o','[0-9]+');
|
||||||
Route::match(['get','post'],'service/{o}/change-request',[ServiceController::class,'change_request'])
|
Route::match(['get','post'],'service/{o}/change-request',[ServiceController::class,'change_request'])
|
||||||
|
Loading…
Reference in New Issue
Block a user