improve project overview (#2467)
This commit is contained in:
@@ -45,17 +45,25 @@ final class ProjectViewModel
|
|||||||
* @var float
|
* @var float
|
||||||
*/
|
*/
|
||||||
private $notExportedRate = 0.00;
|
private $notExportedRate = 0.00;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $notBilledDuration = 0;
|
||||||
|
/**
|
||||||
|
* @var float
|
||||||
|
*/
|
||||||
|
private $notBilledRate = 0.00;
|
||||||
|
|
||||||
public function getProject(): ?Project
|
public function __construct(Project $project)
|
||||||
{
|
|
||||||
return $this->project;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setProject(Project $project): void
|
|
||||||
{
|
{
|
||||||
$this->project = $project;
|
$this->project = $project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getProject(): Project
|
||||||
|
{
|
||||||
|
return $this->project;
|
||||||
|
}
|
||||||
|
|
||||||
public function getDurationDay(): int
|
public function getDurationDay(): int
|
||||||
{
|
{
|
||||||
return $this->durationDay;
|
return $this->durationDay;
|
||||||
@@ -116,6 +124,26 @@ final class ProjectViewModel
|
|||||||
$this->notExportedRate = $notExportedRate;
|
$this->notExportedRate = $notExportedRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getNotBilledDuration(): int
|
||||||
|
{
|
||||||
|
return $this->notBilledDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNotBilledDuration(int $notBilledDuration): void
|
||||||
|
{
|
||||||
|
$this->notBilledDuration = $notBilledDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNotBilledRate(): float
|
||||||
|
{
|
||||||
|
return $this->notBilledRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNotBilledRate(float $notBilledRate): void
|
||||||
|
{
|
||||||
|
$this->notBilledRate = $notBilledRate;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRateTotal(): float
|
public function getRateTotal(): float
|
||||||
{
|
{
|
||||||
return $this->rateTotal;
|
return $this->rateTotal;
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ final class ProjectViewService
|
|||||||
|
|
||||||
$projectViews = [];
|
$projectViews = [];
|
||||||
foreach ($result as $res) {
|
foreach ($result as $res) {
|
||||||
$entity = new ProjectViewModel();
|
$entity = new ProjectViewModel($res['project']);
|
||||||
$entity->setProject($res['project']);
|
|
||||||
$entity->setDurationTotal($res['totalDuration'] ?? 0);
|
$entity->setDurationTotal($res['totalDuration'] ?? 0);
|
||||||
$entity->setRateTotal($res['totalRate'] ?? 0.00);
|
$entity->setRateTotal($res['totalRate'] ?? 0.00);
|
||||||
|
|
||||||
@@ -164,6 +163,25 @@ final class ProjectViewService
|
|||||||
$projectViews[$row['id']]->setNotExportedRate($row['rate']);
|
$projectViews[$row['id']]->setNotExportedRate($row['rate']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// values for the all time (not exported and billable)
|
||||||
|
$qb = $this->timesheetRepository->createQueryBuilder('t');
|
||||||
|
$qb
|
||||||
|
->select('IDENTITY(t.project) AS id, SUM(t.duration) AS duration, SUM(t.rate) AS rate')
|
||||||
|
->andWhere($qb->expr()->in('t.project', ':project'))
|
||||||
|
->andWhere('t.exported = :exported')
|
||||||
|
->andWhere('t.billable = :billable')
|
||||||
|
->groupBy('t.project')
|
||||||
|
->setParameter('exported', false, Types::BOOLEAN)
|
||||||
|
->setParameter('billable', true, Types::BOOLEAN)
|
||||||
|
->setParameter('project', array_values($projectIds))
|
||||||
|
;
|
||||||
|
|
||||||
|
$result = $qb->getQuery()->getScalarResult();
|
||||||
|
foreach ($result as $row) {
|
||||||
|
$projectViews[$row['id']]->setNotBilledDuration($row['duration']);
|
||||||
|
$projectViews[$row['id']]->setNotBilledRate($row['rate']);
|
||||||
|
}
|
||||||
|
|
||||||
return array_values($projectViews);
|
return array_values($projectViews);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
{% import "macros/widgets.html.twig" as widgets %}
|
{% import "macros/widgets.html.twig" as widgets %}
|
||||||
{% import "macros/datatables.html.twig" as tables %}
|
{% import "macros/datatables.html.twig" as tables %}
|
||||||
{% import "project/actions.html.twig" as projectActions %}
|
{% import "project/actions.html.twig" as projectActions %}
|
||||||
{% block box_body_class %}project-view-reporting-box {% if hasData %}no-padding{% endif %} table-responsive{% endblock %}
|
{% block box_body_class %}project-view-reporting-box {% if hasData %}no-padding{% endif %}{% endblock %}
|
||||||
{% block box_before %}
|
{% block box_before %}
|
||||||
{{ form_start(form, {'attr': {'class': 'form-inline form-reporting', 'id': 'project-view-form'}}) }}
|
{{ form_start(form, {'attr': {'class': 'form-inline form-reporting', 'id': 'project-view-form'}}) }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -52,7 +52,6 @@
|
|||||||
{{ tables.datatable_header(tableName, columns, null, {'bordered': true, 'striped': false, 'boxClass': ''}) }}
|
{{ tables.datatable_header(tableName, columns, null, {'bordered': true, 'striped': false, 'boxClass': ''}) }}
|
||||||
|
|
||||||
{% for id, mapping in entries|sort((a, b) => a.customer.name <=> b.customer.name) %}
|
{% for id, mapping in entries|sort((a, b) => a.customer.name <=> b.customer.name) %}
|
||||||
{% if is_granted('budget', mapping.customer) %}
|
|
||||||
<tr class="summary">
|
<tr class="summary">
|
||||||
<td colspan="11">{{ widgets.label_customer(mapping.customer) }}</td>
|
<td colspan="11">{{ widgets.label_customer(mapping.customer) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -60,7 +59,7 @@
|
|||||||
{% set project = entry.project %}
|
{% set project = entry.project %}
|
||||||
{% set currency = project.customer.currency %}
|
{% set currency = project.customer.currency %}
|
||||||
{% if is_granted('budget', project) %}
|
{% if is_granted('budget', project) %}
|
||||||
<tr>
|
<tr{% if is_granted('view', project) %} class="alternative-link open-edit" data-href="{{ path('project_details', {'id': project.id}) }}"{% endif %}>
|
||||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'name') }}">{{ widgets.label_project(project) }}</td>
|
<td class="{{ tables.data_table_column_class(tableName, columns, 'name') }}">{{ widgets.label_project(project) }}</td>
|
||||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'today') }}">{{ entry.durationDay|duration }}</td>
|
<td class="{{ tables.data_table_column_class(tableName, columns, 'today') }}">{{ entry.durationDay|duration }}</td>
|
||||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'week') }}">{{ entry.durationWeek|duration }}</td>
|
<td class="{{ tables.data_table_column_class(tableName, columns, 'week') }}">{{ entry.durationWeek|duration }}</td>
|
||||||
@@ -87,11 +86,11 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'stateMoney') }}">
|
<td class="{{ tables.data_table_column_class(tableName, columns, 'stateMoney') }}">
|
||||||
{% if is_granted('view_invoice') %}
|
{% if is_granted('view_invoice') %}
|
||||||
<a href="{{ path('invoice', {'customer': project.customer.id, 'projects[]': project.id, 'daterange': ''}) }}">
|
<a href="{{ path('invoice', {'customers[]': project.customer.id, 'projects[]': project.id, 'daterange': ''}) }}">
|
||||||
{{ entry.notExportedRate|money(currency) }}
|
{{ entry.notBilledRate|money(currency) }}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ entry.notExportedRate|money(currency) }}
|
{{ entry.notBilledRate|money(currency) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'projectEnd') }}">{% if project.end is not null %}{{ project.end|date_short }}{% endif %}</td>
|
<td class="{{ tables.data_table_column_class(tableName, columns, 'projectEnd') }}">{% if project.end is not null %}{{ project.end|date_short }}{% endif %}</td>
|
||||||
@@ -102,7 +101,6 @@
|
|||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ tables.data_table_footer(entries) }}
|
{{ tables.data_table_footer(entries) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ class ProjectViewModelTest extends TestCase
|
|||||||
{
|
{
|
||||||
public function testDefaults()
|
public function testDefaults()
|
||||||
{
|
{
|
||||||
$sut = new ProjectViewModel();
|
$project = new Project();
|
||||||
|
$sut = new ProjectViewModel($project);
|
||||||
|
|
||||||
self::assertNull($sut->getProject());
|
self::assertSame($project, $sut->getProject());
|
||||||
self::assertEquals(0, $sut->getDurationDay());
|
self::assertEquals(0, $sut->getDurationDay());
|
||||||
self::assertEquals(0, $sut->getDurationMonth());
|
self::assertEquals(0, $sut->getDurationMonth());
|
||||||
self::assertEquals(0, $sut->getDurationTotal());
|
self::assertEquals(0, $sut->getDurationTotal());
|
||||||
@@ -34,11 +35,7 @@ class ProjectViewModelTest extends TestCase
|
|||||||
|
|
||||||
public function testSetterGetter()
|
public function testSetterGetter()
|
||||||
{
|
{
|
||||||
$sut = new ProjectViewModel();
|
$sut = new ProjectViewModel(new Project());
|
||||||
|
|
||||||
$project = new Project();
|
|
||||||
$sut->setProject($project);
|
|
||||||
self::assertSame($project, $sut->getProject());
|
|
||||||
|
|
||||||
$sut->setDurationDay(123456789);
|
$sut->setDurationDay(123456789);
|
||||||
$sut->setDurationMonth(23456789);
|
$sut->setDurationMonth(23456789);
|
||||||
|
|||||||
Reference in New Issue
Block a user