<?php namespace vonRotenberg\WeinanlieferungBundle\EventListener; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Contao\CoreBundle\Monolog\ContaoContext; use Contao\MemberModel; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Filesystem\Filesystem; use vonRotenberg\WeinanlieferungBundle\Event\CheckInCompletedEvent; use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLageModel; use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungLeseartModel; use vonRotenberg\WeinanlieferungBundle\Model\WeinanlieferungRebsorteModel; /** * Listener for the CheckInCompletedEvent. * Generates a CSV export file for each checked-in booking. */ class CheckInCompletedListener implements EventSubscriberInterface { /** * @var LoggerInterface */ private $logger; /** * @var string */ private $projectDir; /** * Constructor. * * @param LoggerInterface $logger * @param string $projectDir */ public function __construct(LoggerInterface $logger, string $projectDir) { $this->logger = $logger; $this->projectDir = $projectDir; } /** * Returns an array of event names this subscriber wants to listen to. * * @return array The event names to listen to */ public static function getSubscribedEvents() { return [ CheckInCompletedEvent::NAME => 'onCheckInCompleted', ]; } /** * Handle the check-in completed event. * * @param CheckInCompletedEvent $event */ public function onCheckInCompleted(CheckInCompletedEvent $event) { // Get the reservation data from the event $reservationData = $event->getReservationData(); $reservationModel = $event->getReservationModel(); // Log the event for testing purposes $this->logger->log( LogLevel::INFO, sprintf('Check-in completed for reservation ID: %s', $reservationData['id']), ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN')] ); // Generate and save the CSV export $this->generateCsvExport($reservationData, $reservationModel); } /** * Generate and save the CSV export file. * * @param array $reservationData * @param object $reservationModel */ private function generateCsvExport(array $reservationData, $reservationModel) { // Create export directory if it doesn't exist $exportDir = $this->projectDir . '/export/check_in'; $filesystem = new Filesystem(); if (!$filesystem->exists($exportDir)) { $filesystem->mkdir($exportDir, 0755); } // Get member data $memberId = $reservationData['uid']; $memberModel = MemberModel::findById($memberId); if (null === $memberModel) { $this->logger->log( LogLevel::ERROR, sprintf('Could not find member with ID: %s', $memberId), ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')] ); return; } // Get behaelter numbers $behaelterNumbers = json_decode($reservationData['behaelter_numbers'], true); if (!is_array($behaelterNumbers) || empty($behaelterNumbers)) { $this->logger->log( LogLevel::ERROR, sprintf('No behaelter numbers found for reservation ID: %s', $reservationData['id']), ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')] ); return; } // Check if we have the new format (array of objects with behaelter and member) // or the old format (simple array of behaelter numbers) $isNewFormat = isset($behaelterNumbers[0]) && is_array($behaelterNumbers[0]) && isset($behaelterNumbers[0]['behaelter']); // If it's the old format, convert it to the new format for compatibility if (!$isNewFormat) { $oldFormat = $behaelterNumbers; $behaelterNumbers = []; foreach ($oldFormat as $number) { $behaelterNumbers[] = [ 'behaelter' => $number, 'member' => $memberModel->memberno ]; } } // Format check-in date $checkInDate = date('d.m.Y', $reservationData['checked_in_on']); // Get sorten (grape varieties and harvest types) $sortenData = []; $sortenLeseartPairs = explode(';', $reservationData['sorten']); foreach ($sortenLeseartPairs as $pair) { if (empty($pair)) { continue; } list($sorteId, $leseartId) = explode(',', $pair); $rebsorteModel = WeinanlieferungRebsorteModel::findById($sorteId); $leseartModel = WeinanlieferungLeseartModel::findById($leseartId); if (null !== $rebsorteModel && null !== $leseartModel) { $sortenData[] = [ 'rebsorte_id' => $rebsorteModel->ident_string, 'rebsorte_title' => $rebsorteModel->title, 'leseart_id' => $leseartModel->ident_string, 'leseart_title' => $leseartModel->title ]; } } // Get lagen (locations) $lagenData = []; $lagenIds = explode(',', $reservationData['lage']); foreach ($lagenIds as $lageId) { if (empty($lageId)) { continue; } $lageModel = WeinanlieferungLageModel::findById($lageId); if (null !== $lageModel) { $lagenData[] = [ 'lage_id' => $lageModel->ident_string, 'lage_title' => $lageModel->title ]; } } // Get ernteart (harvest method) $ernteartValues = explode(',', $reservationData['ernteart']); $ernteartMapping = [ 'handlese' => 'H', 'vollernter' => 'V' ]; // Group CSV data by member number $csvDataByMember = []; $memberNames = []; // Store member names for logging // For each behaelter, create a line in the CSV and group by member number foreach ($behaelterNumbers as $behaelterData) { // Get behaelter number and member number from the data $behaelterNumber = $isNewFormat ? $behaelterData['behaelter'] : $behaelterData; $memberNo = $isNewFormat && isset($behaelterData['member']) ? $behaelterData['member'] : $memberModel->memberno; // Skip special value 9999 if needed /*if ($behaelterNumber === '9999') { continue; }*/ // If member number is empty, use the booking member's number if (empty($memberNo)) { $memberNo = $memberModel->memberno; } // Get member name - use the booking member's name as default $memberName = $memberModel->firstname . ' ' . $memberModel->lastname; // If the member number is different from the booking member's number, // try to find the corresponding member to get their name if ($memberNo !== $memberModel->memberno) { $otherMember = MemberModel::findByMemberno($memberNo); if ($otherMember) { $memberName = $otherMember->firstname . ' ' . $otherMember->lastname; } } // Store member name for logging $memberNames[$memberNo] = $memberName; // Use the first sorte, leseart, and lage if available $rebsorteId = !empty($sortenData) ? $sortenData[0]['rebsorte_id'] : ''; $rebsorteTitle = !empty($sortenData) ? $sortenData[0]['rebsorte_title'] : ''; $leseartId = !empty($sortenData) ? $sortenData[0]['leseart_id'] : ''; $leseartTitle = !empty($sortenData) ? $sortenData[0]['leseart_title'] : ''; $lageId = !empty($lagenData) ? $lagenData[0]['lage_id'] : ''; $lageTitle = !empty($lagenData) ? $lagenData[0]['lage_title'] : ''; // Map ernteart values to H/V $ernteart = ''; foreach ($ernteartValues as $value) { if (isset($ernteartMapping[$value])) { $ernteart = $ernteartMapping[$value]; break; } } // Create CSV line and add to the appropriate member group if (!isset($csvDataByMember[$memberNo])) { $csvDataByMember[$memberNo] = []; } $csvDataByMember[$memberNo][] = [ $memberNo, // member id (now using the member number associated with this behaelter) $memberName, // member first and lastname $rebsorteId, // rebsorte identifikator $rebsorteTitle, // rebsorte title $lageId, // lage identifikator $lageTitle, // lage title $leseartId, // leseart identifikator $leseartTitle, // leseart title $ernteart, // ernteart (H for handlese, V for vollernter) $behaelterNumber, // behaelter number $checkInDate, // check-in date // $reservationData['behaelter'] // behaelter amount for the whole checked-in booking ]; } // Generate a separate CSV file for each member $generatedFiles = []; foreach ($csvDataByMember as $memberNo => $csvData) { // Generate CSV file with the naming scheme "bookingId_memberno.csv" $filename = $reservationData['id'] . '_' . $memberNo . '.csv'; $filepath = $exportDir . '/' . $filename; $generatedFiles[] = $filepath; $file = fopen($filepath, 'w'); foreach ($csvData as $line) { $line[] = count($csvData); fputcsv($file, $line, ';'); } fclose($file); $this->logger->log( LogLevel::INFO, sprintf('CSV export created for reservation ID: %s, member: %s (%s) at %s', $reservationData['id'], $memberNo, $memberNames[$memberNo], $filepath ), ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')] ); } // Log summary of all generated files $this->logger->log( LogLevel::INFO, sprintf('CSV export completed for reservation ID: %s. Generated %d file(s) for %d member(s).', $reservationData['id'], count($generatedFiles), count($csvDataByMember) ), ['contao' => new ContaoContext(__METHOD__, 'CHECK_IN_CSV_EXPORT')] ); } }