Implement service update and deletion

This commit is contained in:
Matteo Gheza 2023-09-01 13:23:44 +02:00
parent 89e66772a9
commit fc9c8635a6
7 changed files with 128 additions and 77 deletions

View File

@ -4,8 +4,10 @@ namespace App\Http\Controllers;
use App\Models\Place; use App\Models\Place;
use App\Models\Service; use App\Models\Service;
use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;
class ServiceController extends Controller class ServiceController extends Controller
{ {
@ -21,15 +23,61 @@ class ServiceController extends Controller
->with('drivers:name') ->with('drivers:name')
->with('crew:name') ->with('crew:name')
->with('place') ->with('place')
->orderBy('start', 'desc')
->get() ->get()
); );
} }
/** /**
* Add a new Service. * Get single Service
*/ */
public function create(Request $request) public function show($id)
{ {
return response()->json(
Service::join('users', 'users.id', '=', 'chief_id')
->join('services_types', 'services_types.id', '=', 'type_id')
->select('services.*', 'users.name as chief', 'services_types.name as type')
->with('drivers:name')
->with('crew:name')
->with('place')
->find($id)
);
}
private function extractServiceUsers($service)
{
$usersList = [$service->chief_id];
foreach($service->drivers as $driver) {
$usersList[] = $driver->id;
}
foreach($service->crew as $crew) {
$usersList[] = $crew->id;
}
return array_unique($usersList);
}
/**
* Add or update Service.
*/
public function createOrUpdate(Request $request)
{
DB::connection()->enableQueryLog();
$adding = !isset($request->id) || is_null($request->id);
$service = $adding ? new Service() : Service::find($request->id)->with('drivers')->with('crew')->first();
if(is_null($service)) abort(404);
if(!$adding) {
$usersToDecrement = $this->extractServiceUsers($service);
User::whereIn('id', $usersToDecrement)->decrement('services');
$service->drivers()->detach();
$service->crew()->detach();
$service->save();
}
//Find Place by lat lon //Find Place by lat lon
$place = Place::where('lat', $request->lat)->where('lon', $request->lon)->first(); $place = Place::where('lat', $request->lat)->where('lon', $request->lon)->first();
if(!$place) { if(!$place) {
@ -64,7 +112,6 @@ class ServiceController extends Controller
$place->save(); $place->save();
} }
$service = new Service();
$service->code = $request->code; $service->code = $request->code;
$service->chief()->associate($request->chief); $service->chief()->associate($request->chief);
$service->type()->associate($request->type); $service->type()->associate($request->type);
@ -76,40 +123,28 @@ class ServiceController extends Controller
$service->updatedBy()->associate($request->user()); $service->updatedBy()->associate($request->user());
$service->save(); $service->save();
$service->drivers()->attach([3]); $service->drivers()->attach(array_unique($request->drivers));
$service->crew()->attach([4, 5, 6]); $service->crew()->attach(array_unique($request->crew));
$service->save(); $service->save();
}
/** $usersToIncrement = array_unique(array_merge(
* Display the specified resource. [$request->chief],
*/ $request->drivers,
public function show(Service $service) $request->crew
{ ));
// User::whereIn('id', $usersToIncrement)->increment('services');
}
/** return response()->json(DB::getQueryLog());
* Show the form for editing the specified resource.
*/
public function edit(Service $service)
{
//
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Service $service)
{
//
} }
/** /**
* Remove the specified resource from storage. * Remove the specified resource from storage.
*/ */
public function destroy(Service $service) public function destroy($id)
{ {
// $service = Service::find($id);
$usersToDecrement = $this->extractServiceUsers($service);
User::whereIn('id', $usersToDecrement)->decrement('services');
$service->delete();
} }
} }

View File

