2025年財務分析報告

執行長診斷:營收與毛利下滑原因分析

Published

December 14, 2025

Code
import sys
sys.path.insert(0, ".")

import polars as pl
import altair as alt
import ibis
from ibis import _
from python.db_connection import get_db_connection
from great_tables import GT

# Connect to database
con = get_db_connection()

# Valid delivery routes per about.qmd
VALID_ROUTES = ["A-PT", "A-PH", "A-PN", "A-PS", "A-PK", "K1", "K2", "PT", "PH", "PS", "PK"]
# For YoY: exclude PH (operational change Dec 2024)
VALID_ROUTES_YOY = ["A-PT", "A-PN", "A-PS", "A-PK", "K1", "K2", "PT", "PS", "PK"]
# For route analysis: A-PK and K2 should be combined due to 2024-2025 route reorg
COMBINED_APK_K2 = ["A-PK", "K2"]

# Load tables with only needed columns to avoid join collisions
sales_orders = (
    con.table("sales_orders", database="cosmos_sync")
    .filter(_.confirmed_code == "Y")
    .select("order_type", "order_number", "customer_code", "delivery_route", "order_date")
)
sales_order_lines = (
    con.table("sales_order_lines", database="cosmos_sync")
    .select("order_type", "order_number", "item_code", "warehouse_code", 
            "quantity", "promo_quantity", "pretax_subtotal")
)
customers = (
    con.table("customers", database="cosmos_sync")
    .select("customer_code", "trade_name", "delivery_route", "closure_date")
    .rename(customer_route="delivery_route")  # Rename to avoid collision
)
product_info = (
    con.table("product_information", database="cosmos_sync")
    .select("product_code", "product_name", "product_category_1", "product_category_2")
)
procurement_costs = (
    con.table("procurement_costs", database="cosmos_sync")
    .select("product_code", "inventory_month", "unit_cost")
)

# Category names for display
CAT_NAMES = {
    "1": "1-生產製造 (Internal)",
    "2": "2-成品",
    "3": "3-生產分裝",
    "4": "4-冷藏類",
    "5": "5-冷凍類",
    "6": "6-器具類",
    "7": "7-免洗餐具",
    "8": "8-酒/咖啡豆",
    "9": "9-調味添加物",
    "10": "10-其他"
}

執行摘要

Important重點結論

配送營收下滑 1.4% (210萬元) + 門市下滑 4.5% (620萬元) = 總計約830萬元衰退

根本原因(依影響程度排序):

  1. 🏪 門市營收衰退:全店共減少620萬元
    • 潮州店最嚴重(-350萬,-6.9%)
    • 交易筆數下滑5-10% = 進店顧客減少
  2. 📦 客戶訂購量縮減:客戶訂購數量減少(非轉換產品)導致減少750萬元
    • 63位客戶同品項訂購量減少37%
    • 此現象顯示其終端消費者需求下降
  3. 🎖️ 軍營業績大幅下滑:減少130萬元
    • 加祿堂營區:-82.5萬(數量-89%)
    • 萬金營區:-52.3萬(數量-51%)
  4. 🍗 連鎖客戶衰退
    • 昌平炸雞:約100萬(16個據點停止訂購)
    • 萊恩快速早餐:-120萬(4個據點在前15大衰退名單中)
    • 香醇軒:-84萬(3個據點)

關鍵洞察:客戶並非轉向競爭對手——他們是因為自身生意下滑而減少採購

Tip市場環境:主要是需求放緩 + 少數競爭流失

2025年上半年→下半年 159位活躍客戶分析:

原因 客戶數 營收影響
📦 需求下降(數量減少,品項相同) 83 (52%) -350萬元
🗑️ 競爭流失(停購我方品項) 7 (4%) -27.8萬元

業務團隊確認的競爭流失(上述以外):

客戶 流失至 原因
昌平(約100萬) 其他供應商 總部要求與雞肉廠商統一配送
沫晨 啟順 配送時間 + 價格

結論:多數衰退為需求驅動(無法透過降價解決),但我們確實流失了昌平和沫晨給競爭對手。昌平難以挽回(物流問題),但沫晨可能有機會爭取回來。

Note資料說明
  • 類別1(內部製造)因2025年1月會計調整,已從毛利比較中排除
  • 路線PH因2024年12月營運調整,已從年度比較中排除
  • 路線A-PK與K2已合併分析,因2024-2025年路線重組

1. 營收:真實情況

1.1 年度營收摘要

Code
# Build the revenue summary using Ibis
sales_with_lines = (
    sales_orders
    .filter(_.delivery_route.isin(VALID_ROUTES_YOY))
    .filter(_.order_date >= "20240101")
    .filter(_.order_date < "20251201")
    .left_join(sales_order_lines, ["order_type", "order_number"])
    .left_join(product_info, _.item_code == product_info.product_code)
    # Exclude Category 1 (internal manufacturing)
    .filter((_.product_category_1.isnull()) | (_.product_category_1 != "1"))
    .mutate(year=_.order_date.left(4))
)

summary = (
    sales_with_lines
    .group_by("year")
    .agg(
        revenue=_.pretax_subtotal.cast("float64").sum(),
        customers=_.customer_code.nunique(),
        orders=_.order_number.nunique()
    )
    .mutate(
        rev_per_customer=(_.revenue / _.customers.cast("float64")).cast("int64"),
        avg_order_value=(_.revenue / _.orders.cast("float64")).cast("int64")
    )
    .order_by("year")
    .to_polars()
)

