Imp Project Status Report

This commit is contained in:
younes 2025-04-29 08:58:50 +01:00
parent fb21eefb4c
commit e43afaac8b
2 changed files with 180 additions and 140 deletions

View File

@ -274,62 +274,64 @@
</div> </div>
</div> </div>
<div class="report-section"> <t t-if="e.project_phase_ids">
<div class="report-section">
<h5> <h5>
Project Stages Project Stages
</h5> </h5>
<table class="table table-condensed table-bordered" <table class="table table-condensed table-bordered"
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;"> style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<thead> <thead>
<tr>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Stage</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Start Date</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">End Date</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Weight</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Completion</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Task</span>
</th>
</tr>
</thead>
<tbody>
<t t-foreach="e.project_phase_ids" t-as="phase">
<tr> <tr>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="phase.phase_id.name"/> <span style="font-weight: bold;">Stage</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="phase.start_date"/> <span style="font-weight: bold;">Start Date</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="phase.end_date"/> <span style="font-weight: bold;">End Date</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="phase.weight"/> <span style="font-weight: bold;">Weight</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span><t t-esc="phase.progress"/>% <span style="font-weight: bold;">Completion</span>
</span> </th>
</td> <th style="border: 1px solid black;">
<td style="border: 1px solid black;"> <span style="font-weight: bold;">Task</span>
<span t-esc="phase.task_count"/> </th>
</td>
</tr> </tr>
</t> </thead>
</tbody> <tbody>
</table> <t t-foreach="e.project_phase_ids" t-as="phase">
</div> <tr>
<td style="border: 1px solid black;">
<span t-esc="phase.phase_id.name"/>
</td>
<td style="border: 1px solid black;">
<span t-esc="phase.start_date"/>
</td>
<td style="border: 1px solid black;">
<span t-esc="phase.end_date"/>
</td>
<td style="border: 1px solid black;">
<span t-esc="phase.weight"/>
</td>
<td style="border: 1px solid black;">
<span><t t-esc="phase.progress"/>%
</span>
</td>
<td style="border: 1px solid black;">
<span t-esc="phase.task_count"/>
</td>
</tr>
</t>
</tbody>
</table>
</div>
</t>
<div class="report-section"> <div class="report-section">
<h5> <h5>
@ -371,7 +373,7 @@
<span>Additional Work Amount</span> <span>Additional Work Amount</span>
</td> </td>
<td style="border: 1px solid black;"> <td style="border: 1px solid black;">
<!-- <span t-esc="(e.total_invoiced_amount or 0) - (e.contract_value or 0) + (e.contract_value or 0)"/>--> <!-- <span t-esc="(e.total_invoiced_amount or 0) - (e.contract_value or 0) + (e.contract_value or 0)"/>-->
<t t-set="invoiced" t-value="e.total_invoiced_amount - e.contract_value"/> <t t-set="invoiced" t-value="e.total_invoiced_amount - e.contract_value"/>
<t t-set="additional_work" t-value="abs(invoiced + e.consultant_cost)"/> <t t-set="additional_work" t-value="abs(invoiced + e.consultant_cost)"/>
@ -382,70 +384,72 @@
</tr> </tr>
<tr/> <tr/>
</table> </table>
<table class="table table-condensed table-bordered" <t t-if="e.invoice_ids">
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;"> <table class="table table-condensed table-bordered"
<thead> style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<tr> <thead>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Payment</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Due Date</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Amount</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Tax</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Total</span>
</th>
<th style="border: 1px solid black;">
<span style="font-weight: bold;">Payment Status</span>
</th>
</tr>
</thead>
<tbody>
<t t-foreach="e.invoice_ids" t-as="invoice">
<tr> <tr>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="invoice.name"/> <span style="font-weight: bold;">Payment</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<span t-esc="invoice.plan_date"/> <span style="font-weight: bold;">Due Date</span>
</td> </th>
<td style="border: 1px solid black;"> <th style="border: 1px solid black;">
<t t-set="subtotal" t-value="0"/> <span style="font-weight: bold;">Amount</span>
<t t-foreach="invoice.project_invline_ids" t-as="line"> </th>
<t t-set="subtotal" t-value="subtotal + line.price_subtotal"/> <th style="border: 1px solid black;">
</t> <span style="font-weight: bold;">Tax</span>
<span t-esc="subtotal"/> </th>
</td> <th style="border: 1px solid black;">
<td style="border: 1px solid black;"> <span style="font-weight: bold;">Total</span>
<t t-set="tax_total" t-value="0"/> </th>
<t t-foreach="invoice.project_invline_ids" t-as="line"> <th style="border: 1px solid black;">
<t t-set="tax_total" t-value="tax_total + line.price_tax"/> <span style="font-weight: bold;">Payment Status</span>
</t> </th>
<span t-esc="tax_total"/>
</td>
<td style="border: 1px solid black;">
<span t-esc="invoice.amount"/>
</td>
<td style="border: 1px solid black;">
<span t-field="invoice.payment_state"/>
</td>
</tr> </tr>
</t> </thead>
</tbody> <tbody>
</table> <t t-foreach="e.invoice_ids" t-as="invoice">
</div> <tr>
<div class="report-section"> <td style="border: 1px solid black;">
<h5> <span t-esc="invoice.name"/>
Project Details </td>
</h5> <td style="border: 1px solid black;">
<span t-field="e.description"/> <span t-esc="invoice.plan_date"/>
</td>
<td style="border: 1px solid black;">
<t t-set="subtotal" t-value="0"/>
<t t-foreach="invoice.project_invline_ids" t-as="line">
<t t-set="subtotal" t-value="subtotal + line.price_subtotal"/>
</t>
<span t-esc="subtotal"/>
</td>
<td style="border: 1px solid black;">
<t t-set="tax_total" t-value="0"/>
<t t-foreach="invoice.project_invline_ids" t-as="line">
<t t-set="tax_total" t-value="tax_total + line.price_tax"/>
</t>
<span t-esc="tax_total"/>
</td>
<td style="border: 1px solid black;">
<span t-esc="invoice.amount"/>
</td>
<td style="border: 1px solid black;">
<span t-field="invoice.payment_state"/>
</td>
</tr>
</t>
</tbody>
</table>
</t>
</div> </div>
<t t-if="not is_html_empty(e.description)">
<div style="page-break-inside: avoid;">
<h5>Project Details</h5>
<span t-field="e.description"/>
</div>
</t>
</div> </div>
</t> </t>
</t> </t>

