Tower: upload tk_construction_management 18.0.2.0.8 (was 18.0.2.0.8, via marketplace)
This commit is contained in:
846
addons/tk_construction_management/models/construction_project.py
Normal file
846
addons/tk_construction_management/models/construction_project.py
Normal file
@@ -0,0 +1,846 @@
|
||||
# -*- 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
|
||||
Reference in New Issue
Block a user