diff --git a/sos_sales/models/__pycache__/sos_proposal_boq.cpython-310.pyc b/sos_sales/models/__pycache__/sos_proposal_boq.cpython-310.pyc
index 9b8f470..bc5e6a9 100644
Binary files a/sos_sales/models/__pycache__/sos_proposal_boq.cpython-310.pyc and b/sos_sales/models/__pycache__/sos_proposal_boq.cpython-310.pyc differ
diff --git a/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc b/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc
index 7b98b7b..8e69670 100644
Binary files a/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc and b/sos_sales/models/__pycache__/sos_sales_achievement_report.cpython-310.pyc differ
diff --git a/sos_sales/models/sos_proposal_boq.py b/sos_sales/models/sos_proposal_boq.py
index a87954c..bb898ef 100755
--- a/sos_sales/models/sos_proposal_boq.py
+++ b/sos_sales/models/sos_proposal_boq.py
@@ -1,5 +1,7 @@
from odoo import models, fields, api
import math
+from collections import defaultdict
+from odoo.tools.misc import format_amount
class Battery_Installation_Requirement(models.Model):
_name = 'sos_proposal_boq'
@@ -100,6 +102,14 @@ class Battery_Installation_Requirement(models.Model):
line_ids_fg_ups13 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 13",compute='_compute_line_ids_by_ups',store=False)
line_ids_fg_ups14 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 14",compute='_compute_line_ids_by_ups',store=False)
line_ids_fg_ups15 = fields.One2many('sos_proposal_boq_fg', 'ref_id', string="FG UPS 15",compute='_compute_line_ids_by_ups',store=False)
+ merged_fg_html = fields.Html(string="FG (Merged)", compute="_compute_merged_fg_html", sanitize=False)
+ merged_sfg_html = fields.Html(string="SFG (Merged)", compute="_compute_merged_sfg_html", sanitize=False)
+ merged_material_html = fields.Html(string="Materials (Merged)", compute="_compute_merged_material_html", sanitize=False)
+ merged_installation_kit_html = fields.Html(string="InstallationKit (Merged)", compute="_compute_merged_installation_kit_html", sanitize=False)
+ merged_miscellaneous_html = fields.Html(string="Miscellaneous (Merged)", compute="_compute_merged_miscellaneous_html", sanitize=False)
+ merged_spare_html = fields.Html(string="Spare (Merged)", compute="_compute_merged_spare_html", sanitize=False)
+
+
#SFG Fields
line_ids_sfg_ups1 = fields.One2many('sos_proposal_boq_sfg', 'ref_id', string="SFG UPS 1",compute='_compute_line_ids_by_ups',store=False)
@@ -120,21 +130,21 @@ class Battery_Installation_Requirement(models.Model):
#Material Fields
- line_ids_material_ups1 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 1",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups2 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 2",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups3 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 3",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups4 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 4",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups5 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 5",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups6 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 6",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups7 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 7",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups8 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 8",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups9 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 9",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups10 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 10",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups11 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 11",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups12 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 12",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups13 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 13",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups14 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 14",compute='_compute_line_ids_by_ups',store=False)
- line_ids_material_ups15 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 15",compute='_compute_line_ids_by_ups',store=False)
+ line_ids_material_ups1 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 1",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups2 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 2",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups3 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 3",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups4 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 4",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups5 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 5",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups6 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 6",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups7 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 7",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups8 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 8",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups9 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 9",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups10 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 10",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups11 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 11",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups12 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 12",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups13 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 13",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups14 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 14",compute='_compute_line_ids_by_ups',store=False,readonly=False)
+ line_ids_material_ups15 = fields.One2many('sos_proposal_boq_material', 'ref_id', string="Material UPS 15",compute='_compute_line_ids_by_ups',store=False,readonly=False)
#Installation Kit Fields
@@ -206,6 +216,454 @@ class Battery_Installation_Requirement(models.Model):
line_ids_spare_ups13 = fields.One2many('sos_proposal_line_spare_ups13','ref_id', string="Spare UPS 13")
line_ids_spare_ups14 = fields.One2many('sos_proposal_line_spare_ups14','ref_id', string="Spare UPS 14")
line_ids_spare_ups15 = fields.One2many('sos_proposal_line_spare_ups15','ref_id', string="Spare UPS 15")
+ def _compute_merged_spare_html(self):
+ for rec in self:
+ # Collect lines from ups1..ups15 (skip models that don't exist)
+ models = [f'sos_proposal_line_spare_ups{i}' for i in range(1, 16)]
+
+ agg = defaultdict(float) # (component_id, uom, currency_id, unit_price) -> qty
+ name_map, curr_map, price_map = {}, {}, {}
+
+ for model in models:
+ if model not in self.env:
+ continue
+ for l in self.env[model].search([('ref_id', '=', rec.id)]):
+ unit_price = l.unit_price or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.component_id.id, l.uom, curr_id, unit_price)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ # Use part number (fallback to component name if needed)
+ name_map[key] = (getattr(l.component_id, 'part_no', False) or l.component_id.name or '')
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = unit_price
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_spare_html = "No Material items."
+ continue
+
+ def fmt_price(amount, currency):
+ return format_amount(self.env, amount, currency) if currency else f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty:
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f"
"
+ f"| {name_map[key]} | "
+ f"{key[1] or ''} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html:
+ rec.merged_spare_html = "No Material items."
+ continue
+
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_spare_html = f"""
+
+
+
+ | Material Name |
+ UoM |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+ def _compute_merged_miscellaneous_html(self):
+ for rec in self:
+ lines = self.env['sos_proposal_miscellaneous_items'].search([('ref_id', '=', rec.id)])
+
+ # Group by (component, currency, cost)
+ agg = defaultdict(float)
+ name_map = {}
+ curr_map = {}
+ price_map = {}
+
+ for l in lines:
+ cost = l.cost or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.name, curr_id, cost)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ name_map[key] = l.name or ''
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = cost
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_miscellaneous_html = "No Miscellaneous items."
+ continue
+
+ def fmt_price(amount, currency):
+ if currency:
+ return format_amount(self.env, amount, currency)
+ return f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty: # Skip rows with qty = 0
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f""
+ f"| {name_map[key]} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html: # If all rows were skipped
+ rec.merged_miscellaneous_html = "No Miscellaneous items."
+ continue
+
+ # Add grand total row
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_miscellaneous_html = f"""
+
+
+
+ | Name |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+ def _compute_merged_installation_kit_html(self):
+ for rec in self:
+ lines = self.env['sos_proposal_line_material_installation'].search([('ref_id', '=', rec.id)])
+
+ # Group by (component, uom, currency, unit_price)
+ agg = defaultdict(float)
+ name_map = {}
+ curr_map = {}
+ price_map = {}
+
+ for l in lines:
+ unit_price = l.unit_price or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.component_id.id, l.uom, curr_id, unit_price)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ name_map[key] = l.component_id.part_no or ''
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = unit_price
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_installation_kit_html = "No Material items."
+ continue
+
+ def fmt_price(amount, currency):
+ if currency:
+ return format_amount(self.env, amount, currency)
+ return f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty: # Skip rows with qty = 0
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f""
+ f"| {name_map[key]} | "
+ f"{key[1] or ''} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html: # If all rows were skipped
+ rec.merged_installation_kit_html = "No Material items."
+ continue
+
+ # Add grand total row
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_installation_kit_html = f"""
+
+
+
+ | Material Name |
+ UoM |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+ def _compute_merged_material_html(self):
+ for rec in self:
+ lines = self.env['sos_proposal_boq_material'].search([('ref_id', '=', rec.id)])
+
+ # Group by (component, uom, currency, unit_price)
+ agg = defaultdict(float)
+ name_map = {}
+ curr_map = {}
+ price_map = {}
+
+ for l in lines:
+ unit_price = l.unit_price or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.component_id.id, l.uom, curr_id, unit_price)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ name_map[key] = l.component_id.part_no or ''
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = unit_price
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_material_html = "No Material items."
+ continue
+
+ def fmt_price(amount, currency):
+ if currency:
+ return format_amount(self.env, amount, currency)
+ return f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty: # Skip rows with qty = 0
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f""
+ f"| {name_map[key]} | "
+ f"{key[1] or ''} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html: # If all rows were skipped
+ rec.merged_material_html = "No Material items."
+ continue
+
+ # Add grand total row
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_material_html = f"""
+
+
+
+ | Material Name |
+ UoM |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+ def _compute_merged_sfg_html(self):
+ for rec in self:
+ lines = self.env['sos_proposal_boq_sfg'].search([('ref_id', '=', rec.id)])
+
+ # Group by (component, uom, currency, unit_price)
+ agg = defaultdict(float)
+ name_map = {}
+ curr_map = {}
+ price_map = {}
+
+ for l in lines:
+ unit_price = l.unit_price or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.component_id.id, l.uom, curr_id, unit_price)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ name_map[key] = l.component_id.name or ''
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = unit_price
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_sfg_html = "No SFG items."
+ continue
+
+ def fmt_price(amount, currency):
+ if currency:
+ return format_amount(self.env, amount, currency)
+ return f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty: # Skip rows with qty = 0
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f""
+ f"| {name_map[key]} | "
+ f"{key[1] or ''} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html: # If all rows were skipped
+ rec.merged_sfg_html = "No SFG items."
+ continue
+
+ # Add grand total row
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_sfg_html = f"""
+
+
+
+ | SFG Name |
+ UoM |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+ def _compute_merged_fg_html(self):
+ for rec in self:
+ lines = self.env['sos_proposal_boq_fg'].search([('ref_id', '=', rec.id)])
+
+ # Group by (component, uom, currency, unit_price)
+ agg = defaultdict(float)
+ name_map = {}
+ curr_map = {}
+ price_map = {}
+
+ for l in lines:
+ unit_price = l.unit_price or 0.0
+ curr_id = l.currency_id.id if l.currency_id else False
+ key = (l.component_id.id, l.uom, curr_id, unit_price)
+
+ agg[key] += float(l.quantity or 0)
+ if key not in name_map:
+ name_map[key] = l.component_id.name or ''
+ curr_map[key] = l.currency_id if l.currency_id else False
+ price_map[key] = unit_price
+
+ rows_sorted = sorted(agg.items(), key=lambda it: name_map[it[0]].lower())
+ if not rows_sorted:
+ rec.merged_fg_html = "No FG items."
+ continue
+
+ def fmt_price(amount, currency):
+ if currency:
+ return format_amount(self.env, amount, currency)
+ return f"{amount:.2f}"
+
+ total_sum = 0.0
+ rows_html = ""
+ for key, qty in rows_sorted:
+ if not qty: # Skip rows with qty = 0
+ continue
+ total_price = qty * price_map[key]
+ total_sum += total_price
+ rows_html += (
+ f""
+ f"| {name_map[key]} | "
+ f"{key[1] or ''} | "
+ f"{fmt_price(price_map[key], curr_map[key])} | "
+ f"{qty:.2f} | "
+ f"{fmt_price(total_price, curr_map[key])} | "
+ f"
"
+ )
+
+ if not rows_html: # If all rows were skipped
+ rec.merged_fg_html = "No FG items."
+ continue
+
+ # Add grand total row
+ currency_for_total = curr_map[rows_sorted[0][0]] if rows_sorted else False
+ rows_html += (
+ f""
+ f"| Grand Total: | "
+ f"{fmt_price(total_sum, currency_for_total)} | "
+ f"
"
+ )
+
+ rec.merged_fg_html = f"""
+
+
+
+ | FG Name |
+ UoM |
+ Unit Price |
+ Total Qty |
+ Total Price |
+
+
+ {rows_html}
+
+ """
+
@api.model
def create(self, vals):
res = super().create(vals)
@@ -662,10 +1120,22 @@ class Battery_Installation_Requirement(models.Model):
record.total_fg_cost = sum(line.total_price for line in record.line_ids_fg)
def action_ce_esign_btn(self):
body_html = f"""
- Below Proposal is waiting for your Updation
+ Below BOQ is waiting for your updation.
+ Customer Name: {self.customer_name or ''}
+ Location: {self.location or ''}
+ Number of Batteries: {self.number_of_batteries or ''}
"""
+
sequence_util = self.env['sos_common_scripts']
- sequence_util.send_group_email(self.env,'sos_proposal_boq',self.id,"deenalaura.m@sosaley.in","Proposal System - BOQ Submitted",body_html,'sos_inventory.sos_finance_user')
+ sequence_util.send_group_email(
+ self.env,
+ 'sos_proposal_boq',
+ self.id,
+ "deenalaura.m@sosaley.in",
+ f"Proposal System - BOQ Submitted for {self.customer_name}",
+ body_html,
+ 'sos_inventory.sos_finance_user'
+ )
return sequence_util.action_assign_signature(
self,
'boq_submitted_by_name',
diff --git a/sos_sales/models/sos_sales_achievement_report.py b/sos_sales/models/sos_sales_achievement_report.py
index 25b26ca..7bb5410 100755
--- a/sos_sales/models/sos_sales_achievement_report.py
+++ b/sos_sales/models/sos_sales_achievement_report.py
@@ -694,16 +694,31 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
report.write({
new_field_billed: (getattr(report, new_field_billed, 0.0) or 0.0) + new_billed_amount
})
- # Optionally create billing collection entry (if needed)
- if new_billed_amount > 0:
+ # Optionally create billing collection entry (if needed
+ domain = [
+ ('ref_id', '=', report.id),
+ ('sales_person', '=', report.sales_person.id),
+ ('customer_name', '=', vals.get('customer_name', rec.customer_name.id))
+ ]
+
+ existing = self.env['sos_billing_collection'].search(domain, limit=1)
+
+ if not existing:
self.env['sos_billing_collection'].create({
'ref_id': report.id,
'customer_name': vals.get('customer_name', rec.customer_name.id),
'sales_person': report.sales_person.id,
'action_status': 'Billed',
'date_of_action': new_billed_date,
+ 'po_no':vals.get('po_no'),
'value': new_billed_amount
})
+ else:
+ existing.write({
+ 'value': new_billed_amount,
+ 'po_no':vals.get('po_no'),
+ 'date_of_action': new_billed_date
+ })
return super(SOS_Sales_Achievement_Report_Brief, self).write(vals)
@@ -748,7 +763,8 @@ class SOS_Sales_Achievement_Report_Brief(models.Model):
'sales_person': report.sales_person.id,
'action_status': 'Billed',
'date_of_action': billed_date,
- 'value': billed_value
+ 'value': billed_value,
+ 'po_no':vals.get('po_no')
})
new_record = super(SOS_Sales_Achievement_Report_Brief, self).create(vals)
return new_record
diff --git a/sos_sales/views/sos_proposal_boq_view.xml b/sos_sales/views/sos_proposal_boq_view.xml
index 28e00a0..f70bcc1 100755
--- a/sos_sales/views/sos_proposal_boq_view.xml
+++ b/sos_sales/views/sos_proposal_boq_view.xml
@@ -40,6 +40,7 @@
+
Finished Goods
@@ -1654,115 +1655,38 @@
-
-
-
-
- | No of Persons | Cost |
+ | No of Persons | Cost per Day |
-| Man Month( 1 to 2 Yrs) | | |
-| Man Month( 2 to 3 Yrs) | | |
+| Man Month( 2 to 3 Yrs) | | |
+| Man Month( 3 to 5 Yrs) | | |
| Man Month(Manager) | | |
| Total | |