Files
odoo-addons/addons/tk_construction_management/models/construction_project.py

847 lines
39 KiB
Python

# -*- coding: utf-8 -*-
# Copyright 2020-Today TechKhedut.
# Part of TechKhedut. See LICENSE file for full copyright and licensing details.
import xlwt
import base64
from io import BytesIO
from odoo import fields, api, models, _
from odoo.exceptions import UserError, ValidationError
class ConstructionProject(models.Model):
_name = 'tk.construction.project'
_description = "Construction Project"
_inherit = ['mail.thread', 'mail.activity.mixin']
name = fields.Char(string="Title", tracking=True)
start_date = fields.Date(string="Schedule Start Date", tracking=True)
end_date = fields.Date(string="Schedule End Date", tracking=True)
project_progress = fields.Float(
related="budget_id.progress", string="Project Progress", tracking=True)
construction_site_id = fields.Many2one(
'tk.construction.site', string="Project ", tracking=True)
responsible_id = fields.Many2one('res.users', default=lambda self: self.env.user and self.env.user.id or False,
string="Created By")
stage = fields.Selection([('draft', 'Draft'),
('Planning', 'Planning'),
('Procurement', 'Procurement'),
('Construction', 'Construction'),
('Handover', 'Handover')], string="Stage", default="draft", tracking=True)
warehouse_id = fields.Many2one(
'stock.warehouse', string="Warehouse", tracking=True)
code = fields.Char(string="Code", tracking=True)
project_id = fields.Many2one(
'project.project', string="Project", tracking=True)
engineer_ids = fields.Many2many(
'hr.employee', string="Engineers", tracking=True)
# Department
department_id = fields.Many2one(
'construction.department', string="Department", tracking=True)
manager_ids = fields.Many2many('res.users', string="Manager")
user_id = fields.Many2one('res.users', string="Responsible")
# Address
zip = fields.Char(string='Pin Code')
street = fields.Char(string='Street1')
street2 = fields.Char(string='Street2')
city = fields.Char(string='City')
country_id = fields.Many2one('res.country', 'Country')
state_id = fields.Many2one(
"res.country.state", string='State', readonly=False, store=True,
domain="[('country_id', '=?', country_id)]")
longitude = fields.Char(string="Longitude")
latitude = fields.Char(string="Latitude")
# BOQ Details
is_use_measure = fields.Boolean(
string="Is use of (LENGTH x WIDTH x HEIGHT ) ?")
boq_budget_ids = fields.One2many(
'boq.budget', 'project_id', string="Budget ")
# Budget
budget_id = fields.Many2one('sub.project.budget', string="Budget")
# One2Many
document_ids = fields.One2many(
'project.documents', 'project_id', string="Documents")
policy_ids = fields.One2many(
'project.insurance', 'project_id', string="Insurance")
expense_ids = fields.One2many(
'extra.expense', 'project_id', string="Expense")
phase_ids = fields.One2many('job.costing', 'project_id')
# Count & Totals
job_sheet_count = fields.Integer(
string="Project Phase Count", compute="_compute_count")
job_order_count = fields.Integer(
string="Work Order Count", compute="_compute_count")
mrq_count = fields.Integer(string="MRQ Count", compute="_compute_count")
mrq_po_count = fields.Integer(
string="MRQ PO Count", compute="_compute_count")
jo_po_count = fields.Integer(
string="JO PO Count", compute="_compute_count")
inspection_task_count = fields.Integer(
string="Inspection Task Count", compute="_compute_count")
task_count = fields.Integer(string="Task Count", compute="_compute_count")
budget_count = fields.Integer(
string="Budget Count", compute="_compute_count")
# Create, Write, Unlink, Constrain
@api.model_create_multi
def create(self, vals):
res = super(ConstructionProject, self).create(vals)
for rec in res:
data = {
'name': rec.name + "'s Project",
'construction_project_id': rec.id,
'company_id': self.env.company.id,
'privacy_visibility': 'followers'
}
project_id = self.env['project.project'].create(data)
rec.project_id = project_id.id
task_stage = self.env['project.task.type'].sudo().search(
[('active', '=', True), ('user_id', '=', False)])
ids = []
for data in task_stage:
ids = data.project_ids.ids
ids.append(project_id.id)
data.project_ids = ids
return res
@api.constrains('boq_budget_ids')
def _check_sub_activity(self):
for rec in self:
activity_counts = {}
for activity in rec.boq_budget_ids:
key = (activity.activity_id.id, activity.sub_activity_id.id)
if key in activity_counts:
activity_counts[key] += 1
else:
activity_counts[key] = 1
duplicate = [pair for pair,
count in activity_counts.items() if count > 1]
if duplicate:
raise ValidationError(
"Duplicate work type and sub work type pair found.")
@api.onchange('construction_site_id')
def onchange_site_address(self):
for rec in self:
if rec.construction_site_id:
rec.zip = rec.construction_site_id.zip
rec.street = rec.construction_site_id.street
rec.street2 = rec.construction_site_id.street2
rec.city = rec.construction_site_id.city
rec.state_id = rec.construction_site_id.state_id.id
rec.country_id = rec.construction_site_id.country_id.id
rec.start_date = rec.construction_site_id.start_date
rec.end_date = rec.construction_site_id.end_date
# Compute
def _compute_count(self):
for rec in self:
rec.job_sheet_count = self.env['job.costing'].search_count(
[('project_id', '=', rec.id)])
rec.job_order_count = self.env['job.order'].search_count(
[('project_id', '=', rec.id)])
rec.mrq_count = self.env['material.requisition'].search_count(
[('project_id', '=', rec.id)])
rec.mrq_po_count = self.env['purchase.order'].search_count(
[('project_id', '=', rec.id)])
job_order_ids = self.env['job.order'].search(
[('project_id', '=', self.id)]).mapped('id')
po_ids = self.env['purchase.order'].search(
[('job_order_id', 'in', job_order_ids)]).mapped('id')
rec.jo_po_count = len(po_ids)
rec.task_count = self.env['project.task'].search_count(
[('con_project_id', '=', rec.id), ('is_inspection_task', '=', False)])
rec.inspection_task_count = self.env['project.task'].search_count(
[('con_project_id', '=', rec.id), ('is_inspection_task', '=', True)])
rec.budget_count = self.env['project.budget'].search_count(
[('sub_project_budget_id', '=', rec.budget_id.id)])
# Onchange
@api.onchange('department_id', 'manager_ids')
def _onchange_department_manager(self):
ids = []
for rec in self:
if rec.department_id:
ids = rec.department_id.manager_ids.ids
return {'domain': {'manager_ids': [('id', 'in', ids)]}}
@api.onchange('department_id', 'manager_ids', 'user_id')
def _onchange_department_responsible(self):
ids = []
for rec in self:
if rec.department_id:
ids = rec.department_id.user_ids.ids
return {'domain': {'user_id': [('id', 'in', ids)]}}
# Smart Button
def action_gmap_location(self):
if self.longitude and self.latitude:
longitude = self.longitude
latitude = self.latitude
http_url = 'https://maps.google.com/maps?q=loc:' + latitude + ',' + longitude
return {
'type': 'ir.actions.act_url',
'target': 'new',
'url': http_url,
}
else:
raise ValidationError(
_("! Enter Proper Longitude and Latitude Values"))
def action_view_job_sheet(self):
return {
'type': 'ir.actions.act_window',
'name': _('Project Phase(WBS)'),
'res_model': 'job.costing',
'domain': [('project_id', '=', self.id)],
'context': {'default_project_id': self.id},
'view_mode': 'tree,form',
'target': 'current'
}
def action_view_job_order(self):
return {
'type': 'ir.actions.act_window',
'name': _('Work Order'),
'res_model': 'job.order',
'domain': [('project_id', '=', self.id)],
'context': {'default_project_id': self.id},
'view_mode': 'tree,form',
'target': 'current'
}
def action_view_material_requisition(self):
return {
'type': 'ir.actions.act_window',
'name': _('Material Requisition'),
'res_model': 'material.requisition',
'domain': [('project_id', '=', self.id)],
'context': {'default_project_id': self.id},
'view_mode': 'tree,form',
'target': 'current'
}
def action_view_mrq_purchase_orders(self):
ids = self.env['purchase.order'].search(
[('project_id', '=', self.id)]).mapped('id')
return {
'type': 'ir.actions.act_window',
'name': _('MRQ Purchase Order'),
'res_model': 'purchase.order',
'domain': [('id', 'in', ids)],
'context': {'create': False},
'view_mode': 'tree,form',
'target': 'current'
}
def action_view_jo_purchase_orders(self):
job_order_ids = self.env['job.order'].search(
[('project_id', '=', self.id)]).mapped('id')
po_ids = self.env['purchase.order'].search(
[('job_order_id', 'in', job_order_ids)]).mapped('id')
return {
'type': 'ir.actions.act_window',
'name': _('Work Order PO'),
'res_model': 'purchase.order',
'domain': [('id', 'in', po_ids)],
'context': {'create': False, 'group_by': 'purchase_order'},
'view_mode': 'tree,form',
'target': 'current'
}
def action_view_project_task(self):
return {
'type': 'ir.actions.act_window',
'name': _('Task'),
'res_model': 'project.task',
'domain': [('con_project_id', '=', self.id), ('is_inspection_task', '=', False)],
'context': {'default_con_project_id': self.id, 'default_project_id': self.project_id.id},
'view_mode': 'kanban,tree,form',
'target': 'current'
}
def action_view_project_task_inspection(self):
return {
'type': 'ir.actions.act_window',
'name': _('Inspection Task'),
'res_model': 'project.task',
'domain': [('con_project_id', '=', self.id), ('is_inspection_task', '=', True)],
'context': {'default_con_project_id': self.id, 'default_project_id': self.project_id.id,
'default_is_inspection_task': True, 'default_priority': '1'},
'view_mode': 'tree,form,kanban',
'target': 'current'
}
def action_view_budget(self):
return {
'type': 'ir.actions.act_window',
'name': _('Budget'),
'res_model': 'project.budget',
'domain': [('sub_project_budget_id', '=', self.budget_id.id)],
'context': {'default_sub_project_budget_id': self.budget_id.id},
'view_mode': 'tree,kanban,form',
'target': 'current'
}
# Button
def action_project_planning(self):
self.stage = 'Planning'
def action_stage_procurement(self):
if not self.warehouse_id:
message = {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'info',
'message': "Please choose a warehouse to proceed to the next stage of construction process",
'sticky': False,
}
}
return message
if not self.budget_id:
message = {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'info',
'message': "Please create a budget to proceed to the next stage of construction process",
'sticky': False,
}
}
return message
self.stage = 'Procurement'
def action_stage_construction(self):
self.stage = 'Construction'
def action_stage_handover(self):
phase_completed = True
phase_record = self.env['job.costing'].search(
[('project_id', '=', self.id)])
for data in phase_record:
if data.status != 'complete':
phase_completed = False
break
if not phase_completed:
message = {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'type': 'info',
'message': "Please complete all the phases related to this project to handover this project.",
'sticky': False,
}
}
return message
self.stage = 'Handover'
def get_float_time(self, t):
hour, minute = divmod(t, 1)
minute *= 60
result = '{}:{}'.format(int(hour), int(minute))
return result
def action_print_budget_excel_report(self):
workbook = xlwt.Workbook(encoding='utf-8')
sheet1 = workbook.add_sheet('Budget Details', cell_overwrite_ok=True)
sheet1.show_grid = False
sheet1.col(0).width = 400
sheet1.col(3).width = 600
sheet1.col(9).width = 600
sheet1.row(4).height = 400
sheet1.row(5).height = 200
sheet1.row(6).height = 400
sheet1.row(7).height = 200
sheet1.row(8).height = 400
sheet1.row(9).height = 200
sheet1.row(10).height = 400
sheet1.row(11).height = 200
sheet1.row(12).height = 400
sheet1.row(17).height = 400
sheet1.col(12).width = 5000
sheet1.col(13).width = 4000
sheet1.col(14).width = 5000
sheet1.col(15).width = 5000
sheet1.col(16).width = 8000
sheet1.col(17).width = 7000
sheet1.col(18).width = 7000
sheet1.col(19).width = 7000
sheet1.col(20).width = 7000
sheet1.col(21).width = 7000
sheet1.col(22).width = 5000
sheet1.row(14).height = 600
border_squre = xlwt.Borders()
border_squre.bottom = xlwt.Borders.HAIR
border_squre.bottom_colour = xlwt.Style.colour_map["sea_green"]
al = xlwt.Alignment()
al.horz = xlwt.Alignment.HORZ_LEFT
al.vert = xlwt.Alignment.VERT_CENTER
date_format = xlwt.XFStyle()
date_format.num_format_str = 'mm/dd/yyyy'
date_format.font.name = "Century Gothic"
date_format.borders = border_squre
date_format.alignment = al
date_format.font.colour_index = 0x36
date_format.font.bold = 1
sheet1.set_panes_frozen(True)
sheet1.set_horz_split_pos(18)
sheet1.remove_splits = True
title = xlwt.easyxf(
"font: height 350, name Century Gothic, bold on, color_index blue_gray;"
" align: vert center, horz center;"
"border: bottom thick, bottom_color sea_green;")
values = xlwt.easyxf(
"font:name Century Gothic, bold on, color_index blue_gray;"
" align: vert center, horz left;"
"border: bottom hair, bottom_color sea_green;")
line_percentage_value = xlwt.easyxf(
"font:name Century Gothic, bold on, color_index blue_gray;"
" align: vert center, horz center;"
"border: bottom hair, bottom_color blue_gray, right hair,right_color blue_gray;")
line_values = xlwt.easyxf(
"font:name Century Gothic;"
" align: vert center, horz center;"
"border: bottom hair, bottom_color blue_gray, right hair,right_color blue_gray,left hair,left_color blue_gray;")
line_amount_values = xlwt.easyxf(
"font:name Century Gothic;"
" align: vert center, horz right;"
"border: bottom hair, bottom_color blue_gray, right hair,right_color blue_gray,left hair,left_color blue_gray;")
line_amount_sub_title = xlwt.easyxf(
"font: height 185, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz right; "
"border: top hair, bottom hair, left hair, right hair, "
"top_color gray50, bottom_color gray50, left_color gray50, right_color gray50")
sub_title = xlwt.easyxf(
"font: height 185, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz center; "
"border: top hair, bottom hair, left hair, right hair, "
"top_color gray50, bottom_color gray50, left_color gray50, right_color gray50")
# Budget Details
budget_amount = str(self.budget_id.currency_id.symbol) + \
" "+str(self.budget_id.total_budget_amount)
utilization_amount = str(self.budget_id.currency_id.symbol) + " " + str(
self.budget_id.utilization_amount)
utilization_percentage = str(self.budget_id.progress) + " %"
sheet1.write_merge(0, 2, 1, 11, "Budget Details", title)
sheet1.write_merge(4, 4, 1, 2, "Project", sub_title)
sheet1.write_merge(4, 4, 4, 5, self.construction_site_id.name, values)
sheet1.write_merge(6, 6, 1, 2, "Sub Project", sub_title)
sheet1.write_merge(6, 6, 4, 5, self.name, values)
sheet1.write_merge(4, 4, 7, 8, "Start Date", sub_title)
sheet1.write_merge(
4, 4, 10, 11, self.budget_id.start_date, date_format)
sheet1.write_merge(6, 6, 7, 8, "End Date", sub_title)
sheet1.write_merge(6, 6, 10, 11, self.budget_id.end_date, date_format)
sheet1.write_merge(8, 8, 1, 2, "Total Budget Amount", sub_title)
sheet1.write_merge(8, 8, 4, 5, budget_amount, values)
sheet1.write_merge(10, 10, 1, 2, "Budget Utilization", sub_title)
sheet1.write_merge(10, 10, 4, 5, utilization_amount, values)
sheet1.write_merge(12, 12, 1, 2, "Utilization(%)", sub_title)
sheet1.write_merge(12, 12, 4, 5, utilization_percentage, values)
# Budget Lines
sheet1.write_merge(14, 15, 1, 22, "Budget Lines", title)
sheet1.write_merge(17, 17, 1, 3, "Work Type", sub_title)
sheet1.write_merge(17, 17, 4, 6, "Work Sub Type", sub_title)
sheet1.write(17, 7, "BOQ Qty", line_amount_sub_title)
sheet1.write_merge(17, 17, 8, 10, "Additional Qty",
line_amount_sub_title)
sheet1.write(17, 11, "Total Qty", line_amount_sub_title)
sheet1.write(17, 12, "Rate Analysis", sub_title)
sheet1.write(17, 13, "Price / Qty", line_amount_sub_title)
sheet1.write(17, 14, "Untaxed", line_amount_sub_title)
sheet1.write(17, 15, "Tax Amount", line_amount_sub_title)
sheet1.write(17, 16, "Total Budget", line_amount_sub_title)
sheet1.write(17, 17, "Material Spent", line_amount_sub_title)
sheet1.write(17, 18, "Equipment Spent", line_amount_sub_title)
sheet1.write(17, 19, "Labour Spent", line_amount_sub_title)
sheet1.write(17, 20, "Overhead Spent", line_amount_sub_title)
sheet1.write(17, 21, "Remaining Budget", line_amount_sub_title)
sheet1.write(17, 22, "Utilization(%)", sub_title)
col = 18
for data in self.budget_id.budget_line_ids:
sheet1.row(col).height = 400
sheet1.write_merge(
col, col, 1, 3, data.job_type_id.name, line_values)
sheet1.write_merge(
col, col, 4, 6, data.sub_category_id.name, line_values)
sheet1.write(col, 7, data.boq_qty, line_amount_values)
sheet1.write_merge(
col, col, 8, 10, data.additional_qty, line_amount_values)
sheet1.write(col, 11, (data.boq_qty +
data.additional_qty), line_amount_values)
sheet1.write(col, 12, ((data.rate_analysis_id.name)
if data.rate_analysis_id else ""), line_values)
sheet1.write(col, 13, (str(self.budget_id.currency_id.symbol) +
" " + str(data.price_per_qty)), line_amount_values)
sheet1.write(col, 14, (str(self.budget_id.currency_id.symbol) +
" " + str(data.untaxed_amount)), line_amount_values)
sheet1.write(col, 15, (str(self.budget_id.currency_id.symbol) +
" " + str(data.tax_amount)), line_amount_values)
sheet1.write(col, 16, (str(self.budget_id.currency_id.symbol) +
" " + str(data.budget)), line_amount_values)
sheet1.write(col, 17, (str(self.budget_id.currency_id.symbol) +
" " + str(data.material_spent)), line_amount_values)
sheet1.write(col, 18, (str(self.budget_id.currency_id.symbol) +
" " + str(data.equipment_spent)), line_amount_values)
sheet1.write(col, 19, (str(self.budget_id.currency_id.symbol) +
" " + str(data.labour_spent)), line_amount_values)
sheet1.write(col, 20, (str(self.budget_id.currency_id.symbol) +
" " + str(data.overhead_spent)), line_amount_values)
sheet1.write(col, 21, (str(self.budget_id.currency_id.symbol) +
" " + str(data.remaining_budget)), line_amount_values)
sheet1.write(
col, 22, (str(data.total_spent) + " " + "%"), line_percentage_value)
col = col + 1
# Budget Spent
self.get_budget_spent(workbook=workbook)
# Print Report
stream = BytesIO()
workbook.save(stream)
out = base64.encodebytes(stream.getvalue())
attachment = self.env['ir.attachment'].sudo()
filename = 'Budget Report' + ".xls"
attachment_id = attachment.create(
{'name': filename,
'type': 'binary',
'public': False,
'datas': out})
if attachment_id:
report = {
'type': 'ir.actions.act_url',
'url': '/web/content/%s?download=true' % (attachment_id.id),
'target': 'self',
}
return report
def get_budget_spent(self, workbook):
title = xlwt.easyxf(
"font: height 300, name Century Gothic, bold on, color_index blue_gray;"
" align: vert center, horz center;"
"border: bottom thick, bottom_color sea_green;")
title2 = xlwt.easyxf(
"font: height 250, name Century Gothic, bold on, color_index blue_gray;"
" align: vert center, horz left;"
"border: bottom thin, bottom_color sea_green;")
title3 = xlwt.easyxf(
"font: height 250, name Century Gothic, bold on;"
" align: vert center, horz right;"
"border: bottom thin, bottom_color sea_green;")
line_amount_sub_title = xlwt.easyxf(
"font: height 185, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz right; "
"border: top hair, bottom hair, left hair, right hair, "
"top_color gray50, bottom_color gray50, left_color gray50, right_color gray50")
line_values = xlwt.easyxf(
"font:name Century Gothic;"
" align: vert center, horz center;"
"border: bottom hair, bottom_color blue_gray, right hair,right_color blue_gray,left hair,left_color blue_gray;")
sub_title = xlwt.easyxf(
"font: height 185, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz center; "
"border: top hair, bottom hair, left hair, right hair, "
"top_color gray50, bottom_color gray50, left_color gray50, right_color gray50")
sub_title2 = xlwt.easyxf(
"font: height 200, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz left; "
"border: bottom hair,"
"bottom_color sea_green;")
sub_title_amount = xlwt.easyxf(
"font: height 200, name Century Gothic, bold on, color_index gray80; "
"align: vert center, horz right; "
"border: bottom hair,"
"bottom_color sea_green;")
horiz_double_line = xlwt.easyxf("border: top double, top_color gray50")
for data in self.budget_id.budget_line_ids:
budget_phase_ids = self.env['job.costing'].search(
[('project_id', '=', self.id), ('activity_id', '=', data.job_type_id.id)]).mapped('id')
domain = [('project_id', '=', self.id), ('work_type_id', '=', data.job_type_id.id),
('sub_category_id', '=',
data.sub_category_id.id), ('state', '=', 'complete'),
('job_sheet_id', 'in', budget_phase_ids)]
material_spent_rec = self.env['order.material.line'].search(domain)
equip_spent_rec = self.env['order.equipment.line'].search(domain)
labour_spent_rec = self.env['order.labour.line'].search(domain)
overhead_spent_rec = self.env['order.overhead.line'].search(domain)
sheet_name = data.job_type_id.name + \
"(" + data.sub_category_id.name + ")"
sheet = workbook.add_sheet(sheet_name, cell_overwrite_ok=True)
sheet.show_grid = False
row = 0
sheet.row(4).height = 400
sheet.row(6).height = 400
sheet.write_merge(0, 2, 0, 6, sheet_name, title)
sheet.write(4, 0, "Total Budget", sub_title2)
sheet.write(4, 1, (str(self.budget_id.currency_id.symbol) +
" " + str(data.budget)), sub_title_amount)
sheet.write_merge(4, 4, 3, 4, "Used Budget Amount", sub_title2)
sheet.write_merge(4, 4, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str((data.budget - data.remaining_budget))), sub_title_amount)
sheet.write_merge(6, 6, 3, 4, "Remaining Budget", sub_title2)
sheet.write_merge(6, 6, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(data.remaining_budget)), sub_title_amount)
row = 5
# Material Rec
sheet.write_merge(row+4, row+5, 0, 4, "Material Spent", title2)
sheet.write_merge(row+4, row+5, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(data.material_spent)), title3)
sheet.col(0).width = 8000
sheet.col(1).width = 8000
sheet.col(2).width = 6500
sheet.col(3).width = 5000
sheet.col(4).width = 5000
sheet.col(5).width = 5000
sheet.col(6).width = 5000
sheet.row(row+6).height = 600
sheet.write(row+6, 0, "Project Phase(WBS)", sub_title)
sheet.write(row+6, 1, "Work Order", sub_title)
sheet.write(row+6, 2, "Material", sub_title)
sheet.write(row+6, 3, "Qty.", line_amount_sub_title)
sheet.write(row+6, 4, "Unit", sub_title)
sheet.write(row+6, 5, "Price/Qty", line_amount_sub_title)
sheet.write(row+6, 6, "Total Price", line_amount_sub_title)
row = row + 7
for rec in material_spent_rec:
sheet.row(row).height = 400
sheet.write(row, 0, (rec.job_sheet_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 1, (rec.job_order_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 2, rec.name, line_values)
sheet.write(row, 3, rec.qty, line_amount_sub_title)
sheet.write(row, 4, rec.uom_id.name, line_values)
sheet.write(row, 5, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.price)), line_amount_sub_title)
sheet.write(row, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.total_price)), line_amount_sub_title)
row = row + 1
sheet.write_merge(row, row, 0, 6, " ", horiz_double_line)
row = row + 1
# Equipment Rec
sheet.write_merge(row+1, row+2, 0, 4, "Equipment Spent", title2)
sheet.write_merge(row+1, row+2, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(data.equipment_spent)), title3)
row = row + 3
sheet.row(row).height = 600
sheet.write(row, 0, "Project Phase(WBS)", sub_title)
sheet.write(row, 1, "Work Order", sub_title)
sheet.write(row, 2, "Vendor", sub_title)
sheet.write(row, 3, "Equipment.", sub_title)
sheet.write(row, 4, "Qty.", line_amount_sub_title)
sheet.write(row, 5, "Price/Qty", line_amount_sub_title)
sheet.write(row, 6, "Total Price", line_amount_sub_title)
row = row+1
for rec in equip_spent_rec:
sheet.row(row).height = 400
sheet.write(row, 0, (rec.job_sheet_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 1, (rec.job_order_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 2, rec.vendor_id.name, line_values)
sheet.write(row, 3, rec.desc, line_values)
sheet.write(row, 4, rec.qty, line_amount_sub_title)
sheet.write(row, 5, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.cost)), line_amount_sub_title)
sheet.write(row, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.total_cost)), line_amount_sub_title)
row = row + 1
sheet.write_merge(row, row, 0, 6, " ", horiz_double_line)
row = row + 1
# Labour Rec
sheet.write_merge(row+1, row+2, 0, 4, "Labour Spent", title2)
sheet.write_merge(row+1, row+2, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(data.labour_spent)), title3)
row = row + 3
sheet.row(row).height = 600
sheet.write(row, 0, "Project Phase(WBS)", sub_title)
sheet.write(row, 1, "Work Order", sub_title)
sheet.write(row, 2, "Vendor", sub_title)
sheet.write(row, 3, "Product", sub_title)
sheet.write(row, 4, "Hours", line_amount_sub_title)
sheet.write(row, 5, "Cost / Hour", line_amount_sub_title)
sheet.write(row, 6, "Sub Total", line_amount_sub_title)
row = row+1
for rec in labour_spent_rec:
sheet.row(row).height = 400
sheet.write(row, 0, (rec.job_sheet_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 1, (rec.job_order_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 2, rec.vendor_id.name, line_values)
sheet.write(row, 3, rec.name, line_values)
sheet.write(row, 4, rec.hours, line_amount_sub_title)
sheet.write(row, 5, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.cost)), line_amount_sub_title)
sheet.write(row, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.sub_total)), line_amount_sub_title)
row = row + 1
sheet.write_merge(row, row, 0, 6, " ", horiz_double_line)
row = row + 1
# Overhead Rec
sheet.write_merge(row+1, row+2, 0, 4, "Overhead Spent", title2)
sheet.write_merge(row+1, row+2, 5, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(data.overhead_spent)), title3)
row = row + 3
sheet.row(row).height = 600
sheet.write(row, 0, "Project Phase(WBS)", sub_title)
sheet.write(row, 1, "Work Order", sub_title)
sheet.write(row, 2, "Vendor", sub_title)
sheet.write(row, 3, "Product", sub_title)
sheet.write(row, 4, "Qty.", line_amount_sub_title)
sheet.write(row, 5, "Cost / Qty", line_amount_sub_title)
sheet.write(row, 6, "Sub Total", line_amount_sub_title)
row = row+1
for rec in overhead_spent_rec:
sheet.row(row).height = 400
sheet.write(row, 0, (rec.job_sheet_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 1, (rec.job_order_id.name +
" - " + rec.job_order_id.name), line_values)
sheet.write(row, 2, rec.vendor_id.name, line_values)
sheet.write(row, 3, rec.name, line_values)
sheet.write(row, 4, rec.qty, line_amount_sub_title)
sheet.write(row, 5, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.cost)), line_amount_sub_title)
sheet.write(row, 6, (str(self.budget_id.currency_id.symbol) +
" " + str(rec.sub_total)), line_amount_sub_title)
row = row + 1
sheet.write_merge(row, row, 0, 6, " ", horiz_double_line)
row = row + 1
class ProjectDocuments(models.Model):
_name = 'project.documents'
_description = "Project Documents"
_rec_name = 'file_name'
document_type_id = fields.Many2one('site.document.type', string="Document")
document = fields.Binary(string='Documents', required=True)
file_name = fields.Char(string='File Name')
project_id = fields.Many2one('tk.construction.project')
class ProjectInsurance(models.Model):
_name = 'project.insurance'
_description = "Project Insurance"
name = fields.Char(string="Insurance")
policy_no = fields.Char(string="Insurance No")
risk_ids = fields.Many2many('insurance.risk', string="Risk Covered")
document = fields.Binary(string='Documents')
file_name = fields.Char(string='File Name')
project_id = fields.Many2one('tk.construction.project')
company_id = fields.Many2one(
'res.company', string="Company", default=lambda self: self.env.company)
currency_id = fields.Many2one(
'res.currency', related='company_id.currency_id', string='Currency')
total_charge = fields.Monetary(string="Total Charge")
issue_date = fields.Date(string="Issue Date", default=fields.Date.today())
bill_id = fields.Many2one('account.move', string="Bill")
vendor_id = fields.Many2one('res.partner', string="Vendor")
def action_create_bil(self):
record = {
'product_id': self.env.ref('tk_construction_management.construction_product_1').id,
'name': self.project_id.name + "\n" + "Name : " + self.name + "\n" + "No : " + self.policy_no,
'quantity': 1,
'tax_ids': False,
'price_unit': self.total_charge
}
line = [(0, 0, record)]
main_data = {
'partner_id': self.vendor_id.id,
'move_type': 'in_invoice',
'invoice_date': fields.date.today(),
'invoice_line_ids': line,
}
bill_id = self.env['account.move'].create(main_data)
self.bill_id = bill_id.id
class ConstructionExtraExpense(models.Model):
_name = 'extra.expense'
_description = "Extra Expense"
product_id = fields.Many2one(
'product.product', string="Expense", domain="[('is_expense','=',True)]")
date = fields.Date(string="Date", default=fields.Date.today())
company_id = fields.Many2one(
'res.company', string="Company", default=lambda self: self.env.company)
currency_id = fields.Many2one(
'res.currency', related='company_id.currency_id', string='Currency')
cost = fields.Monetary(string="Cost")
bill_id = fields.Many2one('account.move', string="Bill")
note = fields.Char(string="Note")
project_id = fields.Many2one('tk.construction.project', string="Project")
qty = fields.Integer(string="Qty.", default=1)
vendor_id = fields.Many2one('res.partner', string="Vendor")
@api.onchange('product_id')
def onchange_expense_cost(self):
for rec in self:
rec.cost = rec.product_id.standard_price
def action_create_expense_bill(self):
if self.vendor_id and self.product_id:
data = {
'product_id': self.product_id.id,
'name': (self.product_id.name + " " + self.note) if self.note else self.product_id.name,
'quantity': self.qty,
'tax_ids': False,
'price_unit': self.cost
}
invoice_line = [(0, 0, data)]
invoice_id = self.env['account.move'].create({
'partner_id': self.vendor_id.id,
'invoice_line_ids': invoice_line,
'move_type': 'in_invoice',
})
self.bill_id = invoice_id.id
class BoqBudget(models.Model):
_name = 'boq.budget'
_description = "Boq Budget"
_rec_name = 'activity_id'
project_id = fields.Many2one(
'tk.construction.project', string="Sub Project")
site_id = fields.Many2one(
related="project_id.construction_site_id", string="Project")
activity_id = fields.Many2one('job.type', string="Work Type")
sub_activity_ids = fields.Many2many(
related="activity_id.sub_category_ids", string="Sub Activities")
sub_activity_id = fields.Many2one('job.sub.category', string="Work Sub Type",
domain="[('id','in',sub_activity_ids)]")
qty = fields.Float(string="Qty.", default=1.0)
total_qty = fields.Float(
string="Total Qty.", compute="compute_total_qty", store=True)
length = fields.Float(string="Length")
width = fields.Float(string="Width")
height = fields.Float(string="Height")
is_use_measure = fields.Boolean(
related="project_id.is_use_measure", store=True)
@api.depends('project_id.is_use_measure', 'length', 'width', 'height', 'qty')
def compute_total_qty(self):
for rec in self:
total_qty = 0.0
if rec.project_id.is_use_measure:
total_qty = rec.height * rec.width * rec.length * rec.qty
else:
total_qty = rec.qty
rec.total_qty = total_qty