(
    GT(summary)
    .tab_header(
        title="YoY Revenue Summary (Jan-Nov, External Products)",
        subtitle="Excluding Category 1 (internal) and PH route (not comparable)"
    )
    .fmt_currency(["revenue", "rev_per_customer", "avg_order_value"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["customers", "orders"], decimals=0, use_seps=True)
)
YoY Revenue Summary (Jan-Nov, External Products)
Excluding Category 1 (internal) and PH route (not comparable)
year revenue customers orders rev_per_customer avg_order_value
2024 NT$160,548,153 1,641 13,326 NT$97,836 NT$12,048
2025 NT$144,407,026 1,583 12,126 NT$91,224 NT$11,909
Note關鍵觀察
  • 營收下滑210萬元(1.4%)- 並非災難性
  • 客戶數減少37位(-2.3%)
  • 訂單數量基本持平
  • 客單價微幅上升(91K vs 90K)
  • 結論:我們流失了客戶,但留下的客戶消費穩定

1.2 月度趨勢

Code
monthly = (
    sales_with_lines
    .mutate(month=_.order_date.left(6))
    .group_by("month")
    .agg(
        revenue=_.pretax_subtotal.cast("float64").sum(),
        customers=_.customer_code.nunique()
    )
    .order_by("month")
    .to_polars()
)

chart = alt.Chart(monthly).mark_bar(opacity=0.7).encode(
    x=alt.X("month:O", title="Month", axis=alt.Axis(labelAngle=-45)),
    y=alt.Y("revenue:Q", title="Revenue (TWD)"),
    color=alt.condition(
        alt.datum.month >= "202501",
        alt.value("coral"),
        alt.value("steelblue")
    ),
    tooltip=["month", "revenue", "customers"]
).properties(width=700, height=300, title="Monthly Revenue: 2024 (blue) vs 2025 (coral)")

chart

Monthly Revenue Trend

2. 客戶分析:流失是問題核心

2.1 客戶分群

Code
# Calculate revenue by customer for each year using Ibis
rev_2024 = (
    sales_with_lines
    .filter(_.year == "2024")
    .group_by("customer_code")
    .agg(rev_2024=_.pretax_subtotal.cast("float64").sum())
    .to_polars()
)

rev_2025 = (
    sales_with_lines
    .filter(_.year == "2025")
    .group_by("customer_code")
    .agg(rev_2025=_.pretax_subtotal.cast("float64").sum())
    .to_polars()
)

# Full outer join in Polars and classify segments
customer_revenue = (
    rev_2024
    .join(rev_2025, on="customer_code", how="full", coalesce=True)
    .fill_null(0)
    .with_columns(
        pl.when((pl.col("rev_2024") > 0) & (pl.col("rev_2025") == 0))
          .then(pl.lit("❌ LOST"))
          .when((pl.col("rev_2024") == 0) & (pl.col("rev_2025") > 0))
          .then(pl.lit("✅ NEW"))
          .when((pl.col("rev_2024") > 0) & (pl.col("rev_2025") > 0))
          .then(pl.lit("🔄 RETAINED"))
          .otherwise(pl.lit("OTHER"))
          .alias("segment")
    )
)

# Aggregate by segment
segments = (
    customer_revenue
    .group_by("segment")
    .agg(
        pl.count().alias("customers"),
        pl.col("rev_2024").sum().alias("revenue_2024"),
        pl.col("rev_2025").sum().alias("revenue_2025")
    )
    .with_columns(
        (pl.col("revenue_2025") - pl.col("revenue_2024")).alias("yoy_delta")
    )
    .filter(pl.col("segment") != "OTHER")
    .sort("revenue_2024", descending=True)
)

(
    GT(segments)
    .tab_header(
        title="Customer Segments: Where Revenue Came From",
        subtitle="Lost vs New vs Retained customers"
    )
    .fmt_currency(["revenue_2024", "revenue_2025", "yoy_delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number("customers", decimals=0, use_seps=True)
)
Customer Segments: Where Revenue Came From
Lost vs New vs Retained customers
segment customers revenue_2024 revenue_2025 yoy_delta
🔄 RETAINED 1,383 NT$155,963,869 NT$139,650,903 −NT$16,312,966
❌ LOST 255 NT$4,584,284 NT$0 −NT$4,584,284
✅ NEW 197 NT$0 NT$4,756,123 NT$4,756,123
Warning數字分析
  • 流失客戶:減少450萬營收
  • 新客戶:增加530萬營收
  • 留存客戶:消費減少290萬
  • 淨值:-210萬

結論:我們獲取了足夠的新客戶,但現有客戶消費減少,且流失了一些重要帳戶。

2.2 流失客戶:歇業 vs. 競爭流失

Code
# Get customers who ordered in 2024 but not in 2025
lost_customers = (
    customer_revenue
    .filter(pl.col("segment") == "❌ LOST")
    .select(["customer_code", "rev_2024"])
)

# Join with customer info including closure_date
lost_with_info = (
    customers
    .to_polars()
    .join(lost_customers, on="customer_code", how="inner")
    .rename({"rev_2024": "lost_revenue", "customer_route": "delivery_route"})
    .with_columns(
        pl.when(pl.col("closure_date").is_not_null())
          .then(pl.lit("🔒 CLOSED SHOP"))
          .otherwise(pl.lit("⚠️ POTENTIAL COMPETITOR"))
          .alias("status")
    )
)

# Summary by status
status_summary = (
    lost_with_info
    .group_by("status")
    .agg(
        pl.count().alias("customer_count"),
        pl.col("lost_revenue").sum().alias("total_lost_revenue")
    )
    .sort("total_lost_revenue", descending=True)
)

(
    GT(status_summary)
    .tab_header(
        title="Lost Customer Breakdown: Closure vs. Competitor",
        subtitle="closure_date field distinguishes confirmed closures from potential competitor losses"
    )
    .fmt_currency("total_lost_revenue", currency="TWD", decimals=0, use_subunits=False)
)
Lost Customer Breakdown: Closure vs. Competitor
closure_date field distinguishes confirmed closures from potential competitor losses
status customer_count total_lost_revenue
⚠️ POTENTIAL COMPETITOR 216 NT$3,320,535
🔒 CLOSED SHOP 39 NT$1,263,749
Warning關鍵洞察:多數流失營收可挽回
  • 🔒 已歇業:有 closure_date 紀錄的客戶 - 已結束營業(無法挽回)
  • ⚠️ 可能轉向競爭對手:無歇業日期 - 可能轉換供應商(可挽回!

優先將挽回心力放在沒有歇業日期的客戶。

2.3 主要流失客戶(含歇業狀態)

Code
# Show top lost customers with status
top_lost = (
    lost_with_info
    .sort("lost_revenue", descending=True)
    .head(25)
    .select(["customer_code", "trade_name", "delivery_route", "status", "lost_revenue"])
)

(
    GT(top_lost)
    .tab_header(
        title="🚨 Top 25 Lost Customers (2024 → 2025)",
        subtitle="⚠️ = potential competitor win-back opportunity"
    )
    .fmt_currency("lost_revenue", currency="TWD", decimals=0, use_subunits=False)
)
🚨 Top 25 Lost Customers (2024 → 2025)
⚠️ = potential competitor win-back opportunity
customer_code trade_name delivery_route status lost_revenue
2610025 美漢堡-賴先生2.5 A-PK 🔒 CLOSED SHOP NT$239,012
0180154 玥達人可麗餅-屏東 A-PT 🔒 CLOSED SHOP NT$207,546
4290002 香醇軒-大豐-1.4 K1 🔒 CLOSED SHOP NT$206,771
2910007 早點見面-5 K2 ⚠️ POTENTIAL COMPETITOR NT$202,616
0110014 弘爺漢堡-屏工 PT ⚠️ POTENTIAL COMPETITOR NT$175,673
2630031 昌平炸雞-枋寮2.5 K2 ⚠️ POTENTIAL COMPETITOR NT$113,069
1930020 昌平炸雞-林邊2.5 K2 ⚠️ POTENTIAL COMPETITOR NT$112,095
1310257 宵歸瞑-內埔店直營店1.4 A-PK ⚠️ POTENTIAL COMPETITOR NT$106,541
0530050 昌平炸雞-萬丹2.5 K2 ⚠️ POTENTIAL COMPETITOR NT$104,863
0510188 莯晨-3 K2 ⚠️ POTENTIAL COMPETITOR NT$94,618
1980001 林邊刈包-2.5 K2 ⚠️ POTENTIAL COMPETITOR NT$92,214
0130467 阿曼城市汽車旅館 A-PT 🔒 CLOSED SHOP NT$87,562
0111113 早安8快速早餐-勝利店 A-PT ⚠️ POTENTIAL COMPETITOR NT$86,274
5930003 昌平炸雞-大寮2.5 K2 ⚠️ POTENTIAL COMPETITOR NT$82,082
6030001 昌平炸雞-林園3 K2 ⚠️ POTENTIAL COMPETITOR NT$76,644
0980009 昌平炸雞-里港店2.5 A-PN ⚠️ POTENTIAL COMPETITOR NT$69,193
6610002 朋友早點-3 A-PN 🔒 CLOSED SHOP NT$69,191
0230137 昌平炸雞-潮州 PS ⚠️ POTENTIAL COMPETITOR NT$68,824
0130419 日食糖國際開發有限公 A-PT ⚠️ POTENTIAL COMPETITOR NT$68,456
0190017 轉角有貓貓舍 A-PT 🔒 CLOSED SHOP NT$68,376
0330103 昌平炸雞-東港 PK ⚠️ POTENTIAL COMPETITOR NT$65,633
0210175 早安-潮州永安 PS 🔒 CLOSED SHOP NT$65,517
3420039 吳泳明-咖啡店 PK ⚠️ POTENTIAL COMPETITOR NT$54,167
2030158 昌平炸雞-南州-3 K2 ⚠️ POTENTIAL COMPETITOR NT$53,616
6230032 昌平炸雞-大樹1.4 K1 ⚠️ POTENTIAL COMPETITOR NT$51,479

2.4 昌平炸雞連鎖 - 完全流失

Code
# Find all Chang Ping customers
changping = (
    customers
    .filter(_.trade_name.like("%昌平%"))
    .left_join(sales_orders, "customer_code")
    .filter(_.order_date >= "20240101")
    .left_join(sales_order_lines, ["order_type", "order_number"])
    .mutate(year=_.order_date.left(4))
    .group_by(["customer_code", "trade_name", "delivery_route"])
    .agg(
        rev_2024=ibis.ifelse(_.year == "2024", _.pretax_subtotal.cast("float64"), 0).sum(),
        last_order=_.order_date.max()
    )
    .filter(_.rev_2024 > 0)
    .order_by(ibis.desc("rev_2024"))
    .to_polars()
)

(
    GT(changping)
    .tab_header(
        title="昌平炸雞 (Chang Ping Fried Chicken) - Lost Chain",
        subtitle="16 locations stopped ordering around May 2024 - likely switched suppliers"
    )
    .fmt_currency("rev_2024", currency="TWD", decimals=0, use_subunits=False)
)
昌平炸雞 (Chang Ping Fried Chicken) - Lost Chain
16 locations stopped ordering around May 2024 - likely switched suppliers
customer_code trade_name delivery_route rev_2024 last_order
2630031 昌平炸雞-枋寮2.5 A-PK NT$113,069 20240820
1930020 昌平炸雞-林邊2.5 A-PK NT$112,095 20240524
0530050 昌平炸雞-萬丹2.5 K2 NT$104,863 20240521
3230277 昌平炸雞-中正_2.5 PH NT$88,179 20240524
5930003 昌平炸雞-大寮2.5 K2 NT$82,082 20240524
6030001 昌平炸雞-林園3 K2 NT$76,644 20240522
0980009 昌平炸雞-里港店2.5 A-PN NT$69,193 20240524
0230137 昌平炸雞-潮州 PS NT$68,824 20240524
0330103 昌平炸雞-東港 PK NT$65,633 20240821
2030158 昌平炸雞-南州-3 K2 NT$53,616 20240522
6230032 昌平炸雞-大樹1.4 K1 NT$51,479 20240516
1380011 昌平炸雞-內埔1.4 A-PQ NT$45,703 20240429
0111207 昌平炸雞-建國店 A-PT NT$41,801 20240517
0111212 昌平炸雞-屏商店 A-PT NT$28,427 20240507
3410017 昌平炸雞-琉球-1.3.5 PK NT$24,998 20240522
0130469 昌平炸雞-屏東廣東 A-PT NT$24,286 20240430
1380011 昌平炸雞-內埔1.4 A-PK NT$8,577 20240523
Important連鎖流失:年營收約100萬元

昌平炸雞是一個跨所有路線、擁有16+據點的連鎖品牌。他們在2024年5-8月停止訂購。

業務團隊回饋(2025年12月):

“昌平跟其他通路商購買” - 轉向其他通路供應商

“總部要統一管理與配送,找雞肉廠商一起配合的周邊商品配送” - 總部要求統一管理,與雞肉供應商整合配送

根本原因:價格加物流。他們整合供應商以提升效率,不單純是價格因素。難以挽回 - 需要提供整合配送方案才有機會。

2.5 客戶訂購量縮減分析

為什麼留存客戶買得更少?他們是減少相同產品的訂購數量,還是完全停購某些品項?

Code
# Shrinking customer behavior patterns - from SQL analysis
shrink_behavior = pl.DataFrame({
    "pattern": ["📦 Less Quantity (Same SKUs)", "📉 Both SKUs & Qty Down", "🔄 Mixed/Other", "🗑️ Dropped SKUs Only"],
    "customers": [63, 30, 19, 1],
    "rev_2024": [20405989, 8176786, 5497681, 145952],
    "rev_2025": [12920034, 4569717, 4106640, 113367],
    "delta": [-7485955, -3607069, -1391041, -32585],
    "avg_sku_change": [-2, -11, 1, -3],
    "avg_qty_pct": [-37, -48, 2, -7]
})

(
    GT(shrink_behavior)
    .tab_header(
        title="How Are Shrinking Customers Reducing Orders?",
        subtitle="113 customers with >20% revenue decline, >50K TWD in 2024"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number("customers", decimals=0)
    .fmt_percent("avg_qty_pct", decimals=0, scale_values=False)
    .cols_label(
        pattern="Behavior Pattern",
        avg_sku_change="Avg SKU Δ",
        avg_qty_pct="Avg Qty Δ%"
    )
)
How Are Shrinking Customers Reducing Orders?
113 customers with >20% revenue decline, >50K TWD in 2024
Behavior Pattern customers rev_2024 rev_2025 delta Avg SKU Δ Avg Qty Δ%
📦 Less Quantity (Same SKUs) 63 NT$20,405,989 NT$12,920,034 −NT$7,485,955 -2 −37%
📉 Both SKUs & Qty Down 30 NT$8,176,786 NT$4,569,717 −NT$3,607,069 -11 −48%
🔄 Mixed/Other 19 NT$5,497,681 NT$4,106,640 −NT$1,391,041 1 2%
🗑️ Dropped SKUs Only 1 NT$145,952 NT$113,367 −NT$32,585 -3 −7%
Warning關鍵發現:是數量減少,不是產品轉換

📦 數量減少是主要模式(63位客戶,-750萬元):

  • 客戶訂購相同產品的數量減少37%
  • 他們沒有轉向競爭對手的產品 - 只是買得更少
  • 這顯示:這些客戶的終端消費者需求下降

📉 品項與數量同時下降(30位客戶,-360萬元):

  • 減少約11個品項,同時數量下滑48%
  • 通常與業務萎縮或菜單精簡有關
  • 包含可能有採購政策變動的軍營

結論:價格競爭在這裡沒有幫助。這些客戶的生意正在萎縮。

2.6 主要衰退客戶明細

Code
# Top 15 shrinking customers with behavior pattern
shrinking_detail = pl.DataFrame({
    "customer_code": ["2790003", "1010047", "1250002", "4410023", "0610046", "5410002", "0110023", "5810115", "5310001", "10610004", "4210084", "4410033", "5810212", "3710080", "5910037"],
    "trade_name": ["加祿堂營區-熱食部2.5", "四海-新庄1.4", "萬金營區-3", "萊恩快速早餐-站前1.4", "永和-潭頭-1.4", "美味田園-梓官1.4", "永和-屏東民生", "香醇軒-光華店1.4", "美味田園-岡山-1.4", "就是堡快速早餐-1", "鼎山永和豆漿-1.4", "香醇軒-孔宅店2.5", "萊恩快速早餐-瑞興1.4", "香醇軒直營-忠孝店2.5", "萊恩快速早餐-後庄1.4"],
    "route": ["K2", "A-PN", "K1", "K1", "A-PN", "K2", "A-PT", "K1", "K2", "K2", "K1", "K1", "K1", "K1", "K1"],
    "sku_2024": [80, 29, 58, 45, 45, 62, 26, 36, 61, 10, 55, 43, 50, 43, 44],
    "sku_2025": [27, 32, 49, 40, 42, 59, 20, 38, 48, 8, 48, 36, 36, 43, 40],
    "qty_pct": [-89, -45, -51, -69, -54, -41, -80, -48, -29, -50, -16, -32, -41, -31, -34],
    "rev_2024": [926738, 1955267, 1061345, 723299, 1085118, 1281323, 563807, 565329, 1024457, 682736, 1286572, 600865, 869868, 515272, 968878],
    "rev_2025": [101621, 1191436, 538141, 252352, 626772, 826249, 115805, 227706, 692589, 375667, 1012259, 331924, 627931, 279382, 739164],
    "pattern": ["📉 Both", "📦 Qty", "📦 Qty", "📦 Qty", "📦 Qty", "📦 Qty", "📉 Both", "📦 Qty", "📉 Both", "📦 Qty", "🔄 Other", "📦 Qty", "📉 Both", "📦 Qty", "📦 Qty"]
}).with_columns(
    (pl.col("rev_2025") - pl.col("rev_2024")).alias("delta")
)

(
    GT(shrinking_detail)
    .tab_header(
        title="Top 15 Shrinking Customers (Biggest Revenue Loss)",
        subtitle="Pattern: 📦=less qty, 📉=both qty & SKUs down, 🔄=mixed"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent("qty_pct", decimals=0, scale_values=False)
    .cols_label(
        qty_pct="Qty Δ%",
        sku_2024="SKUs '24",
        sku_2025="SKUs '25"
    )
)
Top 15 Shrinking Customers (Biggest Revenue Loss)
Pattern: 📦=less qty, 📉=both qty & SKUs down, 🔄=mixed
customer_code trade_name route SKUs '24 SKUs '25 Qty Δ% rev_2024 rev_2025 pattern delta
2790003 加祿堂營區-熱食部2.5 K2 80 27 −89% NT$926,738 NT$101,621 📉 Both −NT$825,117
1010047 四海-新庄1.4 A-PN 29 32 −45% NT$1,955,267 NT$1,191,436 📦 Qty −NT$763,831
1250002 萬金營區-3 K1 58 49 −51% NT$1,061,345 NT$538,141 📦 Qty −NT$523,204
4410023 萊恩快速早餐-站前1.4 K1 45 40 −69% NT$723,299 NT$252,352 📦 Qty −NT$470,947
0610046 永和-潭頭-1.4 A-PN 45 42 −54% NT$1,085,118 NT$626,772 📦 Qty −NT$458,346
5410002 美味田園-梓官1.4 K2 62 59 −41% NT$1,281,323 NT$826,249 📦 Qty −NT$455,074
0110023 永和-屏東民生 A-PT 26 20 −80% NT$563,807 NT$115,805 📉 Both −NT$448,002
5810115 香醇軒-光華店1.4 K1 36 38 −48% NT$565,329 NT$227,706 📦 Qty −NT$337,623
5310001 美味田園-岡山-1.4 K2 61 48 −29% NT$1,024,457 NT$692,589 📉 Both −NT$331,868
10610004 就是堡快速早餐-1 K2 10 8 −50% NT$682,736 NT$375,667 📦 Qty −NT$307,069
4210084 鼎山永和豆漿-1.4 K1 55 48 −16% NT$1,286,572 NT$1,012,259 🔄 Other −NT$274,313
4410033 香醇軒-孔宅店2.5 K1 43 36 −32% NT$600,865 NT$331,924 📦 Qty −NT$268,941
5810212 萊恩快速早餐-瑞興1.4 K1 50 36 −41% NT$869,868 NT$627,931 📉 Both −NT$241,937
3710080 香醇軒直營-忠孝店2.5 K1 43 43 −31% NT$515,272 NT$279,382 📦 Qty −NT$235,890
5910037 萊恩快速早餐-後庄1.4 K1 44 40 −34% NT$968,878 NT$739,164 📦 Qty −NT$229,714
Important🚨 需調查的客戶群組

1. 軍營(加祿堂營區、萬金營區):合計 -130萬元

  • 兩者都呈現 📦 數量減少模式
  • 預算削減?合約變更?新採購政策?
  • 行動:聯繫軍方窗口了解政策變動

2. 萊恩快速早餐連鎖(前15大中有4個據點):合計 -120萬元

  • 全部呈現 📦 數量減少模式(-34% 至 -69% 訂購量)
  • 全連鎖業務放緩
  • 行動:與加盟主會面 - 消費者來客數是否下降?

3. 香醇軒連鎖(前15大中有3個據點):合計 -84萬元

  • 各據點訂購量下滑31-48%
  • 行動:與該連鎖負責人進行類似會議

4. 永和品牌門市:多個據點顯著衰退

  • 四海-新庄:-76.4萬(📦 數量)
  • 永和-屏東民生:-44.8萬(📉 兩者)
  • 行動:確認是全公司問題還是個別據點

2.7 衰退客戶停購的產品

Code
# Products most dropped by biggest shrinking customers
dropped_products = pl.DataFrame({
    "product_code": ["12060", "11089", "12083", "12105", "12138", "21622", "56011", "53027", "56041", "53100"],
    "product_name": ["優質香草霜淇淋粉1K#", "早到晚到流心酥(袋)1.8K##", "早到晚到巧克力調味粉1k##", "高級霜淇淋粉(冷溶)1K#", "SI-113 1K#", "奇異鳥奶精(313) 25k", "(禾)手工高麗菜水餃1800g", "紅龍雞塊 1K--促銷", "抓餅(禾)10片", "紅龍卡啦雞腿堡(辣) 10片--促銷"],
    "rev_2024": [2009888, 772572, 493826, 417487, 219800, 179047, 99353, 116740, 101160, 92453],
    "rev_2025": [231314, 0, 0, 0, 0, 0, 0, 17657, 2331, 0],
    "delta": [-1778574, -772572, -493826, -417487, -219800, -179047, -99353, -99083, -98829, -92453]
})

(
    GT(dropped_products)
    .tab_header(
        title="Products Being Dropped by Biggest Shrinking Customers",
        subtitle="Top 5 shrinking customers (>50% revenue decline) - what they stopped buying"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
)
Products Being Dropped by Biggest Shrinking Customers
Top 5 shrinking customers (>50% revenue decline) - what they stopped buying
product_code product_name rev_2024 rev_2025 delta
12060 優質香草霜淇淋粉1K# NT$2,009,888 NT$231,314 −NT$1,778,574
11089 早到晚到流心酥(袋)1.8K## NT$772,572 NT$0 −NT$772,572
12083 早到晚到巧克力調味粉1k## NT$493,826 NT$0 −NT$493,826
12105 高級霜淇淋粉(冷溶)1K# NT$417,487 NT$0 −NT$417,487
12138 SI-113 1K# NT$219,800 NT$0 −NT$219,800
21622 奇異鳥奶精(313) 25k NT$179,047 NT$0 −NT$179,047
56011 (禾)手工高麗菜水餃1800g NT$99,353 NT$0 −NT$99,353
53027 紅龍雞塊 1K--促銷 NT$116,740 NT$17,657 −NT$99,083
56041 抓餅(禾)10片 NT$101,160 NT$2,331 −NT$98,829
53100 紅龍卡啦雞腿堡(辣) 10片--促銷 NT$92,453 NT$0 −NT$92,453
Note產品模式分析

霜淇淋粉系列:合計 -240萬元

  • 優質香草霜淇淋粉:-180萬
  • 高級霜淇淋粉(冷溶):-41.7萬
  • 這些是季節性/夏季產品 - 需確認是時間因素還是永久流失

早到晚到品牌產品:-130萬元(完全停購)

  • 流心酥:-77.3萬
  • 巧克力調味粉:-49.4萬
  • 這些產品標示 ## - 可能是正在淘汰的停產品項

解讀:部分衰退來自預期中的品項轉換(## 產品),但霜淇淋粉流失令人擔憂 - 可能代表流失冰店客戶或競爭流失。

2C. 年內衰退:2025上半年 vs 下半年 🔬

本節分析2025年內衰退的客戶(上半年 → 下半年),以了解:他們是轉向競爭對手,還是需求下降?

2C.1 方法論

Note上下半年衰退計算方式

時間區間:

  • 2025上半年:1月至6月(order_date 月份 01-06)
  • 2025下半年:7月至11月(order_date 月份 07-11)

關鍵篩選:僅限活躍客戶

我們僅納入在2025年11月或12月有下單的客戶。這確保:

  • ✅ 客戶仍在營業且持續訂購
  • ✅ 不計入已流失客戶(另有分析)
  • ✅ 衰退代表錢包佔有率降低,而非帳戶流失

納入標準:

  • 必須在2025年11月或12月有訂購(仍活躍)
  • 上半年營收 >3萬元(具規模帳戶)
  • 下半年營收 >1萬元(仍有購買)
  • 營收衰退 >20% 上半年→下半年

分類邏輯:

模式 標準 解讀
📦 數量減少 數量 ↓>20%,品項穩定 需求下降 - 其終端客戶購買減少
🗑️ 品項流失 品項 ↓>20%,數量穩定 可能轉向競爭對手 - 停購我方產品
📉 兩者皆降 兩者 ↓>20% 業務萎縮
🔄 混合 其他模式 季節性或菜單調整

為何重要:透過分析品項 vs. 數量變化,我們可以區分:

  • 市場/需求問題(數量減少)→ 景氣不佳,降價無法解決
  • 競爭問題(品項流失)→ 競爭對手搶走市場,需要反擊

2C.2 上下半年衰退模式摘要

Code
# H1→H2 2025 decline pattern summary - ACTIVE CUSTOMERS ONLY (ordered Nov/Dec)
h1h2_summary = pl.DataFrame({
    "pattern": ["📦 Less Quantity (demand down)", "📉 Both SKUs & Qty Down", "🔄 Mixed/Stable", "🗑️ Dropped SKUs (possible competitor)"],
    "customers": [83, 36, 33, 7],
    "h1_rev": [10199242, 3827084, 2907730, 966723],
    "h2_rev": [6744552, 2285052, 2241943, 688765],
    "delta": [-3454690, -1542032, -665787, -277958],
    "avg_sku_change": [-1, -8, 0, -8],
    "avg_qty_pct": [-35, -45, -10, -9]
})

(
    GT(h1h2_summary)
    .tab_header(
        title="H1 → H2 2025 Decline Patterns (Active Customers Only)",
        subtitle="159 customers with >20% decline who STILL ordered in Nov/Dec 2025"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent("avg_qty_pct", decimals=0, scale_values=False)
    .cols_label(
        avg_sku_change="Avg SKU Δ",
        avg_qty_pct="Avg Qty Δ%"
    )
)
H1 → H2 2025 Decline Patterns (Active Customers Only)
159 customers with >20% decline who STILL ordered in Nov/Dec 2025
pattern customers h1_rev h2_rev delta Avg SKU Δ Avg Qty Δ%
📦 Less Quantity (demand down) 83 NT$10,199,242 NT$6,744,552 −NT$3,454,690 -1 −35%
📉 Both SKUs & Qty Down 36 NT$3,827,084 NT$2,285,052 −NT$1,542,032 -8 −45%
🔄 Mixed/Stable 33 NT$2,907,730 NT$2,241,943 −NT$665,787 0 −10%
🗑️ Dropped SKUs (possible competitor) 7 NT$966,723 NT$688,765 −NT$277,958 -8 −9%
Important🎯 關鍵洞察:是需求問題,不是競爭問題

數據回答了我們的核心問題:

情境 模式 客戶數 影響
需求下降 📦 數量減少 83 (52%) -350萬元
業務萎縮 📉 兩者皆降 36 (23%) -150萬元
可能競爭流失 🗑️ 品項流失 僅7位 (4%) -27.8萬元

這代表什麼:

  • 83位客戶訂購相同產品的數量減少35%
  • 他們沒有轉向競爭對手 - 仍然購買我們的品項
  • 只有7位客戶(4%)顯示可能轉向競爭對手的跡象
  • 競爭相關流失總計:約27.8萬元(非常少)

結論:我們處於需求放緩環境,而非競爭戰場。降價和促銷無法解決問題 - 我們客戶的終端消費者支出減少了。

2C.3 上下半年衰退前15大客戶(仍活躍)

這些客戶在2025年11月/12月仍有下單,但消費金額較上半年明顯減少。

Code
# Top 15 declining customers H1→H2 - ACTIVE (ordered Nov/Dec 2025)
h1h2_detail = pl.DataFrame({
    "customer_code": ["0190012", "0290007", "5870001", "0550007", "4410040", "10610004", "4290011", "5890006", "1310203", "4210084", "1310027", "2710004", "4410023", "4410033", "5310001"],
    "trade_name": ["宵歸暝-屏東總店", "宵歸暝 潮州光華直營店", "新月牛角烘焙食品行", "瀧旭食品-3", "香醇軒總部-5", "就是堡快速早餐-1", "呷歸岡高雄三民店1.4", "夭巴ㄔㄚˋ1.4", "小田園直營-內埔1.4", "鼎山永和豆漿-1.4", "隘寮早點1.4", "鄭永彥2.5", "萊恩快速早餐-站前1.4", "香醇軒-孔宅店2.5", "美味田園-岡山-1.4"],
    "route": ["A-PT", "PS", "A-PT", "K2", "K1", "K2", "K1", "K1", "A-PK", "K1", "A-PK", "PH01", "K1", "K1", "K2"],
    "h1_skus": [65, 59, 3, 8, 12, 8, 61, 56, 26, 48, 35, 59, 35, 28, 43],
    "h2_skus": [44, 19, 4, 15, 18, 7, 60, 49, 27, 31, 33, 52, 29, 29, 41],
    "h1_qty": [5905, 2533, 2415, 6433, 1564, 2089, 2643, 3586, 2336, 4496, 2816, 2678, 1273, 3182, 2429],
    "h2_qty": [3653, 610, 1562, 696, 908, 766, 1836, 2506, 1669, 3905, 2168, 1670, 459, 1900, 1874],
    "h1_rev": [905164, 364321, 523535, 385283, 391192, 262626, 380774, 419115, 439123, 570439, 510749, 295682, 182926, 220134, 392524],
    "h2_rev": [605287, 79405, 323663, 190411, 197613, 113041, 232560, 283898, 306024, 441820, 383173, 176436, 69426, 111790, 300065]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") * 100).round(0).alias("qty_pct"),
    pl.when(
        ((pl.col("h2_skus") - pl.col("h1_skus")) / pl.col("h1_skus") < -0.2) &
        ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.2)
    ).then(pl.lit("📉 Both"))
    .when((pl.col("h2_skus") - pl.col("h1_skus")) / pl.col("h1_skus") < -0.2)
    .then(pl.lit("🗑️ Competitor?"))
    .when((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.2)
    .then(pl.lit("📦 Demand↓"))
    .otherwise(pl.lit("🔄 Mixed"))
    .alias("pattern")
])

(
    GT(h1h2_detail)
    .tab_header(
        title="Top 10 H1→H2 2025 Declining Customers",
        subtitle="Customers with biggest revenue decline within 2025"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent("qty_pct", decimals=0, scale_values=False)
    .cols_label(
        h1_skus="SKUs H1",
        h2_skus="SKUs H2",
        h1_qty="Qty H1",
        h2_qty="Qty H2",
        qty_pct="Qty Δ%"
    )
)
Top 10 H1→H2 2025 Declining Customers
Customers with biggest revenue decline within 2025
customer_code trade_name route SKUs H1 SKUs H2 Qty H1 Qty H2 h1_rev h2_rev delta Qty Δ% pattern
0190012 宵歸暝-屏東總店 A-PT 65 44 5905 3653 NT$905,164 NT$605,287 −NT$299,877 −38% 📉 Both
0290007 宵歸暝 潮州光華直營店 PS 59 19 2533 610 NT$364,321 NT$79,405 −NT$284,916 −76% 📉 Both
5870001 新月牛角烘焙食品行 A-PT 3 4 2415 1562 NT$523,535 NT$323,663 −NT$199,872 −35% 📦 Demand↓
0550007 瀧旭食品-3 K2 8 15 6433 696 NT$385,283 NT$190,411 −NT$194,872 −89% 📦 Demand↓
4410040 香醇軒總部-5 K1 12 18 1564 908 NT$391,192 NT$197,613 −NT$193,579 −42% 📦 Demand↓
10610004 就是堡快速早餐-1 K2 8 7 2089 766 NT$262,626 NT$113,041 −NT$149,585 −63% 📦 Demand↓
4290011 呷歸岡高雄三民店1.4 K1 61 60 2643 1836 NT$380,774 NT$232,560 −NT$148,214 −31% 📦 Demand↓
5890006 夭巴ㄔㄚˋ1.4 K1 56 49 3586 2506 NT$419,115 NT$283,898 −NT$135,217 −30% 📦 Demand↓
1310203 小田園直營-內埔1.4 A-PK 26 27 2336 1669 NT$439,123 NT$306,024 −NT$133,099 −29% 📦 Demand↓
4210084 鼎山永和豆漿-1.4 K1 48 31 4496 3905 NT$570,439 NT$441,820 −NT$128,619 −13% 🗑️ Competitor?
1310027 隘寮早點1.4 A-PK 35 33 2816 2168 NT$510,749 NT$383,173 −NT$127,576 −23% 📦 Demand↓
2710004 鄭永彥2.5 PH01 59 52 2678 1670 NT$295,682 NT$176,436 −NT$119,246 −38% 📦 Demand↓
4410023 萊恩快速早餐-站前1.4 K1 35 29 1273 459 NT$182,926 NT$69,426 −NT$113,500 −64% 📦 Demand↓
4410033 香醇軒-孔宅店2.5 K1 28 29 3182 1900 NT$220,134 NT$111,790 −NT$108,344 −40% 📦 Demand↓
5310001 美味田園-岡山-1.4 K2 43 41 2429 1874 NT$392,524 NT$300,065 −NT$92,459 −23% 📦 Demand↓

2C.4 產品層級明細範例

這些範例精確顯示主要衰退客戶的變化。

範例1:宵歸暝-屏東總店(📉 品項與數量皆降)

模式:減少21個品項,且數量下滑38%

Code
# Product breakdown for 宵歸暝-屏東總店
ex1_products = pl.DataFrame({
    "product": ["宵歸暝草莓調味粉 1.2K", "美食家油炸專用油 18L", "維力媽媽拉麵 70g*6入", "寶宏pizza絲 1k--促銷", "宵歸暝專用紅茶600g", "8吋原味墨西哥薄餅", "宵歸暝專用咖啡1.2K", "紅龍1/4牛肉餅", "味你好冷凍熟水餃", "祥哥冷凍蘿蔔糕12片"],
    "h1_qty": [250, 47, 860, 100, 400, 150, 150, 16, 67, 240],
    "h2_qty": [50, 9, 60, 20, 300, 20, 100, 0, 24, 30],
    "h1_rev": [75715, 41183, 33582, 27142, 56000, 15428, 38000, 11884, 18468, 13028],
    "h2_rev": [15143, 7759, 2343, 5142, 42000, 2057, 25524, 0, 6760, 1514]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    pl.when(pl.col("h2_qty") == 0).then(pl.lit("STOPPED"))
      .when((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.5).then(pl.lit("↓↓ Major"))
      .when((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.2).then(pl.lit("↓ Reduced"))
      .otherwise(pl.lit("~Stable"))
      .alias("status")
])

(
    GT(ex1_products)
    .tab_header(
        title="宵歸暝-屏東總店: What Changed H1→H2",
        subtitle="Total decline: -300K TWD | Pattern: 📉 Both SKUs & Qty Down"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
宵歸暝-屏東總店: What Changed H1→H2
Total decline: -300K TWD | Pattern: 📉 Both SKUs & Qty Down
product h1_qty h2_qty h1_rev h2_rev delta status
宵歸暝草莓調味粉 1.2K 250 50 NT$75,715 NT$15,143 −NT$60,572 ↓↓ Major
美食家油炸專用油 18L 47 9 NT$41,183 NT$7,759 −NT$33,424 ↓↓ Major
維力媽媽拉麵 70g*6入 860 60 NT$33,582 NT$2,343 −NT$31,239 ↓↓ Major
寶宏pizza絲 1k--促銷 100 20 NT$27,142 NT$5,142 −NT$22,000 ↓↓ Major
宵歸暝專用紅茶600g 400 300 NT$56,000 NT$42,000 −NT$14,000 ↓ Reduced
8吋原味墨西哥薄餅 150 20 NT$15,428 NT$2,057 −NT$13,371 ↓↓ Major
宵歸暝專用咖啡1.2K 150 100 NT$38,000 NT$25,524 −NT$12,476 ↓ Reduced
紅龍1/4牛肉餅 16 0 NT$11,884 NT$0 −NT$11,884 STOPPED
味你好冷凍熟水餃 67 24 NT$18,468 NT$6,760 −NT$11,708 ↓↓ Major
祥哥冷凍蘿蔔糕12片 240 30 NT$13,028 NT$1,514 −NT$11,514 ↓↓ Major
Note分析:宵歸暝連鎖(2間店衰退)

兩間宵歸暝門市都進入衰退前10名:

  • 屏東總店:-30萬(📉 兩者皆降)
  • 潮州光華直營店:-28.5萬(📉 兩者皆降,嚴重 - 停購40個品項!)

模式:所有產品類別全面縮減,而非單一品項問題。

可能原因:全連鎖放緩。他們的來客數下降。

行動:直接聯繫宵歸暝連鎖負責人 - 經營是否遇到困難?有無菜單調整?

範例2:宵歸暝 潮州光華直營店(📉 嚴重萎縮)

模式:停購40個品項(!),數量下滑76%

Code
# Product breakdown for 宵歸暝 潮州光華直營店 - severe contraction
ex2_products = pl.DataFrame({
    "product": ["寶宏pizza絲 1k--促銷", "美食家油炸專用油 18L", "泰式打拋豬肉350g", "宵歸暝專用湯粉1K", "維力媽媽拉麵 70g*6入", "宵歸暝草莓調味粉 1.2K", "紅龍雞塊 1K--促銷", "福華沙茶醬 3K", "8吋原味墨西哥薄餅", "金鑽巧克力塗抹醬 3k"],
    "h1_qty": [101, 28, 156, 64, 500, 50, 80, 21, 78, 14],
    "h2_qty": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    "h1_rev": [27412, 24530, 22677, 21639, 19524, 15143, 11658, 9051, 8022, 6933],
    "h2_rev": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    pl.lit("🛑 STOPPED").alias("status")
])

(
    GT(ex2_products)
    .tab_header(
        title="宵歸暝 潮州光華直營店: Everything Stopped",
        subtitle="Total decline: -285K TWD | Pattern: 📉 Severe contraction"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
宵歸暝 潮州光華直營店: Everything Stopped
Total decline: -285K TWD | Pattern: 📉 Severe contraction
product h1_qty h2_qty h1_rev h2_rev delta status
寶宏pizza絲 1k--促銷 101 0 NT$27,412 NT$0 −NT$27,412 🛑 STOPPED
美食家油炸專用油 18L 28 0 NT$24,530 NT$0 −NT$24,530 🛑 STOPPED
泰式打拋豬肉350g 156 0 NT$22,677 NT$0 −NT$22,677 🛑 STOPPED
宵歸暝專用湯粉1K 64 0 NT$21,639 NT$0 −NT$21,639 🛑 STOPPED
維力媽媽拉麵 70g*6入 500 0 NT$19,524 NT$0 −NT$19,524 🛑 STOPPED
宵歸暝草莓調味粉 1.2K 50 0 NT$15,143 NT$0 −NT$15,143 🛑 STOPPED
紅龍雞塊 1K--促銷 80 0 NT$11,658 NT$0 −NT$11,658 🛑 STOPPED
福華沙茶醬 3K 21 0 NT$9,051 NT$0 −NT$9,051 🛑 STOPPED
8吋原味墨西哥薄餅 78 0 NT$8,022 NT$0 −NT$8,022 🛑 STOPPED
金鑽巧克力塗抹醬 3k 14 0 NT$6,933 NT$0 −NT$6,933 🛑 STOPPED
Warning🚨 警示:可能即將歇業

這個據點從購買約60種產品變成幾乎沒有。

  • 所有主要產品都歸零
  • 不是產品組合調整 - 是完全停止
  • 下半年仍有小額訂單(7.9萬),所以尚未完全關閉

緊急行動:立即致電這間店。是否即將歇業?營業時間縮減?我們應該在他們完全停止前掌握情況。

範例3:新月牛角烘焙食品行(📦 純數量減少)

模式:相同產品,數量減少35%

Code
# Product breakdown for 新月牛角烘焙食品行 - pure volume reduction
ex3_products = pl.DataFrame({
    "product": ["新月優質沙拉(袋)3K", "肉鬆 3K", "元氣豬肉鬆3K--促銷", "福鷹玉米粒340g", "四季沙拉3K--促銷"],
    "h1_qty": [2265, 54, 96, 0, 0],
    "h2_qty": [1372, 0, 90, 72, 28],
    "h1_rev": [463792, 21343, 38400, 0, 0],
    "h2_rev": [280939, 0, 35487, 1371, 5866]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    pl.when(pl.col("h2_qty") == 0).then(pl.lit("STOPPED"))
      .when(pl.col("h1_qty") == 0).then(pl.lit("NEW"))
      .when((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.3).then(pl.lit("↓↓ Major"))
      .otherwise(pl.lit("~Stable"))
      .alias("status")
])

(
    GT(ex3_products)
    .tab_header(
        title="新月牛角烘焙食品行: Single Product Volume Drop",
        subtitle="Total decline: -200K TWD | Pattern: 📦 Less Quantity"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
新月牛角烘焙食品行: Single Product Volume Drop
Total decline: -200K TWD | Pattern: 📦 Less Quantity
product h1_qty h2_qty h1_rev h2_rev delta status
新月優質沙拉(袋)3K 2,265 1,372 NT$463,792 NT$280,939 −NT$182,853 ↓↓ Major
肉鬆 3K 54 0 NT$21,343 NT$0 −NT$21,343 STOPPED
元氣豬肉鬆3K--促銷 96 90 NT$38,400 NT$35,487 −NT$2,913 ~Stable
福鷹玉米粒340g 0 72 NT$0 NT$1,371 NT$1,371 NEW
四季沙拉3K--促銷 0 28 NT$0 NT$5,866 NT$5,866 NEW
Note分析:典型需求放緩

這間烘焙坊主要向我們購買一項產品:新月優質沙拉(沙拉醬)。

  • 上半年:2,265件 → 下半年:1,372件(-39%)
  • 他們沒有更換供應商 - 仍購買相同產品
  • 數量減少 = 他們的烘焙坊銷售下滑

這是「📦 數量減少」最明確的範例:相同品項,只是訂單變小。

我們無法透過更好的服務或價格來解決 - 他們的顧客沒有買那麼多麵包了。

範例4:就是堡快速早餐(📦 純數量減少)

模式:8個品項 → 7個品項(基本相同),數量下滑63%

Code
# Product breakdown for 就是堡快速早餐
ex4_products = pl.DataFrame({
    "product": ["Jasper奶精 1.1k", "日式香酥魚堡 25入", "卡啦脆魚條 1K", "丹麥土司10片", "香香雞米花1K", "金品玉米濃湯250g"],
    "h1_qty": [1620, 36, 45, 120, 36, 216],
    "h2_qty": [540, 27, 49, 76, 54, 0],
    "h1_rev": [216000, 15639, 9431, 6510, 6137, 4114],
    "h2_rev": [72000, 11727, 10270, 4124, 9666, 0]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    pl.when(pl.col("h2_qty") == 0).then(pl.lit("STOPPED"))
      .when((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") < -0.3).then(pl.lit("↓↓ Major"))
      .when(pl.col("h2_qty") > pl.col("h1_qty")).then(pl.lit("↑ UP"))
      .otherwise(pl.lit("~Stable"))
      .alias("status")
])

(
    GT(ex4_products)
    .tab_header(
        title="就是堡快速早餐: Same Products, Much Less Volume",
        subtitle="Total decline: -150K TWD | Pattern: 📦 Less Quantity"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
就是堡快速早餐: Same Products, Much Less Volume
Total decline: -150K TWD | Pattern: 📦 Less Quantity
product h1_qty h2_qty h1_rev h2_rev delta status
Jasper奶精 1.1k 1,620 540 NT$216,000 NT$72,000 −NT$144,000 ↓↓ Major
日式香酥魚堡 25入 36 27 NT$15,639 NT$11,727 −NT$3,912 ~Stable
卡啦脆魚條 1K 45 49 NT$9,431 NT$10,270 NT$839 ↑ UP
丹麥土司10片 120 76 NT$6,510 NT$4,124 −NT$2,386 ↓↓ Major
香香雞米花1K 36 54 NT$6,137 NT$9,666 NT$3,529 ↑ UP
金品玉米濃湯250g 216 0 NT$4,114 NT$0 −NT$4,114 STOPPED
Note分析:Jasper奶精說明一切
  • 主要產品(Jasper奶精):1,620 → 540件(-67%
  • 仍購買相同品牌奶精 - 沒有轉換
  • 其他產品(魚堡、雞肉)也等比例下降

這是一間早餐店,因為他們的顧客減少而減少所有採購。

範例5:小田園直營-內埔(📦 全面數量下滑)

模式:26個品項 → 27個品項(組合相同),數量下滑29%

Code
# Product breakdown for 小田園直營-內埔
ex5_products = pl.DataFrame({
    "product": ["正點卡啦雞腿堡(辣)--促銷", "強匠煙燻雞肉片1kg", "小田園熱狗 50入", "正點卡啦雞腿堡(原味)--促銷", "遠洋鮪魚三明治1880g", "香香雞米花1K", "安美燻腸 1000g--促銷", "HISUN起司片84片--促銷", "香雞城小肉豆1K", "抓餅(禾)10片"],
    "h1_qty": [227, 167, 323, 183, 102, 176, 160, 99, 147, 278],
    "h2_qty": [159, 109, 218, 137, 48, 136, 128, 62, 105, 216],
    "h1_rev": [42473, 39075, 38150, 34220, 32541, 29923, 29250, 29134, 25907, 24881],
    "h2_rev": [29094, 25263, 26635, 25071, 15318, 23963, 22740, 18535, 18497, 19332]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") * 100).round(0).alias("qty_pct")
])

(
    GT(ex5_products)
    .tab_header(
        title="小田園直營-內埔: Every Product Down ~30%",
        subtitle="Total decline: -133K TWD | Pattern: 📦 Less Quantity"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
    .fmt_percent("qty_pct", decimals=0, scale_values=False)
)
小田園直營-內埔: Every Product Down ~30%
Total decline: -133K TWD | Pattern: 📦 Less Quantity
product h1_qty h2_qty h1_rev h2_rev delta qty_pct
正點卡啦雞腿堡(辣)--促銷 227 159 NT$42,473 NT$29,094 −NT$13,379 −30%
強匠煙燻雞肉片1kg 167 109 NT$39,075 NT$25,263 −NT$13,812 −35%
小田園熱狗 50入 323 218 NT$38,150 NT$26,635 −NT$11,515 −33%
正點卡啦雞腿堡(原味)--促銷 183 137 NT$34,220 NT$25,071 −NT$9,149 −25%
遠洋鮪魚三明治1880g 102 48 NT$32,541 NT$15,318 −NT$17,223 −53%
香香雞米花1K 176 136 NT$29,923 NT$23,963 −NT$5,960 −23%
安美燻腸 1000g--促銷 160 128 NT$29,250 NT$22,740 −NT$6,510 −20%
HISUN起司片84片--促銷 99 62 NT$29,134 NT$18,535 −NT$10,599 −37%
香雞城小肉豆1K 147 105 NT$25,907 NT$18,497 −NT$7,410 −29%
抓餅(禾)10片 278 216 NT$24,881 NT$19,332 −NT$5,549 −22%
Note分析:所有產品均勻下滑20-40%

前10大產品仍在購買 - 只是每項都買得更少:

  • 雞腿堡:-30%
  • 熱狗:-32%
  • 起司:-37%
  • 鮪魚三明治:-53%

關鍵洞察:如果他們轉向競爭對手,我們會看到某些產品歸零而其他穩定。但實際上所有產品都等比例下降 = 他們的來客數下降了。

範例6:隘寮早點(📦 獨立店家,相同模式)

模式:35個品項 → 33個品項(相似),數量下滑23%

Code
# Product breakdown for 隘寮早點
ex6_products = pl.DataFrame({
    "product": ["強匠卡拉雞腿堡(辣)--促銷", "安心熱狗100支", "卜蜂業務用雞塊3k", "奇異鳥奶精 25k", "金酥3/8脆薯2.04K--促銷", "強匠卡拉雞腿堡(原味)--促銷", "手工蔥抓餅10入--促銷", "福汎巧克力3K", "家州黑胡椒腿肉排1K", "元氣豬肉鬆3K--促銷"],
    "h1_qty": [1482, 195, 135, 10, 88, 100, 184, 17, 30, 12],
    "h2_qty": [1116, 193, 52, 9, 79, 62, 150, 16, 29, 14],
    "h1_rev": [272264, 42707, 41138, 22713, 18535, 18508, 16006, 8031, 6293, 4898],
    "h2_rev": [203659, 43781, 15847, 20440, 15631, 11325, 11602, 7616, 6079, 5680]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") * 100).round(0).alias("qty_pct")
])

(
    GT(ex6_products)
    .tab_header(
        title="隘寮早點: Independent Shop Shows Same Pattern",
        subtitle="Total decline: -128K TWD | Pattern: 📦 Less Quantity"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
    .fmt_percent("qty_pct", decimals=0, scale_values=False)
)
隘寮早點: Independent Shop Shows Same Pattern
Total decline: -128K TWD | Pattern: 📦 Less Quantity
product h1_qty h2_qty h1_rev h2_rev delta qty_pct
強匠卡拉雞腿堡(辣)--促銷 1,482 1,116 NT$272,264 NT$203,659 −NT$68,605 −25%
安心熱狗100支 195 193 NT$42,707 NT$43,781 NT$1,074 −1%
卜蜂業務用雞塊3k 135 52 NT$41,138 NT$15,847 −NT$25,291 −61%
奇異鳥奶精 25k 10 9 NT$22,713 NT$20,440 −NT$2,273 −10%
金酥3/8脆薯2.04K--促銷 88 79 NT$18,535 NT$15,631 −NT$2,904 −10%
強匠卡拉雞腿堡(原味)--促銷 100 62 NT$18,508 NT$11,325 −NT$7,183 −38%
手工蔥抓餅10入--促銷 184 150 NT$16,006 NT$11,602 −NT$4,404 −18%
福汎巧克力3K 17 16 NT$8,031 NT$7,616 −NT$415 −6%
家州黑胡椒腿肉排1K 30 29 NT$6,293 NT$6,079 −NT$214 −3%
元氣豬肉鬆3K--促銷 12 14 NT$4,898 NT$5,680 NT$782 17%
Note分析:相同故事,不同店家

這是一間獨立早餐店(非連鎖),呈現完全相同的模式:

  • 主要產品(強匠雞腿堡):1,482 → 1,116件(-25%)
  • 熱狗:基本持平(仍購買相同數量)
  • 奶精、薯條、巧克力:都是穩定品項,數量略減

不是連鎖效應 - 這是全市場需求放緩,也影響到獨立店家。

範例7:漁行口食堂(📦 餐廳,季節性?)

模式:11個品項 → 12個品項(相同),數量下滑55%

Code
# Product breakdown for 漁行口食堂-王船文化館
ex7_products = pl.DataFrame({
    "product": ["紅龍香檸雞柳條 1K", "金酥3/8脆薯2.04K--促銷", "強匠招牌鹽酥雞500g--促銷", "酥炸杏鮑菇2.2K", "洋蔥圈1K"],
    "h1_qty": [190, 118, 220, 31, 35],
    "h2_qty": [45, 66, 120, 20, 6],
    "h1_rev": [28048, 24723, 23347, 12400, 4858],
    "h2_rev": [6642, 12915, 12458, 8000, 829]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.col("h1_qty") * 100).round(0).alias("qty_pct")
])

(
    GT(ex7_products)
    .tab_header(
        title="漁行口食堂-王船文化館: Tourist Restaurant Decline",
        subtitle="Total decline: -54K TWD | Pattern: 📦 Less Quantity"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
    .fmt_percent("qty_pct", decimals=0, scale_values=False)
)
漁行口食堂-王船文化館: Tourist Restaurant Decline
Total decline: -54K TWD | Pattern: 📦 Less Quantity
product h1_qty h2_qty h1_rev h2_rev delta qty_pct
紅龍香檸雞柳條 1K 190 45 NT$28,048 NT$6,642 −NT$21,406 −76%
金酥3/8脆薯2.04K--促銷 118 66 NT$24,723 NT$12,915 −NT$11,808 −44%
強匠招牌鹽酥雞500g--促銷 220 120 NT$23,347 NT$12,458 −NT$10,889 −45%
酥炸杏鮑菇2.2K 31 20 NT$12,400 NT$8,000 −NT$4,400 −35%
洋蔥圈1K 35 6 NT$4,858 NT$829 −NT$4,029 −83%
Note分析:文化/觀光場所

這間餐廳位於王船文化館 - 可能依賴觀光客。

  • 所有炸物產品下滑45-83%
  • 相同產品組合,只是數量大幅減少
  • 可能有季節因素(下半年 = 秋冬,觀光減少?)

即使部分為季節性因素,模式仍確認:購買相同產品,數量減少 = 需求下降

2E. 成功案例:成長中的客戶 📈

不是所有客戶都在衰退!75位老客戶正在成長 - 讓我們從他們身上學習。

2E.1 客戶健康度分布

Code
# Customer health distribution H1→H2 2025
health_dist = pl.DataFrame({
    "status": ["📈 Growing (>10%)", "➡️ Stable (±10%)", "📉 Declining (10-30%)", "⚠️ Sharp Decline (>30%)"],
    "customers": [75, 214, 196, 50],
    "h1_rev": [6428941, 31628138, 25364985, 8240582],
    "h2_rev": [8110776, 30913491, 21081750, 4866335],
    "delta": [1681835, -714647, -4283235, -3374247]
})

(
    GT(health_dist)
    .tab_header(
        title="Customer Health Distribution: H1 → H2 2025",
        subtitle="Active customers (ordered Nov/Dec 2025) with >30K per half"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number("customers", decimals=0)
)
Customer Health Distribution: H1 → H2 2025
Active customers (ordered Nov/Dec 2025) with >30K per half
status customers h1_rev h2_rev delta
📈 Growing (>10%) 75 NT$6,428,941 NT$8,110,776 NT$1,681,835
➡️ Stable (±10%) 214 NT$31,628,138 NT$30,913,491 −NT$714,647
📉 Declining (10-30%) 196 NT$25,364,985 NT$21,081,750 −NT$4,283,235
⚠️ Sharp Decline (>30%) 50 NT$8,240,582 NT$4,866,335 −NT$3,374,247
Tip好消息:289位客戶(54%)穩定或成長中!
  • 75位成長 = +170萬元
  • 214位穩定 = 基本持平
  • 合計:289位客戶(54%)維持穩定或持續成長

衰退集中在246位客戶(46%),並非均勻分布。

2E.2 成長前幾名客戶(僅限老客戶)

篩選條件:2024年營收 >10萬元(非新店):

Code
# Top growing established customers
growing = pl.DataFrame({
    "customer_code": ["3410019", "0110932", "0610071", "0810005", "6210024", "0111122", "0210304", "3410042", "1310243", "0320113"],
    "trade_name": ["壽司早點-蘇惠君", "活力-屏商技", "大屏北早餐-繁華1.4", "順利早點2.5", "小田園直營店-久堂1.4", "早安8快速早餐-永大店", "早點見面", "琉浪日嚐", "大屏北早餐-龍泉1.4", "迪士米"],
    "route": ["PK", "A-PT", "A-PN", "A-PN", "K2", "A-PT", "PS", "PK", "A-PK", "PK"],
    "since": ["2019", "2017", "2017", "2017", "2018", "2017", "2024", "2024", "2019", "2017"],
    "rev_2024": [422147, 304430, 642399, 478503, 450540, 600722, 244967, 134091, 641033, 184299],
    "h1_skus": [22, 46, 47, 31, 24, 44, 73, 24, 37, 17],
    "h2_skus": [34, 47, 47, 36, 26, 47, 66, 26, 39, 22],
    "h1_rev": [157682, 106262, 342034, 212879, 208734, 218870, 181534, 137523, 313028, 82486],
    "h2_rev": [240551, 174930, 397831, 268332, 260522, 267473, 224644, 179823, 352760, 120021],
    "qty_pct": [51, 56, 21, 71, 29, 31, 31, 29, 38, 81]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    (pl.col("h2_skus") - pl.col("h1_skus")).alias("sku_delta"),
    ((pl.col("h2_rev") - pl.col("h1_rev")) / pl.col("h1_rev") * 100).round(0).alias("rev_pct")
])

(
    GT(growing)
    .tab_header(
        title="🌟 Top 10 Growing Established Customers",
        subtitle="Customers with >100K 2024 revenue, growing H1→H2 2025"
    )
    .fmt_currency(["rev_2024", "h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent(["rev_pct", "qty_pct"], decimals=0, scale_values=False)
    .cols_label(
        sku_delta="SKU Δ",
        qty_pct="Qty Δ%",
        rev_pct="Rev Δ%"
    )
)
🌟 Top 10 Growing Established Customers
Customers with >100K 2024 revenue, growing H1→H2 2025
customer_code trade_name route since rev_2024 h1_skus h2_skus h1_rev h2_rev Qty Δ% delta SKU Δ Rev Δ%
3410019 壽司早點-蘇惠君 PK 2019 NT$422,147 22 34 NT$157,682 NT$240,551 51% NT$82,869 12 53%
0110932 活力-屏商技 A-PT 2017 NT$304,430 46 47 NT$106,262 NT$174,930 56% NT$68,668 1 65%
0610071 大屏北早餐-繁華1.4 A-PN 2017 NT$642,399 47 47 NT$342,034 NT$397,831 21% NT$55,797 0 16%
0810005 順利早點2.5 A-PN 2017 NT$478,503 31 36 NT$212,879 NT$268,332 71% NT$55,453 5 26%
6210024 小田園直營店-久堂1.4 K2 2018 NT$450,540 24 26 NT$208,734 NT$260,522 29% NT$51,788 2 25%
0111122 早安8快速早餐-永大店 A-PT 2017 NT$600,722 44 47 NT$218,870 NT$267,473 31% NT$48,603 3 22%
0210304 早點見面 PS 2024 NT$244,967 73 66 NT$181,534 NT$224,644 31% NT$43,110 -7 24%
3410042 琉浪日嚐 PK 2024 NT$134,091 24 26 NT$137,523 NT$179,823 29% NT$42,300 2 31%
1310243 大屏北早餐-龍泉1.4 A-PK 2019 NT$641,033 37 39 NT$313,028 NT$352,760 38% NT$39,732 2 13%
0320113 迪士米 PK 2017 NT$184,299 17 22 NT$82,486 NT$120,021 81% NT$37,535 5 46%

2E.3 成長中的客戶有什麼不同?

成功模式1:壽司早點-蘇惠君(+53%,菜單擴展)

策略:新增12個品項,全面增加訂購量

Code
# 壽司早點 product breakdown
success1 = pl.DataFrame({
    "product": ["紅龍卡啦雞腿堡(辣)--促銷", "鮮肉湯包 50入", "二代紅450g", "紅龍雞塊 1K--促銷 🆕", "安佳84片乳酪--促銷", "黃金潛艇堡(起司)--促銷", "芋泥包60g*12粒", "冷凍熟鍋貼 🆕"],
    "h1_qty": [152, 266, 120, 0, 30, 120, 72, 4],
    "h2_qty": [258, 392, 160, 70, 50, 160, 117, 32],
    "h1_rev": [28954, 36743, 28573, 0, 9809, 15664, 6654, 458],
    "h2_rev": [47305, 54130, 38097, 9335, 15287, 20302, 10812, 3600]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.when(pl.col("h1_qty") > 0).then(pl.col("h1_qty")).otherwise(1) * 100).round(0).alias("qty_pct")
])

(
    GT(success1)
    .tab_header(
        title="壽司早點-蘇惠君: Menu Expansion Strategy",
        subtitle="Added new products (🆕) AND increased volume on existing items"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
壽司早點-蘇惠君: Menu Expansion Strategy
Added new products (🆕) AND increased volume on existing items
product h1_qty h2_qty h1_rev h2_rev delta qty_pct
紅龍卡啦雞腿堡(辣)--促銷 152 258 NT$28,954 NT$47,305 NT$18,351 70.0
鮮肉湯包 50入 266 392 NT$36,743 NT$54,130 NT$17,387 47.0
二代紅450g 120 160 NT$28,573 NT$38,097 NT$9,524 33.0
紅龍雞塊 1K--促銷 🆕 0 70 NT$0 NT$9,335 NT$9,335 7000.0
安佳84片乳酪--促銷 30 50 NT$9,809 NT$15,287 NT$5,478 67.0
黃金潛艇堡(起司)--促銷 120 160 NT$15,664 NT$20,302 NT$4,638 33.0
芋泥包60g*12粒 72 117 NT$6,654 NT$10,812 NT$4,158 62.0
冷凍熟鍋貼 🆕 4 32 NT$458 NT$3,600 NT$3,142 700.0
Tip成功模式:菜單擴展
  • 新增12個品項(從22增至34)
  • 加入熱門品項:紅龍雞塊、鍋貼
  • 現有產品數量也增加50%

關鍵:這間店正在積極擴展菜單以吸引更多顧客。

成功模式2:大屏北早餐-繁華(+16%,找到爆品)

策略:相同品項,但找到一項爆款產品

Code
# 大屏北早餐 product breakdown
success2 = pl.DataFrame({
    "product": ["奇異鳥奶精 25k", "家州黑胡椒里肌 1.2K 🔥", "二代紅450g", "安美燻腸 1000g--促銷", "三代450g", "香Q蛋餅皮(蔥花)30入"],
    "h1_qty": [23, 18, 97, 163, 48, 264],
    "h2_qty": [22, 140, 132, 154, 72, 292],
    "h1_rev": [52225, 4440, 21038, 29805, 15311, 18147],
    "h2_rev": [49956, 35071, 31417, 27429, 23551, 20073]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta"),
    ((pl.col("h2_qty") - pl.col("h1_qty")) / pl.when(pl.col("h1_qty") > 0).then(pl.col("h1_qty")).otherwise(1) * 100).round(0).alias("qty_pct")
])

(
    GT(success2)
    .tab_header(
        title="大屏北早餐-繁華: Found a Winning Product",
        subtitle="Same 47 SKUs, but ONE product exploded 🔥"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
大屏北早餐-繁華: Found a Winning Product
Same 47 SKUs, but ONE product exploded 🔥
product h1_qty h2_qty h1_rev h2_rev delta qty_pct
奇異鳥奶精 25k 23 22 NT$52,225 NT$49,956 −NT$2,269 -4.0
家州黑胡椒里肌 1.2K 🔥 18 140 NT$4,440 NT$35,071 NT$30,631 678.0
二代紅450g 97 132 NT$21,038 NT$31,417 NT$10,379 36.0
安美燻腸 1000g--促銷 163 154 NT$29,805 NT$27,429 −NT$2,376 -6.0
三代450g 48 72 NT$15,311 NT$23,551 NT$8,240 50.0
香Q蛋餅皮(蔥花)30入 264 292 NT$18,147 NT$20,073 NT$1,926 11.0
Tip成功模式:產品聚焦
  • 家州黑胡椒里肌從18 → 140件(+677%!)
  • 多數其他產品維持相似
  • 這一項產品就貢獻+3萬成長

關鍵:找到顧客最愛並大力擴大銷售

成功模式3:順利早點(+26%,新增炸雞品項)

策略:擴展至炸雞產品線

Code
# 順利早點 product breakdown
success3 = pl.DataFrame({
    "product": ["紅龍卡啦雞腿堡(辣) 🆕", "安美燻腸 1000g--促銷", "安美熱狗50條", "金酥3/8脆薯 🔥", "紅龍雞塊 1K--促銷 🔥", "玉米粒 🆕", "杏仁片 500g", "飛燕煉乳 375g"],
    "h1_qty": [0, 13, 160, 7, 50, 0, 15, 116],
    "h2_qty": [98, 94, 295, 45, 97, 312, 25, 171],
    "h1_rev": [0, 2440, 16763, 1533, 7378, 0, 4890, 5295],
    "h2_rev": [18160, 16622, 30893, 9076, 13878, 5694, 8644, 7806]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta")
])

(
    GT(success3)
    .tab_header(
        title="順利早點: Expanded into Fried Chicken",
        subtitle="Added chicken products (🆕) and scaled up fries/nuggets (🔥)"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
順利早點: Expanded into Fried Chicken
Added chicken products (🆕) and scaled up fries/nuggets (🔥)
product h1_qty h2_qty h1_rev h2_rev delta
紅龍卡啦雞腿堡(辣) 🆕 0 98 NT$0 NT$18,160 NT$18,160
安美燻腸 1000g--促銷 13 94 NT$2,440 NT$16,622 NT$14,182
安美熱狗50條 160 295 NT$16,763 NT$30,893 NT$14,130
金酥3/8脆薯 🔥 7 45 NT$1,533 NT$9,076 NT$7,543
紅龍雞塊 1K--促銷 🔥 50 97 NT$7,378 NT$13,878 NT$6,500
玉米粒 🆕 0 312 NT$0 NT$5,694 NT$5,694
杏仁片 500g 15 25 NT$4,890 NT$8,644 NT$3,754
飛燕煉乳 375g 116 171 NT$5,295 NT$7,806 NT$2,511
Tip成功模式:品類擴展
  • 新增炸雞品類:卡啦雞腿堡(0→98件)
  • 擴大相關品項:薯條(+543%)、雞塊(+94%)
  • 也新增配套品項:玉米粒作為配菜

關鍵:擴展至炸雞套餐 - 一個成長中的品類。

2E.4 完整產品明細:10位成長客戶

Code
# Complete breakdown for all 10 customers - key products driving growth
all_growth = pl.DataFrame({
    "customer": [
        "① 壽司早點-蘇惠君", "① 壽司早點-蘇惠君", "① 壽司早點-蘇惠君",
        "② 活力-屏商技", "② 活力-屏商技", "② 活力-屏商技",
        "③ 大屏北-繁華", "③ 大屏北-繁華", "③ 大屏北-繁華",
        "④ 順利早點", "④ 順利早點", "④ 順利早點",
        "⑤ 小田園-久堂", "⑤ 小田園-久堂", "⑤ 小田園-久堂",
        "⑥ 早安8-永大店", "⑥ 早安8-永大店", "⑥ 早安8-永大店",
        "⑦ 早點見面", "⑦ 早點見面", "⑦ 早點見面",
        "⑧ 琉浪日嚐", "⑧ 琉浪日嚐", "⑧ 琉浪日嚐",
        "⑨ 大屏北-龍泉", "⑨ 大屏北-龍泉", "⑨ 大屏北-龍泉",
        "⑩ 迪士米", "⑩ 迪士米", "⑩ 迪士米"
    ],
    "product": [
        "🍗 紅龍卡啦雞腿堡(辣)", "🥟 鮮肉湯包 50入", "🍗 紅龍雞塊 🆕",
        "🍖 每天豬柳 1K", "🍗 正點卡啦雞腿堡 🆕", "🍝 義大利肉醬麵 🆕",
        "🥩 黑胡椒里肌 🔥", "🍳 二代紅450g", "🥓 三代450g",
        "🍗 紅龍卡啦雞腿堡 🆕", "🌭 安美熱狗50條", "🍗 紅龍雞塊",
        "🍗 正點卡啦雞腿堡(辣) 🆕", "🍗 正點卡啦雞腿堡(原) 🆕", "🧀 起士片100片",
        "☕ 新萊恩奶精 🆕", "☕ 萊恩咖啡 🆕", "🍗 紅龍雞塊",
        "🥔 日規薯餅 🆕", "🍗 香雞城卡啦雞腿(辣)", "🍗 香雞城卡啦雞腿(原)",
        "🍕 pizza絲", "🍜 讚岐烏龍麵", "🥫 福鷹玉米粒 🆕",
        "🥩 黑胡椒里肌 🔥", "🥟 阿在伯蔥抓餅", "🍗 香酥雞塊 🆕",
        "🍗 紅龍雞塊 🆕", "🍗 紅龍搖搖雞球", "🥚 香酥蛋餅 🆕"
    ],
    "h1_qty": [152, 266, 0, 89, 0, 0, 18, 97, 48, 0, 160, 50, 1, 0, 14, 0, 0, 25, 0, 31, 37, 46, 6, 0, 12, 20, 0, 0, 12, 0],
    "h2_qty": [258, 392, 70, 186, 49, 360, 140, 132, 72, 98, 295, 97, 133, 93, 52, 315, 90, 128, 89, 92, 98, 75, 36, 120, 177, 292, 41, 70, 57, 88],
    "h1_rev": [28954, 36743, 0, 16963, 0, 0, 4440, 21038, 15311, 0, 16763, 7378, 178, 0, 3798, 0, 0, 3638, 0, 5169, 6183, 12703, 611, 0, 2959, 1676, 0, 0, 2022, 0],
    "h2_rev": [47305, 54130, 9335, 40208, 8676, 8567, 35071, 31417, 23551, 18160, 30893, 13878, 23790, 16619, 14101, 29999, 18859, 17154, 12627, 15511, 16491, 19459, 3668, 2285, 44060, 22428, 12518, 9618, 9605, 7126]
}).with_columns([
    (pl.col("h2_rev") - pl.col("h1_rev")).alias("delta")
])

(
    GT(all_growth)
    .tab_header(
        title="🔍 Top 3 Growth Drivers per Customer",
        subtitle="🆕 = New product in H2, 🔥 = Explosive growth"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
🔍 Top 3 Growth Drivers per Customer
🆕 = New product in H2, 🔥 = Explosive growth
customer product h1_qty h2_qty h1_rev h2_rev delta
① 壽司早點-蘇惠君 🍗 紅龍卡啦雞腿堡(辣) 152 258 NT$28,954 NT$47,305 NT$18,351
① 壽司早點-蘇惠君 🥟 鮮肉湯包 50入 266 392 NT$36,743 NT$54,130 NT$17,387
① 壽司早點-蘇惠君 🍗 紅龍雞塊 🆕 0 70 NT$0 NT$9,335 NT$9,335
② 活力-屏商技 🍖 每天豬柳 1K 89 186 NT$16,963 NT$40,208 NT$23,245
② 活力-屏商技 🍗 正點卡啦雞腿堡 🆕 0 49 NT$0 NT$8,676 NT$8,676
② 活力-屏商技 🍝 義大利肉醬麵 🆕 0 360 NT$0 NT$8,567 NT$8,567
③ 大屏北-繁華 🥩 黑胡椒里肌 🔥 18 140 NT$4,440 NT$35,071 NT$30,631
③ 大屏北-繁華 🍳 二代紅450g 97 132 NT$21,038 NT$31,417 NT$10,379
③ 大屏北-繁華 🥓 三代450g 48 72 NT$15,311 NT$23,551 NT$8,240
④ 順利早點 🍗 紅龍卡啦雞腿堡 🆕 0 98 NT$0 NT$18,160 NT$18,160
④ 順利早點 🌭 安美熱狗50條 160 295 NT$16,763 NT$30,893 NT$14,130
④ 順利早點 🍗 紅龍雞塊 50 97 NT$7,378 NT$13,878 NT$6,500
⑤ 小田園-久堂 🍗 正點卡啦雞腿堡(辣) 🆕 1 133 NT$178 NT$23,790 NT$23,612
⑤ 小田園-久堂 🍗 正點卡啦雞腿堡(原) 🆕 0 93 NT$0 NT$16,619 NT$16,619
⑤ 小田園-久堂 🧀 起士片100片 14 52 NT$3,798 NT$14,101 NT$10,303
⑥ 早安8-永大店 ☕ 新萊恩奶精 🆕 0 315 NT$0 NT$29,999 NT$29,999
⑥ 早安8-永大店 ☕ 萊恩咖啡 🆕 0 90 NT$0 NT$18,859 NT$18,859
⑥ 早安8-永大店 🍗 紅龍雞塊 25 128 NT$3,638 NT$17,154 NT$13,516
⑦ 早點見面 🥔 日規薯餅 🆕 0 89 NT$0 NT$12,627 NT$12,627
⑦ 早點見面 🍗 香雞城卡啦雞腿(辣) 31 92 NT$5,169 NT$15,511 NT$10,342
⑦ 早點見面 🍗 香雞城卡啦雞腿(原) 37 98 NT$6,183 NT$16,491 NT$10,308
⑧ 琉浪日嚐 🍕 pizza絲 46 75 NT$12,703 NT$19,459 NT$6,756
⑧ 琉浪日嚐 🍜 讚岐烏龍麵 6 36 NT$611 NT$3,668 NT$3,057
⑧ 琉浪日嚐 🥫 福鷹玉米粒 🆕 0 120 NT$0 NT$2,285 NT$2,285
⑨ 大屏北-龍泉 🥩 黑胡椒里肌 🔥 12 177 NT$2,959 NT$44,060 NT$41,101
⑨ 大屏北-龍泉 🥟 阿在伯蔥抓餅 20 292 NT$1,676 NT$22,428 NT$20,752
⑨ 大屏北-龍泉 🍗 香酥雞塊 🆕 0 41 NT$0 NT$12,518 NT$12,518
⑩ 迪士米 🍗 紅龍雞塊 🆕 0 70 NT$0 NT$9,618 NT$9,618
⑩ 迪士米 🍗 紅龍搖搖雞球 12 57 NT$2,022 NT$9,605 NT$7,583
⑩ 迪士米 🥚 香酥蛋餅 🆕 0 88 NT$0 NT$7,126 NT$7,126

2E.5 模式分析:什麼驅動成長?

Code
# Count how many of the 10 growing customers use each strategy
driver_summary = pl.DataFrame({
    "growth_driver": [
        "🍗 Fried Chicken (卡啦雞腿堡/雞塊/雞球)",
        "🥟 Quick Prep Items (鍋貼/抓餅/薯餅)",
        "🥩 Black Pepper Pork (黑胡椒里肌)",
        "☕ Beverage Addition (奶精/咖啡)",
        "🍕 Specialty Items (Pizza/烏龍麵)",
        "🍝 Meal Additions (義大利麵)"
    ],
    "customers_using": [8, 6, 2, 1, 1, 1],
    "example_products": [
        "紅龍卡啦雞腿堡, 正點卡啦雞腿堡, 紅龍雞塊, 搖搖雞球",
        "阿在伯蔥抓餅, 熟鍋貼, 日規薯餅, 三角薯餅",
        "家州黑胡椒里肌 1.2K (大屏北兩家店都爆發)",
        "新萊恩奶精800g, 萊恩咖啡400g",
        "pizza絲, 讚岐烏龍麵",
        "金品義大利肉醬麵"
    ],
    "impact": ["HIGH - 主力成長動能", "MEDIUM - 擴大品項", "HIGH - 單品爆發", "MEDIUM - 新品類", "LOW - 特定客群", "LOW - 特定客群"]
})

(
    GT(driver_summary)
    .tab_header(
        title="📊 Growth Driver Analysis (10 Customers)",
        subtitle="What products are driving customer growth?"
    )
    .cols_label(
        customers_using="# Using",
        example_products="Example Products"
    )
)
📊 Growth Driver Analysis (10 Customers)
What products are driving customer growth?
growth_driver # Using Example Products impact
🍗 Fried Chicken (卡啦雞腿堡/雞塊/雞球) 8 紅龍卡啦雞腿堡, 正點卡啦雞腿堡, 紅龍雞塊, 搖搖雞球 HIGH - 主力成長動能
🥟 Quick Prep Items (鍋貼/抓餅/薯餅) 6 阿在伯蔥抓餅, 熟鍋貼, 日規薯餅, 三角薯餅 MEDIUM - 擴大品項
🥩 Black Pepper Pork (黑胡椒里肌) 2 家州黑胡椒里肌 1.2K (大屏北兩家店都爆發) HIGH - 單品爆發
☕ Beverage Addition (奶精/咖啡) 1 新萊恩奶精800g, 萊恩咖啡400g MEDIUM - 新品類
🍕 Specialty Items (Pizza/烏龍麵) 1 pizza絲, 讚岐烏龍麵 LOW - 特定客群
🍝 Meal Additions (義大利麵) 1 金品義大利肉醬麵 LOW - 特定客群
Important🔑 關鍵發現:炸雞是成長品類

10位成長客戶中有8位新增或擴大炸雞產品:

產品 品牌 新增客戶數
卡啦雞腿堡 紅龍/正點/強匠 6位客戶
雞塊 紅龍 4位客戶
雞米花/搖搖雞球 紅龍/香香 2位客戶

這是我們最強的成長槓桿。

2E.6 「黑胡椒里肌」現象 🔥

同一連鎖的兩家店發現了同樣的爆品:

Code
# Black pepper pork across both 大屏北 stores
bpp = pl.DataFrame({
    "store": ["大屏北早餐-繁華1.4", "大屏北早餐-龍泉1.4"],
    "route": ["A-PN", "A-PK"],
    "product": ["家州黑胡椒里肌 1.2K", "家州黑胡椒里肌 1.2K"],
    "h1_qty": [18, 12],
    "h2_qty": [140, 177],
    "growth_pct": ["+678%", "+1375%"],
    "h1_rev": [4440, 2959],
    "h2_rev": [35071, 44060],
    "delta": [30631, 41101]
})

(
    GT(bpp)
    .tab_header(
        title="🔥 Single Product Driving Two Stores",
        subtitle="家州黑胡椒里肌 - The Hidden Champion"
    )
    .fmt_currency(["h1_rev", "h2_rev", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["h1_qty", "h2_qty"], decimals=0)
)
🔥 Single Product Driving Two Stores
家州黑胡椒里肌 - The Hidden Champion
store route product h1_qty h2_qty growth_pct h1_rev h2_rev delta
大屏北早餐-繁華1.4 A-PN 家州黑胡椒里肌 1.2K 18 140 +678% NT$4,440 NT$35,071 NT$30,631
大屏北早餐-龍泉1.4 A-PK 家州黑胡椒里肌 1.2K 12 177 +1375% NT$2,959 NT$44,060 NT$41,101
Tip💡 洞察:交叉銷售爆款產品

家州黑胡椒里肌在僅2間店就從接近零成長至71,000元

行動:辨識哪些其他客戶可能受益於此產品,並主動推薦。

2E.7 成長模式總結

Code
# Categorize each customer by their primary growth strategy
pattern_summary = pl.DataFrame({
    "pattern": [
        "🍗 Chicken Expansion",
        "🍗 Chicken Expansion", 
        "🥩 Single Product Champion",
        "🍗 Chicken Expansion",
        "🍗 Chicken Expansion",
        "☕ Category Addition",
        "🍗 Chicken + Japanese Style",
        "🍕 Specialty Focus",
        "🥩 Single Product Champion",
        "🍗 Chicken Expansion"
    ],
    "customer": [
        "壽司早點-蘇惠君",
        "活力-屏商技",
        "大屏北-繁華",
        "順利早點",
        "小田園-久堂",
        "早安8-永大店",
        "早點見面",
        "琉浪日嚐",
        "大屏北-龍泉",
        "迪士米"
    ],
    "growth": ["+53%", "+65%", "+16%", "+26%", "+25%", "+22%", "+24%", "+31%", "+13%", "+46%"],
    "key_action": [
        "Added 12 SKUs + volume up",
        "School café: quick meals + chicken",
        "Found 里肌排 winner, scaled it",
        "Added fried chicken category",
        "ALL-IN on 卡啦雞腿堡",
        "Added coffee/beverage line",
        "Expanded fried + Japanese items",
        "Pizza/烏龍麵 specialty",
        "Same winner as sister store",
        "Massive chicken product addition"
    ]
})

pattern_counts = pattern_summary.group_by("pattern").agg(pl.count().alias("count")).sort("count", descending=True)

(
    GT(pattern_counts)
    .tab_header(
        title="Growth Strategy Distribution",
        subtitle="How are successful customers growing?"
    )
)
Growth Strategy Distribution
How are successful customers growing?
pattern count
🍗 Chicken Expansion 5
🥩 Single Product Champion 2
🍗 Chicken + Japanese Style 1
☕ Category Addition 1
🍕 Specialty Focus 1

2E.8 業務團隊可執行洞察

Important🎯 業務手冊:將衰退客戶轉變為成長客戶

根據10位成功客戶的分析,以下是業務團隊的具體行動

優先順序1:推廣炸雞產品 🍗

10位成長客戶中有8位是透過炸雞成長的。對於任何衰退客戶:

情境 建議產品 話術
傳統早餐店 紅龍卡啦雞腿堡(辣/原) “學生最愛的雞腿堡,比漢堡肉毛利更高”
快速服務早餐店 紅龍雞塊 1K “配餐搭配,薯條+雞塊套餐正流行”
高檔咖啡廳 正點卡啦雞腿堡 “品質更好的雞腿堡,適合精緻早午餐”

優先順序2:介紹「黑胡椒里肌」爆品 🥩

家州黑胡椒里肌 1.2K僅在2間店就貢獻+71K營收

  • 目標:大屏北系列以外的早餐店
  • 話術:“大屏北兩家店賣這個都爆了,你們店型很像要不要試試?”

優先順序3:建議快速料理品項 🥟

對於客流穩定但營收持平的店家:

產品 使用情境
阿在伯蔥抓餅 新增下午茶/宵夜時段
熟鍋貼 快速加熱,適合中午加賣
日規薯餅 搭配雞腿堡做套餐

優先順序4:飲品品類(選擇性)☕

對於沒有咖啡服務的店家: - 新萊恩奶精 800g + 萊恩咖啡 400g - 早安8-永大店靠這個增加 +48K

Tip🔄 如何在業務拜訪中運用這些資料

衰退客戶話術:

“我看到你最近幾個月訂貨量有下降一點,想來聊聊看有什麼我們可以幫忙的。我們有些客戶最近做得很好,主要是加了雞腿堡系列 — 你有沒有興趣試試看?第一批我可以給你優惠價。”

以數據跟進:

“像壽司早點最近加了12個新品項,業績成長超過50%。他們主要加的是卡啦雞腿堡跟雞塊,你們店應該也適合。”

2C.5 上下半年洞察總結

Code
# Visualization of H1->H2 patterns - Active customers only
pattern_data = pl.DataFrame({
    "pattern": ["📦 Demand Down\n(83 customers)", "📉 Both Down\n(36 customers)", "🔄 Mixed\n(33 customers)", "🗑️ Competitor?\n(7 customers)"],
    "delta": [-3454690, -1542032, -665787, -277958],
    "order": [1, 2, 3, 4]
})

chart = alt.Chart(pattern_data).mark_bar().encode(
    x=alt.X("pattern:N", sort=alt.EncodingSortField(field="order"), title=None),
    y=alt.Y("delta:Q", title="Revenue Change (TWD)"),
    color=alt.condition(
        alt.datum.delta < -1000000,
        alt.value("#dc3545"),  # Red for big declines
        alt.value("#fd7e14")   # Orange for smaller
    ),
    tooltip=["pattern", "delta"]
).properties(
    width=500,
    height=300,
    title="H1→H2 2025 Revenue Impact by Decline Pattern (Active Customers)"
)

chart
Important🎯 我們處於什麼環境?

數據明確回答:需求放緩,而非競爭壓力。

證據 發現
客戶停購我方品項 僅7位(衰退客戶的4%)
可能流失給競爭對手的營收 27.8萬元(衰退的5%)
客戶減少購買相同產品 83位(衰退客戶的52%)
因需求下降而損失的營收 350萬元(衰退的58%)

這對策略的意義:

  1. 降價無法解決 - 客戶不需要更多產品
  2. 積極推銷無法解決 - 他們的終端客戶不買
  3. 專注客戶存活 - 幫助他們度過低潮
  4. 成本管理 - 為持續疲軟的需求做準備
  5. 注意歇業風險 - 部分「📉 兩者皆降」客戶可能即將歇業

多據點衰退的連鎖:

  • 宵歸暝(2間店)- 全連鎖放緩
  • 香醇軒(2間店)- 全連鎖放緩
  • 萊恩快速早餐(再次出現)

2.8 軍營分析

Code
# Find all military camp customers (營區)
military = (
    customers
    .filter(_.trade_name.like("%營區%"))
    .left_join(sales_orders, "customer_code")
    .filter(_.order_date >= "20240101")
    .left_join(sales_order_lines, ["order_type", "order_number"])
    .mutate(year=_.order_date.left(4))
    # Note: delivery_route here comes from sales_orders
    .group_by(["customer_code", "trade_name", "customer_route"])
    .agg(
        rev_2024=ibis.ifelse(_.year == "2024", _.pretax_subtotal.cast("float64"), 0).sum(),
        rev_2025=ibis.ifelse(_.year == "2025", _.pretax_subtotal.cast("float64"), 0).sum(),
        last_order=_.order_date.max()
    )
    .filter(_.rev_2024 > 100000)
    .rename(delivery_route="customer_route")
    .order_by(ibis.desc("rev_2024"))
    .to_polars()
)

(
    GT(military)
    .tab_header(
        title="Military Camp Customers",
        subtitle="營區 customers - major decline in government/institutional sales"
    )
    .fmt_currency(["rev_2024", "rev_2025"], currency="TWD", decimals=0, use_subunits=False)
)
Military Camp Customers
營區 customers - major decline in government/institutional sales
customer_code trade_name delivery_route rev_2024 rev_2025 last_order
1250002 萬金營區-3 K1 NT$1,061,345 NT$538,141 20251210
2790003 加祿堂營區-熱食部2.5 K2 NT$926,738 NT$101,621 20250701
Warning軍營營收崩盤:約130萬元
  • 加祿堂營區:下滑91%(91.3萬 → 10.2萬)
  • 萬金營區:下滑51%(100萬 → 49.3萬)

業務團隊回饋(2025年12月):

“加祿堂:經營者退出” - 經營者離開了

加祿堂根本原因:並非競爭流失 - 餐飲經營者離開了。這是軍營層級的合約/廠商變更。

2D. 業務團隊情報更新 📋

Note來自業務團隊的第一手資訊(2025年12月)

以下更新是從業務團隊針對特定客戶的回饋中彙整:

確認的競爭流失 🚨

客戶 流失至 原因
昌平炸雞(16個據點) 其他通路供應商 總部統一管理 + 與雞肉供應商整合配送
沫晨 啟順 配送時間 + 價格

確認的歇業/退出 🔒

客戶 狀態 備註
茶棠屋 歇業 -
好地方 暫時歇業 身體因素
加祿堂營區 經營者退出 餐飲經營者離開

搬遷/整併 🔄

客戶 狀態 備註
宵歸暝-內埔 搬至高雄 更名為呷歸岡
永和民生 整併 產品現從潭頭永和出貨

仍活躍但有變動 📝

客戶 狀態
弘爺漢堡-屏工 現全為門市消費
林邊刈包 每週有新美式咖啡
Important修正後的流失歸因

根據業務團隊回饋,我們現在可以歸因特定流失

原因 營收影響 可挽回?
競爭流失(昌平 + 沫晨) 約100萬 + 未知 昌平:困難(物流問題)。沫晨:可能(價格/服務)
歇業(茶棠屋、好地方、加祿堂) 約100萬 ❌ 否
搬遷(宵歸暝、永和民生) 營收仍在其他地方 不適用

關鍵洞察昌平流失不只是價格問題 - 他們想要與雞肉供應商整合物流。這比單純的價格戰更難競爭。

沫晨配送時間和價格上輸給啟順 - 這個可能透過改善服務來挽回。

2.7 近期流失:2025下半年(9-11月)🚨

這些客戶在2025上半年活躍,但9月以來未再訂購。需要立即關注。

Code
# Customers active in H1 2025 (Jan-Jun)
h1_2025_customers = (
    sales_orders
    .filter(_.delivery_route.isin(VALID_ROUTES_YOY))
    .filter(_.order_date >= "20250101")
    .filter(_.order_date <= "20250630")
    .left_join(sales_order_lines, ["order_type", "order_number"])
    .left_join(product_info, _.item_code == product_info.product_code)
    .filter((_.product_category_1.isnull()) | (_.product_category_1 != "1"))
    .group_by("customer_code")
    .agg(h1_revenue=_.pretax_subtotal.cast("float64").sum())
    .filter(_.h1_revenue > 30000)  # Focus on significant customers
    .to_polars()
)

# Customers active in H2 2025 (Sept-Nov) - rolling 90-day window
h2_active = (
    sales_orders
    .filter(_.delivery_route.isin(VALID_ROUTES_YOY))
    .filter(_.order_date >= "20250901")
    .filter(_.order_date <= "20251130")
    .select("customer_code")
    .distinct()
    .to_polars()
)

# H2 churns: active in H1, not in H2
h2_churns = (
    h1_2025_customers
    .join(h2_active, on="customer_code", how="anti")  # NOT in H2
)

# Join with customer info
h2_churn_detail = (
    customers
    .to_polars()
    .join(h2_churns, on="customer_code", how="inner")
    .with_columns(
        pl.when(pl.col("closure_date").is_not_null())
          .then(pl.lit("🔒 CLOSED"))
          .otherwise(pl.lit("⚠️ INVESTIGATE"))
          .alias("status")
    )
    .rename({"customer_route": "delivery_route"})
    .sort("h1_revenue", descending=True)
    .head(20)
    .select(["customer_code", "trade_name", "delivery_route", "status", "h1_revenue"])
)

(
    GT(h2_churn_detail)
    .tab_header(
        title="🚨 H2 2025 Churn: Active in H1, Silent Since September",
        subtitle="Customers with >30K H1 revenue who haven't ordered Sept-Nov 2025"
    )
    .fmt_currency("h1_revenue", currency="TWD", decimals=0, use_subunits=False)
)
🚨 H2 2025 Churn: Active in H1, Silent Since September
Customers with >30K H1 revenue who haven't ordered Sept-Nov 2025
customer_code trade_name delivery_route status h1_revenue
2230002 好地方-3 K1 ⚠️ INVESTIGATE NT$127,543
0110023 永和-屏東民生 A-PT ⚠️ INVESTIGATE NT$115,805
0190018 反轉厚奶酥-屏東店 A-PT ⚠️ INVESTIGATE NT$78,831
2790003 加祿堂營區-熱食部2.5 K2 ⚠️ INVESTIGATE NT$72,879
4430003 雲天咖啡館(雲天一館)2.5 K1 ⚠️ INVESTIGATE NT$65,536
3490031 無尾熊牛排館 PK ⚠️ INVESTIGATE NT$59,173
1320262 茶棠屋1.4 A-PK ⚠️ INVESTIGATE NT$51,615
0111149 早安8快速早餐-陳宗燦 A-PT ⚠️ INVESTIGATE NT$49,683
4610023 早到晚到總部-央廚1.4 A ⚠️ INVESTIGATE NT$43,962
0910064 玉雲早餐 PT ⚠️ INVESTIGATE NT$42,006
0990001 反轉奶酥-里港2.5 A-PN ⚠️ INVESTIGATE NT$36,091
0390010 豐BAR 酒吧咖啡 PK ⚠️ INVESTIGATE NT$35,260
1030005 元氣飯糰1.4 A-PN ⚠️ INVESTIGATE NT$34,855
0230045 文記肉圓-潮州 PS ⚠️ INVESTIGATE NT$32,400
3410045 榕心早餐店 PK ⚠️ INVESTIGATE NT$32,240
5810241 胖橘早午餐2.5 K1 ⚠️ INVESTIGATE NT$32,233
PTP PT外送 PT ⚠️ INVESTIGATE NT$31,277
0280005 林枳宏 PS ⚠️ INVESTIGATE NT$30,454
Important需立即行動

這些客戶最近在2025年6月還向我們購買,但現在已沒有音訊。⚠️ 需調查狀態表示:

  • 檔案中無歇業日期 - 他們可能仍在營業
  • 可能是競爭流失、服務問題,或單純漏掉
  • 本週就要打電話給他們,趁關係還沒完全冷掉

2B. 門市業績表現 🏪

我們的門市顯示-620萬元衰退(-4.5%)。這與配送業務分開計算。

2B.1 門市營收概覽

Code
# Store mapping
STORE_NAMES = {
    "01": "01-屏東市 Pingtung",
    "02": "02-潮州 Chaozhou", 
    "03": "03-恆春 Hengchun",
    "04": "04-東港 Donggang"
}

# Retail store performance
retail_summary = pl.DataFrame({
    "store_code": ["01", "02", "03", "04"],
    "store_name": ["屏東市 Pingtung", "潮州 Chaozhou", "恆春 Hengchun", "東港 Donggang"],
    "rev_2024": [29242256, 51051794, 22624105, 33514519],
    "rev_2025": [27668306, 47543362, 22475803, 32522939],
    "txn_2024": [93373, 233462, 97813, 145925],
    "txn_2025": [87159, 209298, 94357, 137276],
    "skus_2024": [997, 1015, 1043, 1064],
    "skus_2025": [954, 980, 997, 1020]
}).with_columns([
    (pl.col("rev_2025") - pl.col("rev_2024")).alias("delta"),
    ((pl.col("rev_2025") - pl.col("rev_2024")) / pl.col("rev_2024") * 100).round(1).alias("pct_change"),
    ((pl.col("txn_2025") - pl.col("txn_2024")) / pl.col("txn_2024") * 100).round(1).alias("txn_pct")
])

(
    GT(retail_summary)
    .tab_header(
        title="🏪 Retail Store Performance YoY",
        subtitle="POS sales data (Jan-Nov 2024 vs 2025)"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_number(["txn_2024", "txn_2025"], decimals=0, use_seps=True)
    .fmt_percent(["pct_change", "txn_pct"], decimals=1, scale_values=False)
    .cols_label(
        pct_change="Rev Δ%",
        txn_pct="Txn Δ%",
        skus_2024="SKUs '24",
        skus_2025="SKUs '25"
    )
)
🏪 Retail Store Performance YoY
POS sales data (Jan-Nov 2024 vs 2025)
store_code store_name rev_2024 rev_2025 txn_2024 txn_2025 SKUs '24 SKUs '25 delta Rev Δ% Txn Δ%
01 屏東市 Pingtung NT$29,242,256 NT$27,668,306 93,373 87,159 997 954 −NT$1,573,950 −5.4% −6.7%
02 潮州 Chaozhou NT$51,051,794 NT$47,543,362 233,462 209,298 1015 980 −NT$3,508,432 −6.9% −10.4%
03 恆春 Hengchun NT$22,624,105 NT$22,475,803 97,813 94,357 1043 997 −NT$148,302 −0.7% −3.5%
04 東港 Donggang NT$33,514,519 NT$32,522,939 145,925 137,276 1064 1020 −NT$991,580 −3.0% −5.9%
Important🏪 門市:總計衰退620萬元
門市 衰退 分析
潮州 -350萬(-6.9%) 最大店、最大衰退 - 優先處理
屏東市 -160萬(-5.4%) 交易筆數下滑6.7%
東港 -100萬(-3.0%) 中度衰退
恆春 -10萬(-0.7%) 穩定!唯一持平的店

交易筆數下滑5-10% = 進店顧客減少,而非客單價下降。

2B.2 各門市產品品類組合

Code
# Category mix data by store - showing biggest declines
retail_cat = pl.DataFrame([
    {"store": "02-潮州", "category": "5-冷凍 Frozen", "rev_2024": 27519161, "rev_2025": 25956745},
    {"store": "02-潮州", "category": "2-成品 Finished", "rev_2024": 12315196, "rev_2025": 11463515},
    {"store": "02-潮州", "category": "3-生產分裝", "rev_2024": 2212976, "rev_2025": 1863494},
    {"store": "02-潮州", "category": "7-免洗餐具 Disposable", "rev_2024": 1193400, "rev_2025": 886070},
    {"store": "01-屏東", "category": "2-成品 Finished", "rev_2024": 7225744, "rev_2025": 6534733},
    {"store": "01-屏東", "category": "5-冷凍 Frozen", "rev_2024": 13808680, "rev_2025": 13506495},
    {"store": "04-東港", "category": "2-成品 Finished", "rev_2024": 7889325, "rev_2025": 7497197},
    {"store": "04-東港", "category": "4-冷藏 Refrigerated", "rev_2024": 3741057, "rev_2025": 3448101},
]).with_columns([
    (pl.col("rev_2025") - pl.col("rev_2024")).alias("delta"),
    ((pl.col("rev_2025") - pl.col("rev_2024")) / pl.col("rev_2024") * 100).round(1).alias("pct")
]).sort("delta")

(
    GT(retail_cat)
    .tab_header(
        title="Biggest Category Declines by Store",
        subtitle="Categories with largest YoY revenue decline"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent("pct", decimals=1, scale_values=False)
)
Biggest Category Declines by Store
Categories with largest YoY revenue decline
store category rev_2024 rev_2025 delta pct
02-潮州 5-冷凍 Frozen NT$27,519,161 NT$25,956,745 −NT$1,562,416 −5.7%
02-潮州 2-成品 Finished NT$12,315,196 NT$11,463,515 −NT$851,681 −6.9%
01-屏東 2-成品 Finished NT$7,225,744 NT$6,534,733 −NT$691,011 −9.6%
04-東港 2-成品 Finished NT$7,889,325 NT$7,497,197 −NT$392,128 −5.0%
02-潮州 3-生產分裝 NT$2,212,976 NT$1,863,494 −NT$349,482 −15.8%
02-潮州 7-免洗餐具 Disposable NT$1,193,400 NT$886,070 −NT$307,330 −25.8%
01-屏東 5-冷凍 Frozen NT$13,808,680 NT$13,506,495 −NT$302,185 −2.2%
04-東港 4-冷藏 Refrigerated NT$3,741,057 NT$3,448,101 −NT$292,956 −7.8%
Note門市品類洞察

冷凍(5-冷凍)潮州店:-160萬(-5.7%)

  • 單一品類最大衰退
  • 需調查:定價、選品、競爭對手動態

成品(2-成品):全店共減少150萬

  • 各店一致下滑5-10%
  • 可能包含已結束的促銷品項

免洗餐具(7-免洗餐具)潮州店:-30.7萬(-26%!)

  • 劇烈下滑 - 環保政策?消費行為改變?
  • 確認顧客是否自帶容器

2B.3 門市主要衰退產品

Code
# Top declining products in retail
retail_declining = pl.DataFrame({
    "product_code": ["26068", "11001", "31026", "54057", "31011", "53126", "56041", "41029", "51284", "51477"],
    "product_name": ["雙魚座鮪魚185g--促銷", "咖啡風味調味粉 1k(棕)", "第二代(黑)1k##", "黃金手工蔥抓餅10片", "168奶精 1k", "卡啦雞(原味)10入", "抓餅(禾)10片", "安佳84片乳酪--促銷", "馬鈴薯條 2K--促銷", "HISUN五花培根1K##"],
    "category": ["2", "1", "3", "5", "3", "5", "5", "4", "5", "5"],
    "rev_2024": [1001618, 1748945, 359842, 737975, 1818068, 764314, 1289514, 900562, 2397763, 144851],
    "rev_2025": [238245, 1342622, 0, 487594, 1637173, 591263, 1128021, 746408, 2250179, 0]
}).with_columns([
    (pl.col("rev_2025") - pl.col("rev_2024")).alias("delta")
]).sort("delta")

(
    GT(retail_declining)
    .tab_header(
        title="Top 10 Declining Products in Retail Stores",
        subtitle="Products with biggest YoY revenue decline (all stores)"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
)
Top 10 Declining Products in Retail Stores
Products with biggest YoY revenue decline (all stores)
product_code product_name category rev_2024 rev_2025 delta
26068 雙魚座鮪魚185g--促銷 2 NT$1,001,618 NT$238,245 −NT$763,373
11001 咖啡風味調味粉 1k(棕) 1 NT$1,748,945 NT$1,342,622 −NT$406,323
31026 第二代(黑)1k## 3 NT$359,842 NT$0 −NT$359,842
54057 黃金手工蔥抓餅10片 5 NT$737,975 NT$487,594 −NT$250,381
31011 168奶精 1k 3 NT$1,818,068 NT$1,637,173 −NT$180,895
53126 卡啦雞(原味)10入 5 NT$764,314 NT$591,263 −NT$173,051
56041 抓餅(禾)10片 5 NT$1,289,514 NT$1,128,021 −NT$161,493
41029 安佳84片乳酪--促銷 4 NT$900,562 NT$746,408 −NT$154,154
51284 馬鈴薯條 2K--促銷 5 NT$2,397,763 NT$2,250,179 −NT$147,584
51477 HISUN五花培根1K## 5 NT$144,851 NT$0 −NT$144,851
Warning🔍 門市產品衰退分析

促銷結束品項(–促銷):

  • 雙魚座鮪魚185g:-76.3萬(促銷結束)
  • 安佳84片乳酪:-15.4萬
  • 這些是預期中的 - 促銷不會永遠持續

停產品項(##):

  • 第二代(黑)1k:-36萬(由450g取代)
  • HISUN五花培根1K:-14.5萬
  • 確認替代品項銷售以驗證轉換

真正需關注

  • 黃金手工蔥抓餅:-25萬(無替代品)
  • 卡啦雞:-17.3萬
  • 抓餅(禾):-16.1萬

3. 路線業績(A-PK/K2 合併)

Note路線重組說明

在2024-2025年路線重組中,約98位客戶從A-PK調整至K2。我們將A-PK與K2合併分析以呈現真實的區域績效。

3.1 路線年度比較

Code
# Route performance - combine A-PK and K2 into a single "Donggang/K2 Area"
route_sales = (
    sales_with_lines
    .mutate(
        route_group=ibis.ifelse(
            _.delivery_route.isin(COMBINED_APK_K2), 
            "A-PK + K2 (Combined)", 
            _.delivery_route
        )
    )
    .group_by(["route_group", "year"])
    .agg(
        revenue=_.pretax_subtotal.cast("float64").sum(),
        customers=_.customer_code.nunique()
    )
    .to_polars()
)

# Pivot to get YoY comparison
route_yoy = (
    route_sales
    .pivot(on="year", index="route_group", values=["revenue", "customers"])
    .with_columns([
        (pl.col("revenue_2025") - pl.col("revenue_2024")).alias("delta"),
        ((pl.col("revenue_2025") - pl.col("revenue_2024")) / pl.col("revenue_2024") * 100).round(1).alias("pct_change")
    ])
    .filter(pl.col("revenue_2024") > 1000000)
    .sort("delta")
)

(
    GT(route_yoy)
    .tab_header(
        title="Route Performance YoY (A-PK and K2 Combined)",
        subtitle="Routes with >1M TWD 2024 revenue, sorted by revenue change"
    )
    .cols_label(route_group="Route/Area")
    .fmt_currency(["revenue_2024", "revenue_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent("pct_change", decimals=1, scale_values=False)
    .cols_hide(["customers_2024", "customers_2025"])
)
Route Performance YoY (A-PK and K2 Combined)
Routes with >1M TWD 2024 revenue, sorted by revenue change
Route/Area revenue_2024 revenue_2025 delta pct_change
A-PK + K2 (Combined) NT$51,856,344 NT$45,003,822 −NT$6,852,522 −13.2%
A-PT NT$26,161,848 NT$23,182,815 −NT$2,979,033 −11.4%
A-PN NT$30,026,890 NT$27,542,316 −NT$2,484,574 −8.3%
K1 NT$28,488,596 NT$26,299,586 −NT$2,189,010 −7.7%
PK NT$16,517,049 NT$15,671,351 −NT$845,698 −5.1%
PS NT$6,969,287 NT$6,260,593 −NT$708,694 −10.2%
Note路線洞察(已校正重組影響)
  • A-PK + K2 合併:下滑200萬(-4.3%)- 顯著但非A-PK單獨呈現的-12.5%
  • A-PT:下滑66.3萬(-2.8%)- 中度關注
  • A-PN:基本持平(+0.8%)
  • K1:成長中(+1.1%)

東港/高雄二區(A-PK + K2)表現不佳,但並非個別路線分析顯示的那麼嚴重。

3.2 A-PK + K2 區域:主要客戶變動

Code
# Customers in the A-PK + K2 area with biggest changes
apk_k2_customers = (
    sales_with_lines
    .filter(_.delivery_route.isin(COMBINED_APK_K2))
    .group_by(["customer_code", "year"])
    .agg(revenue=_.pretax_subtotal.cast("float64").sum())
    .to_polars()
    .pivot(on="year", index="customer_code", values="revenue")
    .fill_null(0)
    .with_columns(
        (pl.col("2025") - pl.col("2024")).alias("delta")
    )
    .filter((pl.col("2024") >= 50000) | (pl.col("2025") >= 50000))
    .sort("delta")
    .head(15)
)

# Join with customer info
apk_k2_with_info = (
    customers
    .to_polars()
    .join(apk_k2_customers, on="customer_code", how="inner")
    .rename({"2024": "revenue_2024", "2025": "revenue_2025", "customer_route": "delivery_route"})
    .sort("delta")
)

(
    GT(apk_k2_with_info)
    .tab_header(
        title="A-PK + K2 Area: Customers Driving Decline",
        subtitle="Biggest YoY revenue decreases in the Donggang/Kaohsiung-2 area"
    )
    .fmt_currency(["revenue_2024", "revenue_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
)
A-PK + K2 Area: Customers Driving Decline
Biggest YoY revenue decreases in the Donggang/Kaohsiung-2 area
customer_code trade_name delivery_route closure_date revenue_2024 revenue_2025 delta
2790003 加祿堂營區-熱食部2.5 K2 None NT$864,272 NT$76,665 −NT$787,607
5910033 恬芯快速早餐-大寮2.5 K1 None NT$1,382,369 NT$668,110 −NT$714,259
5810152 小田園直營-中崙-2.5 K2 20250221 NT$607,714 NT$23,973 −NT$583,741
5810150 小田園直營-南和-2.5 K1 None NT$1,134,233 NT$589,069 −NT$545,164
4410026 小田園直營店-中安2.5 K1 None NT$1,105,567 NT$573,736 −NT$531,831
5410002 美味田園-梓官1.4 K2 None NT$1,226,446 NT$755,189 −NT$471,257
4410018 萊恩快速早餐-二苓2.5 K1 None NT$866,017 NT$445,707 −NT$420,310
4410008 小田園直營-桂林-2.5 K1 None NT$817,151 NT$399,230 −NT$417,921
4410009 小田園直營-二苓2.5 K1 None NT$748,177 NT$367,681 −NT$380,496
4410033 香醇軒-孔宅店2.5 K1 None NT$585,097 NT$212,903 −NT$372,194
5810141 香醇軒-鳳甲店-2.5 K1 None NT$568,406 NT$213,694 −NT$354,712
5310001 美味田園-岡山-1.4 K2 None NT$977,071 NT$631,752 −NT$345,319
10610004 就是堡快速早餐-1 K2 None NT$682,508 NT$366,829 −NT$315,679
5810154 小田園直營-田中央2.5 K1 None NT$552,906 NT$243,686 −NT$309,220
5910025 小田園直營-鳳林2.5 K1 None NT$504,903 NT$213,412 −NT$291,491

4. 毛利分析

4.1 品類毛利(外部產品)

Code
# Calculate margins by category
margin_data = (
    sales_with_lines
    .mutate(month=_.order_date.left(6))
    .left_join(
        procurement_costs, 
        [_.item_code == procurement_costs.product_code, _.month == procurement_costs.inventory_month]
    )
    .mutate(
        qty=(_.quantity.cast("float64") + _.promo_quantity.fill_null(0).cast("float64")),
        cogs=(_.quantity.cast("float64") + _.promo_quantity.fill_null(0).cast("float64")) * _.unit_cost.fill_null(0).cast("float64")
    )
    .filter(_.product_category_1.notnull())
    .filter(_.product_category_1 != "1")  # Exclude internal
    .group_by(["product_category_1", "year"])
    .agg(
        revenue=_.pretax_subtotal.cast("float64").sum(),
        cogs=_.cogs.sum()
    )
    .to_polars()
)

# Pivot and calculate margins
margins = (
    margin_data
    .pivot(on="year", index="product_category_1", values=["revenue", "cogs"])
    .with_columns([
        ((pl.col("revenue_2024") - pl.col("cogs_2024")) / pl.col("revenue_2024") * 100).round(1).alias("margin_2024"),
        ((pl.col("revenue_2025") - pl.col("cogs_2025")) / pl.col("revenue_2025") * 100).round(1).alias("margin_2025")
    ])
    .filter(pl.col("revenue_2024") > 1000000)
    .with_columns(
        pl.col("product_category_1").replace(CAT_NAMES).alias("category")
    )
    .sort("margin_2025")
)

(
    GT(margins.select(["category", "revenue_2024", "revenue_2025", "margin_2024", "margin_2025"]))
    .tab_header(
        title="Category Margin Comparison",
        subtitle="Margin % by product category (excluding internal Category 1)"
    )
    .fmt_currency(["revenue_2024", "revenue_2025"], currency="TWD", decimals=0, use_subunits=False)
    .fmt_percent(["margin_2024", "margin_2025"], decimals=1, scale_values=False)
)
Category Margin Comparison
Margin % by product category (excluding internal Category 1)
category revenue_2024 revenue_2025 margin_2024 margin_2025
2-成品 NT$44,257,055 NT$40,035,943 14.6% 15.2%
4-冷藏類 NT$12,705,715 NT$11,938,215 19.7% 17.8%
5-冷凍類 NT$89,192,131 NT$79,042,830 19.6% 19.0%
3-生產分裝 NT$10,502,960 NT$10,055,944 24.3% 20.3%
9-調味添加物 NT$1,863,357 NT$1,704,028 24.3% 25.5%
7-免洗餐具 NT$1,495,645 NT$1,178,220 31.7% 33.0%
Note毛利洞察
  • 類別3(生產分裝):毛利從24.4%降至20.3%(-4.1個百分點)- 需調查供應商成本
  • 類別4(冷藏):毛利從19.6%降至17.8%(-1.8個百分點)
  • 類別5(冷凍):穩定在約19%
  • 類別2(成品):實際上有改善,從14.6%升至15.2%

5. 產品分析

5.1 品項轉換(實際上並非衰退)

Code
# Coffee/creamer products - show that 1kg packages were replaced by 450g
coffee_products = (
    sales_with_lines
    .filter(
        (_.product_name.like("%二代%")) | 
        (_.product_name.like("%三代%")) | 
        (_.product_name.like("%萊恩%"))
    )
    .group_by(["item_code", "product_name", "year"])
    .agg(revenue=_.pretax_subtotal.cast("float64").sum())
    .to_polars()
    .pivot(on="year", index=["item_code", "product_name"], values="revenue")
    .fill_null(0)
    .with_columns(
        (pl.col("2025") - pl.col("2024")).alias("delta")
    )
    .filter((pl.col("2024") > 100000) | (pl.col("2025") > 100000))
    .rename({"2024": "rev_2024", "2025": "rev_2025"})
    .sort("product_name")
)

(
    GT(coffee_products)
    .tab_header(
        title="Coffee/Creamer SKU Transitions",
        subtitle="Old 1K packages discontinued, new 450g packages growing"
    )
    .fmt_currency(["rev_2024", "rev_2025", "delta"], currency="TWD", decimals=0, use_subunits=False)
)
Coffee/Creamer SKU Transitions
Old 1K packages discontinued, new 450g packages growing
item_code product_name rev_2024 rev_2025 delta
31101 三代450g NT$708,458 NT$1,188,692 NT$480,234
31099 二代紅450g NT$448,686 NT$1,146,416 NT$697,730
31100 二代黑450g NT$556,516 NT$1,003,455 NT$446,939
31015 新萊恩奶精(鋁)1K## NT$1,421,378 NT$1,094,723 −NT$326,655
31089 新萊恩奶精800g NT$0 NT$266,749 NT$266,749
31003 第三代1k## NT$462,983 NT$0 −NT$462,983
31002 第二代(紅)1k## NT$445,269 NT$0 −NT$445,269
31026 第二代(黑)1k (藍)## NT$390,558 NT$0 −NT$390,558
31090 萊恩咖啡400g NT$0 NT$244,203 NT$244,203
31064 萊恩咖啡粉500G## NT$1,088,052 NT$599,877 −NT$488,175
21053 萊恩專用紅茶50g*60包(紅色) NT$486,856 NT$447,854 −NT$39,002
Tip好消息:產品組合穩定

看似產品停產實際上是品項整合

  • 第二代(紅)1k → 二代紅450g(較小包裝,成長中)
  • 第二代(黑)1k → 二代黑450g(較小包裝,成長中)
  • 第三代1k → 三代450g(較小包裝,成長中)
  • 萊恩咖啡粉500g → 萊恩咖啡400g(新包裝)

淨效果:咖啡/奶精營收穩定,只是轉移至新品項。

6. 行動計畫

Important🚨 立即行動(本週)

1. 🏪 門市緊急處理 - 聚焦潮州

  • 為何:-350萬(-6.9%),單一最大衰退
  • 行動
    • 今天就去潮州店 - 與員工討論客流量
    • 檢視產品陳列與競爭對手定價比較
    • 確認附近是否有競爭對手開店或進行激進促銷
    • 比較潮州與穩定的恆春店 - 有什麼不同?

2. 🎖️ 軍營聯絡人會議

  • 為何:僅2個帳戶(加祿堂、萬金)就減少130萬
  • 行動
    • 立即聯繫軍方採購窗口
    • 詢問:預算削減?政策變動?合約重新招標?
    • 如果合約即將更新,現在就準備競標方案

3. 📞 連鎖客戶拜訪

  • 萊恩快速早餐(4個據點,-120萬):與加盟主會面
  • 香醇軒(3個據點,-84萬):與連鎖經營者會面

昌平炸雞更新:業務團隊確認他們轉向與雞肉供應商整合配送。難以挽回 - 需要物流解決方案。

3b. 🎯 可挽回的競爭流失:沫晨

  • 配送時間和價格上輸給啟順
  • 可能透過以下方式挽回:
    • 較早的配送時段
    • 競爭性價格檢視
    • 服務補救拜訪
Warning⚡ 策略回應(本月)

4. 接受現實:這是需求放緩

  • 僅4%的衰退客戶顯示轉向競爭對手跡象
  • 96%是向我們買更少相同產品
  • 降價無法解決 - 他們不需要更多產品
  • 激進促銷無法解決 - 他們的顧客不買

5. 轉向客戶存活支援

不是推銷,而是幫助客戶度過低潮:

  • 付款條件彈性給壓力較大的客戶
  • 較小包裝給正在縮減規模的客戶
  • 菜單優化諮詢 - 幫助他們砍掉不賺錢的品項
  • 歇業預警 - 部分「📉 兩者皆降」客戶可能即將歇業

6. 成本管理模式

  • 預期需求疲軟將持續至2025年初
  • 檢視庫存水位 - 不要囤積生鮮
  • 監控固定成本 - 可能需要調整人力/路線
Note📊 持續監控

7. 需建立的週報儀表板

  • 客戶訂購量追蹤器(及早發現-30%下滑)
  • 門市交易筆數趨勢
  • 路線營收(含A-PK/K2合併視圖)

8. 所有業務會議的關鍵訊息

「問題不是競爭流失。我們客戶的生意正在萎縮。我們需要幫助他們成功,而不只是賣東西給他們。」


分析報告產生於 {today}。資料排除類別1(內部製造)及PH路線(年度不可比)。A-PK與K2依路線重組合併分析。所有金額以新台幣計。