Fix coding standard.

yt-rest-api
Lio Novelli 2023-01-02 15:18:52 +01:00
parent ff2e35bb93
commit 624b895fd6
23 changed files with 372 additions and 165 deletions

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
// src/Commands/InvoiceCommand.php;
namespace RprtCli\Commands;
use RprtCli\Utils\Configuration\ConfigurationInterface;
use Symfony\Component\Console\Command\Command;
// use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Abstract class that adds some common services and input options.
*/
class AbstractCliCommand extends Command
{
protected $configuration;
// @TODO Add service factory service.
// protected $trackingServiceFactory;
public function __construct(
ConfigurationInterface $configuration,
?string $name = null
) {
$this->configuration = $configuration;
parent::__construct($name);
}
}

View File

@ -38,8 +38,8 @@ use function var_export;
/** /**
* Main file - invoice command. * Main file - invoice command.
*/ */
class InvoiceCommand extends Command { class InvoiceCommand extends Command
{
use SelectReportTrait; use SelectReportTrait;
protected $csv; protected $csv;
@ -50,8 +50,8 @@ class InvoiceCommand extends Command {
protected $pdfExport; protected $pdfExport;
const TYPE_WORK = 1; protected const TYPE_WORK = 1;
const TYPE_EXPENSE = 2; protected const TYPE_EXPENSE = 2;
public function __construct( public function __construct(
ReportCsvInterface $csv, ReportCsvInterface $csv,
@ -124,6 +124,7 @@ class InvoiceCommand extends Command {
'expenses', 'expenses',
'e', 'e',
InputOption::VALUE_OPTIONAL, InputOption::VALUE_OPTIONAL,
// phpcs:ignore
'List of additional expenses in format expense1=value1;expenses2=value2... or empty for interactive output.', 'List of additional expenses in format expense1=value1;expenses2=value2... or empty for interactive output.',
false false
); );
@ -131,6 +132,7 @@ class InvoiceCommand extends Command {
'custom', 'custom',
'c', 'c',
InputOption::VALUE_OPTIONAL, InputOption::VALUE_OPTIONAL,
// phpcs:ignore
'Additional custom work untracked in format: name1=time1;name2=time2... Project to assign work items to has to be configured in app config. Leave empty for interactive output.', 'Additional custom work untracked in format: name1=time1;name2=time2... Project to assign work items to has to be configured in app config. Leave empty for interactive output.',
false false
); );
@ -161,9 +163,7 @@ class InvoiceCommand extends Command {
return Command::SUCCESS; return Command::SUCCESS;
} }
// Gets report parameter. // Gets report parameter.
$this->getReportParameter($input, $output, 'tracking_service.youtrack.invoice.report'); $file = $this->getReportCsvFilePath($input, $output, 'tracking_service.youtrack.invoice.report');
$report_id = $this->trackingService->getReportId();
$file = $this->getReportCsvFilePath($input, $output, $report_id);
$report_name = $this->trackingService->getReportName(); $report_name = $this->trackingService->getReportName();
if ($input->hasParameterOption('--expenses') || $input->hasParameterOption('-e')) { if ($input->hasParameterOption('--expenses') || $input->hasParameterOption('-e')) {
$expenses = $this->getCustomWorkOrExpenses($input->getOption('expenses'), self::TYPE_EXPENSE); $expenses = $this->getCustomWorkOrExpenses($input->getOption('expenses'), self::TYPE_EXPENSE);
@ -326,7 +326,8 @@ class InvoiceCommand extends Command {
return $output; return $output;
} }
protected function getCustomWorkOrExpenses($custom, $type) { protected function getCustomWorkOrExpenses($custom, $type)
{
$output = []; $output = [];
if (is_string($custom)) { if (is_string($custom)) {
foreach (explode(';', $custom) as $item) { foreach (explode(';', $custom) as $item) {

View File

@ -18,8 +18,8 @@ use Symfony\Component\Console\Output\OutputInterface;
use function is_array; use function is_array;
use function is_null; use function is_null;
class ReportCommand extends Command { class ReportCommand extends Command
{
use SelectReportTrait; use SelectReportTrait;
protected $trackingService; protected $trackingService;
@ -28,6 +28,7 @@ class ReportCommand extends Command {
protected $csv; protected $csv;
// phpcs:ignore
public function __construct(ConfigurationInterface $configuration, YoutrackInterface $tracking_service, ReportCsvInterface $csv, ?string $name = null) public function __construct(ConfigurationInterface $configuration, YoutrackInterface $tracking_service, ReportCsvInterface $csv, ?string $name = null)
{ {
$this->config = $configuration; $this->config = $configuration;
@ -37,7 +38,8 @@ class ReportCommand extends Command {
parent::__construct($name); parent::__construct($name);
} }
protected function configure() : void { protected function configure(): void
{
$this->setName('report'); $this->setName('report');
$this->setDescription('Get a time-tracking report into command line.'); $this->setDescription('Get a time-tracking report into command line.');
$this->addOption( $this->addOption(
@ -77,10 +79,8 @@ class ReportCommand extends Command {
$output->writeln('<error>This option is not supported yet.</error>'); $output->writeln('<error>This option is not supported yet.</error>');
return Command::FAILURE; return Command::FAILURE;
} }
$this->getReportParameter($input, $output);
// Currently we only support csv download. // Currently we only support csv download.
$report_id = $this->trackingService->getReportId(); $file = $this->getReportCsvFilePath($input, $output);
$file = $this->getReportCsvFilePath($input, $output, $report_id);
$report_name = $this->trackingService->getReportName(); $report_name = $this->trackingService->getReportName();
$output->writeln("report: <info>{$report_name}</info>"); $output->writeln("report: <info>{$report_name}</info>");
$data = $this->csv->generateReportTable($file); $data = $this->csv->generateReportTable($file);
@ -109,7 +109,10 @@ class ReportCommand extends Command {
$rows[$key] = new TableSeparator(); $rows[$key] = new TableSeparator();
} elseif (is_array($row) && is_null($row[0]) && is_null($row[2])) { } elseif (is_array($row) && is_null($row[0]) && is_null($row[2])) {
// Check which elements in array are null. // Check which elements in array are null.
$rows[$key] = [new TableCell($row[1], ['colspan' => 2]), new TableCell((string) $row[3], ['colspan' => 2])]; $rows[$key] = [
new TableCell($row[1], ['colspan' => 2]),
new TableCell((string) $row[3], ['colspan' => 2]),
];
} }
} }
$table->setRows($rows); $table->setRows($rows);

View File

@ -9,6 +9,8 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ChoiceQuestion;
use function array_flip;
/** /**
* Trait to select report. * Trait to select report.
* *
@ -16,16 +18,21 @@ use Symfony\Component\Console\Question\ChoiceQuestion;
* Command must have report input option. It is not the most elegant solution * Command must have report input option. It is not the most elegant solution
* but it helps avoiding code duplication. * but it helps avoiding code duplication.
*/ */
trait SelectReportTrait { trait SelectReportTrait
{
protected function checkContext() { protected function checkContext()
{
if (! isset($this->trackingService)) { if (! isset($this->trackingService)) {
return FALSE; return false;
} }
return $this instanceof Command; return $this instanceof Command;
} }
protected function getReportParameter(InputInterface $input, OutputInterface $output, $default = 'tracking_service.youtrack.report.report') { protected function getReportParameter(
InputInterface $input,
OutputInterface $output,
$default = 'tracking_service.youtrack.report.report'
) {
if (! $this->checkContext()) { if (! $this->checkContext()) {
return Command::FAILURE; return Command::FAILURE;
} }
@ -60,8 +67,14 @@ trait SelectReportTrait {
$this->trackingService->setReportName(); $this->trackingService->setReportName();
} }
protected function getReportCsvFilePath(InputInterface $input, OutputInterface $output, ?string $report_id) : ?string { protected function getReportCsvFilePath(
InputInterface $input,
OutputInterface $output,
?string $default = 'tracking_service.youtrack.report.report'
): ?string {
if (! $file = $input->getOption('file')) { if (! $file = $input->getOption('file')) {
$this->getReportParameter($input, $output, $default);
$report_id = $this->trackingService->getReportId();
$cache_clear_status = $this->trackingService->clearReportCache($report_id); $cache_clear_status = $this->trackingService->clearReportCache($report_id);
if ($output->isVerbose()) { if ($output->isVerbose()) {
$output->writeln("Report <info>{$report_id}</info> cache cleared, status: {$cache_clear_status}"); $output->writeln("Report <info>{$report_id}</info> cache cleared, status: {$cache_clear_status}");
@ -75,6 +88,4 @@ trait SelectReportTrait {
} }
return $file; return $file;
} }
} }

View File

@ -34,6 +34,7 @@ class TrackCommand extends Command
{ {
$this->setName('youtrack'); $this->setName('youtrack');
$this->setDescription('Track time into your youtrack service'); $this->setDescription('Track time into your youtrack service');
// phpcs:ignore
$this->addUsage('rprt-cli youtrack --issue=[issue-name] --minutes=[minutes] --date=[days-ago] --description=[text] --work-type=[work-type]'); $this->addUsage('rprt-cli youtrack --issue=[issue-name] --minutes=[minutes] --date=[days-ago] --description=[text] --work-type=[work-type]');
// Options or arguments? Technically they are arguments but default value could be provided by config. // Options or arguments? Technically they are arguments but default value could be provided by config.
// Options are more suitable. // Options are more suitable.

View File

@ -4,6 +4,8 @@ declare(strict_types=1);
// src/Utils/Configuration/TranslationService.php // src/Utils/Configuration/TranslationService.php
namespace RprtCli\Utils\Translation;
use RprtCli\Utils\Configuration\ConfigurationInterface; use RprtCli\Utils\Configuration\ConfigurationInterface;
class TranslationService class TranslationService

View File

@ -111,7 +111,12 @@ class CsvReport implements CsvReportInterface
} }
// @TODO Check rate in final result. // @TODO Check rate in final result.
// $rows[] = [$this->translator->trans('Sum'), $totalHours, $config['price'], $totalPrice]; // $rows[] = [$this->translator->trans('Sum'), $totalHours, $config['price'], $totalPrice];
$rows[] = ['Gesamt netto', number_format($totalHours, 2, ',', '.'), number_format($config['price'], 2, ',', '.'), number_format($totalPrice, 2, ',', '.')]; $rows[] = [
'Gesamt netto',
number_format($totalHours, 2, ',', '.'),
number_format($config['price'], 2, ',', '.'),
number_format($totalPrice, 2, ',', '.')
];
$rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')]; $rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')];
return $rows; return $rows;
@ -127,15 +132,15 @@ class CsvReport implements CsvReportInterface
'price' => 26, 'price' => 26,
// optional specify columns // optional specify columns
], ],
'WV' => [ 'TNP' => [
'name' => 'Wirtschaftsverlag', 'name' => 'Triglav National Park',
'pattern' => 'WV-[0-9]+', 'pattern' => 'TNP-[0-9]+',
'price' => 26, 'price' => 26,
// optional specify columns // optional specify columns
], ],
'Other' => [ 'Other' => [
'name' => 'Other projects', 'name' => 'Other projects',
'pattern' => '(?!.\bLDP\b)(?!.\bWV\b)', 'pattern' => '(?!.\bLDP\b)(?!.\bTNP\b)',
'price' => 26, 'price' => 26,
// optional specify columns // optional specify columns
], ],

View File

@ -127,7 +127,12 @@ class ReportCsv implements ReportCsvInterface
if ($add_separator) { if ($add_separator) {
// @TODO replace separators with constants for normal separating. // @TODO replace separators with constants for normal separating.
$rows[] = null; $rows[] = null;
$rows[] = ['Gesamt netto', number_format($totalHours, 2, ',', '.'), ' ', number_format($totalPrice, 2, ',', '.')]; $rows[] = [
'Gesamt netto',
number_format($totalHours, 2, ',', '.'),
' ',
number_format($totalPrice, 2, ',', '.')
];
$add_separator = false; $add_separator = false;
} }
if (empty($data)) { if (empty($data)) {
@ -189,7 +194,13 @@ class ReportCsv implements ReportCsvInterface
return []; return [];
} }
$explodeMinus = fn($ticket) => explode('-', $ticket)[0] ?? 'UNKNOWN'; $explodeMinus = fn($ticket) => explode('-', $ticket)[0] ?? 'UNKNOWN';
[$previous, $time_sum, $project_time, $table, $all_projects] = [$data[0]['id'], 0, 0, [], [$explodeMinus($data[0]['id'])]]; [$previous, $time_sum, $project_time, $table, $all_projects] = [
$data[0]['id'],
0,
0,
[],
[$explodeMinus($data[0]['id'])]
];
foreach ($data as $line) { foreach ($data as $line) {
$project = $explodeMinus($line['id']); $project = $explodeMinus($line['id']);
$previous_project = $explodeMinus($previous); $previous_project = $explodeMinus($previous);
@ -242,5 +253,4 @@ class ReportCsv implements ReportCsvInterface
} }
return $output; return $output;
} }
} }

View File

@ -12,17 +12,17 @@ interface ReportCsvInterface
/** /**
* Normal separator. * Normal separator.
*/ */
const SEPARATOR_SOFT = false; public const SEPARATOR_SOFT = false;
/** /**
* Medium separator. Next line bold. * Medium separator. Next line bold.
*/ */
const SEPARATOR_MEDIUM = null; public const SEPARATOR_MEDIUM = null;
/** /**
* Next line should be bold and centered. * Next line should be bold and centered.
*/ */
const SEPARATOR_HARD = 0; public const SEPARATOR_HARD = 0;
/** /**
* Returns array of hours per configured projects. * Returns array of hours per configured projects.

View File

@ -155,7 +155,12 @@ class MailerService implements MailerInterface
public function sendDefaultMail(string $output): void public function sendDefaultMail(string $output): void
{ {
$tokens = $this->pdf->gatherTokensForTemplate($this->getEmailTemplatePath(), false, $this->getDefaultTokens(), 'email.tokens'); $tokens = $this->pdf->gatherTokensForTemplate(
$this->getEmailTemplatePath(),
false,
$this->getDefaultTokens(),
'email.tokens'
);
$text = $this->pdf->replaceTokensInTemplate($this->getEmailTemplatePath(), $tokens); $text = $this->pdf->replaceTokensInTemplate($this->getEmailTemplatePath(), $tokens);
$this->sendMail( $this->sendMail(
$this->getProperty('from'), $this->getProperty('from'),

View File

@ -75,5 +75,10 @@ interface PdfExportInterface
* *
* Token keys and values array. * Token keys and values array.
*/ */
public function gatherTokensForTemplate(string $template_path, bool $skip_missing, array $runtime_tokens = [], string $config = 'export.token') : array; public function gatherTokensForTemplate(
string $template_path,
bool $skip_missing,
array $runtime_tokens = [],
string $config = 'export.token'
): array;
} }

View File

@ -138,8 +138,12 @@ class PdfExportService implements PdfExportInterface
* *
* Token keys and values array. * Token keys and values array.
*/ */
public function gatherTokensForTemplate(string $template_path, bool $skip_missing = false, array $runtime_tokens = [], string $config = 'export.tokens') : array public function gatherTokensForTemplate(
{ string $template_path,
bool $skip_missing = false,
array $runtime_tokens = [],
string $config = 'export.tokens'
): array {
[$tokens, $missing] = [[], []]; [$tokens, $missing] = [[], []];
$token_keys = $this->getTokensInTemplate(file_get_contents($template_path)); $token_keys = $this->getTokensInTemplate(file_get_contents($template_path));
$config_tokens = $this->config->get($config); $config_tokens = $this->config->get($config);

View File

@ -36,6 +36,8 @@ interface YoutrackInterface
public function listReports(): array; public function listReports(): array;
public function setReportId(string $report_id): void; public function setReportId(string $report_id): void;
public function setReportName(?string $report_name = NULL) :void;
public function setReportName(?string $report_name = null): void;
public function getReportName(): ?string; public function getReportName(): ?string;
} }

View File

@ -36,7 +36,7 @@ class YoutrackService implements YoutrackInterface
protected ClientInterface $httpClient; protected ClientInterface $httpClient;
protected string $report_id; protected string $report_id;
protected ?string $reportName = NULL; protected ?string $reportName = null;
public function __construct(ConfigurationInterface $config, ClientInterface $http_client) public function __construct(ConfigurationInterface $config, ClientInterface $http_client)
{ {
@ -107,20 +107,21 @@ class YoutrackService implements YoutrackInterface
$this->report_id = $report_id; $this->report_id = $report_id;
} }
public function setReportName(?string $report_name = NULL) : void { public function setReportName(?string $report_name = null): void
{
if (! $report_name) { if (! $report_name) {
$reports = $this->listReports(); $reports = $this->listReports();
if ($report_id = $this->getReportId()) { if ($report_id = $this->getReportId()) {
$report_name = $reports[$report_id] ?? NULL; $report_name = $reports[$report_id] ?? null;
} } else {
else { $report_name = null;
$report_name = NULL;
} }
} }
$this->reportName = $report_name; $this->reportName = $report_name;
} }
public function getReportName() : ?string { public function getReportName(): ?string
{
return $this->reportName; return $this->reportName;
} }
@ -222,6 +223,7 @@ class YoutrackService implements YoutrackInterface
$path = "/youtrack/api/reports/${report_id}/status"; $path = "/youtrack/api/reports/${report_id}/status";
$query = [ $query = [
'$top' => -1, '$top' => -1,
// phpcs:ignore
'fields' => 'calculationInProgress,error(id),errorMessage,isOutdated,lastCalculated,progress,wikifiedErrorMessage', 'fields' => 'calculationInProgress,error(id),errorMessage,isOutdated,lastCalculated,progress,wikifiedErrorMessage',
]; ];
$post = [ $post = [

View File

@ -11,8 +11,22 @@ use DI\ContainerBuilder;
use RprtCli\Commands\InvoiceCommand; use RprtCli\Commands\InvoiceCommand;
use RprtCli\Commands\ReportCommand; use RprtCli\Commands\ReportCommand;
/**
* Report and invoice command test.
*
* Does not cover the part of talking to the api, nor does it yet cover email
* and pdf generation. @TODO
*/
class ReportCommandTest extends TestCase { class ReportCommandTest extends TestCase {
protected const INPUT_CSV_FILE = __DIR__ . '/../data/21-03.csv';
protected const REPORT_OUTPUT_FILE = __DIR__ . '/../data/report-21-03.txt';
protected const INVOICE_OUTPUT_FILE = __DIR__ . '/../data/invoice-21-03.txt';
protected const INVOICE_OUTPUT_PDF = __DIR__ . '/../data/output/Invoice-test.pdf';
public function testExecute() { public function testExecute() {
$builder = new ContainerBuilder(); $builder = new ContainerBuilder();
$builder->addDefinitions(__DIR__ . '/../test-dependencies.php'); $builder->addDefinitions(__DIR__ . '/../test-dependencies.php');
@ -26,9 +40,9 @@ class ReportCommandTest extends TestCase {
$application->add($reportCommand); $application->add($reportCommand);
$command = $application->find('report'); $reportCommand = $application->find('report');
$commandTester = new CommandTester($command); $reportCommandTester = new CommandTester($reportCommand);
$commandTester->execute([ $reportCommandTester->execute([
// pass arguments to the helper // pass arguments to the helper
'--file' => __DIR__ . '/../data/21-03.csv', '--file' => __DIR__ . '/../data/21-03.csv',
@ -38,13 +52,37 @@ class ReportCommandTest extends TestCase {
// e.g: '--some-option' => ['option_value'], // e.g: '--some-option' => ['option_value'],
]); ]);
$commandTester->assertCommandIsSuccessful(); $reportCommandTester->assertCommandIsSuccessful();
// the output of the command in the console // the output of the command in the console
$output = $commandTester->getDisplay(); $output = $reportCommandTester->getDisplay();
var_dump($output); // var_dump($output);
$this->assertStringContainsString('21-03.csv', $output); $this->assertStringContainsString('21-03.csv', $output);
$this->assertStringEqualsFile(self::REPORT_OUTPUT_FILE, $output);
$invoiceCommand = $application->find('invoice');
$invoiceCommandTester = new CommandTester($invoiceCommand);
$invoiceCommandTester->execute([
'--file' => self::INPUT_CSV_FILE,
'--pdf' => TRUE,
]);
$invoiceCommandTester->assertCommandIsSuccessful();
// the output of the command in the console
$invoice_output = $invoiceCommandTester->getDisplay();
var_dump($invoice_output);
$this->assertStringContainsString('21-03.csv', $invoice_output);
$this->assertStringEqualsFile(self::INVOICE_OUTPUT_FILE, $invoice_output);
// $invoiceCommandTester->execute([
// '--file' => self::INPUT_CSV_FILE,
// '--pdf'
// ]);
// $invoice_output = $invoiceCommandTester->getDisplay();
// var_dump($invoice_output);
// $this->assertFileExists();
// ...
} }
} }

View File

@ -3,13 +3,13 @@ Group name,Item,Item Summary,Estimation time,Spent time
-,DEV-56,Developer training,0,60 -,DEV-56,Developer training,0,60
-,DEV-122,Daily standup,0,255 -,DEV-122,Daily standup,0,255
-,INF-6,"Infrastructure misc, diverse",0,75 -,INF-6,"Infrastructure misc, diverse",0,75
-,KUR-181,Sprint meetings (PM),240,390 -,SND-181,Sprint meetings (PM),240,390
-,KUR-507,(TKT-307) Change webhook integration for Slack,0,330 -,SND-507,(TKT-307) Change webhook integration for Slack,0,330
-,KUR-552,(TKT-740) Allow kicking users out of collections,780,45 -,SND-552,(TKT-740) Allow kicking users out of collections,780,45
-,KUR-554,(TKT-1448) Adaptions in Backend,0,30 -,SND-554,(TKT-1448) Adaptions in Backend,0,30
-,KUR-556,[story] (TKT-1393) Make Paragraph embedding more user friendly,0,75 -,SND-556,[story] (TKT-1393) Make Paragraph embedding more user friendly,0,75
-,KUR-558,(TKT-1467) Full copy of article doesn't update the timestamp,0,15 -,SND-558,(TKT-1467) Full copy of article doesn't update the timestamp,0,15
-,KUR-562,(TKT-1441) Implement SEO title in BE,0,45 -,SND-562,(TKT-1441) Implement SEO title in BE,0,45
-,LDP-668,Add json-ld schema.org metadata to articles,0,300 -,LDP-668,Add json-ld schema.org metadata to articles,0,300
-,LDP-685,"LDP-Contentpool sitemaps. Extend ""simple_sitemap_extended"" setup to support per front-end site sitemaps.",0,15 -,LDP-685,"LDP-Contentpool sitemaps. Extend ""simple_sitemap_extended"" setup to support per front-end site sitemaps.",0,15
-,LDP-692,Output json-ld script,0,30 -,LDP-692,Output json-ld script,0,30
@ -28,26 +28,26 @@ Group name,Item,Item Summary,Estimation time,Spent time
-,LDP-740,CP: Add portal path prefixes,480,30 -,LDP-740,CP: Add portal path prefixes,480,30
-,LDP-741,Defects marketing Blocks,0,450 -,LDP-741,Defects marketing Blocks,0,450
-,LDP-742,[Red Alert] Develop branch fails to build,0,45 -,LDP-742,[Red Alert] Develop branch fails to build,0,45
-,VAL-8,Plan hosting setup on custom hosting provider,0,45 -,TES-8,Plan hosting setup on custom hosting provider,0,45
-,WV-31,"Internal sprint meetings (PM, fixed-price).",0,150 -,TNP-31,"Internal sprint meetings (PM, fixed-price).",0,150
-,WV-4304,"(ODT-1240) Structured data on article (satellite) pages and overview pages such as the startpage, branch, topic & channel pages.",600,750 -,TNP-4304,"(ODT-1240) Structured data on article (satellite) pages and overview pages such as the startpage, branch, topic & channel pages.",600,750
-,WV-4305,(ODT-1202) Add mobile-banner-3 & 4 (advertisement in articles),0,60 -,TNP-4305,(ODT-1202) Add mobile-banner-3 & 4 (advertisement in articles),0,60
-,WV-4326,(ODT-1174) Make image optional in the Call to Action block,135,60 -,TNP-4326,(ODT-1174) Make image optional in the Call to Action block,135,60
-,WV-4355,(ODT-1270) Add article title to breadcrumbs,0,270 -,TNP-4355,(ODT-1270) Add article title to breadcrumbs,0,270
-,WV-4359,"(ODT-1254) Display the text paragraph ""zwischentitel"" in H2",0,90 -,TNP-4359,"(ODT-1254) Display the text paragraph ""zwischentitel"" in H2",0,90
-,WV-4372,(ODT-1297) Branch analytics for articles associated with specific branch (GA),135,15 -,TNP-4372,(ODT-1297) Branch analytics for articles associated with specific branch (GA),135,15
-,WV-4384,(ODT-1306) Layout-builder rendering in Chrome browser,120,120 -,TNP-4384,(ODT-1306) Layout-builder rendering in Chrome browser,120,120
-,WV-4393,WVsat docker build error,0,90 -,TNP-4393,TNPsat docker build error,0,90
-,WV-4410,(ODT-1317) SOLR Search optimization >> suggested articles does NOT affect the relevance for search results.,375,30 -,TNP-4410,(ODT-1317) SOLR Search optimization >> suggested articles does NOT affect the relevance for search results.,375,30
-,WV-4411,Extend simple_sitemap_extensions for dynamic variants & Install and configure simple_sitemap_extensions,600,2070 -,TNP-4411,Extend simple_sitemap_extensions for dynamic variants & Install and configure simple_sitemap_extensions,600,2070
-,WV-4412,Implement custom dynamic variants for sitemaps to group by month,0,105 -,TNP-4412,Implement custom dynamic variants for sitemaps to group by month,0,105
-,WV-4414,Invalid JSON in the cache_tools composer.json file,0,60 -,TNP-4414,Invalid JSON in the cache_tools composer.json file,0,60
-,WV-4421,WV Satellites Hand bau image file entities are not replicated,0,15 -,TNP-4421,TNP Satellites Hand bau image file entities are not replicated,0,15
-,WV-4422,"[Red Alert] Behat test fail. ""Demo content loaded..Error pages work.""",0,75 -,TNP-4422,"[Red Alert] Behat test fail. ""Demo content loaded..Error pages work.""",0,75
-,WV-4423,(ODT-1325) Site managers must be able to change article status from Unpublished to Unpublished,0,15 -,TNP-4423,(ODT-1325) Site managers must be able to change article status from Unpublished to Unpublished,0,15
-,WV-4425,Unpublished Advertorials are returned,0,30 -,TNP-4425,Unpublished Advertorials are returned,0,30
-,WV-4427,"(ODT-1332) ""Og: image"" is not specified explicitly",120,15 -,TNP-4427,"(ODT-1332) ""Og: image"" is not specified explicitly",120,15
-,WV-4437,"(ODT-1339) User (id 511) on wv-contentpool is locked and cannot access the system.",0,30 -,TNP-4437,"(ODT-1339) User (id 511) on wv-contentpool is locked and cannot access the system.",0,30
-,WV-4442,(ODT-1341) Custom HTML block is not rendered,0,120 -,TNP-4442,(ODT-1341) Custom HTML block is not rendered,0,120
-,WV-4478,(ODT-1368) Hosting provider transition of all projects hosted on their OpenShift infrastructure to the new Kuberneets (k8) infrastructure.,0,90 -,TNP-4478,(ODT-1368) Hosting provider transition of all projects hosted on their OpenShift infrastructure to the new Kuberneets (k8) infrastructure.,0,90
-,WV-4480,(ODT-1370) Error: Call to a member function getUrl() on null / cannot save an article on stage systems,0,90 -,TNP-4480,(ODT-1370) Error: Call to a member function getUrl() on null / cannot save an article on stage systems,0,90

1 Group name Item Item Summary Estimation time Spent time
3 - DEV-56 Developer training 0 60
4 - DEV-122 Daily standup 0 255
5 - INF-6 Infrastructure misc, diverse 0 75
6 - KUR-181 SND-181 Sprint meetings (PM) 240 390
7 - KUR-507 SND-507 (TKT-307) Change webhook integration for Slack 0 330
8 - KUR-552 SND-552 (TKT-740) Allow kicking users out of collections 780 45
9 - KUR-554 SND-554 (TKT-1448) Adaptions in Backend 0 30
10 - KUR-556 SND-556 [story] (TKT-1393) Make Paragraph embedding more user friendly 0 75
11 - KUR-558 SND-558 (TKT-1467) Full copy of article doesn't update the timestamp 0 15
12 - KUR-562 SND-562 (TKT-1441) Implement SEO title in BE 0 45
13 - LDP-668 Add json-ld schema.org metadata to articles 0 300
14 - LDP-685 LDP-Contentpool sitemaps. Extend "simple_sitemap_extended" setup to support per front-end site sitemaps. 0 15
15 - LDP-692 Output json-ld script 0 30
28 - LDP-740 CP: Add portal path prefixes 480 30
29 - LDP-741 Defects marketing Blocks 0 450
30 - LDP-742 [Red Alert] Develop branch fails to build 0 45
31 - VAL-8 TES-8 Plan hosting setup on custom hosting provider 0 45
32 - WV-31 TNP-31 Internal sprint meetings (PM, fixed-price). 0 150
33 - WV-4304 TNP-4304 (ODT-1240) Structured data on article (satellite) pages and overview pages such as the startpage, branch, topic & channel pages. 600 750
34 - WV-4305 TNP-4305 (ODT-1202) Add mobile-banner-3 & 4 (advertisement in articles) 0 60
35 - WV-4326 TNP-4326 (ODT-1174) Make image optional in the Call to Action block 135 60
36 - WV-4355 TNP-4355 (ODT-1270) Add article title to breadcrumbs 0 270
37 - WV-4359 TNP-4359 (ODT-1254) Display the text paragraph "zwischentitel" in H2 0 90
38 - WV-4372 TNP-4372 (ODT-1297) Branch analytics for articles associated with specific branch (GA) 135 15
39 - WV-4384 TNP-4384 (ODT-1306) Layout-builder rendering in Chrome browser 120 120
40 - WV-4393 TNP-4393 WVsat docker build error TNPsat docker build error 0 90
41 - WV-4410 TNP-4410 (ODT-1317) SOLR Search optimization >> suggested articles does NOT affect the relevance for search results. 375 30
42 - WV-4411 TNP-4411 Extend simple_sitemap_extensions for dynamic variants & Install and configure simple_sitemap_extensions 600 2070
43 - WV-4412 TNP-4412 Implement custom dynamic variants for sitemaps to group by month 0 105
44 - WV-4414 TNP-4414 Invalid JSON in the cache_tools composer.json file 0 60
45 - WV-4421 TNP-4421 WV Satellites Hand bau image file entities are not replicated TNP Satellites Hand bau image file entities are not replicated 0 15
46 - WV-4422 TNP-4422 [Red Alert] Behat test fail. "Demo content loaded..Error pages work." 0 75
47 - WV-4423 TNP-4423 (ODT-1325) Site managers must be able to change article status from Unpublished to Unpublished 0 15
48 - WV-4425 TNP-4425 Unpublished Advertorials are returned 0 30
49 - WV-4427 TNP-4427 (ODT-1332) "Og: image" is not specified explicitly 120 15
50 - WV-4437 TNP-4437 (ODT-1339) User (id 511) on wv-contentpool is locked and cannot access the system. 0 30
51 - WV-4442 TNP-4442 (ODT-1341) Custom HTML block is not rendered 0 120
52 - WV-4478 TNP-4478 (ODT-1368) Hosting provider transition of all projects hosted on their OpenShift infrastructure to the new Kuberneets (k8) infrastructure. 0 90
53 - WV-4480 TNP-4480 (ODT-1370) Error: Call to a member function getUrl() on null / cannot save an article on stage systems 0 90

View File

@ -0,0 +1,11 @@
report: /home/lio/Projects/drunomix/rprt-cli/app/tests/Kernel/../data/21-03.csv
+-----------------------------+--------+-------+----------+
| Project | Hours | Rate | Price |
+-----------------------------+--------+-------+----------+
| lupus.digital publishing | 61,75 | 25,60 | 1.580,80 |
| Projektbezogene Entwicklung | 100,50 | 29,10 | 2.924,55 |
+-----------------------------+--------+-------+----------+
| Gesamt netto | 162,25 | | 4.505,35 |
+-----------------------------+--------+-------+----------+
| Gessamt brutto | 4.505,35 |
+-----------------------------+--------+-------+----------+

View File

@ -0,0 +1,76 @@
report: /home/lio/Projects/drunomix/rprt-cli/app/tests/Kernel/../data/21-03.csv
+----------------+--------------------------------------------------------------+------+------------+
| Ticket Id | Name | Time | Estimation |
+----------------+--------------------------------------------------------------+------+------------+
| DEV-46 | Wochenplanung, Weekly | 315 | 0 |
| DEV-56 | Developer training | 60 | 0 |
| DEV-122 | Daily standup | 255 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| DEV | 10.5 |
+----------------+--------------------------------------------------------------+------+------------+
| INF-6 | Infrastructure misc, diverse | 75 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| INF | 1.25 |
+----------------+--------------------------------------------------------------+------+------------+
| SND-181 | Sprint meetings (PM) | 390 | 240 |
| SND-507 | (TKT-307) Change webhook integration for Slack | 330 | 0 |
| SND-552 | (TKT-740) Allow kicking users out of collections | 45 | 780 |
| SND-554 | (TKT-1448) Adaptions in Backend | 30 | 0 |
| SND-556 | [story] (TKT-1393) Make Paragraph embedding more user friend | 75 | 0 |
| SND-558 | (TKT-1467) Full copy of article doesn't update the timestamp | 15 | 0 |
| SND-562 | (TKT-1441) Implement SEO title in BE | 45 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| SND | 15.5 |
+----------------+--------------------------------------------------------------+------+------------+
| LDP-668 | Add json-ld schema.org metadata to articles | 300 | 0 |
| LDP-685 | LDP-Contentpool sitemaps. Extend "simple_sitemap_extended" s | 15 | 0 |
| LDP-692 | Output json-ld script | 30 | 0 |
| LDP-693 | Add WebPage schema.org support | 180 | 120 |
| LDP-700 | LDP onboarding Somebody | 15 | 0 |
| LDP-706 | Backend FAQ Marketing Block | 165 | 0 |
| LDP-707 | Backend "Hero" Marketing Block | 1035 | 0 |
| LDP-709 | Backend "Newsletter Signup" Marketing Block | 195 | 0 |
| LDP-711 | Backend "Call to action" Marketing Block | 165 | 0 |
| LDP-712 | Backend "Feature section" Marketing Block | 300 | 0 |
| LDP-713 | Provide a field type and pre-configuration for choosing icon | 45 | 300 |
| LDP-716 | Entity browser UX is not as good as expected | 15 | 0 |
| LDP-720 | Improve display of nodes and add support for article heros | 45 | 0 |
| LDP-728 | ldp-marketing blocks break the page when they are added to t | 195 | 0 |
| LDP-729 | ldp-cp portal entity | 480 | 0 |
| LDP-740 | CP: Add portal path prefixes | 30 | 480 |
| LDP-741 | Defects marketing Blocks | 450 | 0 |
| LDP-742 | [Red Alert] Develop branch fails to build | 45 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| LDP | 61.75 |
+----------------+--------------------------------------------------------------+------+------------+
| TES-8 | Plan hosting setup on custom hosting provider | 45 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| TES | 0.75 |
+----------------+--------------------------------------------------------------+------+------------+
| TNP-31 | Internal sprint meetings (PM, fixed-price). | 150 | 0 |
| TNP-4304 | (ODT-1240) Structured data on article (satellite) pages and | 750 | 600 |
| TNP-4305 | (ODT-1202) Add mobile-banner-3 & 4 (advertisement in article | 60 | 0 |
| TNP-4326 | (ODT-1174) Make image optional in the Call to Action block | 60 | 135 |
| TNP-4355 | (ODT-1270) Add article title to breadcrumbs | 270 | 0 |
| TNP-4359 | (ODT-1254) Display the text paragraph "zwischentitel" in H2 | 90 | 0 |
| TNP-4372 | (ODT-1297) Branch analytics for articles associated with spe | 15 | 135 |
| TNP-4384 | (ODT-1306) Layout-builder rendering in Chrome browser | 120 | 120 |
| TNP-4393 | TNPsat docker build error | 90 | 0 |
| TNP-4410 | (ODT-1317) SOLR Search optimization >> suggested articles do | 30 | 375 |
| TNP-4411 | Extend simple_sitemap_extensions for dynamic variants & Inst | 2070 | 600 |
| TNP-4412 | Implement custom dynamic variants for sitemaps to group by m | 105 | 0 |
| TNP-4414 | Invalid JSON in the cache_tools composer.json file | 60 | 0 |
| TNP-4421 | TNP Satellites Hand bau image file entities are not replicat | 15 | 0 |
| TNP-4422 | [Red Alert] Behat test fail. "Demo content loaded..Error pag | 75 | 0 |
| TNP-4423 | (ODT-1325) Site managers must be able to change article stat | 15 | 0 |
| TNP-4425 | Unpublished Advertorials are returned | 30 | 0 |
| TNP-4427 | (ODT-1332) "Og: image" is not specified explicitly | 15 | 120 |
| TNP-4437 | (ODT-1339) User (id 511) on wv-contentpool is locked and can | 30 | 0 |
| TNP-4442 | (ODT-1341) Custom HTML block is not rendered | 120 | 0 |
| TNP-4478 | (ODT-1368) Hosting provider transition of all projects hoste | 90 | 0 |
| TNP-4480 | (ODT-1370) Error: Call to a member function getUrl() on null | 90 | 0 |
+----------------+--------------------------------------------------------------+------+------------+
| TNP | 72.5 |
+----------------+--------------------------------------------------------------+------+------------+
| DEV, INF, SND, LDP, TES, TNP | 162.25 |
+----------------+--------------------------------------------------------------+------+------------+

View File

@ -2,6 +2,6 @@
$dependencies = require_once(__DIR__ . '/../dependencies.php'); $dependencies = require_once(__DIR__ . '/../dependencies.php');
$dependencies['config.path'] = __DIR__ . '/data'; $dependencies['config.path'] = __DIR__ . '/data/';
return $dependencies; return $dependencies;

View File

@ -21,8 +21,8 @@ TODO:
TODO (end of 2022): TODO (end of 2022):
- DONE fix project list output (first is missing) - DONE fix project list output (first is missing)
- DONE report selection trait - DONE report selection trait
- automated tests - DONE automated tests
- phpcs - DONE phpcs
- phpstan - phpstan
OPTIONAL: OPTIONAL:
- phing build system to run quality assurance - phing build system to run quality assurance