Skip to content

Commit

Permalink
Merge pull request #1902 from VoicuStefan2001/14.0
Browse files Browse the repository at this point in the history
[14.0][UPD] deltatech_business_process
  • Loading branch information
VoicuStefan2001 authored Feb 11, 2025
2 parents 6fb6ce9 + c28cafa commit 8455b21
Show file tree
Hide file tree
Showing 13 changed files with 225 additions and 46 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ addon | version | maintainers | summary | price
[deltatech_auto_reorder_rule](deltatech_auto_reorder_rule/) | 14.0.0.0.3 | | Auto create reorder rule | Free
[deltatech_average_payment_period](deltatech_average_payment_period/) | 14.0.1.0.4 | [![dhongu](https://github.com/dhongu.png?size=30px)](https://github.com/dhongu) | Computes average duration of cash accounting | Free
[deltatech_batch_transfer](deltatech_batch_transfer/) | 14.0.0.0.2 | [![danila12](https://github.com/danila12.png?size=30px)](https://github.com/danila12) | Batch transfer improvements | Free
[deltatech_business_process](deltatech_business_process/) | 14.0.1.3.0 | [![dhongu](https://github.com/dhongu.png?size=30px)](https://github.com/dhongu) | Business process | Free
[deltatech_business_process](deltatech_business_process/) | 14.0.1.3.7 | [![dhongu](https://github.com/dhongu.png?size=30px)](https://github.com/dhongu) | Business process | Free
[deltatech_cash](deltatech_cash/) | 14.0.1.0.0 | [![dhongu](https://github.com/dhongu.png?size=30px)](https://github.com/dhongu) | Cash In / Out | Free
[deltatech_cash_statement](deltatech_cash_statement/) | 14.0.3.0.1 | [![dhongu](https://github.com/dhongu.png?size=30px)](https://github.com/dhongu) | Update cash balance | Free
[deltatech_category_group](deltatech_category_group/) | 14.0.0.0.2 | [![danila12](https://github.com/danila12.png?size=30px)](https://github.com/danila12) | Groups for internal categories | Free
Expand Down
2 changes: 1 addition & 1 deletion deltatech_business_process/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Business process
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ac5ff79483e139ab8d219ad62a3d4978cea24a785d19016d1da940bdefb63162
!! source digest: sha256:46aa3d219febd0c9ce97a7225babf101f73c16ce8d2456a3e90d985d7d457790
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
Expand Down
2 changes: 1 addition & 1 deletion deltatech_business_process/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
{
"name": "Business process",
"summary": "Business process",
"version": "14.0.1.3.0",
"version": "14.0.1.3.7",
"author": "Terrabit, Dorin Hongu",
"website": "https://www.terrabit.ro",
"license": "OPL-1",
Expand Down
20 changes: 13 additions & 7 deletions deltatech_business_process/models/business_development.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ class BusinessDevelopment(models.Model):

project_id = fields.Many2one(string="Project", comodel_name="business.project")
approved = fields.Selection(
[("draft", "Draft"), ("approved", "Approved"), ("rejected", "Rejected"), ("pending", "Pending")],
[
("draft", "Draft"),
("approved", "Approved"),
("rejected", "Rejected"),
("pending", "Pending"),
("awaiting_approval", "Awaiting Approval"),
],
string="Approved",
default="draft",
tracking=True,
Expand Down Expand Up @@ -74,13 +80,13 @@ class BusinessDevelopment(models.Model):
development_duration = fields.Float(string="Development duration")
note = fields.Html(string="Note")

@api.model
def create(self, vals):
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
result = super().create(vals)
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)

return result
return super().create(vals_list)

def write(self, vals):
result = super().write(vals)
Expand Down
24 changes: 13 additions & 11 deletions deltatech_business_process/models/business_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,21 @@ class BusinessIssue(models.Model):
string="Closed by", comodel_name="res.partner", readonly=True, states={"in_test": [("readonly", False)]}
)

@api.model
def create(self, vals):
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
result = super().create(vals)
result.send_mail()
return result
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
res = super().create(vals_list)
res.send_mail()
return res

def send_mail(self):
today = date.today().strftime("%Y-%m-%d")
self.sudo().message_post(body=f"Date of approval: {today}")
template = self.env.ref("deltatech_business_process.email_template_issue_submitted")
self.env["mail.template"].browse(template.id).send_mail(self.id, force_send=True)
for item in self:
today = date.today().strftime("%Y-%m-%d")
item.sudo().message_post(body=f"Date of approval: {today}")
template = self.env.ref("deltatech_business_process.email_template_issue_submitted")
self.env["mail.template"].browse(template.id).send_mail(item.id, force_send=True)

def name_get(self):
self.browse(self.ids).read(["name", "code"])
Expand Down
32 changes: 23 additions & 9 deletions deltatech_business_process/models/business_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ class BusinessProcess(models.Model):
states={"draft": [("readonly", False)], "design": [("readonly", False)]},
)
state = fields.Selection(
[("draft", "Draft"), ("design", "Design"), ("test", "Test"), ("ready", "Ready"), ("production", "Production")],
[
("draft", "Draft"),
("design", "Design"),
("test", "Test"),
("ready", "Ready"),
("production", "Production"),
("abandoned", "Abandoned"),
],
string="State",
default="draft",
tracking=True,
Expand Down Expand Up @@ -169,14 +176,16 @@ class BusinessProcess(models.Model):
[("standard", "Standard"), ("custom", "Custom"), ("implementor", "Implementor")], string="Module type"
)

@api.model
def create(self, vals):
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
result = super().create(vals)
if result.area_id.responsible_id and not result.responsible_id:
result.responsible_id = result.area_id.responsible_id
return result
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
results = super().create(vals_list)
for result in results:
if result.area_id.responsible_id and not result.responsible_id:
result.responsible_id = result.area_id.responsible_id
return results

def name_get(self):
self.browse(self.ids).read(["name", "code"])
Expand Down Expand Up @@ -228,6 +237,7 @@ def action_view_tests(self):
domain = [("process_id", "=", self.id)]
context = {
"default_process_id": self.id,
"default_scope": "internal",
}
action = self.env["ir.actions.actions"]._for_xml_id("deltatech_business_process.action_business_process_test")
action.update({"domain": domain, "context": context})
Expand All @@ -239,6 +249,7 @@ def action_view_acceptance_tests(self):
domain = [("process_id", "=", self.id), ("scope", "=", "user_acceptance")]
context = {
"default_process_id": self.id,
"default_scope": "user_acceptance",
}
tests = self.env["business.process.test"].search(domain)
if len(tests) == 1:
Expand Down Expand Up @@ -395,6 +406,9 @@ def button_go_live(self):
def button_draft(self):
self.write({"state": "draft"})

def button_abandon(self):
self.write({"state": "abandoned"})

def start_internal_test(self):
self._start_test("internal")

Expand Down
12 changes: 6 additions & 6 deletions deltatech_business_process/models/business_process_step.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ class BusinessProcessStep(models.Model):

details = fields.Html()

@api.model
def create(self, vals):
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
result = super().create(vals)
return result
@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
return super().create(vals_list)

def name_get(self):
self.browse(self.ids).read(["name", "code"])
Expand Down
1 change: 0 additions & 1 deletion deltatech_business_process/models/business_process_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class BusinessProcessTest(models.Model):
string="Tester",
comodel_name="res.partner",
domain="[('is_company', '=', False)]",
states={"done": [("readonly", True)]},
)
date_start = fields.Date(string="Date start", states={"done": [("readonly", True)]}, default=fields.Date.today)
date_end = fields.Date(string="Date end", states={"done": [("readonly", True)]})
Expand Down
161 changes: 155 additions & 6 deletions deltatech_business_process/models/business_project.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# © 2023 Deltatech
# See README.rst file on addons root folder for license details
import base64
import io

import xlsxwriter

from odoo import _, api, fields, models
from odoo.exceptions import UserError

# from odoo.tools import date_utils


class BusinessProject(models.Model):
Expand Down Expand Up @@ -52,12 +59,44 @@ class BusinessProject(models.Model):
)
project_type = fields.Selection([("remote", "Remote"), ("local", "Local")], string="Project Type", default="remote")

attachment_ids = fields.One2many(
"ir.attachment",
compute="_compute_attachment_ids",
string="Main Attachments",
help="Attachments that don't come from a message.",
)

@api.model
def create(self, vals):
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
result = super().create(vals)
return result
def _get_attachments_search_domain(self, model, res_ids):
return [("res_id", "in", res_ids), ("res_model", "=", model)]

def _compute_attachment_ids(self):
for project in self:
domain = project._get_attachments_search_domain(project._name, project.ids)
attachments = self.env["ir.attachment"].search(domain)
attachments |= project.mapped("message_ids.attachment_ids")
field_name = [
"process_ids",
"process_ids.step_ids",
"process_ids.test_ids",
"process_ids.development_ids",
"process_ids.step_ids.development_ids",
"process_ids.test_ids.test_step_ids",
"process_ids.test_ids.test_step_ids.issue_ids",
]
for field in field_name:
if "attachment_ids" in project.mapped(field):
attachments |= project.mapped(field).mapped("attachment_ids")
if "message_ids" in project.mapped(field):
attachments |= project.mapped(field).mapped("message_ids.attachment_ids")
project.attachment_ids = attachments

@api.model_create_multi
def create(self, vals_list):
for vals in vals_list:
if not vals.get("code", False):
vals["code"] = self.env["ir.sequence"].next_by_code(self._name)
return super().create(vals)

def name_get(self):
self.browse(self.ids).read(["name", "code"])
Expand Down Expand Up @@ -111,7 +150,7 @@ def get_attachment_domain(self):
def _compute_attached_docs_count(self):
for order in self:
domain = order.get_attachment_domain()
order.doc_count = self.env["ir.attachment"].search_count(domain)
order.doc_count = self.env["ir.attachment"].sudo().search_count(domain)

def attachment_tree_view(self):
domain = self.get_attachment_domain()
Expand Down Expand Up @@ -158,3 +197,113 @@ def calculate_total_project_duration(self):
[("project_id", "=", project.id), ("approved", "not in", ("draft", "rejected"))]
):
project.total_project_duration += development.development_duration

def float_to_time(self, float_hours):
hours = int(float_hours)
minutes = int((float_hours - hours) * 60)
if minutes % 5 != 0:
minutes = round(minutes / 5) * 5
if minutes < 10:
minutes = f"0{minutes}"
if hours < 10:
hours = f"0{hours}"
return f"{hours}:{minutes}"

def generate_excel_report(self):
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {"in_memory": True})
worksheet = workbook.add_worksheet()
header_format = workbook.add_format({"bg_color": "#D0F0C0", "bold": True})
red_text_format = workbook.add_format({"font_color": "red"})

# Add headers
headers = [
"Code",
"Name",
"Configuration Duration",
"Training duration",
"Testing duration",
"Data Migration Duration",
"Total Duration",
]
for col_num, header in enumerate(headers):
worksheet.write(0, col_num, header, header_format)
worksheet.set_column(col_num, col_num, len(header) + 2)

area_processes = {}
for process in self.process_ids:
if process.area_id:
if process.area_id not in area_processes:
area_processes[process.area_id] = []
area_processes[process.area_id].append(process)
area_format = workbook.add_format({"bg_color": "#FFFF99", "bold": True, "align": "center"})

row = 1
configuration_duration = 0
instructing_duration = 0
data_migration_duration = 0
duration_for_completion = 0
duration_for_testing = 0
for area in sorted(area_processes.keys(), key=lambda a: a.name):
processes = area_processes[area]
processes.sort(key=lambda p: p.code)
worksheet.merge_range(row, 0, row, 6, f"{area.name} - {len(processes)}", area_format)
row += 1
for process in processes:
format_to_use = red_text_format if process.duration_for_completion == 0 else None
worksheet.write(row, 0, process.code, format_to_use)
worksheet.write(row, 1, process.name, format_to_use)
worksheet.write(row, 2, self.float_to_time(process.configuration_duration), format_to_use)
configuration_duration += process.configuration_duration
worksheet.write(row, 3, self.float_to_time(process.instructing_duration), format_to_use)
instructing_duration += process.instructing_duration
worksheet.write(row, 4, self.float_to_time(process.data_migration_duration), format_to_use)
data_migration_duration += process.data_migration_duration
worksheet.write(row, 5, self.float_to_time(process.testing_duration), format_to_use)
duration_for_testing += process.testing_duration
worksheet.write(row, 6, self.float_to_time(process.duration_for_completion), format_to_use)
duration_for_completion += process.duration_for_completion
row += 1
worksheet.write(row, 1, "Total", header_format)
worksheet.write(row, 2, self.float_to_time(configuration_duration), header_format)
worksheet.write(row, 3, self.float_to_time(instructing_duration), header_format)
worksheet.write(row, 4, self.float_to_time(data_migration_duration), header_format)
worksheet.write(row, 5, self.float_to_time(duration_for_testing), header_format)
worksheet.write(row, 6, self.float_to_time(duration_for_completion), header_format)
# for project in self:
# worksheet.write(row, 0, project.code)
# worksheet.write(row, 1, project.name)
# worksheet.write(row, 2, project.customer_id.name)
# worksheet.write(row, 3, project.state)
# worksheet.write(row, 4, project.date_start and project.date_start.strftime('%Y-%m-%d') or '')
# worksheet.write(row, 5, project.date_go_live and project.date_go_live.strftime('%Y-%m-%d') or '')
# row += 1
# worksheet.autofit()

workbook.close()
output.seek(0)
return output.read()

def action_download_excel_report(self):
active_id = self.env.context.get("active_id")
if not active_id:
raise UserError(_("No active project found."))

project = self.browse(active_id)
excel_data = project.generate_excel_report()

attachment = self.env["ir.attachment"].create(
{
"name": "Project_Report.xlsx",
"type": "binary",
"datas": base64.b64encode(excel_data),
"store_fname": "Project_Report.xlsx",
"mimetype": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
}
)

return {
"type": "ir.actions.act_url",
"url": f"/web/content/{attachment.id}?download=true",
"target": "self",
}
2 changes: 1 addition & 1 deletion deltatech_business_process/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ <h1 class="title">Business process</h1>
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:ac5ff79483e139ab8d219ad62a3d4978cea24a785d19016d1da940bdefb63162
!! source digest: sha256:46aa3d219febd0c9ce97a7225babf101f73c16ce8d2456a3e90d985d7d457790
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="https://www.odoo.com/documentation/master/legal/licenses.html"><img alt="License: OPL-1" src="https://img.shields.io/badge/licence-OPL--1-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/dhongu/deltatech/tree/14.0/deltatech_business_process"><img alt="dhongu/deltatech" src="https://img.shields.io/badge/github-dhongu%2Fdeltatech-lightgray.png?logo=github" /></a></p>
<dl class="docutils">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
widget="badge"
decoration-danger="approved == 'rejected' "
decoration-success="approved == 'approved' "
decoration-warning="approved == 'awaiting_approval' "
/>
<field name="state" widget="badge" />
<field name="state" widget="badge" />
<field name="responsible_id" optional="show" />
<field name="date_start_fs" optional="show" />
<field name="date_end_fs" optional="show" />
Expand Down
Loading

0 comments on commit 8455b21

Please sign in to comment.