diff --git a/common/manager/EventRegistrationManager.php b/common/manager/EventRegistrationManager.php index b55fefc..696026d 100644 --- a/common/manager/EventRegistrationManager.php +++ b/common/manager/EventRegistrationManager.php @@ -10,8 +10,8 @@ use common\models\EventRegistration; use common\models\Ticket; use customerapi\models\available\EventInterval; use customerapi\models\registrations\EventRegistrationAvailable; +use customerapi\models\details\EventRegistrationView; use Exception; -use Throwable; use Yii; use yii\base\BaseObject; use yii\db\ActiveRecord; @@ -37,6 +37,7 @@ class EventRegistrationManager extends BaseObject const UNKNOWN_ERROR = 7; const MAX_SEAT_COUNT_EXCEEDED = 8; const EVENT_UNAVAILABLE = 9; + const ALREADY_REGISTERED = 10; public static $STATES = [ self::CARD_NOT_FOUND => 'CARD_NOT_FOUND', @@ -48,8 +49,7 @@ class EventRegistrationManager extends BaseObject self::UNKNOWN_ERROR => 'UNKNOWN_ERROR', self::MAX_SEAT_COUNT_EXCEEDED => 'MAX_SEAT_COUNT_EXCEEDED', self::EVENT_UNAVAILABLE => 'EVENT_UNAVAILABLE', - - + self::ALREADY_REGISTERED => 'ALREADY_REGISTERED', ]; /** @@ -77,7 +77,7 @@ class EventRegistrationManager extends BaseObject $activeTickets = $card->getActiveTickets(); if (count($activeTickets) === 0) { - throw new NotFoundHttpException('Ticket not found', self::TICKET_NOT_FOUND); + throw new NotFoundHttpException('Ticket not found1', self::TICKET_NOT_FOUND); } /** @var Event $event */ @@ -101,24 +101,23 @@ class EventRegistrationManager extends BaseObject } //detect if customer is already registered to event + /** @var EventRegistration[] $registrations */ $registrations = $event->getActiveEventRegistrations()->all(); foreach ($registrations as $registration ){ - if ($registration->customer_id == $card->customer->id_customer){ - throw new BadRequestHttpException("Already registered"); + if ($registration->id_customer == $card->customer->id_customer){ + throw new BadRequestHttpException("Already registered", self::ALREADY_REGISTERED); } } $selectedTicket = $eventType->findTicketAllowingEventType($activeTickets); - if (!isset($selectedTicket)) { - throw new NotFoundHttpException('Ticket not found', self::TICKET_INSUFFICIENT); + throw new NotFoundHttpException('Ticket not found2', self::TICKET_INSUFFICIENT); } - if ($selectedTicket->hasOpenReservationCount()) { - $selectedTicket->consumeReservationCount(1); - } + $selectedTicket->consumeReservationCount(1); + $selectedTicket->save(); $registration = new EventRegistration(); diff --git a/common/models/EventRegistration.php b/common/models/EventRegistration.php index 03bf6d1..8a4f2b8 100644 --- a/common/models/EventRegistration.php +++ b/common/models/EventRegistration.php @@ -83,4 +83,56 @@ class EventRegistration extends \yii\db\ActiveRecord public function getCustomerClass(){ return Customer::class; } + + /** + * @param EventRegistration $eventRegistration + */ + public static function isActive($eventRegistration){ + if ( !isset($eventRegistration ) ){ + return false; + } + if ( isset($eventRegistration->canceled_at ) ){ + return false; + } + + if ( isset($eventRegistration->deleted_at ) ){ + return false; + } + + return true; + } + + /** + * @param EventRegistration $eventRegistration + */ + public static function isForCustomer($eventRegistration,$idCustomer){ + if ( !isset($eventRegistration ) ){ + return false; + } + if ( !isset($eventRegistration->id_customer ) ){ + return false; + } + + return $eventRegistration->id_customer == $idCustomer; + } + + /** + * @param EventRegistration[] $eventRegistrations + */ + public static function filterActive($eventRegistrations){ + return array_filter($eventRegistrations, EventRegistration::class.'::isActive' ); + } + + /** + * @param EventRegistration[] $eventRegistrations + */ + public static function filterForCustomer($eventRegistrations,$idCustomer){ + $result = []; + foreach ($eventRegistrations as $eventRegistration){ + if ( EventRegistration::isForCustomer($eventRegistration,$idCustomer)){ + $result[] = $eventRegistration; + } + } + return $result; + } } diff --git a/common/models/Ticket.php b/common/models/Ticket.php index 9cc39e7..7b9ec56 100644 --- a/common/models/Ticket.php +++ b/common/models/Ticket.php @@ -48,7 +48,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord const STATUS_DELETED = 0; const STATUS_ACTIVE = 10; const STATUS_INACTIVE = 20; - + public static $SQL_UPDATE = "UPDATE card as c1 left JOIN ( select ticket.id_card as id_card , max(ticket.id_ticket) as id_ticket from ticket @@ -68,7 +68,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord , c1.flag = case when c1.type = 50 then ( c1.flag & ~(1 << 0) ) when t.id_card is null then ( c1.flag | 1 << 0 ) else ( c1.flag & ~(1 << 0) ) end , c1.id_ticket_current = case when t.id_ticket is null then null else t.id_ticket end where c1.status = 10"; - + public static $SQL_UPDATE_CARD = "UPDATE card as c1 left JOIN ( select ticket.id_card as id_card , max(ticket.id_ticket) as id_ticket from ticket @@ -141,11 +141,11 @@ class Ticket extends \common\models\BaseFitnessActiveRecord [['start', 'end', 'created_at', 'updated_at'], 'safe'], [['comment'], 'required'], [['comment'], 'string', 'max' => 255], - + [[ 'start', ], 'date' , 'timestampAttribute' => 'timestampStart' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], [[ 'end' , ], 'date' , 'timestampAttribute' => 'timestampEnd' ,'timestampAttributeFormat' => 'yyyy-MM-dd' ], - - + + ]; } @@ -176,12 +176,12 @@ class Ticket extends \common\models\BaseFitnessActiveRecord 'original_end' => Yii::t('common/transfer', 'Eredeti érvényesség vége'), ]; } - + public function getCard(){ return $this->hasOne( Card::className(), ["id_card" =>"id_card" ] ); } - + public function getContract(){ return $this->hasOne( Contract::className(), ["id_contract" =>"id_contract" ] ); } @@ -189,7 +189,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord public function getTransfer(){ return $this->hasOne( Transfer::className(), ["id_object" =>"id_ticket"] )->andWhere(['transfer.type' => Transfer::TYPE_TICKET]); } - + public function getCardNumber(){ $result = ""; /** @noinspection PhpUndefinedFieldInspection */ @@ -199,11 +199,11 @@ class Ticket extends \common\models\BaseFitnessActiveRecord } return $result; } - + public function getCustomer(){ return $this->hasOne( Customer::className(), ["id_customer_card" =>"id_card" ] )->via('card'); } - + public function getCustomerName(){ $result = ""; /** @noinspection PhpUndefinedFieldInspection */ @@ -217,14 +217,14 @@ class Ticket extends \common\models\BaseFitnessActiveRecord public function getUser(){ return $this->hasOne( User::className(), ["id" =>"id_user" ] ); } - + public function getTicketType(){ return $this->hasOne( TicketType::className(), ["id_ticket_type" =>"id_ticket_type" ] ); } public function getDiscount(){ return $this->hasOne( Discount::className(), ["id_discount" =>"id_discount" ] ); } - + public function getAccount() { return $this->hasOne ( Account::className (), [ 'id_account' => 'id_account' @@ -277,10 +277,10 @@ class Ticket extends \common\models\BaseFitnessActiveRecord * @return array|\yii\db\ActiveRecord[] */ public static function readActive($card, $validOnDay = null){ - + if ( $card == null ) return []; - + $query = Ticket::find(); if (!isset( $validOnDay ) ){ $today = date('Y-m-d'); @@ -292,11 +292,11 @@ class Ticket extends \common\models\BaseFitnessActiveRecord $query->andWhere( 'ticket.start <= :today' ,[ 'today' => $today] ); $query->andWhere( 'ticket.end >= :today' ,[ 'today' => $today] ); $query->andWhere( 'ticket.status = :status' ,[ 'status' => Ticket::STATUS_ACTIVE] ); - $query->orderBy([ "ticket.created_at" =>SORT_DESC] ); + $query->orderBy([ "ticket.created_at" =>SORT_DESC] ); $result = $query->all(); return $result; - + } /** @@ -305,10 +305,10 @@ class Ticket extends \common\models\BaseFitnessActiveRecord * @return array|\yii\db\ActiveRecord[] */ public static function readUnpaid($card){ - + if ( $card == null ) return []; - + $query = Ticket::find(); $query->innerJoin("transfer", "transfer.id_object = ticket.id_ticket "); $today = date('Y-m-d'); @@ -320,39 +320,39 @@ class Ticket extends \common\models\BaseFitnessActiveRecord $query->andWhere( ["transfer.type" => Transfer::TYPE_TICKET] ); $query->andWhere( [ "transfer.status" => Transfer::STATUS_NOT_PAID ]); $query->orderBy([ "ticket.created_at" =>SORT_DESC] ); - + $result = $query->all(); return $result; - + } - - + + public static function mkStatisticQuery($start,$end,$id_card = null){ - - + + $query = new Query(); $query->addSelect( [ new Expression( 'ticket_type.id_ticket_type as id'), new Expression( 'ticket_type.name as name'), new Expression( 'coalesce( count(ticket.id_ticket),0) as total'), - + new Expression( "coalesce( sum( case when ticket.status <> " .Ticket::STATUS_DELETED ." AND ". Helper::sqlValidRule('ticket.start', 'ticket.end', ':start', ':end') . " then 1 else 0 end) , 0) as valid" ), //valid new Expression( "coalesce( sum( case when ticket.status <> " .Ticket::STATUS_DELETED ." AND ". Helper::sqlInIntervalRule('ticket.created_at', ':start', ':end') . " then 1 else 0 end) , 0) as created" ),//created new Expression( "coalesce( sum( case when ticket.status <> " .Ticket::STATUS_DELETED ." AND ". Helper::sqlInIntervalRule('ticket.created_at', ':start', ':end') . " then transfer.money else 0 end) , 0) as created_money" ),//created_money new Expression( "coalesce( sum( case when ticket.status <> " .Ticket::STATUS_DELETED ." AND " . Helper::sqlExpireRule('ticket.start', 'ticket.end', ':start', ":end") . " then 1 else 0 end) , 0) as expired" ), - - + + ]); - + $query->from('ticket_type'); $query->innerJoin('ticket', 'ticket.id_ticket_type = ticket_type.id_ticket_type'); $query->innerJoin('transfer', 'ticket.id_ticket = transfer.id_object and transfer.type = '. Transfer::TYPE_TICKET ); - + Helper::queryAccountConstraint($query, 'ticket.id_account'); - + $query->andFilterWhere(['id_card' =>$id_card]); - + $query->andWhere( [ 'or', @@ -361,23 +361,23 @@ class Ticket extends \common\models\BaseFitnessActiveRecord Helper::queryExpireRule('ticket.start', 'ticket.end', $start, $end), ] ); - - + + $query->groupBy("ticket_type.id_ticket_type, ticket_type.name"); - + $query->params([':start' => $start, ':end' => $end]); - + return $query; } - + public static function statuses( ) { return [ - Ticket::STATUS_ACTIVE => 'Aktív', - Ticket::STATUS_DELETED => 'Törölve', - Ticket::STATUS_INACTIVE => 'Inaktív', + Ticket::STATUS_ACTIVE => 'Aktív', + Ticket::STATUS_DELETED => 'Törölve', + Ticket::STATUS_INACTIVE => 'Inaktív', ]; } - + public static function toStatusName($id_status){ $result = "Ismeretlen"; $statuses = Ticket::statuses(); @@ -386,23 +386,23 @@ class Ticket extends \common\models\BaseFitnessActiveRecord } return $result; } - + public function getStatusName(){ return static::toStatusName($this->status); } - + public function isDeleted(){ return $this->status == Ticket::STATUS_DELETED; } - + /**csoportos beszedéses a bérlet*/ public function isInstallmentTicket(){ return ( isset($this->part_count) && $this->part_count > 0 ); } - + /** * Apply request - * + * * @var \common\models\TicketInstallmentRequest $request megbízás * */ public function applyTicketInstallmentRequest( $request ) { @@ -414,12 +414,12 @@ class Ticket extends \common\models\BaseFitnessActiveRecord } $this->recalclulate(); }else if ( $request->isStatusRejected() ){ - $this->status = static::STATUS_INACTIVE; + $this->status = static::STATUS_INACTIVE; } } } /* - * * + * * * @param common\models\TicketInstallmentRequest $request megbízás */ public function setPartRequired($request){ @@ -431,7 +431,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord } } } - + /** * Csoportos beszedéses bérlet érvényességének újraszámolása * */ @@ -457,7 +457,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord public function consumeReservationCount($count){ $newReservationCount = $this->reservation_count + $count; if ( $newReservationCount > $this->max_reservation_count ){ - throw new HttpException(406, 'Max ticket seat count exceeded',EventRegistrationManager::MAX_SEAT_COUNT_EXCEEDED); + throw new HttpException(400, 'Max ticket seat count exceeded',EventRegistrationManager::MAX_SEAT_COUNT_EXCEEDED); } $this->reservation_count = $newReservationCount; } @@ -473,7 +473,7 @@ class Ticket extends \common\models\BaseFitnessActiveRecord public function afterSave($insert, $changedAttributes) { Card::updateCardFlagTicket($this->id_card);; } - + public function afterDelete(){ Card::updateCardFlagTicket($this->id_card);; } diff --git a/customer/app/src/app/_helpers/error.interceptor.ts b/customer/app/src/app/_helpers/error.interceptor.ts index 6c4c25a..61e4bd3 100644 --- a/customer/app/src/app/_helpers/error.interceptor.ts +++ b/customer/app/src/app/_helpers/error.interceptor.ts @@ -1,6 +1,6 @@ import { Injectable } from "@angular/core"; import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "@angular/common/http"; -import { Observable, throwError } from "rxjs"; +import {EMPTY, Observable, throwError} from "rxjs"; import { catchError } from "rxjs/operators"; import { AuthenticationService} from "../services/authentication.service"; import {NavigationService} from "../services/navigation.service"; @@ -26,10 +26,11 @@ All other errors are RE-THROWN to be caught by the calling service so an alert c this.authenticationService.logout(); this.navigationService.navigateToLogin(); // location.reload(true); + return EMPTY; } - - const error = err.error.message || err.statusText; - return throwError(error); + // const error = err.error.message || err.statusText; + // return throwError(error); + return throwError(err); }) ) diff --git a/customer/app/src/app/_helpers/fake-backend.ts b/customer/app/src/app/_helpers/fake-backend.ts index a2cee01..7b8a54b 100644 --- a/customer/app/src/app/_helpers/fake-backend.ts +++ b/customer/app/src/app/_helpers/fake-backend.ts @@ -83,7 +83,8 @@ export class FakeBackendInterceptor implements HttpInterceptor { end: this.createEventDate(dayIndex, hourIndex + 1), trainer: [trainer1, trainer2][id % 2], eventType: eventTypes[id % eventTypes.length], - reservedAt: reservedAt, + // reservedAt: reservedAt, + registrations: [], reservationCount: id % 11, seat_count: 10 } diff --git a/customer/app/src/app/app.types.ts b/customer/app/src/app/app.types.ts index 5fb66e7..0e398a0 100644 --- a/customer/app/src/app/app.types.ts +++ b/customer/app/src/app/app.types.ts @@ -9,3 +9,17 @@ export interface PasswordChangeRequest{ passwordOld: string; password: string; } + + +export const RegistrationErrors ={ + CARD_NOT_FOUND : 1, + CUSTOMER_NOT_FOUND : 2, + TICKET_NOT_FOUND : 3, + NO_FREE_SEATS : 4, + EVENT_TYPE_NOT_FOUND : 5, + TICKET_INSUFFICIENT : 6, + UNKNOWN_ERROR : 7, + MAX_SEAT_COUNT_EXCEEDED : 8, + EVENT_UNAVAILABLE : 9, + ALREADY_REGISTERED : 10, +} diff --git a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.html b/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.html index f6ae3be..7a7e292 100644 --- a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.html +++ b/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.html @@ -1,9 +1,13 @@ - + class="event d-block p-1 pl-2 pr-2 mb-1 rounded text-truncate small text-white" title="Test Event 2" + [class.bg-dark]="maySelect()" + [class.bg-primary]="isRegistered()" + [class.bg-secondary]="isDisabled()" +> {{formatTime()}}:{{event.eventType.name}}
{{formatTrainer()}}
-
+ diff --git a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.spec.ts b/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.spec.ts deleted file mode 100644 index d3c7200..0000000 --- a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { MonthCalendarEventComponent } from './month-calendar-event.component'; - -describe('MonthCalendarEventComponent', () => { - let component: MonthCalendarEventComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ MonthCalendarEventComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MonthCalendarEventComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.ts b/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.ts index fefa463..9bee905 100644 --- a/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.ts +++ b/customer/app/src/app/components/month-calendar-event/month-calendar-event.component.ts @@ -40,4 +40,16 @@ export class MonthCalendarEventComponent implements OnInit { event: this.event }) } + + maySelect() { + return this.event.registrations?.length == 0 && this.event.hasFreeSeats; + } + + isRegistered() { + return this.event.registrations?.length > 0; + } + + isDisabled() { + return false; + } } diff --git a/customer/app/src/app/components/month-calendar/month-calendar.component.html b/customer/app/src/app/components/month-calendar/month-calendar.component.html index 70c205a..ba0ab37 100644 --- a/customer/app/src/app/components/month-calendar/month-calendar.component.html +++ b/customer/app/src/app/components/month-calendar/month-calendar.component.html @@ -2,8 +2,11 @@

