import subprocess import openpyxl from openpyxl.utils import get_column_letter from openpyxl.styles import PatternFill from datetime import datetime import time import sys import os sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) from config import get_connection ROOT_DIR = os.path.abspath(os.path.dirname(__file__)) file_ref = f"{ROOT_DIR}/wlc.xlsx" file_hasil = f"{ROOT_DIR}/hasil/wlc.xlsx" start_time = time.time() conn = get_connection() if conn is None: print("Koneksi ke database gagal.") sys.exit(1) cur = conn.cursor() # Fungsi untuk mengambil data dari PostgreSQL def fetch_data_from_postgresql(q=""): try: cur.execute(q) # Jalankan query yang diberikan col_names = [desc[0] for desc in cur.description] # Ambil nama kolom rows = cur.fetchall() # Ambil semua baris data # Buat list dictionary berdasarkan nama kolom result = [dict(zip(col_names, row)) for row in rows] return result except Exception as e: print(f"Error: {e}") return None def insert_and_shift_right(file_path, sheet_name): # Load workbook and select sheet wb = openpyxl.load_workbook(file_path) sheet = wb[sheet_name] # Get the last two columns max_col = sheet.max_column last_two_cols = [max_col - 1, max_col] # Insert a new column after the last two columns new_col_idx = max_col + 1 sheet.insert_cols(new_col_idx) # Shift formulas, values, and styles for row in range(1, sheet.max_row + 1): for col in last_two_cols: current_cell = sheet.cell(row=row, column=col) current_value = current_cell.value if isinstance(current_value, str) and current_value.startswith("="): # Adjust formula to the new column formula = current_value.replace(get_column_letter(col), get_column_letter(new_col_idx)) sheet.cell(row=row, column=new_col_idx, value=formula) else: sheet.cell(row=row, column=new_col_idx, value=current_value) # Copy cell style (fill color) new_cell = sheet.cell(row=row, column=new_col_idx) if current_cell.fill: new_cell.fill = PatternFill(start_color=current_cell.fill.start_color.rgb, end_color=current_cell.fill.end_color.rgb, fill_type=current_cell.fill.fill_type) # Save workbook with changes wb.save(file_path) print(f"Column inserted and shifted to the right in {file_path}") def insert_column_data(file_path, sheet_name, col_name, data): """ Memasukkan data ke Excel per kolom. Args: file_path (str): Path file Excel. sheet_name (str): Nama sheet Excel. col_name (str): Nama kolom untuk dicari di baris pertama. data (dict): Data yang akan dimasukkan, dengan kunci adalah baris (row_name) dan nilai adalah isi sel. """ # Load workbook dan pilih sheet wb = openpyxl.load_workbook(file_path, data_only=False) sheet = wb[sheet_name] # Temukan indeks kolom berdasarkan col_name di baris pertama col_index = None for col in range(1, sheet.max_column + 1): if sheet.cell(row=1, column=col).value == col_name: col_index = col break # Jika kolom ditemukan, masukkan data per baris if col_index: for row_name, value in data.items(): row_index = None # Cari indeks baris berdasarkan nama di kolom pertama for row in range(2, sheet.max_row + 1): # Mulai dari baris ke-2 untuk menghindari header if sheet.cell(row=row, column=1).value == row_name: row_index = row break # Isi nilai jika baris ditemukan if row_index: sheet.cell(row=row_index, column=col_index, value=value) else: print(f"Column name '{col_name}' not found in the sheet.") # Simpan workbook setelah semua data kolom dimasukkan wb.save(file_path) wb.close() wb.save(file_path) def insert_param(file_path): wb = openpyxl.load_workbook(file_path, data_only=False) sheet = wb["Params"] col_name = "Value" # Temukan indeks kolom berdasarkan col_name di baris pertama col_index = None for col in range(1, sheet.max_column + 1): if sheet.cell(row=1, column=col).value == col_name: col_index = col break query = """SELECT value_str, CASE WHEN unit_of_measurement = '%' THEN value_num / 100 ELSE value_num END AS value_num FROM lcc_ms_master""" data_map = fetch_data_from_postgresql(query) mapping_data = {} for item in data_map: mapping_data[item['value_str']] = round(item['value_num'], 2) # Jika kolom ditemukan, masukkan data per baris if col_index: for row in range(2, sheet.max_row + 1): # Mulai dari baris ke-2 untuk menghindari header param_name = sheet.cell(row=row, column=1).value # Kolom 1 == value_str if param_name in mapping_data: sheet.cell(row=row, column=col_index, value=mapping_data[param_name]) else: print(f"Params: Baris name '{col_name}' not found in the sheet.") # Simpan workbook setelah semua data diperbarui wb.save(file_path) wb.close() def get_abjad(i): if i < 0: raise ValueError("Indeks harus berupa angka 0 atau lebih.") result = "" while i >= 0: i, remainder = divmod(i, 26) result = chr(65 + remainder) + result i -= 1 # Mengurangi 1 untuk menangani offset ke basis 0 return result def validate_number(n): return n if n is not None else 0 # Example usage # insert_and_shift_right(file_ref, "Calc") # ====================================================== 00000 ================================================= # =============================================== SET DATA KE EXCEL ================================================= # ====================================================== 00000 ================================================= # insert PARAM insert_param(file_ref) print("Insert Params Sukses") # Pengolahan data dari PostgreSQL current_year = datetime.now().year query = "SELECT * FROM lcc_plant_tr_data ORDER BY seq" data = fetch_data_from_postgresql(query) if data: for record in data: # print(f"Processing column for year {record['tahun']}") # Kumpulkan semua data untuk satu kolom col_data = {} # Tambahkan data tambahan berdasarkan kondisi if record['is_actual'] == 1: col_data.update({ "Net Capacity Factor": validate_number(record['net_capacity_factor']), "EAF": validate_number(record['eaf']), "Biaya Investasi Tambahan": validate_number(record['cost_a_pinjaman'])/1000000, "O & M Cost": validate_number(record['cost_bd_om'])/1000000, "Periodic Maintenance Cost (Non MI)": validate_number(record['cost_bd_pm_nonmi'])/1000000, "Production (Bruto)": validate_number(record['production_bruto']), "Production (Netto)": validate_number(record['production_netto']), "Fuel Consumption": validate_number(record['fuel_consumption']), "Revenue A": validate_number(record['revenue_a'])/1000000, "Revenue B": validate_number(record['revenue_b'])/1000000, "Revenue C": validate_number(record['revenue_c'])/1000000, "Revenue D": validate_number(record['revenue_d'])/1000000, "Fuel Cost": validate_number(record['cost_c_fuel'])/1000000 }) else: seq_offset = record['seq'] + 2 col_data.update({ "Net Capacity Factor": validate_number(record['net_capacity_factor']), "EAF": validate_number(record['eaf']), "Biaya Investasi Tambahan": validate_number(record['cost_a_pinjaman'])/1000000, "O & M Cost": validate_number(record['cost_bd_om'])/1000000, "Periodic Maintenance Cost (Non MI)": validate_number(record['cost_bd_pm_nonmi'])/1000000, "Production (Bruto)": f"={get_abjad(seq_offset)}7/(100-SUM(Params!$C$16:$C$17))*100", "Production (Netto)": f"={get_abjad(seq_offset)}4*8760*Params!$C$15/100", "Fuel Consumption": f"={get_abjad(seq_offset)}6*Params!$C$18", "Revenue A": f"=(Params!$C$19*{get_abjad(seq_offset)}5*Params!$C$15*1000*12/100)/1000000", "Revenue B": f"=(Params!$C$20*{get_abjad(seq_offset)}5*Params!$C$15*1000*12/100)/1000000", "Revenue C": f"=Params!$C$21*{get_abjad(seq_offset)}7*1000/1000000", "Revenue D": f"=Params!$C$22*{get_abjad(seq_offset)}7*1000/1000000", "Fuel Cost": f"={get_abjad(seq_offset)}9*Params!$C$23/10^6" }) # Masukkan data ke Excel insert_column_data(file_ref, "Calc", record['tahun'], col_data) else: print("No data found.") # ====================================================== 00000 ================================================= # =============================================== SIMPAN UNTUK CHART ================================================= # ====================================================== 00000 ================================================= # Mapping dari kolom Excel ke nama kolom database sesuai gambar 2 libreoffice_path = "soffice" # Sesuaikan dengan lokasi di Linux/Windows command = f'"{libreoffice_path}" --headless --convert-to xlsx {file_ref} --outdir {ROOT_DIR}/hasil' subprocess.run(command, shell=True, check=True) print("recalculate OK") # def read_excel_with_pandas(file_path, sheet_name): # df = pd.read_excel(file_path, sheet_name=sheet_name, engine='openpyxl') # print(df.head()) # Periksa apakah nilai diambil dengan benar # read_excel_with_pandas(f"{file_hasil}", "Upload") # column_mapping = { "Total Revenue": "chart_total_revenue", "Revenue A": "chart_revenue_a", "Revenue B": "chart_revenue_b", "Revenue C": "chart_revenue_c", "Revenue D": "chart_revenue_d", "Revenue Annualized": "chart_revenue_annualized", "Fuel Cost (Component C)": "chart_fuel_cost_component_c", "Fuel Cost": "chart_fuel_cost", "Fuel Cost Annualized": "chart_fuel_cost_annualized", "O and M Cost (Component B and D)": "chart_oem_component_bd", "O and M Cost": "chart_oem_bd_cost", "Periodic Maintenance Cost (NonMI)": "chart_oem_periodic_maintenance_cost", "O and M Cost Annualized": "chart_oem_annualized", "Capex (Component A)": "chart_capex_component_a", "Biaya Investasi Tambahan": "chart_capex_biaya_investasi_tambahan", "Acquisition Cost": "chart_capex_acquisition_cost", "Capex Annualized": "chart_capex_annualized" } # Fungsi untuk memperbarui database def update_database_from_excel(): # Buka koneksi ke PostgreSQL try: # Load workbook dan pilih sheet wb = openpyxl.load_workbook(f"{file_hasil}", data_only=True) sheet = wb["Upload"] # Ambil tahun dari baris pertama mulai dari kolom ketiga years = [sheet.cell(row=1, column=col).value for col in range(3, sheet.max_column + 1)] # Loop melalui setiap baris di Excel mulai dari baris kedua for row in range(2, sheet.max_row + 1): row_name = sheet.cell(row=row, column=1).value # Nama data di kolom pertama row_name = row_name if row_name else sheet.cell(row=row,column=2).value # Nama data di kolom kedua jika kolom pertama kosong db_column = column_mapping.get(row_name) if db_column: for col_index, year in enumerate(years, start=3): # Iterasi mulai dari kolom ke-3 value = sheet.cell(row=row, column=col_index).value if value is None: continue # Lakukan update data ke database query = f""" UPDATE lcc_plant_tr_data SET {db_column} = %s WHERE tahun = %s """ seq = sheet.cell(row=row, column=2).value # Ambil seq dari kolom kedua jika dibutuhkan cur.execute(query, (value, year)) # Jalankan query dengan parameter conn.commit() print("Data successfully updated in database.") except Exception as e: conn.rollback() print(f"Error: {e}") update_database_from_excel() cur.close() conn.close() end_time = time.time() elapsed_time = end_time - start_time minutes = int(elapsed_time // 60) seconds = int(elapsed_time % 60) # Cetak hasil print(f"Execution time: {minutes} minutes and {seconds} seconds")