diff --git a/sos_inventory/__manifest__.py b/sos_inventory/__manifest__.py index 90f48b2..5408d67 100755 --- a/sos_inventory/__manifest__.py +++ b/sos_inventory/__manifest__.py @@ -114,6 +114,7 @@ 'report/mme_history_card_report.xml', 'report/sos_boq_labels.xml', 'report/shelflife_report.xml', + 'report/sos_boq_report.xml', 'data/send_indent_plan_email_template.xml', 'data/selection_item.xml' diff --git a/sos_inventory/models/__pycache__/sos_deliverables_boq.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_deliverables_boq.cpython-310.pyc index 36ffa66..bb729eb 100644 Binary files a/sos_inventory/models/__pycache__/sos_deliverables_boq.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_deliverables_boq.cpython-310.pyc differ diff --git a/sos_inventory/models/__pycache__/sos_dock_audit.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_dock_audit.cpython-310.pyc index 0b3a6b5..5f36228 100644 Binary files a/sos_inventory/models/__pycache__/sos_dock_audit.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_dock_audit.cpython-310.pyc differ diff --git a/sos_inventory/models/__pycache__/sos_fir.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_fir.cpython-310.pyc index 26b6fed..427b994 100644 Binary files a/sos_inventory/models/__pycache__/sos_fir.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_fir.cpython-310.pyc differ diff --git a/sos_inventory/models/__pycache__/sos_inventory_customers.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_inventory_customers.cpython-310.pyc index 2d548e4..7fc5528 100644 Binary files a/sos_inventory/models/__pycache__/sos_inventory_customers.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_inventory_customers.cpython-310.pyc differ diff --git a/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc index b1577ce..1cb55d4 100644 Binary files a/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_ir.cpython-310.pyc differ diff --git a/sos_inventory/models/__pycache__/sos_sales_order.cpython-310.pyc b/sos_inventory/models/__pycache__/sos_sales_order.cpython-310.pyc index b4a5ee0..b5bd074 100644 Binary files a/sos_inventory/models/__pycache__/sos_sales_order.cpython-310.pyc and b/sos_inventory/models/__pycache__/sos_sales_order.cpython-310.pyc differ diff --git a/sos_inventory/models/sos_deliverables_boq.py b/sos_inventory/models/sos_deliverables_boq.py index 3bcdea3..b5158ef 100755 --- a/sos_inventory/models/sos_deliverables_boq.py +++ b/sos_inventory/models/sos_deliverables_boq.py @@ -65,6 +65,19 @@ class sos_deliverables_boq(models.Model): verified_by = fields.Many2one('res.users', string='Prepared by') verified_by_image = fields.Image(related="verified_by.signature_image",string='Prepared by Sign',readonly=True) verified_on = fields.Datetime(string="Prepared On") + ce_verified_by = fields.Many2one('res.users', string='CE Verified by') + ce_verified_by_image = fields.Image(related="ce_verified_by.signature_image",string='CE Verified by Sign',readonly=True) + ce_verified_on = fields.Datetime(string="CE Head Verified On") + scg_head_verified_by = fields.Many2one('res.users', string='SCG Verified by') + scg_head_verified_by_image = fields.Image(related="scg_head_verified_by.signature_image",string='SCG Verified by Sign',readonly=True) + scg_head_verified_on = fields.Datetime(string="SCG Head Verified On") + batter_or_cells=fields.Integer(string="Battery/Cells") + def action_report_boq(self): + try: + action = self.env.ref("sos_inventory.action_sos_deliverables_boq").report_action(self) + return action + except ValueError as e: + print(f"Failed to find report action: {e}") def action_print_labels_btn(self): try: action = self.env.ref("sos_inventory.action_report_labels").report_action(self) @@ -127,11 +140,44 @@ class sos_deliverables_boq(models.Model): ) def action_prepared_esign_btn(self): sequence_util = self.env['sos_common_scripts'] + # Email part + body_html = f""" +
Below Deliverables/BOQ is waiting for your Approval
+ """ + sequence_util.send_group_email(self.env,'sos_deliverables_boq',self.id,"deenalaura.m@sosaley.in","Deliverables/BOQ Approval Request",body_html,'sos_inventory.sos_ce_head') + # Email part ends return sequence_util.action_assign_signature( self, 'prepared_by', 'prepared_on' ) + def action_ce_verified_esign_btn(self): + sequence_util = self.env['sos_common_scripts'] + # Email part + body_html = f""" +Below Deliverables/BOQ is waiting for your Approval
+ """ + sequence_util.send_group_email(self.env,'sos_deliverables_boq',self.id,"deenalaura.m@sosaley.in","Deliverables/BOQ Approval Request",body_html,'sos_inventory.sos_scg_group_manager') + # Email part ends + return sequence_util.action_assign_signature( + self, + 'ce_verified_by', + 'ce_verified_on' + ) + def action_scg_head_verified_esign_btn(self): + sequence_util = self.env['sos_common_scripts'] + # Email part + body_html = f""" +Below Deliverables/BOQ is waiting for your Approval
+ """ + sequence_util.send_group_email(self.env,'sos_deliverables_boq',self.id,"deenalaura.m@sosaley.in","Deliverables/BOQ Approval Request",body_html,'sos_inventory.sos_qa_user') + # Email part ends + return sequence_util.action_assign_signature( + self, + 'scg_head_verified_by', + 'scg_head_verified_on' + ) + def action_scg_esign_btn(self): sequence_util = self.env['sos_common_scripts'] return sequence_util.action_assign_signature( @@ -185,6 +231,7 @@ class sos_deliverables_boq_Line_Material(models.Model): ref_id = fields.Many2one('sos_deliverables_boq', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) + display_name = fields.Char(string="Display Name", related="component_id.name", store=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") @@ -306,6 +353,7 @@ class sos_deliverables_Material_installationkit(models.Model): ref_id = fields.Many2one('sos_deliverables_boq', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) + display_name = fields.Char(string="Display Name", related="component_id.name", store=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram'), ('Packs', 'Packs')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") diff --git a/sos_inventory/models/sos_dock_audit.py b/sos_inventory/models/sos_dock_audit.py index 1e55618..83d6754 100755 --- a/sos_inventory/models/sos_dock_audit.py +++ b/sos_inventory/models/sos_dock_audit.py @@ -17,12 +17,15 @@ class SOS_Dock_Audit(models.Model): deliverables_boq_id = fields.Many2one('sos_deliverables_boq', string="Deliverables/BOQ Id") fg_name = fields.Selection( [ - ('BHMS 1.2V', 'BHMS 1.2V'), - ('BHMS 2V', 'BHMS 2V'), - ('BHMS 12V', 'BHMS 12V'), + ('BHMS 1.2V', 'BHMS 1.2V'), + ('BHMS 2V', 'BHMS 2V'), + ('BHMS 12V', 'BHMS 12V'), + ('BHMS 48V', 'BHMS 48V'), + ('BMS-HV', 'BMS-HV'), ('BMS-LV 100A', 'BMS-LV 100A'), - ('BMS-LV 40A', 'BMS-LV 40A'), - ('MC 250W', 'MC 250W'), + ('BMS-LV 40A', 'BMS-LV 40A'), + ('SBMS 55A', 'SBMS 55A'), + ('MC 250W', 'MC 250W'), ('HeartTarang', 'HeartTarang') ], string="Product Type",required=True) @@ -384,6 +387,7 @@ class sos_dock_audit_Line_Material(models.Model): ref_id = fields.Many2one('sos_dock_audit', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) + display_name = fields.Char(string="Display Name", related="component_id.name", store=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") @@ -689,6 +693,7 @@ class sos_dock_audit_Material_installationkit(models.Model): ref_id = fields.Many2one('sos_dock_audit', string="Materials", ondelete="cascade") component_id = fields.Many2one('sos_material', string="Material Name", required=True) + display_name = fields.Char(string="Display Name", related="component_id.name", store=True) uom = fields.Selection([('meters', 'Meters'),('Nos', 'Nos'),('coils', 'Coils'), ('litre', 'litre'), ('kg', 'Kilogram')], default="Nos",string="Uom") currency_id = fields.Many2one('res.currency', string='Currency') material_code = fields.Char(related="component_id.material_code",string="Material Code") diff --git a/sos_inventory/models/sos_fir.py b/sos_inventory/models/sos_fir.py index e2302b6..9ab45da 100755 --- a/sos_inventory/models/sos_fir.py +++ b/sos_inventory/models/sos_fir.py @@ -51,21 +51,45 @@ class FIR_Only(models.Model): stores_received_on = fields.Date(string="Stores Received On") ncmr_ref = fields.Many2one('sos_ncmr',string="NCMR Reference (If any Rejected)") customer_name = fields.Many2one('sos_inventory_customers', string="Customer Name", required=True) - remarks = fields.Text(string="Remarks") test_log = fields.Binary("Test Log", required=False, attachment=True) test_log_filename = fields.Char("Test Log Filename") rejected_line_ids = fields.One2many('sos_fir_rejected_lines', 'ref_id', string="Finished Goods",copy=True, ondelete='cascade') serial_no_line_ids = fields.One2many('sos_fir_serial_no_lines', 'ref_id',copy=True) - sd_card_data = fields.Binary("SD Card Data", required=False, attachment=True) sd_card_data_filename = fields.Char("SD Card Data Filename") - cloud_data = fields.Binary("Cloud Data", required=False, attachment=True) cloud_data_filename = fields.Char("Cloud Data Filename") - firmware_data = fields.Binary("Firmware Data", required=False, attachment=True) firmware_data_filename = fields.Char("Firmware Data Filename") + serial_no_parse = fields.Text(string="Serial no's to parse") + def parse_serial_nos(self): + self.ensure_one() + if not self.serial_no_parse: + return + + # Split into clean serial numbers + serial_numbers = [ + line.strip() for line in self.serial_no_parse.splitlines() if line.strip() + ] + + SerialLine = self.env['sos_fir_serial_no_lines'] + + for serial in serial_numbers: + # Check if already exists for this ref_id + exists = SerialLine.search([ + ('ref_id', '=', self.id), + ('serial_no', '=', serial) + ], limit=1) + + if not exists: + SerialLine.create({ + 'ref_id': self.id, + 'serial_no': serial, + 'inspection_decision': 'PASS', # default + }) + + @api.onchange('batch_size') def _onchange_batch_size(self): if self._origin and self.batch_size is not False: diff --git a/sos_inventory/models/sos_inventory_customers.py b/sos_inventory/models/sos_inventory_customers.py index b9c0615..b54768a 100755 --- a/sos_inventory/models/sos_inventory_customers.py +++ b/sos_inventory/models/sos_inventory_customers.py @@ -18,18 +18,30 @@ class sos_inventory_customers(models.Model): new_name = (vals.get('customer_name') or '').lower() if new_name and len(new_name) >= 5: - existing_customers = self.search([]) + # Words/phrases to exclude + blacklist = [ + 'private limited', 'pvt ltd', 'pvt. ltd.', 'ltd', 'llp', 'inc', 'co', 'company', 'corporation' + ] + def clean_name(name): + for word in blacklist: + name = name.replace(word, '') + return name.strip() + + new_name_clean = clean_name(new_name) + + existing_customers = self.search([]) for customer in existing_customers: existing_name = (customer.customer_name or '').lower() + existing_name_clean = clean_name(existing_name) - # Check all substrings of length 5 or more - for i in range(len(new_name) - 4): - substring = new_name[i:i+5] - if substring in existing_name: + # Check all substrings of length 7 or more + for i in range(len(new_name_clean) - 6): + substring = new_name_clean[i:i+7] + if substring in existing_name_clean: raise UserError( f"A customer with a similar name already exists: '{customer.customer_name}' " f"(matched substring: '{substring}')" ) - return super(sos_inventory_customers, self).create(vals) \ No newline at end of file + return super().create(vals) \ No newline at end of file diff --git a/sos_inventory/models/sos_ir.py b/sos_inventory/models/sos_ir.py index ed8d164..6a19daa 100755 --- a/sos_inventory/models/sos_ir.py +++ b/sos_inventory/models/sos_ir.py @@ -217,6 +217,11 @@ class SOS_IR(models.Model): for item in self.line_ids_material: # Fetch the component related to the current item component = self.env['sos_material'].browse(item.component_id.id) + if self.supplier_name and self.supplier_name.id not in component.suppliers.ids: + component.write({ + 'suppliers': [(4, self.supplier_name.id)] + }) + if component.shelf_life == "yes": shelflife_line_values = { 'ir_ref_no':self.id, @@ -301,6 +306,10 @@ class SOS_IR(models.Model): for item in self.line_ids_sfg: # PO update part sfg_component = self.env['sos_sfg'].browse(item.component_id.id) + if self.service_provider_name and self.service_provider_name.id not in sfg_component.service_providers.ids: + sfg_component.write({ + 'service_providers': [(4, self.service_provider_name.id)] + }) if self.wo_planned_at == "outsource": if self.wo_no: if not self.orr_no: diff --git a/sos_inventory/models/sos_sales_order.py b/sos_inventory/models/sos_sales_order.py index d7a1ab4..3ee5d5b 100755 --- a/sos_inventory/models/sos_sales_order.py +++ b/sos_inventory/models/sos_sales_order.py @@ -25,7 +25,7 @@ class SOS_SalesOrder(models.Model): ], string="Product Name",required=True) line_ids = fields.One2many('sos_sales_order_line', 'ref_id',copy=True) - customer_name = fields.Char(string="Customer Name") + customer_name = fields.Many2one('sos_inventory_customers',string="Customer Name") lead_time = fields.Datetime(string="Lead Time") customer_po_no = fields.Char(string="PO No") customer_po_date = fields.Datetime(string="PO Date") @@ -58,7 +58,7 @@ class SOS_SalesOrder(models.Model): 'sales_id':self.id, 'fg_name':self.fg_name, 'quantity':self.qty, - 'customer_name':self.customer_name, + 'customer_name':self.customer_name.customer_name, 'lead_time':self.lead_time, 'customer_po_no':self.customer_po_no, 'customer_po_date':self.customer_po_date @@ -109,15 +109,15 @@ class SOS_SalesOrder(models.Model): sequence_util = self.env['sos_common_scripts'] return sequence_util.generate_sequence('sos_sales_order','SALES', 'order_id') - @api.model - def create(self, vals): - customer_name = vals.get('customer_name') - if customer_name: - existing = self.env['sos_inventory_customers'].search([('customer_name', '=', customer_name)], limit=1) - if not existing: - self.env['sos_inventory_customers'].create({'customer_name': customer_name}) + # @api.model + # def create(self, vals): + # customer_name = vals.get('customer_name') + # if customer_name: + # existing = self.env['sos_inventory_customers'].search([('customer_name', '=', customer_name)], limit=1) + # if not existing: + # self.env['sos_inventory_customers'].create({'customer_name': customer_name}) - return super(SOS_SalesOrder, self).create(vals) + # return super(SOS_SalesOrder, self).create(vals) class SOS_SalesOrder_Line(models.Model): _name = 'sos_sales_order_line' diff --git a/sos_inventory/report/sos_boq_labels.xml b/sos_inventory/report/sos_boq_labels.xml index 86ae22f..c7a8ea7 100755 --- a/sos_inventory/report/sos_boq_labels.xml +++ b/sos_inventory/report/sos_boq_labels.xml @@ -86,131 +86,192 @@ } -| Set No | +# |
+
| Battery | +|
| No | +|
| Name | +
+ |
+
| UOM | +
+ |
+
| Qty | +
+ |
+
| S.No | ++ |
| Set No | -# |
-
| Battery | -- |
| No | -|
| Name | -|
| UOM | -|
| Qty | -|
| S.No | -- |
| Set No | -# |
-
| Battery | -- |
| No | -|
| Name | -|
| UOM | -|
| Qty | -|
| S.No | -- |
| Set No | +# |
+
| Battery | +|
| No | +|
| Name | +
+ |
+
| UOM | +
+ |
+
| Qty | +
+ |
+
| S.No | ++ |
| Customer Name | Location | ||
| Product Name | Quantity |
| Finished Goods | |||||
| S.No | +Name | +UOM | +Single set Qty | +Total Set | +Qty | +
| Semi-Finished Goods | |||||
| Materials | |||||
| Installation Kit | |||||
| Miscellaneous | |||||
| S.No | +Name | +Qty | +|||
Serial No's | ||||||
| Verified By + | QA Verified By
|
@@ -307,6 +353,8 @@
| Parse Serial No's | |||