diff --git a/app/Http/Controllers/ServiceController.php b/app/Http/Controllers/ServiceController.php index 8bf2028..ed569fd 100644 --- a/app/Http/Controllers/ServiceController.php +++ b/app/Http/Controllers/ServiceController.php @@ -67,7 +67,11 @@ class ServiceController extends Controller if (! $o->order_info) $o->order_info = collect(); - $o->order_info->put('change_cancel',Carbon::now()->format('Y-m-d H:i:s')); + // @todo add some validation if this doesnt return a result + $np = $o->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop(); + $np->pivot->active = FALSE; + $np->pivot->save(); + $o->order_status = 'ACTIVE'; return $o->save(); @@ -91,6 +95,9 @@ class ServiceController extends Controller public function change_pending(ServiceChangeRequest $request,Service $o) { + // @todo add some validation if this doesnt return a result + $np = $o->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop(); + if ($request->post()) { foreach ($this->service_change_charges($request,$o) as $co) $co->save(); @@ -100,12 +107,17 @@ class ServiceController extends Controller $o->order_status = 'ACTIVE'; $o->save(); + $np->pivot->complete = TRUE; + $np->pivot->effective_at = Carbon::now(); + $np->pivot->save(); + return redirect()->to(url('u/service',[$o->id])); } return view('service.change_pending') ->with('breadcrumb',collect()->merge($o->account->breadcrumb)) - ->with('o',$o); + ->with('o',$o) + ->with('np',$np); } /** @@ -218,16 +230,22 @@ class ServiceController extends Controller { if ($request->post()) { $request->validate([ + 'product_id'=>'required|exists:products,id', 'change_date'=>'required|date', - 'notes'=>'required|min:10', + 'notes'=>'nullable|min:10', ]); - if (! $o->order_info) - $o->order_info = collect(); + $o->changes()->attach([$o->id=>[ + 'site_id'=> $o->site_id, + 'ordered_by' => Auth::id(), + 'ordered_at' => Carbon::now(), + 'effective_at' => $request->change_date, + 'product_id' => $request->product_id, + 'notes' => $request->notes, + 'active' => TRUE, + 'complete' => FALSE, + ]]); - $o->order_info->put('change_note',$request->notes); - $o->order_info->put('change_date',$request->change_date); - $o->order_info->put('change_product_id',$request->product_id); $o->order_status = 'CHANGE-REQUEST'; $o->save(); diff --git a/app/Mail/ChangeRequest.php b/app/Mail/ChangeRequest.php index f5ef620..48c7dbd 100644 --- a/app/Mail/ChangeRequest.php +++ b/app/Mail/ChangeRequest.php @@ -26,7 +26,7 @@ class ChangeRequest extends Mailable public function __construct(Service $o,string $notes='') { $this->service = $o; - $this->notes = $notes; + $this->notes = $notes ?? ''; } /** diff --git a/app/Models/Service.php b/app/Models/Service.php index e090ea0..fe841a6 100644 --- a/app/Models/Service.php +++ b/app/Models/Service.php @@ -28,6 +28,11 @@ use App\Traits\SiteID; * Class Service * Services that belong to an account * + * So each service attribute has: + * - Offering, what product we supply (we make offerings from supplier's supplied products) - in the DB these are products/* + * - Supplied, our supplier's product that is providing the service - in the DB these are supplier/* + * - Type, what service we are providing, made up of a product we supply - in the DB these are service/* + * * Attributes for services: * + additional_cost : Pending additional charges for this service (excluding setup) //@todo check all these are still valid * + billing_charge : Charge for this service each invoice period // @todo change to "charge" @@ -46,14 +51,10 @@ use App\Traits\SiteID; * + sid : System ID for service * + supplied : The model of the supplier's product used for this service. * - * = Terminology: - * - Offering, what product we supply (we make offerings from supplier's supplied products) - in the DB these are products/* - * - Supplied, our supplier's product that is providing the service - in the DB these are supplier/* - * - Type, what service we are providing, made up of a product we supply - in the DB these are service/* - * * @package App\Models * @todo "Billing Start Date" = "connection date" for sub types?? * @todo Add min_charge + * @todo deprecate price_override, and if price < what would be billed, show it striked through, otherwise show it as if it was the price */ class Service extends Model implements IDs { @@ -356,6 +357,14 @@ class Service extends Model implements IDs ->orderBy('created_at'); } + public function changes() + { + return $this->belongsToMany(Product::class,'service__change','service_id','product_id','id','id') + ->where('service__change.site_id',$this->site_id) + ->withPivot(['ordered_at','effective_at','ordered_by','active','complete','notes']) + ->withTimestamps(); + } + // @todo changed to invoiced_items public function invoice_items($active=TRUE) { diff --git a/app/Models/ServiceChange.php b/app/Models/ServiceChange.php index a8c55e0..9d18274 100644 --- a/app/Models/ServiceChange.php +++ b/app/Models/ServiceChange.php @@ -12,5 +12,4 @@ use Illuminate\Database\Eloquent\Model; class ServiceChange extends Model { protected $table = 'service__change'; - public $timestamps = FALSE; } \ No newline at end of file diff --git a/database/migrations/2023_05_05_234120_service_change_update.php b/database/migrations/2023_05_05_234120_service_change_update.php new file mode 100644 index 0000000..9f3e4d4 --- /dev/null +++ b/database/migrations/2023_05_05_234120_service_change_update.php @@ -0,0 +1,100 @@ +dateTime('created_at')->nullable()->after('id'); + $table->dateTime('updated_at')->nullable()->after('created_at'); + $table->date('ordered_at')->nullable()->after('ordered_by'); + $table->date('effective_at')->nullable()->after('ordered_at'); + $table->text('notes')->nullable(); + }); + + DB::statement('ALTER TABLE service__change MODIFY service_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service__change MODIFY product_id int unsigned NOT NULL'); + DB::statement('ALTER TABLE service__change MODIFY ordered_by int unsigned NOT NULL'); + + DB::statement('ALTER TABLE service__change MODIFY active tinyint(1) NOT NULL'); + DB::statement('ALTER TABLE service__change MODIFY complete tinyint(1) NOT NULL'); + + // Convert out dates + foreach (\App\Models\ServiceChange::withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + // If we are running again + if ($o->created_at) + continue; + + if ($o->ordered_at_old) + $o->created_at = \Carbon\Carbon::create(substr($o->ordered_at_old,0,4),substr($o->ordered_at_old,4,2),substr($o->ordered_at_old,6,2)); + + $o->updated_at = $o->created_at; + $o->ordered_at = $o->created_at; + + if ($o->effective_at_old) + $o->effective_at = \Carbon\Carbon::create(substr($o->effective_at_old,0,4),substr($o->effective_at_old,4,2),substr($o->effective_at_old,6,2)); + + $o->save(); + } + + Schema::table('service__change', function (Blueprint $table) { + $table->dropColumn(['ordered_at_old','effective_at_old']); + }); + + DB::statement('ALTER TABLE service__change MODIFY ordered_at date NOT NULL'); + + foreach (\App\Models\Service::where('order_info','LIKE','%change%')->withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + if ($o->order_info->only(['change_note','change_product_id','change_date'])->count() !== 3) + continue; + + $o->changes()->attach([$o->id => [ + 'site_id'=> $o->site_id, + 'ordered_by' => 1, + 'ordered_at' => $x=\Carbon\Carbon::createFromDate(\Illuminate\Support\Arr::get($o->order_info,'change_date')), + 'effective_at' => $x, + 'product_id' => \Illuminate\Support\Arr::get($o->order_info,'change_product_id'), + 'notes' => \Illuminate\Support\Arr::get($o->order_info,'change_note'), + 'active' => true, + 'complete' => true, + ]]); + + $o->order_info->forget(['change_note','change_product_id','change_date']); + $o->save(); + } + + // Additional cleanup + foreach (\App\Models\Service::whereNotNull('order_info')->withoutGlobalScope(\App\Models\Scopes\SiteScope::class)->cursor() as $o) { + foreach (['notes','provision_notes','cancel_note'] as $key) { + if ($o->order_info && ((is_array($o->order_info) && array_key_exists($key,$o->order_info)) || ($o->order_info->has($key))) && is_null(\Illuminate\Support\Arr::get($o->order_info,$key))) + $o->order_info->forget($key); + } + + $o->save(); + } + + // Final cleanup + DB::statement("UPDATE services set order_info=null WHERE order_info='[]'"); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + abort(500,'cant go back'); + } +}; diff --git a/resources/views/theme/backend/adminlte/service/change_pending.blade.php b/resources/views/theme/backend/adminlte/service/change_pending.blade.php index 75c34ad..5b88081 100644 --- a/resources/views/theme/backend/adminlte/service/change_pending.blade.php +++ b/resources/views/theme/backend/adminlte/service/change_pending.blade.php @@ -14,7 +14,7 @@ {{ $o->sid }} @endsection - + @section('main-content')
@@ -56,7 +56,7 @@ @foreach (\App\Models\Product::get() as $po) @if (! $po->category || ($po->category !== $o->product->category)) @continue @endif - + @endforeach @@ -81,7 +81,7 @@
- + @error('broadband.start_at') {{ $message }} @@ -153,7 +153,7 @@
- @include('service.widget.internal',['o'=>$o,'p'=>\App\Models\Product::where('id',Arr::get($o->order_info,'change_product_id'))->singleOrFail()]) + @include('service.widget.internal',['o'=>$o,'p'=>$np])
@@ -170,13 +170,14 @@ var pid = $('#product_id').val(); var start = $('#start_at').val(); var fee = $('#change_fee').val(); + var price = $('#price').val(); $("div[id=transactions]").empty(); $.ajax({ type: 'POST', dataType: 'html', - data: {broadband: {product_id: pid,start_at: start,change_fee: fee}}, + data: {broadband: {product_id: pid,start_at: start,change_fee: fee,price: price}}, cache: false, url: '{{ url('r/service_change_charges',[$o->id]) }}', timeout: 2000, @@ -205,6 +206,10 @@ pendingtrans(); }); + $('#price').on('change',function() { + pendingtrans(); + }); + pendingtrans(); }); diff --git a/resources/views/theme/backend/adminlte/service/home.blade.php b/resources/views/theme/backend/adminlte/service/home.blade.php index dac7134..614ea05 100644 --- a/resources/views/theme/backend/adminlte/service/home.blade.php +++ b/resources/views/theme/backend/adminlte/service/home.blade.php @@ -89,7 +89,11 @@ @can('wholesaler')
- @include('service.widget.internal',['o'=>$o,'p'=>new \App\Models\Product()]) + @if(($x=$o->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop())) + @include('service.widget.internal',['o'=>$o,'p'=>$x]) + @else + @include('service.widget.internal',['o'=>$o,'p'=>new \App\Models\Product()]) + @endif
diff --git a/resources/views/theme/backend/adminlte/service/widget/broadband/details.blade.php b/resources/views/theme/backend/adminlte/service/widget/broadband/details.blade.php index 4fdb607..c8dfc5f 100644 --- a/resources/views/theme/backend/adminlte/service/widget/broadband/details.blade.php +++ b/resources/views/theme/backend/adminlte/service/widget/broadband/details.blade.php @@ -49,7 +49,7 @@ Traffic - {{ $o->service->offering->allowance_string() }} GB @if(FALSE)(YY GB used month)@endif + {{ $o->service->offering->allowance_string() }} GB IP4 Address @@ -73,6 +73,23 @@ Cancel Notice 1 month @if($o->inContract())(after {{ $o->service_expire->subMonth()->format('Y-m-d') }})@endif + + @if(($x=$o->service->changes()->where('service__change.active',TRUE)->where('complete',FALSE)->get()->pop())) + + Pending Plan Change + {{ $x->name }} + + + Pending Submitted + {{ $x->pivot->ordered_at }} + + @if($x->pivot->effective_at) + + Pending Active + {{ $x->pivot->effective_at }} + + @endif + @endif
\ No newline at end of file diff --git a/resources/views/theme/frontend/metronic/order/widget/info/base.blade.php b/resources/views/theme/frontend/metronic/order/widget/info/base.blade.php index 43e74a0..e0f54d9 100644 --- a/resources/views/theme/frontend/metronic/order/widget/info/base.blade.php +++ b/resources/views/theme/frontend/metronic/order/widget/info/base.blade.php @@ -11,12 +11,14 @@ @if ($o->setup_charge) Setup Charges * - ${{ number_format($user->exists ? $user->taxed($o->setup_charge) : Config::get('site')->taxed($o->setup_charge),2) }} + {{-- @todo this should use account::taxed() when the user is known --}} + ${{ number_format($user->exists ? Config::get('site')->taxed($o->setup_charge) : Config::get('site')->taxed($o->setup_charge),2) }} @endif - Cost + - ${{ number_format($user->exists ? $user->taxed($o->base_charge) : Config::get('site')->taxed($o->base_charge),2) }} + Cost + + {{-- @todo this should use account::taxed() when the user is known --}} + ${{ number_format($user->exists ? Config::get('site')->taxed($o->base_charge) : Config::get('site')->taxed($o->base_charge),2) }} Default Billing @@ -28,7 +30,8 @@ Minimum Costs +* - ${{ number_format($user->exists ? $user->taxed($o->min_charge) : Config::get('site')->taxed($o->min_charge),2) }} + {{-- @todo this should use account::taxed() when the user is known --}} + ${{ number_format($user->exists ? Config::get('site')->taxed($o->min_charge) : Config::get('site')->taxed($o->min_charge),2) }}