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\Service;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\DB;
class ServiceController extends Controller
{
@ -21,15 +23,61 @@ class ServiceController extends Controller
->with('drivers:name')
->with('crew:name')
->with('place')
->orderBy('start', 'desc')
->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
$place = Place::where('lat', $request->lat)->where('lon', $request->lon)->first();
if(!$place) {
@ -64,7 +112,6 @@ class ServiceController extends Controller
$place->save();
}
$service = new Service();
$service->code = $request->code;
$service->chief()->associate($request->chief);
$service->type()->associate($request->type);
@ -76,40 +123,28 @@ class ServiceController extends Controller
$service->updatedBy()->associate($request->user());
$service->save();
$service->drivers()->attach([3]);
$service->crew()->attach([4, 5, 6]);
$service->drivers()->attach(array_unique($request->drivers));
$service->crew()->attach(array_unique($request->crew));
$service->save();
}
/**
* Display the specified resource.
*/
public function show(Service $service)
{
//
}
$usersToIncrement = array_unique(array_merge(
[$request->chief],
$request->drivers,
$request->crew
));
User::whereIn('id', $usersToIncrement)->increment('services');
/**
* 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)
{
//
return response()->json(DB::getQueryLog());
}
/**
* 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 = [
'code',
'chief',
//'place', //TODO: replace with a table
'notes',
//'type' //TODO: add table
'notes'
];
/**

View File

@ -43,7 +43,9 @@ Route::middleware('auth:web')->group( function () {
Route::post('/manual_mode', [AvailabilityController::class, 'updateAvailabilityManualMode']);
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::post('/service_types', [ServiceTypeController::class, 'create']);

View File

@ -86,12 +86,10 @@ export class TableComponent implements OnInit, OnDestroy {
}
editService(id: number) {
return;
this.router.navigate(['/services', id]);
}
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; }) => {
Swal.fire({
title: res['table.remove_service_confirm'],

View File

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

View File

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

View File

@ -1,8 +1,5 @@
<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>
</div>
<app-table *ngIf="false" [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>
<app-table [sourceType]="'services'" [refreshInterval]="1200000"></app-table>