|
|
def format_number_for_table(value): |
|
|
"""用于表格的数字格式化:自动 B/M,保留适当小数""" |
|
|
if value is None or value == 0: |
|
|
return "0" |
|
|
if abs(value) >= 1_000_000_000: |
|
|
num = value / 1_000_000_000 |
|
|
if num.is_integer(): |
|
|
return f"{int(num)}B" |
|
|
else: |
|
|
return f"{num:.2f}B".rstrip('0').rstrip('.') |
|
|
elif abs(value) >= 1_000_000: |
|
|
num = value / 1_000_000 |
|
|
if num.is_integer(): |
|
|
return f"{int(num)}M" |
|
|
else: |
|
|
return f"{num:.1f}M".rstrip('0').rstrip('.') |
|
|
else: |
|
|
return f"{value:,.1f}".rstrip('0').rstrip('.') |
|
|
|
|
|
def safe_float_or_zero(val): |
|
|
if val is None: |
|
|
return 0.0 |
|
|
try: |
|
|
return float(val) |
|
|
except (ValueError, TypeError): |
|
|
return 0.0 |
|
|
|
|
|
def calculate_yoy_rate(current, previous): |
|
|
if previous == 0: |
|
|
return "+0.0%" if current >= 0 else "-0.0%" |
|
|
rate = (current - previous) / abs(previous) * 100 |
|
|
sign = "+" if rate >= 0 else "-" |
|
|
return f"{sign}{abs(rate):.1f}%" |
|
|
|
|
|
def build_table_format(three_year_data): |
|
|
|
|
|
sorted_data = sorted(three_year_data, key=lambda x: x["fiscal_year"], reverse=True) |
|
|
|
|
|
|
|
|
year_labels = [] |
|
|
for item in sorted_data: |
|
|
if item['level'] == 'FY': |
|
|
year_labels.append(f"FY {item['fiscal_year']}") |
|
|
else: |
|
|
year_labels.append(f"{item['fiscal_year']} {item['level']}") |
|
|
|
|
|
|
|
|
while len(sorted_data) < 3: |
|
|
sorted_data.append({ |
|
|
"fiscal_year": 0, |
|
|
"level": "N/A", |
|
|
"total_revenue": 0, |
|
|
"net_income": 0, |
|
|
"earnings_per_share": 0.0, |
|
|
"operating_expenses": 0, |
|
|
"operating_cash_flow": 0 |
|
|
}) |
|
|
year_labels.append("N/A") |
|
|
|
|
|
|
|
|
y0, y1, y2 = sorted_data[0], sorted_data[1], sorted_data[2] |
|
|
|
|
|
|
|
|
list_data = [ |
|
|
["Category"] + year_labels[:3], |
|
|
["Total Revenue", |
|
|
format_number_for_table(safe_float_or_zero(y0["total_revenue"])), |
|
|
format_number_for_table(safe_float_or_zero(y1["total_revenue"])), |
|
|
format_number_for_table(safe_float_or_zero(y2["total_revenue"]))], |
|
|
["Net Income", |
|
|
format_number_for_table(safe_float_or_zero(y0["net_income"])), |
|
|
format_number_for_table(safe_float_or_zero(y1["net_income"])), |
|
|
format_number_for_table(safe_float_or_zero(y2["net_income"]))], |
|
|
["Earnings Per Share", |
|
|
f"{safe_float_or_zero(y0['earnings_per_share']):.2f}", |
|
|
f"{safe_float_or_zero(y1['earnings_per_share']):.2f}", |
|
|
f"{safe_float_or_zero(y2['earnings_per_share']):.2f}"], |
|
|
["Operating Expenses", |
|
|
format_number_for_table(safe_float_or_zero(y0["operating_expenses"])), |
|
|
format_number_for_table(safe_float_or_zero(y1["operating_expenses"])), |
|
|
format_number_for_table(safe_float_or_zero(y2["operating_expenses"]))], |
|
|
["Operating Cash Flow", |
|
|
format_number_for_table(safe_float_or_zero(y0["operating_cash_flow"])), |
|
|
format_number_for_table(safe_float_or_zero(y1["operating_cash_flow"])), |
|
|
format_number_for_table(safe_float_or_zero(y2["operating_cash_flow"]))] |
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
yoy_rates = [ |
|
|
["Category"] + year_labels[:3], |
|
|
["Total Revenue", |
|
|
calculate_yoy_rate(safe_float_or_zero(y0["total_revenue"]), safe_float_or_zero(y1["total_revenue"])), |
|
|
calculate_yoy_rate(safe_float_or_zero(y1["total_revenue"]), safe_float_or_zero(y2["total_revenue"])), |
|
|
"--"], |
|
|
["Net Income", |
|
|
calculate_yoy_rate(safe_float_or_zero(y0["net_income"]), safe_float_or_zero(y1["net_income"])), |
|
|
calculate_yoy_rate(safe_float_or_zero(y1["net_income"]), safe_float_or_zero(y2["net_income"])), |
|
|
"--"], |
|
|
["Earnings Per Share", |
|
|
calculate_yoy_rate(safe_float_or_zero(y0["earnings_per_share"]), safe_float_or_zero(y1["earnings_per_share"])), |
|
|
calculate_yoy_rate(safe_float_or_zero(y1["earnings_per_share"]), safe_float_or_zero(y2["earnings_per_share"])), |
|
|
"--"], |
|
|
["Operating Expenses", |
|
|
calculate_yoy_rate(safe_float_or_zero(y0["operating_expenses"]), safe_float_or_zero(y1["operating_expenses"])), |
|
|
calculate_yoy_rate(safe_float_or_zero(y1["operating_expenses"]), safe_float_or_zero(y2["operating_expenses"])), |
|
|
"--"], |
|
|
["Operating Cash Flow", |
|
|
calculate_yoy_rate(safe_float_or_zero(y0["operating_cash_flow"]), safe_float_or_zero(y1["operating_cash_flow"])), |
|
|
calculate_yoy_rate(safe_float_or_zero(y1["operating_cash_flow"]), safe_float_or_zero(y2["operating_cash_flow"])), |
|
|
"--"] |
|
|
] |
|
|
|
|
|
return { |
|
|
"list_data": list_data, |
|
|
"yoy_rates": yoy_rates |
|
|
} |