Add report command, rename to invoice.
parent
1e2e6bade4
commit
c8e38922c0
|
@ -5,7 +5,7 @@
|
|||
|
||||
** Usage
|
||||
|
||||
~./rprt.php rprt -y -p -s~
|
||||
~./rprt.php invoice -y -p -s~
|
||||
|
||||
This command would send an invoice for last month created from the template
|
||||
file and last month report from youtrack as an email attachment.
|
||||
|
@ -69,9 +69,9 @@ curl 'https://drunomics.myjetbrains.com/youtrack/api/reports?$top=-1&fields=id,n
|
|||
|
||||
*** most current
|
||||
1. For version 0.6.7
|
||||
- data value objects
|
||||
- [X] data value objects
|
||||
- phar file
|
||||
- additional expenses
|
||||
- [X] additional expenses
|
||||
2. For version 1.0
|
||||
- plugin system
|
||||
- for time tracking services
|
||||
|
|
|
@ -3,11 +3,11 @@
|
|||
use function DI\create;
|
||||
use function DI\get;
|
||||
|
||||
use RprtCli\Commands\RprtCommand;
|
||||
use RprtCli\Commands\InvoiceCommand;
|
||||
use RprtCli\Commands\ReportCommand;
|
||||
use RprtCli\Commands\TrackCommand;
|
||||
use RprtCli\Utils\Configuration\ConfigurationInterface;
|
||||
use RprtCli\Utils\Configuration\ConfigurationService;
|
||||
use RprtCli\Utils\CsvReport\CsvReport;
|
||||
use RprtCli\Utils\CsvReport\CsvReportInterface;
|
||||
use RprtCli\Utils\CsvReport\ReportCsv;
|
||||
use RprtCli\Utils\CsvReport\ReportCsvInterface;
|
||||
use GuzzleHttp\Client;
|
||||
|
@ -60,7 +60,7 @@ return [
|
|||
get('pdf_export.service')
|
||||
),
|
||||
'mailer' => get(MailerInterface::class),
|
||||
RprtCommand::class => create()->constructor(
|
||||
InvoiceCommand::class => create()->constructor(
|
||||
get('csv.report'),
|
||||
get('config.service'),
|
||||
get('youtrack.service'),
|
||||
|
@ -70,5 +70,10 @@ return [
|
|||
TrackCommand::class => create()->constructor(
|
||||
get('config.service'),
|
||||
get('youtrack.service')
|
||||
),
|
||||
ReportCommand::class => create()->constructor(
|
||||
get('config.service'),
|
||||
get('youtrack.service'),
|
||||
get('csv.report')
|
||||
)
|
||||
];
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use RprtCli\Commands\RprtCommand;
|
||||
use RprtCli\Commands\InvoiceCommand;
|
||||
use RprtCli\Commands\ReportCommand;
|
||||
use DI\ContainerBuilder;
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
@ -13,7 +14,9 @@ $container = $builder->build();
|
|||
|
||||
$application = new Application();
|
||||
|
||||
$rprtCommand = $container->get(RprtCommand::class);
|
||||
$application->add($rprtCommand);
|
||||
$invoiceCommand = $container->get(InvoiceCommand::class);
|
||||
$application->add($invoiceCommand);
|
||||
$reportCommand = $container->get(ReportCommand::class);
|
||||
$application->add($reportCommand);
|
||||
|
||||
$application->run();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
declare(strict_types=1);
|
||||
|
||||
// src/Commands/RprtCommand.php;
|
||||
// src/Commands/InvoiceCommand.php;
|
||||
|
||||
namespace RprtCli\Commands;
|
||||
|
||||
|
@ -25,9 +25,9 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
use function var_dump;
|
||||
|
||||
/**
|
||||
* Main file - rprt command.
|
||||
* Main file - invoice command.
|
||||
*/
|
||||
class RprtCommand extends Command
|
||||
class InvoiceCommand extends Command
|
||||
{
|
||||
protected $csv;
|
||||
|
||||
|
@ -61,8 +61,8 @@ class RprtCommand extends Command
|
|||
*/
|
||||
protected function configure() : void
|
||||
{
|
||||
$this->setName('rprt');
|
||||
$this->setDescription('Generate monthly report');
|
||||
$this->setName('invoice');
|
||||
$this->setDescription('Generate an invoice from (monthly) report');
|
||||
// @TODO $this->addUsage('');
|
||||
// @TODO add sub options (config overrides)
|
||||
$this->addOption(
|
||||
|
@ -85,7 +85,7 @@ class RprtCommand extends Command
|
|||
);
|
||||
$this->addOption(
|
||||
'test',
|
||||
't',
|
||||
'',
|
||||
InputOption::VALUE_NONE,
|
||||
'Test login into youtrack service. Prints out your name.'
|
||||
);
|
||||
|
@ -129,7 +129,7 @@ class RprtCommand extends Command
|
|||
);
|
||||
$this->addOption(
|
||||
'report',
|
||||
'g',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Show time tracked for report.',
|
||||
FALSE
|
||||
|
@ -146,7 +146,7 @@ class RprtCommand extends Command
|
|||
$list = $this->youtrack->listReports();
|
||||
$output->writeln(var_export($list, TRUE));
|
||||
}
|
||||
if ($input->hasParameterOption('--report') || $input->hasParameterOption('-g')) {
|
||||
if ($input->hasParameterOption('--report') || $input->hasParameterOption('-t')) {
|
||||
if ($report = $input->getOption('report')) {
|
||||
$this->youtrack->setReportId($report);
|
||||
}
|
||||
|
@ -174,8 +174,8 @@ class RprtCommand extends Command
|
|||
}
|
||||
if ($youtrack || $file = $input->getOption('file')) {
|
||||
// Youtrack can also provide a file name.
|
||||
var_dump($file);
|
||||
$data = $this->csv->getReportData($file);
|
||||
// var_dump($file);
|
||||
$data = $this->csv->getInvoiceData($file);
|
||||
if (!empty($expenses)) {
|
||||
$data = array_merge($data, $expenses);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace RprtCli\Commands;
|
||||
|
||||
use RprtCli\Utils\Configuration\ConfigurationInterface;
|
||||
use RprtCli\Utils\CsvReport\ReportCsvInterface;
|
||||
use RprtCli\Utils\TimeTrackingServices\YoutrackInterface;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ReportCommand extends Command {
|
||||
|
||||
protected $trackingService;
|
||||
|
||||
protected $config;
|
||||
|
||||
protected $csv;
|
||||
|
||||
public function __construct(ConfigurationInterface $configuration, YoutrackInterface $tracking_service, ReportCsvInterface $csv, ?string $name = null) {
|
||||
$this->config = $configuration;
|
||||
// @TODO generalize tracking service.
|
||||
$this->trackingService = $tracking_service;
|
||||
$this->csv = $csv;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected function configure() :void {
|
||||
$this->setName('report');
|
||||
$this->setDescription('Get a time-tracking report into command line.');
|
||||
$this->addOption(
|
||||
'report',
|
||||
'r',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Select a report from list of your reports'
|
||||
);
|
||||
$this->addOption(
|
||||
'time-range',
|
||||
't',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
'Calculates report from tracking service work items directly for time range'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) :int {
|
||||
// Could just parse a csv file or actually get workItems from youtrack ...
|
||||
if ($input->hasParameterOption('--report') || $input->hasParameterOption('-r')) {
|
||||
if ($report = $input->getOption('report')) {
|
||||
$this->trackingService->setReportId($report);
|
||||
} else {
|
||||
$reports = $this->trackingService->listReports();
|
||||
$count = 1;
|
||||
foreach ($reports as $id => $name) {
|
||||
$output->writeln("[{$count}] {$name} ({$id})");
|
||||
$count++;
|
||||
}
|
||||
$output->writeln("[{$count}] None (null)");
|
||||
$report = readline('Select id of the report: ');
|
||||
// Asume people are literate.
|
||||
if (!in_array($report, array_keys($reports) )) {
|
||||
$output->writeln('Non-existing report. Exiting.');
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
$this->trackingService->setReportId($report);
|
||||
}
|
||||
}
|
||||
|
||||
// Currently we only support csv download.
|
||||
$report_id = $this->trackingService->getReportId();
|
||||
$file = $this->trackingService->downloadReport($report_id);
|
||||
// var_dump($file);
|
||||
$data = $this->csv->generateReportTable($file);
|
||||
$table = $this->buildTable($output, $data);
|
||||
$table->render();
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds table from the report csv data.
|
||||
*
|
||||
* @TODO: Code duplication with InvoiceCommand::getTable.
|
||||
*/
|
||||
protected function buildTable(OutputInterface $output, array $rows): Table {
|
||||
$table = new Table($output);
|
||||
$table->setHeaders([
|
||||
'Ticket Id', 'Name', 'Time', 'Estimation',
|
||||
]);
|
||||
foreach ($rows as $key => $row) {
|
||||
if (!$row) {
|
||||
$rows[$key] = new TableSeparator();
|
||||
} elseif (is_array($row) && is_null($row[0]) && is_null($row[2])) {
|
||||
// Check which elements in array are null.
|
||||
$rows[$key] = [new TableCell($row[1], ['colspan' => 2]), new TableCell((string) $row[3], ['colspan' => 2])];
|
||||
}
|
||||
}
|
||||
$table->setRows($rows);
|
||||
return $table;
|
||||
}
|
||||
|
||||
}
|
|
@ -36,7 +36,7 @@ class CsvReport implements CsvReportInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReportData(string $filePath) : array
|
||||
public function getInvoiceData(string $filePath) : array
|
||||
{
|
||||
$output = [];
|
||||
// @TODO replace with config service.
|
||||
|
|
|
@ -17,7 +17,7 @@ interface CsvReportInterface
|
|||
*
|
||||
* Project key as key and number of hours as value.
|
||||
*/
|
||||
public function getReportData(string $filePath) : array;
|
||||
public function getInvoiceData(string $filePath) : array;
|
||||
|
||||
/**
|
||||
* Data for default drunomics pdf export.
|
||||
|
|
|
@ -38,7 +38,7 @@ class ReportCsv implements ReportCsvInterface
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getReportData(string $filePath) : array
|
||||
public function getInvoiceData(string $filePath) : array
|
||||
{
|
||||
$output = [];
|
||||
// @TODO replace with config service.
|
||||
|
@ -117,6 +117,7 @@ class ReportCsv implements ReportCsvInterface
|
|||
}
|
||||
}
|
||||
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;
|
||||
|
@ -124,7 +125,7 @@ class ReportCsv implements ReportCsvInterface
|
|||
foreach ($data as $invoice_element) {
|
||||
if ($invoice_element instanceof ExpensesInterface) {
|
||||
if (!isset($added_expenses)) {
|
||||
// Make next line bold and centered.
|
||||
// @TODO - separator 0: Make next line bold and centered.
|
||||
$rows[] = 0;
|
||||
$rows[] = [
|
||||
null,
|
||||
|
@ -168,6 +169,64 @@ class ReportCsv implements ReportCsvInterface
|
|||
return $rows;
|
||||
}
|
||||
|
||||
public function generateReportTable(string $filePath) {
|
||||
// ticket-id, ticket-name, time-spent
|
||||
$data = $this->parseReportData($filePath);
|
||||
[$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];
|
||||
$project_time += (float) $line['time'];
|
||||
$table[] = array_values($line);
|
||||
if ($project !== $previous_project) {
|
||||
// When project changes, add a sum of time for that project.
|
||||
$table[] = null;
|
||||
$table[] = [null, $previous_project, null, $project_time/60];
|
||||
$table[] = null;
|
||||
$time_sum += (float) $project_time;
|
||||
$project_time = 0;
|
||||
$all_projects[] = $project;
|
||||
}
|
||||
$previous = $line['id'];
|
||||
}
|
||||
// Add sum for the last project.
|
||||
$table[] = null;
|
||||
$table[] = [null, $project, null, $project_time / 60];
|
||||
$time_sum += (float) $project_time;
|
||||
$all_projects[] = $project;
|
||||
// Add a sum of time for whole day.
|
||||
$table[] = null;
|
||||
$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, 80),
|
||||
'time' => $line[4],
|
||||
'estimation' => $line[3],
|
||||
];
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Should be moved into test class.
|
||||
*/
|
||||
|
|
|
@ -17,7 +17,7 @@ interface ReportCsvInterface
|
|||
*
|
||||
* Project key as key and number of hours as value.
|
||||
*/
|
||||
public function getReportData(string $filePath): array;
|
||||
public function getInvoiceData(string $filePath): array;
|
||||
|
||||
/**
|
||||
* Returns array of rows created from array of InvoiceElements.
|
||||
|
|
Loading…
Reference in New Issue