Fix phpstan errors, improve automated test.

yt-rest-api
Lio Novelli 2023-01-02 20:35:41 +01:00
parent 624b895fd6
commit 99d16c3a72
14 changed files with 70 additions and 37 deletions

View File

@ -36,7 +36,8 @@
}, },
"scripts": { "scripts": {
"cs": "phpcs --colors --standard=PSR12", "cs": "phpcs --colors --standard=PSR12",
"cbf": "phpcbf" "cbf": "phpcbf",
"phpstan": "phpstan analyze -l 5 src"
}, },
"config": { "config": {
"allow-plugins": { "allow-plugins": {

View File

@ -27,6 +27,7 @@ use function explode;
use function is_array; use function is_array;
use function is_null; use function is_null;
use function is_string; use function is_string;
use function PHPUnit\Framework\throwException;
use function readline; use function readline;
use function strpos; use function strpos;
use function strtolower; use function strtolower;
@ -42,13 +43,15 @@ class InvoiceCommand extends Command
{ {
use SelectReportTrait; use SelectReportTrait;
protected $csv; protected ReportCsvInterface $csv;
protected $config; protected ConfigurationInterface $config;
protected $youtrack; protected YoutrackInterface $trackingService;
protected $pdfExport; protected PdfExportInterface $pdfExport;
protected MailerInterface $mailer;
protected const TYPE_WORK = 1; protected const TYPE_WORK = 1;
protected const TYPE_EXPENSE = 2; protected const TYPE_EXPENSE = 2;
@ -185,11 +188,11 @@ class InvoiceCommand extends Command
if ($out = $input->getOption('output')) { if ($out = $input->getOption('output')) {
$this->pdfExport->setOutput($out); $this->pdfExport->setOutput($out);
} }
$output_path = $this->pdfExport->fromDefaultDataToPdf($nice_data); $output_path = $this->pdfExport->fromDefaultDataToPdf($nice_data) ?: sys_get_temp_dir();
// Notify the user where the file was generated to. // Notify the user where the file was generated to.
$output->writeln("The file was generated at <info>${output_path}</info>."); $output->writeln("The file was generated at <info>${output_path}</info>.");
} }
if ($input->getOption('send') && $output_path) { if ($input->getOption('send') && isset($output_path)) {
// @TODO If no output path print an error. // @TODO If no output path print an error.
// Send email to configured address. // Send email to configured address.
if ($recipients = $input->getOption('recipients')) { if ($recipients = $input->getOption('recipients')) {
@ -273,7 +276,7 @@ class InvoiceCommand extends Command
$rows[] = new TableSeparator(); $rows[] = new TableSeparator();
// @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[] = ['Sum', $totalHours, $config['price'], $totalPrice]; $rows[] = ['Sum', $totalHours, NULL, $totalPrice];
$table->setRows($rows); $table->setRows($rows);
return $table; return $table;
@ -326,7 +329,7 @@ class InvoiceCommand extends Command
return $output; return $output;
} }
protected function getCustomWorkOrExpenses($custom, $type) protected function getCustomWorkOrExpenses(mixed $custom, int $type)
{ {
$output = []; $output = [];
if (is_string($custom)) { if (is_string($custom)) {
@ -343,6 +346,9 @@ class InvoiceCommand extends Command
$message_name = 'Enter expenses name or leave empty to stop: '; $message_name = 'Enter expenses name or leave empty to stop: ';
$message_value = 'Enter expenses value: '; $message_value = 'Enter expenses value: ';
} }
else {
throw new \Exception('Unknown type of custom data.');
}
while ($continue) { while ($continue) {
$name = readline($message_name); $name = readline($message_name);
$value = (float) readline($message_value); $value = (float) readline($message_value);

View File

@ -22,11 +22,11 @@ class ReportCommand extends Command
{ {
use SelectReportTrait; use SelectReportTrait;
protected $trackingService; protected YoutrackInterface $trackingService;
protected $config; protected ConfigurationInterface $config;
protected $csv; protected ReportCsvInterface $csv;
// phpcs:ignore // 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)

View File

@ -114,8 +114,8 @@ class CsvReport implements CsvReportInterface
$rows[] = [ $rows[] = [
'Gesamt netto', 'Gesamt netto',
number_format($totalHours, 2, ',', '.'), number_format($totalHours, 2, ',', '.'),
number_format($config['price'], 2, ',', '.'), NULL,
number_format($totalPrice, 2, ',', '.') number_format($totalPrice, 2, ',', '.'),
]; ];
$rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')]; $rows[] = [null, null, 'Gessamt brutto', number_format($totalPrice, 2, ',', '.')];

View File

@ -6,6 +6,8 @@ namespace RprtCli\Utils\CsvReport;
/** /**
* Handles creating report data from csv file downloaded from youtrack service. * Handles creating report data from csv file downloaded from youtrack service.
*
* @deprecated Use ReportCsv instead.
*/ */
interface CsvReportInterface interface CsvReportInterface
{ {

View File

@ -98,11 +98,11 @@ class ReportCsv implements ReportCsvInterface
{ {
[$rows, $totalHours, $totalPrice, $add_separator] = [[], 0, 0, false]; [$rows, $totalHours, $totalPrice, $add_separator] = [[], 0, 0, false];
$projectsConfig = $this->configurationService->get('projects'); $projectsConfig = $this->configurationService->get('projects');
// @TODO Remove unnecessary header after check.
// $header = $this->configurationService->get('export.labels', null); // $header = $this->configurationService->get('export.labels', null);
$header = null; // if (is_array($header)) {
if (is_array($header)) { // $rows[] = $header;
$rows[] = $header; // }
}
// First only list work invoice elements. // First only list work invoice elements.
foreach ($data as $key => $invoice_element) { foreach ($data as $key => $invoice_element) {
if ($invoice_element instanceof WorkInvoiceElementInterface) { if ($invoice_element instanceof WorkInvoiceElementInterface) {
@ -186,7 +186,10 @@ class ReportCsv implements ReportCsvInterface
return $rows; return $rows;
} }
public function generateReportTable(string $filePath) /**
* {@inheritdoc}
*/
public function generateReportTable(string $filePath): array
{ {
// ticket-id, ticket-name, time-spent // ticket-id, ticket-name, time-spent
$data = $this->parseReportData($filePath); $data = $this->parseReportData($filePath);

View File

@ -48,4 +48,6 @@ interface ReportCsvInterface
* Parsed data from csv report. * Parsed data from csv report.
*/ */
public function arangeDataForDefaultPdfExport(array $data): array; public function arangeDataForDefaultPdfExport(array $data): array;
public function generateReportTable(string $filePath): array;
} }

View File

@ -7,6 +7,17 @@ namespace RprtCli\Utils\Mailer;
/** /**
* Methods for symfony (swift)mailer service. * Methods for symfony (swift)mailer service.
*/ */
interface MailerInterface interface MailerInterface {
{
/**
* Recipients for message.
*
* @param string[] $to
*/
public function setRecipients(array $to): void;
/**
* Sends default mail.
*/
public function sendDefaultMail(string $output): void;
} }

View File

@ -46,6 +46,8 @@ class MailerService implements MailerInterface
protected $email; protected $email;
protected string $password;
public function __construct(ConfigurationInterface $config, PdfExportInterface $pdf) public function __construct(ConfigurationInterface $config, PdfExportInterface $pdf)
{ {
$this->config = $config; $this->config = $config;

View File

@ -69,6 +69,7 @@ class PdfExportService implements PdfExportInterface
$table = '<table><thead><tr class="tr-header">'; $table = '<table><thead><tr class="tr-header">';
$header = array_shift($data); $header = array_shift($data);
$classes = ''; $classes = '';
$rows = [];
foreach ($header as $index => $cell) { foreach ($header as $index => $cell) {
$table .= "<th class=\"th-{$index}\">{$cell}</th>"; $table .= "<th class=\"th-{$index}\">{$cell}</th>";
} }

View File

@ -40,4 +40,9 @@ interface YoutrackInterface
public function setReportName(?string $report_name = null): void; public function setReportName(?string $report_name = null): void;
public function getReportName(): ?string; public function getReportName(): ?string;
/**
* Clears cache for youtrack report.
*/
public function clearReportCache(string $report_id): int;
} }

View File

@ -27,6 +27,9 @@ class ReportCommandTest extends TestCase {
protected const INVOICE_OUTPUT_PDF = __DIR__ . '/../data/output/Invoice-test.pdf'; protected const INVOICE_OUTPUT_PDF = __DIR__ . '/../data/output/Invoice-test.pdf';
/**
* Run report and invoice command with file option parameter. Check if pdf was generated.
*/
public function testExecute() { public function testExecute() {
$builder = new ContainerBuilder(); $builder = new ContainerBuilder();
$builder->addDefinitions(__DIR__ . '/../test-dependencies.php'); $builder->addDefinitions(__DIR__ . '/../test-dependencies.php');
@ -60,29 +63,25 @@ class ReportCommandTest extends TestCase {
$this->assertStringContainsString('21-03.csv', $output); $this->assertStringContainsString('21-03.csv', $output);
$this->assertStringEqualsFile(self::REPORT_OUTPUT_FILE, $output); $this->assertStringEqualsFile(self::REPORT_OUTPUT_FILE, $output);
if (file_exists(self::INVOICE_OUTPUT_PDF)) {
unlink(self::INVOICE_OUTPUT_PDF);
}
$invoiceCommand = $application->find('invoice'); $invoiceCommand = $application->find('invoice');
$invoiceCommandTester = new CommandTester($invoiceCommand); $invoiceCommandTester = new CommandTester($invoiceCommand);
$invoiceCommandTester->execute([ $invoiceCommandTester->execute([
'--file' => self::INPUT_CSV_FILE, '--file' => self::INPUT_CSV_FILE,
'--pdf' => TRUE, '--pdf' => TRUE,
'--output' => self::INVOICE_OUTPUT_PDF,
]); ]);
$invoiceCommandTester->assertCommandIsSuccessful(); $invoiceCommandTester->assertCommandIsSuccessful();
// the output of the command in the console // the output of the command in the console
$invoice_output = $invoiceCommandTester->getDisplay(); $invoice_output = $invoiceCommandTester->getDisplay();
var_dump($invoice_output); // var_dump($invoice_output);
$this->assertStringContainsString('21-03.csv', $invoice_output); $this->assertStringContainsString('21-03.csv', $invoice_output);
$this->assertStringEqualsFile(self::INVOICE_OUTPUT_FILE, $invoice_output); $this->assertStringEqualsFile(self::INVOICE_OUTPUT_FILE, $invoice_output);
$this->assertFileExists(self::INVOICE_OUTPUT_PDF);
// $invoiceCommandTester->execute([
// '--file' => self::INPUT_CSV_FILE,
// '--pdf'
// ]);
// $invoice_output = $invoiceCommandTester->getDisplay();
// var_dump($invoice_output);
// $this->assertFileExists();
} }
} }

View File

@ -9,3 +9,4 @@ report: /home/lio/Projects/drunomix/rprt-cli/app/tests/Kernel/../data/21-03.csv
+-----------------------------+--------+-------+----------+ +-----------------------------+--------+-------+----------+
| Gessamt brutto | 4.505,35 | | Gessamt brutto | 4.505,35 |
+-----------------------------+--------+-------+----------+ +-----------------------------+--------+-------+----------+
The file was generated at /home/lio/Projects/drunomix/rprt-cli/app/tests/Kernel/../data/output/Invoice-test.pdf.

View File

@ -1,5 +1,4 @@
TODO: TODO:
- nice report selection
- clean up the config (default reports) - clean up the config (default reports)
- Improve readme - Improve readme
- abstract baseCommand with some input params - abstract baseCommand with some input params
@ -8,13 +7,9 @@ TODO:
- in dependencies.php find subdependencies.php - in dependencies.php find subdependencies.php
- Create interface for 3rd party service integration and abstract class - Create interface for 3rd party service integration and abstract class
- Create factory to add correct service of a 3rd party service to the Command - Create factory to add correct service of a 3rd party service to the Command
- separator constant
------------------------ ------------------------
- add plugin system for time tracking service - add plugin system for time tracking service
- add tests
------------------------ ------------------------
- question helper: https://symfony.com/doc/current/components/console/helpers/questionhelper.html
- psr-12 code check and add phpstan https://phpstan.org/user-guide/getting-started
- phing for build automation - phing for build automation
- add ddev for dockerization - add ddev for dockerization
@ -32,6 +27,7 @@ OPTIONAL:
- youtrack - youtrack
- jira - jira
- kimai - kimai
- build phar without most of the fonts
@ -44,4 +40,8 @@ DONE:
- upload a phar file on repo - upload a phar file on repo
- create release - create release
- clear report cache - clear report cache
- nice report selection
- separator constant
- add tests
- psr-12 code check and add phpstan https://phpstan.org/user-guide/getting-started
- question helper: https://symfony.com/doc/current/components/console/helpers/questionhelper.html