Naptár

-
-
+
+
{{dayOfWeek.name}} {{dayOfWeek.shortName}}
diff --git a/customer/app/src/app/pages/event-details/event-details.component.html b/customer/app/src/app/pages/event-details/event-details.component.html index 7243ff6..f63d7f6 100644 --- a/customer/app/src/app/pages/event-details/event-details.component.html +++ b/customer/app/src/app/pages/event-details/event-details.component.html @@ -1,4 +1,4 @@ -
+

Jelentkezés

@@ -25,51 +25,15 @@
Terem
{{event?.room?.name }}
-

- Szükséges eszközök -

- -

{{equipment?.equipmentType?.name }}

-
-
-
- - -
-
- - -
-
-
-
+
- Foglalás - Lemondás - Már nincs szabad hely + Foglalás + Lemondás + Már nincs szabad hely + Vissza
- Vissza
diff --git a/customer/app/src/app/pages/event-details/event-details.component.ts b/customer/app/src/app/pages/event-details/event-details.component.ts index cebddd4..672ca45 100644 --- a/customer/app/src/app/pages/event-details/event-details.component.ts +++ b/customer/app/src/app/pages/event-details/event-details.component.ts @@ -1,8 +1,10 @@ -import { Component, OnInit } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import {Event, EventService, RegisterEventRequest} from "../../services/event.service"; import {ActivatedRoute} from "@angular/router"; import {NavigationService} from "../../services/navigation.service"; import {FormBuilder, FormGroup, Validators} from "@angular/forms"; +import {ToastrService} from "ngx-toastr"; +import {RegistrationErrors} from "../../app.types"; @Component({ selector: 'app-event-details', @@ -20,39 +22,32 @@ export class EventDetailsComponent implements OnInit { private fb: FormBuilder, private eventService: EventService, private route: ActivatedRoute, - private navigationService: NavigationService - ) { } + private navigationService: NavigationService, + private toastr: ToastrService + ) { + this.formControls = { + idEvent: ["", [Validators.required]], + } + this.eventForm = this.fb.group(this.formControls); + + } ngOnInit() { - console.info("event details") - this.formControls = { - idEvent: ["", [Validators.required ]], - } let idEvent = +this.route.snapshot.paramMap.get('idEvent'); this.eventService.findEvent(idEvent).subscribe( value => { - this.event = value; - this.event.equipmentTypeAssignments.forEach((assignment,index) =>{ - this.formControls['equipment'+assignment.id] = ["", [Validators.required ]] - }) - this.eventForm = this.fb.group(this.formControls); this.eventForm.patchValue({"idEvent": this.event.id}) } ); } mayRegister(event: Event) { - // return event.reservedAt == null && event.reservationCount < event.seat_count; - return true + return event.hasFreeSeats && event.registrations.length == 0; } mayCancel(event: Event) { - return event.reservedAt; - } - - noFreeSeat(event: Event) { - return event.reservedAt == null && event.reservationCount >= event.seat_count; + return event.registrations.length > 0; } goBack(event: Event) { @@ -60,33 +55,53 @@ export class EventDetailsComponent implements OnInit { } register(event: Event) { - console.info("register", event); - console.info(this.eventForm.value); - let request :RegisterEventRequest= { + let request: RegisterEventRequest = { idEvent: this.eventForm.value.idEvent, equipment: [] }; - this.event.equipmentTypeAssignments.forEach((value, index) => { - if ( this.eventForm.value.hasOwnProperty('equipment'+value.id) ){ - if ( this.eventForm.value['equipment'+value.id] === "1"){ - request.equipment.push(value.id); - } - } - }); - - console.info(request); this.eventService.register(request) .subscribe( - value => {}, - value => {}, + value => { + this.toastr.success('Sikeresen Foglalás', 'Foglalás'); + + this.navigationService.navigateToHome() + }, + error => { + let status = error.status; + let code = error?.error?.code; + let message = "Hiba történt"; + if (status == 400) { + switch (code) { + case RegistrationErrors.ALREADY_REGISTERED: + message = "Már regisztárlt erre az edzésre!"; + break; + case RegistrationErrors.MAX_SEAT_COUNT_EXCEEDED: + case RegistrationErrors.TICKET_INSUFFICIENT: + message = "Nem rendelkezik megfelelő bérlettel!" + break; + case RegistrationErrors.NO_FREE_SEATS: + message = "Nincs több szabad hely!" + break; + } + } + + this.toastr.error(message, "Foglalás") + }, ); } cancel(event: Event) { - + this.eventService.cancelRegistration(event.registrations[0].id) + .subscribe( + () => { + this.navigationService.navigateToHome(); + }, + () => { + this.toastr.error("Hiba történt", "Lemondás") + }); } } diff --git a/customer/app/src/app/pages/events/events.component.html b/customer/app/src/app/pages/events/events.component.html index d2351c4..3ab5b19 100644 --- a/customer/app/src/app/pages/events/events.component.html +++ b/customer/app/src/app/pages/events/events.component.html @@ -27,8 +27,8 @@
Vissza diff --git a/customer/app/src/app/pages/events/events.component.ts b/customer/app/src/app/pages/events/events.component.ts index a26d7f7..7d24f15 100644 --- a/customer/app/src/app/pages/events/events.component.ts +++ b/customer/app/src/app/pages/events/events.component.ts @@ -69,15 +69,15 @@ export class EventsComponent implements OnInit { } mayRegister(event: Event) { - return event.reservedAt == null && event.reservationCount < event.seat_count; + return event.hasFreeSeats && event.registrations.length == 0; } - mayCancel(event: Event) { - return event.reservedAt; - } + // mayCancel(event: Event) { + // return event.reservedAt; + // } noFreeSeat(event: Event) { - return event.reservedAt == null && event.reservationCount >= event.seat_count; + return !event.hasFreeSeats; } prepareEventDates(events: Event[]) { diff --git a/customer/app/src/app/pages/registrations/registrations.component.spec.ts b/customer/app/src/app/pages/registrations/registrations.component.spec.ts deleted file mode 100644 index 80c6083..0000000 --- a/customer/app/src/app/pages/registrations/registrations.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { RegistrationsComponent } from './registrations.component'; - -describe('RegistrationsComponent', () => { - let component: RegistrationsComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ RegistrationsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(RegistrationsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/customer/app/src/app/services/event.service.ts b/customer/app/src/app/services/event.service.ts index 311a2ca..d92fd22 100644 --- a/customer/app/src/app/services/event.service.ts +++ b/customer/app/src/app/services/event.service.ts @@ -1,9 +1,7 @@ import {Injectable} from '@angular/core'; import {HttpClient} from "@angular/common/http"; import {Endpoints} from "./endpoints"; -import {forkJoin, Observable} from "rxjs"; -import {map} from "rxjs/operators"; -import {CalendarEvent} from "../app.types"; +import { Observable} from "rxjs"; @Injectable({ providedIn: 'root' @@ -64,9 +62,9 @@ export interface Event { seat_count: number; reservationCount: number; eventType: EventType; - reservedAt: number; room: Room; - equipmentTypeAssignments?: EquipmentTypeAssignment[]; + registrations: Registration[]; + hasFreeSeats?: boolean; } export interface EquipmentTypeAssignment { @@ -106,7 +104,7 @@ export interface EventsAvailableResponse { export interface Registration { id: number; created_at: number; - event: Event + event?: Event } export interface RegisterEventRequest{ diff --git a/customer/app/src/app/services/navigation.service.ts b/customer/app/src/app/services/navigation.service.ts index 77380b7..02b8e23 100644 --- a/customer/app/src/app/services/navigation.service.ts +++ b/customer/app/src/app/services/navigation.service.ts @@ -29,5 +29,9 @@ export class NavigationService { this.navigate(['/registration/'+idRegistration ]) } + public navigateRegistrations(){ + this.navigate(['/registrations' ]); + } + } diff --git a/customerapi/controllers/EventController.php b/customerapi/controllers/EventController.php index 0a9626b..7490ec1 100644 --- a/customerapi/controllers/EventController.php +++ b/customerapi/controllers/EventController.php @@ -9,13 +9,19 @@ namespace customerapi\controllers; +use common\models\Event; +use common\models\EventRegistration; +use customerapi\manager\EventRegistrationManager; use customerapi\models\available\EventInterval; use customerapi\models\available\EventAvailable; use customerapi\models\DayToDisplay; use customerapi\models\details\EventDetailsView; +use customerapi\models\details\EventRegistrationView; +use customerapi\models\details\EventTypeDetailsView; +use customerapi\models\details\RoomDetailsView; +use customerapi\models\details\TrainerDetailsView; use DateTime; use Exception; -use yii\db\ActiveRecord; use yii\db\Query; use yii\web\Response; @@ -63,7 +69,7 @@ class EventController extends CustomerApiController ->innerJoinWith('trainer') ->innerJoinWith('eventType') ->innerJoinWith('room') - ->joinWith('activeEventRegistrationsForCustomer') +// ->leftJoin('activeEventRegistrationsForCustomer') ->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()]) ->andWhere(['<', 'event.start', (clone $interval->lastActiveDate)->modify('+1 day')->getTimestamp()]) ->andWhere(['event.active' => '1']) @@ -77,6 +83,7 @@ class EventController extends CustomerApiController $eventDay->setTime(0, 0); $event->reservationCount = $event->getEventRegistrationCount(); + $event->hasFreeSeats = $event->reservationCount < $event->seat_count; /** @var DayToDisplay $date */ foreach ($dates as $date) { @@ -105,7 +112,7 @@ class EventController extends CustomerApiController ->innerJoinWith('trainer') ->innerJoinWith('eventType') ->innerJoinWith('room') - ->joinWith('activeEventRegistrations') + ->joinWith('activeEventRegistrations','event.id = activeEventRegistrations.id_event') ->andWhere(['>=', 'event.start', $interval->firstActiveDate->getTimestamp()]) ->andWhere(['<', 'event.start', (clone $interval->lastActiveDate)->modify('+1 day')->getTimestamp()]) ->andWhere(['event.active' => '1']); @@ -121,11 +128,32 @@ class EventController extends CustomerApiController { $interval = EventInterval::createInterval(); try { - $query = EventDetailsView::find(); + $query = Event::find(); $query = $this->buildEventQuery($query, $interval); $query = $query->andWhere(['event.id' => $id_event]); + + /** @var Event $event */ $event = $query->one(); - return $this->asJson($event); + + + $result = new EventDetailsView(); + $result->id = $event->id; + $result->start = $event->start; + $result->end = $event->end; + $result->seatCount = $event->seat_count; + $result->trainer = TrainerDetailsView::findOne($event->id_trainer); + $result->room = RoomDetailsView::findOne($event->id_room); + $result->eventType = EventTypeDetailsView::findOne($event->id_event_type); + $registrations = EventRegistrationView::find()->all(); + $allActiveRegistrations = EventRegistration::filterActive($registrations); + $customerActiveRegistrations = EventRegistration::filterForCustomer($allActiveRegistrations,\Yii::$app->user->id); + $result->reservationCount = count($allActiveRegistrations); + $result->registrations = $customerActiveRegistrations; + $result->hasFreeSeats = $event->seat_count > count($allActiveRegistrations); + + + + return $this->asJson($result); } catch (Exception $e) { throw new \yii\base\Exception($e->getMessage()); } diff --git a/customerapi/controllers/EventRegistrationController.php b/customerapi/controllers/EventRegistrationController.php index 8ce7bff..8c1455c 100644 --- a/customerapi/controllers/EventRegistrationController.php +++ b/customerapi/controllers/EventRegistrationController.php @@ -59,7 +59,7 @@ class EventRegistrationController extends CustomerApiController $form->event_id = $id_event; $form->card_number = $card->number; - $manager = new EventRegistrationManager(); + $manager = new \common\manager\EventRegistrationManager(); $manager->registerCard($form); return $form->registration; diff --git a/customerapi/manager/EventRegistrationManager.php b/customerapi/manager/EventRegistrationManager.php index 65483df..d5818ed 100644 --- a/customerapi/manager/EventRegistrationManager.php +++ b/customerapi/manager/EventRegistrationManager.php @@ -17,7 +17,7 @@ class EventRegistrationManager return $this->prepareQueryFindRegistrationsForCustomer()->all(); } - public function findCustomerRegistrations() + public function findCustomerRegistrations($clazz= EventRegistration::class ) { $interval = EventInterval::createInterval(); return EventRegistration::find() diff --git a/customerapi/models/available/EventAvailable.php b/customerapi/models/available/EventAvailable.php index ef0d2bf..a74346d 100644 --- a/customerapi/models/available/EventAvailable.php +++ b/customerapi/models/available/EventAvailable.php @@ -10,6 +10,7 @@ class EventAvailable extends Event { public $reservationCount; + public $hasFreeSeats; protected function getTrainerClass() { @@ -39,6 +40,7 @@ class EventAvailable extends Event "seat_count" => "seat_count", "active" => "active", "reservationCount" => "reservationCount", + "hasFreeSeats" => "hasFreeSeats", ]; $fields['trainer'] = 'trainer'; $fields['eventType'] = 'eventType'; diff --git a/customerapi/models/details/EventDetailsView.php b/customerapi/models/details/EventDetailsView.php index 76570e2..052e16c 100644 --- a/customerapi/models/details/EventDetailsView.php +++ b/customerapi/models/details/EventDetailsView.php @@ -5,37 +5,37 @@ namespace customerapi\models\details; use common\models\Event; +use yii\base\Model; -class EventDetailsView extends Event +/** +$property string $eventName; +$property string $start; +$property string $end; +$property string $seatCount; +$property string $reservationCount; +$property customerapi\models\details\EventDetailsView $room; +$property customerapi\models\details\TrainerDetailsView $trainer; +$property customerapi\models\details\EventTypeDetailsView $eventType; +$property string $registrations; + */ +class EventDetailsView extends Model // extends Event { + public $id; + public $start; + public $end; + public $seatCount; + // total count of registrations public $reservationCount; + public $room; + public $trainer; + public $eventType; + // registrations for current user + public $registrations; + + public $hasFreeSeats; - /** - * @return string - */ - protected function getTrainerClass() - { - // override trainer class to have more control - // about json fields - return TrainerDetailsView::class; - } - - protected function getEventTypeClass() - { - return EventTypeDetailsView::class; - } - - protected function getRoomClass() - { - return RoomDetailsView::class; - } - - protected function getEquipmentTypeAssignmentsClass() - { - return EventEquipmentTypeAssignmentView::class; - } /** @@ -49,15 +49,17 @@ class EventDetailsView extends Event "id" => "id", "start" => "start", "end" => "end", - "seat_count" => "seat_count", - "active" => "active", -// "reservationCount" => "reservationCount" + "seat_count" => "seatCount", + "reservationCount" => "reservationCount", + "registrations" => "registrations", + "hasFreeSeats" => "hasFreeSeats" ]; $fields['trainer'] = 'trainer'; $fields['eventType'] = 'eventType'; $fields['room'] = 'room'; - $fields['equipmentTypeAssignments'] = 'equipmentTypeAssignments'; return $fields; } } + + diff --git a/customerapi/models/details/EventRegistrationView.php b/customerapi/models/details/EventRegistrationView.php new file mode 100644 index 0000000..5e05248 --- /dev/null +++ b/customerapi/models/details/EventRegistrationView.php @@ -0,0 +1,17 @@ + 'id', + 'created_at' => 'created_at', + ]; + } + +} diff --git a/docker/start.sh b/docker/start.sh index 94ed85c..f92c8da 100644 --- a/docker/start.sh +++ b/docker/start.sh @@ -4,6 +4,8 @@ PROJECT_DIR=$(pwd)/.. PORT=86 HOST=localhost +docker container stop fitness-web || true + docker run \ -v ${PROJECT_DIR}:/var/www/html/fitness_web \ --rm \