db->beginTransaction(); $stopWatch = new StopWatch(); \Yii::error("Started"); if (isset($createdAt)) { $createdAt = DateUtil::parseDateTime($createdAt); } else { $createdAt = DateUtil::utcDateTime(); } $createdAtStr = DateUtil::formatDateTimeUtc($createdAt); if (isset($date)) { $date = DateUtil::parseDateTime($date); } else { $date = DateUtil::utcDate(); } $dateStr = DateUtil::formatDateUtc($date); $doorLog = new DoorLog(); $doorLog->direction = $direction; $doorLog->source_app = $device; $doorLog->created_at = $createdAtStr; /** * 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; \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); } $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) { $start = $interval['start']; $end = $interval['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) { $createdAt = DateUtil::parseDateTime($log->created_at); if ($createdAt >= $start && $createdAt < $end) { $result['logs'][] = $log; } } return $result; } function getCountDoorLogsForTicketSince($idTicket, $since) { \Yii::error("getting door log count for today"); return DoorLog::find() ->innerJoinWith('card') ->andWhere(['card.id_ticket_current' => $idTicket]) ->andWhere(['in', 'door_log.direction', [DoorLog::$DIRECTION_IN, DoorLog::$DIRECTION_IN_WITHOUT_MOVE]]) ->andWhere(['>=', 'door_log.created_at', DateUtil::formatDateUtc($since)]) ->count(); } public function readActive($cardNumber) { $card = Card::readCard($cardNumber); return Ticket::readActive($card); } 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) { return DoorLog::findAll( ['id_card' => $cardNumber] ); } public function getInfo($cardNumber) { $card = Card::readCard($cardNumber); return [ 'card' => $card, 'customer' => $card->customer, 'tickets' => Ticket::readActive($card), 'doorLogs' => DoorLog::findAll( ['id_card' => $card->id_card] ), 'lastDoorLog' => DoorLog::find()->orderBy(['id_door_log' => SORT_DESC])->limit(1)->one(), 'doorLogCount' => DoorLog::find()->count() ]; } // // public function createDoorLog($direction, $idCard, $idTicket, $createdAt) // { // $doorLog = new DoorLog(); // $doorLog->id_card = $idCard; // $doorLog->direction = $direction; // $doorLog->id_ticket_current = $idTicket; // // $doorLog->save(false); // // update the created at flag // \Yii::$app->db->createCommand('update door_log set created_at = :created_at where id_door_log = :id ') // ->bindValue("created_at", $createdAt) // ->bindValue("id", $doorLog->id_door_log) // ->execute(); // } public function createLog() { \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); $log->save(false); return $log; } else { throw new BadRequestHttpException(print_r($log->getErrors(), true)); } } else { \Yii::error("validated" . print_r($log->errors, true)); throw new BadRequestHttpException(); } } 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(); } }