Merge pull request #2923 from expsa/kchyounes_dev_odex25_project

Imp Project Status Report
This commit is contained in:
kchyounes19 2025-04-29 09:01:31 +01:00 committed by GitHub
commit fc7e813e5b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 180 additions and 140 deletions

View File

@ -274,62 +274,64 @@
</div>
</div>
<div class="report-section">
<t t-if="e.project_phase_ids">
<div class="report-section">
<h5>
Project Stages
</h5>
<table class="table table-condensed table-bordered"
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<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">
<h5>
Project Stages
</h5>
<table class="table table-condensed table-bordered"
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<thead>
<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>
<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>
</t>
</tbody>
</table>
</div>
</thead>
<tbody>
<t t-foreach="e.project_phase_ids" t-as="phase">
<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">
<h5>
@ -371,7 +373,7 @@
<span>Additional Work Amount</span>
</td>
<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="additional_work" t-value="abs(invoiced + e.consultant_cost)"/>
@ -382,70 +384,72 @@
</tr>
<tr/>
</table>
<table class="table table-condensed table-bordered"
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<thead>
<tr>
<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">
<t t-if="e.invoice_ids">
<table class="table table-condensed table-bordered"
style="width: 100%; margin-top: 20px;page-break-inside: avoid;border: 2px solid black; border-collapse: collapse;">
<thead>
<tr>
<td style="border: 1px solid black;">
<span t-esc="invoice.name"/>
</td>
<td style="border: 1px solid black;">
<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>
<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>
</t>
</tbody>
</table>
</div>
<div class="report-section">
<h5>
Project Details
</h5>
<span t-field="e.description"/>
</thead>
<tbody>
<t t-foreach="e.invoice_ids" t-as="invoice">
<tr>
<td style="border: 1px solid black;">
<span t-esc="invoice.name"/>
</td>
<td style="border: 1px solid black;">
<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>
<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>
</t>
</t>

View File

@ -7,12 +7,11 @@ import base64
import matplotlib
# matplotlib.use('Agg')
import logging
from matplotlib import font_manager
import os
import arabic_reshaper
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__)
@ -39,12 +38,39 @@ class ReportProjectStatus(models.AbstractModel):
'doc_model': 'project.project',
'docs': projects,
'chart_map': chart_map,
'is_html_empty': is_html_empty,
}
def _get_chart_image(self, project):
_logger.info(
f"Task counts - New: {project.task_count_new}, In Progress: {project.task_count_inprogress}, Done: {project.task_count_finished}")
def get_all_fonts_paths(self):
font_extensions = ('.ttf')
# '.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 = {
'new': project.task_count_new or 0,
'in_progress': project.task_count_inprogress or 0,
@ -52,22 +78,23 @@ class ReportProjectStatus(models.AbstractModel):
}
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}
# 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))
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):
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']]
colors = ['#f0312e', '#add8e6', '#90ee90']
plt.pie(sizes, labels=labels, autopct='%1.1f%%', colors=colors, startangle=90,
textprops= {'fontsize': 16})
# {'fontproperties': prop, 'fontsize': 16} if prop else
wedges, texts, autotexts = plt.pie(
sizes,
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.rcParams['font.size'] = 18
plt.rcParams['font.size'] = 12
title_text = format_arabic('احصائيات المهام')
plt.title(title_text)
# fontproperties = prop if prop else None
plt.title(title_text, fontproperties=prop, fontsize=16) if prop else plt.title(title_text)
buffer = io.BytesIO()
plt.savefig(buffer, format='png', bbox_inches='tight', dpi=300)