View File

@ -7,12 +7,11 @@ import base64
import matplotlib import matplotlib
# matplotlib.use('Agg') # matplotlib.use('Agg')
import logging import logging
from matplotlib import font_manager
import os import os
import arabic_reshaper import arabic_reshaper
from bidi.algorithm import get_display from bidi.algorithm import get_display
from odoo.modules.module import get_module_resource from odoo.tools import is_html_empty
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@ -39,12 +38,39 @@ class ReportProjectStatus(models.AbstractModel):
'doc_model': 'project.project', 'doc_model': 'project.project',
'docs': projects, 'docs': projects,
'chart_map': chart_map, 'chart_map': chart_map,
'is_html_empty': is_html_empty,
} }
def _get_chart_image(self, project): def get_all_fonts_paths(self):
_logger.info( font_extensions = ('.ttf')
f"Task counts - New: {project.task_count_new}, In Progress: {project.task_count_inprogress}, Done: {project.task_count_finished}") # '.otf', '.woff', '.woff2'
fonts_dict = {}
installed_modules = self.env['ir.module.module'].search([('state', '=', 'installed')]).mapped('name')
installed_modules_set = set(installed_modules)
from odoo.tools import config
addons_paths = config.get('addons_path', '').split(',')
for addons_path in addons_paths:
if not addons_path:
continue
addons_path = addons_path.strip()
if not os.path.exists(addons_path):
continue
for module_name in os.listdir(addons_path):
module_path = os.path.join(addons_path, module_name)
if os.path.isdir(module_path) and module_name in installed_modules_set:
for root, dirs, files in os.walk(module_path):
for file in files:
if file.lower().endswith(font_extensions):
full_path = os.path.join(root, file)
font_name = os.path.splitext(file)[0].lower() # Lowercase
fonts_dict[font_name] = full_path
return fonts_dict
def _get_chart_image(self, project):
task_data = { task_data = {
'new': project.task_count_new or 0, 'new': project.task_count_new or 0,
'in_progress': project.task_count_inprogress or 0, 'in_progress': project.task_count_inprogress or 0,
@ -52,22 +78,23 @@ class ReportProjectStatus(models.AbstractModel):
} }
if sum(task_data.values()) == 0: if sum(task_data.values()) == 0:
_logger.warning("All task counts are zero, using dummy data")
task_data = {'new': 1, 'in_progress': 1, 'done': 1} task_data = {'new': 1, 'in_progress': 1, 'done': 1}
# font_path = os.path.join(os.path.dirname(__file__), 'img', 'amiri-regular.ttf')
# if not os.path.exists(font_path):
# font_path = get_module_resource('project_base', 'static/fonts', 'amiri-regular.ttf')
# if not font_path:
# _logger.warning("Arabic font not found. Using default font.")
# font_path = None
#
# if font_path:
# prop = matplotlib.font_manager.FontProperties(fname=font_path)
# else:
# prop = None
fig = plt.figure(figsize=(5, 4)) fig = plt.figure(figsize=(5, 4))
fonts = self.get_all_fonts_paths()
prop = None
company_font_name = self.env.company.font
if company_font_name:
font_path = None
for font_name, path in fonts.items():
if font_name.startswith(company_font_name.lower()):
font_path = path
break
if font_path:
font_manager.fontManager.addfont(font_path)
prop = font_manager.FontProperties(fname=font_path)
def format_arabic(text): def format_arabic(text):
reshaped_text = arabic_reshaper.reshape(text) reshaped_text = arabic_reshaper.reshape(text)
@ -79,14 +106,23 @@ class ReportProjectStatus(models.AbstractModel):
sizes = [task_data['new'], task_data['in_progress'], task_data['done']] sizes = [task_data['new'], task_data['in_progress'], task_data['done']]
colors = ['#f0312e', '#add8e6', '#90ee90'] colors = ['#f0312e', '#add8e6', '#90ee90']
plt.pie(sizes, labels=labels, autopct='%1.1f%%', colors=colors, startangle=90, wedges, texts, autotexts = plt.pie(
textprops= {'fontsize': 16}) sizes,
# {'fontproperties': prop, 'fontsize': 16} if prop else labels=labels,
autopct='%1.1f%%',
colors=colors,
startangle=90,
textprops={'fontproperties': prop, 'fontsize': 12} if prop else {'fontsize': 12}
)
for autotext in autotexts:
autotext.set_fontsize(12)
if hasattr(autotext, 'set_fontproperties'):
autotext.set_fontproperties(None)
plt.axis('equal') plt.axis('equal')
plt.rcParams['font.size'] = 18 plt.rcParams['font.size'] = 12
title_text = format_arabic('احصائيات المهام') title_text = format_arabic('احصائيات المهام')
plt.title(title_text) plt.title(title_text, fontproperties=prop, fontsize=16) if prop else plt.title(title_text)
# fontproperties = prop if prop else None
buffer = io.BytesIO() buffer = io.BytesIO()
plt.savefig(buffer, format='png', bbox_inches='tight', dpi=300) plt.savefig(buffer, format='png', bbox_inches='tight', dpi=300)