Project Reports

This commit is contained in:
David Bomba 2025-02-20 17:11:52 +11:00
parent c7a577d908
commit 2ab15ea8eb
3 changed files with 293 additions and 1 deletions

View File

@ -74,7 +74,8 @@ class ProjectReport extends BaseExport
'company_name' => $this->company->present()->name(),
'created_on' => $this->translateDate(now()->format('Y-m-d'), $this->company->date_format(), $this->company->locale()),
'created_by' => $user_name,
'charts' => $this->getCharts($projects),
// 'charts' => $this->getCharts($projects),
];
$ts = new TemplateService();

View File

@ -5503,6 +5503,7 @@ $lang = array(
'enable_client_profile_update_help' => 'Allow clients to update their profile information from the client portal',
'preference_product_notes_for_html_view' => 'Use Item Notes for HTML View',
'preference_product_notes_for_html_view_help' => 'Preference the item Description over the item title if displaying the invoice in HTML.',
'project_report' => 'Project Report',
);
return $lang;

View File

@ -0,0 +1,290 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Project Report</title>
<style>
@page {
size: landscape;
margin: 10mm 10mm;
}
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
margin: 0px;
}
.report-header {
border-bottom: 2px solid #2c3e50;
padding-bottom: 20px;
margin-bottom: 30px;
}
.report-header {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #2c3e50;
padding-bottom: 10mm;
margin-bottom: 5mm;
}
.header-left {
flex: 1;
}
.company-logo {
max-height: 50px;
width: auto;
object-fit: contain;
}
.report-title {
color: #2c3e50;
font-size: 14pt;
font-weight: 600;
margin: 0;
}
.report-meta {
color: #666;
margin-top: 2mm;
font-size: 8pt;
display: flex;
flex-direction: column;
/* Stack items vertically */
gap: 1mm;
/* Space between items */
}
@media print {
.company-logo {
print-color-adjust: exact;
-webkit-print-color-adjust: exact;
}
}
.report-title {
color: #2c3e50;
font-size: 24px;
font-weight: 600;
margin: 0;
}
.table-container {
margin-top: 30px;
overflow-x: auto;
}
table {
width: 100%;
border-collapse: collapse;
background: white;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
th {
background: #34495e;
color: white;
padding: 6px;
text-align: center;
}
td {
padding: 6px;
border-bottom: 1px solid #eee;
text-align: center;
}
tr {
page-break-inside: avoid;
break-inside: avoid;
}
/* Optional: Keep header with first few rows */
thead {
display: table-header-group;
}
/* Optional: Keep footer at bottom */
tfoot {
display: table-footer-group;
}
/* Ensure tbody can break between rows */
tbody {
page-break-inside: auto;
}
tr:hover {
background: #f9f9f9;
}
.amount,
.balance {
text-align: center;
font-family: monospace;
}
.status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
}
.status-sent {
background: #e8f5e9;
color: #2e7d32;
}
</style>
</head>
<body>
<ninja>
{% if projects|e %}
{% for project in projects %}
<h1>{{ project.name }}</h1>
<h3>Due: {{ project.due_date }}</h3>
<h6>{{ project.current_hours }} / {{ project.budgeted_hours }}: (Hours / Budgeted Hours @ {{ project.task_rate }}) -
Report generated on {{ "now"|date('Y-m-d') }}</h6>
<table>
<thead>
<tr>
<th>Date</th>
<th>Description</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
{% for task in project.tasks %}
{% for log in task.time_log%}
<tr>
<td>{{ log.start_date }}</td>
<td>
<div>
<ul>
<li>{{ log.description }}</li>
<li>{{ task.user.name }}</li>
</ul>
</div>
</td>
<td>{{ log.duration|date('h:i:s')}}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
{% if project.invoices %}
<table>
<thead>
<tr>
<th>{{ t('date')}}</th>
<th>{{ t('invoice_number')}}</th>
<th>{{ t('amount') }}</th>
<th>{{ t('balance') }}</th>
</tr>
</thead>
<tbody>
{% set total_amount = 0 %}
{% set total_balance = 0 %}
{% for invoice in project.invoices %}
<tr>
<td>{{ invoice.date }}</td>
<td>{{ invoice.number }}</td>
<td>{{ invoice.amount }}</td>
<td>{{ invoice.balance }}</td>
</tr>
{% set total_amount = total_amount + invoice.amount_raw %}
{% set total_balance = total_balance + invoice.balance_raw %}
{% endfor%}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td>{{ total_amount }}</td>
<td>{{ total_balance }}</td>
</tr>
</tfoot>
</table>
{% endif %}
{% if project.expenses %}
<table>
<thead>
<tr>
<th>{{ t('date')}}</th>
<th>{{ t('number')}}</th>
<th>{{ t('amount') }}</th>
</tr>
</thead>
<tbody>
{% set total_expense_amount = 0 %}
{% for expense in project.expenses %}
<tr>
<td>{{ expense.date }}</td>
<td>{{ expense.number }}</td>
<td>{{ expense.amount }}</td>
</tr>
{% set total_amount = total_amount + expense.amount_raw %}
{% endfor%}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td>{{ total_expense_amount }}</td>
</tr>
</tfoot>
</table>
{% endif %}
<table>
<thead>
<tr>
<th>Summary</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ t('expenses') }}</td>
<td>{{ total_expense_amount }}</td>
</tr>
<tr>
<td>{{ t('invoices') }}</td>
<td>{{ total_amount }}</td>
</tr>
<tr>
<td>{{ t('budgeted') }}</td>
<td>{{ project.budgeted_hours * project.task_rate_raw }}</td>
</tr>
<tr>
<td>{{ t('budgeted') }}</td>
<td>{{ project.budgeted_hours * project.task_rate_raw }}</td>
</tr>
<tr>
<td>Budget - Expenses</td>
<td>{{ (project.budgeted_hours * project.task_rate_raw) - total_expense_amount }}</td>
</tr>
<tr>
<td>Invoices - Expenses</td>
<td>{{ total_amount - total_expense_amount }}</td>
</tr>
</tbody>
</table>
{% endfor %}
{% endif %}
</ninja>
</body>
</html>