improve integration tests

This commit is contained in:
Schneider Roland
2022-05-13 23:01:14 +02:00
parent 946799a598
commit 7e5efc2c7f
8 changed files with 532 additions and 251 deletions

View File

@@ -0,0 +1,72 @@
<?php
namespace common\components;
class StopWatch
{
public $start;
public $splits = [];
public $stop;
// public function _(){
// $this->start();
// }
public function __construct()
{
$this->start();
}
public function start()
{
$this->start = $this->time();
}
public function split()
{
$this->splits[] = $this->time();
return $this->getSplit();
}
public function stop()
{
$this->stop = $this->time();
}
function time()
{
return time();
}
function diff($start, $end)
{
if (!isset($start) || !isset($end)) {
return -1;
}
return $end - $start;
}
function getSplit()
{
$lastSplit = null;
if (isset($this->stop)) {
$lastSplit = $this->stop;
} else {
$count = count($this->splits);
if ($count > 0) {
$lastSplit = $this->splits[$count - 1];
}
}
return $this->diff($this->start, $lastSplit);
}
function getTotal(){
return $this->diff($this->start, $this->stop);
}
}

View File

@@ -4,26 +4,15 @@ namespace common\manager;
use common\components\DateUtil;
use common\components\Helper;
use common\components\StopWatch;
use common\models\Card;
use common\models\CardEventRegistrationForm;
use common\models\Customer;
use common\models\DoorLog;
use common\models\DoorLogForTest;
use common\models\Event;
use common\models\EventRegistration;
use common\models\Log;
use common\models\MobileDevice;
use common\models\Ticket;
use customerapi\models\available\EventInterval;
use customerapi\models\registrations\EventRegistrationAvailable;
use customerapi\models\details\EventRegistrationView;
use Exception;
use Yii;
use frontend\models\KeyToggleForm;
use yii\base\BaseObject;
use yii\db\ActiveRecord;
use yii\db\Query;
use yii\web\BadRequestHttpException;
use yii\web\NotFoundHttpException;
use yii\web\ServerErrorHttpException;
/**
@@ -46,219 +35,262 @@ class DoorManager extends BaseObject
* @throws BadRequestHttpException
* @throws \yii\base\InvalidConfigException
*/
public function move($cardNumber, $device, $direction, $createdAt = null, $date = null )
public function move($cardNumber, $device, $direction, $createdAt = null, $date = null)
{
if ( isset($createdAt)){
$createdAt = DateUtil::parseDateTime($createdAt);
}else{
$createdAt = DateUtil::utcDateTime();
}
try {
\Yii::$app->db->beginTransaction();
$createdAtStr = DateUtil::formatDateTimeUtc($createdAt);
$stopWatch = new StopWatch();
\Yii::error("Started");
if (isset($createdAt)) {
$createdAt = DateUtil::parseDateTime($createdAt);
} else {
$createdAt = DateUtil::utcDateTime();
}
if ( isset($date)){
$date = DateUtil::parseDateTime($date);
}else{
$date = DateUtil::utcDate();
}
$createdAtStr = DateUtil::formatDateTimeUtc($createdAt);
$dateStr = DateUtil::formatDateUtc($date);
if (isset($date)) {
$date = DateUtil::parseDateTime($date);
} else {
$date = DateUtil::utcDate();
}
$doorLog = new DoorLog();
$doorLog->direction = $direction;
$doorLog->source_app = $device;
$doorLog->created_at = $createdAtStr;
$dateStr = DateUtil::formatDateUtc($date);
/**
* emergency- no card needed
*/
if ($direction == DoorLog::$DIRECTION_ALL_EMERGENCY) {
$doorLog->save(false);
Log::log(
[
'type' => Log::$TYPE_INFO,
'message' => 'Ajtó nyitás: vészhelyzet',
'id_door_log' => $doorLog->id_door_log
]
);
\Yii::$app->response->statusCode = 204;
return;
}
$doorLog = new DoorLog();
$doorLog->direction = $direction;
$doorLog->source_app = $device;
$doorLog->created_at = $createdAtStr;
$card = Card::readCard(Helper::fixAsciiChars($cardNumber));
/*
* in any other cases, the door needs a card
*/
if (!isset($card)) {
throw new BadRequestHttpException('Card not found with number: ' . $cardNumber);
}
$doorLog->id_card = $card->id_card;
$doorLog->card_flag = $card->flag;
/**
* if the card type is employee, neither customer nor ticket is needed.
* Free to enter/leave
*/
if ($card->type == Card::TYPE_EMPLOYEE) {
$doorLog->save(false);
\Yii::$app->response->statusCode = 204;
return;
}
//otherwise ticket is required
$activeTickets = Ticket::readActive($card, clone $date);
\Yii::error('active ticket count:' . count($activeTickets));
$ticket = null;
if (isset($activeTickets) && count($activeTickets) > 0) {
$ticket = $activeTickets[0];
}
$doorLog->id_ticket_current = $ticket->id_ticket;
if (!isset($ticket)) {
throw new BadRequestHttpException("No active ticket found for:" . $card->number);
}
\Yii::error("active ticket: " . $ticket->id_ticket);
// customer is also required
$customer = $card->customer;
if (!isset($customer)) {
throw new BadRequestHttpException("Customer not found for:" . $card->number);
}
$doorLog->id_customer = $customer->id_customer;
// save the door log
$doorLog->save(false);
// if direction is in
if ($direction == DoorLog::$DIRECTION_IN || $direction == DoorLog::$DIRECTION_IN_WITHOUT_MOVE) {
$countDoorLogsForTicketSince = $this->getCountDoorLogsForTicketSince($ticket->id_ticket, DateUtil::utcDate( clone $date));
// if the current event is the first door log today
if ($countDoorLogsForTicketSince == 1) {
// increase the ticket usage count with 1
$usageCount = $ticket->usage_count;
$ticket->usage_count += 1;
$ticket->save(false);
/**
* emergency- no card needed
*/
if ($direction == DoorLog::$DIRECTION_ALL_EMERGENCY) {
$doorLog->save(false);
Log::log(
[
'type' => Log::$TYPE_TICKET_USAGE_FIRST,
'message' => 'Bérlet használat(előtte: ' . $usageCount . ' -> utána: ' . $ticket->usage_count,
'id_ticket' => $ticket->id_ticket,
'type' => Log::$TYPE_INFO,
'message' => 'Ajtó nyitás: vészhelyzet',
'id_door_log' => $doorLog->id_door_log
]
);
} else {
// we have already a door log for today, other than this
// Now we split the day into 3hour intervalls, starting with the createdAt value of the first event.
// If the actual event happens in an interval, in which still now doorlog event happend, we increase
// the usage count with 1
// 3 óránként 1-et levonunk
$startOfDay = DateUtil::utcDate(clone $date);
$startOfTomorrow = DateUtil::tomorrowStart(clone $date);
$allDoorLogToday = DoorLog::find()
->andWhere(['>=', 'door_log.created_at', DateUtil::formatDateUtc($startOfDay)])
->andWhere(['<', 'door_log.created_at', DateUtil::formatDateUtc($startOfTomorrow)])
->andWhere(['id_ticket_current' => $ticket->id_ticket])
->andWhere(['in', 'direction', [DoorLog::$DIRECTION_IN_WITHOUT_MOVE, DoorLog::$DIRECTION_IN]])
->orderBy(['door_log.created_at' => SORT_ASC])
->all();
\Yii::error("new door log: ".$doorLog->id_door_log.";".$doorLog->created_at.";".$doorLog->type);
foreach ($allDoorLogToday as $log){
\Yii::error("all log: ".$log->id_door_log.";".$log->created_at.";".$log->type);
}
$firstInToday = $allDoorLogToday[0];
if (isset($firstInToday)) {
$firstEntryDateTimeToday = DateUtil::parseDateTime($firstInToday->created_at);
$interval = \DateInterval::createFromDateString('3 hours');
$daterange = new \DatePeriod($firstEntryDateTimeToday, $interval ,$startOfTomorrow);
$intervals = [];
$intervalStart = null;
foreach($daterange as $intervalEnd){
if ( isset($intervalStart)){
$intervals[] = $this->createTicketUsageInterval($intervalStart,$intervalEnd,$allDoorLogToday,$doorLog);
}
$intervalStart = clone $intervalEnd;
}
if ( $intervalStart < $startOfTomorrow ){
$intervals[] = $this->createTicketUsageInterval($intervalStart,$startOfTomorrow,$allDoorLogToday,$doorLog);
}
$activeInterval = $this->getActiveInterval($intervals,$createdAt);
if ( !isset($activeInterval)){
throw new ServerErrorHttpException("Active Interval not found");
}
$logCountInActiveInterval = count($activeInterval['logs']);
if ( $logCountInActiveInterval == 1){
$ticket->usage_count = $ticket->usage_count+1;
$ticket->save(false);
}
}
// select min(created_at) + INTERVAL (3 * FLOOR( ( ( HOUR( TIMEDIFF( min(created_at) , now() ) ) /3 ) ) ) ) hour as last_date
// into @p_from
// from door_log
// where created_at > CURDATE() and id_customer is not null and id_ticket_current = NEW.id_ticket_current and ( direction = 7 or direction = 3);
// select count(*) into @p_count_all_2 from door_log where created_at >= @p_from and id_ticket_current = New.id_ticket_current and ( direction = 7 or direction = 3);
// INSERT INTO devlog ( msg) values(CONCAT( 'Bel<65>p<EFBFBD>sek sz<73>ma az aktu<74>lis 3 <20>r<EFBFBD>s intervalumban: ', @p_count_all_2) );
// IF @p_count_all_2 = 1
// THEN
// INSERT INTO devlog ( msg) values( 'Az aktu<74>lis intervallumban ez az els? bel<65>p<EFBFBD>s, usage_count n<>vel<65>se' );
//
// select usage_count, max_usage_count into @p_usage_count ,@p_max_usage_count from ticket where id_ticket = NEW.id_ticket_current;
//
// update ticket set usage_count = usage_count +1 where id_ticket = New.id_ticket_current;
//
// INSERT INTO log (type,message, app, id_ticket, id_door_log,created_at, updated_at)
// values(
// 40, concat('B<>rlet haszn<7A>lat/egy nap tobbszori (elotte: ',@p_usage_count, ' > utana: ' , @p_usage_count +1 , ' max: ', @p_max_usage_count, ')' ), ' trigger_inc_ticket',New.id_ticket_current, New.id_door_log,now(),now());
// END IF;
\Yii::$app->response->statusCode = 204;
\Yii::error("emergency event in sec " . $stopWatch->split());
\Yii::$app->db->transaction->commit();
return;
}
//
$card = Card::readCard(Helper::fixAsciiChars($cardNumber));
\Yii::error("card loaded in sec " . $stopWatch->split());
//
//
/*
* in any other cases, the door needs a card
*/
if (!isset($card)) {
throw new BadRequestHttpException('Card not found with number: ' . $cardNumber);
}
\Yii::error("finished");
$doorLog->id_card = $card->id_card;
$doorLog->card_flag = $card->flag;
/**
* if the card type is employee, neither customer nor ticket is needed.
* Free to enter/leave
*/
if ($card->type == Card::TYPE_EMPLOYEE) {
$doorLog->save(false);
\Yii::$app->response->statusCode = 204;
\Yii::error("employee card {$card->id_card} event finished in sec " . $stopWatch->split());
\Yii::$app->db->transaction->commit();
return;
}
//otherwise ticket is required
$activeTickets = Ticket::readActive($card, clone $date);
\Yii::error('active ticket count:' . count($activeTickets));
/** @var Ticket $ticket */
$ticket = null;
if (isset($activeTickets) && count($activeTickets) > 0) {
$ticket = $activeTickets[0];
}
$doorLog->id_ticket_current = $ticket->id_ticket;
if (!isset($ticket)) {
throw new BadRequestHttpException("No active ticket found for:" . $card->number);
}
\Yii::error("ticket {$ticket->id_ticket} loaded in sec " . $stopWatch->split());
// customer is also required
$customer = $card->customer;
if (!isset($customer)) {
throw new BadRequestHttpException("Customer not found for:" . $card->number);
}
$doorLog->id_customer = $customer->id_customer;
\Yii::error("customer {$customer->id_customer} loaded in sec " . $stopWatch->split());
// save the door log
$doorLog->save(false);
\Yii::error("door log {$doorLog->id_door_log} saved in sec " . $stopWatch->split());
// if direction is in
if ($direction == DoorLog::$DIRECTION_IN || $direction == DoorLog::$DIRECTION_IN_WITHOUT_MOVE) {
if ($card->isFlagDoor()) {
throw new BadRequestHttpException("Card already 'IN': " . $card->id_card);
}
if ($card->isFlagKey()) {
throw new BadRequestHttpException("Key required: " . $card->id_card);
}
if ($card->isFlagStatus()) {
throw new BadRequestHttpException("Card has no active status: " . $card->id_card);
}
$countDoorLogsForTicketSince = $this->getCountDoorLogsForTicketSince($ticket->id_ticket, DateUtil::utcDate(clone $date));
\Yii::error("count of door logs '{$countDoorLogsForTicketSince}' loaded in sec " . $stopWatch->split());
// if the current event is the first door log today
if ($countDoorLogsForTicketSince == 1) {
// increase the ticket usage count with 1
$usageCount = $ticket->usage_count;
$ticket->usage_count += 1;
$ticket->save(false);
Log::log(
[
'type' => Log::$TYPE_TICKET_USAGE_FIRST,
'message' => 'Bérlet használat(előtte: ' . $usageCount . ' -> utána: ' . $ticket->usage_count,
'id_ticket' => $ticket->id_ticket,
'id_door_log' => $doorLog->id_door_log
]
);
\Yii::error("Ticket usage count increased after first doorlog of day in sec " . $stopWatch->split());
} else {
// we have already a door log for today, other than this
// Now we split the day into 3hour intervalls, starting with the createdAt value of the first event.
// If the actual event happens in an interval, in which still now doorlog event happend, we increase
// the usage count with 1
// 3 óránként 1-et levonunk
$startOfDay = DateUtil::utcDate(clone $date);
$startOfTomorrow = DateUtil::tomorrowStart(clone $date);
$allDoorLogToday = DoorLog::find()
->andWhere(['>=', 'door_log.created_at', DateUtil::formatDateUtc($startOfDay)])
->andWhere(['<', 'door_log.created_at', DateUtil::formatDateUtc($startOfTomorrow)])
->andWhere(['id_ticket_current' => $ticket->id_ticket])
->andWhere(['in', 'direction', [DoorLog::$DIRECTION_IN_WITHOUT_MOVE, DoorLog::$DIRECTION_IN]])
->orderBy(['door_log.created_at' => SORT_ASC])
->all();
\Yii::error("All door logs for today loaded in sec " . $stopWatch->split());
$firstInToday = $allDoorLogToday[0];
if (isset($firstInToday)) {
$firstEntryDateTimeToday = DateUtil::parseDateTime($firstInToday->created_at);
$interval = \DateInterval::createFromDateString('3 hours');
$daterange = new \DatePeriod($firstEntryDateTimeToday, $interval, $startOfTomorrow);
$intervals = [];
$intervalStart = null;
foreach ($daterange as $intervalEnd) {
if (isset($intervalStart)) {
$intervals[] = $this->createTicketUsageInterval($intervalStart, $intervalEnd, $allDoorLogToday, $doorLog);
}
$intervalStart = clone $intervalEnd;
}
if ($intervalStart < $startOfTomorrow) {
$intervals[] = $this->createTicketUsageInterval($intervalStart, $startOfTomorrow, $allDoorLogToday, $doorLog);
}
$activeInterval = $this->getActiveInterval($intervals, $createdAt);
if (!isset($activeInterval)) {
throw new ServerErrorHttpException("Active Interval not found");
}
$logCountInActiveInterval = count($activeInterval['logs']);
if ($logCountInActiveInterval == 1) {
$ticket->usage_count = $ticket->usage_count + 1;
$ticket->save(false);
\Yii::error("Ticket usage count increased after first IN after first door_log in interval in sec " . $stopWatch->split());
}
}
}
}
if ($direction == DoorLog::$DIRECTION_OUT || $direction == DoorLog::$DIRECTION_OUT_WITHOUT_MOVE) {
if ($card->isFlagOutKey()) {
throw new BadRequestHttpException("Can't exit with card has a key assigned");
}
if ($card->isFlagStatus()) {
throw new BadRequestHttpException("Can't exit with card has inactive status");
}
$ticket->count_move_out = $ticket->usage_count;
$ticket->save(false);
\Yii::error("direction_out: ticket count_move_out set after direction_out in sec " . $stopWatch->split());
}
Card::updateCardFlagTicket($ticket->id_ticket);
\Yii::error("updateCardFlagTicket: card flag updated in sec " . $stopWatch->split());
// reload card after flag is set
$card = Card::readCard($cardNumber);
if ($card->type != Card::TYPE_EMPLOYEE) {
if ($direction == DoorLog::$DIRECTION_OUT_WITHOUT_MOVE || $direction == DoorLog::$DIRECTION_OUT) {
$card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, true);
$card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, false);
$card->save(false);
\Yii::error("direction_out: Door flag updated in sec " . $stopWatch->split());
} else if ($direction == DoorLog::$DIRECTION_IN || $direction == DoorLog::$DIRECTION_IN_WITHOUT_MOVE) {
$card->flag_out = Helper::setBit($card->flag_out, Card::$FLAG_DOOR, false);
$card->flag = Helper::setBit($card->flag, Card::$FLAG_DOOR, true);
$card->save(false);
\Yii::error("direction_in: Card flag updated in sec " . $stopWatch->split());
}
}
$stopWatch->stop();
\Yii::error("finished in sec " . $stopWatch->getTotal());
\Yii::$app->db->transaction->commit();
} catch (Exception $e) {
\Yii::$app->db->transaction->rollBack();
throw $e;
}
}
function getActiveInterval($intervals,$date){
foreach ($intervals as $interval ){
function getActiveInterval($intervals, $date)
{
foreach ($intervals as $interval) {
$start = $interval['start'];
$end = $interval['end'];
if ( $start <= $date && $date < $end ){
if ($start <= $date && $date < $end) {
return $interval;
}
}
return null;
}
function createTicketUsageInterval($start,$end, $allLogs, $actualDoorLog){
$result = ['start' => $start, 'end' => $end , 'logs' =>[] ];
foreach ($allLogs as $log){
function createTicketUsageInterval($start, $end, $allLogs, $actualDoorLog)
{
$result = ['start' => $start, 'end' => $end, 'logs' => []];
foreach ($allLogs as $log) {
$createdAt = DateUtil::parseDateTime($log->created_at);
if ( $createdAt >= $start && $createdAt < $end){
if ($createdAt >= $start && $createdAt < $end) {
$result['logs'][] = $log;
}
}
@@ -285,9 +317,15 @@ class DoorManager extends BaseObject
public function resetLogs($cardNumber)
{
$card = Card::readCard($cardNumber);
$card->flag = 0;
$card->flag_out = 0;
$card->save(false);
Card::updateCardFlagTicket($card->id_card);
DoorLog::deleteAll(
['id_card' => $card->id_card]
);
// todo: revoke all assigned key
$this->revokeKey($cardNumber,"f100");
}
public function getLogs($cardNumber)
@@ -330,16 +368,16 @@ class DoorManager extends BaseObject
public function createLog()
{
\Yii::error("Post create log:". \Yii::$app->request->method);
\Yii::error("Post create log:" . \Yii::$app->request->method);
if (\Yii::$app->request->isPost) {
$log = new DoorLogForTest();
if ($log->load(\Yii::$app->request->post(), "")) {
if ($log->validate()) {
\Yii::error("Door log saving:".$log->created_at);
\Yii::error("Door log saving:" . $log->created_at);
$log->save(false);
return $log;
}else{
throw new BadRequestHttpException(print_r($log->getErrors(),true));
} else {
throw new BadRequestHttpException(print_r($log->getErrors(), true));
}
} else {
\Yii::error("validated" . print_r($log->errors, true));
@@ -349,4 +387,24 @@ class DoorManager extends BaseObject
throw new BadRequestHttpException('Not a Post');
}
function checkoutKey($cardNumber, $keyNumber)
{
$model = new KeyToggleForm();
$model->card = Card::readCard($cardNumber);
$model->customer = $model->card->customer;
$model->keyCard = $model->card;
$model->keyModel = $model->readKey($keyNumber);
$model->assign();
}
function revokeKey($cardNumber, $keyNumber)
{
$model = new KeyToggleForm();
$model->card = Card::readCard($cardNumber);
$model->customer = $model->card->customer;
$model->keyCard = $model->card;
$model->keyModel = $model->readKey($keyNumber);
$model->revoke();
}
}

View File

@@ -35,7 +35,7 @@ class DoorLog extends \yii\db\ActiveRecord
public static $DIRECTION_ALL_MANUAL_READ = 0; // "Kézi olvasás",
public static $DIRECTION_OUT_WITHOUT_MOVE = 1; // "KI olvastatás mozgás nélkül",
public static $DIRECTION_IN_WITHOUT_MOVE = 3; // "BE olvastatás mozgás nélkül",
public static $DIRECTION_OUT_ = 5; // "KI mozgás",
public static $DIRECTION_OUT = 5; // "KI mozgás",
public static $DIRECTION_IN = 7; // "BE mozgás",
public static $DIRECTION_OUT_ERROR_KEY_ASSIGNED = 9; // "KI olvastatás, van érvényes öltöző kulcs (nem enged)",
public static $DIRECTION_IN_ERROR_KEY_MISSING = 11; // "BE olvastatás, nincs érvényes öltöző kulcs (nem enged)",