You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							184 lines
						
					
					
						
							9.5 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							184 lines
						
					
					
						
							9.5 KiB
						
					
					
				
								# -*- coding: utf-8 -*-
							 | 
						|
								################################################################################
							 | 
						|
								#
							 | 
						|
								#    Cybrosys Technologies Pvt. Ltd.
							 | 
						|
								#
							 | 
						|
								#    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
							 | 
						|
								#    Author: Anfas Faisal K (odoo@cybrosys.info)
							 | 
						|
								#
							 | 
						|
								#    You can modify it under the terms of the GNU AFFERO
							 | 
						|
								#    GENERAL PUBLIC LICENSE (AGPL v3), Version 3.
							 | 
						|
								#
							 | 
						|
								#    This program is distributed in the hope that it will be useful,
							 | 
						|
								#    but WITHOUT ANY WARRANTY; without even the implied warranty of
							 | 
						|
								#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
							 | 
						|
								#    GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details.
							 | 
						|
								#
							 | 
						|
								#    You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
							 | 
						|
								#    (AGPL v3) along with this program.
							 | 
						|
								#    If not, see <http://www.gnu.org/licenses/>.
							 | 
						|
								#
							 | 
						|
								################################################################################
							 | 
						|
								import io
							 | 
						|
								import json
							 | 
						|
								import xlsxwriter
							 | 
						|
								from odoo import models
							 | 
						|
								from odoo.tools import date_utils
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								class AccountMove(models.Model):
							 | 
						|
								    """Inherits the account move model"""
							 | 
						|
								    _inherit = 'mrp.bom'
							 | 
						|
								
							 | 
						|
								    def action_print_bom_structure(self):
							 | 
						|
								        """Generate and export the BOM Structure Report in Excel format."""
							 | 
						|
								        bom = self.env['mrp.bom'].browse(self.id)
							 | 
						|
								        candidates = bom.product_id or bom.product_tmpl_id.product_variant_ids
							 | 
						|
								        quantity = bom.product_qty
							 | 
						|
								        for product_variant_id in candidates.ids:
							 | 
						|
								            doc = self.env['report.mrp.report_bom_structure']._get_pdf_line(
							 | 
						|
								                bom.id, product_id=product_variant_id,
							 | 
						|
								                qty=quantity, unfolded=True)
							 | 
						|
								        return {
							 | 
						|
								            'type': 'ir.actions.report',
							 | 
						|
								            'data': {'model': 'mrp.bom',
							 | 
						|
								                     'options': json.dumps(doc,
							 | 
						|
								                                           default=date_utils.json_default),
							 | 
						|
								                     'output_format': 'xlsx',
							 | 
						|
								                     'report_name': 'BoM Structure',
							 | 
						|
								                     },
							 | 
						|
								            'report_type': 'xlsx',
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								    def get_xlsx_report(self, data, response):
							 | 
						|
								        """ Generate an Excel report with BOM structure and cost."""
							 | 
						|
								        output = io.BytesIO()
							 | 
						|
								        workbook = xlsxwriter.Workbook(output, {'in_memory': True})
							 | 
						|
								        sheet = workbook.add_worksheet()
							 | 
						|
								        # Define cell formats
							 | 
						|
								        head = workbook.add_format(
							 | 
						|
								            {'align': 'left', 'bold': True, 'font_size': '20px'})
							 | 
						|
								        format3 = workbook.add_format({'font_size': '15px', 'bold': True})
							 | 
						|
								        format4 = workbook.add_format({'font_size': 10})
							 | 
						|
								        format6 = workbook.add_format({'font_size': 10, 'bold': True})
							 | 
						|
								        format7 = workbook.add_format({'font_size': 10, 'font_color': 'green'})
							 | 
						|
								        format8 = workbook.add_format({'font_size': 10, 'font_color': 'red'})
							 | 
						|
								        format9 = workbook.add_format({'font_size': 10, 'font_color': 'yellow'})
							 | 
						|
								        # Check if there are components or lines in the data
							 | 
						|
								        if data and data.get('components') or data.get('lines'):
							 | 
						|
								            # Merge and format header cells
							 | 
						|
								            sheet.merge_range('A1:F2', 'BoM Structure & Cost', head)
							 | 
						|
								            sheet.merge_range('A4:Z5', data['name'], format3)
							 | 
						|
								            # Merge and format cells for product information
							 | 
						|
								            sheet.merge_range('A7:C7', 'Products', format6)
							 | 
						|
								            sheet.merge_range('D7:E7', 'Quantity', format6)
							 | 
						|
								            sheet.merge_range('F7:G7', 'Unit of Measure', format6)
							 | 
						|
								            sheet.merge_range('H7:I7', 'Ready to Produce', format6)
							 | 
						|
								            sheet.merge_range('J7:K7', 'Free to Use / On Hand', format6)
							 | 
						|
								            sheet.merge_range('L7:M7', 'Availability', format6)
							 | 
						|
								            sheet.merge_range('N7:O7', 'Lead Time', format6)
							 | 
						|
								            sheet.merge_range('P7:Q7', 'Route', format6)
							 | 
						|
								            sheet.merge_range('R7:S7', 'Product Cost', format6)
							 | 
						|
								            sheet.merge_range('T7:U7', 'BOM Cost', format6)
							 | 
						|
								            row_start = 9  # Starting row for data
							 | 
						|
								            currency_symbol = self.env.user.company_id.currency_id.symbol
							 | 
						|
								            # Iterate through lines in the data
							 | 
						|
								            for index, value in enumerate(data.get('lines')):
							 | 
						|
								                # Calculate leading spaces based on the level
							 | 
						|
								                if value['level'] != 0:
							 | 
						|
								                    space_td = '    ' * value['level']
							 | 
						|
								                else:
							 | 
						|
								                    space_td = '    '
							 | 
						|
								                # Merge and format cells for product name
							 | 
						|
								                sheet.merge_range('A8:C8', data['name'], format6)
							 | 
						|
								                sheet.merge_range('D8:E8', data['quantity'], format4)
							 | 
						|
								                sheet.merge_range(f'A{index + row_start}:C{index + row_start}',
							 | 
						|
								                                  space_td + value['name'], format4)
							 | 
						|
								                # Merge and format cells for quantity
							 | 
						|
								                sheet.merge_range(f'D{index + row_start}:E{index + row_start}',
							 | 
						|
								                                  value['quantity'], format4)
							 | 
						|
								                # Merge and format cells for unit of measure
							 | 
						|
								                if 'uom' in value:
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'F{index + row_start}:G{index + row_start}',
							 | 
						|
								                        value['uom'], format4)
							 | 
						|
								                # Merge and format cells for 'Ready to Produce'
							 | 
						|
								                if 'producible_qty' in value:
							 | 
						|
								                    sheet.merge_range('H8:I8', data['producible_qty'], format4)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'H{index + row_start}:I{index + row_start}',
							 | 
						|
								                        value['producible_qty'], format4)
							 | 
						|
								                # Merge and format cells for 'Quantity Available / On Hand'
							 | 
						|
								                if 'quantity_available' in value:
							 | 
						|
								                    quantity_available_on_hand = \
							 | 
						|
								                        f"{value['quantity_available']} / {value['quantity_on_hand']}"
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        'J8:K8', f"{data['quantity_available']} / "
							 | 
						|
								                                 f"{data['quantity_on_hand']}", format4)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'J{index + row_start}:K{index + row_start}',
							 | 
						|
								                        quantity_available_on_hand, format4)
							 | 
						|
								                # Merge and format cells for 'Availability'
							 | 
						|
								                if 'availability_display' in value:
							 | 
						|
								                    availability_main_text = data['availability_display']
							 | 
						|
								                    availability_text = value['availability_display']
							 | 
						|
								                    color_format_main = format7 if (
							 | 
						|
								                            availability_main_text == 'Available') \
							 | 
						|
								                        else (
							 | 
						|
								                        format8 if availability_main_text == 'Not Available'
							 | 
						|
								                        else format9)
							 | 
						|
								                    color_format = format7 if availability_text == 'Available' \
							 | 
						|
								                        else (format8 if availability_text == 'Not Available'
							 | 
						|
								                              else format9)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        'L8:M8', availability_main_text, color_format_main)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'L{index + row_start}:M{index + row_start}',
							 | 
						|
								                        availability_text, color_format)
							 | 
						|
								                # Merge and format cells for 'Product Cost'
							 | 
						|
								                if 'prod_cost' in value:
							 | 
						|
								                    prod_cost_with_symbol = f"{currency_symbol} {data['prod_cost']} "
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        'R8:S8', prod_cost_with_symbol, format4)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'R{index + row_start}:S{index + row_start}',
							 | 
						|
								                        f"{currency_symbol} {value['prod_cost']}", format4)
							 | 
						|
								                # Merge and format cells for 'BOM Cost'
							 | 
						|
								                if 'bom_cost' in value:
							 | 
						|
								                    bom_cost_with_symbol = f" {currency_symbol} {data['bom_cost']}"
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        'T8:U8', bom_cost_with_symbol, format4)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'T{index + row_start}:U{index + row_start}',
							 | 
						|
								                        f" {currency_symbol} {value['bom_cost']}", format4)
							 | 
						|
								                # Merge and format cells for 'Route Info'
							 | 
						|
								                if 'route_name' in value:
							 | 
						|
								                    route_info = f"{value['route_name']} {value['route_detail']}"
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'P{index + row_start}:Q{index + row_start}',
							 | 
						|
								                        route_info, format4)
							 | 
						|
								                # Merge and format cells for 'Lead Time'
							 | 
						|
								                if 'lead_time' in value:
							 | 
						|
								                    lead_time = value['lead_time']
							 | 
						|
								                    lead_time_days = f"{int(lead_time)} days" if lead_time != 0.0 else "0 days"
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'N{index + row_start}:O{index + row_start}',
							 | 
						|
								                        lead_time_days, format4)
							 | 
						|
								                # Check if 'prod_cost' is present in the data dictionary
							 | 
						|
								                if 'prod_cost' in data:
							 | 
						|
								                    prod_cost_with_symbol = f"{currency_symbol} {data['prod_cost']}"
							 | 
						|
								                    bom_cost_with_symbol = f" {currency_symbol} {data['bom_cost']}"
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'D{index + row_start + 1}:E{index + row_start + 1}',
							 | 
						|
								                        'UnitCost', format6)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'T{index + row_start + 1}:U{index + row_start + 1}',
							 | 
						|
								                        bom_cost_with_symbol, format4)
							 | 
						|
								                    sheet.merge_range(
							 | 
						|
								                        f'R{index + row_start + 1}:S{index + row_start + 1}',
							 | 
						|
								                        prod_cost_with_symbol, format4)
							 | 
						|
								        # Close the workbook, seek to the beginning, and stream the output
							 | 
						|
								        workbook.close()
							 | 
						|
								        output.seek(0)
							 | 
						|
								        response.stream.write(output.read())
							 | 
						|
								        output.close()
							 | 
						|
								
							 |