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 Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
use App\Http\Requests\ServiceChangeRequest;
|
||||
use App\Http\Requests\{ServiceCancel,ServiceChangeRequest};
|
||||
use App\Mail\{CancelRequest,ChangeRequest};
|
||||
use App\Models\{Charge,Invoice,Product,Service};
|
||||
|
||||
@ -124,34 +124,29 @@ class ServiceController extends Controller
|
||||
/**
|
||||
* Process a request to cancel a service
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ServiceCancel $request
|
||||
* @param Service $o
|
||||
* @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)
|
||||
$o->order_info = collect();
|
||||
|
||||
if (! $o->order_info)
|
||||
$o->order_info = collect();
|
||||
$o->stop_at = $request->stop_at;
|
||||
$o->order_info->put('cancel_note',$request->validated('notes'));
|
||||
|
||||
$o->stop_at = $request->stop_at;
|
||||
$o->order_info->put('cancel_note',$request->notes);
|
||||
$o->order_status = 'CANCEL-REQUEST';
|
||||
$o->save();
|
||||
if ($request->validated('extra_charges'))
|
||||
$o->order_info->put('cancel_extra_charges_accepted',$request->extra_charges_amount);
|
||||
|
||||
//@todo Get email from DB.
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
||||
$o->order_status = 'CANCEL-REQUEST';
|
||||
$o->save();
|
||||
|
||||
return redirect('u/service/'.$o->id)->with('success','Cancellation lodged');
|
||||
}
|
||||
Mail::to(config('osb.ticket_admin'))
|
||||
->queue((new CancelRequest($o,$request->notes))->onQueue('email'));
|
||||
|
||||
return view('theme.backend.adminlte.service.cancel_request')
|
||||
->with('o',$o);
|
||||
return redirect('u/service/'.$o->id)
|
||||
->with('success','Cancellation lodged');
|
||||
}
|
||||
|
||||
/**
|
||||
|
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 Leenooks\Casts\LeenooksCarbon;
|
||||
|
||||
use App\Models\Product\Type;
|
||||
use App\Interfaces\IDs;
|
||||
use App\Models\Product\Type;
|
||||
use App\Models\Service\Broadband;
|
||||
use App\Traits\{ScopeAccountUserAuthorised,ScopeServiceActive,SiteID};
|
||||
|
||||
/**
|
||||
@ -565,6 +566,26 @@ class Service extends Model implements IDs
|
||||
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
|
||||
*
|
||||
@ -582,7 +603,7 @@ class Service extends Model implements IDs
|
||||
if (! $this->start_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 (! $this->type->expire_at)
|
||||
@ -892,6 +913,27 @@ class Service extends Model implements IDs
|
||||
: $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
|
||||
*
|
||||
|
@ -36,5 +36,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
Route::model('co',\App\Models\Checkout::class);
|
||||
Route::model('po',\App\Models\Payment::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_review' => 3, // Days to review an invoice before it is emailed
|
||||
'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' }} |
|
||||
| Account | {{ $service->account->name }} |
|
||||
| Service ID | {{ $service->sid }} |
|
||||
| Cancel Date | {{ $service->stop_at->format('Y-m-d') }} |
|
||||
| Product | {{ $service->product->name }} |
|
||||
@switch($service->product->category)
|
||||
@case('broadband')
|
||||
|
@ -1,17 +1,19 @@
|
||||
@use(Carbon\Carbon)
|
||||
|
||||
@extends('adminlte::layouts.app')
|
||||
|
||||
@section('htmlheader_title')
|
||||
{{ $o->sid }}
|
||||
{{ $so->sid }}
|
||||
@endsection
|
||||
@section('page_title')
|
||||
{{ $o->sid }}
|
||||
{{ $so->sid }}
|
||||
@endsection
|
||||
|
||||
@section('contentheader_title')
|
||||
Service: {{ $o->sid }} <strong>{{ $o->product->name }}</strong>
|
||||
Service: {{ $so->sid }} <strong>{{ $so->product->name }}</strong>
|
||||
@endsection
|
||||
@section('contentheader_description')
|
||||
{{ $o->name }}
|
||||
{{ $so->name }}
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
@ -27,14 +29,27 @@
|
||||
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-8 col-sm-5 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') : '' "/>
|
||||
<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" :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>
|
||||
|
||||
@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="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>
|
||||
|
@ -64,7 +64,7 @@
|
||||
|
||||
<div class="card-body p-2">
|
||||
<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">
|
||||
@include('theme.backend.adminlte.service.widget.invoice')
|
||||
</div>
|
||||
|
@ -193,7 +193,9 @@ Route::group(['middleware'=>['auth'],'prefix'=>'u'],function() {
|
||||
Route::get('service/{o}',[ServiceController::class,'home'])
|
||||
->middleware('can:view,o')
|
||||
->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"')
|
||||
->where('o','[0-9]+');
|
||||
Route::match(['get','post'],'service/{o}/change-request',[ServiceController::class,'change_request'])
|
||||
|
Loading…
Reference in New Issue
Block a user