sglab02_lib 0.1.6

num sglab02
Documentation
use crate::sg::{dcl, dcl::DaVa, /*ldp,*/ ldp::base, uty::NumForm, wk5};
use askama::Template;
//use askama_axum;
use axum::extract::{Path, /*Query*/};
use regex::Regex;
use serde::{Deserialize, Serialize};
//use std::cmp::{Eq, Ord, PartialEq, PartialOrd};
//use std::collections::{HashMap, HashSet};
use std::sync::Arc;
//use financial;
//use thousands::Separable;
use tokio::sync::RwLock;
//use tokio::sync::{OwnedRwLockReadGuard, RwLockReadGuard};

#[derive(Template, Debug)]
#[template(path = "pg2/wk5x.html", escape = "none")]
pub struct ReportTemp {
    pub title: String,
    //pub wk: OwnedRwLockReadGuard<wk5::Wk5Proc>,
	//pub ssid: String,
	pub repo: Report,
}

#[allow(dead_code)]
fn rp(wk5prc: &wk5::Wk5Proc) -> &Report {
    &wk5prc.wk5x2
}

#[allow(dead_code)]
fn sp(wk5prc: &mut wk5::Wk5Proc, rp: Report) {
    wk5prc.wk5x2 = rp;
}

impl ReportTemp {
    pub fn repo(&self) -> &Report {
        &self.repo
    }
    async fn new(wk5prc: Arc<RwLock<wk5::Wk5Proc>>, ssid: String) -> Self {
        let wk = wk5prc.read_owned().await;
        let title = "IRR CALCULATION FOR SUBSTATION ".to_string();
		
		let mut repo = Report::default();

		for t in TT {
			repo.cols.push(t.to_string());
		}
		let cfg = base().config.read().await;
		let syf = cfg.criteria.start_year_from_2022;
		let imy = cfg.criteria.implement_year;
		let opy = cfg.criteria.operate_year;
		let yrl = syf + imy + opy;
		let yrl = yrl as usize;
		for i in 0..yrl {
			let yr = 2022 + i + 1;
			repo.cols.push(format!("{}", yr));
		}
		let mut s_list = Vec::new();
		for s in 0..wk.ssv.len() {
			//if wk5prc.ssv[s].ssid!="BLA" { continue; }
			if wk.ssv[s].ssid!=ssid { continue; }
			s_list.push(s);
		}
		
		let mut rw_solar_power = RepoRow1::default();
		rw_solar_power.item = "Solar power : MW".to_string();
		let mut rw_solar_day_energy = RepoRow1::default();
		rw_solar_day_energy.item = "Solar energy : MWH".to_string();
		let mut rw_solar_storage = RepoRow1::default();
		rw_solar_storage.item = "Solar storage : MWH".to_string();
		let mut rw_solar_revenue = RepoRow1::default();
		rw_solar_revenue.item = "Solar revenue : THB".to_string();
		let mut rw_storage_cost = RepoRow1::default();
		rw_storage_cost.item = "Storage cost : THB".to_string();
		let mut rw_trx_cost = RepoRow1::default();
		rw_trx_cost.item = "Tranx cost : THB".to_string();
		let mut rw_m1p_cost = RepoRow1::default();
		rw_m1p_cost.item = "Meter 1 cost : THB".to_string();
		let mut rw_m3p_cost = RepoRow1::default();
		rw_m3p_cost.item = "Meter 3 cost : THB".to_string();
		let mut rw_comm_cost = RepoRow1::default();
		rw_comm_cost.item = "Commu cost : THB".to_string();
		let mut rw_plat_cost = RepoRow1::default();
		rw_plat_cost.item = "Platform cost : THB".to_string();
		let mut rw_impl_cost = RepoRow1::default();
		rw_impl_cost.item = "Implement cost : THB".to_string();
		let mut rw_oper_cost = RepoRow1::default();
		rw_oper_cost.item = "Operation cost : THB".to_string();
		let mut rw_read_cost = RepoRow1::default();
		rw_read_cost.item = "Reading cost : THB".to_string();
		let mut rw_ev_car = RepoRow1::default();
		rw_ev_car.item = "EV car number".to_string();
		let mut rw_ev_power = RepoRow1::default();
		rw_ev_power.item = "EV Power : MW".to_string();
		let mut rw_ev_energy = RepoRow1::default();
		rw_ev_energy.item = "EV Energy : MWH".to_string();
		let mut rw_ev_revenue = RepoRow1::default();
		rw_ev_revenue.item = "EV Revenue : THB".to_string();

		let mut rw_oper_cost_trx = RepoRow1::default();
		rw_oper_cost_trx.item = "Operation trx : THB".to_string();
		let mut rw_oper_cost_m1p = RepoRow1::default();
		rw_oper_cost_m1p.item = "Operation m1p : THB".to_string();
		let mut rw_oper_cost_m3p = RepoRow1::default();
		rw_oper_cost_m3p.item = "Operation m3p : THB".to_string();
		let mut rw_oper_cost_ess = RepoRow1::default();
		rw_oper_cost_ess.item = "Operation ess : THB".to_string();

		let mut rw_fin_return = RepoRow1::default();
		rw_fin_return.item = "Fin return : THB".to_string();
		let mut rw_all_cost = RepoRow1::default();
		rw_all_cost.item = "All cost : THB".to_string();
		let mut rw_cash_flow = RepoRow1::default();
		rw_cash_flow.item = "Cash flow: THB".to_string();

		let mut rw_fin_45 = RepoRow1::default();
		rw_fin_45.item = "Fin 4.5% : THB".to_string();
		let mut rw_cost_45 = RepoRow1::default();
		rw_cost_45.item = "Cost 4.5% : THB".to_string();
		
		let mut rw_fin_10 = RepoRow1::default();
		rw_fin_10.item = "Fin 10% : THB".to_string();
		let mut rw_cost_10 = RepoRow1::default();
		rw_cost_10.item = "Cost 10% : THB".to_string();
		
		let mut rw_fin_15 = RepoRow1::default();
		rw_fin_15.item = "Fin 14.5% : THB".to_string();
		let mut rw_cost_15 = RepoRow1::default();
		rw_cost_15.item = "Cost 14.5% : THB".to_string();

		let mut rw_inve_ret = RepoRow1::default();
		rw_inve_ret.item = "Investor : THB".to_string();
		
		for i in 0..17 {
			rw_solar_power.amts.push(0f32);
			rw_solar_day_energy.amts.push(0f32);
			rw_solar_storage.amts.push(0f32);
			rw_solar_revenue.amts.push(0f32);
			rw_storage_cost.amts.push(0f32);
			rw_trx_cost.amts.push(0f32);
			rw_m1p_cost.amts.push(0f32);
			rw_m3p_cost.amts.push(0f32);
			rw_comm_cost.amts.push(0f32);
			rw_plat_cost.amts.push(0f32);
			rw_impl_cost.amts.push(0f32);
			rw_oper_cost.amts.push(0f32);
			rw_read_cost.amts.push(0f32);
			rw_ev_car.amts.push(0f32);
			rw_ev_power.amts.push(0f32);
			rw_ev_energy.amts.push(0f32);
			rw_ev_revenue.amts.push(0f32);
			rw_fin_return.amts.push(0f32);
			rw_all_cost.amts.push(0f32);
			rw_cash_flow.amts.push(0f32);
			rw_fin_45.amts.push(0f32);
			rw_cost_45.amts.push(0f32);
			rw_fin_10.amts.push(0f32);
			rw_cost_10.amts.push(0f32);
			rw_fin_15.amts.push(0f32);
			rw_cost_15.amts.push(0f32);

			rw_oper_cost_trx.amts.push(0f32);
			rw_oper_cost_m1p.amts.push(0f32);
			rw_oper_cost_m3p.amts.push(0f32);
			rw_oper_cost_ess.amts.push(0f32);

			let mut invr = 360000000f32;
			if i<5 { invr = 0f32; }
			rw_inve_ret.amts.push(invr);
			//rw_all_cost.amts[i] += invr;
			//rw_all_cost.sum1 += invr;
		}
		let re = Regex::new(r"..._[0-9][0-9].+").unwrap();
		for s in s_list {
			for f in 0..wk.ssv[s].feeders.len() {
				let fd = &wk.ssv[s].feeders[f];
				if re.is_match(fd.fdid.as_str()) {
					if fd.ev.ev_ds > 0.0 && fd.tx.tx_no > 0 {
						rw_trx_cost.sum2 += fd.tx.tx_no as f32;
						rw_m1p_cost.sum2 += fd.tx.mt1_no as f32;
						rw_m3p_cost.sum2 += fd.tx.mt3_no as f32;
						for i in 0..17 {
							rw_solar_power.amts[i] += fd.solar_power_series[i];
							rw_solar_day_energy.amts[i] += fd.solar_day_energy_series[i];
							rw_solar_storage.amts[i] += fd.solar_storage_series[i];
							rw_solar_revenue.amts[i] += fd.solar_revenue_series[i];
							rw_solar_revenue.sum1 += fd.solar_revenue_series[i];
							rw_storage_cost.amts[i] += fd.solar_storage_cost_series[i];
							rw_storage_cost.sum1 += fd.solar_storage_cost_series[i];
							rw_trx_cost.amts[i] += fd.smart_trx_cost_series[i];
							rw_trx_cost.sum1 += fd.smart_trx_cost_series[i];
							
							rw_m1p_cost.amts[i] += fd.smart_m1p_cost_series[i];
							rw_m1p_cost.sum1 += fd.smart_m1p_cost_series[i];

							rw_m3p_cost.amts[i] += fd.smart_m3p_cost_series[i];
							rw_m3p_cost.sum1 += fd.smart_m3p_cost_series[i];

							rw_comm_cost.amts[i] += fd.comm_cost_year_series[i];
							rw_comm_cost.sum1 += fd.comm_cost_year_series[i];

							rw_plat_cost.amts[i] += fd.platform_cost_series[i];
							rw_plat_cost.sum1 += fd.platform_cost_series[i];

							rw_impl_cost.amts[i] += fd.implement_cost_series[i];
							rw_impl_cost.sum1 += fd.implement_cost_series[i];

							rw_oper_cost.amts[i] += fd.operation_cost_series[i];
							rw_oper_cost.sum1 += fd.operation_cost_series[i];

							rw_read_cost.amts[i] += fd.meter_reading_cost_series[i];
							rw_read_cost.sum1 += fd.meter_reading_cost_series[i];
							
							rw_ev_car.amts[i] += fd.ev_car_series[i];
							rw_ev_car.sum1 += fd.ev_car_series[i];
							
							rw_ev_power.amts[i] += fd.ev_power_series[i];
							rw_ev_power.sum1 += fd.ev_power_series[i];
							
							rw_ev_energy.amts[i] += fd.ev_energy_series[i];
							rw_ev_energy.sum1 += fd.ev_energy_series[i];
							
							rw_ev_revenue.amts[i] += fd.ev_revenue_series[i];
							rw_ev_revenue.sum1 += fd.ev_revenue_series[i];
							
							rw_fin_return.amts[i] += fd.financial_benefit_series[i];
							rw_fin_return.sum1 += fd.financial_benefit_series[i];

							rw_all_cost.amts[i] += fd.total_cost_series[i];
							rw_all_cost.sum1 += fd.total_cost_series[i];

							rw_oper_cost_trx.amts[i] += fd.operation_cost_trx_series[i];
							rw_oper_cost_trx.sum1 += fd.operation_cost_trx_series[i];

							rw_oper_cost_m1p.amts[i] += fd.operation_cost_m1p_series[i];
							rw_oper_cost_m1p.sum1 += fd.operation_cost_m1p_series[i];

							rw_oper_cost_m3p.amts[i] += fd.operation_cost_m3p_series[i];
							rw_oper_cost_m3p.sum1 += fd.operation_cost_m3p_series[i];

							rw_oper_cost_ess.amts[i] += fd.operation_cost_ess_series[i];
							rw_oper_cost_ess.sum1 += fd.operation_cost_ess_series[i];

						}
					}
				}
			}
		}
		let rt45 = 0.045f32;
		let rt10 = 0.1f32;
		let rt15 = 0.145f32;
		for i in 0..15 {
			let t = i as f32 + 1f32;
			
			let deno : f32 = 1.0 + rt45;
			let deno : f32 = deno.powf(t);
			rw_fin_45.amts[i+2] = rw_fin_return.amts[i+2] / deno;
			rw_cost_45.amts[i+2] = rw_all_cost.amts[i+2] / deno;
			
			let deno : f32 = 1.0 + rt10;
			let deno : f32 = deno.powf(t);
			rw_fin_10.amts[i+2] = rw_fin_return.amts[i+2] / deno;
			rw_cost_10.amts[i+2] = rw_all_cost.amts[i+2] / deno;
			
			let deno : f32 = 1.0 + rt15;
			let deno : f32 = deno.powf(t);
			rw_fin_15.amts[i+2] = rw_fin_return.amts[i+2] / deno;
			rw_cost_15.amts[i+2] = rw_all_cost.amts[i+2] / deno;
		}
		for i in 0..17 {
			rw_cash_flow.amts[i] = rw_fin_return.amts[i] - rw_all_cost.amts[i];
			rw_cash_flow.sum1 += rw_cash_flow.amts[i];
			rw_fin_45.sum1 += rw_fin_45.amts[i];
			rw_cost_45.sum1 += rw_cost_45.amts[i];
			rw_fin_10.sum1 += rw_fin_10.amts[i];
			rw_cost_10.sum1 += rw_cost_10.amts[i];
			rw_fin_15.sum1 += rw_fin_15.amts[i];
			rw_cost_15.sum1 += rw_cost_15.amts[i];
		}
		let mut cashflow = vec![];
		for cf in &rw_cash_flow.amts {
			let cf = *cf as f64;
			cashflow.push(cf);
		}
		let irr = financial::irr(&cashflow, None).unwrap();
		rw_cash_flow.sum1 = irr as f32 * 100.0;
		
		repo.rows.push(rw_solar_power);
		repo.rows.push(rw_solar_day_energy);
		repo.rows.push(rw_solar_storage);
		repo.rows.push(rw_solar_revenue);
		
		repo.rows.push(rw_ev_car);
		repo.rows.push(rw_ev_power);
		repo.rows.push(rw_ev_energy);
		repo.rows.push(rw_ev_revenue);
		
		repo.rows.push(rw_storage_cost);
		repo.rows.push(rw_trx_cost);
		repo.rows.push(rw_m1p_cost);
		repo.rows.push(rw_m3p_cost);
		
		repo.rows.push(rw_oper_cost_trx);
		repo.rows.push(rw_oper_cost_m1p);
		repo.rows.push(rw_oper_cost_m3p);
		repo.rows.push(rw_oper_cost_ess);
		
		repo.rows.push(rw_comm_cost);
		repo.rows.push(rw_plat_cost);
		repo.rows.push(rw_impl_cost);
		repo.rows.push(rw_oper_cost);
		repo.rows.push(rw_inve_ret);
		repo.rows.push(rw_read_cost);
		
		repo.rows.push(rw_fin_return);
		repo.rows.push(rw_all_cost);
		repo.rows.push(rw_cash_flow);
		
		/*
		repo.rows.push(rw_fin_45);
		repo.rows.push(rw_cost_45);
		repo.rows.push(rw_fin_10);
		repo.rows.push(rw_cost_10);
		repo.rows.push(rw_fin_15);
		repo.rows.push(rw_cost_15);
		*/
		
        ReportTemp { /*wk,*/ title, /*ssid,*/ repo, }
    }
    pub fn cell(&self, r: &usize, c: &usize) -> String {
        let ce = self.repo.dava(*r, *c);
        match ce {
            DaVa::Text(s) => s,
            DaVa::F32(f) => f.form(),
            DaVa::F64(f) => f.form(),
            DaVa::USZ(u) => format!("{}", u),
            d => format!("{:?}", d),
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Report {
    pub rows: Vec<RepoRow1>,
    pub cols: Vec<String>,
}

#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct RepoRow1 {
    pub s: usize, // substation
    pub f: usize, // feeder
	pub item: String,
	pub sum1: f32,
	pub sum2: f32,
	pub amts: Vec<f32>,
}

const TT: [&str; 4] = ["NO", "ITEM NAME ---------", "SUM1", "SUM2"];

pub async fn make_repo(_wk5prc: &mut wk5::Wk5Proc, _acfg: Arc<RwLock<dcl::Config>>) {
}

impl Report {
    pub fn dava(&self, r: usize, c: usize) -> dcl::DaVa {
		let rw = &self.rows[r];
        //let ss = &ssv[s];
        //let fd = &ssv[s].feeders[f];
        match c {
            0 => DaVa::USZ(r + 1),
            1 => DaVa::Text(rw.item.to_string()),
            2 => DaVa::F32(rw.sum1),
            3 => DaVa::F32(rw.sum2),
            n => DaVa::F32(rw.amts[n - 4]),
        }
    }
}

pub async fn handler(Path(ssid): Path<String>) -> ReportTemp {
    ReportTemp::new(base().wk5prc.clone(), ssid.to_string()).await
}