Imp Project Status Report
This commit is contained in:
parent
fb21eefb4c
commit
e43afaac8b
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue