configurationService = $config; } /** * {@inheritdoc} */ public function getInvoiceData(string $filePath) : array { $output = []; // @TODO replace with config service. // $config = $this->dummyConfig()['projects']; $config = $this->configurationService->get('projects'); foreach (array_keys($config) as $key) { $output[$key] = 0; } if ($file = fopen($filePath, 'r')) { while (($line = fgetcsv($file)) !== false) { $parsed = $this->parseCsvFile($line); // $key = reset(array_keys($parsed)); $key = array_key_first($parsed); if (isset($output[$key])) { $output[$key] += (float) reset($parsed); } } } $report_data = []; foreach ($output as $project => $hours) { $report_data[] = new WorkInvoiceElement($project, $hours); } return $report_data; } /** * Get correct values from the raw data lines of csv. * * @param array $rawData * Columns with data are specified in config. * * @return array * Project key and unit of time spent. */ protected function parseCsvFile(array $rawData) : array { $config = $this->configurationService->get('projects'); foreach ($config as $key => $project) { if (preg_match('/' . $project['pattern'] . '/', $rawData[1])) { return [$key => $rawData[4]]; } } return []; } /** * Input is array of Work elements and expenses. */ public function generateTable(array $data): array { [$rows, $totalHours, $totalPrice, $add_separator] = [[], 0, 0, FALSE]; $projectsConfig = $this->configurationService->get('projects'); // $header = $this->configurationService->get('export.labels', null); $header = null; if (is_array($header)) { $rows[] = $header; } // First only list work invoice elements. foreach ($data as $key => $invoice_element) { if ($invoice_element instanceof WorkInvoiceElementInterface) { $add_separator = TRUE; $project = $invoice_element->getName(); $time = $invoice_element->getTime(); $config = $projectsConfig[$project]; $hours = $config['time_format'] == 'm' ? $time/60 : $time; $price = $hours * (float) $config['price']; $row = [ $config['name'] ?? $project, number_format($hours, 2, ',', '.'), number_format($config['price'], 2, ',', '.'), number_format($price, 2, ',', '.'), ]; $totalHours += $hours; $totalPrice += $price; $rows[] = $row; unset($data[$key]); } } if ($add_separator) { // @TODO replace separators with constants for normal separating. $rows[] = null; $rows[] = ['Gesamt netto', number_format($totalHours, 2, ',', '.'), ' ', number_format($totalPrice, 2, ',', '.')]; $add_separator = FALSE; } if (empty($data)) { $add_separator = TRUE; } foreach ($data as $invoice_element) { if ($invoice_element instanceof ExpensesInterface) { if (!isset($added_expenses)) { // Separator 0: Make next line bold and centered. $rows[] = ReportCsvInterface::SEPARATOR_HARD; $rows[] = [ null, null, 'Kosten', 'EUR', ]; // Don't make next line bold. See RprtCli\PdfExport\PdfExportService::parsedDataToHtml. $rows[] = ReportCsvInterface::SEPARATOR_SOFT; $added_expenses = TRUE; } $add_separator = TRUE; $rows[] = [ null, null, $invoice_element->getName(), number_format($invoice_element->getValue(), 2, ',', '.'), ]; $totalPrice += $invoice_element->getValue(); } } if ($add_separator) { $rows[] = ReportCsvInterface::SEPARATOR_MEDIUM; } $rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')]; return $rows; } /** * {@inheritdoc} */ public function arangeDataForDefaultPdfExport(array $data) :array { $rows = $this->generateTable($data); $header = $this->configurationService->get('export.labels', null); array_unshift($rows, $header); foreach ($rows as $key => $row) { if (!$row) { unset($data[$key]); } } return $rows; } public function generateReportTable(string $filePath) { // ticket-id, ticket-name, time-spent $data = $this->parseReportData($filePath); if (empty($data)) { return []; } [$previous, $time_sum, $project_time, $table, $all_projects] = [$data[0]['id'], 0, 0, [], []]; foreach ($data as $line) { $project = explode('-', $line['id'])[0]; $previous_project = explode('-', $previous)[0]; if ($project !== $previous_project) { // When project changes, add a sum of time for that project. $table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $table[] = [null, $previous_project, null, $project_time/60]; $table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $time_sum += (float) $project_time; $project_time = 0; $all_projects[] = $project; } $project_time += (float) $line['time']; $previous = $line['id']; $table[] = array_values($line); } // Add sum for the last project. $table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $table[] = [null, $project, null, $project_time / 60]; $time_sum += (float) $project_time; $all_projects[] = $project; // Add a sum of time for whole day. $table[] = ReportCsvInterface::SEPARATOR_MEDIUM; $table[] = [null, implode(', ', $all_projects), null, $time_sum/60]; return $table; } /** * {@inheritdoc} */ protected function parseReportData(string $filePath): array { $output = []; // @TODO replace with config service. // $config = $this->dummyConfig()['projects']; if ($file = fopen($filePath, 'r')) { while (($line = fgetcsv($file)) !== false) { if (!is_numeric($line[4])) { // Skip header at least. continue; } // @TODO validate line $output[] = [ 'id' => $line[1], 'name' => substr($line[2], 0, 60), 'time' => $line[4], 'estimation' => $line[3], ]; } } return $output; } /** * Should be moved into test class. */ protected function dummyConfig() : array { return [ 'projects' => [ 'LDP' => [ 'name' => 'lupus.digital', 'pattern' => 'LDP-[0-9]+', 'price' => 25, // optional specify columns ], 'WV' => [ 'name' => 'Wirtschaftsverlag', 'pattern' => 'WV-[0-9]+', 'price' => 25, // optional specify columns ], 'Other' => [ 'name' => 'Other projects', 'pattern' => '(?!.\bLDP\b)(?!.\bWV\b)', 'price' => 25, // optional specify columns ], ], ]; } }