All files / src/pages/flowsheet-page/economics/results-panel/model resultLineSelectors.ts

26.76% Statements 19/71
10.34% Branches 3/29
55.55% Functions 5/9
26.78% Lines 15/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185                    76x                 76x 76x 76x 76x           76x                                     76x                                                                         78x               188x       100x       5x   100x                                                                                                   17x 5x 15x                                                            
import type { EconomicsResultLineRead } from "@/api/apiStore.gen";
import { EconomicsResultLineKindEnum } from "@/api/apiStore.gen";
import type { DetailSectionValue } from "./types";
import {
  isPresent,
  numericField,
  objectValue,
  stringField,
} from "./valueParsing";
 
export const OPERATING_EXPENSE_LABELS = [
  "Derived fuel costs",
  "Utility costs",
  "Feedstock costs",
  "Disposal costs",
  "Maintenance",
  "Labour",
  "Custom",
];
export const ANNUAL_EXPENSES_ROW_KEY = "metric.annual_opex";
export const ANNUAL_REVENUE_ROW_KEY = "metric.annual_revenue";
export const ANNUAL_PROFIT_ROW_KEY = "metric.annual_profit";
export const OPERATING_SUMMARY_ROW_KEYS = [
  ANNUAL_EXPENSES_ROW_KEY,
  ANNUAL_REVENUE_ROW_KEY,
  ANNUAL_PROFIT_ROW_KEY,
];
 
export const KEY_FINANCIAL_METRIC_ROWS = [
  { rowKey: "metric.simple_payback_years", label: "Payback period" },
  { rowKey: "metric.annual_savings", label: "Annual savings" },
  {
    rowKey: "metric.after_tax_annual_cash_flow",
    label: "After-tax annual cash flow",
  },
  { rowKey: "metric.annual_depreciation", label: "Annual depreciation" },
  {
    rowKey: "metric.depreciation_tax_shield",
    label: "Depreciation tax shield",
  },
  { rowKey: "metric.capex", label: "Total capital cost" },
  { rowKey: "metric.incremental_capex", label: "Incremental capital cost" },
  { rowKey: "metric.annual_opex", label: "Annual operating cost" },
  { rowKey: "metric.npv", label: "NPV" },
  { rowKey: "metric.roi_percent", label: "ROI" },
  { rowKey: "metric.lcoh", label: "LCOH" },
] as const;
export const DEPRECIATION_METRIC_ROW_KEYS = new Set([
  "metric.annual_depreciation",
  "metric.depreciation_tax_shield",
  "metric.after_tax_annual_cash_flow",
]);
 
export function detailSectionsForLineId(
  lines: EconomicsResultLineRead[],
  lineId: number,
): DetailSectionValue[] {
  const line = lines.find((candidate) => candidate.id === lineId);
  Iif (!line) return [];
  if (line.kind === EconomicsResultLineKindEnum.Capital) {
    return ["capital-summary"];
  }
  if (line.kind === EconomicsResultLineKindEnum.Operating) {
    return ["resource-breakdown", "operating-breakdown", "operating-summary"];
  }
  if (line.kind === EconomicsResultLineKindEnum.Depreciation) {
    return ["depreciation-tax"];
  }
  if (line.kind === EconomicsResultLineKindEnum.FinancialMetric) {
    if (DEPRECIATION_METRIC_ROW_KEYS.has(line.row_key)) {
      return ["depreciation-tax"];
    }
    return [];
  }
  if (line.kind === EconomicsResultLineKindEnum.CashFlow) {
    return ["calculation-trace"];
  }
  return [];
}
 
export function mergeDetailSections(
  explicitSections: DetailSectionValue[],
  selectedRowSections: DetailSectionValue[],
): DetailSectionValue[] {
  if (selectedRowSections.length === 0) return explicitSections;
  return Array.from(new Set([...explicitSections, ...selectedRowSections]));
}
 
export function linesByKind(
  lines: EconomicsResultLineRead[],
  kind: EconomicsResultLineKindEnum,
) {
  return lines.filter((line) => line.kind === kind);
}
 
export function depreciationMetricRows(lines: EconomicsResultLineRead[]) {
  return lines.filter((line) => DEPRECIATION_METRIC_ROW_KEYS.has(line.row_key));
}
 
export function depreciationDetailRows(lines: EconomicsResultLineRead[]) {
  return lines.filter(
    (line) =>
      line.kind === EconomicsResultLineKindEnum.Depreciation &&
      line.group === "depreciation_lines",
  );
}
 
export function operatingBreakdownRows(lines: EconomicsResultLineRead[]) {
  const grouped = new Map<string, EconomicsResultLineRead[]>();
  for (const line of lines) {
    const label = operatingBreakdownLabel(line);
    Iif (!label) continue;
    grouped.set(label, [...(grouped.get(label) ?? []), line]);
  }
  return grouped;
}
 
export function operatingExpenseRows(lines: EconomicsResultLineRead[]) {
  return lines.filter(
    (line) => line.group === "operating_lines" && !operatingLineIsRevenue(line),
  );
}
 
export function revenueRows(lines: EconomicsResultLineRead[]) {
  return lines.filter(
    (line) => line.group === "operating_lines" && operatingLineIsRevenue(line),
  );
}
 
export function resourceBreakdownRows(lines: EconomicsResultLineRead[]) {
  const grouped = new Map<string, EconomicsResultLineRead[]>();
  for (const line of lines) {
    Iif (line.group !== "operating_lines") continue;
    const category = resourceBreakdownCategory(line);
    Iif (!category) continue;
    grouped.set(category, [...(grouped.get(category) ?? []), line]);
  }
  return grouped;
}
 
export function resourceBreakdownCategory(line: EconomicsResultLineRead) {
  return stringField(line.resource_breakdown_category);
}
 
export function sumLineAmounts(lines: EconomicsResultLineRead[]) {
  return lines.reduce(
    (total, line) => total + (numericField(line.amount) ?? 0),
    0,
  );
}
 
export function operatingSummaryRows(lines: EconomicsResultLineRead[]) {
  const byRowKey = new Map(lines.map((line) => [line.row_key, line]));
  return OPERATING_SUMMARY_ROW_KEYS.map((rowKey) =>
    byRowKey.get(rowKey),
  ).filter(isPresent);
}
 
export function operatingBreakdownLabel(line: EconomicsResultLineRead) {
  const category = operatingCategory(line);
  if (category === "energy") {
    return operatingLineIsRevenue(line) ? "Utility credits" : "Utility costs";
  }
  Iif (category === "feedstock") return "Feedstock costs";
  Iif (category === "output_revenue") return "Sold output revenue";
  Iif (category === "disposal") return "Disposal costs";
  Iif (category === "maintenance") return "Maintenance";
  Iif (category === "labour") return "Labour";
  Iif (category === "fixed_annual") return null;
  return "Custom";
}
 
export function operatingCategory(line: EconomicsResultLineRead) {
  const payload = objectValue(line.warning_payload);
  return stringField(payload?.category || payload?.line_type);
}
 
export function operatingLineIsRevenue(line: EconomicsResultLineRead) {
  const payload = objectValue(line.warning_payload);
  return (
    stringField(payload?.economic_effect) === "revenue" ||
    stringField(payload?.category) === "output_revenue"
  );
}