/**
  * Get reminders for a user.
  *
  * @param \Finna\Db\Table\Row\User $user User.
  *
  * @return array Array of loans to be reminded.
  */
 protected function getReminders($user)
 {
     if (!$user->email || trim($user->email) == '') {
         $this->warn("User {$user->username} (id {$user->id})" . ' does not have an email address, bypassing due date reminders');
         return false;
     }
     $remindLoans = [];
     foreach ($user->getLibraryCards() as $card) {
         if (!$card['id']) {
             continue;
         }
         $patron = null;
         $card = $user->getLibraryCard($card['id']);
         try {
             $patron = $this->catalog->patronLogin($card['cat_username'], $card['cat_password']);
         } catch (\Exception $e) {
             $this->err('Catalog login error: ' . $e->getMessage());
         }
         if (!$patron) {
             $this->warn("Catalog login failed for user {$user->username}" . " (id {$user->id}), card {$card->cat_username}" . " (id {$card->id})");
             continue;
         }
         $todayTime = new \DateTime();
         try {
             $loans = $this->catalog->getMyTransactions($patron);
         } catch (\Exception $e) {
             $this->err("Exception trying to get loans for user {$user->username}" . " (id {$user->id}), card {$card->cat_username}" . " (id {$card->id}): " . $e->getMessage());
             continue;
         }
         foreach ($loans as $loan) {
             $dueDate = new \DateTime($loan['duedate']);
             $dayDiff = $dueDate->diff($todayTime)->days;
             if ($todayTime >= $dueDate || $dayDiff <= $user->finna_due_date_reminder) {
                 $params = ['user_id' => $user->id, 'loan_id' => $loan['item_id'], 'due_date' => $dueDate->format($this::DUE_DATE_FORMAT)];
                 $reminder = $this->dueDateReminderTable->select($params);
                 if (count($reminder)) {
                     // Reminder already sent
                     continue;
                 }
                 // Store also title for display in email
                 $title = isset($loan['title']) ? $loan['title'] : null;
                 if (isset($loan['id'])) {
                     $record = $this->recordLoader->load($loan['id'], 'Solr', true);
                 }
                 $dateFormat = isset($this->currentSiteConfig['Site']['displayDateFormat']) ? $this->currentSiteConfig['Site']['displayDateFormat'] : $this->mainConfig->Site->displayDateFormat;
                 $remindLoans[] = ['loanId' => $loan['item_id'], 'dueDate' => $loan['duedate'], 'dueDateFormatted' => $dueDate->format($dateFormat), 'title' => $title, 'record' => $record];
             }
         }
     }
     return $remindLoans;
 }
 /**
  * Try to register a failed transaction.
  *
  * @param Transaction $t             Transaction
  * @param array       $report        Transactions to be reported.
  * @param int         $registeredCnt Number of registered transactions.
  * @param int         $expiredCnt    Number of expired transactions.
  * @param int         $failedCnt     Number of failed transactions.
  * @param User        $user          User object.
  *
  * @return boolean success
  */
 protected function processTransaction($t, &$report, &$registeredCnt, &$expiredCnt, &$failedCnt, &$user)
 {
     $this->msg("  Registering transaction id {$t->id} / {$t->transaction_id}");
     // Check if the transaction has not been registered for too long
     $now = new \DateTime();
     $paid_time = new \DateTime($t->paid);
     $diff = $now->diff($paid_time);
     $diffHours = $diff->days * 24 + $diff->h;
     if ($diffHours > $this->expireHours) {
         if (!isset($report[$t->driver])) {
             $report[$t->driver] = 0;
         }
         $report[$t->driver]++;
         $expiredCnt++;
         if (!$this->transactionTable->setTransactionReported($t->transaction_id)) {
             $this->err('    Failed to update transaction ' . $t->transaction_id . 'as reported');
         }
         $t->complete = Transaction::STATUS_REGISTRATION_EXPIRED;
         if (!$t->save()) {
             $this->err('    Failed to update transaction ' . $t->transaction_id . ' as expired.');
         } else {
             $this->msg('    Transaction ' . $t->transaction_id . ' expired.');
             return true;
         }
     } else {
         if ($user === false || $t->user_id != $user->id) {
             $user = $this->userTable->getById($t->user_id);
         }
         $catUsername = $patron = null;
         foreach ($user->getLibraryCards() as $card) {
             $card = $user->getLibraryCard($card['id']);
             if ($card['cat_username'] == $t->cat_username) {
                 try {
                     $patron = $this->catalog->patronLogin($card['cat_username'], $card['cat_password']);
                     if ($patron) {
                         break;
                     }
                 } catch (\Exception $e) {
                     $this->err('Patron login error: ' . $e->getMessage());
                 }
             }
         }
         if (!$patron) {
             $this->warn("Catalog login failed for user {$user->username}" . " (id {$user->id}), card {$card->cat_username}" . " (id {$card->id})");
             $failedCnt++;
             return false;
         }
         try {
             $this->catalog->markFeesAsPaid($patron, $t->amount);
             if (!$this->transactionTable->setTransactionRegistered($t->transaction_id)) {
                 $this->err('    Failed to update transaction ' . $t->transaction_id . 'as registered');
             }
             $registeredCnt++;
             return true;
         } catch (\Exception $e) {
             $this->err('    Registration of transaction ' . $t->transaction_id . ' failed');
             $this->err('      ' . $e->getMessage());
             if ($this->transactionTable->setTransactionRegistrationFailed($t->transaction_id, $e->getMessage())) {
                 $this->err('Error updating transaction ' . $t->transaction_id . ' status: ' . 'registering failed');
             }
             $failedCnt++;
             return false;
         }
     }
 }