257 lines
8.6 KiB
PHP
257 lines
8.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace RprtCli\Utils\CsvReport;
|
|
|
|
use RprtCli\Utils\Configuration\ConfigurationInterface;
|
|
use RprtCli\ValueObjects\ExpensesInterface;
|
|
use RprtCli\ValueObjects\WorkInvoiceElement;
|
|
use RprtCli\ValueObjects\WorkInvoiceElementInterface;
|
|
|
|
use function array_key_first;
|
|
use function array_keys;
|
|
use function array_unshift;
|
|
use function array_values;
|
|
use function explode;
|
|
use function fgetcsv;
|
|
use function fopen;
|
|
use function implode;
|
|
use function is_array;
|
|
use function is_numeric;
|
|
use function number_format;
|
|
use function preg_match;
|
|
use function reset;
|
|
use function substr;
|
|
|
|
/**
|
|
* Creates a report of projects and hours.
|
|
*
|
|
* Uses value objects instead of arrays.
|
|
*/
|
|
class ReportCsv implements ReportCsvInterface
|
|
{
|
|
/**
|
|
* A configuration service.
|
|
*
|
|
* @var ConfigurationInterface
|
|
*/
|
|
protected $configurationService;
|
|
|
|
public function __construct(ConfigurationInterface $config)
|
|
{
|
|
$this->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.
|
|
*
|
|
*
|
|
* Columns with data are specified in config.
|
|
*
|
|
* 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 [];
|
|
}
|
|
$explodeMinus = fn($ticket) => explode('-', $ticket)[0] ?? 'UNKNOWN';
|
|
[$previous, $time_sum, $project_time, $table, $all_projects] = [
|
|
$data[0]['id'],
|
|
0,
|
|
0,
|
|
[],
|
|
[$explodeMinus($data[0]['id'])]
|
|
];
|
|
foreach ($data as $line) {
|
|
$project = $explodeMinus($line['id']);
|
|
$previous_project = $explodeMinus($previous);
|
|
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;
|
|
}
|
|
}
|