@ -19,9 +19,7 @@ class Service extends Model
protected $fillable = [ protected $fillable = [
'code', 'code',
'chief', 'chief',
//'place', //TODO: replace with a table 'notes'
'notes',
//'type' //TODO: add table
]; ];
/** /**

View File

@ -43,7 +43,9 @@ Route::middleware('auth:web')->group( function () {
Route::post('/manual_mode', [AvailabilityController::class, 'updateAvailabilityManualMode']); Route::post('/manual_mode', [AvailabilityController::class, 'updateAvailabilityManualMode']);
Route::get('/services', [ServiceController::class, 'index']); Route::get('/services', [ServiceController::class, 'index']);
Route::post('/services', [ServiceController::class, 'create']); Route::post('/services', [ServiceController::class, 'createOrUpdate']);
Route::get('/services/{id}', [ServiceController::class, 'show']);
Route::delete('/services/{id}', [ServiceController::class, 'destroy']);
Route::get('/service_types', [ServiceTypeController::class, 'index']); Route::get('/service_types', [ServiceTypeController::class, 'index']);
Route::post('/service_types', [ServiceTypeController::class, 'create']); Route::post('/service_types', [ServiceTypeController::class, 'create']);

View File

@ -86,12 +86,10 @@ export class TableComponent implements OnInit, OnDestroy {
} }
editService(id: number) { editService(id: number) {
return;
this.router.navigate(['/services', id]); this.router.navigate(['/services', id]);
} }
deleteService(id: number) { deleteService(id: number) {
return;
this.translate.get(['table.yes_remove', 'table.cancel', 'table.remove_service_confirm', 'table.remove_service_text']).subscribe((res: { [key: string]: string; }) => { this.translate.get(['table.yes_remove', 'table.cancel', 'table.remove_service_confirm', 'table.remove_service_text']).subscribe((res: { [key: string]: string; }) => {
Swal.fire({ Swal.fire({
title: res['table.remove_service_confirm'], title: res['table.remove_service_confirm'],

View File

@ -3,15 +3,15 @@
<form method="post" [formGroup]="serviceForm" (ngSubmit)="formSubmit()"> <form method="post" [formGroup]="serviceForm" (ngSubmit)="formSubmit()">
<div class="container"> <div class="container">
<div class="form-group has-validation"> <div class="form-group has-validation">
<label for="date-picker">{{ 'start'|translate|titlecase }}</label> <label for="date-picker-start">{{ 'start'|translate|titlecase }}</label>
<datetime-picker formControlName="start" [class.is-invalid]="!isFieldValid('start')"></datetime-picker> <datetime-picker formControlName="start" [class.is-invalid]="!isFieldValid('start')" id="date-picker-start"></datetime-picker>
<div class="invalid-feedback" *ngIf="start.errors?.['required']" translate> <div class="invalid-feedback" *ngIf="start.errors?.['required']" translate>
edit_service.select_start_datetime edit_service.select_start_datetime
</div> </div>
</div> </div>
<div class="form-group has-validation"> <div class="form-group has-validation">
<label for="date-picker">{{ 'end'|translate|titlecase }}</label> <label for="date-picker-end">{{ 'end'|translate|titlecase }}</label>
<datetime-picker formControlName="end" [class.is-invalid]="!isFieldValid('end')"></datetime-picker> <datetime-picker formControlName="end" [class.is-invalid]="!isFieldValid('end')" id="date-picker-end"></datetime-picker>
<div class="invalid-feedback" *ngIf="end.errors?.['required']" translate> <div class="invalid-feedback" *ngIf="end.errors?.['required']" translate>
edit_service.select_end_datetime edit_service.select_end_datetime
</div> </div>
@ -30,7 +30,7 @@
<ng-container *ngFor="let user of users"> <ng-container *ngFor="let user of users">
<div class="form-check"> <div class="form-check">
<input formControlName="chief" [class.is-invalid]="!isFieldValid('chief')" <input formControlName="chief" [class.is-invalid]="!isFieldValid('chief')"
class="form-check-input chief-{{ user.id }}" type="radio" value='{{ user.id }}'> class="form-check-input" id="chief-{{ user.id }}" type="radio" value='{{ user.id }}'>
<label class="form-check-label" for="chief-{{ user.id }}"> <label class="form-check-label" for="chief-{{ user.id }}">
{{ user.name }} {{ user.name }}
</label> </label>
@ -42,7 +42,7 @@
<br> <br>
<ng-container *ngFor="let user of users"> <ng-container *ngFor="let user of users">
<div class="form-check" *ngIf="user.driver"> <div class="form-check" *ngIf="user.driver">
<input class="form-check-input driver-{{ user.id }}" [class.is-invalid]="!isFieldValid('drivers')" <input class="form-check-input" id="driver-{{ user.id }}" [class.is-invalid]="!isFieldValid('drivers')"
(change)="onDriversCheckboxChange($event)" [checked]="isDriverSelected(user.id)" type="checkbox" value='{{ user.id }}'> (change)="onDriversCheckboxChange($event)" [checked]="isDriverSelected(user.id)" type="checkbox" value='{{ user.id }}'>
<label class="form-check-label" for="driver-{{ user.id }}"> <label class="form-check-label" for="driver-{{ user.id }}">
{{ user.name }} {{ user.name }}
@ -55,7 +55,7 @@
<br> <br>
<ng-container *ngFor="let user of users"> <ng-container *ngFor="let user of users">
<div class="form-check"> <div class="form-check">
<input class="form-check-input crew-{{ user.id }}" [class.is-invalid]="!isFieldValid('crew')" <input class="form-check-input" id="crew-{{ user.id }}" [class.is-invalid]="!isFieldValid('crew')"
(change)="onCrewCheckboxChange($event)" [checked]="isCrewSelected(user.id)" type="checkbox" value='{{ user.id }}'> (change)="onCrewCheckboxChange($event)" [checked]="isCrewSelected(user.id)" type="checkbox" value='{{ user.id }}'>
<label class="form-check-label" for="crew-{{ user.id }}"> <label class="form-check-label" for="crew-{{ user.id }}">
{{ user.name }} {{ user.name }}

View File

@ -20,8 +20,8 @@ export class EditServiceComponent implements OnInit {
chief: '', chief: '',
drivers: [], drivers: [],
crew: [], crew: [],
lat: 0, lat: -1,
lon: 0, lon: -1,
notes: '', notes: '',
type: '' type: ''
}; };
@ -30,7 +30,7 @@ export class EditServiceComponent implements OnInit {
users: any[] = []; users: any[] = [];
types: any[] = []; types: any[] = [];
addingType = false; addingType = false;
newType = ""; newType = "";
@ -56,8 +56,8 @@ export class EditServiceComponent implements OnInit {
chief: [this.loadedService.chief, [Validators.required]], chief: [this.loadedService.chief, [Validators.required]],
drivers: [this.loadedService.drivers, [Validators.required]], drivers: [this.loadedService.drivers, [Validators.required]],
crew: [this.loadedService.crew, [Validators.required]], crew: [this.loadedService.crew, [Validators.required]],
lat: [this.loadedService.lat, [Validators.required]], //TODO add validations or in UI you can submit without place lat: [this.loadedService.lat, [Validators.required, Validators.min(0)]], //TODO add validations or in UI you can submit without place
lon: [this.loadedService.lon, [Validators.required]], lon: [this.loadedService.lon, [Validators.required, Validators.min(0)]],
notes: [this.loadedService.notes], notes: [this.loadedService.notes],
type: [this.loadedService.type, [Validators.required, Validators.minLength(1)]] type: [this.loadedService.type, [Validators.required, Validators.minLength(1)]]
}); });
@ -72,19 +72,25 @@ export class EditServiceComponent implements OnInit {
) { ) {
this.route.paramMap.subscribe(params => { this.route.paramMap.subscribe(params => {
this.serviceId = params.get('id') || undefined; this.serviceId = params.get('id') || undefined;
if(this.serviceId === "new") { if (this.serviceId === "new") {
this.addingService = true; this.addingService = true;
} else { } else {
this.api.get(`services/${this.serviceId}`).then((service) => { this.api.get(`services/${this.serviceId}`).then((service) => {
this.loadedService = service; this.loadedService = service;
this.loadedServiceLat = service.lat; this.loadedServiceLat = service.place.lat;
this.loadedServiceLng = service.lng; this.loadedServiceLng = service.place.lon;
this.chief.setValue(service.chief_id);
console.log(service);
let patch = Object.assign({}, service); let patch = Object.assign({}, service);
patch.start = new Date(parseInt(patch.start)); patch.start = new Date(patch.start);
patch.end = new Date(parseInt(patch.end)); patch.end = new Date(patch.end);
patch.drivers = patch.drivers.split(";"); patch.chief = patch.chief_id;
patch.crew = patch.crew.split(";"); patch.drivers = patch.drivers.map((e: any) => e.pivot.user_id+"");
patch.crew = patch.crew.map((e: any) => e.pivot.user_id+"");
patch.type = patch.type_id;
this.serviceForm.patchValue(patch); this.serviceForm.patchValue(patch);
}); });
} }
@ -105,13 +111,13 @@ export class EditServiceComponent implements OnInit {
} }
addType() { addType() {
if(this.newType.length < 2) { if (this.newType.length < 2) {
this.translate.get('edit_service.type_must_be_two_characters_long').subscribe((res: string) => { this.translate.get('edit_service.type_must_be_two_characters_long').subscribe((res: string) => {
this.toastr.error(res); this.toastr.error(res);
}); });
return; return;
} }
if(this.types.find(t => t.name == this.newType)) { if (this.types.find(t => t.name == this.newType)) {
this.translate.get('edit_service.type_already_exists').subscribe((res: string) => { this.translate.get('edit_service.type_already_exists').subscribe((res: string) => {
this.toastr.error(res); this.toastr.error(res);
}); });
@ -123,9 +129,9 @@ export class EditServiceComponent implements OnInit {
this.addingType = false; this.addingType = false;
this.newType = ""; this.newType = "";
console.log(type); console.log(type);
if(type.name) { if (type.name) {
this.translate.get('edit_service.type_added_successfully').subscribe((res: string) => { this.translate.get('edit_service.type_added_successfully').subscribe((res: string) => {
this.toastr.success(res); this.toastr.success(res);
}); });
this.loadTypes(); this.loadTypes();
} }
@ -168,27 +174,42 @@ export class EditServiceComponent implements OnInit {
formSubmit() { formSubmit() {
console.log("form values", this.serviceForm.value); console.log("form values", this.serviceForm.value);
this.formSubmitAttempt = true; this.formSubmitAttempt = true;
if(this.serviceForm.valid) { if (this.serviceForm.valid) {
this.submittingForm = true; this.submittingForm = true;
let values = Object.assign({}, this.serviceForm.value); let values = Object.assign({}, this.serviceForm.value);
values.start = values.start.getTime(); values.start = values.start.getTime();
values.end = values.end.getTime(); values.end = values.end.getTime();
values.drivers = values.drivers.join(";");
values.crew = values.crew.join(";");
console.log(values); console.log(values);
this.api.post("services", values).then((res) => { if (this.serviceId !== "new") {
console.log(res); values.id = this.serviceId;
this.translate.get('edit_service.service_added_successfully').subscribe((res: string) => { this.api.post("services", values).then((res) => {
this.toastr.success(res); console.log(res);
this.translate.get('edit_service.service_added_successfully').subscribe((res: string) => {
this.toastr.success(res);
});
this.submittingForm = false;
}).catch((err) => {
console.error(err);
this.translate.get('edit_service.service_add_failed').subscribe((res: string) => {
this.toastr.error(res);
});
this.submittingForm = false;
}); });
this.submittingForm = false; } else {
}).catch((err) => { this.api.post("services", values).then((res) => {
console.error(err); console.log(res);
this.translate.get('edit_service.service_add_failed').subscribe((res: string) => { this.translate.get('edit_service.service_added_successfully').subscribe((res: string) => {
this.toastr.error(res); this.toastr.success(res);
});
this.submittingForm = false;
}).catch((err) => {
console.error(err);
this.translate.get('edit_service.service_add_failed').subscribe((res: string) => {
this.toastr.error(res);
});
this.submittingForm = false;
}); });
this.submittingForm = false; }
});
} }
} }

View File

@ -1,8 +1,5 @@
<owner-image></owner-image> <owner-image></owner-image>
<div *ngIf="false" class="text-center mb-4"> <div class="text-center mb-4">
<button type="button" class="btn btn-primary" (click)="addService()">{{ 'add'|translate|titlecase }} {{ 'service'|translate }}</button> <button type="button" class="btn btn-primary" (click)="addService()">{{ 'add'|translate|titlecase }} {{ 'service'|translate }}</button>
</div> </div>
<app-table *ngIf="false" [sourceType]="'services'" [refreshInterval]="1200000"></app-table> <app-table [sourceType]="'services'" [refreshInterval]="1200000"></app-table>
<div class="alert alert-warning" role="alert">
Questa sezione di AllertaVVF è stata temporaneamente disabilitata per motivi di manutenzione. Ci scusiamo per il disagio.
</div>