修改紀錄
每次新增功能、變更、刪除、Breaking Changes 的時間軸。共 264 篇。
📅 2026 年 7 月 (66 篇)
-
07-19 po-ack-acknowledgment ▸
2026-07-19 — 採購單簽章回執:供應商回覆交期(雙向閉環)
摘要
把採購單簽章 PDF 迴圈補成雙向閉環:供應商匯入採購單後,可簽一份採購單簽章回執
(接受 / 調整交期 / 拒接)寄回買方;買方在採購協同回覆審閱(
POCOLLABRPY)匯入回執、驗章後,照既有流程套用交期回採購單。回執落進與 Phase 7 token 回覆同一張 reply 表,套用邏輯完全重用。
新增
- 供應商可回覆買方:於「採購協同收件」(
POINBOUND)匯入採購單後,按「回覆買方」,
選擇接受 / 調整交期(逐行填新交期、數量、備註)/ 拒接並附整單備註 → 簽章後產出回執 PDF
自動寄回買方。
- 買方可匯入簽章回執:於採購協同回覆審閱(
POCOLLABRPY)動作列新增「匯入簽章回執」按鈕,
選回執 PDF → 驗章通過後落入回覆清單,照原有「套用交期」把交期寫回採購單(更新預訂交期、
發送狀態、開待辦),與供應商臨時連結回覆走同一套審閱套用流程。
- 同一份回執重複匯入會被擋(防重放)。
- 回執明細以「單號 + 序號」自動對應採購明細;對不上的行仍會落入審閱清單供人工檢視。
變更
- 採購單簽章資料新增買方回覆信箱:送出採購單時,payload 加入採購員(採購單輸入人員)的
email,供應商回執自動寄回該信箱。此信箱只寫進簽章資料、不印在採購單報表上(人看報表不露信箱),
且受簽章保護、防竄改。
刪除
無
Breaking Changes
無:採購單簽章 PDF 的資料格式(payload)新增
buyerEmail欄位向後相容,既有已簽章文件仍可驗章;回執落入既有回覆表,不影響原有的臨時連結回覆流程。
前置設定(使用者需先完成)
回執為 B2B 全迴圈延伸,沿用簽章 PDF 的既有前置(見 2026-07-18 採購單簽章 PDF):
1. 產生機構簽章金鑰:買賣雙方各自跑簽章金鑰向導產生正式金鑰。
2. 設定往來對象公鑰(
POKEYCP):買方需匯入供應商公鑰卡才驗得了回執的章。3. 回覆信箱來源:採購員(採購單輸入人員)需於
perdata維護 email,回執才寄得回本人。!!! warning "尚未 runtime 驗證"
本次交付建置與單元測試全綠(供應商端回執組裝、買方端驗章落表、既有套用交期回歸測試皆通過),
但供應商真簽章產回執 PDF、寄信,以及買方真驗章匯入、套用交期回採購單等 runtime 全鏈尚未實機驗證;
「匯入簽章回執」按鈕的多語系文字尚未建立(有預設中文,不影響功能)。上線前請先完成前置設定並實機測試。
相關 ADR
- 供應商可回覆買方:於「採購協同收件」(
-
07-18 po-signed-pdf ▸
2026-07-18 — 採購單簽章 PDF:給供應商的 B2B 雙向迴圈
摘要
把採購單接進既有簽章 PDF 系統,做成 B2B 雙向迴圈:買方送出簽章採購單 PDF → 供應商收下驗章
→ 匯入自家系統自動建立銷貨訂單。沿用既有 RSA-3072 簽章、PDF/A-3 內嵌與公鑰配對機制。
新增
- 採購單可列印/預覽:補完採購單報表(含單價、原幣未稅、合計),可從採購單列印/預覽出圖。
- 供應商協同信可附上採購單簽章 PDF:協同信寄出時附帶已簽章的採購單 PDF,供應商端可驗章確認來源與內容未遭竄改。
- 「採購協同收件」功能(
POINBOUND):供應商匯入已簽章採購單 PDF → 驗章通過後自動建立銷貨訂單(ORMAST)。
- 依採購單上的買方統一編號自動對應客戶代號(查無客戶檔則擋下,提示先建檔)。
- 同一份採購單重複匯入會被擋(防重放),並回報既有訂單號。
變更
- 採購單報表資料對映修正:原報表因欄位對映問題無法正常顯示,本次修正後欄位正常帶值。
- 供應商協同信改為「先產簽章 PDF 附件、失敗則回退純連結信」——產 PDF 失敗不影響協同連結寄達。
刪除
無
Breaking Changes
無:採購單簽章 PDF 的資料格式(payload)新增欄位一律向後相容,既有已簽章文件仍可驗章。
前置設定(使用者需先完成)
此功能為 B2B 全迴圈,上線前需先備妥簽章金鑰與往來對象公鑰:
1. 產生機構簽章金鑰:跑簽章金鑰向導產生正式金鑰(未產生時送出端會提示「金鑰未建立」,不會建立錯誤 PDF)。
2. 設定往來對象公鑰(
POKEYCP):於「往來對象公鑰」維護匯入供應商/客戶的公鑰卡,收件端才驗得了章。3. 部署資料庫物件:對各目標 DB 執行
sql/pocollab-inbound-doc-deploy.sql(建收件防重放表twork_com_inbound_doc+_sheetno/_tableseq登錄)。!!! warning "尚未 runtime 驗證"
本次交付建置與單元測試全綠,但送出端 headless 渲染 PDF、真簽章、供應商端真驗章匯入 ORMAST 等
runtime 流程尚未實機驗證;正式機資料庫物件尚未部署。上線前請先完成前置設定並實機測試。
相關 ADR
-
07-18 po-signed-pdf-encryption ▸
2026-07-18 採購協同:採購單完整文件加密
摘要
採購協同送出簽章採購單時,新增「完整加密文件」選項——採購單整份加密,只有指定供應商用 TsERP
能打開,email 途中、郵件伺服器、誤收者都讀不到金額。簽章(防偽 / 防竄改)不變,加密是再加一層。
新增
- 發送方式三選一:PURCH 發送供應商協同時可選 ① 一般簽章 PDF ② 完整加密文件
③ 只要供應商回覆交期(純連結、不附檔)。
- 完整加密:採購單整份簽章 PDF 加密成
.poenc檔隨信寄出,只有指定供應商用 TsERP 匯入才解得開;
金額照留在文件內(整份都是密文)。
- 收件端支援加密檔:供應商在「採購協同收件」(POINBOUND)可匯入
.poenc,系統自動用自己的
私鑰解密還原文件、驗章後建立訂單;既有明文
.pdf簽章檔照常匯入。- 機構金鑰備份 / 還原:金鑰向導可把機構金鑰備份成密碼保護檔並在換機 / 重建時還原
(加密私鑰一旦遺失,先前收到的加密單將永久打不開,故務必備份)。
變更
- 買賣雙方識別改帶統編 + 完整公司名稱:國外客戶(無統一編號)可改用公司名稱對映,
收件匯入建訂單時客戶對映改為「統編優先、公司名稱後備」。
- 金鑰輪替保留舊金鑰:重新產生機構金鑰時保留舊私鑰於本機,以便解開先前收到的加密單;
向導提醒改為「新公鑰卡須重新交付往來對象配對」。
刪除
- 無。
Breaking Changes
- 無(既有明文簽章 PDF、純連結協同均照常運作;加密是新增選項,非取代)。
Migration Notes
- 發送方式欄:各資料庫需執行
sql/pocollab-portal-deploy.sql的 Phase F2 段
(為
sent表加發送方式欄)。dev(csa1 / csa5)已完成;正式機(csa2/3/4 及其他客戶庫)待部署。- 雙向公鑰配對:要送「完整加密文件」給某供應商,須先在 POKEYCP 匯入該對象的公鑰卡;
買方自身也要把新公鑰卡交付往來對象配對。POKEYCP 選單權限掛載與
_sheetno重登為前置。- 未配對到對方公鑰時,系統會自動改送「未加密簽章 PDF」並於發送結果訊息提醒。
已知限制 / 未驗
- 金鑰向導開窗互動、端到端加密收送(
.poenc→ email → 匯入解密驗章)、跨客戶機的憑證庫行為
尚未實機驗證(金鑰解密 / 備份還原 / 輪替已於本開發機憑證庫以整合測試驗過)。
- 目前採單一金鑰雙用途(簽章 + 解密),簽 / 密金鑰分離列為日後強化選項。
-
07-17 pocollab-generalize ▸
2026-07-17 供應商協同入口廣義化
摘要
供應商回覆表單全新設計(手機優先、繁體中文),並讓協同追蹤機制脫離採購單、支援任意單據別與
客戶/廠商雙類別。承辦人拉回回覆後,左側待辦事項會出現通知,套用或忽略即自動消失。
新增
- 供應商回覆表單全新設計:手機優先版面、繁體中文介面,提供確認、逐項調整、
拒接三種回覆動作,並顯示回覆期限。表單仍不顯示金額。
- 承辦人待辦通知:供應商回覆拉回後,承辦人左側「待辦事項」出現「供應商回覆」通知;
承辦人套用或忽略該回覆後,通知自動消失。
變更
- (內部)協同追蹤表廣義化:追蹤欄位由採購專用改為通用——單號、單據別、
客戶廠商代號、類別(客戶/廠商)等欄位,讓同一套協同流程可套用到採購單以外的單據別。
刪除
- 無。
Breaking Changes
- 無面向使用者的破壞性變更。內部追蹤表欄位改名(採購單號→單號、供應商統編→統一編號等)
以冪等 migration 處理,見 Migration Notes。
Migration Notes
- 正式機部署執行
sql/pocollab-portal-deploy.sql(含追蹤表欄位改名/新增的冪等 migration,
可重複執行)。worker 端與表單端契約 v2 已同步佈署。
已知限制
- 套用交期寫回明細目前僅支援採購單(PURCH);其他單據別可讀取/回覆,但套用交期寫回會被
擋下,待該單據別補寫回支援後再開放(見 ADR 0106)。
-
07-17 genaffair-view-wiring-dbset-backfill ▸
2026-07-17 總務模組畫面接線修復+12 個資料型別註冊補齊
使用者可見變動
- G庫存主檔(GINVENT)可以正常使用了:先前開窗只顯示一行類別名稱(畫面空白)、按上下筆會跳「Cannot create a DbSet」或「Object reference not set」錯誤;現在開窗後點「基本」分頁即可正常瀏覽與導覽資料。
- 已知小瑕疵:開窗當下不會自動選中「基本」分頁,需手動點一下(待後續修正)。
- 總務模組其餘程式(G廠商報價、G採購單、G出入庫單、G出貨單、領料、倉庫表等 8 支)畫面已接上:先前一律顯示空白+類別名稱。其中仍使用舊版表格元件的程式(如 G廠商報價)開窗會出現「Exception has been thrown by the target of an invocation」錯誤視窗——這是既有的舊表格元件問題,待表格元件升級(dg-to-radgrid)後解除。
- 修復 12 個單據型別的本機資料庫註冊(GPURCH、GSPLACE、PPURCH、PURAMA/TWRAMA/WKRAMA、SALEMA、SAMPLE):這些單據相關畫面先前導覽即崩潰;同時依兩客戶庫(鈞寶/朝陽)欄位聯集補齊資料欄位與共用審核欄。
技術摘要
1.
Model/LocalDbContext.cs新增 12 個 DbSet(C.總務/E.訂單/G.採購/新增 J.品質區);smoke baseline 由 126 收緊至 112。2.
TsERP/App.xaml補 C.GeneralAffair 8 支隱式 DataTemplate(該模組原本零接線)。3.
GinventViewModel.TabSelectedItem加 null 防護(Tabs集合從未初始化,靜態分頁 XAML 與動態分頁 VM 的 fork 斷裂)。4. 14 個 Source 拿掉
(IAppContext context)建構子改無參(EF materialize 需求),呼叫端連動修改(含Gstkbas_1TmpPoco、Sample1Source衍生類: base())。Migration
無需資料庫變更。本機 SQLite 由
EnsureCreated自動重建新表。 -
07-16 sliy-balance-remove-accitem-link ▸
2026-07-16 傳票「未沖帳款查詢」暫時下架;項目編號表「項目分類」標籤可跳摘要檔
傳票(SLIY):未沖帳款查詢暫時下架
- 右側支援面板的「其他查詢」頁籤(未沖帳款查詢/挑款)暫時移除,新增傳票時也不再自動切到該頁。
- 屬暫時下架(2026-07-16 裁決):
SliyViewModel移除ISpecialQuery介面;要恢復把介面加回並還原建構子的SpecialQueryContent與AfterAddNew的切頁呼叫即可,SliyBalanceViewModel本體未刪。
- 手冊
docs/N-GeneralLedger/sliy.md已同步移除對應段落與截圖佔位。
項目編號表(ACCITEM):「項目分類」標籤加超連結
- 「項目分類」標籤改用
TsNavigateLabel(比照群組表 GRPM 分類標籤既有模式):雙擊標籤跳轉摘要檔(SMEMS)並定位到C227類別,方便直接維護項目分類選項。
-
07-16 purch-ui-adjust ▸
PURCH 採購單畫面調整
日期:2026-07-16
變更內容
- 表頭版面:唯讀欄位(輸入人員、總數量、原幣金額、本幣金額)移到「是否結案」下方集中顯示,標籤顏色統一為系統產生欄顏色;傳真日期移至左欄補位。
- 發送供應商協同按鈕:從採購單號旁移到表頭最右側,獨立成一個直欄與其他欄位區塊並排。
- 運送方式:表頭與明細表格內的下拉選單改為只顯示名稱(原先為代號+名稱兩欄併排),上下兩處樣式一致。
- 明細表格「結案」「須否成績表」勾選欄經查與增刪修狀態本來就同步(EF 變更追蹤保證),行為不變。
- 本幣金額改顯示本幣合計:原先與原幣金額綁同一個合計值(兩欄永遠同數字),現改為各自加總明細的原幣未稅/本幣未稅。
影響範圍
僅 PURCH 畫面呈現;共用下拉控件新增的「只顯示名稱」模式為選用(預設關閉),其他程式不受影響。
-
07-16 dash-history-retention ▸
行動儀表板網站:歷史報表保留+多公司發布專案參數
日期:2026-07-16
變更內容
每次發布保留歷史(原本只留最新一份)
主管行動儀表板網站(Cloudflare Pages,
tserp-dash)原本每次排程發布會整站替換,只看得到最新一期報表。現在:- 每次發布時,來源檔會先累積到發布機的歷史夾(
%ProgramData%\TsERP\dash-archive\<專案名>\,檔名含期間,同一期重發覆蓋不重複),再連同全部歷史一起上傳。
- 首頁不變:打開網站仍直接是最新一期報表,右下角多一顆「🗂 歷史報表」浮動按鈕。
- 點入
history.html是各期清單(最新置頂,附產出時間),點任一期可看當期完整報表。
- 佔位頁模式(
-Placeholder,事故蓋台用)不帶歷史;本機歷史夾不受影響,下次真實發布即還原。
多公司:排程參數可指定發布專案
排程任務
Customdash_ScheduledDeck新增參數「發布專案」:- 空白=預設
tserp-dash(現行行為不變,既有排程事件不用改)。
- 填專案名=發布到該 Cloudflare Pages 專案(一家公司一個專案、各掛各的 Access 白名單);歷史夾也按專案名分開。
- 新公司啟用前置:在 Cloudflare 建同名 Pages 專案、掛 Access(**必須含
<專案>.pages.dev與*.<專案>.pages.dev兩筆**,缺一即漏)、無痕實測被擋後才發真實數據。
影響範圍
tools/dash-publish.ps1:新增-ArchiveDir參數;dist 打包邏輯改為「最新 index.html+歷史檔+history.html」。
AutoPilot/Customdash_ScheduledDeck.cs:DefaultParameter加「發布專案」,TryPublishMobile帶入-ProjectName。
- 既有排程事件參數不需調整;下次日報發布起自動開始累積歷史。
- 每次發布時,來源檔會先累積到發布機的歷史夾(
-
07-16 canswitch-allow-validation-errors ▸
2026-07-16 表單有驗證錯誤時允許切換其他程式
使用者可見變動
- 表單欄位有紅框(驗證錯誤)時,現在可以直接切換到其他程式。以前只要目前畫面有任何欄位驗證錯誤,點選單裡的任何程式都沒有反應、也沒有任何提示,體感像系統當掉;打單打到一半想切去別支程式查資料會被卡住。
- 切換後資料不會遺失:切走再切回來,打到一半的內容與紅框都還在(程式畫面有快取)。
- 資料正確性不受影響:存檔時仍會完整驗證,有錯誤的資料照樣存不進去。
(此變更取代 2026-07-15 changelog 中「表單有欄位驗證錯誤時切換其他程式被擋的行為維持不變」的敘述——2026-07-16 裁決改為放行。)
技術面
ViewModel/ProgramNavigator.cs:CanSwitch移除第一段「目前畫面有驗證錯誤 → 對所有目標程式回 false」的檢查。
TsERP/ScreenshotAutomation/ScreenshotRunner.cs:同步更新引用該行為的註解(批次截圖仍以權限存在性判定,避免建 VM 失敗跳錯誤窗打斷批次)。
-
07-16 acc-scan-depth-cap ▸
2026-07-16 ACC_SCAN 新增「展開位數上限」(第 5 參數)
變動
ACC_SCAN新增第 5 參數=展開位數上限:ACC_SCAN('目標','範圍別','範圍內容',抬頭,位數上限)。控制逐科目展開時「列到科目代號幾碼為止」,省略=4(多數帳套的明細科目層級)。
- 逐科目展開的結構(大/中/小分類標頭、層級縮排、每科目一列)維持不變。
- 代號長度超過上限的子科目不各自成列,金額由其較短碼的母科目那一列以
%前綴合計併入——母科目公式自動變成ACC_xxx('代號%')(例:ACC_IS('1101%')涵蓋 1101 及其所有子科目);母科目底下無更深子科目時公式不帶%。- 母子科目同時成列不重複計數:母科目與其子科目都在上限內、都成列時(如統制科目 110 與 4 碼 1101 並存),母列只計自身與「未各自成列的子科目」,不用
110%吞掉已成列的 1101;保證每個科目金額在整份展開中恰被計入一列。- 孤兒保底:超過上限、但沒有可併入的短碼母科目(母科目不在掃描範圍內)的子科目,仍個別列出,金額不漏。
- 要展更細:把第 5 參數調大,例如
ACC_SCAN('IS','L','營業費用',1,6)會把 6 碼子科目也各自列出。
R範圍別一樣套用位數上限規則(平鋪、不補分類標頭)。
- 參數檢查:第 5 參數若填非正整數(含 0、負數、非數字),公式檢查會報「錯誤」級(第5參數展開位數須為正整數)。
- 兩種引號寫法(各自引號
('IS','L','營業費用',1,6)與一組引號("IS,L,營業費用,1,6"))都支援;減項(公式前加-)維持整段以減項計入。
影響範圍
自訂財務報表(ACC_SELFRPT)查詢與 ACC_RPT「模擬表預覽」中的
ACC_SCAN展開結果。既有寫ACC_SCAN的報表列不需改設定——省略第 5 參數者一律套預設 4 碼上限(子科目金額併入母科目列);要維持逐科目展到更深,補上第 5 參數即可。 -
07-16 acc-formula-wildcard ▸
2026-07-16 自訂財報公式新增「含子科目」寫法(前綴 %)
使用者可見變動
- 自訂財報(Acc_selfrpt)的算值公式,科目參數多了一種「含子科目」寫法:在科目代號後面加
%。例如ACC_IS('1101%')會加總所有以1101開頭的科目——含母科目1101本身與其下所有子科目(110101、110102…)。
- 適用四個算金額的函式:
ACC_IS、ACC_ISA、ACC_BS、ACC_SC。
- 解決的痛點:母科目底下掛子科目、明細金額都記在子科目上時,舊的單一代號寫法
'1101'是完全比對、算不到子科目,使用者得手動湊一段區間才行;現在寫'1101%'一次到位。
- 既有寫法行為完全不變:單一代號
'1101'仍是完全比對(不含子科目)、區間'1101~1199'仍照起迄加總。
!!! warning "
%要放結尾、且是整段前綴比對"%只能放在科目代號最後面當前綴合計,不是萬用字元。前綴是整段比對:'1101%'不會把1102算進來;要同時涵蓋1101與1102,請用共同母層前綴'110%'或區間'1101~1102'。技術面
LogicBll/N.GeneralLedger/Util_Acc.cs:新增ParseGLAccountRangehelper 統一解析科目參數(單一代號/區間/%前綴),四支函式改呼叫它。前綴模式把「迄值」定為三個資料來源(TmpSliySum/TmpSliyyear/TmpBudget)中最大的同前綴科目代號,讓既有的string.Compare起迄過濾天然涵蓋所有子科目;幣別/部門/借貸/預算/期初等其餘分支一行未動。
- 之所以選
%而非*:公式引擎AccSelfReportEvaluateBll.DecodeFormula會對原始公式字串以運算子(+ - * /)切割,引號內的*會被誤當乘號切壞公式;%不在運算子集合,安全。
LogicBll/N.GeneralLedger/Acc_selfrpt/AccFormulaChecker.cs:公式檢查的科目存在性驗證同步支援%前綴(改用StartsWith判定),查無時沿用原警告訊息。
- 自訂財報(Acc_selfrpt)的算值公式,科目參數多了一種「含子科目」寫法:在科目代號後面加
-
07-15 customdashcfg-ui-tweaks ▸
2026-07-15 自訂面板配置(CUSTOMDASHCFG)操作性調整
變動內容
- 查詢清單可直接拖曳排序:在「自訂面板配置」的查詢清單內按住項目上下拖曳即可調整順序(=看板查詢與匯出的排序);原本的「上移/下移」按鈕保留。
- 彙整列印報表下拉改顯示中文報表名稱:原本顯示報表檔名(如
Balance1),改顯示報表抬頭(如「資產負債表」)。查詢清單項目下方與看板側「已選報表」的顯示同步改為中文;舊配置沒存過中文抬頭時仍顯示檔名,重選一次報表即更新。
- 版面精簡:拿掉配置表單外圍的「配置」群組框。
- 匯出項目分頁文字放大(字級 12 → 14),並將分頁與面板內控件統一為 Ts 系列控件(TsTabControl/TsLabel/TsTextBlock/TsComboBox/TsTextBox)。
相容性
- 配置 JSON 新增選填欄位
報表抬頭(僅供顯示;彙整列印比對仍用報表編號),舊配置照常讀取,無需轉檔。
- 修正開窗時右上稽核面板的綁定錯誤:
twork_sys_customdashconfig補上標準審核五欄(聯絡單id/工作流程/審核人員/審核日期/已審核)。部署需先跑sql/customdashconfig-add-audit-columns.sql再更新程式(dev 已跑;正式機待跑)。
-
07-15 customdash-export-company-name ▸
2026-07-15 自訂查詢面板匯出 HTML 標題改用公司名稱
變動
- 自訂查詢面板「匯出HTML」與排程報表產出的封面/瀏覽器標題,原本固定顯示「禾久」,改為讀系統設定的公司名稱(公司基本資料 codata 的公司名稱欄)。
- 平台層
DeckExportOptions.公司名預設值不再寫死客戶名,未帶入時留空,避免其他客戶匯出印成禾久。
影響範圍
自訂查詢面板匯出 HTML、排程報表(ScheduledDeck)各格式輸出、行動版儀表板 HTML。
-
07-15 crash-recovery-and-open-check ▸
2026-07-15 崩潰復原改進與全程式開窗體檢
使用者可見變動
- 程式畫面崩潰不再拖垮整個系統:某支程式開啟時若持續發生錯誤(例如畫面元件載入失敗),以前會連跳數次錯誤視窗後整個 ERP 自動關閉;現在改為:第一次只提示錯誤,若同一錯誤重複發生,系統自動把壞掉的畫面清空,其他程式照常使用。
- 「系統錯誤」視窗現在會顯示是哪支程式發生錯誤(內文第一行「程式:XXX」)。以前錯誤訊息可能在切換到下一支程式時才彈出,容易誤判是新程式的問題。
- 表單有欄位驗證錯誤時切換其他程式被擋的行為維持不變;但程式畫面「建立失敗」的殘留狀態不再令所有程式都無法切換。
追加(同日晚間):舊頁面批次修復
- 18 支原本打不開的程式恢復可用:傳票(SLIY)、客戶資料(CUDATA)、財產目錄(ASSET)、銀行資料(BANK)、發票系列(TICKMIN/TICK3/TUTAX)、MRP、庫存查詢(INVSTK/INVBK1)等。成因為三層歷史問題疊加:舊 TsPage 頁面進不了新容器、查詢條件元件未註冊、畫面模板未登記。
- 44 支舊 TsPage 頁面完成 TsView 遷移;15 支確認尚未移植(薪資、成本、群組維護等,屬移植待辦非故障)。
技術面
TsERP/App.xaml.cs:全域例外處理改「重發才復原」策略(ADR-0103)。
ViewModel/ProgramNavigator.cs:CanSwitch對半毀 context 加 null 防護。
TsERP/ScreenshotAutomation/ScreenshotRunner.cs:批次截圖模式強化(單支 45 秒逾時、結果逐筆落檔、登入等待 60 分、權限判定去污染)。
- 全程式開窗體檢結果與後續修復清單:
.claude/tmp/opencheck-20260715/REPORT.md。
追加(深夜):查詢條件面板統一
- 15 支查詢程式的查詢條件改到畫面下方的標準查詢區(原本各自畫在畫面上方):總務入庫帳簿、營業稅媒體申報(401)、MRP、庫存查詢、庫存帳簿、庫齡、樞紐、預測、FillRate、Itemship、AR/AP 查詢、採購查詢、表格設定等。條件內容與預設值不變。
- 這批程式先前無法開窗的問題一併解決;排程報表現在能正確記住這些程式的查詢條件(ADR-0105)。
-
07-15 calendar-dot-permission ▸
2026-07-15 行事曆圓點尊重權限
變動內容
- 主視窗右側行事曆的日期圓點(提示當天有事件)改為只統計使用者有權限看的事件。修正前:非管理員雖然在下方清單看不到「系統」類事件,但只有系統事件的日期仍會畫圓點,等於洩漏了看不到的資料存在。
- 「今天沒有事件」與「已被篩選隱藏」的判斷同步改用權限過濾後的事件,無權限的事件不再被當成「被篩選隱藏」。
- 「個人/部門/公司」勾選是暫時的顯示篩選,行為不變:取消勾選只影響下方清單,圓點照常顯示。
-
07-15 alert-sources-batch2 ▸
2026-07-15 主動警示第二批:六個新警示源+信件風格統一
新增警示源(warning 信件,於「警示規則」程式啟用與設定門檻)
警示類型 內容 預設門檻 採購逾期未交(PO_OVERDUE) 未結案採購單,預訂交期逾期且尚有未交量,按廠商彙整通知採購 逾期 3 天 委外逾期未交(WK_OVERDUE) 未結案委外派工單,預訂完成日逾期且尚有未交量 逾期 3 天 呆滯庫存(STAGNANT_STOCK) 有庫存但長期無任何出入庫異動的品項(含從無異動紀錄者) 180 天、明細列前 200 筆 退票警示(CHECK_BOUNCE) 收票發生退票(已兌退票/未兌退票/票貼退票)即時通知財務 回看 7 天 排程健康監控(SKD_HEALTH) 排程執行失敗或執行中卡死,通知系統管理員 回看 24 小時、卡死 60 分鐘 郵件佇列監控(MAILQ_STUCK) 通知信死信/滯留/卡鎖,通知系統管理員 滯留 2 小時 - 全部沿用警示框架(ADR 0092):規則表門檻 JSON、收件人設定、重複警示抑制。
- 新規則預設停用,需在警示規則程式逐項啟用並填收件人。
- 排程掛載:行事曆事件設「執行方法+Dispatcher=SKD」即可定時觸發(同安全庫存警示作法)。
信件風格統一
- 所有系統警示信改用同一套版面(深藍表頭、紅色警示強調、統一字體字級);風格集中於
資料庫函數
TWORK_FN_HTML_STYLE,日後調整一處生效(ADR 0104)。- 朝陽「送樣未合格通知」信件由無樣式舊版改為標準版面(內容欄位不變)。
部署注意(正式機)
1. 先跑
sql/html-fn-deploy.sql(風格函數,警示 SP 相依它)。2. 再跑各警示源 deploy:
po-overdue、wk-overdue、stagnant-stock、check-bounce、skd-health、mailq-stuck,以及 refit 後的ar-overdue-deploy、check-due-deploy。3. CY 另跑
cy-sample-notify-restyle-deploy.sql(送樣通知改版)。4. 皆需
sqlcmd -f 65001(含中文),跑完看各檔結尾驗證區。 -
07-15 acc-scan-lineno-headers ▸
2026-07-15 ACC_SCAN 展開補序號/分類標頭縮排/模擬表列號修正
變動
- ACC_SCAN 展開列帶序號:展開出來的每一列序號=母公式列序號+子流水(如
000005-01),在模擬表預覽與查詢結果中可直接看出該列由哪條掃描公式產生。純顯示用,不寫回報表設定。
- L/M/S 掃描自動產生分類標頭與縮排:依大/中/小分類補純文字標頭列(無公式),縮排比照 ACC_BSCE——大分類 0 格、中分類 2 格、小分類 4 格、科目列 6 格。R(科目範圍)掃描維持平鋪不變。
- 模擬表預覽列號修正:原本列號出現 1、10、11、2 跳著排——根因是
_sheetno的 ACC_RPT 序號長度登記為 0,列號完全不補零,格線字串排序就亂了。現列號寬度至少取總列數位數,保證等寬可排序。
- 模擬順序修正:新增尚未存檔的公式列(序號空白)原會排到模擬結果最前面,改排最後(與存檔後被編到尾端一致)。
影響範圍
自訂財務報表(ACC_RPT 維護的「模擬表預覽」按鈕)與 ACC_SELFRPT 查詢的 ACC_SCAN 展開結果。既有報表不需改設定。
- ACC_SCAN 展開列帶序號:展開出來的每一列序號=母公式列序號+子流水(如
-
07-14 workflow-approval-fix ▸
2026-07-14 簽核流程修復(送簽通知、核准生效、退件回上一關)
行為修復(原本壞掉、現在會動的)
- 核准真正生效:按「同意」後,關卡完成率確實更新、全部關卡完成時來源單據會蓋上
審核章(已審核=Y)並鎖定不可修改。(修復前核准只在畫面上看起來成功,後端從未寫入。)
- 代理人可以簽核:有被設定為代理人(組織代理關係)的使用者,現在可以代處理人核准;
修復前代理判定永遠失敗、只有本人能簽。
- 取消流程生效:取消後流程正確結案。
行為變更
- 退件改為「退回上一關」:在第 N 關按退件,流程回到第 N-1 關重新簽核(退件說明會記錄);
在第一關退件則整個流程退回發行者重新開始。修復前退件一律整個流程重來。
- 簽核通知改走郵件佇列:送簽、核准(通知下一關)、退件三種事件都會發信通知對應處理人,
由排程服務統一寄送(含失敗重試);寄信失敗不影響簽核動作本身。
- 待簽清單預設範圍:預設只列「本人+代理」的待辦;查看下屬待辦的分頁仍在,
但簽核動作僅限本人與代理人。
- 送簽通知改為單一來源(存檔成功後發),修正同一位簽核人收到兩封送簽通知的問題。
-
07-14 supplier-collaboration-portal ▸
2026-07-14 供應商協同入口(採購單交期回覆)
新增
- 發送供應商協同:採購單(PURCH)新增「發送供應商協同」按鈕,對當前採購單產生一次性
安全連結、寄信給供應商。供應商用手機或電腦開連結,即可看到採購單明細(品項、數量、需求交期;
不含單價與金額)並回覆:一鍵確認訂單、逐行調整交期(可含數量)、或拒接並附備註。
- 供應商回覆審閱(POCOLLABRPY,掛在採購模組):採購人員檢視供應商回覆,逐行對照原交期與
供應商回覆的新交期,決定「套用交期到採購單」或「忽略」。套用後才會更新採購單的預訂交期並留下紀錄;
系統不會自動改單。
- 逾期未回提醒:供應商在期限(預設發送後 14 天、到期前 3 天起)內未回覆,系統會寄信提醒
當初發送的採購人員(一天一封彙整)。此提醒預設關閉,由警示規則啟用。
安全與行為
- 供應商連結有 14 天效期、可撤銷;重新發送會使舊連結失效。
- 連結本身即權限(無需帳號密碼),請勿轉發給非供應商。
- 入口只顯示該採購單的明細,不顯示任何金額;供應商無法看到其他採購單或其他供應商的資料。
- 供應商的回覆為「快照」,採購人員審閱後手動套用,不即時改動採購單。
-
07-14 mobile-dashboard ▸
2026-07-14 主管行動端儀表板(排程寄送行動版 + 受控網址)
新增
- 行動版報表格式
HTMLMOBILE:排程報表(行事曆事件Customdash_ScheduledDeck)的
「格式」參數新增
HTMLMOBILE(別名MOBILE),產出手機直立可讀的卡片流 HTML,檔名尾為
_mobile.html;可與HTML、EXCEL等並列多選。- 寄信標註:信件內文會把行動版附件標為「(行動版)」並提示用手機瀏覽器開啟。
- 發布到受控網址(選用):排程事件參數新增「發布網址」(預設不啟用);設
Y時
寄信成功後自動把最新行動版推上受 Cloudflare Access 保護的網址,主管手機開網址即看。
需在 worker 環境設定 Cloudflare 憑證與
DASH_ACCESS_CONFIRMED=Y(Access 驗證完成的明示確認)。行為變更
- 排程報表檔名加期間段:
<配置名>_<期間>_<產出日>(期間=目標月 yyyyMM 或「當期」),
例
財務報表_202606_20260714_mobile.html。原因:同配置的日報與週報同日產出時舊檔名會互相覆蓋。保留天數清理同時認得新舊兩種檔名,既有舊檔照常清理。
- 行動版隱藏零值:整列全為 0 的資料列不顯示;數值欄的 0 顯示為空白(代號欄如「0001」不受影響)。
桌機版 HTML/Excel 不變。
- 行動版報表格式
-
07-14 i18n-coverage ▸
2026-07-14 多語言覆蓋補完
改善
- 多語言覆蓋率大幅提升:全系統畫面(XAML)的多語言真實覆蓋率從約 29% 提升到約 74%。
原本大量畫面標籤、表格欄位標題是寫死的中文或英文,切換英/日/越語系時會露出原文;
本次把有多語言基礎的一般程式補齊四語(繁中/英/日/越),切語言時會正確翻譯。
- 英文介面中文化:部分畫面(多為進退貨、統計、報表頁)表格欄位標題原本是英文(如 Line No、SKU、
Unit Price),現已改為中文並補上多語言,中文介面不再露出英文欄名。
修正(順帶清理的既有問題)
- 移除 25 個「永遠空白」的欄位:這些表格欄位綁定到不存在的資料屬性,任何情況下都顯示空白(既有缺陷),
已移除。
- 下架一張空白舊頁:應收對帳的舊列印預覽頁(已被新版取代、開啟即空白)已下架。
已知限制
- 少數畫面(客戶專屬客製版、部分舊式視窗)尚未納入,之後按需補做。
- 自動翻譯的專業術語建議由熟悉業務的人員過目校正。
- 部分表格欄位標題在非中文語系下仍顯示中文(底層命名機制的既有限制,中文顯示不受影響)。
-
07-14 grpm-usage-tab ▸
2026-07-14 群組表維護(GRPM):新增「使用狀況查詢」分頁
變更
- 群組表維護畫面改為兩個分頁:
- 群組資料:原本的群組維護內容(欄位、明細)完全不變。
- 使用狀況:查出目前這個群組代號被哪些主檔資料引用,結果列在表格。
- 使用狀況分頁行為:
- 切到分頁時,依「群組別」自動查對應主檔(品號→品號檔、客戶→客戶檔、廠商→廠商檔、科目→科目群組、總務品號、費用、工作中心、稽核)。
- 上方顯示目前群組代號與群組別;提供「查詢」按鈕可手動重新整理。
- 隨主檔上一筆/下一筆切換自動更新(同一筆重覆切分頁不會重覆查詢)。
- 群組別為「區域」或未設定時,顯示「此群組別尚未支援使用狀況查詢」。
影響範圍
TsERP/B.BasicData/Grpm.xaml(加分頁)、ViewModel/B.BasicData/Grpm/GrpmViewModel.cs
- 新增
LogicBll/B.BasicData/GrpmUsageBll.cs
- 查詢走既有通用查詢 SP(DARB_GETDATA4),不需部署任何資料庫物件。
詳細取捨見 ADR 0099。
-
07-14 customdashcfg-split ▸
2026-07-14 自訂查詢面板瘦身+新程式「自訂面板配置」(A.系統資料)
變更
- 新程式「自訂面板配置」(A.系統資料,標準增刪修程式):自訂查詢面板的配置管理集中到這裡——
- 標準工具列:瀏覽(只列自己的配置)、新增、修改、刪除、存檔。
- 表單:配置名稱、使用部門。
- 「查詢清單」分頁:組裝配置內容(選查詢程式→原生條件畫面設條件→加入/更新條件/移除/清空、每項自訂標題、上移/下移),並可對選中的查詢直接下拉改「彙整列印報表」。
- 「匯出項目」分頁:直接內嵌在畫面上(不再開視窗)——拖曳排序匯出頁順序、新增/編輯/停用報表與圖表顯示項目;「儲存顯示項目」立即生效(全部配置共用),匯出順序則隨「存檔」存進該配置。
- 自訂查詢面板調整:
- 查詢區:既有設置下拉(選了即載入)、查詢清單、目標月份+整批換月;點查詢清單的項目會顯示該查詢的條件畫面,可臨時調整後按「更新條件」(只影響本次,不會改配置)。
- 儲存設置、刪除設置、配置名稱、使用部門、選程式/加入/移除/清空等管理功能移除(改到「自訂面板配置」操作);主工具列移除「匯出設置」鈕,保留 彙整列印、匯出HTML。
- 排程報表(ScheduledDeck)的匯出頁順序改為套用配置存的「匯出項目順序」,與手動匯出一致。
影響範圍
- 新程式需登錄後才可用:
sql/customdashcfg-register-program.sql(選單+瀏覽用_sheetno,待部署;開發環境 dev-programs.json 注入+重登,但瀏覽也需要先跑 SQL 的_sheetno段)。
- 既有配置完全相容;看板選配置、查詢、列印、匯出行為不變。
詳細取捨見 ADR 0096。
-
07-14 accl-tier-cascade ▸
2026-07-14 — 會計科目維護:分類連動與群組代號
會計科目維護(Accl)
- 大分類/中分類/小分類三個下拉連動:
- 選了大分類,中分類與小分類的選項自動縮小到該分類底下。
- 選了中分類,會自動帶入大分類;選了小分類,會自動帶入大分類與中分類(可對應到多個上層時不亂帶,維持原值)。
- 選上層分類不會清掉已填的下層分類,只縮小選項。
- 新增「群組代號」欄位:可搜尋科目群組(群組表中群組別=科目的群組),選了之後自動帶入大/中/小分類,群組代號會隨科目儲存。
- 分類下拉的選項來源(摘要檔)與科目群組表已依現有科目資料重建完成;分類資料有疑義的科目已另列清單待與客戶確認。
注意(IT/部署)
- 本次需搭配資料庫腳本
sql/accl-tier-grpm-seed.sql(新增 accl.群組代號欄+重建摘要檔與科目群組)。先跑腳本再發版,否則開啟會計科目維護會出錯。
-
07-14 acc-selfrpt-percentage-fix ▸
2026-07-14 — 自訂財報百分比欄修復
自訂財報(ACC_SELFRPT)
- 修復:百分比欄位一律顯示 0 的問題。報表定義(acc_rpt)「百分比基準」欄填
Y的那一列,現在會正確作為基準——全表每列的 當期百分比/總計(合計)百分比/當月百分比 = 該列值 ÷ 基準列值 × 100(四捨五入取兩位;基準值為 0 時該欄為 0)。原因:查詢建立輸出列時漏帶「百分比基準」欄位,導致引擎永遠找不到基準列。
- 修復:列印/匯出(N130 報表)「今年當期百分比」誤印成「今年總計百分比」的欄位錯置。
使用方式
在財務報表格式維護(acc_rpt)想當分母的那一列(例如「銷貨收入」或「營業收入合計」)的「百分比基準」欄填
Y即可;一張報表取第一個Y的列為基準。 - 修復:百分比欄位一律顯示 0 的問題。報表定義(acc_rpt)「百分比基準」欄填
-
07-14 acc-scan-formula ▸
2026-07-14 — 自訂財報新增 ACC_SCAN 掃描公式與模擬表預覽
自訂財報公式(ACC_SELFRPT)
- 新增
ACC_SCAN掃描函數:一列公式自動展開成多列(每個符合條件的會計科目一列,抬頭=科目名稱)。
- 寫法:
ACC_SCAN('ISA','L','營業費用',1)- 參數1=目標函數:
ISA、IS、BS、SC、CF(展開成ACC_ISA('科目')等)- 參數2=範圍別:
L大分類、M中分類、S小分類、R科目範圍- 參數3=分類內容,或
R時的起始科目~截止科目- 參數4=抬頭:
1=科目名稱(目前僅此一種,可省略)- 前面加
-(如-ACC_SCAN('ISA','L','營業收入',1))可讓展開的每列公式都帶負號。- 引號寫法兩種都可:每參數各自引號,或一組引號內含逗號(
ACC_SCAN("ISA,L,營業費用,1"))。財務報表格式維護(acc_rpt)
- 新增「模擬表預覽」按鈕:不需執行查詢,直接列出目前公式明細展開後的報表列(列號/序號/抬頭/公式/列印碼),方便確認 ACC_SCAN、ACC_BSCE 會展出哪些科目。
- 注意:
ACC_BSAUTO依實際查詢期間有異動的科目展開,模擬時不會產生列。- 新增「公式檢查」按鈕:一鍵檢查所有明細公式,結果依嚴重度分級列出。
- 錯誤(查詢會當掉或必然算錯):函數名打錯或大小寫錯、括號/引號不配對、
ACC_SCAN/ACC_BSC參數不合法、ACC_ISTB引用的單一序號不存在。- 警告(不會當,但結果必為 0 或空):科目/分類/引用序號範圍查無資料、
ACC_SCAN展開後 0 列、ACC_ISTB引用計算順序排在自己後面的列、展開巨集同一列混寫其他內容。- 檢查不需執行查詢;全部通過時直接提示「未發現公式設定問題」。
- 新增
-
07-13 tscombobox-items-tooltip-fix ▸
下拉選單項目提示(ToolTip)修正:不再顯示程式型別名稱
日期:2026-07-13
使用者可見變動
- 自訂查詢面板 →「彙整列印」選擇報表的下拉選單:滑鼠移上時的提示(ToolTip)原本會顯示
ViewModel.Control.Layout.PrintLayout.ReportPrintSource之類的程式型別名稱,現在正確顯示該下拉內的報表清單(例:1.出貨日報表、2.應收帳款明細逐行列出)。
- 無報表而停用的查詢列,滑鼠移到下拉上現在會顯示「無報表的查詢無法列印」的原因提示(先前停用狀態不會出現任何提示)。
- 本修正在平台層(TsComboBox)生效:所有使用
DisplayMemberPath顯示自訂物件清單的下拉選單,若曾出現同樣的型別名稱提示,一併修復。
備註
- 根因:下拉項目提示在「項目來源已設定、顯示欄位路徑尚未生效」的瞬間產生,取不到顯示文字時退回物件預設字串(即型別全名),且之後不會重算。現改為顯示欄位路徑生效時重新產生提示。
- 純前端控件修正,無資料庫部署需求;runtime 尚未開窗驗收。
- 自訂查詢面板 →「彙整列印」選擇報表的下拉選單:滑鼠移上時的提示(ToolTip)原本會顯示
-
07-13 scheduled-report-deck ▸
排程報表自動寄送:任何自訂查詢面板配置可排程產檔寄信
日期:2026-07-13
使用者可見變動
- 新排程方法「排程報表自動寄送」(自動執行方法
ScheduledDeck):在行事曆排程事件掛上後,系統會定時把指定的自訂查詢面板(CUSTOMDASH)儲存配置整頁跑一遍(含各分頁查詢與圖表),產出 Excel+HTML 檔,作為附件自動寄給指定收件人——財務部月報、業務月報從此無人值守。
- 排程參數:配置 pkid、格式(預設 EXCEL,HTML)、收件人(逗號分隔,必填)、輸出目錄(預設
C:\temps\排程報表\)、月份(支援{-d1}上月自動平移——每月 1 號排程自動產「上個月」的報表)、保留天數(預設 30)。
- 郵件佇列支援附件:排程信可帶多個附件;既有寄信行為不變。
- 產出檔留存:檔案保留在輸出目錄供事後稽核,超過保留天數的舊檔於下次排程自動清理(只清本功能產出的檔案,不動目錄中其他檔案)。
- 排程事件清單上的顯示文字為人話摘要,例:「排程報表:配置#3(當期)→ 收件人 2 人,格式 EXCEL,HTML」。
備註
- 需在排程器(SchedulerWorker)設定檔設定 headless 登入帳號(
ScheduledDeck節);正式環境建議帳密改走 Azure Key Vault。
- PDF 格式本期未支援(匯出引擎無 PDF writer),指定 PDF 會記警告略過。
- 正式環境部署需執行:
sql\mailqueue-attachment-deploy.sql(附件欄+DEQUEUE SP)、sql\mailqueue-enqueue-deploy.sql、sql\alertlog-skd-deploy.sql、sql\autopilotmethod-register-deploy.sql(選用字典)。
- 同步修正:金流跌破警戒警示(ADR 0092)的排程資料存取改走排程派發器,修正排程環境下無法入列的問題。
對應 ADR 0093;沿用 ADR 0018(郵件佇列)、0065(集中自動化庫)、0083(配置持久化)、0088(彙整匯出)。
- 新排程方法「排程報表自動寄送」(自動執行方法
-
07-13 preview-toolbar-and-merged-watermark ▸
2026-07-13 報表預覽:按鈕順序調整+彙整浮水印修正
變更
- 預覽工具列按鈕換位:「列印」與「匯出PDF」對調,順序改為 列印 →(中一刀列印)→ 匯出PDF → 匯出EXCEL → 搜尋 → 浮水印 → 大綱。
- 修正:自訂查詢彙整列印(合併 PDF)預覽套浮水印後,多支報表只剩一支。原因是 FastReport 內建浮水印「套用到全部頁面」會整份重新產生報表,合併自多支範本的頁面因此被洗掉。修正後浮水印直接套用在已備妥的頁面上,各報表內容保持完整;套完即可照常「匯出PDF」。
影響範圍
TsERP/TsFastReportPreview.xaml(按鈕順序、浮水印鈕改自訂處理)
TsERP/TsFastReportPreview.xaml.cs(合併報表浮水印安全路徑)
單一報表預覽的浮水印行為不變。
-
07-13 customdash-month-shift-year-rollover ▸
CUSTOMDASH 整批換月:自訂財報跨年時年度連動
日期:2026-07-13
變更
自訂查詢面板(CUSTOMDASH)的「整批換月」碰到自訂財報(ACC_SELFRPT)時,當期的年度與月份改為一起真實平移:
- 跨年換月時
年度會跟著進位/回溯(例:2026 年 12 月換到下個月 → 2027 年 1 月)。
- 舊行為是年度固定、月份夾在 1–12(12 月 +1 仍停在 12 月),已取消。
- 起訖月份平移後若跨在兩個年度(如 11–12 月換到 12 月與隔年 1 月),年度以截止月份的落點為準,起始月份調整到該年度邊界。
- 截止日期(如 12/31)維持不動。
排程報表自動寄送(ScheduledDeck)的換月走同一套邏輯,行為一併更新。
相關決策:ADR 0089(2026-07-13 修訂段)。
- 跨年換月時
-
07-13 customdash-export-setup ▸
2026-07-13 自訂查詢面板(CUSTOMDASH):新增「匯出設置」畫面(拖曳排序+項目維護)
變更
- 工具列新增「匯出設置」按鈕,開啟匯出內容設置畫面:
- 左側清單列出目前面板各查詢的顯示項目(報表/圖表),可拖曳調整順序(也提供上移/下移按鈕),順序即「匯出HTML」的頁面順序。
- 右側可編輯選中項目的完整定義:名稱、圖型、類別欄/數值欄/顯示欄位(下拉提供查詢結果欄位候選)、排序、TopN、篩選、欄位別名、計算欄、逐欄展開。
- 可新增顯示項目、停用(停用列不再出現在匯出勾選清單,設置畫面標灰可重新啟用)。
- 儲存時逐列驗證;若目前有選定配置會詢問是否同步更新該配置的匯出順序。
- 匯出順序會隨「儲存設置」存進配置,下次套用同配置匯出時自動套用;未調整過順序時行為與先前完全相同。
影響範圍
- 新畫面
TsERP/M.EIS/匯出內容設置.xaml+ViewModel/M.EIS/CustomdashExportSetupViewModel.cs
twork_sys_chartspec改為可由程式寫回(LogicBll/CommonSystem/ChartSpec/ChartSpecBll.cs;表遷移見sql/chartspec-maintain-deploy.sql,需部署)
- CUSTOMDASH 儲存配置 JSON 結構升級為 wrapper(舊配置自動相容)
詳細取捨見 ADR 0095。
-
07-13 customdash-export-hide-zero ▸
2026-07-13 自訂查詢面板(CUSTOMDASH)匯出:新增「隱藏零值」勾選
變更
- 「匯出HTML」的勾選對話框新增「隱藏零值」選項,預設勾選,可取消:
- 資料列中所有數值欄皆為 0 的整列不匯出(純文字列與合計列不受整列過濾影響)。
- 數值為 0 的儲存格顯示空白,不再顯示 0(含合計列)。
- HTML 與 EXCEL 兩種匯出格式皆適用(EXCEL 目前預設未開啟產出,開啟後同樣生效)。
- 取消勾選時輸出與先前完全相同;排程寄送(ScheduledDeck)路徑行為不變。
影響範圍
LogicBll/CommonSystem/Reporting/ReportDeckDtos.cs(DeckExportOptions.HideZeroValues)
LogicBll/CommonSystem/Reporting/HtmlDeckWriter.cs、ExcelDeckWriter.cs(整列過濾+零值留白)
ViewModel/M.EIS/CustomdashExportSelectViewModel.cs、CustomdashViewModel.cs
TsERP/M.EIS/自訂查詢匯出選擇.xaml(新增勾選框)
-
07-13 alert-notifications ▸
主動警示通知:應收逾期/票據到期/金流跌破警戒自動寄信
日期:2026-07-13
使用者可見變動
- 新增三種自動警示信(由排程觸發,經既有郵件佇列寄出):
- 應收逾期帳款通知:逾期超過門檻天數(預設 30 天,可調)的未沖應收清單,含客戶/單號/到期日/逾期天數/金額與合計。
- 票據到期通知:未來 N 天內(預設 7 天,可調)到期的收票/付票清單(收付票可分別開關),含票別/票號/到期日/金額。
- 金流預測跌破警戒通知:金流預測的累計淨額首次跌破警戒線時通知,含首次跌破月/警戒線/最低累計淨額。只通知首次跌破——跌破月與警戒線沒變不會重寄。
- 同一警示不轟炸:警示內容沒變時,抑制視窗(預設 24 小時,可調)內不重寄;內容有變(例如逾期名單多了一張單)會照常通知。
- 警示設定集中維護:門檻、收件人、啟用開關、抑制時數收斂到新的警示規則設定(警示規則維護頁);規則未設收件人時沿用行事曆事件的「通知帳號」,既有安全庫存警示行為不變。
- 金流預測畫面的「資金警戒線」數值現在可持久化到警示規則(原本只在畫面上手填、關窗即失)。
備註
- 通知通道本期為 Email(Mailgun)。LINE Notify 服務已於 2025-03-31 終止,如需 LINE 通知須另行申辦 LINE 官方帳號走 Messaging API,列為後續選項。
- dev 環境已完成三輪功能實測與排程器端到端真寄驗證;正式環境需部署:
sql\alertrule-deploy.sql、sql\alertlog-deploy.sql、sql\ar-overdue-deploy.sql、sql\check-due-deploy.sql(正式機 proc_param 為 IDENTITY,用腳本檔頭註明的不帶 pkid 版)。
- 金流跌破警示的排程實跑(行事曆事件觸發)尚未 runtime 驗收。
對應 ADR 0092(主動警示框架);通道與佇列沿用 ADR 0018、排程沿用 ADR 0065。
-
07-13 ai-nl-query-open-action ▸
AI 查詢:自然語言問句可一鍵開啟查詢程式;資料列不再送雲端模型
日期:2026-07-13
使用者可見變動
- AI 查詢視窗(admin)新增「開啟查詢」動作卡:用自然語言提問(例「上個月哪個客戶毛利最低」)後,AI 會判斷該用哪支查詢程式、幫你填好查詢條件,回覆下方出現卡片與「開啟查詢」按鈕;點擊即關閉 AI 視窗並開啟該程式(例:毛利率分析),條件已預填、不自動查詢——你可以先確認或微調條件再按查詢。
- 首波支援 13 支常用查詢程式(毛利率分析、訂單/出貨/進貨查詢、客戶資料、庫齡呆料、金流預測等);「毛利」類問題固定對應毛利率分析(QRY_PROFIT_NOGI)。
- 資料安全強化(預設生效):AI 對話中的查詢不再把實際資料列傳給雲端模型——模型只知道欄位結構與筆數,明細請透過「開啟查詢」在程式內查看;聊天內圖表改由本地繪製(資料不經模型)。此行為由系統參數
AI_ROWS_TO_MODEL控制(預設關閉)。
- AI 產生的查詢條件經過多重驗證(程式白名單、欄位存在、運算子合法、值型別檢查)才會開窗;個別條件套用失敗會明確提示,不會靜默遺漏。
- 毛利率分析新增預設圖表「客戶毛利額前十五」(需部署 chart-spec)。
備註
- 入口維持 admin 帳號限定;一般使用者開放與逐使用者資料權限過濾為後續議題。
- 測試指令
/testcard(僅開發版)可不接模型驗證動作卡。
- 對應 ADR 0094;沿用 ADR 0007/0027/0030(AI 查詢閘道與稽核)、0091(運算子口徑)。
-
07-13 acc-selfrpt-query-busy ▸
2026-07-13 自訂財報(ACC_SELFRPT):查詢時清空舊結果+執行中指示
變更
- 按下「查詢」後立即清空上一次的查詢結果,避免查詢執行期間舊資料被誤讀成新結果。
- 查詢執行期間,表格區顯示忙碌指示(轉圈),查詢完成自動消失。
影響範圍
ViewModel/N.GeneralLedger/Acc_selfrptViewModel.cs(Query 先清空+IsQuerying 旗標)
TsERP/N.GeneralLedger/Acc_selfrpt.xaml(RadBusyIndicator 包住結果表格)
報表編號未輸入時的行為不變(僅提示訊息)。
-
07-12 browsecondition-type-aware-operators ▸
2026-07-12 — 查詢條件運算子依欄位型別過濾
使用者可見變動
查詢視窗的「條件」面板,運算子下拉選單現在會依欄位型別只顯示合理的運算子,行為對齊表格(RadGridView)內建篩選:
- 文字欄:全部運算子(等於、開始於、包含、被包含…,含大於/小於等區間比較)。
- 數值欄:等於、不等於、大於、小於(及等於)、被包含、介於之間…;不再出現「開始於/包含」等文字專用運算子。
- 日期欄:等於、不等於、大小比較、介於之間…;不再出現文字運算子與「被包含」。
- 是/否(布林)欄:等於、不等於、等於 Null、不等於 Null。
- 切換欄位後,若原本選的運算子在新欄位型別已不適用,會自動改回「不等於」。
「套用此條件/不套用此條件/介於之間」等自家延伸運算子在各型別維持可用。
相容性
- 既有已存的預設查詢條件不受影響(運算子代碼未重編,僅限制「新選」時的可選項)。
- 布林欄位的等於/不等於查詢 SQL 修正為
= 1 / = 0。
詳見 ADR 0091。
-
07-11 flowcast-waterfall ▸
金流預測:下圖改堆疊式瀑布圖、版面調整
日期:2026-07-11(2026-07-12 更新為堆疊式瀑布;2026-07-13 改為月階梯瀑布並移除來源組成瀑布)
使用者可見變動
- 金流預測(FLOWCAST) 畫面的下方圖表由原本的「收付堆疊柱圖」改為 堆疊式瀑布圖:
- 每個月仍依 四來源(票據/帳款/訂單/採購)分色堆疊、收向上/付向下,但整根柱不再從 0 起算,而是錨在「前期累計淨額」基線上浮動——柱的堆疊頂/底恰好接到本期累計,因此下圖的柱與上圖的累計淨額折線相互呼應,一眼看出每個月是哪些來源把現金往上推或往下拉。
- 點柱段過濾:點某來源的收(或付)段,明細分頁會過濾到該月 × 該來源 × 該收付;再點同段取消、點空白清除。
- 上方「來源」勾選(票據/帳款/訂單/採購)照舊即時開關;某來源取消勾選時,該色段會變成 0 高度自動消失。
- 版面比例調整:圖表區放大、數據(明細/彙總)區縮小(由 2:3 改為 3:2)。
- 圖表區加上外框(淺灰圓角邊界)。
- 圖表區改用分頁(2026-07-12):原本累計淨額線圖與瀑布圖上下相擠,改成三個分頁——「累計淨額趨勢」「金流瀑布」「來源組成瀑布」,各佔整個圖表區、各自帶時間軸標籤與圖例。
- 新增「來源組成瀑布」分頁(2026-07-12):把整個查詢區間的淨現金變化,拆成四來源的淨貢獻階梯(票據 → 帳款 → 訂單 → 採購 → 期末淨變化),淨流入藍、淨流出橘、期末總計深藍灰,柱上顯示各步淨變化金額,滑鼠移上顯示名稱/金額/佔比。
- 「金流瀑布」分頁改為逐項順序堆疊(2026-07-12):每月的瀑布柱改依 票據收 + → 票據支出 - → 帳款收 + → 帳款支出 - → 訂單收入 + → 採購支出 - 的順序逐項疊出,末端落在該月累計淨額(原為「所有收往上、所有付往下」的分組堆疊)。
- 條件列改版(2026-07-12):查詢條件(預測顯示區間/帳款立帳起日/資金警戒線)改成左側三排「標籤+輸入框」對齊排列,右側新增「計算方式與口徑」說明框(列出每月現金淨變化公式與各來源可信度)。
- 「金流瀑布」改為月階梯瀑布(2026-07-13):X 軸=月份,每月內六段依 票據收 → 票據付 → 帳款收 → 帳款付 → 訂單收 → 採購付 順序並排階梯(原重疊堆疊在收上付下時會互相遮蓋),深色=收(往上)、淡色=付(往下);每月末段收在該月累計淨額=下月首段起點,另加一條灰色累計淨額階梯線把前後月視覺銜接起來。
- 移除「來源組成瀑布」分頁(2026-07-13):整區間四來源組成的視角改由月階梯瀑布涵蓋(X 軸統一為月份),圖表區回到「累計淨額趨勢」「金流瀑布」兩分頁。
- 條件區說明補詳細口徑(2026-07-13):說明框逐來源列出資料來源與日期依據——票據(票況範圍、預兌日→到期日)、帳款(rp_m 未沖、單據分類 AR+/AP+、到期日→收付條件 PAYMENTTERM 推算→立帳日)、訂單/採購(未交數量×含稅單價、回覆日期→預訂交期+收付條件 PAYMENTTERM 推算)。
備註
- 本版本 Telerik RadChartView 無原生瀑布圖,月階梯瀑布以 6 條
RangeBarSeries(浮動柱、CombineMode=Cluster 同月並排)+各段依前期累計計算的絕對座標+StepLineSeries累計淨額銜接線實作。
- 純前端與 ViewModel 變更,無資料庫部署需求。
- runtime 尚未開窗驗收。
延續 ADR 0084(金流預測圖表拆雙軸)。
-
07-10 bor-cycle-audit ▸
BOR 新增「循環稽核」按鈕
日期:2026-07-10
使用者可見變動
- Bor(上位/下位組織結構維護) 畫面備註欄下方新增一顆 「循環稽核」 按鈕。
- 按下後對全部類別碼(替代/下屬/部門/客戶/廠商/工作中心)的上位/下位關係做循環參照偵測:若存在 A→B→…→A 這種繞回自己的循環鏈,會彈出結果表格視窗列出每一條循環(類別碼/起點編號/循環點編號/循環路徑/層數);沒有循環時提示「循環稽核完成:查無循環參照。」
- 只稽核「當前生效」(依生效起訖日)的關係。
部署需求
- 需在資料庫執行兩支腳本並實查驗證:
-
sql\TWORK_QRY_BOR_CYCLE-deploy-5.sql(建立 SP,csa 五帳套)-
sql\TWORK_QRY_BOR_CYCLE-procparam-log5.sql(proc_param 登錄,log 五庫)- 換別家客戶:照該客戶實際庫名整批取代後再跑。
詳見 ADR 0090。
-
07-09 customdash-batch-month-acc-selfrpt ▸
2026-07-09 自訂查詢面板「整批換月」支援自訂財報
變動
CUSTOMDASH 自訂查詢面板的整批換月現在也會換到 ACC_SELFRPT(自訂財報) 的當期月份:
- 按「整批換月」並選目標月份時,清單中的財報 tile 會把「當期起始月份」與「當期截止月份」兩個月份同步平移到目標月(兩者移動同樣的月數,維持當期區間寬度)。
- 清單即使全部都是財報(沒有一般日期查詢),也能判斷來源月份並換月;先前這種情況會跳出「清單中的條件都沒有日期欄位」而換不了。
注意
- 年度不會被換月改動:只平移兩個當期月份,
年度、截止日期維持不變。因此跨年換月(例如 12 月的報表想換到隔年 1 月)月份會停在 12/1 不外溢——同一年度內逐月推進不受影響。
- 換月改的是設定端查詢清單的條件;換完仍需按「查詢」重新產生面板才會看到更新後的結果(與原本行為一致)。
- 財報的抓數區間(由年度+截止日期決定)不受此次換月影響,換的只是報表中「當期」欄位的計算月份範圍。
對應
- ADR 0089
- runtime 尚未實機驗證(單元測試 35/35 通過)。
-
07-08 accexp-report-print ▸
2026-07-08 費用攤提報表(ACCEXP)列印上線
摘要
費用攤提列印(AccexpPrint)程式原本有查詢參數面板但按不出報表(舊列印邏輯是停用的 Crystal 殘碼)。本次把兩張報表 當月攤提報表 與 年度攤提總表 轉成 FastReport 並接好整條列印管線,使用者現在可從程式實際列印/預覽。
新增
- 當月攤提報表(Accexp1):依「起始/截止費用編號」範圍與「年度/月份」列出當期各費用的本期攤提、累計攤提。
- 年度攤提總表(Accexp2):同範圍條件,橫向列出 01~12 月各月攤提金額的年度總表。
- 兩張報表皆掛在既有的「費用攤提列印」程式,沿用畫面上的年度/月份與費用編號起訖條件。
變更
- 「費用攤提列印」的列印按鈕從無作用改為可正常出報表(預覽/列印)。查詢條件面板與欄位不變。
刪除
- 移除 AccexpPrintViewModel 內已停用的舊 Crystal 列印註解碼(無使用者可見影響)。
Breaking Changes
- 無。
Migration Notes
- 報表檔已佈署:
Accexp1.frx、Accexp2.frx已放入報表目錄C:\dglibrary\REPORTSROOT\Reports\。新機器佈署時,記得將這兩個 .frx 一併同步到該目錄,否則列印會找不到報表。
- 資料來源沿用既有 SP
TWORK_RPT_ACCEXP,無需新增資料庫物件。
已知限制
- 簡體中文版(Accexp1cn/Accexp2cn)暫未接線:舊系統僅「鈞寶電子(蘇州)」使用簡體版報表,本次為本公司(非該客戶)只接繁體版;簡體 .frx 已轉好備存,該客戶需要時再接線。
- runtime 驗收尚未進行(未實開視窗按列印驗證資料回填)。
-
07-06 customdash-export-and-chart-spec ▸
2026-07-06 自訂查詢面板彙整匯出(Excel/PPT/HTML)與宣告式圖表
摘要
自訂查詢面板(CUSTOMDASH)新增
彙整匯出鈕:勾選各查詢要用的報表後,選一個資料夾,一鍵同時輸出 Excel、PowerPoint、HTML 三個檔。同時導入一套「宣告式圖表」機制——圖表定義存在資料庫,前端依定義自動畫圖,加一張圖不用改程式;資產負債表已率先掛上圖表區示範。新增
- 彙整匯出(Excel/PPT/HTML):面板頂端工具列的
彙整列印 (PDF)旁新增彙整匯出鈕。操作與彙整列印一致(逐支查詢勾選、各挑一張報表),確定後選資料夾,系統直接以查詢的原始資料產出三個檔案並自動開啟資料夾。與既有「彙整列印(PDF)」、報表預覽「匯出EXCEL」並存、各自獨立。
- 圖表區:查詢頁面可顯示由「圖表定義」自動產生的圖表(直條/圓餅/折線)。資產負債表第一分頁明細下方已掛上圖表區作為示範;因自訂查詢面板顯示的是各查詢的原生畫面,凡是掛了圖表區的查詢,放進面板後也會一併顯示圖表。
- 匯出檔內含圖表:彙整匯出的 Excel 為 Telerik 原生圖、HTML 為 SVG 圖;PPT 一期先放「圖表位置占位文字框」(原生可編輯圖表為二期)。
變更
- 無既有功能行為變更(純新增按鈕與圖表區;彙整列印、儲存設置、整批換月等既有功能不受影響)。
刪除
- 無使用者可見刪除。
Breaking Changes
- 無。
Migration Notes
- 圖表與匯出圖表需先部署圖表定義:由系統管理者於各客戶資料庫執行
sql/chart-spec-deploy.sql(建表+示範定義;跑含中文腳本須加-f 65001並實查驗證)。
- 未部署時:圖表區不顯示、彙整匯出只輸出表格頁(無圖),功能不會出錯,可照常使用。
- 之後要新增一張圖,只需在資料庫的圖表定義表插入一筆設定,不必改程式、不必重新發版。
已知限制(二期候選)
- PPT 圖表為占位文字框:一期 PowerPoint 檔中,圖表位置以文字框標示;可原生編輯的 PPT 圖表列為二期。Excel 與 HTML 已為真圖。
- 表格頁沿用彙整列印取數,沒有報表的查詢不會有表格頁(圖表頁不受此限)。
- 圖表定義一期支援排序、取前 N 名(TopN)與簡單篩選,不做分組彙總(彙總請由查詢程式本身處理)。
- runtime 驗收進行中。
- 彙整匯出(Excel/PPT/HTML):面板頂端工具列的
-
07-05 excel-export-shrinktofit ▸
匯出EXCEL 重寫:彙整列印一支報表一個工作表、不再出現細碎欄位
- 日期:2026-07-05
- 影響範圍:所有報表預覽視窗(
TsFastReportPreview)的「匯出EXCEL」;彙整列印(CUSTOMDASH)受益最大
變更內容
- 彙整列印匯出 EXCEL:原本所有報表擠在同一張工作表,現在一支報表一個工作表,工作表名稱=報表名稱(超過 31 字自動截斷、重名自動補序號)。一支報表有多頁時仍併在同一張工作表。
- 欄位不再細碎:匯出改用非 Wysiwyg 模式——原本會沿報表物件邊緣切出大量超細欄、跨欄標題被截半;現在改用較粗的欄格,出來的檔案可讀可編輯。
- 縮字貼合:文字塞不下儲存格時自動縮小該格字型完整顯示,不再被隔壁儲存格遮住
(在 OOXML 層整片補上——FastReport 自帶的 ShrinkToFit 量測偏窄會漏,SpreadProcessing 轉存又會把它丟掉)。
- 列高補足:列高低於該列最大字型所需高度時自動拉高(只加高不縮矮)——修「標題整個看不到」
(實例:資產負債表 18.7pt 標題被壓在 8.51pt 的列裡)。
備註
- 版面精度換編輯性:非 Wysiwyg 匯出與預覽畫面不會 100% 相同(要完全一致請用匯出 PDF)。
- 若個別報表匯出後版面不理想,請反映報表名稱。
-
07-05 bomflow-diagram-arrow-keys ▸
BOM流程圖查詢:切到「流程圖圖形」後左側清單上下鍵失效——修正
- 日期:2026-07-05
- 影響範圍:BOM流程圖查詢(
Bom_flow)
變更內容
- 修正:切到「流程圖圖形」分頁後,左側組件清單按上下鍵只動一格(或完全不動)的問題。現在可以用上下鍵連續瀏覽組件、流程圖即時跟著切換。
- 平移改進:按住空白背景拖曳即可平移視角(原本要按住 Ctrl 再拖)。拖曳節點、滾輪縮放不變。
備註
- 原因:流程圖控件(RadDiagram)在圖形重建時會主動搶走鍵盤焦點——左側清單每按一次上下鍵就重建一次流程圖,焦點隨即被搶走,下一鍵就沒反應。
- 修法:擋掉「非滑鼠操作」的焦點進入;滑鼠實際點在流程圖上時照常取得焦點(拖曳、縮放不受影響)。
-
07-05 bom-flow-hier-split ▸
2026-07-05 流程圖製程表與階層式製程表拆回兩支獨立程式
對應 ADR 0087(取代 ADR 0076 併版)。
使用者可見變動
- 流程圖製程表(BOM_FLOW) 回歸單純流程圖用途:
- 查詢條件精簡為 起訖品號 / 去除重複 / 計算流程圖。
- 移除先前併入的階層式專屬條件(查詢類別、生效日期、工時別、數量方式、母件方式),以及 自訂條件、文件說明、製程檢查基準分頁。
- 樹狀展開、流程圖、流程圖圖形、多階材料、含插件等分頁維持不變。
- 階層式製程表(BOM_HIER) 改為獨立程式(原本併在流程圖裡):
- 完整保留 VFP 階層式查詢能力:查詢類別(品號/客戶代號暨品號)、起訖品號、客戶區間、生效日期(本日/指定日期)、工時別(標準/改善前/改善後/備料)、數量方式、母件方式、自訂條件、只顯示工時。
- 自訂條件旁提供 「泛用取品號」按鈕(可由 Excel 品號清單一鍵組成查詢條件)。
- 明細表欄位順序對齊 VFP 原版。
- 選單位置:D.設計 → 階層式製程表。若權限管理中看不到,請開啟該程式的瀏覽權限。
備註
- 兩支現為各自獨立的程式與查詢條件,可分別在「自訂查詢面板(CUSTOMDASH)」加入、各自儲存設定。
- VFP 主檔的「備註」欄本次未帶入(資料源尚未提供);階層式製程表報表(BOM_H1/H2/H4)另案處理。
-
07-04 scx-stk-cy-full-port ▸
2026-07-04 朝陽(CY)庫存模組整支移植(scx_stk_cy)
摘要
VFP 庫存模組
scx_stk_cy(14 class)以三階段流程(兩庫欄位聯集 → VFP 為規格書完整實作 → 報表轉 FastReport)整批移植完成。含 6 支整支新建程式、9 支既有程式補完、5 支轉單子表單、約 50 張報表。全部建置通過;runtime 全未驗,上線前需實機驗收。新增
- 廠商庫存表 INV_SP(CY 專屬):年結計算(沿用 DARB_QRY_INV_SP年結)+ Excel 匯入
- 廠商分攤計算 INV_SP1:三分頁彈窗(調撥廠商/其他單據 FIFO 分攤/稽核上傳),演算法下沉 SQL(ADR 0081)
- 委外申請單 TRINOUT_CY:朝陽委外變體(ADR 0080),含外包查詢、53 委外重算驗證
- 加工單 TRWKMA:主檔維護+外送回收自動產耗料(DB→DARB_LOG_DB_TO_PD)+暫收轉入 Tptodb
- 年度盤點產生 INVREC3Y:勾倉儲批次產生多張盤點單(盤點單其他5鈕)
- 轉單子表單五支:NATRLO 不良轉借、TRLIMA_M 借出查詢、NATRRB 轉不良、TRINOUT1 轉異領、TRLOST_S 調整耗料(負庫存分攤)
- 報表約 50 張:八支單據列印(依前置碼自動選版面)、進貨/出貨分析面板(各 3/4 種×含金額)、INVBK1M/GINVBOOK1 對帳、盤點卡/盤點表/盤點標籤(QR 改 FastReport 原生條碼)、TRLILOBI 未歸還明細表
- invbk1 補:計算廠商、廠商追蹤整頁、日記帳過濾、品號/群組條件別、朝陽預設
- trlost 補:盤點退料鈕+PB→PA 鈕
變更
- trsama「已轉帳款」防呆由警告改為擋下修改(照 VFP,使用者裁定)
- Invrecm 新增查詢改走
DARB_INVREC原版(TWORK_INVREC 從未部署,屬壞引用)
- trsama 訂單轉出貨導航修復(誤用他模組 ViewModel 的 pkid)
- H.Inventory 全部 15 支 Source 補 LocalDbContext 註冊+無參建構子(先前 navigate 開窗即崩)
- IOther7/IOther8 介面簽章 void→Task(框架反射建 Func<Task>,void 實作按下即炸)
- 兩庫欄位聯集同步:trinoutd 委外 9 欄、trsama.隸屬客戶、trrafee.進貨單序號、多個 view 顯示欄
刪除
無(美規 Trinout、DARB 英文版報表 plugin 均保留)
Breaking Changes
無(新程式以 dev-programs.json / ProgramClassRouter 疊加,不影響既有客戶)
Migration Notes
1. 模擬環境已部署/登錄:TWORK_QRY_INV_SP1+proc_param 七筆(INV_SP年結/INV_SP1/TRINOUTE1/TRLOST_S_P2/INVBK1_TRSP/INV_SP2×2/RPT_SPLACE)。正式庫上線時需重跑 sql/ 下對應腳本。
2. CY 切新版時執行
sql/trlost-turn-proc-param-CY.sql註解段(prgsct1 其他鈕重排)——VFP 在線時不可跑。3.
sql/trwkma-add-darb-log-db-to-pd-nogi.sql未執行(鈞寶是否使用加工單 DB 流程待確認)。4. 報表 frx 需同步佈署各機
C:\dglibrary\REPORTSROOT\Reports\;版面為轉檔+手修稿,建議實印後 Designer 微調。5. 刻意延後:WKDAY_TR 耗料產生視窗(另案)、撿料標籤群、trlost2(VFP 無路徑選到)、tr_sp 分攤編輯(invbk1)、SEEKWKQ、樞紐分析。
-
07-03 trrama-trsama-analysis-reports ▸
進貨/出貨分析報表(VFP trrama_bd / trsama_bd 移植)
摘要
scx_stk_cy 報表批次 R5:移植 VFP 瀏覽分析面板掛的 14 張分析報表,並新建兩支承載視窗。
- 進貨分析 6 張:RA_DE1/2/3(廠商別/產品別/日期別)+含金額 RA_DE11/21/31
- 出貨分析 8 張:SAL_YR1/2/3/4(客戶/產品/日期/單號)+含金額 SAL_YR11/21/31/41
新增
- 進貨單(TRRAMA)、出貨單(TRSAMA) 主檔畫面單號旁新增「分析報表」按鈕,開啟分析報表視窗。
- 分析報表視窗(ContentWindow 彈窗):
- 查詢條件:交易日期區間(預設本月 1 日~今天)+廠商/客戶代號區間(空白=全部)
- 報表種類 radio(進貨:廠商別/產品別/進貨日期別;出貨:客戶/產品/日期/單號)
- 「包含金額」勾選 → 改印含 單價/金額 的版本(RA_DE11/21/31、SAL_YR11/21/31/41)
- 預覽 / 列印 按鈕
- 報表頁首顯示查詢條件文字(對應 VFP L_瀏覽查詢條件)。
- 資料源沿用既有 SP
DARB_BD_TRRAMA/DARB_BD_TRSAMA(proc_param 已登錄,無需 DB 佈署)。
變更
- 無既有行為變更。
刪除
- 無。
Breaking Changes
- 無。
Migration Notes
- 報表樣板 14 張
.frx已佈署C:\dglibrary\REPORTSROOT\Reports\(其他機器需同步佈署)。
- VFP 面板上的「遮罩」鈕(grid 數量欄格式化)與樞紐選單為瀏覽 grid 專屬功能,新版由 RadGridView 欄位格式取代,不移植。
-
07-03 salesdash-monthly-report ▸
2026-07-03 業務儀表板 + 業務課報告表自動產生
摘要
新增「業務儀表板」(SALESDASH,E.營業收款)與 AutoPilot 排程任務「產生業務課報告表」,
兩者共用同一產生邏輯:ERP 訂單明細 + TTVMA 汽機車銷售統計自動填入業務課報告表 Excel 範本。
新增
- 業務儀表板:本月訂單金額/出貨數量/LOT 數/交易客戶數 KPI 卡片、
各月訂單金額長條圖、本月客戶 Top15 清單。
- 儀表板內「產生報告表」按鈕:指定年月一鍵產出業務課報告表,可勾選是否含 TTVMA 市場資料,
完成後可直接開啟輸出檔。
- AutoPilot 任務
ORMAST / SalesMonthlyReport:可排程每月自動產生(建議每月 18~20 日產上月,
Month 參數用
{-d1})。- 自動填寫的工作表:原紙(整年訂單明細)、樞紐1~12月、國內/國外向出貨數、國內/國外LOT、
渡邊總工程、銷貨趨勢表(實績)、營業額(實績)、4W/2W銷售(TTVMA 原表)、
汽/機車市場佔有率、4W/2W銷售趨勢圖。
變更
- 無既有功能行為變更。
刪除
- 無。
Breaking Changes
- 無。
Migration Notes
- 範本檔:
C:\dglibrary\REPORTSROOT\Template\業務課報告表範本.xlsx
(SalesReportTemplateBuilder 產生的乾淨空白版;舊人工版備份為同資料夾
-原版備份.xlsx)。- 「5月-市佔率/5月-暢銷車款/電動車市佔」三頁為外部新聞圖片,仍需人工貼圖。
- 銷貨趨勢表未來月份的客戶預示金額、營業額目標列維持人工維護,程式不覆寫。
- 開發環境入口已加入
dev-programs.json;正式環境需登錄 SALESDASH 程式權限。
-
07-03 preview-excel-export ▸
報表預覽工具列:「另存新檔」改為「匯出EXCEL」
- 日期:2026-07-03
- 影響範圍:所有報表預覽視窗(
TsFastReportPreview)
變更內容
- 工具列移除「另存新檔」按鈕(原為 FastReport 原生存檔對話框,可選多種匯出格式)。
- 原位置改為「匯出EXCEL」按鈕:直接匯出
.xlsx(Excel 2007 格式),選好存檔路徑後自動以預設程式開啟。
- 「匯出PDF」按鈕不變。
備註
- 匯出走已備妥的報表頁面,不重新運算(彙整多支合併的報表匯出結果與畫面一致)。
- 原「另存新檔」提供的其他匯出格式(Word、HTML、圖片等)自此版起不再提供入口;如有需要請反映。
-
07-03 manual-site-redesign ▸
2026-07-03 使用手冊網站改版 + 批次補主畫面截圖
摘要
manual.yanyue.io 全站視覺改版:自訂品牌配色(深松石綠 × 工安琥珀)、新首頁「模組索引牆」(20 個模組字母磚依五大業務域上色,與桌面系統選單代號一致)、新 logo/favicon、字體與導覽功能升級。並以新的批次截圖工具補齊 38 張功能頁主畫面截圖。
新增
- 首頁模組索引牆:五大業務域(基礎資料與系統/銷售與供應鏈/製造與品質/財務與帳務/協作與決策)分組的字母磚導航
- 首頁三步驟使用指引與維運連結列
- 38 張功能頁主畫面截圖(
*-step1.png)
- 網站 logo 與 favicon
變更
- 佈景主題配色由預設 indigo 改為自訂色系(亮/暗兩模式皆調整)
- 字體:內文 Noto Sans TC、模組字母與編號 Space Grotesk、程式碼 JetBrains Mono
- 首頁改為隱藏側欄的全寬版面;模組名稱對齊
.nav.yml正式名稱(如「總務管理」「工程資料」「營業收款」)
- 導覽功能追加:instant navigation、navigation.footer、toc.follow、search.share
刪除
- 舊首頁的模組表格(名稱已過時,由索引牆取代)
- 「欄位比對工具」「欄位比對列印」頁面(DB 維運工具,屬開發者工具非終端使用者功能)
Breaking Changes
無。
Migration Notes
無需動作;push 至 master 後由既有 pipeline 自動部署。
-
07-03 flowcast-chart-split-panels ▸
2026-07-03 金流預測圖表拆成上下兩張單軸圖
摘要
「金流預測」的圖表區從單張雙軸圖(6 條收付堆疊柱掛左軸+累計淨額折線與資金警戒線掛右側第二軸),
改成上下兩張共用時間軸的單軸圖:上圖只畫累計淨額,下圖保留收付堆疊柱。
雙軸讓使用者容易把柱頂拿去跟警戒線比較而誤讀(柱頂是單月收付金額,警戒線是累計淨額門檻,兩者量級不同),
拆成兩張單軸圖後每張圖的縱軸只對應一種量級,避免誤讀。
新增
- 上圖新增警戒區塗色:從資金警戒線到(月彙總最低累計淨額/警戒線取小值再留 10% 緩衝)之間塗淡紅色。
- 上圖累計淨額線跌破警戒的區段改標紅色粗線(含跌破區與正常區的銜接邊界)。
- 上圖新增「最低點」標註(僅最低累計吃緊時顯示)與「首次跌破警戒」標註(僅期間內曾跌破時顯示)。
- KPI 摘要列新增「首次跌破警戒」卡片(期末累計淨額卡之後),有跌破顯示月份紅字、無跌破顯示「—」灰字。
變更
- 圖表區由「一張雙軸圖+右側圖例」改成「上圖(累計淨額,45% 高)+下圖(堆疊柱,55% 高)+跨兩列圖例」。
- 下圖(堆疊柱)不再掛累計淨額折線與右側第二軸,只保留 6 條收付堆疊柱;點柱過濾、來源勾選、
X 軸粒度切換(年月/日期)行為不變。
- 圖例文字「累計淨額(右軸)」改為「累計淨額(上圖)」,新增「資金警戒線」「警戒區」兩列圖例。
- 上圖時間軸(X 軸)標籤隱藏,僅下圖顯示時間軸標籤,避免兩張圖重複顯示。
刪除
- 移除右側第二軸(
cumulativeAxis);金流預測不再有雙軸圖表。
Breaking Changes
- 無(純畫面呈現調整,資料來源與明細/月彙總分頁不變)。
Migration Notes
FlowcastMonthPoco新增跌破值(可為 null)、FlowcastSummaryPoco新增首次跌破月/有跌破,
純附加欄位,不影響既有 SP/DB 結構。
FlowcastComposer新增ApplyBaseline(periods, baseline),取代原本內嵌在 ViewModel 的
「跌破警戒」判定迴圈;
Summarize需在ApplyBaseline之後呼叫才能算出正確的「首次跌破月」。- Runtime 未驗(需開啟金流預測畫面實際操作確認圖表呈現、警戒區位置、標註顯示邏輯),已記入 memory。
-
07-03 findash-phase1 ▸
2026-07-03 財務月報一期:自訂查詢面板整批換月+進貨廠商統計
- 自訂查詢面板(CUSTOMDASH)新增「整批換月」:條件區新增「目標月份」與「整批換月」按鈕,一鍵把清單中所有查詢條件的日期平移到目標月份(月底日自動對齊目標月月底,如 5/31→6/30)。載入上個月存的月報配置後不必再逐支手改日期。
- 新增查詢程式「進貨廠商統計」(SPBUYRANK):期間內進貨(含退貨沖減)按廠商彙總金額、降冪排序、附佔比與合計,供財務部月報「進貨/加工廠商金額統計」使用;可加入自訂查詢面板。
- 毛利率分析(QRY_PROFIT_NOGI)新增兩張報表:客戶別(M160-1)與品號別(M160-2)毛利彙總表,毛利率低於 10% 以紅字標示(FastReport 原生 Highlight,非 script);補上後此查詢可加入自訂查詢面板的彙整列印。
- 進貨廠商統計新增報表(M-D5-1):廠商排行列表報表,補齊後可進自訂查詢面板彙整列印。
- 整批換月支援斜線日期格式:條件裡以字串儲存的
yyyy/MM/dd日期(全系統字串日期標準格式)也會被平移,不再只認 DateTime 型日期。
- 終端使用者手冊新增/更新四頁:自訂查詢面板(含整批換月)、進貨廠商統計、毛利率分析(列印一節+移除過期的「尚未移植」標示)、M-EIS 索引。
- 尚未包含:以上各項 runtime 未實機驗證;庫存統計查詢的報表(口徑待確認)後續補。
相關決策:ADR 0085。
-
07-03 customdash-save-config ▸
2026-07-03 自訂查詢面板:儲存設置、報表記憶、點選顯示條件
變更內容
自訂查詢面板(CUSTOMDASH)新增三項功能:
1. 儲存/載入設置(可按組織關係分享):查詢區上方新增配置列——可將目前的查詢清單(選了哪些查詢程式、各自的條件、分頁順序)以名稱儲存,之後從下拉選單載入還原,也可刪除不用的配置。配置存於伺服器資料庫,換電腦也看得到同一份。
- 分享:儲存時會記錄「使用部門」——預設自動帶入自己目前的部門,可手動改成其他部門代號;該部門與其上層部門的人都看得到這份配置。此外,主管看得到下屬(含各層)建立的配置、代理人看得到被代理人的配置。
- 下拉選單中別人分享來的配置會標註擁有者代號;只有自己建立的配置能刪除(別人分享來的不可刪,但可另存成自己的一份)。
2. 彙整列印報表記憶:彙整列印時每支查詢選過的報表會被記住(並隨設置一併儲存),下次開彙整列印視窗自動預選上次的報表;只有勾選列印的列才會更新記憶。
3. 點選查詢清單顯示條件:點擊查詢清單中的項目,左側條件面板會顯示該項目已存的條件內容,可修改後按「更新條件」寫回;原本加入清單後條件只能從 ToolTip 看 JSON。
影響範圍
- 僅自訂查詢面板(M.主管資訊 CUSTOMDASH);其他程式不受影響。
- 需部署資料庫腳本
sql/customdash-config-deploy.sql(五帳套一次跑完:表+讀取權限查詢 SPTWORK_CUSTOMDASH_QRY建至 darbnogicsa1~5、proc_param 登錄至各自配對的 darbnogilog1~5;缺席的帳套庫自動跳過;寫入改走標準上傳引擎,舊的 SAVE/DEL SP 廢除)。未部署時面板照常可用,僅儲存/載入設置會顯示失敗訊息。
- 分享可見範圍依既有的「工作關係設定(BOR)」與人事部門資料判定;未設定組織關係者,配置行為與純個人一致(只有自己看得到)。
-
07-03 check-module-reports-fix ▸
票據管理報表列印修復(Bank / Bankfcst / Spbank / Checkrec1)
摘要
票據管理(O.Check)與帳款管理(I.ARAP)共 76 張報表全面盤點,發現 4 張報表的資料管線斷鏈(皆在票據管理),列印時跳「Not found Assembly」或整張空白,已全部修復。帳款管理 76 張中的其餘報表均健康,無需變動。
變更
- 銀行帳戶表(Bank)、預估資金表(Bankfcst)、廠商帳戶表(Spbank)、應收票據一覽表(Checkrec1):新增對應報表 plugin 與報表 POCO。從主檔畫面列印時由 plugin 以全表資料產出;從瀏覽視窗列印時維持原本的瀏覽結果複製(可先篩選再印)。
- 應收票據一覽表:修正
CheckrecViewModel的 sqlite 資料表名錯位(rpt_o030_checkrec_report1→rpt_o020_checkrec_report1),並將Checkrec1.frx的資料表引用改為瀏覽式_1後綴,與應付票據一覽表(Checkpay)行為一致。
新增檔案
Model/Rpt/Rpt_O010_BankReportPoco.cs、Rpt_O050_BankfcstReportPoco.cs、Rpt_O120_SpbankReportPoco.cs、Rpt_O020_CheckrecReportPoco1.cs
TworkReportPluginOfficial/Bank.cs、Bankfcst.cs、Spbank.cs、Checkrec1.cs
Breaking Changes
無。
Migration Notes
Checkrec1.frx已同步佈署至C:\dglibrary\REPORTSROOT\Reports\;其他機器需隨版更新報表樣板。
- 無 DB 變更(資料取數走既有
DARB_GETDATA4,proc_param 已登錄)。
- Runtime 尚未實機驗證(模擬環境 bankfcst 表無資料屬正常)。
-
07-03 bom-query-condition-parity ▸
2026-07-03 D.Bom 查詢程式條件全面補齊(對齊 VFP scx_eng_cy)
摘要
六支 BOM 查詢程式的條件面板與結果功能依 VFP 對比結果全面補上(ADR 0078)。零 DB 部署。
新增
- 共通
- 「自訂條件」輸入欄(最低階用料/產品用途表/流程圖製程表):自由輸入 SQL 條件,非空白時優先於面板品號條件(取代 VFP _SQLQRY1)。
- 「泛用取品號」Excel 批次品號匯入(最低階用料/產品用途表/成本表):檔案選擇視窗(預設 C:\TEMPS,支援 .xls/.xlsx),格式同 VFP(第 2 列起 B=客戶代號、D=客戶品號、E=品號)。
- 成本表(BOM_COST)
- 代工費率(元/分)+代工費率別(單一費率/代工廠商):P320 委外部門工序成本依此計算;代工廠商模式抓組件主要廠商費率與 B00 報價工時。
- 客戶報價截止日/廠商報價截止日:可回溯歷史報價(空白=最新,維持原行為);廠商報價日同時作為 BOM 展開生效基準日。
- 查詢別「泛用取品號」模式:以 Excel 清單逐列(客戶×品號)計算成本。
- 產品用途表(BOM_PURP):結果篩選別
全部/不含舊品/去除重複星號品。
- 最低階用料(BOM_BOTM):「相同品號彙總」勾選(依品號合併、加總數量/含損耗數量/庫存量/總重)。
- 專用材料表(BOM_EXCL):「品別不含B.客戶機種」勾選(預設勾選,對齊 VFP 預設輸出);查詢前品號必填驗證。
- 流程圖製程表(BOM_FLOW):條件區 ISO 文件說明回顯(品名/文件編號/文件名稱/版次);多階材料用量清單「含插件」整批旗標+欄位;新「製程檢查基準」分頁(工程代號檢查項目/基準)。
變更
- 成本表 比例別預設由「成本」改回 VFP 的「售價」。
- 產品用途表「僅查詢最底階」改傳層數 0 給 SP(VFP 同款),結果等價、查詢資料量大幅下降。
修正
- 🔴 成本表
SetCost_Optimized材料價/委外工序價兩個查價來源交叉錯置:進貨價模式材料誤抓廠商報價、委外工序報價會漏查(人工成本 0)。
- 🔴 專用材料表 用途表
品別欄型別錯誤(SP 回傳「4.成品」字串、Poco 宣告 int):CY 庫開查即炸;連動修正「是否專用」判斷與品別說明。
Breaking Changes
- 無(新條件預設值=原行為;P320 邏輯僅在有該部門代號的庫觸發)。
Migration Notes
- 無 DB 變更。runtime 未驗,重點驗收:自訂條件、Excel 匯入、bom_cost File 模式、代工費率兩模式、報價截止日回溯、bom_excl 品別過濾預設值。
-
07-03 alledi-transfer-completion ▸
2026-07-03 alledi(CY 機車 OEM EDI 轉單)轉單層照 VFP 逐頁補完
摘要
alledi(ProgramClass.ALLEDI)14 個在用分頁的「轉單/上傳」業務邏輯,照 VFP
alledi_utf8.prg各頁轉單 procedure 逐頁補完。先前僅顯示層+讀檔 parser 完成、上傳為通用骨架;本次補齊單價/單位/包裝量反查、預示版次規則、工作日攤分、編輯既有單模式、工具頁產出(EXCEL/DBF),並修正一個必炸接線 bug。新增
- 共用轉單支援
AllediTransferSupport:
- 單價反查
vw_cupdma最新報價(SEEK 品號+客戶品號;舊頁 fallback SEEK 品號、反查不到單價=0)- 單位反查 invent、包裝量/標籤數反查 cuinve(生效/失效區間)
- 預示表版次規則:版次 1→9 找空號、「已有大於本月份之預示訂單」擋下、單號=年月+版次+客戶代號
- 工作日曆
BackWorkDay/WorkDaysBetween(Util_Pdt LCL工作日曆,載不到退日曆日)- 攤分演算法:
SpreadByBase(基數100×工作天倍數攤分)+BuildAllocationOrder(日期分配每 5 工作日跳排)AllediDbfWriter:極簡 dBase III 寫出器(年度銷售「產生DBF」用,Big5 中文欄名)
- SYM預示 工作日攤分:4 個 UI 日期(下一/下二/下三起始日+下三截止日)接進 BLL,
期別末碼≥'A'(CKD/SPD)不拆分、其餘照 VFP edipdsym 攤成逐工作日明細,攤分後逐列重反查品號、備註=期納客供(invent.規格)
- YMTT預示 扣當月訂單量:近一年 vw_ordetlid 對照,交期改最新訂單交期+5工作日、過期標「-過期」、數量=原始數量-當月訂單量
- SY計劃/SYM-2W「編輯既有單」轉單:
UploadSyPlan(依預示單號扣減既有明細'E'+新增'A')、
UploadSym2w(依取代預估單號,起訖區間舊明細標'D'+新增,備註=使用者+日期+EDI);新明細用負數 pkid(同 VFP)- SY_BOM 先刪後建:轉單前刪 bom_m 中品別11(客戶機種)且在本批的既有 BOM(AdeUploadBll.Delete / INPUT-BD),再全新建(途程序號 001…、數量公式=STR(數量))
- SY計劃/SYM-2W BOM 展開接真資料:invent 品號檢核+bom_d(生效/失效過濾)展開,原 TODO stub(展開恆空)移除;需求日提前一工作日(UPDT_BACKWKDAY_LCL -1)
- 工具頁產出:泛用取品號「產生EXCEL」(CopyToExcelBll 匯出開啟)、年度銷售「產生DBF」(C:\TEMPS\訂單及預示.DBF)
- 輔助鈕全數實作:Excel 匯出×5、重新檢查×2(重標無品號)、新YAMAHA 文字檔讀入(notepad 開檔)——原「後續階段實作」占位訊息全移除
變更
- ORMAST 轉單表頭補齊 VFP 共通值:倉儲代號='出貨倉'、訂單別='1'、序號前置碼='CO'、匯率=1、per-vendor 訂單備註(鼎豪=訂單輸入日+採購+今天+EDI轉入、新SUZUKI=展開日期:…);明細補 交貨地點/客戶訂單號/結關日期/單位/包裝量/標籤數/原幣未稅=ROUND(數量×單價,0),序號一律重編 001…
- 轉單前置檢查:訂單類擋「查無品號」列;SY_BOM/SY計劃/SYM-2W/年度銷售 擋「錯誤欄非空」列;SY計劃/SYM-2W 擋「已更新過」重複轉單
- 年度銷售 parser 修正:CSV 第 2 欄是公司品號(含
*,直接查 invent),原誤當客戶品號走 cuinve 反查;補 查無客戶/品號無 */查無品號 檢核與 客戶簡稱/品名/停用說明
- 新YAMAHA/新SUZUKI 雙軌轉單:預示年月基準各自正確(最小預訂交期 / 展開日期);新SUZUKI C檔下示交期接真工作日曆
- SYM-2W parser:.xls 讀檔改走共用 AllediExcel(原 XlsxFormatProvider 讀 .xls 會炸)、客戶品號反查方向修正(品號→客戶品號)
- 慶俊預示/YMTT預示/SY計劃/新SUZUKI 的工作日推算由「日曆日保底」改接真正 LCL 工作日曆(Util_Pdt,載不到才退保底)
修正
- 🔴 慶俊預示轉入必炸:VM 未把 起始日期/客戶代號 設進 BLL,BLL 起始日期必填直接 throw——已接線
- SYM/慶俊/SY計劃/SYM-2W 各頁輸入框(年度/月份/起始日期/預示單號/取代預估單號/轉單起訖日)原是裝飾、未接 BLL/轉單——全部接上
已知限制(待後續)
- 全數 runtime 未驗收:需
C:\轉EDI資料\真實樣本檔逐頁跑(轉入預覽+轉單對帳)
- 選單僅開發期 dev-programs.json 注入;正式 DB 登錄(usp_新增程式+_menum)未做
preord_m.採購員(YMTT預示='貿易商')與ormast.公司代碼合併 Source 無此欄(darbnogicsa1 缺,ADR0050 CY 專屬欄待裁定)→ 未寫入
vw_cupdma最新報價無「已審核」欄(VFP SYM/YMTT 帶此條件;view 本身即最新報價彙總,視為等義)
- SYM預示 VFP 的「重複客戶品號+品號+交貨地點」檢查副表(EDIPDSYMCHK)未呈現(讀檔去重已涵蓋主要情境)
- 年度銷售 grid 以「每月一列」呈現(VFP 為一列 12 月欄+總計列;產生 DBF 的資料等價)
- YMTT訂單 grid「公司報價」欄未回填(轉單時以 vw_cupdma最新報價 反查,資料等價、僅顯示差)
建置
LogicBll(dotnet)/ ViewModel / TsERP.csproj(VS MSBuild)0 error;HarnessSmokeTests 3/3 通過。
TsERP.sln 整包僅 UnitTest1.csproj(net48 參考 net8,既有問題)失敗,與本次無關。
- 共用轉單支援
-
07-02 scx-qry-cy-recompare-fixes ▸
2026-07-02 scx_qry_cy 主管資訊查詢 重新對比修補
摘要
對朝陽 CY 主管資訊 EIS 查詢庫
scx_qry_cy(15 支可執行 class)重新逐支對比 VFP 原碼與新版(程式碼 + 前端 XAML),修掉 4 組會阻斷/算錯的 RED 與數個可直接處理的 YELLOW。whole-tab/子表單/報表列印/DB 客戶專屬公式等 feature port 仍列為延後(見下)。變更(使用者可見)
- 外退不良統計 / 派工排程查詢 / 庫存統計查詢:補回
DIExtension.cs遺漏的 3 支ConditionViewModel註冊。此前這三支開窗即崩(「無法建立 ViewModel」),現在可正常開啟。(Group B 移植當時漏了 DI 那一步,同 Group A 曾犯的病。)
- 達成率統計(pd_qry4):新增「僅查詢訂單」勾選框,預設勾選,勾選時排除 A 開頭預示/估算製通單(
製通單號 NOT LIKE 'A%')。此前無此選項=永遠納入 A% 單,與 VFP 預設相反,會使計畫點數/達成率算錯。動態部門欄改依生產順序排序(原用部門代號字典序)。
- 收料不良統計(pur_qry2):
- 廠商別頁「名次」欄修正 binding(原綁不到屬性永遠空白)。
- 廠商評分公式改對齊 VFP 現行(2019/09/03)算法,並分「採購/外包」兩式(原套用被註解的舊公式且不分類,分數會錯)。
- 明細頁新增「只顯示不良」勾選框,預設勾選(對齊 VFP page4 預設)。
- 期間效率統計(pd_qry2):修「期間工時調整」分頁開啟即崩(重複索引鍵例外);修「組立狀況」起訖品號在派工品號模式下用錯維度(製單品號 vs 派工品號)導致查錯資料。
- 期間效率統計 / 非生產工時統計:查詢前補「請先選擇生產部門」防呆(原全不勾會組出殘缺 SQL 拋例外)。
- 派工排程查詢(pd_qry8):生產部門清單新增「全選/不選」批次鈕。
- 庫存統計查詢(costqry2):Tab A/B 補顯示「期初數量/期前正數量/期前負數量」三欄(資料原已算出只是沒上版面);各補一個 client-side 過濾勾選框(僅顯示單價不完整/銷售價為0;僅顯示材料價為0)。
新增
sql/TWORK_QRY_EXCE_INOUT_darbcycsa1.sql、sql/TWORK_QRY_STOCKLIFE_darbcycsa1.sql:補 CY 庫(darbcycsa1)缺的 SP 本體。原本 SP 只佈署到 darbnogicsa1,但 proc_param 已指向 C → CY 執行會崩「無效物件名稱」。⚠️ body 沿用 nogi 版,執行前須人工複核 CY 是否有客戶專屬差異。
Migration Notes
- 上述兩支 CY SP 部署腳本尚未執行,需在 darbcycsa1 跑過,exce_inout / 庫齡分析 才能在 CY 環境查詢。含中文,用 sqlcmd 要
-f 65001並執行後實查物件存在。
仍延後(本次未做,屬 feature port)
- pur_qry2 Page5「品質管制」整頁(含查詢別2 SP + 品號條件 + grid + Excel)。
- pd_qry2「調整工時」鈕開的子表單 PD_QRY21。
- qc_qry2 Page4「生產日報表含無不良明細」整頁、Page1「個別組立數/個別不良率」兩欄、Page3 權限回寫頁、彙總資料 surface(Bll 已算但未輸出=dead code)。
- 各查詢的 FastReport 列印/Excel/Email(ADR 0034 決策:scx_qry 一律用 RadGridView 內建匯出取代)。
- stocklife:庫齡分桶交易別 DB↔MP 差異(SP 層)、單位成本公式落後版(VFP 2025/07/18 改 BOM材料+製程加工×人工費率)、庫齡明細缺 5 欄、P4 移植的是 VFP 已停用舊演算法。
- pd_qry7:設變建議品號確認窗、外部 DBF 資料別3、Excel 樞紐;OperationForecast 7 支 SP 待部署。
驗證
LogicBll(dotnet)、ViewModel、TsERP(VS MSBuild)三者建置 0 錯誤。runtime 尚未實機驗證。
</content>
</invoke>
- 外退不良統計 / 派工排程查詢 / 庫存統計查詢:補回
-
07-02 scx-ord-cy-xaml-field-completion ▸
2026-07-02 — E.Order(scx_ord_cy+scx_ord)XAML 欄位補齊與綁定修正
摘要
依 VFP 三方對齊檢查(VFP UI 欄 ↔ Source 屬性 ↔ XAML 綁定)結果分兩批補齊:第一批對
scx_ord_cy(CY 版)7 支表單補 UI 缺欄、修正 2 個錯誤綁定、解鎖 5 處唯讀倒退、刪除 2 支不可達 US 變體孤兒 view;第二批對scx_ord(非 CY 版)獨有 12 class 與共用 class 差集再補一輪(ormast 主檔 4+明細 17 欄、cuqt 加工明細 4 欄、cudata 6 欄等)。全部改動 TsERP 整包 build exit 0。新增
表單 新增欄位 訂單(Ormast) 主檔:訂單備註、聯絡單ID;明細:交貨地點、包裝量、標籤數、結關日期、製通單號(唯讀)、合併單號、補貨數量、出通單數量(唯讀) 裝箱單(Pk) 主檔:出船日、到達日;明細:產品別(插在品號附近)、合約號碼、訂單編號、預訂交期 預示訂單(Preord) 明細唯讀欄:停用日期、管制說明、生產線、工時、規格、生產批量;品號/客戶品號改值時即時回填品號附屬欄(查得到才覆蓋) 商業發票(Ci) 主檔:交易條件(可編輯文字,選碼帶入可手改);明細唯讀欄:轉入單號、訂單編號 出貨通知(Salema) 明細:客戶訂單號(可編輯)、訂單編號-序號(唯讀反查) 報價單(Cuqt) 主檔:人工費率、YMT材料費、YMT加工費(費用區,紫標對應 VFP) 客戶資料(Cudata) Tab1:發票地點+發票郵遞號(地址四連段補齊)、英文簡稱、英文名稱、港口代碼(M202 下拉)、助理、助理二、業務主管(SalesRepSearch+姓名反查) 第二批(scx_ord 非 CY 版差集)
表單 新增欄位 訂單(Ormast) 主檔:訂單別、報價單號、業務員編號(SalesRepSearch+姓名)、聯絡人;明細 17 欄:顏色、客訂單序號、廠商代號、建議採購量、建議交期、建議售價(AllowViewPrice 閘)、請購數量、是否採購、是否核發、製程別、採購別、客戶交期、訂單分類、交期變更、營業確認、出貨別、分批交貨 報價單(Cuqt) 加工明細 grid:費率(連動重算)、參考加工費、裸價治具費、治具費(非 CY 欄組原整組漏掉) 客戶資料(Cudata) 對照碼、經銷商(C270 下拉)、科目代號(GLAccountSearch)、倉儲別、公司客號、保養廠代碼 客戶報價(Cupdma) 叫修單號 裝箱單(Pk) 明細:包裝量_箱 送樣(Sample) 聯絡單ID;承認書升級下拉(1.PDF/2.EXCEL/3.書面);完成日期/是否結案唯讀對齊 達成率(Fillrate) 類別欄(C:客戶/S:廠商);備註唯讀對齊 維修(Repair) 5 處唯讀對齊(叫修人/服務人員/品名/機器序號/客戶簡稱)⚠️ 叫修人/服務人員鎖定待裁定(新版原做成可編輯指派欄) 信用額度(Cudatalimit) 上次額度/最新額度欄序修正(原顛倒) typo 修正:Sample1.xaml 兩處
DescriptionBindingPath="SKUDescription"(stale 英文名)→品名。完全對齊零修改:claim、cmplain、culbl、cungma、invent1、orssma、rtaxma、visit、pdtsal、estsal、cuinve、ci、salema(差集部分)。
變更
- Ci 商品名稱碼表修正:
TableAlias C269 → C275。DB 查證:朝陽庫(darbcycsa1)只有vwcmb275_商品名稱(有實際資料),269 不存在;VFP 原始碼c_type=275。原 C269 在 CY 環境下拉會是空/錯表。
- Pk 商品名稱升級下拉:純 TsTextBox →
TsComboBoxBySql TableAlias="C275"(對齊 VFP sqlcombo c_type=275,與 Ci 同款)。
- Cudata 請款郵遞區號錯位修正:請款地點列的郵遞區號原誤綁
發票郵遞號→ 改綁請款郵遞號;地址四連段(公司/發票/請款/送貨)郵遞配對整組核對正確。
- Cudata 唯讀解鎖 5 處:停用(Tab1)、帳號/支存帳號/活存帳號/資本額幣別(Tab2)。VFP 皆可編輯、新版無其他編輯入口、git blame 確認鎖定來自 scaffold 批次非刻意決策。
- Ci_m1(批次選取轉入)接線修復:①視窗標題改綁 VM
Title(出貨通知單轉商業發票/出貨單轉商業發票);②code-behind 補建 VM 與 DataContext(原本被註解掉、整窗 DataContext=null)+ DialogCloser;③轉入時轉入單號依 VFP 規格填「出通單號-序號」(查詢別 21),出貨單路(23)維持只填倉單號。
- Preord 移除無作用的
RowDetailsVisibilityMode殘留屬性;Cuqt 修Orientation=" Horizontal"多餘空格。
刪除
TsERP/E.Order/Ormast_US.xaml(.cs)、TsERP/E.Order/Cudata_US.xaml(.cs):兩支皆為不可達孤兒 view(無任何 DataTemplate/路由引用、TsPage 舊堆疊、綁定大面積 stale——Ormast_US 有 7 個大小寫 dead binding、Cudata_US 有 3 個 typo binding+200+ 英文 stale 綁定)。使用者裁定刪除。tools/release-notes/bootstrap-system-map.ps1跳過清單同步清理。
Breaking Changes
無。所有新增欄位的 Source/Model 屬性原本就存在,DB schema 未動。
Migration Notes
- 本批表單(E.Order 多數)無 per-view 語系 JSON、XAML 全走中文字面值;新增欄位比照既有慣例用中文 Header/Label。日後若做多語系需整模組一起建 JSON,非本次範圍。
- 使用者裁定不補(記憶已載,後續對比勿再報):公司代碼欄(5 支表單,單公司環境維持 hardcode=1)、Cudata 聯絡人 grid skype/msn/facebook/呼叫器 4 欄(已淘汰)。
- 已知另案待辦:ormast 兩庫 twin 欄(訂單號碼/倉庫/ORDERCLOSE/結案 綁美系側,CY 庫需裁定)、preord LTMP 用量 6 欄(需 DB 端彙總設計,grid 已留占位註解)、Ci_m1 挑出通轉入時新欄「訂單編號」為空(TmpSalede POCO 未映射 SP 欄位,需查證 TWORK_QRY_CI)、WindowHelper 對 RadWindow 基底的 TsWindow 會 InvalidCastException(Ci_m1 開窗路徑,建議 window-to-tsview 轉換)、PkViewModel.ItemDescriptionTypeSource 死碼待清。
- 第二批新增另案:cupdma「業務報價查詢」暫存面板(cupdtbizprice grid)、ormast「訂單歷史查詢」彈窗(ltmp訂單歷史 11 欄)、preord「採購需求表」(ltmp 39 欄)三個整組功能未移植(無 Source,屬功能移植非補欄);cudatam「付款條件」反查顯示欄需加 Source 屬性(循 收付條件說明+GetPaymentTermDescription 模式);fillrate「修改模式保留舊資料」邏輯未實作;repair 叫修人/服務人員唯讀鎖定待裁定(VFP 靠派工程式回寫,新系統若無對應則需回退為可編輯)。
- Runtime 未驗:本批為靜態補欄+build 驗證(C#/XAML 編譯通過;完整 build 因執行中 TsERP 鎖 DLL 只到複製步驟),實機開窗驗收待使用者執行。
- Ci 商品名稱碼表修正:
-
07-02 report-preview-custom-toolbar ▸
2026-07-02 報表預覽視窗工具列整併
摘要
報表預覽視窗(TsFastReportPreview)原本上下兩排工具列(自家的「匯出PDF/中一刀列印」+ FastReport 內建英文工具列)整併成單一自家中文工具列。
新增
- 工具列新增:列印、另存新檔(支援 FastReport 全部匯出格式)、搜尋、浮水印編輯、大綱面板開關、第一頁/上一頁/下一頁/最末頁、頁碼輸入框(輸入頁碼按 Enter 跳頁)、目前頁/總頁數顯示、縮小/放大/縮放至頁寬/整頁顯示。
變更
- 「匯出PDF」「中一刀列印」與預覽操作按鈕合併在同一列。
- 工具列文字全面中文化(原內建列為英文圖示列)。
- 工具列改用 Telerik Office2019 主題外觀(RadButton + RadGlyph 圖示),與系統整體風格一致;導覽與縮放為圖示鈕附中文 ToolTip。
刪除
- FastReport 內建工具列隱藏(
ToolbarVisible=False)。其上的 Open/Design/Edit 原本就已停用;Save(匯出)功能由「另存新檔」承接。
Breaking Changes
無。
Migration Notes
無需資料或設定變更。
-
07-02 program-class-router ▸
2026-07-02 程式分流:舊系統共用 DB 的程式鍵導向新版程式
摘要
新增程式分流中央對照表(ADR 0075)。與 VFP 舊系統共用資料庫的客戶(朝陽),選單登錄的
舊程式鍵會在登入後自動導向新版程式;超連結跳轉也會自動解析到該客戶實際使用的客製變體。
新增
- 朝陽:選單「庫存主檔」(
INVENT)現在會開新版INVENT_BS畫面(之前顯示
「無法建立ViewModel」無法進入)。
- 全客戶:程式內品號等超連結寫死
INVENT時,自動跳到該客戶選單實際登錄的變體
(
INVENT_BS/INVENT_PRIME)。變更
- 無既有可運作行為的變更;所有分流都只在原本會失敗(查無程式/無權限)時介入。
刪除
- 無
Breaking Changes
- 無
後續更新(2026-07-03)
- 公版庫存主檔
INVENT完成(ADR 0077)後,移除「朝陽 INVENT→INVENT_BS」的
CompanyOverrides 條目:選單登錄
INVENT的資料庫現在直接開公版畫面。CompanyOverrides 機制本身保留(空表),之後有真實分流需求再登錄。
Migration Notes
- 不需要任何資料庫變更。
- 朝陽如需
INVENT_BS的新版報表,_reportname類 keyed 資料需另行以新鍵登錄
(純新增,不影響 VFP)。
- 朝陽:選單「庫存主檔」(
-
07-02 invent-standard-base ▸
2026-07-02 庫存主檔公版化(INVENT 基底 + 客製衍生)
摘要
新增公版庫存主檔程式
INVENT(ADR 0077)。原禾久版INVENT_BS重構為公版的衍生類,功能與畫面完全不變。搭配程式分流(ADR 0075),超連結寫死
INVENT會自動導航到各客戶實際使用的版本。
新增
- 公版庫存主檔
INVENT(InventViewModel+Invent.xaml+InventSave)。
選單登錄
INVENT的資料庫(且無公司分流對照)現在會開公版畫面。變更
Invent_bsViewModel/Invent_bsSave改為公版的衍生類——對使用者零行為變更。
刪除
- 無
Breaking Changes
- 無
Migration Notes
- 不需要資料庫變更。
- 模擬環境要單獨開公版:dev-programs.json 註冊
INVENT(注意:注入後寫死
INVENT 的超連結會開公版而非客製變體)。
- 公版庫存主檔
-
07-02 flowcast-ux-improvements ▸
2026-07-02 — 金流預測 (flowcast) 畫面與口徑強化
摘要
金流預測第二輪打磨:頂端加 KPI 摘要卡、明細區改「金流明細/月彙總」雙分頁、圖表時間軸空月補零不再跳月、點柱過濾狀態可見可清除。
新增
- KPI 摘要列(畫面頂端五張卡):期間總流入/總流出/淨額/期末累計淨額/最低累計淨額(含發生月)。最低累計跌破資金警戒線(或警戒線 0 時為負)顯示紅字。
- 月彙總分頁:明細區改 TsTab 雙分頁,新增月彙總數字表(年月/應收/應付/當月淨額/累計淨額),累計淨額跌破警戒線的月份整列紅底。
- 點柱過濾狀態列:點圖表柱段後,明細分頁頂端顯示「過濾中:年月 × 來源收付(N 筆)」黃色標籤與 ✕ 清除鈕(原本只能再點同段或點空白取消,狀態不可見)。
- 明細 grid 補 原幣金額 欄(幣別旁,小數位走原幣設定);欄序改「預計現金日」在最前。
- 圖表 tooltip 補來源系列名(原本只有年月+金額,堆疊柱分不出哪層)。
新增(第二批,同日)
- X 軸粒度切換:來源勾選列加「X 軸:年月/日期」radio,日期模式逐日堆疊柱+逐日累計線(點柱過濾與期間彙總表同步以日為鍵)。空日一樣補零,跨度超過 3 年退回稀疏顯示。
- 累計淨額改掛右側副軸:原本與月柱共用左軸,累計量級大把柱壓扁(柱狀體太矮);現在柱用左軸、累計線與資金警戒線用右軸(圖例標示「累計淨額(右軸)」)。
變更
- 空月補零:
GroupByMonth/GroupByMonthStacked產出首月~末月連續月序列,無資料月份補 0 列(累計淨額沿用上月)。原本空月直接消失,柱狀圖時間軸跳月、累計線斜率失真。鍵解析失敗或跨度超過 50 年退回原稀疏序列。
- 摘要 KPI 抽成純函數
FlowcastComposer.Summarize(LogicBll),與月彙總同層可單元測試;FlowcastMonthPoco加跌破警戒旗標(查詢時依當時警戒線計算)。
刪除
- 無。
Breaking Changes
- 無(查詢口徑、SP、參數皆未動;純顯示層與彙總呈現)。
Migration Notes
- 無需 DB 動作。警戒線仍在查詢條件「資金警戒線」設定,查詢後才會反映到月彙總紅底與 KPI 紅字。
-
07-02 bom-purp-process-date-filter ▸
2026-07-02 產品用途表:工程代號查詢補生效區間過濾+成本表預設值修正
摘要
scx_eng_cy 查詢條件全面對比(六支查詢程式)發現的回歸修正。
變更
- 產品用途表(BOM_PURP)以「工程代號」查詢時,補回生效/失效日期過濾:只列「現行有效或未來生效」該工程的組件。VFP 於 2016/11/15 特別修過「工程失效也會出來」的問題,新版移植時用到修正前的舊 SQL,導致已失效工程的品號也被查出。(
Bom_purpBll.cs)
- 成本表(BOM_COST)
起始受訂日預設值補設為空字串:ResetToDefault()原漏設此欄(null),與其他欄位行為不一致。
Breaking Changes
- 無(行為回歸 VFP 正確口徑)。
Migration Notes
- 無 DB 變更。
- 產品用途表(BOM_PURP)以「工程代號」查詢時,補回生效/失效日期過濾:只列「現行有效或未來生效」該工程的組件。VFP 於 2016/11/15 特別修過「工程失效也會出來」的問題,新版移植時用到修正前的舊 SQL,導致已失效工程的品號也被查出。(
-
07-02 bom-hier-parity ▸
2026-07-02 階層式製程表(流程圖製程表)補齊 VFP 缺口
摘要
依 VFP
scx_eng_cy的bom_hier對比結果,把整併在「流程圖製程表」(BOM_FLOW)裡的階層式製程表能力補齊:查詢條件、明細欄位、主檔欄位與「只顯示工時」過濾。(ADR 0076)新增
- 查詢條件
- 查詢類別:
品號/客戶代號暨品號(後者可輸入起訖客戶代號,以客戶產品對照 cuinve 篩品號)- 生效日期:
本日/指定日期(BOM 生效區間以指定日為基準展開)- 工時別:
標準工時/改善前工時/改善後工時/備料工時(改善前/後與備料工時僅朝陽庫有資料,其他庫為 0)-
各層皆自數量1往下查詢:每層母件數量視為 1,明細數量=自身單位用量-
各層須增加原母件資料:每個展開節點前插一列母件自身(顯示序號後綴----)- 製程明細表/製程明細(樹狀) 新欄位:製程別、庫存量、包裝量_包、廠商代號1、廠商簡稱1、治具品號
- 左側查詢組件清單新欄位:品名、客戶品號
- 製程明細表「只顯示工時」勾選:只列製程列(VFP
SET FILTER TO '◇'$顯示品號對應)
變更
- 無既有行為變更:新條件預設值=原行為(本日、標準工時、兩個展開選項不勾)。
刪除
- 無。
Breaking Changes
- 無。
U_Bomflow其他呼叫端(報價單、營運預測、庫齡呆料、生產計劃)不受影響。
Migration Notes
- 無 DB 部署需求(
DARB_QRY_BOM_PROCES/DARB_GETDATA4皆已登錄 proc_param)。
- 尚未移植(後續另案):VFP bom_hier 的「自訂查詢」條件產生器、報表選擇 5 種列印(BOM_H1 產品組件表/BOM_H2 標準工時表×3/BOM_H4 治工具管制表)與治工具管制表 Excel 匯出。
-
07-02 bom-flow-diagram-and-tree-enhancements ▸
2026-07-02 — 流程圖製程表:圖形排版改水平左上、樹狀分頁補按鈕、新增需求數量重算
摘要
D-110 流程圖製程表(Bom_flow)四項強化:流程圖圖形預設改為水平排列(根節點在左上角、先明細後製程、往右下角展開)、製程明細(樹狀)補「展開全部/收攏全部」、新增「需求數量+重新計算」、樹狀根節點補數量/單位並讓製程列顯示名稱。新增
- 需求數量重算:製程明細(樹狀)分頁下方新增
需求數量輸入欄與重新計算按鈕。輸入需求數量後按下,整棵樹的數量(明細 = 父數量 × 單位用量)與標準工時(製程 = 數量 × 單位標工時)即時重算,製程明細表、多階材料用量清單、流程圖、流程圖圖形同步更新;純記憶體計算,不重新查詢資料庫。切換查詢組件時輸入欄會帶回該組件目前的根數量。
- 樹狀分頁按鈕:製程明細(樹狀)分頁下方新增
展開全部/收攏全部按鈕(原本只有製程明細表有)。
變更
- 流程圖圖形預設水平排列:開啟即水平(原預設垂直)。根節點固定在左上角,每條鏈沿明細往右直走、製程與其他分支往下換列,整張圖往右下角延伸——與「流程圖」表格分頁(VFP 原版)的閱讀順序一致。
垂直排列按鈕行為不變。
- 圖形同層順序:展開子節點時先放明細(物料)再放製程;同組內仍照顯示序號。
- 圖形根節點:補顯示數量+單位(第 3 行),品名缺漏時改從查詢結果帶入。
- 樹狀根節點:第一個組件(查詢組件自己)改用查詢結果的層數 0 那筆,因此數量、單位、生效日期等欄位都有值(原本是合成節點,數量/單位空白)。
- 樹狀品號欄:改綁
樹狀顯示品號——去掉縮排與 ▼/▲ 三角形、保留 ◎/◇ 前綴;製程列因此顯示 ◇+工程簡稱(有名稱),不再只有工程代號。
- 製程品名顯示代號+名稱:樹狀分頁品名欄與流程圖圖形的製程節點第 2 行改顯示「工程代號+工程說明」(說明缺漏時退回工程簡稱),代號跟名稱一眼可見。
- 圖形連線改直角折線:連線改 Polyline+自動路由(OrgTreeRouter 依排列方向轉折),不再畫斜線。
- 圖形雙擊不再縮放:拿掉 RadDiagram 內建「雙擊畫布重設 100% 縮放」行為,避免看圖時誤觸突然縮小。
- 隱藏背景格線:畫布背景格子改為不顯示,並在畫板外加一圈框線、自動縮放四周留 30px 邊界。
刪除
- 無。
Breaking Changes
- 無。資料庫、報表、參數皆未變動。
Migration Notes
- 無需任何佈署動作。多語系新增鍵:
展開全部、收攏全部、需求數量、重新計算(Common/Lang/Xaml/Bom_flow.json)。
- 需求數量重算只影響畫面上的顯示值,不寫回任何資料表。
- 需求數量重算:製程明細(樹狀)分頁下方新增
-
07-01 ESTSAL-union-length-fix ▸
2026-07-01 ESTSAL 兩庫欄位聯集同步(長度補齊 + 年預估分類/分類 鏡射)
摘要
依
/dual-db-union-sync ESTSAL比對鈞寶darbnogicsa1與朝陽darbcycsa1兩庫的estsalm(主表,無 view)、estsald/vw_estsald(子表 + view)欄位聯集。結論:Model / Source 的欄位聯集在先前 CY 對比時已補齊(
EstsalmModel、EstsalmSource、Twork_ord_vw_estsaldModel、Twork_ord_vw_estsaldSource皆含兩庫聯集欄)。本次做兩件事:(1) 修正兩個
TsStringLength未取聯集上限、可能截斷 CY 值的問題;(2) 對照 VFP
scx_ord(NOGI)與scx_ord_cy(CY)原始碼確認年預估分類(int) 與分類(char) 是同一「年預估分類」欄的兩庫不同存法(同標籤、同 InputMask 9999),改以「設一欄、鏡射填兩欄」串接共用 UI。
比對結果
物件 NOGI CY 處理 base estsalm10 欄 13 欄 聯集 14 欄,Model/Source 早已齊全 base estsald8 欄 8 欄 相同,Model 無變更 view vw_estsald+品名 +品名/停用/停用說明/停用日期/管制說明 Source 私有欄位早已承接 (主表
estsalm無編輯 view;年預估分類(NOGI int) 與分類(CY char) 名稱不同,聯集各留一欄。)變更
Model/Source/E.Order/EstsalmSource.cs:審核人員TsStringLength(10)→(20)
(NOGI
nvarchar(10)/ CYnvarchar(20),取聯集上限避免截斷 CY 審核人員)。Model/Source/E.Order/Twork_ord_vw_estsaldSource.cs:品名TsStringLength(120)→(200)
(view 顯示欄,NOGI
nvarchar(120)/ CYnvarchar(200),取聯集上限)。Model/Source/E.Order/EstsalmSource.cs:年預估分類(int) 與分類(char(1)) 兩個 setter 互為鏡射
(直接寫對方 Model 欄避免遞迴)。編輯共用 UI 欄或任一庫載入時,兩欄恆同步:
- 設
年預估分類 = N→分類 = N.ToString()(N=0 時清空)。- 設
分類 = s(CY 載入僅回傳此欄)→年預估分類 = int.TryParse(s),讓 UI 顯示與EstsalSave的「年預估分類 != 0」必填檢查對兩庫皆成立。ViewModel/E.Order/EstsalViewModel.cs:AfterAddNew新增預設年預估分類 = 1
(對應 CY VFP
REPLACE 分類 WITH '1'=1.銷售,經鏡射同步填 CY分類)。VFP 對照依據
面向 NOGI scx_ord(int 年預估分類)CY scx_ord_cy(char 分類)綁定欄 年預估分類分類標籤 / InputMask 年預估分類 / 9999年預估分類 / 9999addagain 預設 無 REPLACE 分類 WITH '1'(銷售)allowsave 必填 Empty(年預估分類)EMPTY(分類)參與 單號 組成 註解掉(若啟用取 LEFT(年預估分類,1))年度+分類+版次+客廠部代號(OPMODE 1/8)刪除 / Breaking Changes
無欄位移除。行為變更:NOGI 新增單據時
年預估分類現預設為 1(VFP NOGI 原留空由使用者輸入);因
EstsalSave本就要求非 0,使用者仍會確認/改值,實務影響小。尚未承接(後續另案,非本次範圍)
CY VFP 由
分類等欄自動組單號(年度+分類+版次+客廠部代號)與「上版鈕」載入前版;現行 C#
EstsalSave仍將單號視為使用者輸入(is_noduplicate),CY 的 單號 自動組成尚未移植。Migration Notes
本機 SQLite 由
EnsureCreated/ LocalDbService 補欄安全網自動處理,無需手動 migration。屬 ADR 0050(多客戶差異處理)既有決策的延伸,不新開 ADR。
-
07-01 CI-union-sync ▸
2026-07-01 CI 兩庫欄位聯集同步
摘要
依
/dual-db-union-sync CI比對鈞寶darbnogicsa1與朝陽darbcycsa1兩庫的ci_m/vw_ci_m(主表 + view)、ci_d(子表,無 view)欄位聯集。live 類別為
Twork_ord_vw_ci_mSource/Twork_ord_vw_ci_dSource(CiViewModel+CiSave使用)與其 Model
Twork_ord_vw_ci_mModel/Twork_ord_vw_ci_dModel。本次僅新增兩庫聯集缺漏欄,未動既有欄位。比對結果
物件 NOGI CY 處理 base ci_m27 27 差 1:NOGI 有 稅別(已在 Model)、CY 有是否si→ 補是否siview vw_ci_m31 31 view-only JOIN 欄( 客戶簡稱/出貨港口/目的港口/運送方式)兩庫皆有、Source 已承接base ci_d19 21 NOGI 有 其他金額(已在 Model);CY 多訂單pkid/預訂交期/合約號碼→ 補 3 欄變更(新增欄,皆兩庫聯集)
Common/Model/E.Order/Twork_ord_vw_ci_mModel.cs、Model/Source/E.Order/Twork_ord_vw_ci_mSource.cs:
-
是否si(CYci_mchar(1))— string,[TsStringLength(1)]。Common/Model/E.Order/Twork_ord_vw_ci_dModel.cs、Model/Source/E.Order/Twork_ord_vw_ci_dSource.cs:
-
訂單pkid(CYci_dint)。-
預訂交期(CYci_dchar(10))— string,[TsStringLength(10)]。-
合約號碼(CYci_dnvarchar(20))— string,[TsStringLength(20)]。NOGI 無上述欄,上傳時 OPENXML 依 ADR 0050 取交集自動略過;CY 現可持久化這些欄。
後續清理(同批完成)
- view-only 欄搬入 Source 私有欄位:
客戶簡稱/出貨港口/目的港口/運送方式從Twork_ord_vw_ci_mModel
移除(含 ctor init 與
[XmlAttribute()]屬性),改由Twork_ord_vw_ci_mSource以私有欄位承接,使 Model 純對應 base
ci_m、GetModelBase不再序列化這 4 個 JOIN 唯讀欄。稅別(NOGI base 欄)保留於 Model。- 刪除重複死碼對:
Common/Model/Ci_mModel.cs、Common/Model/Ci_dModel.cs、
Model/Source/E.Order/Ci_mSource.cs、Model/Source/E.Order/Ci_dSource.cs—— 經全 repo(.cs/.xaml)確認無任何 ViewModel/BLL/DataManager 註冊或反射引用,整組移除。
刻意未動(超出本次聯集範圍,另記備查)
- EDI/856-810 欄組:
ci_m的出貨ID/名稱/地址…請款…/trno/blno/scac/carrier/shipdate/estdate/create856/create810/receiveid/TaxCode/出通單PKID、
ci_d的PILinePkid/SalesOrderLinePkid/reqno—— 皆不在 NOGI/CY 兩庫ci_m/ci_d,屬第三變體(EDI)欄,保留。- 型別/精度既有差異:
公司代碼C#shortvs DBint、匯率[TsDecimalLength(19,6)]vs DBnumeric(14,4)、
產品描述別len 10 vs DB 4 —— 皆放大或無害,保留不動。刪除 / Breaking Changes
無欄位移除、無行為變更。純新增聯集欄。
Migration Notes
本機 SQLite 由
EnsureCreated/ LocalDbService 補欄安全網自動處理,無需手動 migration。屬 ADR 0050(多客戶差異處理)既有決策的延伸,不新開 ADR。
📅 2026 年 6 月 (148 篇)
-
06-30 radgridview-header-corner-autofit ▸
2026-06-30 RadGridView 表頭左上角雙擊自動調整欄寬
摘要
TsRadGridView(全 app 共用表格控件)新增一個隱形的快捷操作:在表頭左上角那一格(row indicator 上方的空白角落)點兩下,即把所有欄位寬度設成 Auto、依內容自動調整。等同原本右鍵表頭 →「自動調整欄寬」,但不必開選單。依使用者裁定採「隱形」作法:左上角不放可見按鈕,只在滑鼠移上去時變手型游標並顯示 tooltip「點兩下自動調整欄寬」提示。
新增
TsControl/TsTelerik/TsRadGridView.cs:
- 在
Loaded掛勾表頭列(GridViewHeaderRow)的左上角PART_IndicatorPresenterBorder,加雙擊 → 自動調整欄寬;同時設Cursor=Hand與 tooltip。- 表頭列可能晚於 Loaded 才實體化,找不到角落時延後重試一次。
變更
- 抽出共用方法
AutoFitAllColumns();右鍵選單「自動調整欄寬」與左上角雙擊共用同一實作。
影響範圍
全 app 所有
TsRadGridView。瀏覽/查詢/明細表格皆適用。使用方式
- 表頭左上角空白格 → 點兩下:所有欄寬依內容自動調整。
- 仍保留原入口:表頭右鍵 →「自動調整欄寬」。
Breaking Changes
無。單擊左上角、或雙擊其他表頭格的既有行為(排序)不受影響。
Migration Notes
需重建 TsERP 才會生效(改動在 TsControl 共用控件)。
-
06-30 ORMAST-union-sync ▸
ORMAST 兩庫欄位聯集同步(darbnogicsa1 ∪ darbcycsa1)
摘要
依
_sheetno查得 ORMAST 主表ormast/vw_ormast、子表1ordetl/vw_ordetl,比對鈞寶(
darbnogicsa1)與朝陽(darbcycsa1)兩庫的 base table 與 view 欄位,取聯集後同步回程式:base table 聯集進 Model、view JOIN 唯讀欄進 Source 私有欄位。
屬 ADR 0050(多客戶差異處理)的延伸,未新開 ADR。
比對結果
物件 NOGI CY 差異 處理 base ormast40 36 CY 多 流程樣板號;NOGI 多訂單類別碼/集團代號/聯絡人/報價單號/叫修單號Model 補 流程樣板號(其餘 NOGI 欄早已在 Model)view vw_ormast48 45 CY 多 JOIN 欄 leadtimes/leadtimet(+流程樣板號)Source 補 leadtimes/leadtimet私有欄位base ordetl59 49 CY 多 預示資料/預示比對/比對說明1/比對說明2/回覆Model 補這 5 欄 view vw_ordetl69 57 CY 多 JOIN 欄 停用/停用日期/預訂完工日(+上述 5 base 欄)Source 補 5 base 欄(委派 Model)+ 停用/停用日期/預訂完工日私有欄位(稽核/系統欄
輸入日期/輸入人員/輸入地點/增刪修/選擇/管制碼/srvdbid/pkid/logid/linkid不列入比對。)新增
Common/Model/E.Order/Twork_ord_vw_ormastModel.cs流程樣板號(string,nvarchar(20),CY-only base 欄)
Model/Source/E.Order/Twork_ord_vw_ormastSource.cs流程樣板號(委派 Model,base 欄)
leadtimes、leadtimet(int,view JOIN 唯讀欄 → Source 私有欄位,不上傳)
Common/Model/E.Order/Twork_ord_vw_ordetlModel.cs預示資料(250)、預示比對(150)、比對說明1(150)、比對說明2(150)、回覆(250)(皆 CY-only base 欄)
Model/Source/E.Order/Twork_ord_vw_ordetlSource.cs預示資料、預示比對、比對說明1、比對說明2、回覆(委派 Model,base 欄)
停用(char(1))、停用日期(varchar(10))、預訂完工日(nvarchar(10))(view JOIN 唯讀欄 → Source 私有欄位,不上傳)
變更
無既有欄位行為變更。
vw_ordetl的品名早已由 Source 私有欄位_SKUDescription承接(符合 view-only 規範),不需調整。刪除
無。本次為純加法聯集;舊 Model 既存的 view JOIN 欄(如
客戶簡稱/姓名/中文描述等)未搬離 Model,因使用者本次未要求 Model 嚴格對應 base table。
Breaking Changes
無。
Migration Notes
- 本機 SQLite 由
EnsureCreated重建即帶新欄;缺欄走 LocalDbService 補欄安全網,無需手動 migration。
- 伺服器上傳沿用 ADR 0050 的 OPENXML 自動取交集,目標庫缺的 base 欄(如 NOGI 沒有
流程樣板號、預示資料等)會被自動略過,不影響存檔。
- view JOIN 唯讀欄走 Source 私有欄位、不在
GetModelBase()序列化,本就不會上傳。
-
06-30 customdash-sqlite-temptable-isolation ▸
2026-06-30 自訂查詢面板 SQLite 暫存表真正隔離(TempTableScope)
摘要
補上 CUSTOMDASH(ADR 0068)的 SQLite 盲區:同一支「SQLite 虛擬化型」查詢被寄生多份時,原本共用 per-ProgramClass/固定名的暫存表而互相 DROP/覆蓋。改以
IAppContext.TempTableScope統一隔離,每塊 tile 各自一張表。新增
Common/TempTableNaming.cs:共用後綴 helperApply(scope, table)(scope 空=原樣回傳)。
IAppContext.TempTableScope(+AppContext實作、CreateChildContext沿用)。
SQLiteForBrowse.DropScopedTables():tile 釋放時清掉本後綴的孤兒暫存表。
變更
SQLiteForBrowse:表名T()與清理改讀Context.TempTableScope(取代過渡期的私有 BrowseScope)。
InvpivotBll("invpivot")、Abook1Bll("abook1"):暫存表名帶TempTableScope後綴(寫讀同名)。
ProgramNavigator:寄生查詢時對該 tile 的 scoped context 設唯一TempTableScope。
- 3 個測試
IAppContext實作補TempTableScopestub。
刪除
無。
Breaking Changes
無。
TempTableScope=null(所有正常程式)時表名完全不變、行為零影響——只有 CUSTOMDASH 寄生實例會帶後綴。Migration Notes
- 經全專案掃描確認:
ExportToSqlite(~250 處)皆報表/列印、CreatePivotDateInSqlite皆樞紐 Excel、PurchQuerygrid 為記憶體型——皆非 grid 暫存表,不需隔離。grid 虛擬化只有兩條路(BrowseProvider→SQLiteForBrowse、SQLiteProvider<T>),都已涵蓋。
SQLiteProvider<T>不需改(接收的是已帶後綴的最終表名)。
- 範圍外同型 pattern:
Splace/Gsplace也用SQLiteProvider<T>固定表,但為主檔編輯表單(非查詢程式),CUSTOMDASH 不 host,未處理。
- runtime 僅模擬環境手動驗(INVPIVOT 同支多開)。
-
06-30 customdash-query-all-on-button ▸
2026-06-30 自訂查詢面板改回「按查詢一次全查」
摘要
CUSTOMDASH 原本是「切到分頁才查、每次切到重查」(ADR 0068 option a),用意是避開 SQLite 虛擬化型查詢共用暫存表被覆蓋。
TempTableScope上線讓每塊 tile 暫存表真正隔離後,重查的理由消失——改回使用者偏好的「按查詢按鈕=一次把每塊 tile 都查好」,之後切分頁只顯示既有結果、不重查。變更
CustomdashViewModel:
-
Query()建好 tiles 後呼叫新的全部查詢Async,直接驅動每塊寄生 VM 的Query()(背景緒)+UIUpdate()(UI 緒)一次全查。直呼 VM 而非走QueryButton,因 TabControl 虛擬化、非當前分頁的 View 沒掛ErrorCheckable,走QueryExecute會 NRE。-
SelectedTilesetter 不再觸發查詢(只更新選取)。刪除
切換查詢Async/自動查(lazy 切到就重查)。
CustomdashTileViewModel.查詢中(重入旗標,已不需要)。
Breaking Changes
無。
Migration Notes
- 依賴
TempTableScope暫存表隔離(2026-06-30 temptable changelog)才安全全查;該隔離不可回退。
- runtime 僅模擬環境手動驗。
-
06-30 customdash-parallel-query-per-tile-sqlite ▸
2026-06-30 自訂查詢面板:多支查詢改並行(per-tile 獨立 SQLite 檔)
摘要
CUSTOMDASH 按「查詢」原本一支查完才查下一支(序列)。改成限流並行:每塊 tile 各自一個實體 SQLite 暫存檔,SQL Server 查詢重疊、SQLite 寫入零鎖競爭。清單多支時明顯變快。詳見 ADR 0070。
變更
CustomdashViewModel.全部查詢Async:foreach … await序列 →SemaphoreSlim(4)限流 +Task.WhenAll並行。各塊查完才解除自己的「查詢中…」轉圈。
SQLiteCreatorFactory.GetTempDb:TempTableScope非空時把它接成UserDirectory子資料夾當快取 key/檔案路徑 → 每塊 tile 一個EnvironmentSettingDB.db。正常程式(scope 為空)行為完全不變。
- tile
Dispose:改成刪整個 per-tile 子資料夾 + 淘汰工廠快取項(取代逐表DropScopedTables)。
新增
ISQLiteCreatorFactory.RemoveTempDb(IAppContext):淘汰 per-tile 暫存 DB 快取項,避免 singleton cache 隨每次查詢堆積。
刪除
無。
Breaking Changes
無。
TempTableScope=null(所有正常程式)時暫存 DB 的 key/路徑/表名完全不變——只有 CUSTOMDASH 寄生 tile 會分檔。Migration Notes
- 並行前提:寄生查詢 VM 的
Query()須 scope 自足(無 static/跨 VM 共享可變狀態)。
- runtime 僅模擬環境手動驗(多支同頁並行)。
-
06-30 customdash-merge-print-pdf ▸
2026-06-30 自訂查詢面板:彙整列印(多查詢報表合併成單一 PDF)
摘要
CUSTOMDASH 自訂查詢面板頂端新增「彙整列印 (PDF)」按鈕:把清單裡的多支查詢各挑一張報表,合併成一份 PDF 預覽(預覽視窗內建「匯出PDF」即另存)。詳見 ADR 0071。
新增
- 面板頂端工具列「彙整列印 (PDF)」按鈕。
CustomdashPrintSelectViewModel+自訂查詢彙整列印選擇.xaml(ProgramClass.CUSTOMDASHPRINT):逐查詢勾選+報表下拉的選擇彈窗,無報表的查詢自動 disable。
PrintHelper.PrepareMergedReport(...):多支報表Load+Prepare(append)合併成一份 FastReport Report。
IContentWindowService.ReportPreviewPrepared(report):預覽「已 Prepare」的報表(不 re-Prepare,避免洗掉合併頁)。
CustomdashTileViewModel.ScopeContext:暴露 tile 的 scoped context,供 browse 型報表從 per-tile 暫存檔匯出資料。
變更
TsFastReportPreview建構子加alreadyPrepared旗標(預設 false,既有呼叫零影響)。
- 選擇彈窗改用
TsCheckBox/TsComboBox(原CheckBox/ComboBox);移除說明文字的顏色覆寫。
修正
PrintHelper.ExportDataToSqlitebrowse 路徑:原本用rpt.BrowseTables[i](server 不帶後綴表名)直接讀暫存 DB,但寄生查詢(TempTableScope 非空)的暫存表是帶後綴建的 → 讀到不存在的表 → 合併列印每筆都失敗、跳「沒有可列印的報表資料」。改成讀取/複製來源套TempTableNaming.Apply(TempTableScope, …)(目的表維持乾淨名)。正常程式 scope 為空=原樣,零影響。
- 註記:browse 報表沿用既有慣例,只輸出 grid 中已勾選的列(
CopyBrowseToOtherSqlite以SysIsSelected='Y'過濾)。彙整列印前請先在各查詢結果勾選要印的列。
刪除
無。
Breaking Changes
無。
Migration Notes
- 合併與匯出全走既有 FastReport,無新相依、不動 DB。
- runtime 僅模擬環境手動驗(多查詢挑報表→合併→預覽→匯出PDF)。
- 跨範本
Prepare(append)若 runtime 出現版面/資料問題,備案為改用 Telerik PdfProcessing 合併(見 ADR 0071)。
-
06-30 customdash-hosted-scope-session-inheritance ▸
2026-06-30 自訂查詢面板寄生 scope 繼承登入 session(修查詢 DataSourceRouter NRE)
摘要
CUSTOMDASH 按查詢時
Sql.SetLogSysExecCommand讀_context.DataSourceRouter.DbType拋 NullReferenceException。原因:寄生 tile 用的新 DI scope 取得的是全新未初始化AppContext,DataSourceRouter/User/EnvironmentSetting等登入時手動塞的 session 欄位都是空的。改為新 scope 主動繼承主 context 的 session 狀態。詳見 ADR 0069。新增
AppContext.InheritSessionFrom(IAppContext parent):把 parent 的 session 級服務(DataSourceRouter/User/EnvironmentSetting/LanguageService/MessageService等)灌進本實例;刻意不沿用SQLiteForBrowse/TempTableScope(維持每塊 tile 暫存表隔離)。
ProgramNavigator.CreateHostedScope()(private):統一「建 scope → 繼承 session → 設唯一TempTableScope」。
變更
ProgramNavigator三條寄生路徑改用CreateHostedScope():CreateHostedQueryProgram、CreateHostedContent、GetProgramDefaultParameter。scope 在建 vm 之前先初始化,確保 vm 與其注入的 Sql/BLL 拿到已填好的 context。
刪除
無。
Breaking Changes
無。只有 CUSTOMDASH 寄生路徑會走
CreateHostedScope;正常程式不開新 scope、不受影響。Migration Notes
- 暫存表隔離(ADR 0068 / 2026-06-30 TempTableScope changelog)不受影響:
SQLiteForBrowse與TempTableScope仍 scope-local。
- runtime 僅模擬環境手動驗(CUSTOMDASH 選查詢程式後按查詢)。
-
06-30 customdash-hosted-query-panel ▸
2026-06-30 自訂查詢面板(CUSTOMDASH,spike)
摘要
新增實驗性「自訂查詢面板」(ProgramClass
CUSTOMDASH,放 M.主管資訊):在下方查詢區選多支既有查詢程式、用各程式自己的中文條件畫面設條件、加入清單,按查詢後上方以 TsTab 分頁並列各查詢的原生結果表格。仍為 spike(未做存配置/拖拉版面)。新增
- 自訂查詢面板頁面:
- 查詢區:查詢型程式下拉(只列查詢型)→ 選了直接顯示該程式原生中文條件畫面 → 「加入清單」累積成查詢清單(可移除/清空)。
- 結果區:每支查詢一個 TsTab 分頁(標題=程式名稱),分頁內容=該程式原生 grid。
- 切到分頁就重查:只實體化當前分頁(省記憶體),每次切到用自己的條件重跑。
- 寄生工廠(
ProgramNavigator):CreateHostedQueryProgram/CreateHostedContent/GetHostableQueryPrograms/GetProgramDefaultParameter——以反射建出查詢程式 VM 並包成 layout 寄生,不進導覽快取。
- dev-programs.json 加
CUSTOMDASH(M-D3);App.xaml 2 個 DataTemplate;DI 註冊CustomdashConditionViewModel。
變更
- 條件不再以 JSON 編輯,改用各程式原生條件畫面(全中文)。內部仍以英文屬性名 JSON 儲存(使用者看不到),查詢時
PopulateObject灌回。
- 每塊分頁各自一個 DI scope → 參數隔離(同支多開、與正常開的同支互不干擾)。
刪除
無。
Breaking Changes
無(純新增)。
Migration Notes
- 開發機:
dev-programs.json已含CUSTOMDASH,啟用DevPrograms重新登入即見。正式環境需usp_新增程式登錄(尚未產 SQL,spike 階段)。
- 已知限制:SQLite 虛擬化型查詢的 per-ProgramClass 暫存表為共用資源,DI scope 隔離不到;靠「切到就重查」在循序檢視下顯示正確,快速來回切/與正常程式並跑仍可能撞表。真正隔離需 StagingScope(ADR 0043),未做。
- runtime 僅模擬環境手動驗。
-
06-30 CUQT-union-sync ▸
CUQT 兩庫欄位聯集同步(darbnogicsa1 ∪ darbcycsa1)
摘要
依
_sheetno查得 CUQT(客戶報價單)主表cuqtm/vw_cuqtm、子表1cuqtd1/vw_cuqtd1、子表2cuqtd2(無 view)。比對鈞寶(
darbnogicsa1)與朝陽(darbcycsa1)兩庫 base table 與 view 欄位,取聯集後同步回程式。屬 ADR 0050(多客戶差異處理)的延伸,未新開 ADR。
⚠️ 類別命名對應(TableMap.json)
CUQT 子表類別名稱與實體表有刻意的位移,務必對照
TsERP/Lang/TableMap.json:實體表 中文 對應類別 cuqtm報價主檔 Twork_ord_vw_cuqtmcuqtd1材料明細 Twork_ord_vw_cuqtd(無數字)cuqtd2加工明細 Twork_ord_vw_cuqtd1(帶 1)比對結果
物件 NOGI CY 差異 處理 base cuqtm49 39 CY 多 單品報價別/美元匯率/日圓匯率/模費轉訂單;NOGI 多報價類別/序號前置碼/報價人員/有效期限/最低訂單量/圖檔名稱/模穴數/材質/生產機器/注意事項/模具摘要/聯絡單id/工作流程/已審核Model+Source 補 4 個 CY-only 欄(NOGI 欄早已齊全) view vw_cuqtm52 42 view-only JOIN 客戶簡稱/說明/廠商簡稱(兩庫相同,皆已存在)無新增 base cuqtd1(材料明細,類別cuqtd)20 25 CY 多 原始品號/淨數量/材料費/加工費/殘料量/殘料單價;NOGI 多損耗率Model+Source 補 6 個 CY-only 欄 view vw_cuqtd121 26 view-only JOIN 廠商簡稱(兩庫相同,已存在)無新增 base cuqtd2(加工明細,類別cuqtd1)14 13 CY 多 費率_分/裸價模具費/模具費;NOGI 多費率/裸價治具費/治具費/參考加工費Model+Source 補 3 個 CY-only 欄;無 view (稽核/系統欄
輸入日期/輸入人員/輸入地點/增刪修/選擇/管制碼/srvdbid/pkid/logid/linkid不列入比對。)新增
Twork_ord_vw_cuqtmModel/Twork_ord_vw_cuqtmSource(報價主檔)單品報價別(char(1))、美元匯率(numeric(12,4))、日圓匯率(numeric(12,4))、模費轉訂單(char(1))
Twork_ord_vw_cuqtdModel/Twork_ord_vw_cuqtdSource(材料明細,實體cuqtd1)原始品號(nvarchar(30))、淨數量(numeric(15,4))、材料費(numeric(16,6))、加工費(numeric(16,6))、殘料量(numeric(11,5))、殘料單價(numeric(16,6))
Twork_ord_vw_cuqtd1Model/Twork_ord_vw_cuqtd1Source(加工明細,實體cuqtd2)費率_分(money(19,4))、裸價模具費(int)、模具費(int)
全部為 base table 聯集欄、Source 委派 Model。本次無新增 view-only JOIN 欄(
客戶簡稱/說明/廠商簡稱/廠商簡稱/品名早已存在)。變更
無既有欄位行為變更。
刪除
無。純加法聯集;舊 Model 既存的 view JOIN 欄(
客戶簡稱/說明/廠商簡稱)未搬離 Model,因本次未要求 Model 嚴格對應 base table。已知缺口(非本次處理)
- 實體
cuqtd2(加工明細)在_sheetno列為子表2,無對應 view,且新系統的Twork_ord_vw_cuqtd1類別已承接其欄位(命名位移,見上表)。_sheetno的「子表2cuqtd2」本身沒有獨立的Twork_ord_vw_cuqtd2類別——這是既有架構(cuqtd1↔cuqtd、cuqtd2↔cuqtd1),非缺漏。
Breaking Changes
無。
Migration Notes
- 本機 SQLite 由
EnsureCreated重建即帶新欄;缺欄走 LocalDbService 補欄安全網,無需手動 migration。
- 伺服器上傳沿用 ADR 0050 的 OPENXML 自動取交集,目標庫缺的 base 欄(如 NOGI 沒有
美元匯率、CY 沒有損耗率/參考加工費等)會被自動略過,不影響存檔。
- view JOIN 唯讀欄走 Model 既有欄位承接(本案未新增),不影響上傳。
-
06-30 CUQT-cy-cost-model ▸
CUQT 客戶報價單 — CY(朝陽/鈞寶) 成本模型還原
摘要
繼 CUQT 兩庫欄位聯集同步(commit d96e609c)補齊 DB 欄位後,本次把 CY 版客戶報價單的成本計算與 UI 還原到 VFP
scx_ord_cy/cuqt的口徑。對比報告指出新版整支原本照 NOGI 做,導致 CY 客戶的加工費、模具/治具分攤費會算成 0 或錯值。屬 ADR 0050(多客戶差異處理)的延伸,未新開 ADR。決策:依使用者裁示,本表單顯示直接切成 CY 版(不做 prgsct1 gating),計算邏輯仍以
CompanyShortName(朝陽/鈞寶)分支以保非 CY 路徑安全。新增(UI 欄位)
主檔(
Cuqt.xaml)模具組數、治具組數:CY 模具分攤費的兩個獨立分母(VFP cuqt_cy 行1926-1927)。
材料明細 grid
淨數量、材料費、加工費、殘料量、殘料單價:CY 專屬成本拆解欄(純輸入/顯示,無自動計算)。
加工明細 grid(改為 CY 版)
- 新增
費率(分)(費率_分)、裸價模具費、模具費;移除 NOGI 專屬的費率、裸價治具費、治具費、參考加工費顯示。
變更(計算邏輯)
- 加工金額:CY 改用
次數 × 加工時間 × 費率_分(VFP 行1916/1984);非 CY 維持費率。Twork_ord_vw_cuqtd1Source.Get加工金額()依CompanyShortName分支,新增費率_分Binding觸發重算。
- 主檔治具價格:CY 彙總加工明細的
模具費欄(VFP 行1916),非 NOGI 的治具費。CuqtViewModel.Sum()。
- 族群寫回:VFP 行1929-1941 —
單品報價別='1'(族群) 時不把彙總寫回主檔;其餘才寫回。CuqtViewModel.Sum()以if (單品報價別 != "1")包住主檔寫回。
- 連動重算:master listener 加入
模具組數/治具組數;detail1 listener 加入模具費,使 CY 欄編輯即時觸發Sum()。
- 單價連動(業務新規則,VFP 無此邏輯):材料明細
材料費/加工費異動 →單價 = 材料費 + 加工費,經既有單價Binding連帶重算材料金額(=數量×單價) 與單價百分比,再觸發主檔Sum()。單價仍維持可手動覆寫。Twork_ord_vw_cuqtdSource新增材料費Binding/加工費Binding。
- 百分比顯示(先前 commit c7cdb602):
單價百分比/加工時間百分比補*100。
刪除
加工明細 grid 不再顯示 NOGI 的
費率/裸價治具費/治具費/參考加工費欄(屬性仍保留於 Source/Model,僅移除 UI)。Breaking Changes
本表單顯示改為 CY 版:非 CY(朝陽/鈞寶) 部署的加工明細將看不到
費率/治具費輸入欄。計算分支雖保留非 CY 路徑,但 UI 已不支援非 CY 輸入。實際部署客戶皆為 CY,影響為零。待確認 / 後續
原始品號(材料明細)VFP 無對應 grid 欄,未露出。
Migration Notes
- 純程式變更,無 DB migration(欄位已於 d96e609c 補齊)。
- 本機 SQLite 由
EnsureCreated重建即帶新欄。
驗收條件
1. CY:填 次數/加工時間/費率_分 → 加工金額 = 次數×加工時間×費率_分;加工費彙總正確。
2. CY:加工明細模具費 → 主檔治具價格正確;治具組數>0 → 模具分攤費含治具分攤。
3. CY:模具組數>0 → 模具分攤費含模具分攤。
4. 報價金額 = 材料費+材料利益+加工費+加工利益+包裝費+運費+關稅+模具分攤費。
5. 單品報價別='1'(族群) 時主檔彙總欄不被明細覆蓋。
6. 材料明細輸入材料費/加工費 → 單價自動=材料費+加工費、材料金額=數量×單價隨之更新;單價仍可手動改。
-
06-29 tssearchtextbox-v1-validation-fix ▸
2026-06-29 — 修復 V1 `TsSearchTextBox` 存在性驗證形同虛設
摘要
修正舊版(V1)
TsSearchTextBox搜尋欄輸入不存在的代號卻不會跳錯的問題。根因:
OnApplyTemplate建好了帶TsSearchRule(資料存在性)/PrimaryKeyRule(主鍵)驗證規則的 binding,卻漏呼叫
BindingOperations.SetBinding套回控件,導致規則建好即丟棄、實際 binding 沒有任何驗證。新版
TsSearchTextBoxV2早已修掉此問題(且留有註解),V1 一直沒同步。本次把 V1 對齊 V2。
變更
TsControl/TextBox/TsSearchTextBox.cs:OnApplyTemplate在加完驗證規則後,
以
ruleAdded旗標守護並呼叫BindingOperations.SetBinding(this, TextBox.TextProperty, newBinding)把帶規則的 binding 套回(與
TsSearchTextBoxV2寫法一致)。影響範圍(Breaking-ish 行為變更)
- 所有 使用 V1
TsSearchTextBox且CheckDataExist=true(預設)的欄位,
自即日起會在失焦時驗證代號是否存在於
ExistTable:- 查無 → 嗶聲 + 跳「資料不存在」訊息框 + 紅框,且存檔會被擋。
-
IsPrimaryKey=true的欄位同步啟用主鍵驗證。- 這是還原本來就該有的行為(屬性預設值即
CheckDataExist=true),
但等於讓多支沿用 V1 的表單「突然開始擋」以前默默吃下的亂輸入。
- 觸發本次調查的案例:
Eventproject.xaml的「負責人」(EmployeeSearchstyle,
查
perdata.員工編號)以前亂打不擋,現會擋。注意事項
- 若有欄位本來就允許自由輸入(非主檔代號)卻沒顯式設
CheckDataExist="False",
修正後會被誤擋——請改設
CheckDataExist="False"。建議回歸時重點測 V1 搜尋欄較多的表單。DeepCopyBinding已完整複製Mode/UpdateSourceTrigger/ValidatesOnExceptions/
NotifyOnValidationError等屬性,重新套 binding 不會掉設定。- TsControl 專案已用 VS MSBuild 建置通過(僅既有無關警告)。
-
06-29 safetystock-mailqueue ▸
2026-06-29 安全庫存自動檢查補寄信(TWORK_AUTO_SAFETYSTOCK → mailqueue)
摘要
行事曆「安全庫存檢查」事件自動執行後,原本只把缺料結果寫進
twork_auto_safetystockhistory並回寫 eventitem,從未把信排進
twork_skd_mailqueue,所以 SchedulerWorker 的寄信路徑(Mailgun)永遠撈不到信、收件人收不到通知。
依
darbnogicsa20260513庫內較新版本的TWORK_AUTO_SAFETYSTOCK,把「撈收件人 → 把未達安全庫存清單渲染成 HTML 表格 →
INSERT twork_skd_mailqueue」這段補回 repo 的母本與各客戶部署腳本。變更
SqlBI/TWORK_AUTO_SAFETYSTOCK.sql(csa 母本/對照)— proc 結尾加入寄信段。
sql/deploy-darbnogiauto1.sql(鈞寶集中自動化庫部署版)— 同步加入。
sql/deploy-darbcyauto1.sql(朝陽集中自動化庫部署版,包在EXEC(N'...')內,引號加倍)— 同步加入。
寄信段行為:
1. 從
twork_skd_eventitem.通知帳號(事件設定畫面維護)取收件人;空白則RETURN(不影響本次執行成功狀態)。2. 本次 GUID 批次無缺料品項(
@rowCount = 0)則不寄。3. 主旨:
【安全庫存檢查通知】<日期> 共 N 筆未達安全庫存。4. 內文:HTML 表格(品號/品名/安全庫存/現有數量/滿足安全/M0–M6),現有數量紅字標示。
5.
INSERT dbo.twork_skd_mailqueue(收件人, 主旨, 內文, 是否HTML='Y', 來源預存程序, 執行guid),交由 AP 端
TsERP.SchedulerWorker的DequeueMailAsync經 Mailgun 寄出。Breaking Changes
無。proc 對外回傳的結果集與既有 history 寫入不變,僅在最後多排一封信。
Migration Notes
⚠️ 需在各客戶的集中自動化庫重跑部署腳本才會生效(本機已
SET PARSEONLY驗證文法,未實際部署):sqlcmd -S <server> -E -f 65001 -i sql\deploy-darbnogiauto1.sql # 鈞寶 sqlcmd -S <server> -E -f 65001 -i sql\deploy-darbcyauto1.sql # 朝陽前置:
twork_skd_mailqueue表(部署腳本內已含建表)。
- CY 版另有既有 guard:
darbcycsa1.dbo.twork_skd_eventitem需有執行guid欄,缺欄會跳過建 proc。
- 事件需在行事曆設定「通知帳號」(收件人),否則只寫 history 不寄信。
-
06-29 gldash-general-ledger-dashboard ▸
2026-06-29 總帳儀表板(GLDASH)
摘要
總帳管理(N.總帳管理)新增一支「總帳儀表板」(ProgramClass
GLDASH),比照主管儀表板(EISDASH)的版面,讓主管一頁綜覽財務全貌:損益、資產負債、費用趨勢、傳票與現金。四塊資料全部重用既有作業的 SP / BLL,不需部署任何新 SP,也不需 proc_param 登錄。新增
- 總帳儀表板頁面:工具列(本月/本季/本年/自訂日期快切 + 自動刷新 + 重新整理)+ 8 張 KPI 卡 + 2×2 圖表 + 2 張清單。
- KPI 卡(本期):本期營收、營業毛利(含毛利率)、營業費用、本期淨利(含淨利率,虧損紅字)、總資產、總負債(含負債比)、現金與銀行、本期傳票(含未過帳張數警示)。
- 圖表:損益結構長條(營收→成本→毛利→費用→營業利益→本期損益)、營業費用逐月趨勢、資產=負債+權益環圈、現金/銀行結餘趨勢(含票據預估)。
- 清單:未過帳傳票、本期費用科目 Top 10。
- 點擊卡片/圖表可直達對應總帳作業(損益表/資產負債表/會計日記帳/銀行金流),到頁後自動帶儀表板當前日期區間並自動查詢(不必再手動設條件或按查詢)。銀行金流因日期語意是現金流預估到期日、非查詢區間,故沿用其自身預設。
- 資料來源(皆重用既有):損益與費用走
IncomeBll(DARB_QRY_INCOME)、資產負債走BalanceBll(DARB_QRY_BALANCE)、傳票走SliybrowdBll(DARB_BD_SLIY)、現金走BankflowBll。
- 選單登錄 SQL:
sql/總帳儀表板_register_program_darbnogicsa1.sql(沿用「資產負債表」選單群組、自動取未使用 N-NN 序號)。
- 開發機免動 DB:
dev-programs.json已加GLDASH一筆(啟用DevPrograms後重新登入即見)。
變更
- 金額統一以本位幣顯示。
- 各區塊獨立載入、錯誤隔離:任一塊讀取失敗只該卡片/圖表顯示「讀取失敗」,不影響其他區塊。
刪除
無。
Breaking Changes
無。
Migration Notes
- 正式環境部署:執行
sql/總帳儀表板_register_program_darbnogicsa1.sql一次即可(前置:usp_新增程式已部署於該庫)。
- 無新 SP、無 proc_param、無資料 migration。
- 第一版只呈現當期數字,未做 YoY/MoM 比較基準;runtime 尚未驗收。
-
06-29 eventproject-register-cy ▸
2026-06-29 — EVENTPROJECT(排程事件(專案))補登錄到朝陽 CY
摘要
把 NOGI(
darbnogicsa1)已登錄的 EVENTPROJECT(排程事件(專案))程式,照搬補登錄到朝陽 CY(
darbcycsa1)的四張中繼資料表_menum/_menud/_sheetno/_tableseq,讓「排程事件(專案)」表單在 CY 的 L.聯絡傳訊 模組也能從主選單開啟與建立單號。
新增
sql/eventproject_register_program_darbcycsa1.sql:冪等部署腳本,
以同伺服器跨庫
INSERT...SELECT從darbnogicsa1複製 EVENTPROJECT 四列。四表各以
NOT EXISTS守護,可重複執行。變更(兩處必要偏離,其餘逐欄原樣複製)
- 選單序號:NOGI 用
L-05,但 CY 的L-05已被PROMOT_QRY
(提案資料查詢)占用。腳本於 L.聯絡傳訊 模組自動挑「現有最大序號 +1」的
第一個空號(本次 →
L-07,附加在選單末端)。_tableseq.seqval:NOGI=5,CY 為全新安裝無任何 EVENTPROJECT 單據,
計數器歸 0(與
usp_新增程式慣例一致),單號從頭起算。srvdbid改用 CY 自身值;pkid重算(_sheetno.pkid為 identity)。
Migration Notes
- 執行(中文物件,務必其一,避免 sqlcmd 預設 codepage 靜默漏建):
sqlcmd -S localhost -E -f 65001 -i sql\eventproject_register_program_darbcycsa1.sql或於 SSMS 開檔執行。
- 已在模擬環境(localhost)實跑驗證:四列成功新增、再跑一次全部略過(冪等)。
- 本腳本只動四張選單/單號中繼表;不建
prgsct1權限列、不改 proc。
使用者權限(可否瀏覽/修改)若需要,另循既有
prgsct1流程補。- 相依資料表
twork_skd_eventitemm/twork_skd_eventitem在 CY 已存在;
但排程「自動執行」鏈在 CY csa 仍有落後(見 ADR 0065 備註:CY 缺
twork_skd_eventitem部分欄位、twork_vw_calendareventview 待修),表單本身的登錄/建單不受影響。
-
06-29 efficiency-query-radgrid-tstab-condition ▸
2026-06-29 個人/期間效率統計改用 TsRadGridView + TsTab,條件面板整理
摘要
CY 主管資訊「個人效率統計」(pd_qry1) 與「期間效率統計」(pd_qry2) 內部仍混用舊 WPF 控件,與其餘查詢頁不一致;查詢條件面板排版凌亂、且未標示各條件適用於哪個分頁。本次統一改版並標註。
變更
TsERP/M.EIS/個人效率統計.xaml:左側「生產部門」勾選表DataGrid→TsRadGridView(選擇用TsGridViewCheckBoxColumn,bool 直綁)。結果格本即 TsRadGridView。補ProgramClass="Pd_qry1"啟用欄位版型持久化。此頁無分頁。
TsERP/M.EIS/期間效率統計.xaml:
- 左側「生產部門」
DataGrid→TsRadGridView。- 外層
TabControl(BottomTab 樣式)→TsControl:TsTabControl/TsTabItem(Header 用TsTextBlock)。- 三個結果格補
ProgramClass="Pd_qry2"。TsERP/M.EIS/個人效率統計Condition.xaml:改用 GroupBox(藍色標題「查詢條件(個人效率統計)」),起訖日期一列。
TsERP/M.EIS/期間效率統計Condition.xaml:拆成兩個 GroupBox 並標註適用分頁:
- 「共用條件 · 全部分頁適用」(藍):起訖日期(部門期間效率 / 組立狀況一覽表 / 期間工時調整一覽表 皆適用)。
- 「僅『組立狀況一覽表』分頁適用」(橘):品號類型(4 選 2×2)、起訖品號、查詢效率。
- 分頁對應依
Pd_qry2ViewModel.Query()實際邏輯確認(tab0/tab2 只用起訖日期;tab1 才用品號/效率/品號類型)。影響範圍
- 兩支查詢頁的外觀與其餘查詢頁一致;條件面板可一眼看出哪些條件只對「組立狀況一覽表」生效。
- 純 View 層(XAML)調整,未改 VM/BLL/邏輯與既有資料繫結(
StartDate/EndDate、RadioButtonCheck+RadioConverter、起始品號/截止品號、起始效率/截止效率、選擇、各結果 Source 維持原樣)。
Breaking Changes
無。
Migration Notes
- 改動在
TsERP組件,需重建 TsERP。runtime 行為(查詢結果)不變。
-
06-29 cy-eventitem-param-width-fix ▸
2026-06-29 修復 CY 行事曆事件「執行」按鈕 JSON 截斷錯誤
摘要
在 CY(darbcycsa1)行事曆單獨按某事件的「執行」按鈕,出現:
ExecuteAsync異常: Unterminated string. Expected delimiter: ". Path 'LP_P1', line 1, position 100. at Newtonsoft.Json.Linq.JObject.Parse(...) at AutoPilot.AutoPilotHelper.ExecuteMethod(...)根因:
twork_skd_eventitem.參數欄位在 CY 是nvarchar(100),母本 darbnogicsa1 是nvarchar(4000)(schema 分歧)。AutoPilot 排程事件的 JSON 參數約 113 字,寫入時被 DB 靜默截斷到 100 字,剛好斷在"LP_P1":"之後,尾巴{eventpkid}"}不見 →JObject.Parse在 position 100 失敗。App 端 Source 宣告[TsStringLength(4000)],本就預期 4000。範圍:darbcycsa1 安全庫存排程事件 265 筆參數全部被截斷。
變更
- 新增
sql/fix_eventitem_param_width_darbcycsa1.sql:
1.
ALTER TABLE twork_skd_eventitem ALTER COLUMN 參數 nvarchar(4000)對齊母本。2. 還原被截斷的事件參數為完整模板
{"DataEvent":"AutopilotLogSysExec","Procedure":"TWORK_AUTO_SAFETYSTOCK","Dispatcher":"SKD","LP_P1":"{eventpkid}"}({eventpkid}由SchedulePlaceholders.ReplaceExecutionEventPkidTokens在執行期替換)。影響範圍
- CY 行事曆事件「執行」按鈕:參數可正確解析並派發
TWORK_AUTO_SAFETYSTOCK(@eventitempkid)。
- 僅補欄寬與還原資料,未改 AutoPilot/SP 邏輯。
Breaking Changes
無。
Migration Notes
- 此為 darbcycsa1 的 schema + 資料修正,需在 darbcycsa1 執行
sql/fix_eventitem_param_width_darbcycsa1.sql。
- ⚠️ 本次因安全機制未由工具直接套用到模擬環境,需手動執行該腳本後才生效。
- 其他客戶庫(darbkccsa1 / darbzdcsa1 / darbcmacsa1 等)可能有相同欄寬分歧,尚未逐庫盤點。
- 新增
-
06-29 cy-calendar-system-events-sp-fix ▸
2026-06-29 修復 CY 行事曆看不到系統事件(SP 漏 or 9)
摘要
朝陽 CY(darbcycsa1)以管理員登入後,右側行事曆已能看到「系統」篩選器,但底下沒有任何系統事件。
根因:darbcycsa1 實際部署的
TWORK_SKD_GETEVENT與母本(darbnogicsa1,SqlBI/TWORK_SKD_GETEVENT.sql)分歧——第一段 @list 來源只有擁有者所屬類別=0(公司),漏了or 擁有者所屬類別=9(系統),導致系統事件永遠不進結果集。資料本身存在(darbcycsa1 有 265 筆系統事件,2026-06 就有 5 筆,皆已審核=Y、項目類型=0),純粹是 SP 不撈。(與前一則 admin Trim 修復
2026-06-28-admin-role-trim-fix是接續:先修好 admin 判定讓「系統」篩選器顯示,才發現 SP 這層也漏。)變更
- DB(darbcycsa1):
ALTER PROCEDURE TWORK_SKD_GETEVENT,第一段where 擁有者所屬類別=0→where 擁有者所屬類別=0 or 擁有者所屬類別=9。CY 專屬的部門 JOIN(twork_bas_vw_dept/DepartmentCode/EmployeeCode)原樣保留,未套母本 schema。
- repo:新增
sql/TWORK_SKD_GETEVENT_darbcycsa1.sql,把修正後的 CY 變體納入版控(含與母本差異註記),避免重佈又掉回舊版。
影響範圍
- CY 行事曆:管理員登入即可看到系統事件(驗證:
EXEC TWORK_SKD_GETEVENT '2026/06/29','CMSA'由 0 筆 → 5 筆系統事件)。
- 系統(9) 是否限管理員仍由前端 UI 把關(DB 端不做 admin 過濾,非硬邊界);如需 DB 端硬邊界另議。
Breaking Changes
無。
Migration Notes
- 此為 darbcycsa1 的 SP 變更,已於模擬環境套用;正式佈署各 CY 庫時請跑
sql/TWORK_SKD_GETEVENT_darbcycsa1.sql。
- 其他客戶庫(darbkccsa1 / darbzdcsa1 / darbcmacsa1 等)可能有相同「漏 or 9」分歧,尚未逐庫盤點。
- DB(darbcycsa1):
-
06-29 checkpayprint-blank-fix ▸
2026-06-29 修正支票套印(上海商銀 / Checkpayprint)列印空白
摘要
支票列印彈窗(
CheckPrintViewModel,由應付票據 checkpay 的「支票列印」鈕開啟)中,程式碼註冊的「上海商銀」報表項(
報表名稱 = "Checkpayprint")選取後會套印空白。變更
TworkReportPluginOfficial/Checkpayprint.cs:ExportToSQLite原本是空殼(直接return true、
未把資料寫入 SQLite),補成讀取
parameters["rpt_o030_checkpayreportpoco1"]並ReportSqliteCreator.ExportToSqlite(...),與Checkpayzd1/Checkpayzd2行為一致。原有的
SetParameters(注入公司電話/傳真/地址)保留不動。根因
PluginHelper.GetReportPlugin(插件名稱, 報表名稱)在插件名稱留空時,會以報表名稱找同名plugin class。該報表項未設
插件名稱,於是 fallback 到同名的Checkpayprintplugin——但它的ExportToSQLite沒有把ReportSource資料寫進共用表rpt_o030_checkpay_report1,導致報表讀到空表(或殘留舊資料)。會正確匯出的
Checkpayzd1/zd2(DB 註冊的各銀行版型用)才是正常路徑。影響範圍
- 只影響選取程式碼註冊的「上海商銀 / Checkpayprint」那一筆;DB 註冊的支票套表銀行版型
(走
Checkpayzd1/zd2plugin)不受影響、原本就正常。- 預設選取為清單第一筆(DB 版型),故僅在使用者手動切到該筆時才會踩到。
Breaking Changes / Migration Notes
無。純行為修正,不需資料庫或設定異動。
待驗
- 實機列印確認:套印確實帶出資料(金額、金額大寫、民國年/月/天、支票抬頭)。
-
06-29 admin-role-trim-fix ▸
2026-06-29 修復管理員角色判定未 Trim 空白導致誤判非管理員
摘要
以管理員帳號(
管制系統欄位設為ADMIN)登入,仍被判為非管理員 → 看不到行事曆「系統」事件、以及其他靠IsAdmin()開放的功能。根因:
UserBll.CheckRoleInManagedAccount把管制系統(逗號分隔角色字串)ToLower()後Split(','),但沒有 Trim 各 token。當管制系統是固定寬度 CHAR 欄位(尾端補空白)或手動輸入夾帶空白時,token 會是"admin ",與"admin"不相等 →Contains回 false →IsAdmin()誤判為非管理員。大小寫本來就有處理(兩邊皆ToLower()),不是問題。變更
LogicBll/Login/UserBll.csCheckRoleInManagedAccount:
-
Split(',')後對每個 tokenTrim();比對的role也Trim().ToLower()。- 修正後
"ADMIN"、"ADMIN "、"Manager, Admin"等皆能正確判定為管理員。影響範圍
- 所有透過
IUser.IsAdmin()/CheckRoleInManagedAccount判斷的功能(如右側行事曆「系統」事件可見性CalendarPageViewModel.RefreshUserPermission、其他管理員專屬入口)。
- 只放寬「空白容錯」,不改變角色語意;原本就正確(無空白)的設定行為不變。
Breaking Changes
無。
Migration Notes
- 改動在
LogicBll組件,需重建 TsERP;IsAdmin在登入時依管制系統計算,需重新登入才生效。
- 資料面不需調整;即使
管制系統欄位是 CHAR 補空白或含手動空白,現在都能正確判定。
-
06-28 radgridview-reenable-column-virtualization ▸
2026-06-28 TsRadGridView 重新開啟欄虛擬化(MinColumnWidth 撐住水平捲軸)
摘要
全 app 共用表格
TsRadGridView/TsBrowseRadGridView重新開啟欄虛擬化(取代 ADR 0026 的全域關閉),並用
MinColumnWidth=50把每欄寬度下限拉高,讓欄虛擬化下未實體化的SizeToHeader/Auto欄仍以真實寬度計入水平
ExtentWidth,避免當初「水平捲軸間歇拖不動」重演。變更
TsControl/Themes/TsRadGridViewGeneric.xaml(TsRadGridView、TsBrowseRadGridView兩個 Style):
-
EnableColumnVirtualization由False改為True。- 新增
MinColumnWidth=50。影響範圍
- 全 app 所有
TsRadGridView/TsBrowseRadGridView。
- 寬表(Sliy、總帳類等數十欄)恢復欄虛擬化 → 記憶體/載入/捲動效能回升。
- 各 grid 的窄欄(序號、選擇欄等)寬度下限變為 50px,原本更窄者會略變寬。
- 仍有 local
EnableColumnVirtualization="False"的頁面(ErpPivotQuery2 個 grid、Receivepq1 個 grid)
維持非虛擬化,視為刻意例外,本次未動。
Breaking Changes
無。
Migration Notes
- 需重建 TsERP 才會生效(改動在 TsControl 共用樣式)。
- ⚠️ 需 runtime 驗收:請在 Sliy / SliyTurn / 總帳類寬表實機確認水平捲軸可順拖、欄捲入時寬度正常。
若捲軸仍塌陷,退路為該類寬表欄改固定 px 寬,或回退(兩個 setter 改回 False / 移除 MinColumnWidth)。
- 詳見 ADR 0064。
-
06-28 pivotselector-selection-not-applied ▸
2026-06-28 樞紐選擇器選取項目未生效修復
摘要
查詢/瀏覽類畫面(如 inventquery)底部「樞紐分析表」選擇器(
PivotSelector1)的 combobox 雖可下拉選取,但按下「樞紐分析表」鈕後永遠用清單第一筆的樣板檔開啟,不管使用者實際選了哪一項。原因是控件的選取值沒有回寫到 ViewModel:
1.
PivotSelector1.xaml把 VM 的SelectedItem用預設模式綁到TsComboBoxWithDescription.SelectedItem,但該 DP 未標記BindsTwoWayByDefault,所以是 OneWay(只 VM→控件)。2.
TsComboBoxWithDescription內層 combobox 選取變更時(ComboBox_OnSelectionChanged)只更新Code/Description,從不回寫自己的SelectedItemDP。3. 另一個
Code="{Binding SelectedItem.Code, Mode=OneWay}"綁定是 OneWay 且指向唯讀巢狀路徑,控件裡的UpdateSource()形同空操作。結果:VM 的
SelectedItem始終停在ItemsSourcesetter 初始化的ItemsSource[0],PivotExecute拿它的檔名去組樣板路徑,於是永遠開第一筆。(這是 樞紐選擇器 combobox 在查詢畫面無法下拉修復 的後續:combobox 解鎖能下拉後,選取沒接回 VM 這條暗 bug 才浮現。)
變更
ViewModel/Control/PivotSelector1ViewModel.cs:新增SelectedCode字串屬性,綁到控件的Code(TwoWay-by-default、選取變更時會被推回);setter 依Code從ItemsSource解析出對應的SelectedItem。ItemsSourcesetter 初始化改設SelectedCode = ItemsSource[0].Code(初始仍選第一筆)。
TsControl/Layout/PivotSelector1.xaml:combobox 綁定改為Code="{Binding SelectedCode, Mode=TwoWay}",移除無作用的SelectedItem="{Binding SelectedItem}"與 OneWay 的Code綁定。
影響範圍
- 樞紐選擇器(
PivotSelector1):使用者選哪一項,就用該項對應的樣板檔開啟。
- 未動到共用控件
TsComboBoxWithDescription本身,其餘 64 處用法行為不變。
Breaking Changes
無。
Migration Notes
改動含 TsControl 共用控件所在組件,需重建整個 TsERP 才會完整生效。
-
06-28 pivotselector-combobox-locked ▸
2026-06-28 樞紐選擇器 combobox 在查詢畫面無法下拉修復
摘要
查詢/瀏覽類畫面(如 inventquery)底部「樞紐分析表」選擇器(
PivotSelector1)的 combobox 點不開下拉選單。原因是三件事疊在一起:
1.
TsComboBox(全 app 共用,繼承RadComboBox)2026-04 加入的IsLocked機制,在OnPreviewMouseDown會把滑鼠點擊吃掉並強制關閉下拉。2.
TsComboBox的全域預設樣式(Generic.xaml)把IsLocked綁到所在表單的編輯狀態:FindAncestor(ITsContentControl).DataContext.ViewModelStatus.Status經AdeStatusIsReadOnlyConverter轉換,FallbackValue=true。3.
AdeStatusIsReadOnlyConverter除Empty/Add/Edit/Copy/SpecialEdit外一律回傳true(鎖定)。查詢畫面停在Normal狀態 → 回true→IsLocked=true→ 下拉永遠打不開。樞紐選擇器是「工具型」控件,在瀏覽(Normal)狀態下本就該可操作,卻被全域 combobox「非編輯就鎖」的樣式波及。
變更
TsControl/CombineComboBox/TsComboBoxWithDescription.xaml.cs:新增 opt-in 相依屬性IgnoreEditStatus(預設false)。為true時用區域值把內層TsComboBox.IsLocked覆寫成false(永遠解鎖)、為false時ClearValue還原成預設樣式的狀態綁定;另在Loaded補套用一次以防屬性早於內層控件設定。
TsControl/Layout/PivotSelector1.xaml:combobox 加上IgnoreEditStatus="True"。
影響範圍
- 樞紐選擇器(
PivotSelector1)的 combobox:任何狀態下皆可下拉。
- 其餘 64 處
TsComboBoxWithDescription用途:IgnoreEditStatus預設false,行為完全不變(維持「非編輯狀態鎖定」)。
Breaking Changes
無。
Migration Notes
需重建 TsERP 才會生效(改動在 TsControl 共用控件)。
-
06-28 order-pivot-templates-dbf-to-sqlite ▸
2026-06-28 訂單樞紐樣板資料來源 DBF→SQLite
摘要
把
C:\dglibrary\REPORTSROOT\Template下三支訂單樞紐分析樣板的外部資料來源從 Visual FoxPro DBF 改為 SQLite,並清空殘留的舊快取,比照已轉好的
部門費用統計表.xlsx連線格式。涉及檔案:
客戶訂單品號數量統計.xlsx
訂單生產部門查詢.xlsx
訂單資料樞紐查詢.xlsx
變更
連線字串(`xl/connections.xml`)
項目 變更前 變更後 連線 DSN=Visual FoxPro Tables;SourceDB=c:\TEMPS\PIVOT;SourceType=DBF;…DRIVER={SQLite3 ODBC Driver};Database=C:\Temps\Sqlite\Twork_TW.db;資料表 ` SELECT * FROM訂單明細_d`` SELECT * FROMDARB_BD_ORMAST00`- DBF 的
訂單明細_d(37–39 欄)對應 SQLiteTwork_TW.db的DARB_BD_ORMAST00
(42 欄)。逐欄比對三支樞紐的 cacheField,全部都在該表中;唯一例外是
客戶訂單品號數量統計.xlsx的「年」欄(databaseField="0",是 Excel 對「受訂日期」做的年度分組欄、非來源欄),不影響。
- 用
SQLite3 ODBC Driver以 Excel 實際送出的反引號查詢實測,DARB_BD_ORMAST00
回傳 258 筆正常。
清空舊快取
檔案 原快取筆數 現在 客戶訂單品號數量統計.xlsx0(本來就空) count=0 訂單生產部門查詢.xlsx85 count=0 訂單資料樞紐查詢.xlsx82 count=0 pivotCacheRecords1.xml清成count="0"的空根節點(保留命名空間)。
pivotCacheDefinition1.xml的recordCount設 0。
- 三支全部加上
refreshOnLoad="1",開檔時自動向 SQLite 重抓最新資料。
刪除
移除三支連線中殘留的
odcFile屬性(指向使用者 OneDrive 的(預設) 訂單明細_d.odc,內含舊 DBF 連線)。保留會在重新整理時把來源蓋回 DBF;已轉好的參考檔
部門費用統計表.xlsx亦無此屬性。Breaking Changes
無。樣板沿用既有樞紐版面,僅換來源。
Migration Notes
- 目標機需安裝 SQLite3 ODBC Driver(Excel 樞紐用;開發機已裝 32/64-bit 兩版)。
Twork_TW.db內的DARB_BD_ORMAST00由 ERP 匯出維護,目前已有資料。
- 各檔已備份:
*.xlsx.dbfbak(換來源前)、*.xlsx.cachebak(清快取前)。
- 使用者開檔即自動重新整理;如停用自動重整,手動按「重新整理」即可。
-
06-28 excel-pivot-trusted-location ▸
2026-06-28 Excel 樞紐信任位置自動化(消除「已停用外部資料連線」警告)
摘要
樞紐分析表範本(.xlsx)內嵌一條外部 ODBC 資料連線(
DRIVER={SQLite3 ODBC Driver};Database=C:\Temps\Sqlite\Twork_TW.db),Excel 開檔時預設封鎖外部連線,跳出「安全性警告:已停用外部資料連線 → 啟用內容」橫幅,使用者每次都要手動點「啟用內容」才會刷新資料。由於 app 每次都把範本複製成新檔再開(
PivotBll.CopySqliteAndOpen→C:\Temps\Template\Pivot\),「信任的文件(Trusted Documents)」綁檔案雜湊會每次失效,無法解決;且封鎖是 Excel 用戶端的信任判斷,檔案本身無法宣告連線可信。正解是把固定的開檔夾設為 Excel 信任位置(Trusted Location)——從信任位置開的檔,外部連線自動啟用、也跳過 Protected View。變更
deploy/install-customer.ps1:Install 階段(per-user)新增自動把C:\Temps\Template\Pivot\設為 Excel 信任位置。
- 新函式
Set-ExcelPivotTrustedLocation:涵蓋 Office 2010~365(14/15/16.0),只設已安裝的版本,同路徑已存在就跳過(冪等);寫HKCU\...\Excel\Security\Trusted Locations\LocationN(Path+AllowSubFolders=1)。- 放在「程式是否已安裝」判斷之前,即使程式已裝、每次跑 Install 仍補設一次(新使用者帳號也涵蓋)。
- 新增參數
-SkipExcelPivotTrust(預設關閉=會設)與-PivotTrustPath(預設C:\Temps\Template\Pivot\,對應ERPIO.PivotTemplateDirectory)。影響範圍
- 走
install-customer.ps1 -Stage Install(或 Active Setup / GPO 使用者登入指令碼)的客戶機器:每個使用者首次套用後,開樞紐不再跳「已停用外部資料連線」警告。
- 既有單機可手動跑同等的 HKCU 設定達成相同效果(本次已在開發機 Office 16.0 套用)。
- 不影響 Config(SYSTEM)階段;不影響未走此佈署腳本的環境(行為不變,仍會跳警告直到設定信任位置)。
Breaking Changes
無。
Migration Notes
- 此設定為 per-user(HKCU),須以「該使用者」身分執行 Install 階段才會寫進其設定檔。
- 信任位置只解除「啟用外部連線」警告;連線要真正刷新仍需安裝對應位元數的 SQLite ODBC 驅動(
-InstallOdbc,位元數對應 Excel 而非 OS)。兩者各管一半。
- Excel 在啟動時讀取信任中心設定;若套用當下 Excel 正開著,需完全關閉再開才生效。
-
06-28 eis-efficiency-query-vm-registration ▸
2026-06-28 修復 CY 主管資訊四支效率查詢「無法建立ViewModel」
摘要
朝陽 CY 主管資訊(M.主管資訊)的四支查詢——個人效率統計、期間效率統計、達成率統計、非生產工時統計——按下選單後跳「無法建立ViewModel」錯誤,無法開啟。
根因:這類「條件查詢」程式的主 ViewModel 由 navigator 反射建立,但其依賴的 ConditionViewModel 需透過 DI 取得(
IQueryConditionFactory.Create()→GetService<TCondition>())。這四支的 ConditionViewModel 類別、App.xaml DataTemplate 都齊全,唯獨TsERP/DIExtension.cs漏了 DI 註冊,GetService回 null → 丟未註冊指定查詢條件 ViewModel→ navigator 顯示「無法建立ViewModel」。(真因記錄在
C:\temps\debuglog\<date>.txt,例:[CreateErpProgramBaseViewModel] 未註冊指定查詢條件 ViewModel:Pd_qry1ConditionViewModel。)變更
TsERP/DIExtension.cs:補上四支 ConditionViewModel 的 DI 註冊:
-
Pd_qry1ConditionViewModel(個人效率)-
Pd_qry2ConditionViewModel(期間效率)-
Pd_qry4ConditionViewModel(達成率)-
WknpdtqConditionViewModel(非生產工時)影響範圍
- 上述四支查詢從「打不開」修復為可正常開啟條件查詢畫面。
- 純新增 DI 註冊,不影響其他程式。
Breaking Changes
無。
Migration Notes
- 改動在
TsERP組件,需重建 TsERP 才生效。
- 通則:移植/新增「條件查詢頁」時,除了 VM 改名、ProgramClass、App.xaml DataTemplate,還必須在
DIExtension.cs加services.AddScoped<XxxConditionViewModel>(),否則執行期跳「無法建立ViewModel」。
-
06-28 cuinve-union-cy-nogi-columns ▸
2026-06-28 cuinve NOGI/CY 欄位聯集(view→Source、table→Model)
摘要
依單據別
CUINVE比對darbnogicsa1與darbcycsa1兩庫的_sheetno對應,做欄位聯集後套回程式:- Source 以 VIEW 為準:
vw_cuinvema(主)/vw_cuinve(子)。
- Model 以資料表為準:
cuinvema(主)/cuinve(子)。
主表(
cuinvema/vw_cuinvema)兩庫資料欄完全相同 → Source/Model 皆無變更。差異全在子表
cuinve/vw_cuinve。比對結果
物件 NOGI CY nogi-only cy-only base cuinve35 29 箱長/箱寬/箱高/材積/單重/單價/變動日期/業務員編號 產品別/紙箱尺寸 view vw_cuinve38 63 單重/單價/變動日期/箱長/箱寬/箱高/材積/業務員編號/姓名 (另含 32 個 JOIN 庫存主檔欄) view 比 base 多出的欄是
vw_cuinveJOIN 庫存主檔 invent 得到的唯讀欄。變更
Model(`Twork_ord_vw_cuinveModel`)— 對應 base table `cuinve`
無新增。base
cuinve聯集(含 nogi-only 8 欄與 cy-only產品別/紙箱尺寸)原本即已齊全。Source(`Twork_ord_vw_cuinveSource`)— 對應 view `vw_cuinve`
新增 32 個 CY view 專屬欄(JOIN 庫存主檔),以 Source 自帶私有欄位承接(不寫入 Model):
群組代號, 設變編號, 設變資料, 停用說明, 管制說明, 群組說明, 中文描述, 停用, 停用日期,
品別(byte), 材質, 規格, 型別, 加工, 包裝材料, 包裝量_包, 儲位, 單位, 標準售價,
廠商代號1, leadtime(short), 內箱包裝數, 最小採購量, 英文描述, 最低訂單量, 停用狀態,
庫存管制, abc分類, 生產部門, 採購緊急度, 設變導入日, 生產批量
型別/長度對齊 CY
vw_cuinve。此外,既有 view JOIN 唯讀欄
品名、客戶簡稱、姓名(base tablecuinve沒有、原本誤放在 Model)一併改為 Source 自帶私有欄位,使 Model 純對應 base table。
刪除
Twork_ord_vw_cuinveModel移除品名、客戶簡稱、姓名三個非 base-table 欄(改由 Source 私有欄位承接)。僅 Source 內部委派引用,無其他消費端,移除後 Common/Model/LogicBll/ViewModel 建置均通過。
Breaking Changes
無。Source 新欄為 view JOIN 唯讀欄,
GetModelBase()回傳的 Model 不含這些欄 →存檔不會序列化上傳(本就不屬 base
cuinve實表),與 ADR 0050 union 取交集行為一致。Migration Notes
本機 SQLite 由
EnsureCreated依 Source 模型重建,新欄自動出現;既有本機庫缺欄走補欄安全網。伺服器端 view/table 不變。
- Source 以 VIEW 為準:
-
06-28 central-automation-db ▸
2026-06-28 — 集中自動化庫 darbnogiauto1 + 排程專屬派發器
> 詳見 ADR 0065。
摘要
把排程/自動化預存程序與其產出的資料表,從公司庫
darbnogicsa1集中搬到新的集中自動化庫
darbnogiauto1,並比照 AI 查詢派發器新增**排程專屬派發器DARB_LOG_SYS_SKD_EXEC**(寫獨立稽核表log_sys_skd、目標一律導向新庫)。查詢自動化資料改走與既有 log 派發器相同的機制(新庫內也佈一份
DARB_GETDATA4)。新增
- 資料庫
darbnogiauto1,內含:
- 自動化 proc:
TWORK_SKD_GET_PENDING_NOTIFY、TWORK_SKD_GET_PENDING_AUTOEXEC、TWORK_SKD_MAILQUEUE_DEQUEUE、TWORK_SKD_MAILQUEUE_UPDATE、TWORK_AUTO_SAFETYSTOCK(讀公司資料以三段式
darbnogicsa1.dbo.*)。- 自動化自有表:
twork_skd_mailqueue、twork_auto_safetystockhistory。- 通用查詢 proc
DARB_GETDATA4(供結果檢視走同一派發器讀本庫表)。darbnogilog1:排程專屬派發器DARB_LOG_SYS_SKD_EXEC+ 稽核表log_sys_skd。
- C#:
Procedure.DARB_LOG_SYS_SKD_EXEC、IDatabaseConnection.Log_Sys_Skd_Exec、
AutoPilotTask.Log_Sys_Skd_Exec。- 部署腳本
sql/deploy-darbnogiauto1.sql、sql/deploy-darbcyauto1.sql(冪等)。
- CY 公司庫排程 schema 修補
sql/fix-darbcycsa1-scheduler-schema.sql(補 eventitem 4 欄 + 重建 calendarevent view)。
proc 本體引用本地同名 view、view 抓對應 csa(跨庫集中在 view 層;公司庫缺的
vwseek_*用 csa 基底表組、_date有則 view 抓 csa、無則自建日曆表)。- 版控補回 3 支原本只存在 DB 的 proc DDL:
SqlBI/TWORK_SKD_GETEVENT.sql、
SqlBI/TWORK_SKD_UPDATE_EVENT_STATUS.sql、SqlBI/TWORK_AUTO_SAFETYSTOCK.sql。變更
SchedulerJob:撈待通知/待自動執行、郵件佇列出列/狀態更新 4 處改走Log_Sys_Skd_Exec(→新庫)。
AutopilotMethod_LogSysExec:新增Dispatcher參數;設為SKD時該事件走排程專屬派發器
(→新庫),其餘維持主派發器(→csa)。安全庫存事件請設
Dispatcher=SKD+Procedure=TWORK_AUTO_SAFETYSTOCK。EventResultViewModel:依事件參數的Dispatcher決定讀結果走哪個派發器(SKD→新庫)。
刪除
- 無。
darbnogicsa1原 8 支 proc、原twork_auto_safetystockhistory、proc_param、共用
DARB_LOG_SYS_EXEC/log_sys一律保留(主派發器 fallback)。Breaking Changes
IDatabaseConnection新增Log_Sys_Skd_Exec:若有自訂實作(測試 fake/mock 以外),需補實作。
- 排程作業(
TsERP.SchedulerWorker)升級後,需先部署darbnogiauto1與
DARB_LOG_SYS_SKD_EXEC,否則排程的撈件/寄信/安全庫存會找不到派發器或 proc。Migration Notes
1. 於目標 SQL 執行個體跑
sql/deploy-darbnogiauto1.sql(sqlcmd -S <srv> -E -f 65001 -i ...或 SSMS)。2. 確認派發器
EXECUTE AS身分(loginfoxcsa)在darbnogiauto1有 user(腳本建foxautoexec);若實機 login 名不同,改腳本第 2 節的
FOR LOGIN。3. 安全庫存的行事曆事件:
參數設Dispatcher=SKD、Procedure=TWORK_AUTO_SAFETYSTOCK、結果表填
twork_auto_safetystockhistory。4. 多客戶:其他客戶用對應
sql/deploy-darb<客戶>auto1.sql(view 層改抓該客戶 csa)。CY(朝陽)已完成:公司庫 schema 原本落後,已用
sql/fix-darbcycsa1-scheduler-schema.sql補齊(
twork_skd_eventitem補真正新欄執行開始時間/執行guid;改基底欄名通知→是否通知、停用→是否停用對齊共用 TsERP Source,並連帶更新引用舊名的 CY 物件
twork_skd_vw_eventitem/_v/TWORK_WKFLOW_EVENTITEM/TWORK_MOLD_CHECK/TWORK_SKD_NOTIFYEVENT;twork_vw_calendarevent修IsApproved→已審核、暴露排程欄),重跑
deploy-darbcyauto1.sql後 CY 端對端驗證通過(NOTIFY/AUTOEXEC/安全庫存全 OK、資料保留),與 NOGI 同等。新客戶若 csa schema 落後,先跑對應 csa 修補(參考 CY 那支、注意各庫舊欄名差異與相依物件)再跑 deploy。
5. 未來把信寫進 mailqueue 的入列端 SP,目標表改
darbnogiauto1.dbo.twork_skd_mailqueue。 - 資料庫
-
06-28 browse-grid-sort-filter-and-statistics ▸
2026-06-28 庫存查詢:統計表顯示 + 表頭排序/篩選
摘要
修好 InventQuery(庫存查詢)遷到
TsBrowseRadGridView後遺留的三個缺口,全在共用 browse 控件補回,影響所有用該控件的瀏覽/查詢畫面。詳見 ADR 0066。
變更
最底下統計表恢復顯示資料
- 病根:5 月重構把主表改成自動產生欄位、卻漏改統計表,統計表仍掛
AutoGenerateColumns="False"
→ 欄位只剩沒綁定的表頭、又被
ClearColumn清空 → 整表空白。- 修法:移除統計表的
AutoGenerateColumns="False",與主表一致即顯示資料。
- 順手把統計列高度由
0.3*改0.2*(統計表變矮、主結果區變高)。
表頭排序改伺服器端
- 之前點欄位表頭沒反應(資料虛擬化下內建前端排序只排已載入頁)。
- 改為:點表頭三段切換「遞增 → 遞減 → 取消」,由 provider 在 SQLite 端
ORDER BY後重新分頁抓取,
整體資料重排;表頭排序箭頭正常顯示。
表頭篩選改伺服器端
- 之前欄位漏斗篩選無作用(Telerik 篩選僅支援 IQueryable 來源)。
- 改為:欄位漏斗的「包含/等於/大於/小於/區間…」等 field filter 會轉成 SQL,由 provider 在 SQLite 端
WHERE後重抓;多欄條件以AND疊加;可與排序併用。- 相異值(distinct)勾選清單在虛擬化下不支援,已隱藏,只保留欄位篩選。
已知限制
- 套用排序/篩選後會重建欄位,漏斗的「已篩選」標記不會留著(資料仍是正確篩過的)。
- 清除篩選:按「查詢」重跑(會一併清空排序與篩選),或重開漏斗設新條件。
Breaking Changes
無。
Migration Notes
- 無需資料或設定調整,重建後生效。
- 病根:5 月重構把主表改成自動產生欄位、卻漏改統計表,統計表仍掛
-
06-27 velopack-per-customer-channel ▸
2026-06-27 — Velopack 每客戶獨立發版通道
摘要
更新機制改為支援 Velopack channel:每家客戶可跟自己的通道,發版時指定通道 → 只更新該客戶、不影響其他家。
維持一份程式碼、一個發布包、一個 blob 容器。詳見 ADR 0063。
新增
appsettings.local.json新增Update區段(每客戶部署時設定,不進 repo):
-
Update:Channel— 該客戶的 Velopack 更新通道(建議用客戶代號)。-
Update:FeedUrl— 覆寫更新 feed 網址(預設darb-vpk,保留供日後內網鏡像)。```json
{ "DatabaseListSourcePath": "...", "Update": { "Channel": "cust-b" } }
```
release-velopack.ps1新增-Channel參數(預設dev):
-
.\release-velopack.ps1 -Channel cust-b→ 只發布到cust-b通道,只跟該通道的客戶會更新。- 不帶參數 → 發到
dev(沒有客戶跟,平常開發用)。deploy/deploy-customer.ps1新增-Channel參數:部署客戶時一併把Update:Channel寫進其
appsettings.local.json(設一次即可)。- 新增
deploy/install-customer.ps1— 大量機器(如單一客戶 500 台)一鍵初次佈署:
-
-Stage Config:寫%ProgramData%\TsERP設定(需系管/SYSTEM),適合 GPO 電腦啟動指令碼。-
-Stage Install:per-user 靜默安裝對應通道的 Velopack Setup,已安裝自動跳過,適合 GPO 使用者登入指令碼。- 預設
-Stage Both:手動單機一次跑完。Velopack 靜默安裝用官方--silent旗標(docs.velopack.io 查證)。- 可選
-InstallOdbc [-OdbcBitness x64|x86|both]:一併靜默安裝隨程式打包的 SQLite ODBC 驅動(NSIS
/S),供 Excel 樞紐分析表透過 ODBC 讀 SQLite 資料用。TsERP 本身不需要 ODBC(內建
System.Data.SQLite.Core引擎已打包)。已裝會依 HKLM 註冊偵測自動跳過。⚠ 位元數要對應 Excel 而非 OS(32 位 Office 用
x86)。- 可選
-RegisterActiveSetup [-ActiveSetupVersion N]:在 HKLM 註冊 Active Setup,讓**每個使用者首次登入時自動安裝**(含日後新建帳號),不必逐人手動裝。StubPath 指向
-Source上的本腳本-Stage Install,故-Source須為 UNC 分享;須以 64 位 PowerShell 執行;bump 版本號可強制全體重觸發。(Velopack 為 per-user 安裝,沒有 MSI 式「一份全機共用」;Active Setup 是讓每使用者各自自動裝的標準作法。)
變更
App.xaml.cs的CheckForUpdatesAsync不再寫死 feed 網址,改從appsettings.local.json讀
Update:Channel/Update:FeedUrl,組UpdateManager的ExplicitChannel。讀取失敗回退預設。刪除
無。
Breaking Changes
無。沒設
Update:Channel的既有安裝走 Velopack 預設通道 = 現行行為,不會壞。Migration Notes
- 既有客戶:不需動作即維持現行更新行為。要納入「逐家發版」,重跑
deploy-customer.ps1 -Channel <客戶碼> -Force,或手動在其appsettings.local.json補"Update": { "Channel": "<客戶碼>" }。- 過渡期:尚未設通道的舊機若仍需更新,繼續以預設通道發布一份(
vpk pack不帶 channel 的舊行為);
全數客戶設上通道後即可只發名通道。
- 發版者注意:
-Channel預設dev以防手滑直推客戶;正式更新某家務必明確帶-Channel <該家>。
發版結尾會印出
Channel:供核對。- 某通道首次發布:該通道 blob 尚無 RELEASES,需加
-SkipDownload(與既有首次發布規則一致)。
-
06-27 primarykey-validation-nested-tab-fix ▸
2026-06-27 修正巢狀分頁主檔的「客戶代號/廠商代號」永遠跳「資料重複」
摘要
修正 cudata(客戶資料)、spdata(廠商資料)、invent(料件)等「主鍵欄位放在巢狀分頁裡」的主檔,按下新增後輸入主鍵一律被判定「資料重複」、重新輸入也不會消失、導致無法存檔新增的問題。
根因
主鍵驗證
PrimaryKeyValidateViewModel.CheckPrimaryKey需要取得程式 VM(ERPProgramViewModel)才能查重,否則直接回傳「重複」。它透過控件的
ViewHelper.RootViewModel(Inherits 附加屬性)取 VM。但TsView.DataContextChanged會把每個 TsView 的RootViewModel覆寫成「該 TsView 自己的 DataContext」。當主鍵欄位TsPrimaryKeyTextBox被放進巢狀分頁 TsView(如CudataTab1,DataContext 是CudataTab1ViewModel)時,控件取到的是分頁 VM——它不是ERPProgramViewModel,於是CheckPrimaryKey走進is not ERPProgramViewModel → return true(=重複)的分支,無論輸入什麼值都恆判重複。因為驗證恆失敗、主鍵欄位永遠帶錯誤,連帶無法通過存檔前的錯誤檢查,新增的客戶/廠商存不進去。
變更
- 新增介面
ViewModel.IErpProgramOwner { ERPProgramViewModel ErpProgramViewModel { get; } }。
ERPProgramViewModel實作之,回傳自己。
- 三個巢狀分頁基底 VM 實作之,回傳宿主程式 VM:
-
CudataTabBaseViewModel → CudataViewModel-
SpdataTabBaseViewModel → SpdataViewModel-
InventTabBaseViewModel → InventBsViewModelPrimaryKeyValidateViewModel.CheckPrimaryKey:取不到ERPProgramViewModel時,改用IErpProgramOwner取回真正的程式 VM 再查重。
行為影響
- cudata / spdata / invent 新增主檔時,主鍵查重恢復正常:輸入既有代號才報「資料重複」,輸入新代號即通過、可存檔。
- 一般(非巢狀分頁)主檔的主鍵驗證行為不變。
附帶修正:新增後游標未自動跳到主鍵欄
同源問題。
FocusExtension.IsFocused綁DataContext.IsFocused(分頁 VM),而分頁 VM 的IsFocused只是轉發程式 VM 的同名屬性。程式端ERPProgramViewModel.SetFocus()切的是程式 VM 的IsFocused(false→true),不會觸發分頁 VM 的PropertyChanged,於是FocusExtension收不到 false→true 邊緣、不聚焦——新增後游標不會自動落在客戶代號/廠商代號/料件代號欄。修法:三個分頁 Tab1 VM(
CudataTab1ViewModel/SpdataTab1ViewModel/InventTab1ViewModel)在建構式訂閱程式 VM 的PropertyChanged,把IsFocused變更轉發成自身的PropertyChanged。Breaking Changes
無。
Migration Notes
無;純程式端修正,不需更動資料庫或本機 db。
- 新增介面
-
06-27 eorder-stale-english-cleanup-batch ▸
2026-06-27 訂單管理(E.Order)模組英文殘留中文化(批次)
摘要
延續 CUINVE/CUQT/CUPDMA,將 訂單管理(E.Order / 銷售訂單)整個模組 的 Source/XAML 英文殘留
系統性中文化。流程:先以多代理 inventory workflow 逐表單盤點+對 VFP 驗證每個英文 token 的分類,
再以對抗式驗證代理覆核高風險的「mapped DB 欄」判定,最後分兩波套用、逐波建置+提交。
涵蓋 40 支候選表單:24 支實作(DO)、16 支略過(SKIP)。
分類原則(每個英文 token)
類別 動作 判準 mapped DB 欄 保留英文 Model-backed + [TsColumnName],且 VFP*_v.<col>確認 DB 欄即英文(如 leadtime/email/website/cino/blno/reqno)。只翻欄位標題顯示文字SP/查詢 DTO 欄 保留英文 由 server SP 結果以屬性名對應(如 Cudatalimit 信用額度 grid、Ci_m1/OrderApprove/Odtosl 轉單 grid);改名會靜默清空 grid Excel 依名對應欄 保留英文 PreordPivotInput 的 CustomerCode/UnitPrice 由 Forecast.xlsx 表頭依屬性名匯入 介面成員 保留(已是中文) ISKU/IUnitPrice/ICustomerSKU/IPageHeaderNotes/ISelfDefined 等 NotMapped/TsSkip helper 改中文 UI plumbing;與既有 mapped 同名時加 Display/Binding後綴避免衝突失效英文 helper 砍除 全 repo grep 確認零 consumer 顯示文字 翻中文 XAML Header/Content/DisplayMeta/按鈕字實作清單(24 支)
- wave1(commit c73c6207):Cudata・CudataTab1・CudataTab2・Cudatalimit・Sample・Ormast・Salema・Odtosl・Orssma・Ci・Ci_m1
- wave2(commit 1cd031de):Pk・Preord・PreordPivotInput・Pi・Fillrate・Visit_q・Cmplain・Estsal・Cungma・Odtosladdi・WarrantyCard・OrderDuplicate・OrderApprove
- 先前(commit f7d4b18b):Cuinve・Cuqt・Cupdma(含 CupdmaSpecialQuery 轉 RadGridView)
略過清單(16 支)與原因
- 已是中文(無殘留):CudataAr・CudataStatistics・CudataTab3・Rtaxma・Invent1・Claim・Visit・Pdtsal・Culbl・Alledi
- 英文版本(刻意保留英文 UI):Ormast_s・Ormast_US・Cudata_US・Rma・Shiptoaddress・OrderApprove_Credit・Darbedittool
- 註:這些英文版/工具表單與主表單共用 Source,故主表單 helper 改名時其綁定路徑亦同步更新(顯示文字維持英文)
- 壞掉的空殼:Sample1(ProgramClass 佔位、VM 未實例化、開窗 NRE)
對抗式驗證攔截到的真實風險(已修正)
1. Ormast:原判 5 組 helper(SalesRepName1-3/TaxDescription1-3/Shipping*/Transaction*/ShippingAgentName)為死碼欲砍 → 實際被 Ormast_US/Darbedittool 綁定且 OrmastSave 有引用 → 保留(砍會編譯失敗+斷綁定)
2. Ormast 套用後建置攔截:helper
CustomerName/GroupCompanyName改名撞到既有 mapped客戶簡稱/集團簡稱→ 改為客戶簡稱Display/集團簡稱Display,同步修 Ormast/Ormast_US/Darbedittool 綁定與 C# caller3. Cudatalimit:3 個信用額度欄為 SP 結果依名對應 → 保留英文綁定(只翻標題)
4. PreordPivotInput:CustomerCode/UnitPrice 為 Excel 依名匯入 → 保留
Breaking Changes
- 各表單的英文 NotMapped/TsSkip helper 屬性已改中文名;少數失效 helper 已刪除。外部若以字串/反射引用舊英文名需同步改。
- 保留英文的 mapped DB 欄 / SP-DTO / Excel 欄綁定路徑不變。
Migration / 驗收
- 不需 DB migration(DB 本即中文 schema,本批為 code 端追平)。
- Runtime 未驗:24 支表單建議人工開窗驗收欄位顯示與存取;特別是 Preord 的
停用說明(VFP REPLACE 註解中,view 是否供值待確認)、各轉單/查價 grid 的 SP 欄位填值。
- 建置:Common/Model/LogicBll/ViewModel 全 exit 0、TsERP markup exit 0;per-form 掃描確認各表單自身改名識別字在自身 XAML 0 殘留。
-
06-27 dashboard-deck-redesign ▸
2026-06-27 主管儀表板「匯出簡報」改版(董事會財報風 + 修溢出)
摘要
把主管儀表板(EISDASH)的「匯出簡報」HTML deck 重新設計成專業、給老闆看的董事會財報風,並修正清單筆數多時內容被裁切、超出頁面的問題。功能、操作、輸出路徑與資料來源皆不變。
變更
LogicBll/M.EIS/主管儀表板/儀表板簡報Generator.cs全面改版(公開 API儀表板簡報資料/產生HTML不變,呼叫端EisdashViewModel.匯出簡報無須修改):
- 視覺(乾淨清爽風):冷調淨白底(
#F4F8FA)+ 白卡片 + 墨色字(#17212E)+ 清新藍綠主色 teal(#0E9488,用於眉標細線、KPI 頂條、排名數字、頁碼);封面為淺色薄荷漸層 + 墨字 + teal 邊角,輕盈通透。數字一律以襯線字型(Georgia)tabular 對齊排版,像印製的損益表。警示色用乾淨珊瑚紅(#E0524F)。趨勢圖:受訂深板岩藍、出貨 teal。- 只用系統字型(Georgia / Microsoft JhengHei / Segoe UI),維持離線即開、零外部相依。
- 封面眉標移除「TSERP」前綴(改為「主管儀表板 EISDASH」)。
- 各頁左右邊距加寬至 150px、KPI 頁字級與間距微調,避免 4 卡列右側貼邊。
修正
- 清單溢出:原本呆料 Top、逾期客戶以單欄表格塞進固定 1080px 版面,筆數多時(最多 12 筆)會超出頁面被
overflow:hidden裁掉。改為兩欄 ledger 版式(直排序、依筆數自動算每欄列數),12 筆只佔 6 列,並收緊上方標題/摘要的垂直間距,確保整頁含頁尾都容得下、不裁切。
- 筆數透明化:清單標頭顯示「共 N 筆 · 顯示前 M 筆」,超過 12 筆時明確標示僅顯示前段,不再靜默截斷。
行為
- 仍是當下顯示快照;← → 翻頁、F 全螢幕、視窗等比縮放(1920×1080 舞台)皆維持。
Breaking Changes
無。樣板與樣式更動,無 API / 資料 / 設定變動。
Migration Notes
無需 migration。
相關
- ADR 0048 — 匯出簡報採自包含 HTML deck(架構決策不變)
- 2026-06-21 主管儀表板新增「匯出簡報」
-
06-27 cuqt-stale-english-cleanup ▸
2026-06-27 客戶單品報價單(CUQT)英文殘留中文化
摘要
延續客戶產品表(CUINVE)的清理,將客戶單品報價單(CUQT)的 Source/XAML 英文殘留中文化。
三張 Source(cuqtm 主檔 / cuqtd 材料明細 / cuqtd1 加工明細)的欄位屬性早已中文化,本次處理剩下的
英文 NotMapped/Binding helper、一個失效的英文 mapped 屬性,以及
Cuqt.xaml仍是英文的 Label 與欄位標題。變更
Twork_ord_vw_cuqtm(主檔)
英文(舊) 處置 GroupDescription([TsColumnName(nameof(GroupDescription))]+ 私有 backing)砍除 — DB view 無此欄、永遠空白;群組說明的真實欄是既有 mapped 的 說明,XAML 改綁說明QuotationStaffName(NotMapped,報價人員姓名顯示)改名 報價人員姓名Twork_ord_vw_cuqtd(材料明細)
英文(舊) 中文(新) GroupDescription(NotMapped)群組說明SKUBinding(NotMapped,品號 seek)品號BindingQuotationDateBinding(TsSkip,幣別查匯率用日期)報價日期BindingUnitPriceBinding(TsBinding 單價)單價BindingQuantityBinding(TsBinding 數量)數量BindingTwork_ord_vw_cuqtd1(加工明細)
- Source 早已全中文,僅 XAML 兩個欄位標題中文化(見下)。
Cuqt.xaml
- 主檔 Label 中文化:
Quotation No:→報價單號:、Quotation Staff:→報價人員:、Quotation Date:→報價日期:、
Customer Code:→客戶代號:、Customer SKU:→客戶品號:、Minimum Order Quantity:→最低訂單量:、Vendor Code:→廠商代號:、Group Code:→群組代號:、Material Fee:→材料費:、Processing Fee:→加工費:。- 按鈕文字
Unit Price Adjust→單價調整。
- 群組說明輸入框由
{Binding GroupDescription}改綁{Binding 說明}(顯示真實 DB 欄)。
- 材料明細格標題/綁定中文化:
SKU→品號(綁品號Binding)、SKUDescription→品名、Group Description→群組說明、
Vendor Code→廠商代號、Vendor Name→廠商簡稱、Currency→幣別、Foreign Exchange Rate→匯率、UOM→單位、Quantity→數量(綁數量Binding)、Unit Price(本幣)→單價(本幣)(綁單價Binding)、幣別欄日期改綁報價日期Binding。- 加工明細格標題:
Processing Code→工程代號、Processing Name→工程簡稱。
Caller 連動修正
CuqtBll.AddDetail:SKUBinding/QuantityBinding/GroupDescription/UnitPriceBinding→品號Binding/數量Binding/群組說明/單價Binding。
CuqtViewModel:UnitPriceBinding→單價Binding、QuotationStaffName→報價人員姓名(2 處)、QuotationDateBinding→報價日期Binding。
Breaking Changes
- CUQT 三張 Source 的英文 helper 屬性已改中文名;主檔
GroupDescription已刪除(改用既有說明)。
外部若以字串/反射引用舊英文名需同步改。
Migration Notes
- 不需 DB migration(DB 本來就是中文 schema,本次為 code 端追平)。
- Runtime 未驗:CUQT 開窗、新增、取得資料(匯入 BOM)、單價調整、儲存需人工驗收。
-
06-27 cupdma-stale-english-cleanup ▸
2026-06-27 客戶產品報價(CUPDMA)英文殘留中文化
摘要
延續 CUINVE / CUQT 的清理,將客戶產品報價單(CUPDMA)的 Source/XAML 英文殘留中文化。
主檔(cupdma)與明細(cupdt)的欄位屬性早已中文化,本次處理剩下的英文 NotMapped/TsSkip helper,
並把
Cupdma.xaml仍是英文的 Label 與欄位標題全面中文化。變更
Twork_ord_vw_cupdma(主檔)helper 中文化
英文(舊) 中文(新) CurrencyPlaces(NotMapped,幣別小數位)幣別小數位ProjectName(NotMapped,專案名稱顯示)專案名稱CustomerCodeBinding(NotMapped,客戶代號 seek + 帶客戶資料)客戶代號BindingTwork_ord_vw_cupdt(明細)helper 中文化
英文(舊) 中文(新) Amount(NotMapped,金額)金額QuantityBinding(TsSkip)數量BindingForeignExchangeRate(TsSkip,取主檔匯率)匯率BindingCurrencyPlace(TsSkip,取主檔幣別小數位)幣別小數位BindingSetPrice()內部運算式同步改中文屬性。
Cupdma(指向主檔 Source 的型別參考)保留 — 它是實體參考、非資料欄位/非綁定路徑,命名沿用程式名。
保留的英文 mapped 欄位(DB 欄本身即英文,動了會破壞對應)
Twork_ord_vw_cupdmaSource.ProjectCode(Model-backed mapped 欄)。
Twork_ord_vw_cupdtSource.leadtime(VFP 確認 DB view 欄即客報價明細_v.leadtime)。
- XAML 該欄標題仍中文化為「前置天數」(顯示文字),綁定維持
{Binding leadtime}。Cupdma.xaml
- 主檔 23 個 Label 全面中文化(報價單號/報價別/報價日期/生效日期/客戶代號/客戶名稱/業務員編號/
聯絡人/電話/傳真/幣別/匯率/製表人員/活動起始日/活動截止日/預計結案日/實際結案日/最低毛利率/
有效天數/收付條件/專案代號/頁首備註/報價備註)。
- 主檔綁定:
CustomerCodeBinding→客戶代號Binding、ProjectName→專案名稱(2 處)。
- 明細格 27 個欄位標題中文化;綁定
QuantityBinding→數量Binding、Amount→金額。
Caller 連動修正
CupdmaViewModel.AfterMoverRecord:ProjectName→專案名稱(SetCurrencyPlaces()方法名保留,內部改設幣別小數位)。
- 明細
SetPrice()由e.Item.Cupdma(VM)/幣別匯率 weak event 觸發,運算改中文屬性。
CupdmaSpecialQuery.xaml(查價子面板)
CUPDMA 操作面板的查價子面板,本批一併處理:
TsDataGrid→TsRadGridView(dg-to-radgrid skill):外層容器、DataGrid.Columns、各欄類型轉換,
Binding→DataMemberBinding,v2:TsDateColumnV2→TsGridViewDataDateColumn(MaskInfo→ForceReadOnly),取價按鈕欄改
TsButtonInCell+ButtonCellCellStyle、Command 改RelativeSource AncestorType=TsRadGridView。ItemsSource="{Binding ItemsSource}"為一般集合(非 DataManager pattern),故不加 DataManager;保留外層ProgramClass。- 18 欄表頭全面中文化(取價/報價日期/報價別/客戶代號/客戶名稱/專案代號/專案名稱/地點/單價/品號/
數量/單位/數量2/單位2/備註/幣別/匯率/客戶品號)。
- 綁定維持原查價結果 POCO 的英文屬性(查詢 DTO,不在本次改名範疇)。
Breaking Changes
- CUPDMA 主檔/明細的英文 helper 屬性已改中文名。外部若以字串/反射引用舊英文名需同步改。
Migration Notes
- 不需 DB migration(DB 本來就是中文 schema,本次為 code 端追平)。
- Runtime 未驗:CUPDMA 開窗、新增、查價(FindPrice)、金額試算、儲存需人工驗收。
-
06-27 cuinve-stale-english-cleanup ▸
2026-06-27 客戶產品表(CUINVE)英文殘留中文化
摘要
客戶產品表(CUINVE,E-040)的 DB view(
vw_cuinve/vw_cuinvema)欄位早已中文化,但Source/Model 仍殘留少數英文屬性,且
Cuinve.xaml的欄位標題與 Label 仍是英文。本次以 VFPcuinve原始欄名(
包裝量/包裝量_箱/備註)為準,將殘留英文屬性改名為中文、砍掉重複的死屬性,並把XAML 標題與 Label 全面中文化。
變更
Twork_ord_vw_cuinvema(主檔)
英文(舊) 中文(新) Notes 備註 - Model、Source 同步改名;
[TsColumnName(nameof(Notes))]→[TsColumnName(nameof(備註))](DB 欄本為備註,原英文 mapping 載入永遠空白)。
- 保留 NotMapped helper
CustomerName(UI 查詢用,非 DB 欄)。
Twork_ord_vw_cuinve(明細)
英文(舊) 中文(新) MinimumPackageQuantity 包裝量 - Model 屬性
MinimumPackageQuantity改名包裝量;Source包裝量wrapper 改讀新名([TsColumnName]本就是包裝量,DB 欄不變)。
- 砍除 Model 死屬性
QuantityPerCarton(與既有中文欄包裝量_箱重複、無任何 caller)。
NotMapped UI helper 中文化
英文(舊) 處置 SKUBinding(明細,品號 seek 欄)改名 品號BindingCustomerName(主檔,客戶簡稱查詢顯示)改名 客戶簡稱Display(避開既有 mapped客戶簡稱)SKUDescription(明細)砍除(無任何 caller、未綁定、未賦值的死碼) CustomerName(明細)砍除(死碼) SalesRepName(明細)砍除(死碼) - 連動修正:
Cuinve.xaml(客戶 seekDescription+ 唯讀簡稱框 + 明細品號欄 binding)、CuinveViewModel.GetPrintViewModel(2 處讀取)、Twork_ord_vw_cuinvemaSource.RefreshDescription。
Cuinve.xaml
- 主檔 Label:
Customer Code:→客戶代號:、Notes:→備註:;{Binding Notes}→{Binding 備註}。
- 明細格 26 個欄位標題全面中文化(
LineNo_→序號、SKU→品號、SKU Description→品名、
Customer SKU→客戶品號、Minimum Package Quantity→包裝量、Quantity Per Carton→包裝量(箱)、Notes→備註等),沿用本檔既有 CY 欄位的字面中文 Header 寫法。Breaking Changes
Twork_ord_vw_cuinvemaSource.Notes、Twork_ord_vw_cuinveModel.MinimumPackageQuantity屬性已改中文名;
Twork_ord_vw_cuinveModel.QuantityPerCarton已刪除。外部若以字串/反射引用舊英文名需同步改。- NotMapped helper 改名/刪除:
SKUBinding→品號Binding、主檔CustomerName→客戶簡稱Display;
明細
SKUDescription/CustomerName/SalesRepName已刪除(皆為死碼)。Migration Notes
- 不需 DB migration(DB 本來就是中文 schema,本次為 code 端追平)。
- Runtime 未驗:CUINVE 開窗、新增、儲存需人工驗收欄位顯示與存取正常。
- Model、Source 同步改名;
-
06-27 cudata-cy-account-fields ▸
2026-06-27 — cudata 補 CY 會計欄位、聯絡傳真重排
摘要
客戶資料
cudata(CY 版)補回 VFPscx_ord_cypage2 的三個會計欄位,並整理第二分頁「詳細聯絡資訊」的電話/傳真排列。
新增
- 第二分頁「銀行帳戶與會計科目」群組(原「銀行帳戶」)加入:
- 帳戶代號 — 公司收款帳戶搜尋框,顯示帳戶簡稱。
- 應收科目 — 會計科目搜尋框,顯示科目名稱。
- 銷貨科目 — 會計科目搜尋框,顯示科目名稱。
- 公司傳真 補進第二分頁「詳細聯絡資訊」(原本只有 Tab1 有)。
變更
- 第二分頁「詳細聯絡資訊」電話/傳真改成並排兩列:
- 公司電話 | 公司傳真
- 工廠電話 | 工廠傳真
Migration Notes
這三個欄位是 CY 客戶(darbcycsa 家族)專屬。共用程式會 SELECT 這三欄,因此
每個 cudata 庫都要先於 SSMS 跑
sql/cudata_add_account_fields_CY.sql:- CY 庫:取消腳本 Section 1 註解後執行(建立實體欄位),再執行 Section 2(重建 vw_cudata)。
- 非 CY 庫:只執行 Section 2(vw_cudata 會以空字串常數投影這三欄)。
未跑前該庫開啟客戶資料會載入失敗。腳本可重複執行。詳見 ADR 0062。
-
06-27 bom-botm-include-no-process ▸
2026-06-27 最低階用料查詢還原「含無製程」選項
摘要
還原 VFP
scx_eng_cy中bom_botm(最低階用料 / BOM 底層展開查詢)的「含無製程」勾選框。此選項在 CY 版DARB_QRY_BOM_BOTM預存程序對應第 4 參數@查詢方式,新版 C# 先前固定不帶該參數,導致 CY 永遠走「無製程不展」分支,VFP 時代的展開模式無法觸發。新增
- 「最低階用料」查詢條件頁新增 「含無製程」勾選框(預設不勾)。
- 勾選 → 預存程序走
DARB_BIZ_BOMBOTTOM加含無製程,將無製程組件一併往下展開。- 不勾 → 維持原行為
DARB_BIZ_BOMBOTTOM無製程不展。變更
Bom_botmParameters新增含無製程(bool,預設 false)。
Bom_botmConditionViewModel新增含無製程屬性。
GetSqlData.GetTWORK_QRY_BOM_BOTM新增選用參數queryMode(預設"0"),映射到 dispatcher 的LP_P4(@查詢方式)。
Breaking Changes
無。
queryMode為帶預設值的選用參數,既有呼叫端不受影響。Migration Notes
- 不需資料庫變更。CY 庫
DARB_QRY_BOM_BOTM本就有@查詢方式參數(proc_param.param_qty=4)。
- 多客戶相容:NOGI 等
param_qty=3的庫,dispatcher 不會轉發第 4 參數,故新增的queryMode會被安靜忽略——對非 CY 客戶該勾選框無作用但不報錯,毋需 per-customer 分支。詳見開發者記憶darb-qry-bom-botm-cy-nogi-divergence。
-
06-26 tssearchtextboxv2-seek-validation-fixes ▸
2026-06-26 — 全域 seek 欄位(TsSearchTextBoxV2 / TsSearchRule)存在性驗證修復
摘要
修復共用搜尋輸入控件
TsSearchTextBoxV2與其驗證規則TsSearchRule的一連串問題:存在性驗證從未真正掛載、誤判正確資料為「資料不存在」、錯誤時不跳訊息、跳訊息後焦點被搶回造成洗版、以及清空儲存格後要點兩次按鈕。屬平台層共用控件,影響全 app 使用TsSearchTextBoxV2的 seek 欄位。變更
- 補上漏掉的
SetBinding(TsSearchTextBoxV2.OnApplyTemplate):
- 原本把
TsSearchRule/PrimaryKeyRule加到「深拷貝後的 binding」卻沒套回TextProperty,導致存在性驗證自始未生效。現於加完規則後BindingOperations.SetBinding套回(無規則時不重綁)。- 訊息框改由規則在「發現錯誤的當下」跳出(
TsSearchRule.Validate):
- 查無此代號時,由規則自身即時
TsMsgBox.ShowMessage(資料不存在),不再等失焦後事後檢查Validation.GetHasError(後者因 binding 來源更新晚於 class handler 而讀到舊狀態,永遠不跳)。-
SeekCondition未設定的設定錯誤亦即時跳窗。- 同一個錯誤值只跳一次窗(
TsSearchRule新增lastWarnedValue守門):
- 防止 Telerik 控件一次失焦驗證多次、或焦點抖動造成的訊息洗版;改成有效值或清空後重置守門,輸入新的錯誤值才會再提示。
- 移除錯誤時的焦點搶回(
TsSearchTextBoxV2.OnLostFocus):
- 先前用
Keyboard.Focus(this)把焦點釘回欄位,會與失焦驗證形成死迴圈(點按鈕→失焦→跳窗→焦點被搶回→再點→再跳…按鈕按不到)。改為僅保留紅框(ValidationResult)視覺提示,存檔時仍會被擋。- 清空儲存格即時清除殘留錯誤(
TsSearchTextBoxV2新增OnTextChanged):
- 規則只在失焦時重驗,把錯誤值刪成空白後仍掛著上一個值的錯誤狀態,使儲存格第一次點按鈕被吃掉(要點兩下)。改為文字清空時立即
Validation.ClearInvalid,空白是合法狀態,下次點按鈕一次生效;失焦時規則仍會重新驗證。- 移除驗證結果快取(
TsSearchRule):
- 移除
previousValue/previousResult快取。原快取會把載入當下暫時性的 false(Context/暫存表尚未就緒)寫死,導致之後正確資料也一直回「資料不存在」。改為每次重新判斷。背景
- 2026-06-25 SLIYBROWD 的 changelog 已點出
OnApplyTemplate漏SetBinding的問題,但當時刻意只在該支以 gridCellValidating就地補、未動全域控件。本次改為直接修平台層TsSearchTextBoxV2,全 app 的 seek 欄位一併受惠。
Breaking Changes
- seek 欄位的存在性驗證現在會真正生效(先前形同關閉):輸入主檔不存在的代號會跳「資料不存在」並標紅框。若有畫面原本「靠驗證沒生效」而能存入不存在代號,現在會被擋。
Migration Notes
- 無資料庫異動。存在性查詢沿用既有
TWORK_EXIST(DataValidate 平台),不需新登錄。
- 行為層面:在一般表單欄位,錯誤時不再強制把焦點留在欄位(改靠紅框 + 存檔擋)。
- RadGridView 儲存格情境:「打錯就擋住、強迫修正」是 grid 原生行為(
ActionOnLostFocus預設CommitEdit+ editorValidationRule失敗 → grid 將焦點退回該格),Tab 切格與點 grid 外按鈕都會被擋。經裁定維持此現狀,刻意不在 editor 加PreviewLostKeyboardFocus去區分「Tab 到輸入欄 vs 點動作按鈕」——那會與 grid 自身的焦點管理衝突。若日後想讓「點 grid 外按鈕(取消/關閉)可放行」,正確做法是把該 grid 的ActionOnLostFocus設為None,而非改 editor。
- 補上漏掉的
-
06-26 statistics-definition-chinese ▸
2026-06-26 統計定義中文化(特殊查詢統計面板)
摘要
客戶 / 廠商 / 品號「特殊查詢」統計面板的項目名稱與描述由英文改為繁體中文;
對應的值計算預存程序內的分支字面值同步改為中文(分支鍵維持用 StatisticsName),
並修復廠商採購額三項的計算。
變更
twork_sys_statistics_definition表 27 筆的StatisticsName、Description_
由英文覆寫為繁體中文(例:
Latest Quotation→最新報價單、MTD Sales (Order)→本月銷售額(訂單)、YTD Purchasing→本年採購額)。- 子程序
TWORK_STATISTIC_CUSTOMER/TWORK_STATISTIC_VENDOR/
TWORK_STATISTIC_INVENT的分支判斷字面值由英文改為對應中文(分支鍵仍為StatisticsName)。- 移除
@language參數:父程序與三支子程序簽章去掉@language;日期顯示固定yyyy/mm/dd;
QueryCondition中文化 REPLACE 改無條件套用。C# 端GetSqlDataWrapper.GetStatistic_definition、CudataBll.GetStatisticDataNew及三支 SpecialQuery ViewModel 一併移除語言引數(位置式參數改為 UserID/Classification/PartnerCode)。SQL 與 C# 須一起部署。
修復
- 廠商「本月/本年/去年採購額」(S003/S004/S005)原本因
vwbd_purch欄名不符而留空:
改用該 view 的
本幣未稅金額欄、並把日期條件對應到實體欄採購日期t,計算恢復正常(驗證:本年採購額 328800、去年採購額 995920)。
- 金額一律改用
本幣未稅:三支子程序所有SUM()金額欄由原幣未稅改為本幣未稅
(
vwbd_trsama出貨、vwbd_ormast受訂、vwbd_trrama進貨、vwbd_purch採購)。Dispatcher 登錄(darbnogilog1)
DARB_LOG_SYS_EXEC依proc_param.param_qty決定轉發參數個數。TWORK_STATISTIC_DEFINITION
移除
@language後參數由 4 → 3,故 darbnogilog1 的proc_param.param_qty由 4 改 3。- 部署腳本:
sql/twork_statistic_definition_procparam_darbnogilog1.sql。
Migration Notes
- 部署腳本:
sql/twork_statistics_definition_chinese_darbnogicsa1.sql
(以 Unicode 執行,例如 SSMS 或 SqlClient;勿用預設 codepage 的 sqlcmd,中文會漏寫)。
- 已部署於 darbnogicsa1。其他公司資料庫(darbcycsa1 / darbzdcsa1 等)若也使用此面板,
需另行套用同一腳本(並確認該庫
vwbd_purch欄名)。- 三者須一起部署:darbnogicsa1 程序、darbnogilog1 的
proc_param、C# 端
(移除
@language後參數位置改變;任一未更新都會參數錯位/過多)。- dispatcher
DARB_LOG_SYS_EXEC與proc_param在 log 庫 darbnogilog1,跨庫 EXEC 到 darbnogicsa1。
已走完端到端驗證(dispatcher → 跨庫 → 子程序)result=OK 並回傳中文統計列;C# 編譯通過。
注意
- 子程序分支鍵 = 顯示名稱(
StatisticsName)。日後再調整顯示文字時,務必同步更新三支子程序內
的字面值,否則對應項目的值會靜默變空白。
-
06-26 cuinve-delete-guard ▸
2026-06-26 客戶產品表(CUINVE)刪除防呆還原
摘要
對比 VFP
scx_ord_cycuinve.deleteclick後,補回「本程式不能執行刪除之功能」的整支刪除阻擋。新版原本無
CuinveEdit/CuinveDelete,刪除走 baseDeleteBll無條件允許,使用者可刪掉某客戶的整張客戶產品表(含所有產品列),與舊系統刻意禁刪的行為不符。變更
- 新增
LogicBll/Ade/E.Order/CuinveDelete.cs:覆寫BeforeDelete直接回false並帶出
「本程式不能執行刪除之功能」訊息(工廠以
<Pascal>Delete反射自動接上)。- 僅擋刪除:修改維持 base
EditBll允許(VFP 無allowedit擋修改)。明細列仍可在編輯時以
增刪修=D 標記移除,不受影響——本防呆擋的是主檔(整筆客戶產品表)刪除按鈕。
- 新增訊息鍵
MessageEnum.ThisProgramCannotDelete(Common/Language/MessageService.cs)
與
TsERP/Lang/Message.json對應條目(繁中「本程式不能執行刪除之功能」/ 英文)。修復(順帶)
- CUINVE / CUPDMA 畫面無法顯示:
App.xaml缺這兩支 ViewModel → View 的DataTemplate
(E.Order CY 路線檔案已建但 runtime 未驗的系統性遺漏)。已補上
CuinveViewModel→Cuinve、CupdmaViewModel→Cupdma兩個DataTemplate(含新增xmlns:cupdma命名空間),程式才能正常導覽載入。2026-06-28 追補:不支援刪除的提醒提前
原本「本程式不能執行刪除之功能」走
CuinveDelete.BeforeDelete,而BeforeDelete在DeleteBll.Delete()內才執行——使用者得先按刪除、跳「確定刪除?」確認、按下「是」之後才被告知不支援。- 新增
DeleteBll.IsDeleteNotSupported(out msg)虛擬方法(預設回false=支援刪除)。
CuinveDelete改覆寫IsDeleteNotSupported回true(取代原BeforeDelete覆寫)。
DeleteService.Delete()在最前面、跳確認對話框之前就先呼叫IsDeleteNotSupported,
整支禁刪的程式按下刪除鈕立即提示,不再先問「確定刪除?」。
DeleteBll.BeforeDelete仍呼叫IsDeleteNotSupported作為後端防線。
Breaking Changes / Migration Notes
無資料庫變動。
Message.json需隨版散佈;MessageEnum與 BLL 一起編譯部署即可。 - 新增
-
06-26 cudata-tab-fields-actually-applied ▸
2026-06-26 客戶資料(CUDATA)Tab1/Tab2 欄位實際補回(修正 2026-06-25 文件脫節)
摘要
2026-06-25 的 changelog(
2026-06-25-cudata-vfp-field-restore.md)記載 CudataTab1 與CudataTab2 已補回多個 VFP
scx_ord_cy對比缺漏的欄位,但實際 XAML 從未寫入——當時只加了
Twork_ord_vw_cudataModel的屬性,畫面綁定遺漏(git 亦無對應 commit)。本次將該批欄位實際補進 XAML 並建置通過(VS MSBuild
TsERP.csprojEXIT=0)。新增(Tab1 基本資料)
- 直接出貨、附成績單、轉廠(Y/N 旗標,
YesNoComboBox,置於基本資料群組 Row 2 第 4–9 欄)
新增(Tab2 財務)
- 新群組「詳細聯絡資訊」:負責人、身分證字號、負責人電話/分機、會計、聯絡人職稱、
會計電話/分機、聯絡人2、工廠傳真、聯絡2電話、聯絡2分機、聯絡1分機
- 新群組「公司概況與交易」:國家別、客戶區域、交易方式、成立時間、收款日、營業項目、
稅籍號碼、關係人(關係人為
YesNoComboBox,比照 SpdataTab1/廠商資料慣例)- 新群組「徵信記錄」(多行 memo)
- 財務資訊群組新增:技術報酬金、佣金(
TsNumericTextBox,兩位小數)
變更(版面)
- CudataTab2 主體 Grid 由單列改為兩列:原四個群組(銀行帳戶/財務資訊/帳款與物流設定/
詳細聯絡資訊)維持第 1 列,新增之公司概況與交易、徵信記錄置於第 2 列。
Breaking Changes / Migration Notes
- 技術報酬金 / 佣金為新 DB 欄位:
cudata表與vw_cudataview 原本沒有。
部署前必須先於 SSMS 對每個目標庫(darbnogicsa1 / darbcycsa1 / production)執行
sql/cudata_add_commission_techfee_darbnogicsa1.sql(ALTER TABLE 加兩欄 + 重建 view)。未執行前若儲存客戶資料會因欄位不存在而失敗。
- 其餘欄位皆為既有 DB 欄位,純補 UI,無需 migration。
備註
- 本條目為「文件與實作脫節」之修正紀錄;2026-06-25 changelog 描述之意圖至此才真正落地。
- 後續若再發生「changelog 已記但 XAML 未綁」情形,請以 build + 實查 binding 為準
(參照記憶
vfp-compare-cross-check-xaml-binding)。 - 直接出貨、附成績單、轉廠(Y/N 旗標,
-
06-26 browse-query-sql-injection-hardening ▸
2026-06-26 瀏覽/查詢 SQL Injection 防護
摘要
修補瀏覽/查詢條件產生器的 SQL Injection 風險:字串值跳脫、非 Int32 數值欄補驗證、Between 結束值也驗證,並把「自定義」查詢條件文字框改為唯讀,關閉使用者手打 raw WHERE 的入口。屬安全性修補,純 C# / XAML 變更,不動資料庫。
變更
- 字串值跳脫(
ViewModel/Browse/BrowseConditionHelper.cs):新增Esc()(單引號'→''),套用到所有把字串嵌進N'...'的分支:等於/不等於/大於小於(A~FString)、like(G/H/I/J)、In 清單(K/LString 逐項)、Between(Q起始+結束值)。
- 數值型驗證(
ViewModel/Browse/BrowseConditionChecker.cs):原本只驗Int32/DateTime/Boolean,新增Decimal/Double/Single/Int64/Int16/Byte/SByte,以逗號切分後逐 tokendecimal.TryParse(同時支援單值與 In 清單);非純數字擋下並提示「請輸入數字」。
- Between 結束值驗證 + 無值運算子豁免(
BrowseConditionHelper.GenerateCondition):Between(Q)的結束值一併驗證(原本只驗起始值);IsNull/IsNotNull/IsEmpty/IsNotEmpty/不考慮/R等不吃輸入值的運算子豁免值驗證。
- 自定義條件輸入框唯讀(
TsControl/Themes/TsStyles.xaml,inv:InventQueryControlTemplate):綁SelfDefinedCondition的TsTextBox加IsReadOnly="True",覆蓋共用此控件的 Cudata/Invent/Spdata/Ginvent。
行為變更(使用者可見)
- 數值欄輸入非數字(含 Between 結束值)會被即時擋下並提示,而非送出後由 SQL 報錯。
- 查詢條件區的「自定義」文字框不再可手動輸入;點選預先定義的特殊查詢仍正常產生條件並查詢。
- 修正一個既有副作用:對數值欄做「IS NULL/IS NOT NULL/IS EMPTY」等不需輸入值的查詢,現在不再被誤要求「請輸入數字」。
Breaking Changes
- 無 API/資料庫破壞性變更。唯一行為差異是「自定義」文字框改唯讀,若有流程依賴使用者在該框手打 SQL 條件,將無法再使用(此即本次刻意關閉的注入入口)。
Migration Notes
- 純前端變更,無部署腳本、無 DB/範本檔需求;不影響呼叫
QueryAndStatistics的各表單契約。
- 已用 VS 2022 MSBuild 建置
ViewModel、TsControl通過(exit 0)。
注意(後續待辦,非本次範圍)
- DB 層二階注入未處理:
TWORK_STATISTIC_CUSTOMER等子程序把客戶代號裸拼進QueryCondition(CudataSpecialQuery 來源)、GetSqlData.cs的GetCustomerSKU/GetARAllowan同類;以及 SPTWORK_BD_VIEWLIST的QUOTENAME/連線帳號降權。詳見 ADR 0061。
- 字串值跳脫(
-
06-26 app-datatemplate-restore-h-p ▸
2026-06-26 補回 App.xaml 缺漏的程式 DataTemplate(H.Inventory + P.Invoice 批次)
摘要
延續 E.Order 批次,補上 H.Inventory 與 P.Invoice 缺漏的 VM→View
DataTemplate(缺了會導覽不出畫面)。變更
TsERP/App.xaml:- 新增
xmlns:inventory(ViewModel.H.Inventory)、xmlns:inventory1(TsERP.H.Inventory)命名空間
(此模組原本完全沒有任何 prefix——
invent:是 D.Bom.Invent,不是它)。- P.Invoice 10 支(
invoice:/invoice1:):Tick3、Ticka、Ticka_disc、Ticka_rej、
Ticka_voidrp、Tickmin、Tickr、Ticks、Ticksr、Tother。- H.Inventory 9 支(
inventory:/inventory1:):Bol、Invrec、Jobcode、Splace、
Trinout、Trlima、Trlost、Trrama、Trsama。排除(誤報修正)
- MasterFile(PRIMEEDI810)不補:
MasterFileViewModel雖 overrideProgramClass且繼承
ERPProgramViewModel,但實為Edi_ExportViewModel的內嵌子 VM(Edi_ExportViewModel內new並以property 持有,畫面由
Edi_Export.xaml內聯DataTemplate宿主),且無獨立 View → 非可導覽程式,不需 App.xaml DataTemplate。屬靜態啟發式的預期誤報。
驗證
MSBuild TsERP.csproj /t:MarkupCompilePass1exit 0(19 個 DataType 與 View 型別全解析)。待辦
原 62 支缺漏:已補 E.Order 10 + H.Inventory 9 + P.Invoice 10 = 29,MasterFile 誤報排除 1,剩 32 支
(C.GeneralAffair 8、I.ARAP 5、J.QC 5、F.Production 4、G.Purchasing 4、A.SystemData 2、L.Communication 2、
D.Bom 1、K.Cost 1)分模組逐批補。建議 runtime 逐支導覽確認。
- 新增
-
06-26 app-datatemplate-restore-eorder ▸
2026-06-26 補回 App.xaml 缺漏的程式 DataTemplate(E.Order 批次)
摘要
延續 Cuinve/Cupdma 的修復,系統性盤點
App.xaml:找出所有 overrideProgramClass且繼承導覽型base(
ERPProgramViewModel/ErpProgramWithDetailViewModel)卻沒有 VM→ViewDataTemplate的程式(任何 ResourceDictionary 都查不到 → 導覽時畫面無法顯示)。全專案共 62 支,本批先補 E.Order 10 支。
變更
TsERP/App.xaml新增 10 個DataTemplate(VM 在ViewModel.E.Order=order:,View 在TsERP.E.Order=order1:):Ci、Cuqt、Preord、Salema、Rma、Sample、Visit、Shiptoaddress、Fillrate、WarrantyCard
(其中 Ci/Cuqt/Preord/Salema 即 scx_ord_cy 移植、先前標「檔案已建但 runtime 未驗」的那批。)
驗證
MSBuild TsERP.csproj /t:MarkupCompilePass1exit 0(10 個 DataType 與 View 型別全解析;避開執行中 MCP server 鎖 DLL 的 copy 步驟)。待辦
其餘 52 支(C.GeneralAffair 8、H.Inventory 10、P.Invoice 10、I.ARAP 5、J.QC 5、F.Production 4、G.Purchasing 4、A.SystemData 2、L.Communication 2、D.Bom 1、K.Cost 1)分模組逐批補。
建議 runtime 逐支實際導覽確認能顯示。
-
06-26 alledi-newyamaha-parser-rewrite ▸
2026-06-26 alledi 新YAMAHA parser 重寫(對齊 VFP Page19 / YDS.TXT)
摘要
alledi「新YAMAHA」分頁的解析器原本整支寫成 Page1 舊 YAMAHA 的格式(SDF 固定欄寬、讀
YAMAHA.TXT、單軌 ORMAST),與本頁(VFP Page19 / EDI-P19-YAMAHA)完全不符。本次依 VFPp19yamaha查詢鈕.Click(8089-8353)整支重寫。變更
- 來源檔改為
C:\轉EDI資料\YDS.TXT(逗號分隔 CSV,VFPAPPEND ... DELIMITED),不再是 SDF 固定欄寬的YAMAHA.TXT。VM 預設檔名同步更新。
- 欄位對映改為 YDS.TXT 的逗號欄序(順序/訂單輸入日/追加刪除/客戶品號/交貨地點/客戶訂單號/預訂交期/數量/單位/包裝量…),只取
追加刪除='A'列;略過檔頭列。
- 客戶品號格式重整
xxx-xxxxx-xx-xx-xx(VFP 8192),再以 cuinve 依「該列預訂交期 + 交貨地點」反查品號。
新增
- 5 期工作日攤分演算法(VFP 8264-8333):依 6 個日期輸入(下二~下六起始日 + 下六截止日)切 5 段,落在各段的數量累加進 N2T~N6T 桶(鍵:客戶品號+品號+交貨地點+單位),再以「基數 100 × 工作天數」倍數攤分、逐工作日攤平成多列。
- 日期分配表(VFP 8117-8156):每段把交期每隔 5 個工作天分配一筆、超出再補洞,決定每筆攤分列的交期。
- 特例:品號含
*P(P 件不拆單)或 預訂交期早於下二起始日 → 直接成一列、不攤分。
- 雙軌目標單據(VFP 轉單鈕 8361-8623):列的
客戶訂單號非空 → ORMAST(轉至訂單);空 → PREORD(轉至預示)。攤分(預示)列一律 PREORD。
- 6 個日期輸入框的值由 VM 帶入 BLL;必填 + 嚴格遞增驗證(VFP 8101-8108)。
工作日曆(已接真正的 LCL工作日曆)
UPDT_WKDAYS/UPDT_BACKWKDAY_LCL已接真正的工作日曆(含假日):BLL 預設用Util_Pdt(從本機 SQLite 暫存表LCL工作日曆載入,沿用既有Updt_WkDays/Updt_BackWKDay_Lcl,與 VFP 同義)。
WorkDaysBetween/BackWorkDay仍可覆寫(單元測試用);當工作日曆載不到(如未登入 / 測試環境)時自動退「日曆日」保底。
已知限制(後續階段)
- 需以真實
YDS.TXT樣本檔 + DB(cuinve 反查 + LCL工作日曆 已載入)runtime 驗收欄位座標與攤分交期。
Breaking Changes
無(行為從「錯誤格式」修正為正確格式)。
Migration Notes
無需 migration。
- 來源檔改為
-
06-25 sliybrowd-edit-gate-and-seek-validation ▸
2026-06-25 — 會計日記帳(SLIYBROWD)修改鈕守門 + seek 欄位存在性驗證
摘要
修正會計日記帳查詢頁(SLIYBROWD)修改模式的兩個問題:修改鈕可被任意切換、以及可輸入的代號欄位(項目編號等)不檢查是否存在。對齊 VFP
scx_acc原行為。變更
- 修改鈕守門(
SliybrowdViewModel.Edit()):
- 已在修改模式時再按「修改」不再重新進入 —— 避免重置每列
IsChanged/增刪修把使用者已做的變更追蹤洗掉(按修改→改幾格→又按修改 會靜默清空、儲存等於沒存)。- 需具該程式「可否修改」權限才允許切入修改模式;無權限時跳訊息並維持唯讀。
- 對應 VFP
ledit.Click守門條件「LSAVE.ENABLED=.F. AND IS_可修改」。- seek 欄位存在性驗證(
Sliybrowd.xaml.cs新增CellValidating):
- 修改模式下,項目編號/部門代號/客廠代號/員工編號/專案代號等 seek 欄位提交前會檢查代號是否存在於主檔,查無此代號就擋下提交、焦點留在格內、跳「資料不存在」。
- 空值與
MISC(雜項)不檢查,比照既有TsSearchRule行為。背景
- 既有平台
TsSearchTextBoxV2.OnApplyTemplate把TsSearchRule(存在性檢查)加到「深拷貝後的 binding」卻漏了SetBinding把它套回控件,導致 seek 控件的存在性驗證從未生效(此修正先在 SLIYBROWD 這支以 gridCellValidating就地補上,未動全域TsSearchTextBoxV2,避免影響全 app 其他 seek 欄)。
- VFP 原版實際只開放編輯 摘要/部門代號/專案代號/分類索引1/分類索引2 五欄;新版 grid 另外放開了 項目代號/客廠代號/員工/分類索引3、4。本次先補驗證,是否要把這幾欄改唯讀以完全對齊 VFP 待裁定。
Breaking Changes
- 無「可否修改」權限的使用者,原本能切入修改模式,現在不行(屬權限修正)。
Migration Notes
- 無資料庫異動。存在性查詢走既有
TWORK_EXIST(DataValidate 平台),不需新登錄。
- 修改鈕守門(
-
06-25 scx-ord-cy-feature-completion ▸
scx_ord_cy(CY 朝陽/鈞寶 訂單模組)功能補完
日期:2026-06-25
摘要
依 VFP
scx_ord_cy全模組對比 + 逐欄位(每個 TextBox/Column)稽核結果,補回新版 TsERP 缺漏的欄位驗證/連動/機制。多客戶分歧依 ADR0050 以
Context.Env.CompanyShortName == "朝陽" || "鈞寶"護欄包覆,不污染非 CY(US/NOGIHISA)行為。本批為 ultracode 多代理人協作(對比→稽核→驗證設計→套用)。
新增(universal,全客戶受惠)
- cupdma:選品號帶 leadtime/最低包裝數/最低訂單量/規格/中文描述;master 補綁 最低毛利率/有效天數;最低毛利率≤0 擋存。
- salema:明細品號查無/停用 存檔驗證。
- preord:控制面板補「調整數量」(交期區間×比率)、「交期變更」(工作日曆回推、*P 用 P件天數)。
新增(cy-specific,朝陽/鈞寶 護欄)
- preord:朝陽+客戶 AZY/AZZ 跳過客戶品號反查。
- cuqt:CY 模具/治具各自獨立分母分攤(非 CY 維持新價台數)。
- pk:A07 客戶箱號前置文字='CY'。
- salema:'單價'$IS_備註 權限隱藏 單價/金額 欄。
- estsal:明細帶 SK_INVENT 停用/停用說明/停用日期 唯讀欄;交期排序鈕(品號+預訂交期重編序號)。
- ormast:預訂交期→依客戶 leadtime 工作日曆回推 回覆日期 + 出貨日90日提示;客戶訂單號帶下空白明細。
- pdtsal:grid 客戶簡稱 顯示欄(IsCyCompany 才顯示)。
- ormast(needs-service/reuse):客戶品號→反查 cuinve 帶 品號/包裝量/單價(reuse GetCustomerSKU,無新 SP)。
- 基建:
EnvShortcut.CompanyShortName(供全模組公司分流)。
跳過(使用者裁定)
- 金額幣別小數位(salema GetAmount 維持 round-2,不動金額計算)。
- 所有「列變色 / 動態底色 / 前景色」(cuinve/pdtsal/estsal DynamicBackColor、cuinve 品號變紅)。
- 快速審核(QuickApproval)。
⏳ 待辦(外部相依,本環境無法完成驗證)
1. needs-service(reuse-existing,已設計、同 ormast 客戶品號反查 pattern,待套用):
- estsal 客廠品號↔品號 雙向反查(reuse SetSKUByCustomerSKU/SetCustomerSKUBySKU)+計算單價鈕(DARB_BIZ_CUST_UNITPRICE)
- cupdma 客戶品號→反查品號(reuse GetCustomerSKU)
- preord 客戶品號反查補 預訂交期+交貨地點 第 4 參數 + 查無客戶品號存檔擋
- cuinve 明細唯讀顯示欄(庫存管制/管制說明/停用/群組/設變,reuse Darb_GetData4 'invent')
2. pdtsal「計算資料」鈕(CY 核心,~420 行):跨 preord/ormast/pdtinf/cost/交易單/cupdt 彙總自動產生產銷計畫。
- ⚠️ 依賴 DB view
vw_pdtsal交易單(新庫不存在),須先在 DB 建該 view(資料庫物件,非 SP);之後寫PdtsalCalculateBll+ grid2 成本匯率輸入 + RelayCommand。無此 view 無法取上月庫存/生產實績/銷售實績。3. alledi(CY 機車 OEM EDI 轉訂單,18 個在用分頁):整支未移植。
- 在用分頁:鼎豪/SYM/SYM預示/慶俊訂單/慶俊預示/YMTT/YMTT預示/泛用取品號/年度銷售/SY_BOM/SY計劃/SYM-2W/新YAMAHA/新SUZUKI 等。
- ⚠️ 無法靜態完成:各廠 XLS/XLSX/CSV/PRN(SDF) 解析的欄位起訖/Cell 座標/表頭列數/編碼,須拿
C:\轉EDI資料\下真實樣本檔逐欄校對;cuinve 反查須朝陽/鈞寶實機 DB;上傳須跑 INPUT-BB dispatcher(PREORD/ESTSAL/BOM 上傳路徑各須實測);Telerik SpreadProcessing 解析 API 下筆前須查 telerik-dpl-assistant。建議參考既有LogicBll/E.Order/Darbedittool/(Amazon/EBay/Walmart)架構,逐廠單頁 runtime 驗收。如何檢查
- 建置:VS MSBuild
TsERP\TsERP.csproj(已全程 exit 0)。
- 業務驗收(須在朝陽/鈞寶庫,CompanyShortName=朝陽/鈞寶):
- cupdma:選品號→單位/leadtime/包裝/訂單量自動帶;最低毛利率輸入 0 存檔應擋。
- preord:填交期區間+比率按「調整數量」;按「交期變更」交期回推。
- ormast:輸客戶品號→自動帶品號/單價;改預訂交期→回覆日期回推 + 超90日提示;改主檔客戶訂單號→空白明細帶入。
- salema:權限備註含「單價」者,單價/金額欄應隱藏;明細輸停用品號存檔應擋。
- estsal:明細顯示停用欄;按交期排序序號重編。
- pk:A07 客戶存檔後明細前置文字=CY。
- 非 CY 庫(如禾久)以上 cy 行為應不觸發(護欄)。
-
06-25 operationforecast-fork ▸
2026-06-25 — 新增「營運預測模擬」、原「生產計劃查詢」回歸精簡
摘要
把生產計劃查詢(pd_qry7)拆成兩支:新增獨立的「營運預測模擬」做為前瞻分析/模擬的第二版,
原「生產計劃查詢」回歸只保留 VFP 三頁 + 金流預測。詳見 ADR 0056。
新增
- 營運預測模擬(OperationForecast) 全新程式,為 pd_qry7 的完整 fork(自有 Model/Source/SP/BLL/VM/XAML)。
分頁與目前生產計劃查詢相同:訂單預示預估、生產計畫、使用量、原物料用量(庫存缺口)、金流預測、模擬插單、產能負荷(需求)、樞紐分析。
- 7 支專屬 SP:
TWORK_QRY_OPERATIONFORECAST、TWORK_QRY_OPFCST_{GETORDER,PRODORDER,OTHERDATA,SUPPLY,CASHBASE,WKLOAD}。
- SQL 部署腳本:
sql/TWORK_QRY_OPERATIONFORECAST_darbnogicsa1.sql、sql/TWORK_QRY_OPFCST_EXT_darbnogicsa1.sql、
sql/TWORK_QRY_OPFCST_WKLOAD_darbnogicsa1.sql(+_darbcycsa1.sql)、登錄腳本sql/營運預測模擬_register_program_darbnogicsa1.sql。變更
- 生產計劃查詢 移除四個分頁:原物料用量、模擬插單、產能負荷(需求)、樞紐分析;
保留:訂單、預示及預估/生產計畫/使用量(機種別)/金流預測。
刪除
- 原「生產計劃查詢」清除被移除分頁的 dead code:
- VM 的 模擬/產能/缺口彙總·明細/樞紐 成員、code-behind 樞紐 handler。
- BLL 的
RunSimulation/BuildWorkCenterLoad/WorkCenterLoads與只給模擬用的快取。- 檔案
WorkCenterLoadPoco.cs、SimulationOrderPoco.cs、ProductionplanDrillDownViewModel.cs、生產計劃查詢明細.xaml(.cs);類別ShortageSummaryPoco。- XAML 的
OrderPivotProvider、ShortageRowBackgroundConverter、模擬累計折線與圖例。- 保留:
BuildShortage/ShortageCalculator/ShortageRows與 Supply/CashBase SP — 金流預測的計劃預測層仍需缺口計算。Breaking Changes
- 無(原程式碼識別、ProgramClass、SP 名皆未改;只是分頁變少 + 多一支新程式)。
Migration Notes
- 「營運預測模擬」要能從選單開啟,需在每個目標資料庫部署上述 4 支 SQL(SP+proc_param)並執行登錄腳本。
sqlcmd 跑含中文 UTF-8 無 BOM 腳本要加
-f 65001;朝陽 darbcylog1 的 proc_param.pkid 是 IDENTITY,WKLOAD 用_darbcycsa1.sql版。- 原生產計劃查詢無需任何 DB 變更。
-
06-25 localization-chinese-keys ▸
2026-06-25 — 本地化採「中文當鍵」(additive)
摘要
多語言查表改用中文當鍵:JSON 新增中文鍵別名(保留英文鍵),讓佔 85% 的中文鍵 XAML 綁定能直查到譯文、切換非中文語言正確翻譯。詳見 ADR 0055。
新增
Common/Lang/Xaml/*.json:94 檔新增共 2060 個中文鍵別名(指向同一譯文物件)。
變更
- 還原 Checkpay pilot:
Checkpay.xaml由 PascalCase 鍵改回中文鍵(中文鍵現可直查命中)。
JsonLocalizationStore:移除先前的反查 fallback(中文鍵直查即命中,反查冗餘)。
Breaking Changes
無(英文鍵 JSON 條目保留,77 個英文鍵 XAML 檔零回歸)。
Migration Notes
- runtime 需 Rebuild TsERP 套用 JSON 變更。
- ⚠️ 類別產生器(repo 外)仍輸出 PascalCase 鍵,下次重跑 JSON 會覆寫中文別名(待後續同步生成器)。
- 25 筆撞名(同 class 兩屬性共用同一中文)只保留一個中文別名,待人工檢視。
-
06-25 flowcast ▸
2026-06-25 — 新增「金流預測」(flowcast)
摘要
新增獨立的金流預測程式,用票據/帳款/訂單採購單 三來源推未來現金(月堆疊柱+累計淨額線)。詳見 ADR 0057。
新增
- 金流預測(flowcast) 程式(ProgramClass
FLOWCAST,M.EIS):
- 一支 SP
TWORK_QRY_FLOWCAST回 4 RS(票據/帳款/訂單未交/採購未交)。-
FlowcastComposer(純函數)合成統一現金事件+月彙總/堆疊;到期日接PayTermDate。- UI:來源勾選(票據/帳款/訂單/採購)+月堆疊柱(收上付下)+累計淨額線+資金警戒線+點柱過濾明細。
- 檔:
Model/SQLProcedure/Twork_Qry_Flowcast/*、LogicBll/M.EIS/Flowcast/*、ViewModel/M.EIS/Flowcast{,Condition}ViewModel.cs、TsERP/M.EIS/金流預測{,Condition}.xaml。
- SQL:
sql/TWORK_QRY_FLOWCAST_darbnogicsa1.sql、sql/flowcast_register_program_darbnogicsa1.sql。
口徑重點
- 票據:收 CA/CB/CF、付 CP/CQ(排除 CC/CD 融資);現金日預兌日優先。
- 帳款:rp_m 未沖,方向用 rpdef.單據分類(AR+ 收/AP+ 付);費用申請只算 9B+83 的「6.直接沖帳」;排除預收/預付/暫付/待抵;立帳起日預設近一年。
- 訂單採購:未交=數量−已交數量,非結案;金額本幣含稅按未交比例;現金日回覆日/預訂交期+收付條件。
- 三來源靠票況/單據分類/已交數量分界,零重疊。
Breaking Changes
- 無(全新程式;既有 OperationForecast 的金流分頁不受影響)。
Migration Notes
- 每個資料庫部署
TWORK_QRY_FLOWCASTSP(含 proc_param)+執行登錄 SQL 後,重啟即可從選單開「金流預測」。
- sqlcmd 跑含中文 UTF-8 腳本要
-f 65001(或轉 UTF-16);其他庫 cy/zd/production 各自部署。
- 金流預測(flowcast) 程式(ProgramClass
-
06-25 dev-parameter-registry ▸
2026-06-25 開發用本機臨時參數檔(dev-prgpar.json)
摘要
延續
dev-programs.json(ADR 0054),新增參數版:開發中的新程式需要專屬參數時,可先把臨時參數寫進 repo 內dev-prgpar.json,登入時合併進記憶體參數表,使U_Prgpar(...)不必先寫 DB_prgpar即可讀到。僅開發機啟用,正式環境不受影響。新增
TsERP/dev-prgpar.json:本機臨時參數檔(放 repo、複製到輸出目錄)。欄位對齊_prgpar(programClass/name/value/description/category/categoryDescription),預設parameters: []附範例。
Common/Environment/DevPrgparRegistry.cs:讀 JSON → 合併進ParameterList的載入器(同名鍵覆寫、新鍵新增)。
EnvironmentSetting.DevParametersEnabled靜態旗標;啟動時由App.xaml.cs從設定讀入。
appsettings.example.json新增DevParameters:Enabled說明。
變更
UserBll.GetParameters():建好ParameterList後,旗標開啟時合併dev-prgpar.json的臨時參數。
啟用方式
在
%ProgramData%\TsERP\appsettings.local.json加:{ "DevParameters": { "Enabled": true } }於
dev-prgpar.json的parameters陣列加參數並重新登入;程式內以Context.User.U_Prgpar("名稱")讀取。Breaking Changes
無。Production 不設旗標 → 完全 no-op。
Migration Notes
- 範圍只覆蓋記憶體
U_Prgpar。Util2017.U_PrgparSql(每次查 DB)與「目前表單參數」編輯器(直接讀_prgpar)不受影響。
- 同名鍵:臨時值覆寫已載入的 DB 值(開發時可暫時試不同值)。
- 還原到資料庫:依各筆
programClass開該程式的「目前表單參數」編輯器照值重輸存檔即可(不自動產生 SQL)。
-
06-25 cudata-vfp-field-restore ▸
2026-06-25 客戶資料(CUDATA)補齊 VFP 缺漏欄位與驗證
摘要
以 VFP
scx_ord_cy的cudata逐欄交叉比對現行畫面,補回「資料層有、UI 沒綁」的欄位、新增兩個資料庫欄位,並補回一條輸入驗證。新增(Tab1 基本資料)
- 直接出貨、附成績單、轉廠(Y/N 旗標,置於基本資料群組)
- 英文簡稱、英文名稱
- 工廠電話(聯絡資訊群組;Tab1 電話僅保留公司電話+工廠電話)
- 發票地點、請款郵遞號(地址資訊群組)
新增(Tab2 財務)
- 新群組「詳細聯絡資訊」:負責人、負責人電話/分機、會計、會計電話/分機、聯絡人2、聯絡2電話、聯絡1/2分機、聯絡人職稱、身分證字號、工廠傳真
- 新群組「公司概況與交易」:國家別、客戶區域、交易方式、成立時間、收款日、營業項目、稅籍號碼、關係人
- 新群組「徵信記錄」(多行)
- 財務資訊群組新增:技術報酬金、佣金
變更(行為)
- 帳款起始日:輸入時驗證須為 1~31(對應 VFP
帳款起始日.Valid),於CudataSave.AllowSave。
Breaking Changes / Migration Notes
- 技術報酬金 / 佣金為新欄位:
cudata表與vw_cudataview 原本沒有。
部署前必須先於 SSMS 對每個目標庫執行
sql/cudata_add_commission_techfee_darbnogicsa1.sql(ALTER TABLE 加兩欄 + 重建 view)。未執行前若儲存客戶資料會因欄位不存在而失敗。
- 其餘欄位皆為既有 DB 欄位,純補 UI,無需 migration。
未處理(依需求略過)
- 聯絡人明細 grid 的 skype / msn / facebook / 呼叫器 4 欄(D 類,刻意忽略)。
-
06-25 alledi-tab-display-restore ▸
2026-06-25 alledi 各分頁顯示還原(對齊 VFP)
摘要
alledi(CY 機車 OEM EDI 轉訂單工具)原本 14 個分頁共用同一個簡化版面(固定 11 欄表格、版面全相同)。逐頁對照 VFP 後,把各頁顯示內容還原成與原版一致:各頁專屬表格欄位、客戶選擇器、日期/年月輸入框、小計、Excel/DBF/篩選/重新檢查等按鈕、正確的轉單鈕文字,並修正會讓分頁壞掉的預設檔名。架構改為 per-tab DataTemplate(每頁一個 VM 子類 + 一個對應 DataType 的 DataTemplate,見 ADR 0058)。 顯示與轉入已就緒、轉單上傳走既有
AllediUploadBll;各廠轉單深層規則(報價/單位反查、工作日攤分、版次、.XLS 舊檔、新YAMAHA 重寫)須真實樣本檔 + DB runtime 驗收,屬後續階段。變更
- 預設檔名修正(原本錯誤,部分會導致分頁無法使用):
- SYM:
VMEP.XLS→640C.TXT- SYM預示:
YAMAHA.PRN→640C.TXT- 慶俊訂單/慶俊預示:
640C.TXT→A09.XLS- 新SUZUKI:
SUZUKI.TXT→SUZUKI_A.TXT(B/C 檔由同目錄推導;原檔名會直接 FileNotFound)- 轉單鈕文字依各頁還原(原一律以「是否含預示」推導):SY_BOM=轉至BOM、SY計劃=轉至預示、SYM-2W=轉至年度預估、新YAMAHA/新SUZUKI=轉至訂單及預示、泛用取品號=產生EXCEL、年度銷售=產生DBF,其餘維持轉至訂單/轉至預示。
- 表格欄位改為各頁專屬(對齊 VFP 各頁 cursor 欄位),不再固定 11 欄。
新增
- 各頁還原 VFP 專屬控件:
- 客戶代號選擇器(各頁預設 A01/A02/A04/A07/A09/A33)。
- 日期/年月輸入框:SYM(年度/月份)、SYM預示(下一/下二/下三起始日、下三截止日、年度/月份)、慶俊訂單(年度)、慶俊預示(起始日期/年度/月份)、SY計劃(起始日期/預示單號/轉單起始日)、SYM-2W(起始日期/取代預估單號/轉單起始日/轉單截止日)、新YAMAHA(下二~下六起始日、下六截止日)、年度銷售(年度)。
- 小計:YMTT訂單(數量小計/金額小計)、YMTT預示(原始數量小計/數量小計),轉入後即時重算。
- 額外按鈕:YMTT(Excel)、SY_BOM(EXCEL)、SY計劃/SYM-2W(篩選錯誤、Excel)、新YAMAHA(文字檔讀入、篩選錯誤)、SYM預示/慶俊預示(重新檢查)、年度銷售(篩選錯誤)。
- 篩選錯誤:已實作客端過濾(只顯示「錯誤」欄非空的列)。
- 解析器把原本塞進「備註」的資料改填獨立欄並顯示:鼎豪(客戶訂單號/三陽編號/訂單輸入日)、YMTT訂單(客戶訂單號/結關日期)、新SUZUKI(客戶訂單號/展開日期/類別)。
已知未完成(後續階段)
- 轉單/上傳(ORMAST/PREORD/ESTSAL/BOM 組單、報價反查單價、單位/包裝量帶值、版次遞增、原幣未稅)尚未實作;多數 BLL 目前只做 Parse。
- 預示頁工作日攤分(含第二/三表格明細)未做。
- Excel/DBF/重新檢查/文字檔讀入 按鈕目前點擊顯示「後續階段實作」訊息。
.XLS(舊 BIFF)讀取:SY計劃/SYM-2W 真檔仍會解析失敗(reader 為 XlsxFormatProvider)。
- ~~新YAMAHA:parser 仍為舊 YAMAHA(Page1)格式~~ → 已於 2026-06-26 重寫,見
2026-06-26-alledi-newyamaha-parser-rewrite.md。
Breaking Changes
無(顯示層還原;資料表/上傳格式未變)。
Migration Notes
無需 migration。
AllediImportRow新增多個顯示欄位(聯集),皆為純 POCO 屬性。 -
06-25 alledi-oem-edi-transfer ▸
2026-06-25 alledi(OEM EDI 轉單)移植完成 + scx_ord_cy 收尾
摘要
完成 VFP
scx_ord_cy.prg(CY = 朝陽/鈞寶 客戶專屬版,18 class)對比的最後一塊缺口:alledi(機車 OEM EDI 轉訂單工具)整支移植。同時收尾 scx_ord_cy 的
cy-specific 連動、needs-service(reuse 既有服務)與 pdtsal「計算資料」。
本檔承接
2026-06-25-scx-ord-cy-feature-completion.md,補記 alledi 與建置修正。新增
- alledi 程式(OEM EDI 轉單) —
LogicBll/E.Order/Alledi/、ViewModel/E.Order/Alledi/、TsERP/E.Order/Alledi.xaml
- 統一列模型
AllediImportRow(實作ICustomerSKU)。- 14 支在用廠別 parser(
Alledi*ImportBll.cs):鼎豪/SYM/SYM 預示/慶俊訂單/慶俊預示/YMTT 訂單/YMTT 預示/泛用取品號/年度銷售/SY_BOM/SY 計劃/SYM-2W/新 YAMAHA(P19)/新 SUZUKI(P20)。
cell 座標、SDF 欄寬均抄自 VFP;客戶品號對照走 cuinve 反查。
- 共用讀檔工具
AllediExcel.cs(Telerik Document Processing,.xls+.xlsx皆支援)。- 上傳
AllediUploadBll:依「目標單據」自動分派至 ORMAST/PREORD/ESTSAL/BOM,走 ItemsBindingManager(
Register<Source>().DirectSaveToSqlite → SaveAll → UploadToSql → TruncateAll),主從以
linkid = 主檔 pkid串接。- 程式外殼:
ProgramClass.ALLEDI+AllediViewModel(14 分頁)+AllediVendorTabViewModel(選檔→轉入預覽→上傳)+
Alledi.xaml(RadTabControl+ 預覽RadGridView)+ App.xaml DataTemplate。- dev-programs.json 加入 ALLEDI — 開發期免動 DB,於
appsettings.local.json開
DevPrograms:Enabled後重新登入,即於「E.營業收款」出現「OEM EDI 轉單」。變更
LogicBll/LogicBll.csproj— 新增 4 個 cross-platform Telerik DPL 套件
(
Telerik.Documents.Spreadsheet+.FormatProviders.OpenXml+.FormatProviders.Xls),供 LogicBll 解析 Excel 而不引入 WPF UI 依賴。
Common/ProgramClass.cs— 新增ALLEDI。
TsERP/App.xaml— 新增 alledi namespace 與AllediViewModelDataTemplate。
修正
- 登入崩潰
The given key 'ALLEDI' was not present in the dictionary—GetExtendFunction.SetDescription
(登入時跑)會逐筆走
PermissionTable用dic[類別名稱]取各程式的「其他N說明」(擴充功能鈕標題),字典
dic只由 DBprgsct1建。dev-programs.json 注入的程式(如 ALLEDI)不在 DB →dic["ALLEDI"]丟
KeyNotFoundException擋住整個登入。改為TryGetValue略過缺項(其他N說明留空)——一併修好所有「純注入、未在 DB prgsct1 登錄」的開發程式。(EISDASH/PRODUCTIONPLAN 因已有 DB prgsct1 列才沒踩到。)
- AllediViewModel 點選後空白 — 原繼承
ERPProgramBaseViewModel(非導覽器認得的三種版面型之一,item為 null
→ 不渲染)。改繼承
ERPProgramDefaultViewModel(同 Library/TodoList 自訂頁面型),由ErpProgramDefaultLayout承載 Content;無下方查詢面板故
BottomPanelContent回 null。- 建置「
App未包含InitializeComponent」+ MSB3027/MSB3021 — 並非 App.xaml 錯誤,
而是執行中的
TsErp.Ai.Mcp.Server鎖住輸出 DLL,導致 App.xaml markup 編譯未完成、App.g.cs未重新產生。停掉該程序後重建,TsERP exit 0、0 編譯錯、0 檔案鎖錯。(已記入
[[build-toolchain-vs-msbuild]]:再遇到先關TsErp.Ai.Mcp.Server再 build。)- Telerik DPL Excel API 對版(telerik-dpl-assistant):改用
Import(stream)、
Cells[r,c].GetValue().Value.RawValue、Worksheet,移除不存在的GetValueAsDouble/GetDefaultCellFormat/HasValue/CellValues。- 平行代理產生的 parser bug:SyPlan
客户代號→客戶代號、YmttForecast 重寫補 helper、Sym 客戶代號預設。
跳過(使用者裁定)
- 快速審核、金額幣別小數位、所有列變色/底色/前景色,本次不做。
Migration Notes
- 無新 SP、無 DB schema 變更:pdtsal 計算資料、estsal 客廠品號雙向、ormast/cupdma/preord 客戶品號反查
全 reuse 既有
DescriptionHelper/Darb_GetData4。- alledi 正式上線:開發期走 dev-programs.json;正式須
usp_新增程式+_menum/_menud/prgsct1登錄。
- 待 runtime 驗收:alledi 各廠 parser cell 座標需以
C:\轉EDI資料\真實樣本檔逐欄校對,
主檔表頭預設(受訂日期/序號前置碼/訂單別/幣別/匯率)需依各廠 VFP「轉至訂單」校正。
- cy-specific 連動以
Context.Env.CompanyShortName == "朝陽" || "鈞寶"護欄,非 CY 客戶不受影響。
詳見
LogicBll/E.Order/Alledi/README.md與記憶[[scx-ord-cy-compare-complete]]。 - alledi 程式(OEM EDI 轉單) —
-
06-24 scx-nogi-query-port ▸
2026-06-24 — scx_nogi 鈞寶專屬查詢(6 支)按 VFP 重寫移植
摘要
把 VFP
scx_nogi.vcx(NOGIHISA/鈞寶客戶專屬查詢報表庫)6 支查詢整批按 VFP 行為移植到新版 TsERP,沿用既有 DARB SP,不新建 SP。三專案(LogicBll/ViewModel/TsERP)建置通過,runtime 待驗收。詳見 ADR 0051。新增
- 訂單資料查詢(M-020,
Qry_ord_nogi):起訖訂單/客戶/品號/受訂日期/預訂交期/業務員 + 集團/倉儲/只含未出貨;結果 grid + 訂單/已出/未出三項統計。
- 出貨資料查詢(M-050,
Qry_sal_nogi):8 個彙總頁(出貨明細/產品/客戶/業務/類別/日期/單號/群組);出貨退回(SB)金額取負;合計框。
- 毛利率分析(M-160,
Qry_profit_nogi):8 彙總頁;利潤=本幣未稅−成本、標準利潤對照(coststd);標準單位成本差異%篩選。
- 其他交易單查詢(M-190,
Qry_trli_nogi):12 種倉儲交易單別(EI/EO/LO/LI/BI/BO/AA/SS/IT/NB/GU/IA,第12欄 UI 標 CI 但過濾碼為 IA);LO/LI 自銷售單補抓;EO 交易備註串接。
- 耗料查詢(M-140,
Qry_trwk_nogi):起訖部門/品號/日期/單號 + 交易別/轉入倉儲;衍生欄(未交數量、金額、年月、使用單號依參數 3012)。
變更
- 進貨資料查詢(M-070,
Qry_ra)修正既有 beta bug,對齊 VFPqry_ra_nogi:
- 結果欄位對映修復(原英文屬性無對映 → 整批空白)。
- 4 個單據別 checkbox(進貨RA/退出RB/總務進貨RC/總務退出RD)與付款別(已轉/未轉應付)實際接上查詢條件(原為空,勾選無效)。
- 新增「進貨費用」勾選 → 帶出進貨費用明細列。
刪除 / 不做
- 列印報表(.frx)、樞紐分析表、報表選擇排序鈕:一律不做,改用清單內建排序與匯出。
- 公司專屬除錯碼(特定 usercode 匯出 dbf)不移植。
後續調整(同日)
- 進貨資料查詢(Qry_ra)介面現代化:改為 TsView、查詢條件改成獨立面板、欄位標題與條件 label 全面中文化(對齊其他 5 支 nogi 查詢)。
- 耗料查詢(M-140)新增明細列雙擊 drill-down:雙擊一列依單號開頭開啟對應「加工單」或「損耗單」並定位(還原 VFP 雙擊跳轉)。
Breaking Changes
無。
Migration Notes
- 不需任何 DB migration:沿用現成
DARB_QRY_STD/DARB_GETDATA4,無新 SP、無 proc_param 變更。
- 選單路由:6 支 ProgramClass 命名一致(M-070 進貨已將 VM 改名
Qry_ra_nogiViewModel/ ProgramClassQRY_RA_NOGI),選單碼對應QRY_*_NOGI即可路由。
- 待 runtime 驗收:開啟各查詢確認有資料、條件過濾正確、彙總金額正負號正確。
- 訂單資料查詢(M-020,
-
06-24 localization-single-service-live-switch ▸
2026-06-24 多語言收斂單一服務 + 即時切換語言
摘要
多語言系統改走單一服務(方案 B 第一刀,見 ADR 0052)。切換語言即時生效、不再需要重新登入;
畫面文字、grid 表頭、選單會一起換成新語言。backend 仍是 JSON,之後可無痛換成資料庫。
新增
Common/Lang/ILocalizationStore+JsonLocalizationStore:多語言字串的可抽換來源(之後換 DB 只動這層)。
Common/Lang/ILocalizationService+LocalizationService:單一語言服務(目前語言、即時切換、查表)。
Common/Lang/LocalizationLocator:給元件層取服務的橋接。
TsControl/Localization/HeaderLocalization:TsDataGrid 與 TsRadGridView 共用的表頭翻譯。
- 單元測試
LogicBllTests/Lang/LocalizationServiceTests(8 項,全綠)。
變更
- 設定 → 切換語言:存檔後即時套用,提示改為一般「儲存成功」,不再顯示「請重新登入」。
- ERPSystemContainerView 功能列新增「語言」選單:直接選語言即時切換並持久化(下次登入沿用),
與設定頁共用同一條
ChangePasswordAndMyFavoriteBll.ChangeLanguage;切換時功能列文字本身也即時重翻(
MainWindowMenuViewModel.ChangeText改讀單一服務目前語言 + 訂閱LanguageChanged)。TsRadGridView現在會翻譯欄位表頭(先前完全不翻,dg-to-radgrid 遷移後的迴歸已修)。
- 切換語言後,grid 表頭、選單列、各表單欄位標籤即時更新。
- grid 版型存檔改存「欄位穩定鍵」而非當下譯文 → 版型跨語言通用(英文存、中文開不再被蓋亂)。
缺口補完(同日追加)
- 訊息/對話框文字即時化:
MessageService與ViewModel LanguageService改讀單一服務的目前語言,
切語言後提示訊息、翻譯文字即時跟著變(不重登)。
- 查詢/報表語言對齊:
IUser.Language改為委派單一服務的CurrentLanguage,約 30 個讀User.Language
的呼叫點(查詢/報表撈語系資料)切換後自動使用新語言。
- 報表 locale 即時刷新:新增
FastReportLocalizationService訂閱語言切換 → 重載對應.frl
(繁中/簡中;英日越無檔則退回英文)。新開報表即套新語言。
- grid 右鍵選單翻譯(M2):排序/群組/匯出/匯入/新增/刪除/勾選等 17 條選單字串改走單一服務翻譯,
查無則以現有繁中字面 fallback;選單每次開啟重建,切語言即生效。
- 列舉/下拉即時翻譯:
CobPoco實作 INotifyPropertyChanged +Retranslate,EnumManager訂閱語言切換
反射重翻所有已建立的列舉集 → 列舉下拉顯示文字即時更新。
- 漏譯偵測(L6):DEBUG 下非繁中查無翻譯會去重記到
C:\temps\debuglog\MissingTranslations.txt。
- 壞檔防護(L2):
LanguageMerger.MergeAllper-file try/catch,單一壞 JSON 不再毀整表/擋啟動。
- CJK 標題修正(N2):
AddBlankBeforeCapital含 CJK 直接原樣返回,不再誤刪中日文間空白。
刪除
- 無(
LanguageConverter/TitleConverter兩個空轉換器標[Obsolete],實體刪除留待後續刀次)。
Breaking Changes
- 無對使用者操作的破壞性變更。
Migration Notes
- 既有 grid 版型自動相容:舊版型存的是譯文 header,第一次開啟時當「鍵」查;中文版型會正確翻譯,
非中文/特殊舊版型則原樣顯示,下次存檔自動轉成穩定鍵(自癒),無需手動處理。
- 已知限制:報表(FastReport)文字與系統訊息對話框維持登入當下語言,切換語言後需重新登入才更新;
欄位/表頭/選單則即時生效。
-
06-24 localization-single-json-tree ▸
2026-06-24 — 本地化 JSON 收斂單一樹
摘要
多語言翻譯字典從「分檔樹 + 發行專屬合併樹」兩棵收斂成單一來源樹,並修復約 69 個翻譯分檔未進發行版的漏譯 bug。詳見 ADR 0053。
變更
Common.csproj:Lang\Xaml\*.json、Lang\Model\*.json改用萬用字元一次納入部署(取代 160 筆逐檔登記)。新增 section JSON 免再手動登記。
JsonLocalizationStore.Reload():DEBUG / RELEASE 一致讀Lang/Xaml分檔(移除 release 專屬 Xaml1 分支與 L3 兩樹差異 log),保留 Xaml1 fallback 僅為相容舊輸出。
刪除
TsERP/Lang/Xaml1/(發行專屬合併檔)與TsERP.csproj對應登記。
TsERP/Lang/Model1/Model.json(確認為死檔——全 repo 無.cs讀取)與TsERP.csproj對應登記。
- 舊
ModelMapService機制全清:Common/Lang/Model/(整夾)、Common.csproj的Lang\Model\*.jsonglob、Common/Context/ModelMapAttribute.cs,及Tmp1.cs/Tmp2.cs的[ModelMap]標註。
Breaking Changes
無。執行期行為對使用者相同(翻譯來源不變,僅部署/讀取路徑收斂)。
Migration Notes
- 開發/發行端重建輸出即可;下次 Velopack 發版自動帶齊全部分檔(含先前漏掉的 ~69 個)。
- 舊輸出目錄殘留的
Lang/Xaml1不再被讀取,可忽略或清除。
-
06-24 dev-program-registry ▸
2026-06-24 開發用本機程式註冊檔(dev-programs.json)
摘要
新增開發用機制:免在 DB 權限表(
_menum/_menud/prgsct1)登錄,即可讓新程式出現在左下角程式清單、可點開、權限通過。僅開發機啟用,正式環境不受影響。新增
TsERP/dev-programs.json:本機程式註冊檔(放 repo、跟著 git 走、複製到輸出目錄)。已預載生產計劃查詢(PRODUCTIONPLAN)、主管儀表板(EISDASH)兩支當範例,掛在M.主管資訊模組下。
Common/Environment/DevProgramRegistry.cs:讀 JSON → 建PermissionTable列(權限全開)的載入器。
EnvironmentSetting.DevProgramsEnabled靜態旗標;啟動時由App.xaml.cs從設定讀入。
appsettings.example.json新增DevPrograms:Enabled說明。
變更
UserBll.CreateUserInfo():登入建立權限表後,旗標開啟時注入dev-programs.json的程式列。
啟用方式
在
%ProgramData%\TsERP\appsettings.local.json加:{ "DevPrograms": { "Enabled": true } }重新登入後,
dev-programs.json的程式即出現在左下角清單。新增程式只要在該檔programs陣列加一筆(programClass/programName/subsystem/programNo)並重新登入。Breaking Changes
無。Production 不設旗標 → 完全 no-op。
Migration Notes
- 此機制只負責「程式出現在清單並可導覽 + 權限通過」。資料顯示仍需該程式的 SP / proc_param / view;走 DataManager/Source 的維護畫面仍需
LocalDbContextDbSet 註冊。
- 新電腦 pull 後,
dev-programs.json已隨 repo 帶入;只要各自在本機appsettings.local.json開旗標即可。
-
06-23 trial-advn-page2 ▸
2026-06-23 試算表新增「ADVN 累計試算表」頁,移除「VFP 對照」頁
摘要
試算表(
Trial)頁籤由「目前算法 / VFP 對照」改為「目前算法 / ADVN 累計試算表」。新頁移植自 VFP
scx_acc_advn的trial.pf.page2「舊系統算法」。新增
- 頁籤「ADVN 累計試算表」:以年度結轉檔
sliyyear為期初、依借貸別累計到截止日,
並列功能幣與集團幣兩組「計初借/貸餘、借/貸方金額、累計借/貸餘」,
底部顯示功能幣與集團幣各自的借方/貸方/累計借方/累計貸方合計。
- 後端
TrialAdvnSource(中文屬性)與TrialAdvnBll(沿用DARB_GETDATA3 / DARB_GETDATA4分段查詢,未新增 SP)。
變更
- 試算表第二頁的內容與意義改變(原為開發對拍用的「VFP 對照」鏡像,現為實際的累計試算表)。
- 「目前算法」頁:本幣模式不再顯示「幣別 + 原幣」欄組(原本那組在本幣模式只是功能幣的鏡像、易誤導)。
僅在試算表種類選「原幣」時才顯示原幣欄。以
ShowCurrencyColumns+BindingProxy綁定欄位IsVisible控制。刪除
- 「VFP 對照」頁籤及其後端
TrialBllVfp/TrialTotalsVfp(開發期對拍碼)。
Breaking Changes
無。資料庫、設定、報表皆不變。
Migration Notes
無需 migration,重建後生效。
備註(原幣是否未實作)
DARB_QRY_ABOOK1中「彙總試算表仍然未做」的註解只針對 server 端彙總,不是「原幣未做」。原幣明細試算表(
@查詢別=3)已實作且實測可用,畫面(TrialType.Currency)與報表(
TrialReportType.Currency)皆已接通,本次不更動。 - 頁籤「ADVN 累計試算表」:以年度結轉檔
-
06-23 sliybrowd-edit-accl-validation ▸
2026-06-23 Sliybrowd 修改模式加入科目代號檢查
摘要
總帳明細查詢(Sliybrowd)進入「修改」模式編輯傳票明細時,新增與 Sliy(總帳傳票)一致的會計科目控制檢查:依該科目的控制方式(控制方式1~9、b、6)判斷哪些欄位必須輸入、哪些禁止輸入。
變更
- Sliybrowd 的明細 Grid 掛上與 Sliy 共用的
InjectAcclValidationRuleBehavior,於整列提交(RowValidating)時依科目控制方式檢查:
- 分類索引 1~4、項目編號、部門代號、員工編號、專案代號、產品群組:控制方式為 Y 必填、為 N 禁填。
- 客廠代號:控制方式 6 為 B/C/S 必填、N 禁填。
- 「輸入傳票」非 Y 的統制/標題科目禁止入帳。
- 編輯任一格後(CellEditEnded),該列會標記為「修改(E)」;只有被實際編輯過的列才會觸發科目檢查,未動過的舊列不會被檢查。
- 連帶讓
SliybrowdViewModel.Save的IsChanged篩選能正確抓到被編輯的列(先前列上的編輯不會設旗標,等同沒有可上傳的列)。
Breaking Changes
無。唯讀查詢與報表行為不變;僅影響「修改」模式下的存檔前驗證。
Migration Notes
無需資料庫或設定變更。科目控制方式沿用既有
accl主檔(OpenDbfTable.GetAcclDic())。 - Sliybrowd 的明細 Grid 掛上與 Sliy 共用的
-
06-22 reportsroot-local-override ▸
報表樣板根目錄可由本機設定覆寫
摘要
報表樣板根目錄(
REPORTSROOT,其下放.frx/ Excel 樣板)原本只能從 DBPrgpar表讀取、全 DB 共用。新增可在每台機器的appsettings.local.json覆寫,讓不同機器指向自己的報表樣板資料夾。新增
appsettings.json新增ReportsRootDirectory鍵(預設空字串)。
- 可在
C:\ProgramData\TsERP\appsettings.local.json設定此鍵,做每台機器各自的覆寫。
- 「密碼及我的最愛設定」(
ProgramClass.Setting)新增「本機設定檔」分頁,可直接在程式內編輯%ProgramData%\TsERP\appsettings.local.json:載入/編輯原始 JSON、存檔前驗證格式、自動建立資料夾,存檔後提示需重新啟動。無寫入權限時提示以系統管理員身分執行。
變更
EnvironmentSetting.SetSystemDecimalPlace():ReportsRootDirectory取值改為「appsettings的ReportsRootDirectory有值就用它,否則回退 DBPrgpar的REPORTSROOT」。
- 啟動時於
App.xaml.cs讀取設定並寫入EnvironmentSetting.ReportsRootDirectoryOverride靜態屬性(與既有DatabaseListPath/DatabaseListSourcePath同一處、同一機制)。
Breaking Changes
無。鍵留空時行為與既往完全相同(仍走
Prgpar)。Migration Notes
- 不想改的機器:不必動,保持空值即可。
- 要在本機指向自訂樣板資料夾:在
C:\ProgramData\TsERP\appsettings.local.json加上
```json
{ "ReportsRootDirectory": "D:\\MyReports" }
```
該目錄下需有
Reports\(.frx)與Template\(Excel 樣板)子資料夾,對應ERPIO.ReportDirectory/TemplateDirectory。 -
06-22 adeupload-specialedit-use-xmlsource ▸
2026-06-22 特殊修改(SpecialEdit)改用 xmlSource 上傳,修實際沒上傳的問題
摘要
修正「特殊修改(Special Edit)實際上沒有把資料上傳成功」的問題。
AdeUploadBll.SpecialEdit原本走舊的反射路徑,從_source重新組上傳字串:var stringList = UseRefrectionToCreateUploadData(isModelSource, useMemory); // 讀 _source Upload(..., "Special Edit", stringList, ...);但「特殊修改」狀態實際只會經由新的 ItemsBindingManager 路徑進來:
SaveBll.UpdateData → ItemsBindingManager.UploadToSql(Status) → AdeUploadBll.UpdateToSql(status, xmlSource)這條路徑只會設定預先組好的
xmlSource、不會設定_source。因此SpecialEdit反射到的是null的_source,等於沒有把資料帶上去。(這與 ADR 0010 對 legacyUpdateData(object[], …)路徑的結論相同——該路徑因同樣只讀xmlSource而早已失效。)變更
LogicBll/Ade/AdeUploadBll.cs—SpecialEdit改成與Edit一致,直接上傳xmlSource(移除UseRefrectionToCreateUploadData反射呼叫)。
影響行為
- 使用「特殊修改」的單據(如 paymnt、ftrlima)現在能正確將特殊修改的內容上傳到 SQL;先前實際上傳為空。
Breaking Changes
無。上傳事件(
INPUT-BE/Special Edit)、PassNumber 流程、狀態語意皆未更動。Migration Notes
無需 migration。
影響範圍確認
- 全 repo 舊路徑
UpdateData(object[], …)/UpdateDataWithModel的呼叫者全部只用Add/Edit,沒有任何一處傳SpecialEdit,故移除反射不影響舊路徑。
- 使用特殊修改的表單(paymnt、ftrlima)皆已遷至 ItemsBindingManager,走
UploadToSql新路徑。
相關
- ADR 0010 — BatchEdit 改用 ItemsBindingManager(記載 legacy
UpdateData路徑只讀xmlSource而失效,本次為同類修正)
-
06-21 turn-staging-cleanup-pkid-collision ▸
2026-06-21 轉單上傳後清除 #turn 暫存,修 navigate 撞主鍵
摘要
修正「編輯傳票途中轉傳票後,編輯表單按上/下一筆會崩潰」的問題:
ExecuteAsync異常: constraint failed UNIQUE constraint failed: Sliy.pkid根因是 StagingScope 隔離(ADR 0043)讓「轉單(scope
#turn)」與「編輯表單(scope = ProgramClass.Name)」的列共存於同一張本機 SQLite 實體表,但pkid是該表INTEGER PRIMARY KEY AUTOINCREMENT(全表唯一)。轉單上傳成功後#turn暫存列沒有被清除,殘留在表中;其 pkid 由 AUTOINCREMENT 高水位配出(例 540548,高水位來自先前 navigate 帶入的 server pkid),之後編輯表單 navigate 帶入相同 server pkid 時即撞主鍵。變更
TransferBindingBll.Save():上傳成功後新增Manager.TruncateAll(),立即清除本次轉單的#turn暫存列(scope-aware,只刪#turn,不動編輯表單的列)。
TransferBindingBll.Cancel():取消轉單時亦設定 scope 後TruncateAll(),清除已落地未上傳的#turn列。
DataManager<T>.Truncate():改用 raw SQL(ExecuteSqlRaw DELETE ... WHERE [StagingScope]=...)刪除,刻意繞過 EFChangeTracker/SaveChanges→ApplySyncFields。
- 原本走 EF
RemoveRange + SaveChanges,會對 EF 物化(無參 ctor、Context==null)的列觸發ApplySyncFields→SetUploadValue()而 NullReference;且對「要丟棄的暫存列」蓋上傳稽核欄本就無意義。- 刪除後呼叫
ChangeTracker.Clear()維持追蹤一致性。影響行為
- 轉傳票上傳成功(或取消)後,轉單畫面的暫存清單會清空(
Truncate連帶_observableCollection.Clear())。對批次轉檔屬預期行為。
AddBll.Clear()(新增單據清場)同樣經Truncate(),改 raw SQL 後語意不變(仍是清本機 staging),不再有 EF 蓋章副作用。
Breaking Changes
無。pkid / 主鍵語意、
pkid==0=新列約定、上傳流程皆未更動。Migration Notes
無需 migration。本機 SQLite 由 EnsureCreated 維護;schema 未變。
相關
- ADR 0043 — StagingScope 同表多流程隔離(本次為其後續修正)
- 未採用的替代方案:RowGuid 改當身分鍵(會使新列恆為 pkid=0,衝擊大量
ToDictionary(x=>x.pkid)主從邏輯)、pkid改負號預設(需改全系統pkid<=0=新列約定)。最終取「轉單上傳完即清#turn」這個最小且不動 pkid 語意的解。
-
06-21 sliyturn-asset-accexp-sliy1-detail ▸
2026-06-21 固定資產/費用攤提轉傳票 — sliy1 改放逐筆品號明細
摘要
固定資產折舊(asset)與費用攤提(accexp)轉傳票時,傳票子檔 sliy 維持「彙總分錄」,
sliy1 改為保留「逐筆品號明細」(帶品號/品名),可作品號層級追溯。原本 sliy1 只是
複製彙總後的 sliy(兩張相同、皆無品號)。
變更
- asset/accexp 轉出的 sliy1 現在帶品號(asset=財產編號、accexp=費用編號/費用名稱),
為彙總前的逐筆明細;sliy 不變,仍依科目+部門+輸入地點(accexp 再加客廠)彙總。
- sliy1 明細自動對齊母傳票(linkid)、補功能幣/集團幣金額;空白/借貸皆 0 的列自動略過。
Breaking Changes
無。其餘轉單流程(AP/AR/Payapply/Ftrlima)行為不變,sliy1 仍與 sliy 內容相同。
無資料 migration(staging 每次登入新建;server 端 sliy1 表結構不變)。
Migration Notes
runtime 驗收:轉一筆折舊/攤提,確認 sliy1 帶出品號、sliy 為彙總、傳票可存且借貸平衡、
sliy1 各列總額與 sliy 一致。
已知限制
sliy1 為轉檔當下的原始明細,不反映使用者事後在彙總 grid 的手動改帳;詳見
ADR 0044。
詳見 ADR:
docs/decisions/0044-sliyturn-asset-accexp-sliy1-detail.md -
06-21 recepdt-transfer-parity ▸
2026-06-21 出貨/暫估轉應收帳款 — VFP 對齊修補
摘要
對
recepdt(出貨轉應收)與recepdt_2(暫估轉應收)兩支轉帳表單做 VFP 對比後的行為修補;recepdt_1(應收帳款拆單)確認為未移植缺口、暫不處理。詳見 ADR 0047。新增
- 出貨轉應收:條件面板恢復「帳款別:應收帳款/暫估」選項,可選擇將出貨直接轉為暫估應收(財務類別 17)。
- 出貨轉應收:按「單張轉帳/合併轉帳」前新增前置檢查 — 指定立帳日期模式須先填立帳日期;合併轉帳須至少勾選一種單據別,否則即時提示。
- 暫估轉應收:查詢列新增「全選/不選」兩顆按鈕,可一次勾選/取消所有暫估單。
變更
- 出貨轉應收:合併轉帳時,若某收款客戶該期間只有退貨(SB)而無出貨(SA),整筆改記為銷貨退回(財務類別 21),與舊系統一致(先前固定記為出貨 12/暫估 17)。
- 出貨轉應收:存檔時新增「主檔金額=明細加總」一致性檢查(與付款轉帳一致)。
- 暫估轉應收:發票金額為 0 時,顯示/計算改以暫估本幣金額為基數(先前顯示 0)。
- 暫估轉應收:校正(重算)原幣應收付公式更正為「本幣應收付 ÷ 匯率」(先前誤用稅額);換稅別後的發票金額重算恢復作用。
刪除
- 移除未使用的
Recepdt轉帳.cs(孤兒抽象類別)。
- 出貨轉應收的「無單價/校正」鈕維持不提供(舊系統亦已停用,屬單一客戶專屬)。
Breaking Changes
無。皆為單機程式行為調整,無資料庫結構或預存程序異動。
Migration Notes
recepdt_1(應收帳款拆單視窗)尚未移植:此為把「部分開票仍有餘額」的應收單拆成兩張的獨立工具。若仍有此作業需求,請回報以排程移植(需新增程式代號、DARB_TUR_RECEPDT_1登錄、畫面與拆單邏輯)。
- 本次變更 runtime 尚未實測,建議驗收:合併轉帳純退貨群組的科目別與金額、暫估轉帳校正與換稅別、暫估轉帳全選/不選、出貨轉暫估整條路徑。
-
06-21 po-signing-key-wizard ▸
採購協同 簽章金鑰 備份/還原向導 UI
日期:2026-06-21
模組:PoCollaboration — L.Communication
摘要
把 ADR 0041「未做」清單中的金鑰備份/還原向導接上 UI。後端金鑰服務(
OrgSigningKeyService,規格 §7.2:產生 RSA-3072 → 匯出密碼 .pfx 備份 → 測試還原 → 匯入不可匯出 CNG 容器)先前已實作並有
單元測試,但無任何畫面呼叫它,使用者無法在系統內操作。本次新增 TsView 模態向導把這層串起來。
新增
PoSigningKeyWizardViewModel(ViewModel/L.Communication/PoCollaboration/):
繼承
ERPProgramContentWindowViewModel,三段功能 —- 狀態檢視:是否已設定/已備份/可出單、金鑰指紋、建立與備份時間、備份位置。
- 產生並備份:統編/公司名(預帶
EnvironmentSetting的CompanyTaxID/CompanyName)、備份密碼+確認、備份位置(
SaveFileDialog)。含密碼強度檢核、兩次密碼一致、同碟警告、已設定時重產二次確認;成功後顯示「救援卡」並可另存 .txt。
- 還原:選 .pfx +備份密碼 →
Restore。PoSigningKeyWizard.xaml/.xaml.cs(TsERP/L.Communication/PoCollaboration/):TsView 版面,
PasswordBox 走
PasswordHelper.BindPassword/BoundPassword,文字走 DisplayMeta 多語系。- 多語系:
Common/Lang/Xaml/PoSigningKeyWizard.json(rootPosignkey,含 Common.csproj Content 登錄)
與
TsERP/Lang/Xaml1/Xaml.json同步補Posignkey。- 入口:設定畫面(
SettingView)新增 「採購協同簽章金鑰」分頁,內含開啟向導的按鈕 →
ChangePasswordAndMyFavoriteViewModel.OpenPoSigningKeyWizardCommand以ShowContentWindow開模態。- 權限限定:分頁
Visibility綁IsCmsaAccount(Context.User.UserId == "cmsa",不分大小寫),非 cmsa 帳號看不到分頁;命令本身另有同樣的後端守門(雙重防護)。
變更
- 金鑰持久化改用憑證庫(修 NTE_NOT_SUPPORTED):原以「把 PKCS#8 私鑰 import-create 進具名 CNG
容器」持久化,在 MS Software KSP 實機回 「不支援要求的操作」(按下產生/還原即失敗;單元測試
原本以
Assert.Inconclusive吞掉,等同從未驗證)。改為把含私鑰的 .pfx 以PersistKeySet(不含Exportable)匯入 CurrentUser\My 憑證庫,達成「持久+不可匯出+可簽章」且免提權;金鑰由憑證 SHA-1 指紋索引。
CngSigningKey改為雙後端(Spike 仍走具名容器產生、正式金鑰走憑證庫);
SigningKeyMetadata.CngContainerName→CertStoreThumbprint。單元測試改為實際 round-trip(產生→簽→刪→還原→再簽驗),現 2 綠 0 略過。
Common/ProgramClass.cs:新增POSIGNKEY。
TsERP/App.xaml:加PoSigningKeyWizardViewModel→PoSigningKeyWizard的 DataTemplate 與兩個 xmlns。
TsERP/SettingView.xaml、ViewModel/Setting/ChangePasswordAndMyFavoriteViewModel.cs:新增 cmsa-only 分頁、
IsCmsaAccount旗標、向導命令。追加:公鑰配對(§7.3,見 ADR 0046)
- 發方匯出公鑰:
PublicKeyCard(JSON 公鑰卡,自洽指紋檢核)+OrgSigningKeyService.ExportMyPublicKeyCard();
向導「公鑰交付」區塊 →「匯出我的公鑰」存
*.pokey.json。- 收方信任清單(SQL):
pocollab_counterparty表 +TWORK_POKEY_QRY/SAVE/DEL(走 DARB_LOG_SYS_EXEC
dispatcher,proc_param 登錄);
CounterpartyKeyStore(LogicBll)做匯入/列出/刪除/ResolvePublicKeyDer。向導「往來對象公鑰(信任清單)」區塊:匯入公鑰卡(強制顯示指紋口頭核對)/ 清單 / 移除。
- 驗章接點:
CounterpartyKeyStore.ResolvePublicKeyDer即InboundProcessor的 resolver,已就緒待正式收件流程接。
- 部署腳本(使用者 SSMS 跑):
.claude/tmp/pocollab-counterparties-deploy.sql(建表+3 SP+proc_param,冪等)。
- 單元測試 +1(公鑰卡自洽 + 公鑰可驗證容器私鑰簽章),signing-key 測試現 3 綠 0 略過。
追加:信任清單改為 L.聯絡傳訊 標準維護程式(POKEYCP,見 ADR 0046)
依使用者裁定,「往來對象公鑰信任清單」從 cmsa 設定分頁的自訂 modal,改成 L.聯絡傳訊 正式選單標準維護程式(瀏覽/新增/修改走平台 Ade):
- 新表
twork_com_counterparty(含平台稽核欄、pkid 非 identity);_sheetno登錄POKEYCP(複製 ACCL);TWORK_POKEY_QRY重指向新表;舊pocollab_counterparty+SAVE/DEL+proc_param 移除。腳本.claude/tmp/pocollab-com-counterparty-deploy.sql(模擬環境已執行驗證)。
- 程式碼:
ProgramClass.POKEYCP、ModelTwork_com_counterpartyModel、SourceTwork_com_counterparty、LocalDbContextDbSet、PokeycpViewModel(IAdd/IOther1=匯入公鑰卡/IOther2=開金鑰向導)、PokeycpSave、Pokeycp.xaml、App.xaml DataTemplate。
- 移除 cmsa 設定分頁入口;向導瘦身(移除信任清單區塊);
CounterpartyKeyStore只剩唯讀供驗章。
- 未做:選單/權限需經系統內建【權限設定/選單維護】登錄
POKEYCP到 L.聯絡傳訊;TsERP XAML 未編譯驗證(須關 ERP 重 build);navigate/upload runtime 未驗。
刪除
無
Breaking Changes
無(純新增)。
Migration Notes
- 金鑰私鑰在本機 CNG 不可匯出(憑證庫),metadata 在
%ProgramData%\TsERP\po-collab\signing-keys.json。
- 公鑰配對需先部署 SQL:跑
.claude/tmp/pocollab-counterparties-deploy.sql(建表/SP 在 csa 庫
darbnogicsa1、proc_param 在 log 庫darbnogilog1——已對照連線設定確認為模擬環境;換別家公司部署時改 DB 名,腳本註解附對照表)。未部署前信任清單留空、匯入會提示尚未部署,不影響金鑰產生/備份/匯出公鑰。
- WebView2 已升至 1.0.3650.58;重建需 VS 2022 MSBuild。
- 仍未做:正式收件匣流程接 resolver、公鑰卡離線真實性(目前靠人工口頭核對指紋)、金鑰輪替舊簽章可驗證性。
-
06-21 delete-approved-inreview-guard ▸
2026-06-21 刪除防呆:已審核/審核中/作廢單據不得刪除
摘要
刪除單據時,若主檔的
已審核欄位處於Y(審核完畢)、G(審核中/進行中)或X(已刪除作廢)狀態,會在跳「確定要刪除嗎?」確認對話框之前就提示「資料已審核或審核中,不得修改或刪除」並中止,不讓使用者按完刪除、按下確定後才被擋。已審核欄位代碼(程式既有定義):Y= 審核完畢(已審核)
G= 進行中(審核中)
X= 已刪除作廢
原本
已審核的狀態檢查只在修改 (Edit) 流程(EditBll.CheckIsApproved),刪除 (Delete) 流程未檢查;本次把同樣的保護補進刪除流程,行為與修改一致。變更
LogicBll/Ade/Basic/DeleteBll.cs
- 新增
IsApprovedOrInReview(out msg)(public):透過ItemsBindingManager.GetMasterFirstItem()取主檔,反射讀SysWorkflowFieldEnum.已審核;值為Y/G/X(大小寫不分)時帶出MessageEnum.DataHasBeenApprovedCannotEditOrDelete並回true。-
BeforeDelete()呼叫IsApprovedOrInReview()作為防線(防止其他直接呼叫DeleteBll.Delete()的路徑漏擋)。ViewModel/Ade/DeleteService.cs
- 在
Delete()跳確認對話框之前先呼叫IsApprovedOrInReview(),命中即顯示訊息並return。TsERP/Lang/Message.json
-
DataHasBeenApprovedCannotEditOrDelete文字調整:- 繁中:
資料已審核,無法修改或刪除→資料已審核或審核中,不得修改或刪除- English:同步改為
The data has been approved or is under review, so it cannot be edited or deleted影響行為
- 對
已審核 = Y/G/X的單據按刪除:還沒跳確認對話框就直接提示「資料已審核或審核中,不得修改或刪除」並中止。
- 此訊息為 Edit/Delete 共用 enum,修改 (Edit) 流程顯示的文字也一併更新為新的措辭(更準確、涵蓋審核中),行為不變。
- 其餘狀態(空白)的刪除行為不變。
- 未新增語系 key,僅調整既有
DataHasBeenApprovedCannotEditOrDelete文字。
Breaking Changes
無。
Migration Notes
無需 migration。
-
06-21 dashboard-export-deck ▸
2026-06-21 主管儀表板新增「匯出簡報」
摘要
主管儀表板(EISDASH)右上工具列新增「📊 匯出簡報」鈕,一鍵把目前畫面的 KPI 數據產成一份自包含 HTML 簡報(單檔、瀏覽器開、可全螢幕投影/分享)。
新增
LogicBll/M.EIS/主管儀表板/儀表板簡報Generator.cs:HTML deck 產生器(儀表板簡報資料DTO +產生HTML)。封面 + KPI 8 卡總覽 + 受訂/出貨趨勢面積圖(手繪 SVG)+ 呆料 Top10 + 逾期客戶清單;← → 翻頁、F 全螢幕、視窗等比縮放(1920×1080 舞台)。
EisdashViewModel.匯出簡報Command:組目前顯示資料 → 產 HTML → 寫ERPIO.TempsReportDirectory\經營儀表板簡報_yyyyMMdd_HHmmss.html→Process.Start用預設瀏覽器開。
變更
TsERP/M.EIS/主管儀表板.xaml:工具列「重新整理」旁加「匯出簡報」鈕。
行為
- 匯出的是當下顯示快照(不重查 DB、不即時連動);要最新數字就重按。
- 用瀏覽器開(非 WebView2 內嵌)——簡報用途要全螢幕/分享,理由見 ADR 0048。
Breaking Changes
無。純新增功能。
Migration Notes
無需 migration。輸出目錄
C:\Temps\Reports由程式自動建立。相關
- ADR 0048 — 匯出簡報採自包含 HTML deck(vs open-slide / .pptx;瀏覽器 vs WebView2)
-
06-21 business-registry-autofill ▸
2026-06-21 客戶/廠商輸入統編自動帶入工商登記資料
摘要
客戶主檔(Cudata)與廠商主檔(Spdata)的「統一編號」欄位,輸入 8 碼統編後可自動向
經濟部商工登記公示資料開放平臺查詢,回填名稱、負責人、公司地點、登記資本額。
新增
- 統編欄旁新增「查工商登記」按鈕,可手動查詢回填。
- 統編輸入完離開欄位(LostFocus)時自動查詢回填。
- 查詢來源:經濟部官方開放資料,先查公司登記、查無再查商業登記(涵蓋獨資/合夥商號),免帳號金鑰。
變更
- 回填規則:API 回傳有的欄位才填,沒有的跳過;欄位空白者直接帶入;
已有值且與登記資料不同者,會集中列出並跳確認視窗,按「是」才覆蓋。
- 僅於新增/修改狀態下才會觸發查詢(瀏覽狀態不會打網路)。
- 登記資本額以「萬」為單位帶入(官方 API 回傳為「元」,回填時自動除以 10000)。
刪除
無。
Breaking Changes
無。原有手動輸入行為不受影響。
Migration Notes
- 無資料庫變更。
- 需可連到
https://data.gcis.nat.gov.tw(官方商工登記開放平臺)。內網若有對外白名單需放行此網域。
- 登記資本額以「萬」為單位儲存;廠商主檔為整數欄位,換算後四捨五入。
-
06-17 prodplan-sim-sku-seekcolumn ▸
2026-06-17 生產計劃查詢 — 模擬插單品號改 SeekColumn
摘要
「生產計劃查詢」→「模擬插單」分頁的品號欄,由純文字輸入改為品號 SeekColumn(查 INVENT),選定品號後自動帶出品名;品名欄改為唯讀。
變更
- 品號欄:
TsGridViewDataColumn→TsSkuSeekGridViewColumn,可下拉/輸入查詢 INVENT 品號,DescriptionBindingPath="品名"選定後自動回寫品名。
- 品名欄:加
ForceReadOnly="True",改為唯讀(由品號 seek 自動帶入,不再手動輸入)。
SimulationOrderPoco實作INotifyPropertyChanged,使 seek 回寫品名時唯讀欄即時刷新顯示。
Breaking Changes
無。模擬訂單仍只存記憶體(what-if,不落 DB),套用邏輯不變。
- 品號欄:
-
06-17 memory-leak-and-allocation-fixes ▸
2026-06-17 記憶體洩漏與配置量修補
摘要
接續 2026-06-10 全專案記憶體稽核,本次針對重新掃描找出的新問題做修補:補齊未釋放的 disposable、修兩處事件處理器洩漏,並降低報表寫檔與生產計劃查詢的尖峰配置量。皆為內部修正,無使用者可見行為變動。
變更
洩漏修復(資源未釋放 / 事件未解除)
Common/Environment/Sql.cs— 中央 SQL 執行層 4 個SqlDataAdapter(判斷表名、Log_LogOn、InputCommand、Log_Sys_Input_Multi)改用using。其中判斷表名在每次同步查詢都會跑。
ViewModel/Reports/FastReportExtension.cs—PDFExport/Excel2007Export改用using(ExportBase建構子訂閱AppDomain.UnhandledException,未釋放會被 root)。
ViewModel/L.Communication/PoCollaboration/ReportPdfExporter.cs— 2 個PDFExport改用using。
ViewModel/Other/TodoList/WorkflowPDFHelper.cs—PDFExport改用using。
ViewModel/Control/Layout/PrintLayout/PrintHelper.cs— Print/Excel 路徑的Report改用using(Preview 路徑所有權轉移給預覽視窗,維持不變)。
LogicBll/E.Order/Darbedittool/DarbedittoolBll.cs— EDI 匯入迴圈內StreamReader改用using,避免每個.txt漏一個檔案 handle 並鎖檔。
TsERP/E.Order/Preord.xaml.cs、TsERP/G.Purchasing/Ppur_sug.xaml.cs—Loaded訂閱 VM 的OnColumnHeaderChanged沒有對應-=,導覽快取的長命 VM 會永久 root 住每個 View,且重新載入時處理器累加。改為「先-=再+=」並於Unloaded解除。
尖峰配置量降低
ViewModel/Reports/FastReportExtension.cs— 報表寫檔由File.WriteAllBytes(path, ms.ToArray())改為ms.Position = 0; ms.CopyTo(fs),避免每次列印/匯出在 LOH 另配一份完整 byte[]。
LogicBll/M.EIS/ProductionPlan/ProductionPlanBll.cs— 生產計劃查詢組 CSV 參數字串由迴圈+=(O(N²))改為string.Join。
Breaking Changes
無。
Migration Notes
無需 migration。純內部修正,無 schema、API 簽章或 UI 行為變動。
備註
下列項目經查證後刻意不改:
- 圖片轉換器
DecodePixelWidth:ResourceImageConverter/FileImageConverter綁的是明細頁單張圖/Logo/按鈕圖示,非逐列 grid 縮圖,固定 decode 寬度會讓全尺寸圖變糊;且ResourceImageConverter已有 256 上限+Freeze。
Model/ReportBll.cs雙份物化:DataSet為區域變數,return 後即可回收,「兩份」僅轉換當下短暫並存。
延後(需 runtime 驗證的獨立後續):瀏覽匯出路徑(
SQLiteForBrowse.GetReportSource+ErpBrowseBaseViewModel.MakeReportSource)單次走訪串流化,以消除匯出當下的短暫 2× 峰值。 -
06-16 report-attached-data-signed-pdf ▸
報表用途含「附加資料」→ 匯出/寄送 PDF 嵌入簽章資料附件
日期:2026-06-16
模組:報表列印(PrintLayout)+ PoCollaboration
摘要
延續採購協同簽章 spike,把「資料簽章後嵌入 PDF」接進通用報表列印流程:報表登錄表
報表用途含「附加資料」的報表,在預覽匯出 PDF與Email 寄送時,會把報表資料來源簽章成信封並以 PDF/A-3
AddEmbeddedFile嵌入 PDF;對方系統可讀回驗章後匯入。新增
- 預覽畫面「匯出PDF」按鈕(
TsFastReportPreview):SaveFileDialog 選位置匯出;
報表用途含「附加資料」時自動產生 PDF/A-3 + 嵌入簽章信封,否則一般 PDF。
- 共用層(
ViewModel/L.Communication/PoCollaboration):
-
ReportPdfExporter:把「已 Prepare 的 Report」匯出 PDF;給信封 bytes 則走 PDF/A-3 + 嵌入。-
ReportAttachmentService:報表用途含「附加資料」→ 讀資料來源 → 簽章成信封 bytes。signerId=統一編號、signerName=公司名稱(取自EnvironmentSetting)。LogicBll/PoCollaboration/Core:
-
ReportDataJson:DataTable→ 穩定 JSON bytes(簽章對象)。-
PoSigner.BuildEnvelopeFromBytes(...):泛化簽章(PO 與報表資料共用)。- 單元測試:
ReportDataAttachmentTests(資料序列化穩定、信封 round-trip、竄改驗證)2 支。
變更
SignatureEnvelope新增signerName(公司名稱)與payloadType(PO/REPORT-DATA)欄位。
IContentWindowService.ReportPreview加選用參數byte[] attachmentEnvelopeJson = null;
WindowService同步;PrintHelper預覽分支預先以ReportAttachmentService簽好信封傳入。EmailPrintHelper.ToPdfByGroup:每群組若需附加資料,改用ReportPdfExporter帶簽章附件匯出。
SliyCarrierPdfWriter改用共用ReportPdfExporter(行為不變)。
ReportPrintSource加需附加資料(報表用途含「附加資料」)。
刪除
無
Breaking Changes
無(既有 172 支測試全綠;
報表用途不含「附加資料」者行為完全不變)Migration Notes
- 無資料庫異動;要啟用某報表的附加資料,把該報表登錄列
報表用途設為含「附加資料」。
- 簽章金鑰目前用 interim 固定容器
TsErp.PoCollab.OrgSigning;正式金鑰產生/備份/配對待規格 §7 向導。
- 預覽/Email 只在「會輸出 PDF 檔」的動作嵌附件;直接列印(送印表機)不產生 PDF 故不嵌。
- 預覽畫面「匯出PDF」按鈕(
-
06-16 prodplan-usage-date-and-sim-message ▸
生產計劃查詢:使用量日期格式/模擬插單提示訊息明確化
日期:2026-06-16
模組:M.EIS 生產計劃查詢 (pd_qry7)
摘要
兩處顯示/提示的小修:「使用量(機種別)」頁的日期欄改顯示
yyyy/MM/dd,以及「模擬插單」按「套用模擬」跳出的籠統「沒資料」訊息拆成兩句可診斷的說明。
變更
- 使用量(機種別)頁「日期」欄改顯示
yyyy/MM/dd:該欄綁定
Twork_eis_vw_productiond4Source.日期(System.DateTime),原本漏設IsStringSource="False",走預設ToString()顯示成2026/6/16 上午 12:00:00。補上後套用
yyyy/MM/dd格式,與生產計畫頁一致。- 模擬插單「套用模擬」訊息明確化:原本兩種失敗都跳同一句
MessageEnum.NoData
(「沒資料」),無法判斷原因。現拆為:
- 尚未查詢(
_lastBll == null)→「請先執行查詢,取得基準資料後才能套用模擬。」- 無可套用訂單(
AppliedCount == 0)→「沒有可套用的模擬訂單。每筆需填寫品號、數量(大於 0)與預訂交期;若剛輸入完,請先按 Enter 或點到其他列讓資料落定再套用。」
新增
無
刪除
無
Breaking Changes
無
Migration Notes
- 無資料庫異動。需重建 TsERP(XAML 改動)與 ViewModel(訊息改動)後生效。
- 模擬插單為記憶體 what-if,須先在條件面板執行「查詢」取得基準快照,才能套用模擬。
- 使用量(機種別)頁「日期」欄改顯示
-
06-16 prodplan-sim-reduction-and-ui ▸
生產計劃查詢:模擬減單 + 結果頁與條件面板版型調整
日期:2026-06-16
模組:M.EIS 生產計劃查詢 (pd_qry7)
摘要
模擬功能由「只能插單」擴充為可加單也可減單(數量填負數=抵減既有需求),
並做了一批結果頁與條件面板的版型/可讀性調整。
新增
- 模擬減單:模擬訂單「數量」可填負數,代表減少既有需求(釋放庫存)。
缺口與金流會反映加單/減單的淨效果。詳見 ADR 0040。
- 金流預測圖表 Y 軸縮放:圖表加
ChartPanAndZoomBehavior
(
ZoomMode/PanMode=Vertical),滑鼠滾輪可放大垂直軸、拖曳上下平移;橫軸年月不縮放。變更
- 「樞紐分析」頁移到最後一頁(原在「原物料用量」與「金流預測」之間)。
- 「庫存缺口」頁更名為「原物料用量」(含條件面板步驟③說明文字同步更新);
內部 grid 名稱與 VM 屬性不變。
- 金流明細收/付配色:
dg金流明細依「收付」上色——收(進帳)淡綠、付(出帳)淡紅。
- 模擬「數量」欄標題改為「數量(負=減單)」;「套用模擬」失敗訊息補上
「正數=插單、負數=減單抵減既有需求」說明。
- 條件面板版型:步驟①/成本匯率/步驟② 改為三欄並排(成本匯率獨立中欄);
「金流預測」GroupBox 內「帳款立帳起日」「資金警戒線」改為兩排水平並列。
刪除
無
Breaking Changes
無(既有「只插單」用法完全相容,正數行為不變)
Migration Notes
- 無資料庫異動。需重建 LogicBll / ViewModel / TsERP 後生效。
- 模擬為記憶體 what-if,須先在條件面板執行「查詢」取得基準快照,才能套用模擬。
- 受影響邏輯:
RunSimulation閘門放寬為數量 != 0、CashFlowComposer
計劃預測收移除
Math.Abs保留正負號、ShortageCalculator缺口量僅對正需求計算。 -
06-16 prodplan-query-cashflow-fixes ▸
生產計劃查詢:缺口品號彙總/金流來源過濾/到期日防呆
日期:2026-06-16
模組:M.EIS 生產計劃查詢 (pd_qry7)、共用控件 TsRadGridView、共用 PayTermDate
摘要
延續 2026-06-11 的缺口/金流/模擬功能,補強顯示與健全度:庫存缺口新增品號彙總
master-detail、金流預測新增來源過濾並修正 Y 軸格式,並修掉一個會讓整支查詢崩潰的
到期日計算缺陷與無日期資料污染圖表的問題。
新增
- 庫存缺口-品號彙總表:缺口頁上半新增「品號彙總」(master),依層級+品號彙總
需求數量合計/缺口量合計/缺口筆數/最早短缺日;選一列下方明細只顯示該品號需求列,
上方「顯示全部」按鈕清除選取回顯全部。缺口品號(缺口量>0)優先排序、紅底標示
- 金流預測-來源過濾:頁頂新增「基礎(票據/帳款)」「推估(在途採購/計劃預測)」兩個
勾選(預設全開),即時重算圖表(基準柱/模擬柱/累計淨額折線)與明細
- TsRadGridView.ClearFilterOnItemsSourceChanged(共用控件,opt-in,預設 false):
設 True 時重新查詢(ItemsSource 換新集合)會自動清掉殘留的欄位篩選;排序/群組不受影響。
本頁各查詢結果表已啟用
變更
- 生產計畫頁「日期」欄改顯示
yyyy/MM/dd:該欄為 DateTime 來源,補上
IsStringSource="False"套用格式(原本以預設 ToString 顯示)- 金流預測 Y 軸格式修正:
LabelFormat由{}{0:N0}改為N0
(Telerik 軸吃純 .NET 格式字串,組合格式會失效導致無千分位)
- 金流預測排除無有效日期項目:來源單據缺交期/需求日期造成的
0001/01/01(MinValue)
不再進金流明細與圖表;排除筆數以警告提示(不靜默)
修正
- PayTermDate.DateAdd 年份補零(共用,影響全 ERP 到期日計算):年份未補零,
年份<1000(如 MinValue
0001/01/01)會產出1/02/01,下一輪Left(4)取到1/02→
int.Parse例外。改用ToString("D4"),對正常年份(≥1000)為 no-op。此缺陷會經金流預測 →
CashFlowComposer→ResolveDueDate直接讓整支查詢崩潰- ResolveDueDate 防護網:到期日推算失敗不再中斷查詢,改回空字串讓
CashFlowComposer退回基準日,並以收付條件去重記一次警告供追根- 使用量(d4) 金額 Context NullReference:
Twork_eis_vw_productiond4Source的 ctor
收了
IAppContext卻沒呼叫SetContext,Context恆為 null,金額getter 取Context.Env.LocalDecimal必拋 NullReference。改為:ctor 無參化;金額改成建檔時於GetUsageBom(Context 可用處)算好存入的儲存屬性(本位幣小數位數四捨五入語意不變)刪除
無
Breaking Changes
無
Migration Notes
- 無資料庫異動。
ClearFilterOnItemsSourceChanged為 opt-in,其他查詢畫面如需「重查清篩選」
在 XAML 加
ClearFilterOnItemsSourceChanged="True"即可- 若金流預測出現「已排除 N 筆無有效日期」警告,代表來源單據(多為訂單預訂交期)缺日期,
該補齊來源單據日期後重查
-
06-16 po-collaboration-signature-spike ▸
採購協同 簽章版 MVP:第 0 步 Spike(傳票載體)
日期:2026-06-16
模組:PoCollaboration(新)— L.Communication
摘要
依《採購協同_簽章版MVP_規格書》§10 先做 Spike,驗證「簽章 → 嵌入傳票 PDF/A-3 → 讀回 → 驗章」
端到端可行。因目前無採購單報表,先用既有傳票(Sliy)報表當人看的載體(規格 §8.2:簽的是 payload
bytes 不是 PDF,載體換誰對驗章零影響)。詳見 ADR 0041。
新增
- PoCollaboration 核心(純邏輯,
LogicBll/PoCollaboration/):
-
Core/PoPayload、CanonicalJson(穩定 UTF-8 bytes,規格 §8.3)、SignatureEnvelope(信封 §5.3)、PoSigner(RSA-3072 / SHA-256 / PKCS1 簽驗 §8)、EmbeddedFileReader(PdfPig 讀回嵌入附件)。-
Keys/CngSigningKey(RSA-3072 CNG,不可匯出;MachineKey 優先、無權退回 CurrentUser)。-
Receiving/IInboundProcessor+InboundProcessor(解耦可獨立呼叫的「讀附件→驗章」服務,規格 §4)。- 載體與 Spike(
ViewModel/L.Communication/PoCollaboration/):
-
SliyCarrierPdfWriter:用傳票報表匯出 PDF/A-3 並AddEmbeddedFile嵌入po-data.json。-
IPoSpikeService/PoSpikeService:串接 sign→embed→read→verify,含竄改/錯誤公鑰負向測試。- 暫時開發觸發:MainWindow 熱鍵 Ctrl+Alt+P → 跑 Spike,結果寫桌面
PoCollabSpike\並訊息框顯示。
- 單元測試:
LogicBllTests/PoCollaboration/PoSignerTests(canonical 穩定、簽驗、竄改、錯誤公鑰、
缺簽章、CNG round-trip)共 6 支,全綠。
- 相依:
PdfPig 0.1.9(LogicBll)。
變更
TsERP/DIExtension.cs:註冊IInboundProcessor、IPoSpikeService。
TsERP/MainWindow.xaml、MainWindowViewModel、ErpSystemContainerViewModel:加暫時 Spike 觸發。
刪除
無
Breaking Changes
無(純新增;既有 170 支單元測試全綠)
Migration Notes
- 無資料庫異動(Spike 用記憶體/檔案)。重建需 VS 2022 MSBuild。
- 如何驗收兩大風險(規格 §10):執行 ERP → 登入並開啟任一程式 → 按 Ctrl+Alt+P →
看桌面
PoCollabSpike\的 PDF(用 Acrobat/Edge 確認可開)與spike-result.txt。任一風險不可行 → 依 §10 停下回報,評估 sidecar / PDFsharp / iText。
- 明確未做(下一階段):加密(§2.2 禁止)、金鑰備份/配對向導、IMAP/SMTP、狀態機、正式 UI、正式 SQL 表。
- PoCollaboration 核心(純邏輯,
-
06-16 directsavetosqlite-audit-fields ▸
2026-06-16 修正轉單/批次上傳的稽核欄位(輸入人員等)未寫入
摘要
修正
ItemsBindingManager.DirectSaveToSqlite上傳時漏蓋稽核欄位的問題。最明顯的症狀:進貨轉應付(paypdt)存檔後,資料庫的「輸入人員」欄變成廠商名稱,而非實際登入者。
變更
DirectSaveToSqlite在把資料寫進本機 SQLite 前,補呼叫SourceBase.SetUploadValue(),
與 EF 追蹤路徑(
LocalDbContext.ApplySyncFields在SaveChanges時的行為)對稱。- 受影響的稽核欄位會正確設定為「當下這次上傳」的值:
-
輸入人員= 登入者、輸入日期= 現在、輸入地點= 機器名、logid、選擇清空。-
建檔人員/建檔日期:只有原本為空才補(Edit 不會蓋掉原始建檔資訊)。影響範圍
所有走
DirectSaveToSqlite的功能一併修正:全部轉單(進貨/暫估轉應付、零用金轉入、票據異動、轉傳票家族、付款轉沖帳…)以及附件、結帳、改密碼、使用者設定、表格版型存檔、AutoPilot 匯率等。
這些情境語意都是「當下登入者執行上傳」,蓋成登入者為正確行為,也與舊
AdeUploadBll路徑一致。背景(為什麼 paypdt 會變廠商名)
轉帳查詢刻意借用「輸入人員」欄帶廠商簡稱做預覽顯示(沿襲 VFP
paypdt.prg:c.廠商簡稱 AS 輸入人員;費用路徑輸入人員 = 客廠名稱)。舊上傳路徑會在送出前用SetUploadValue蓋回登入者;遷移到ItemsBindingManager後,DirectSaveToSqlite走UpsertBatch直寫 SQLite、略過 EF 與該蓋值動作,導致廠商名直接存進 DB(並使存檔後以「輸入人員 = 登入者」撈剛存單號的訊息撈不到)。
Migration Notes
無資料庫結構變更。已存在、輸入人員被誤存成廠商名的歷史單據不會自動修正,必要時需另行更新。
待驗證
實機存一張 paypdt 進貨費用單,確認 DB
輸入人員= 登入者、存檔後起訖單號訊息正常。 -
06-15 prodplan-sp-failure-surfaced ▸
2026-06-15 生產計劃查詢:SP 失敗不再靜默回空
摘要
生產計劃查詢(pd_qry7)的「庫存缺口」「金流預測」tab 依賴擴充 SP(
TWORK_QRY_PRODPLAN_SUPPLY/TWORK_QRY_PRODPLAN_CASHBASE)。先前若 SP 未部署或proc_param未登錄,ProductionPlanBll會在BuildShortage()/BuildCashFlow()直接return,結果靜默回空,使用者執行後看到對應 tab 空白卻沒有任何提示,無法判斷是「資料面沒料」還是「SP 沒裝」。變更
ProductionPlanBll新增Warnings清單。三個原本靜默return的點(Handle()基礎資料、BuildShortage()供給、BuildCashFlow()金流)SP 失敗時改寫入帶有 SP 名稱與部署腳本路徑的警告訊息,其餘結果照常顯示。
ProductionplanViewModel.Query()查詢完若有Warnings以提示框一次列出。
- 修正
ProductionplanViewModel.Query()失敗分支的 bug:原本Context.MessageService.GetMessage(MessageEnum.SystemError)只取回字串就丟棄、不跳框,改為TsMsgBox.ShowExclamationMessage(...)。
測試
新增
LogicBllTests/M.EIS/ProductionPlan/ProductionPlanBllTests.cs(9 個測試):BuildDemands:成品/材料合併、層級與欄位對應、數量 0 略過、模擬旗標傳遞。
GetUsageBom:有 BOM 展開用量、品號無 BOM → 使用量為空(記錄此口徑,避免日後誤判為 bug)、多組件各自展開。
ProductionPlan 測試資料夾共 26 個測試全通過。
Breaking Changes
無。
Migration Notes
此變更只負責「把錯誤顯示出來」,不會自動修復空白資料。若「庫存缺口/金流預測」實際為空,仍需在 DB 執行
sql/TWORK_QRY_PRODPLAN_EXT_darbnogicsa1.sql(建立兩支 SP + 登錄proc_param,檔尾含登錄段)。「使用量」為空通常是該計畫品號無 BOM 展開,屬資料面。 -
06-15 prodplan-condition-horizontal-pivot-drilldown ▸
生產計劃查詢:條件面板水平化+樞紐分析雙擊看明細
日期:2026-06-15
模組:M.EIS 生產計劃查詢 (pd_qry7)
摘要
條件面板從縱向堆疊改為水平版面以壓低高度;樞紐分析頁籤新增雙擊彙總格
drill-down 顯示背後訂單明細的功能。
新增
- 樞紐分析 drill-down:在「樞紐分析」頁籤雙擊任一彙總格 → 彈出唯讀明細視窗,
顯示該格(客戶×品號 對 年×月)背後的原始訂單明細(欄位沿用第一頁訂單頁全套)。
雙擊在表頭/空白/無對應彙總格會安全略過。
變更
- 條件面板版面水平化:步驟①(查詢條件+成本匯率)移到左欄、步驟②(客戶設定 grid)
移到右欄並佔滿剩餘寬度與高度、步驟③說明橫跨底部。面板因此變寬變矮、客戶設定 grid
配合可用高度自動拉伸(原為縱向堆疊、整體偏高)。
刪除
無
Breaking Changes
無(第一頁訂單排序維持原本 訂單→預示→預估 分區塊的後端 SQL 順序,未更動)
Migration Notes
- 無資料庫異動;純前端版面與互動調整。
- 修正一處 cross-thread:樞紐
LocalDataSourceProvider餵 ItemsSource 與
GetUnderlyingDataCompleted皆於背景緒觸發,已 marshal 回 UI 緒(DispatcherObject執行緒親和)。
-
06-12 stale-english-cleanup-batch1 ▸
2026-06-12 英文殘留屬性中文化清理(批次 1)
摘要
DB schema 已全面中文化,但 E.Order / J.QC / P.Invoice / H.Inventory 多支 Source/Model 仍殘留英文
[TsColumnName]屬性(DB 已無該欄 → 載入永遠空白、儲存靜默遺失)。本批以 DB view 實際欄名為準,將殘留英文屬性改名為中文、砍掉 DB 已廢除的欄位屬性,並連動修正 C# caller 與 XAML binding。
另對 sample / visit / repair 三支做 VFP 深度對比,缺驗證/預設值直接補修。
F.Production 的 wkpaper 家族不在本批(另案);C.GeneralAffair 由另一 agent 作業。
變更
Twork_ord_vw_samplema(送樣聯絡單 主檔)
英文(舊) 中文(新) DocumentNo 送樣編號 CustomerCode 客戶代號 CustomerName 客戶簡稱 SalesRepCode 業務員編號 Applicant 申請人 DocumentDate 開立日期 NotesID 聯絡單id WorkflowCode 工作流程 Auditor 審核人員 AuditDate 審核日期 IsApproved 已審核 - 砍除:
CreatedDate(DB 無 建檔日期 欄)、SysEntryDate/SysEntryUser/SysEntryMachine/SysRowStatus/SysIsChosen/SysControlCode(改繼承 ModelBase 中文欄)
- 砍除 NotMapped
SalesRepName→ 改用 view JOIN 欄姓名(vwseek_salesmen)
- 補真缺欄:
流程樣板號、姓名(DB 有、原本無任何對應屬性)
- 保留 NotMapped
ApplicantName(view 無對應欄)、CustomerCodeBinding
Twork_ord_vw_samplede(送樣明細)
英文(舊) 中文(新) LineNo_ 序號 Material 材質 Type 型別 Spec 規格 Processing 加工 LocalDescription 中文描述 ImageNo 圖號 ETA 指定納期 CompletionDate 完成日期 Quantity 數量 Acknowledgment 承認書 Portion 份數 IsSample 是否打樣 ShippedQuantity 已交數量 IsClosed 是否結案 Notes 備註 (Model) SKU / SKUDescription / UnitOfMeasurement 品號 / 品名 / 單位 - 砍除 Sys* 6 欄;字串長度/小數位對齊 DB(材質 4、規格 20、數量 16,4 等)
Twork_ord_vw_visit(拜訪單)
- 改名:
CompanyCode→公司代碼、SalesRepCode→業務員編號、SalesRepCodeBinding→業務員編號Binding
- 砍除:
NotesID/WorkflowCode/Auditor/AuditDate/IsApproved/CreatedDate(visit 表與 vw_visit 均無此欄,DB 已廢除)+ Sys* 6 欄
- 砍除 NotMapped
受訪名稱/SalesRepName/業部門名稱→ 改用 view JOIN 欄客戶簡稱/客戶名稱/姓名/部門簡稱(補 4 個 mapped 欄)
RefreshDescription()、GetContent()同步改用中文欄
Twork_jqc_vw_repair(叫修單)
- 改名:
CompanyCode→公司代碼、CustomerCode→客戶代號、SKU→品號
- 砍除:
NotesID/WorkflowCode/Auditor/AuditDate/IsApproved/CreatedDate(DB 已廢除)+ Sys* 6 欄
- 砍除 NotMapped
CustomerName/SKUDescription→ 改用 view JOIN 欄客戶簡稱/品名(補 mapped 欄)
- 保留 NotMapped
服務人員姓名/購買日期(view 無對應欄)
Twork_jqc_vw_purama(暫收單 主檔)
英文(舊) 中文(新) TempReceivingDocumentNo 暫收單號 DocumentPrefix 序號前置碼 PurchasingType 採購別 CompanyCode 公司代碼 WarehouseCode 倉儲代號 TempReceivingDate 暫收日期 ProductionDepartmentCode 生產部門 Currency 幣別 QCOver 檢驗完畢 Remark 暫收備註 MaterialUsageTransactionNo 耗料單號 CreatedDate 建檔日期(型別 string→DateTime,對齊 DB datetime) NotesID 聯絡單id WorkflowCode 工作流程 ProductionDepartmentName 客廠部簡稱(view JOIN cusp) - 砍除(DB 已廢除,22 個):
Auditor/AuditDate/IsApproved、TempReceivingType/VendorCode/VendorName/Trno/InvoiceNo/ShipViaCode/VesselBookingNo/BillOfLadingNo/DeclarationNo/DeclarationDate/CBM/WGT/ETD/ETA/LoadingPort/ETAInWarehouse/PDFFile/TurnInNote/TurnOutNote/ContainerNo+ Sys* 6 欄
- 保留 NotMapped
WarehouseName
Twork_jqc_vw_purade(暫收明細)
⚠️ 此檔同概念新舊兩套英文並存(如 InspectionDate/InspDate),以 DB 中文欄為準收斂成一個中文屬性:
中文(DB 欄) 收斂自(兩套英文) 序號 LineNo_ 庫存管制 InventoryControl 廠商品號 VendorSKU 數量 / 單價 / 幣別 Quantity / UnitPrice / Currency 金額 CurrencyAmountWithoutTax(砍 CurrencyAmount、Amount) 預訂交期 ETA(砍 ETD) 備註 Remark 檢驗日期 InspectionDate(砍 InspDate) 檢驗人員 InspectionStaff(砍 InspStaff) 須否成績表 NeedGrade(砍 IsRpt) 入庫日期 WarehouseInDate(砍 InstkDate) 檢驗別 InspectionType(砍 InspType;DB tinyint 與 byte 型別吻合) 包裝材料 PackagingMaterial(砍 Pkmat) 包裝量_包 / 包裝量_箱 MinimumPackageQuantity / QuantityPerCarton(砍 BagQuantity / CtnQuantity) 儲位 Bin(砍 Site) 成績表扣分 IsGradeMinus(砍 RptMinus;DB char(1) 與 string 吻合) ng數量 / 特採數量 / 入庫數量 NGQuantity / AcceptOnDivisionQuantity / WarehouseInQuantity(砍 SpeadmQuantity / InstkQuantity) 問題點 / 確認 / 抽檢數量 / 檢驗結果 Question / Confirmed / SampleQuantity / InspectionResult(砍 Cinfirmed / SampQuantity / InspResult) 是否結案 / 品質管制日 / 管制批數 / 暫收批數 / 合格 IsClosed / QualityControlDate / ControlLotNum / TempReceivingLotNum / IsAcceptable ng退貨量 / ng退貨日 NGReturnQuantity / NGReturnDate 採購單pkid / 製通單pkid / 派工單pkid / 生產單pkid PurchaseOrderLinePkid / ProductionOrderPkid / WorkOrderPkid / WorkDailyReportPkid 停用說明 / 管制說明(view JOIN) IsDisabled / InventoryControlDescription 派工單號 / 生產單號 / 採購單號 / 合格批數(view JOIN) WorkOrderNo / DailyWorkDocumentNo / PurchaseOrderNo / AcceptableCount - 另砍:
ContNo/ContSize/Instk01~10/InstkQuantity01~10/OtherCost(DB 無)+ Sys* 6 欄
單價精度修正為 DB 實際 (16,6)
Twork_inv_vw_tickadisc_m(折讓單 主檔)
- 砍除英文舊屬性(中文欄屬性先前已補好):
FinancialCategory(→財務類別)、NotesID(→聯絡單id)、WorkflowCode(→工作流程)、Auditor(→審核人員)、AuditDate(→審核日期)、IsApproved(→已審核)、CreatedDate(DB 無)+ Sys* 6 欄
客廠部代號Binding內FinancialCategory == "22"改財務類別 == "22";Model 建構子重複初始化清理
Twork_stk_vw_trrafee(費用明細)
- 砍除:
CustVendDeptName(→客廠部簡稱)、AccountDescription(→科目名稱)(中文 view 欄已存在,無 C# caller,僅 Trrama.xaml 兩欄 binding 改中文)
檔名修正
Model/Source/N.GeneralLedger/Twork_acc_vw_budgetSoruce.cs→Twork_acc_vw_budgetSource.cs(git mv,class 名原本就正確,僅檔名 typo)
Caller 連動修正
C#(23 檔)
- E.Order:SampleViewModel(新增預設 開立日期/申請人)、SampleSave、Sample1Bll、Sample1Source(SP 回傳欄 修改人員/送樣編號/客戶代號/客戶簡稱/開立日期 改中文,修復原本對不上的 mapping)、VisitSave、Visit_weekly/daily/customer/mileage ViewModel(查詢 SQL 原用英文欄名打中文 DB,runtime 必錯,全改 業務員編號/姓名;mileage 加欄位別名對應報表 Poco)
- J.QC:RepairViewModel、RepairSave、Purama/Twrama/Wkrama ViewModel(建檔日期 改 DateTime.Now、列印改用 生產部門)、Purama/Twrama/Wkrama Save、Purama_E/Twrama_E/Wkrama_E Bll(轉單組裝全改中文欄;移除寫入已廢除欄 VendorCode/TurnInNote/ContainerNo/ETA/CurrencyAmount/Amount)
- H.Inventory:TptoraBll(轉單條件改 生產部門/倉儲代號/檢驗完畢/數量/入庫數量;移除 ContainerNo 過濾——DB 已無此欄)、TptowkBll、TptowkViewModel
- P.Invoice:Ticka_discViewModel(FinancialCategory="22" → 財務類別)
XAML(10 檔)
Sample、Sample1、Visit、Visit_q(僅 visitSource 綁定的 tab,週報/里程 Poco 欄不動)、Repair、Purama、Twrama、Wkrama、Ticka_disc、Trrama。
Purama/Twrama/Wkrama 並移除已廢除欄位的整組 label+輸入框(InvoiceNo、TurnInNote、TurnOutNote、ETD、ETA、ETAInWarehouse、DeclarationNo/Date)與明細 ETD 欄。
刪除
- 已廢除 DB 欄對應之輸入欄位:暫收單 master 區的 Invoice No / Turn In Note / Turn Out Note / ETD / ETA / ETA In Warehouse / Declaration No / Declaration Date(DB purama 已無這些欄,原本輸入也存不進去)
- Tptora 轉暫收的「櫃號過濾」條件(DB 無 ContainerNo 欄,原查詢必噴 SQL 錯誤)
VFP 對比結果(sample / visit / repair)
🔴 已修:
1. sample —
客戶代號.Valid一律強制帶出 客戶簡稱(2014/04/03 鈞寶要求):CustomerCodeBinding 補客戶簡稱 = GetCustomerName(...)(原本寫進 stale 英文欄等於沒存)2. sample — 新增預設寫入不存在的 CreatedDate → 改寫
開立日期3. sample — allowsave「客戶代號或客戶簡稱擇一」→ SampleSave 對齊(原本只檢查代號)
4. visit — 新增時未帶
公司代碼、儲存未檢查公司代碼=0→ AfterAddNew 預設 1 + VisitSave 補檢查5. visit — 四支查詢 SQL 英文欄名(SalesRepCode/SalesRepName)打中文 view → 全改中文(原 runtime 必錯)
6. repair — 儲存未檢查
公司代碼=0且表單無輸入欄 → AfterAddNew 預設 1 + RepairSave 補檢查🟡 未修(列出待辦):
1. sample — 明細列
完成日期非空時該列唯讀(VFP grid1.AfterRowColChange)未移植2. sample — SAMPLE1 批次完成後跳轉至該筆(VFP else1click MOVEREC)未移植,現僅 Renew
3. visit — addagain 依公司別(禾久/台賓/可俐明)以登入者姓名反查業務員編號帶入之特例未移植
4. visit — 瀏覽 SEEK 可輸入「客戶簡稱?」模糊查詢(SEEK1.InteractiveChange)未移植
5. repair — VFP 公司代碼可輸入(新版表單無該欄位,固定帶 1);多公司環境需補輸入欄
Breaking Changes
- 本批 Source/Model 屬性名全面改中文:外部若有以反射/字串引用舊英文屬性名(含
.frx以外的自訂報表、AutoPilot 腳本)需同步改名。
Twork_jqc_vw_purama.建檔日期型別由string改為DateTime。
- 已廢除欄屬性(purama 航運欄、purade 重複英文欄、各表 Sys*/CreatedDate)直接刪除,無相容別名。
Migration Notes
- 不需 DB migration(DB 本來就是中文 schema,本批是 code 端追平)。
- 本機 SQLite staging 表為每次查詢重建,無需手動清理。
- Runtime 未驗:sample / visit / repair / purama / twrama / wkrama / ticka_disc / trrama 開窗、新增、儲存、轉單與四支 visit 查詢報表需人工驗收。
- 砍除:
-
06-12 scx_stk-ticka-trxama-fixes ▸
2026-06-12 — scx_stk 對比修補(ticka / trinout / trlima / trrama / trsama)
摘要
VFP
scx_stk五支單據(銷貨發票 H-100、出入庫申請 H-070、出入庫單 H-040、進貨單 H-010、出貨單 H-050)與新版深度對比後的修補。最大宗問題為 2025-12-10 Source 英→中屬性改名(commit e37e2809)後,H.Inventory 四支 XAML 完全沒跟著改,主檔/明細/費用欄位 binding 全數失效(開窗欄位空白、輸入不回寫)。本次以改名 commit 的對應表逐欄修復共 218 處 binding,另補回 4 項 VFP 驗證、1 項編輯防呆、1 個金額公式 bug、1 個代碼表別名錯誤。
變更
XAML stale binding 全面修復(使用者可見:欄位從空白恢復顯示/可輸入)
檔案 修復數 範圍 TsERP/H.Inventory/Trrama.xaml90 行 主檔(倉單號/單號/隸屬倉庫/廠商/幣別/匯率/發票/稅別/報單/提單/分攤費用/應收付…)、明細 grid 全欄、費用 grid 全欄 TsERP/H.Inventory/Trsama.xaml57 行 主檔(倉單號/單號/客戶/集團/業務員/發票/稅別/帳款期別/實際出貨日/應收付…)、明細 grid 主要欄位 TsERP/H.Inventory/Trlima.xaml49 行 主檔(倉單號/單號/交易部門/快遞號碼/程式註記/關聯單號/發票/稅別…)、明細 grid(含例外出入/不良/處理方式代碼欄) TsERP/H.Inventory/Trinout.xaml22 行 主檔(申請單號/申請日期/申請人員/申請部門/廠商/隸屬倉庫/申請原因…)、明細 grid(品號/申請量/單價/核發量/轉入倉儲…) 修法:英文 path → 現行 Source 中文屬性(依 e37e2809 改名對應表+現行 Source 屬性集逐欄核對),
Binding後綴的代理屬性對應到xxxBinding中文版(如SKUBinding→品號Binding、QuantityBinding→數量Binding/申請量Binding、PaymentTerm→收付條件號Binding(trrama))。Ticka.xaml(P.Invoice)逐欄核對結果全數正確,無需修改。驗證 / 防呆補齊(對齊 VFP)
LogicBll/Ade/P.Invoice/TickaSave.cs
- 補:課稅別=
4.作廢時,作廢日期、作廢原因必填(VFP allowsave)。- 補:存檔時幣別空白 → 預設本位幣+匯率 1(VFP changeopmode,與全系統新增預設一致)。
LogicBll/Ade/H.Inventory/TrinoutSave.cs
- 補:申請日期必填、申請部門必填、申請部門不得與隸屬倉庫相同(VFP allowsave 三條漏移植驗證)。
LogicBll/Ade/H.Inventory/TrlimaSave.cs
- 補:EO 單必須輸入維修人員(VFP allowsave)。
- 補:EI 例外出入碼=99(虛擬進貨)單價=0 不得存檔;存檔時自動補
交易別碼='OC'、單位成本=單價、其他資料2='自填成本',並先清除舊「自填成本」註記(VFP 2019/01/16 虛擬進貨邏輯)。LogicBll/Ade/H.Inventory/TrsamaEdit.cs
- 恢復被註解掉的 「已轉發票(發票號碼非空白)不得修改/刪除」 防呆(VFP allowedit;DeleteBll 同走此檢查)。
Bug 修正
LogicBll/H.Inventory/TrramaBll.cs(費用分攤 SetCostAmount)
- 原幣含稅公式錯誤:原寫成
ROUND(單價*(100+稅率)/100)(即含稅單價),漏乘數量、漏加其他金額。改為 VFP 公式ROUND(數量*含稅單價+其他金額, 幣別小數位數)。多數量明細的原幣含稅/本幣含稅原本嚴重失真。TsERP/H.Inventory/Trlima.xaml
- 明細「不良原因碼」下拉代碼表
TableAlias由 C219 改為 C246(VFP 用 cmb_246 報廢不良原因;C218/C220/C221/C245 其餘各欄核對正確)。未修(🟡 列出,含刻意不修)
- trinout:VFP allowsave 的倉儲代號連動驗證/自動補值鏈(依 LCL交易事項表/LCL交易別 的轉入/轉出部門 W/T × 倉同儲 Y/N 決定 轉入倉儲/轉出倉儲 與倉儲代號歸屬檢查)整段未移植——邏輯量大且依賴本地 LCL 表,需 runtime 驗證後另案補。
- trinout XAML Prime 殘留死欄:ApplyType/CUSTCATG/IsFree/Contact/Email/Fax/ShipTo 地址區塊/Attention/Instruction/To Warehouse(
Warehouse)/FreeSample/Pending/Restocked/Billed——Source 無對應屬性(部分疑為 特殊要求/詢比議記錄 的前身,對應不確定,不猜)。
- trsama XAML 死欄:DocumentCategory(進銷分類)/ProjectCode(專案代號)/ShipToAddress/PickDate/PackDate/TrlimaPkid/SKU1/Quantity1·2/UOM1·2/Density/StartPoint/EndPoint/聯單號碼/Remark/DiscountPercentage——屬性已在孤兒清理時刪除或為 trsama_房售 變體殘留。
- trrama XAML:
CompletedAllocation(分攤完成)全 codebase 已無屬性(Gtrrama 同樣殘留),死欄不動。
- VFP 按鈕差異(多為刻意重設計):
- ticka:else3「更新資料」(_CHANGENO 泛用工具) 未移植;批量匯出已對應
ExtendedFunction3→Ticka_export並非缺漏。- trrama/trinout:工作流程/快速審核 → 新版集中式 workflow(已知等價);trrama 特殊修改走框架 SpecialEdit。
- trsama:VFP 批次審核/批次改價/轉訂單/拆單/客戶標籤/借出出貨 vs 新版 訂單轉出貨/Picking/Packshipdate/PickingReport/Ratosa——按鈕集合重新設計,未逐一對應;trinout else3「轉入」(TRINOUT2) 未移植。
- trlima:CMDELSE2~6 在 VFP 即 Visible=.F.,不比;特殊修改走框架。
- ticka:VFP「發票日期必須是今日或本月最後一天」未移植——新版改為允許 發票月份/次月(雙月期別),視為刻意放寬。
- ticka 明細刪除條件:VFP 砍「品號與品名皆空」列,新版只看品號(影響極小)。
- trinout AfterAddNew:隸屬倉庫未帶
U_PRGPAR(7009)預設;公司代碼=1 寫死(與 trlima/trrama/trsama 一致的單公司慣例,不動)。
- trlima:IT 類「調撥金額合計必須=0」檢查為刻意註解(禾久品名調撥可輸單價);新版以分攤群組數量平衡檢查替代。
Breaking Changes
無資料格式變動。出貨單(trsama)已轉發票者將恢復「不得修改/刪除」防呆——此為 VFP 原有行為的回復,需修改時請走特殊修改(不受此限制)。
Migration Notes
無需 migration。XAML/ViewModel 變更需在 Visual Studio 內建置驗證(dotnet CLI 會撞既有 MSB4803,與本次改動無關);runtime 驗收重點:四支 H.Inventory 表單開窗欄位顯示、trrama 多數量明細含稅金額、trsama 已轉發票單據的編輯阻擋。
-
06-12 scx_stk-inv-splace-trlost-fixes ▸
2026-06-12 — scx_stk 對比修補:invbk1 / invrec / invstk / splace / trlost
摘要
VFP 舊版
scx_stk五支表單與新版 TsERP 深度對比(接續 commit9b69004d被中斷的前手批次):- invrec(盤點單 H-080)/splace(倉庫表 H-090):驗證前手修補,確認已完整,本批無新增修改。
- invbk1(交易進出查詢 H-060)/invstk(庫存明細表 H-120)/trlost(耗料單 H-020,含 Trlost_A 發送料):本批新對比並修補。
主要問題型態:2025-10 英→中 schema 改名後殘留的 stale XAML binding(欄位永遠空白)、BLL 查詢 SQL 用到已不存在的英文欄名(runtime 必炸)、查詢條件沒傳給 SP、計算欄串接半成品。
變更
invbk1(交易進出查詢)
Invbk1ViewModel:Bll 改以new Invbk1Bll(context)建構(原無參建構 Context 為 null,查詢必 NRE);移除BeginningBinsetter 內無條件覆寫EndingBin的贅行(清空起始倉儲會把截止倉儲蓋成空字串)。
Invbk1Bll:
- 儲位範圍條件原本拼好但沒傳給 SP(傳的是不含儲位的
skuCondition),且截止儲位誤用BeginningSKUBin(複製貼上 typo)——已改傳完整condition並修正 typo。-
EndingSKUBin預設由zzzzz改回 VFP 哨兵龜鶴遐齡(避免漏排序在 z 之後的中文儲位)。- 交易別碼+交易事項串接:變數算了沒用,三處改用串接後的
transactionCode(明細/日記帳「交易別碼」欄補上中文說明)。- PC 異領單轉入單號補值半成品:原本算出 index 後什麼都沒做,已照 VFP 從
trwkma.轉入備註取「:」後申請單號覆寫PriorTransactionNo。- 品號群組「品號結尾」標記 off-by-one:最後一組末筆補標。
invstk(庫存明細表)
Invstk.xaml:3 處 stale binding 修正(SKU→品號、SKUDescription→品名、ReservedQuantity→ReserveQuantity),主表三欄原本永遠空白。
InvstkBll:
- 品名「包含」查詢 LIKE 補
%(原為完全比對)。- 訂單查詢 SQL 欄名修正:
ETA/ShippedQuantity/結案/訂單號碼→ DB 實欄預訂交期/已交數量/是否結案/訂單編號(原 SQL 必炸)。- 負庫存查詢 SQL 重寫:補
a/b表別名、WHERE 前空白、twork_stk_vw_invstk改回invstk(照 VFP 等價寫法)。- 預訂交期預設改
今天+60 天(VFPDATE()+60的業務意圖:抓 60 天內未交訂單)。trlost(耗料單)+ Trlost_A(發送料轉單)
Trlost.xaml:整頁 stale 英文 binding 全面修正(master 12 處+detail 24 處,修正前所有主檔欄位與大部分明細欄空白);移除 9 個綁定到已刪 DB 欄的孤兒欄/區塊(Quantity1/2、UOM1/2、VehicleNo、EmployeeName、StartPoint、EndPoint、ProjectCode 區塊);補備註1欄(VFP 有)。
Trlost_A.xaml:detail grid 11 處 stale 英文 binding 改中文屬性。
Trlost_APoco/Trlost_APoco1:英文屬性補[TsColumnName]中文欄名映射(對中文 schema SP 回傳欄名原本永遠映射不到,轉單查詢全空)。
TrlostViewModel:listener 的nameof由誤借trlimaSource改正為trwkmaSource(值相同,純正確性)。
前手驗證(invrec / splace,commit 9b69004d)
驗證結論:兩支均已完整,無需再補。
- invrec:欄位/binding 全數 cross-check 通過;
InvrecSave(製單日期/隸屬倉庫必填+倉同儲自動帶倉儲+空列標刪)、InvrecEdit(盤點備註防呆)、IOther1~3(重算帳列/執行確認/轉盤點單)與 VFP else1~3 對齊;快速審核=集中式 workflow(等價);查詢鈕→Invrecm視窗存在且有 VM。
- splace:
SplaceSave涵蓋 VFP allowsave 全部(另多虛擬倉儲自動建立=新版擴充);倉同儲 LostFocus 連動、現有數查詢(DARB_TUR_SPLACE查詢別=2)、批次關帳(else1→Stkbas_1)均對齊。
未修(🟡 已知差異,列入待辦)
- invbk1:
TWORK_INVBK1SP 未部署於 darbnogicsa1 且 proc_param 未登錄(查詢會靜默回空,需部署+登錄);群組代號查詢路徑不可達(UI Collapsed);所有倉庫 chk 與起迄倉庫必填驗證未移植;Journal 頁 p2 查詢鈕、明細 5 個註解欄、單號 drill-down、報表(僅 Excel 匯出)未移植。
- invstk:
TWORK_QRY_INVSTKSP 未部署(本庫只有 DARB 版,且其第 3/5 result set 缺隸屬倉庫欄)+ VM 預設WarehouseOnly="PR"(Prime 專屬倉)三件一體,需部署決策後 runtime 才能跑;今年/去年出貨量、篩選別、品號雙擊連結、交期不同紅底列色、出貨通知單查詢別(刻意隱藏半成品)、起始品號 LostFocus 自動查詢未移植。
- trlost:
TWORK_TUR_TRLOST_ASP 未部署(腳本已備於.claude/tmp/scx_stk/TWORK_TUR_TRLOST_A.sql,請在 SSMS 執行);轉單彈窗家族WindowHelper.OpenWindow+code-behind VM 註解的系統性開窗問題(跨數十支,需 window-to-tsview 專案統一遷移,本批不動);else8 調整耗料(TRLOST_S)未移植;發票四欄被註解;本國幣總額 footer、關聯單號 DblClick 連結、部分 VFP 明細欄(責任單位/退貨日期/轉入單號等)未移植;Model 的材料單價/建檔日期與本機 DB 不一致疑待 migration(需 runtime 驗證)。
- Trlost_A 的 VFP 原始碼缺(獨立 .scx 未匯出),本批僅做新版一致性修補;如需逐欄對比請提供
TRLOST_A.scx匯出檔。
Breaking Changes
無。均為缺陷修補與顯示修正,不改資料格式。
Migration Notes
- runtime 驗收前需在 darbnogicsa1 部署並於 proc_param 登錄:
TWORK_INVBK1(param_qty=6)、TWORK_QRY_INVSTK(需含隸屬倉庫欄)、TWORK_TUR_TRLOST_A(腳本已備)。
- 本批依指示未 build;XAML/ViewModel 改動請於 Visual Studio 建置驗證(dotnet CLI 會撞既有 MSB4803)。
-
06-12 scx_ord-ormast-pk-fixes ▸
2026-06-12 — SCX_ORD ormast (E-060) / pk (E-100) VFP 對比修補
摘要
VFP
scx_ord.prg的ormast(訂單管理)與pk(PACKING LIST)跟新版深度對比後的修補。最大宗問題:2025-10 Source 屬性英→中改名(commit
fd97583d)沒同步改 XAML,Ormast.xaml / Ormast_US.xaml / Pk.xaml 合計 160+ 個 binding 綁到已不存在的英文屬性名,
欄位全部永遠空白、輸入不回寫。
變更
XAML dead binding 全面修正
TsERP/E.Order/Pk.xaml:23 處(主檔 cino/ci日期/製表日期/pino/商品名稱/幣別/頁首備註/頁尾備註/正嘜;明細 序號/客戶品號/單箱數量/毛重/淨重/產品描述/單位/材積/單箱材積/廠商代號/客戶訂單號 等)
TsERP/E.Order/Ormast.xaml:27 處(主檔 訂單號碼/受訂日期/倉庫/幣別/匯率/運送方式碼/付款方式碼/收付條件號/稅別/專案代號/客戶訂單號/ORDERCLOSE/總原幣未稅/總本幣未稅;明細 序號/品名/客戶品號/單位/DISCOUNTPG/原幣未稅/本幣未稅/備註/PICKEDQTY/結案)
TsERP/E.Order/Ormast_US.xaml:121 處(依fd97583d改名對照表機械還原,含註解區一併校正)
VFP 行為補齊
- Ormast.xaml 新增「交易條件 (C202)」下拉(VFP 主檔欄位,新版漏做);
Twork_ord_vw_ormastSource.CustomerCodeBindingsetter 同步補交易條件碼 = item.交易條件碼- OrmastSave:補 VFP allowsave 的
公司代碼、倉儲代號(倉庫)必填檢查(取代原本重複兩次的受訂日期死碼)
- OrmastViewModel:新增單預設補
訂單別 = "1";新增明細列預設出貨別 = "1"(VFP addagain/addsonitem)
- Ormast.xaml / Ormast_US.xaml 匯率改 Buy(買入):原 XAML TsCurrency 用 Sell,與 VFP
U_BLRATE(...,'買')及 Source setter 的 Buy 不一致
- 新增
PkEdit(LogicBll/Ade/E.Order/PkEdit.cs):VFP pk.allowedit 的「轉退稅註記='Y' 不得修改/刪除」防呆,之前完全沒擋
- PkSave:補 VFP allowsave 的「品號空白列標記增刪修='D'」,避免空白明細列入庫
- Pk 明細 起始箱號/截止箱號 自動算箱數:
Twork_ord_vw_pkdeSource新增BeginningBoxNoBinding/EndingBoxNoBinding(VFP LostFocus:箱數=截止-起始+1),Pk.xaml 兩欄改綁新 helper
Breaking Changes
無(全部是修復原本就壞掉/缺漏的行為)。
Migration Notes
- ORMAST / PK 仍未在
TsERP/App.xaml註冊 DataTemplate,程式開啟後無畫面——需另行補
OrmastViewModel→Ormast(或Ormast_US)與PkViewModel→Pk兩條 DataTemplate(共用登錄檔,本次不動)。- ormast Source/Model 仍含大量 US 專屬欄位(SALES1/PICKEDQTY/ORDERCLOSE/訂單號碼/倉庫/付款方式碼…),
本地 darb DB
vw_ormast沒這些欄位(DB 實際是 訂單編號/倉儲代號/結案);schema 對齊需另走
/db-model-compare,本次未動 Model schema。 -
06-12 scx_ord-cuqt-salema-preord-fixes ▸
2026-06-12 scx_ord 對比修補:cuqt / salema / preord
摘要
VFP scx_ord 三支 class(cuqt 客戶單品報價單、salema 出貨通知單、preord 預示表)與新版深度對比後的修補。
最大宗問題:2025-10 Source 屬性英文→中文改名時,三支表單的 XAML binding 沒有同步改名,
造成大量欄位畫面永遠空白/輸入不會存(binding typo 不會編譯錯誤)。
新增
- Cuqt:主檔新增「報價類別」下拉欄位(A.群組 / B.廠商 / C.客戶 / D.特殊,還原 VFP combo;先前完全沒有此欄位)。
- Salema:明細新增「箱數」「包裝量」兩欄(VFP 原有、新版漏建)。
變更
- Cuqt.xaml / Salema.xaml / Preord.xaml:修正共 40+ 處 stale 英文 binding
(如
QuotationNo→報價單號、ShippingNoticeNo→單號、Year→年度…),並修正
模具估價單數→模具價單數、群組代號 seek 欄補 DataMemberBinding(預設產品群組與 Source 不符)。- CuqtSave:AllowSave 改成依報價類別驗證必填(A 驗群組代號、B 驗廠商代號、C/D 驗客戶代號;
原本一律驗客戶代號,群組/廠商報價會被誤擋)。存檔前自動回填「模具組數 = 明細模具編號非空白筆數」(VFP 行為)。
- CuqtBll.Import(取得資料鈕):前置檢查改驗「報價日期」(原誤驗報價單號、訊息卻講報價日期);
匯入前先清空既有明細,避免重複按鈕造成明細重複。
- CuqtViewModel:移除誤接的 IOther1(原本「快速審核」鈕會開「樣品單轉入」視窗,copy-paste 殘留);
快速審核改走集中式工作流程機制。新增時報價類別預設
C.客戶(VFP addagain)。- SalemaViewModel:修正主檔客戶代號連動明細永遠不觸發的 listener case 名稱錯誤
(監聽
客戶代號但 switch 比對CustomerCodeBinding);數量/金額總額改成換筆瀏覽時也會重算(原本只有編輯中才算,瀏覽顯示前一筆的合計)。
- PreordViewModel.ImportExecute:修正
int.TryParse條件相反——使用者輸入的年度/月份會被覆寫成當月(應為解析失敗才補預設)。
- PreordSave:
- 「不得有大於該月份之預示」檢查改成只在新增模式執行(原本修改舊單也會被擋)。
- 新增模式補 VFP 年度(>=2010)/月份(1-12)驗證與月份補零(
3→03,否則單號組錯)。- 明細「原預訂交期必填」檢查改成跳過品號空白列(空白列存檔時本來就會被標記刪除)。
- PreordControlViewModel.SplitExecute(批數拆解):修正拆解列共用同一物件 instance 的 bug
(原本所有拆解列是同一筆、序號尾碼累加成 001A、001AB…);
改為每列獨立 Copy、序號 = 原序號+A/B/C…、交期逐批推算、原始/扣減數量歸零(VFP 行為),並防護空白序號。
刪除
- CuqtViewModel 的
ExtendedFunction1()(開錯視窗的死碼)。
Breaking Changes
無資料格式變更。報價類別新單預設值由存檔時補
C改為新增時帶C.客戶(驗證以開頭字母判斷,兩種舊資料皆相容)。Migration Notes
無需 migration。XAML / ViewModel 變更需在 Visual Studio 內 build 驗證(dotnet CLI 會撞既有 MSB4803 工具鏈問題)。
-
06-12 scx_gen-purch-trxama-fixes ▸
2026-06-12 — scx_gen 五支總務單據 VFP 對比修補(gppurch / gpurch / gtrlima / gtrrama / gtrsama)
摘要
依 VFP 舊版
scx_gen(gppurch G請購單 C-040、gpurch G採購單 C-050、gtrlima G出入庫單 C-080、gtrrama G進貨單 C-070、gtrsama G出貨單 C-090)逐欄/逐驗證對比新版 TsERP。
主要問題為 2025-10 英→中屬性改名後 XAML 留下大量 stale English binding(binding 不報錯但欄位永遠空白、
輸入不會存檔),四支已上線表單全部修正;另補回數個 VFP 驗證/預設值/計算鏈缺漏。
gtrsama(G出貨單)確認為未完工(只有 View 殼,無 ViewModel/Save/接線,docs 狀態 planned),未修。
變更
Gppurch(G請購單)
- XAML stale binding 修正(
TsERP/C.GeneralAffair/Gppurch.xaml):
- 主檔:
備註→請購備註、序號前置碼→倉儲代號(原本倉儲欄綁錯名,畫面顯示/輸入皆無效)。- 明細:
LineNo_→序號、VendorName→廠商簡稱(2 處)、SKUBinding→品號Binding、RequestQuantityBinding→需求數量Binding、UnitPriceBinding→單價Binding、原幣未稅→金額、預定交期→預訂交期(typo)。- 金額計算鏈修正(
Model/Source/C.GeneralAffair/Twork_gen_vw_gppurdeSource.cs):
SetAmount原本金額 = 單價 × 數量,但新版 UI 已將 VFP 的 數量/需求數量 併為單一「需求數量」欄,數量永遠 0 → 金額恆 0。改為金額 = 單價 × 需求數量。- TotalAmount 即時加總修正(
ViewModel/C.GeneralAffair/GppurchViewModel.cs):
WeakEvent listener 清單漏掛
金額,ReceiveWeakEvent的金額 case 從未觸發。已補。- 存檔補值(
LogicBll/Ade/C.GeneralAffair/GppurchSave.cs):
比照 VFP allowsave SCAN,明細
需求部門空白時帶主檔請購部門。- 多語系(
Common/Lang/Xaml/Gppurch.json):序號前置碼條目改正為倉儲代號(原為 WarehouseCode 的誤譯鍵),新增請購備註。
Gpurch(G採購單)
- XAML 全面 stale binding 修正(
TsERP/C.GeneralAffair/Gpurch.xaml,整張表單原本全綁英文舊名):
主檔 採購單號/公司代碼/廠商代號Binding/廠商簡稱/採購日期/倉儲代號/幣別/匯率/收付條件號/說明/採購備註/結案/請購單號;
明細 序號/品號Binding/品名/廠商品號/數量Binding/請購單號/單價Binding/原幣未稅/本幣未稅/預訂交期/回覆日期/暫定週數/備註/是否結案/已交數量/需求部門。
- 死欄位處理:
Purchaser(無對應欄)改為送貨地點(VFP 主檔欄);VesselBookingNo改為傳真日期;TempReceivedQuantity(無對應欄)改為需求部門;ETAInWarehouse改為暫定週數。- 預設值型別錯誤修正(
ViewModel/C.GeneralAffair/GpurchViewModel.cs):
SetNewData誤判Twork_pur_vw_purchSource(PURCH 的型別),預訂交期 +14 天預設從未生效,改為Twork_gen_vw_gpurchSource。- 存檔驗證補齊(
LogicBll/Ade/C.GeneralAffair/GpurchSave.cs):
- 補 VFP
幣別未輸入、匯率<=0驗證。- 補 VFP 明細
需求部門必填驗證、送貨地點空白帶主檔。- 補呼叫
TaxCalculate()(原本方法定義了但沒人呼叫;與 PurchSave/GtrramaSave 平行)→主檔 原幣金額/本幣金額/稅額 存檔時未計算的問題修復(對應 VFP SUM加總 + REPLACE)。
- 預訂交期訊息誤用
ProgramClass.PURCH改為GPURCH。Gtrlima(G出入庫單)
- XAML stale binding 修正(
TsERP/C.GeneralAffair/Gtrlima.xaml):
主檔 倉單號/單號/序號前置碼/交易日期/公司代碼/交易部門/客廠部簡稱/運送方式碼/交易備註/轉入備註/轉出備註;
明細 序號/品號Binding/品名/單位/數量Binding/轉出倉儲/轉入倉儲/途程序號/工程代號/批號別/批號/單價Binding/原幣未稅/本幣未稅/備註。
- 批號別/批號欄改為可輸入:原 IsReadOnly=True,但 GinventorySave 在倉庫批號管制時要求必填,唯讀導致無法存檔。
- 新增欄位/區塊(對應 VFP 既有欄):主檔 幣別(TsCurrency,買入匯率自動帶)+ 匯率;明細 交易別碼、客廠品號、其他金額(其他金額Binding,連動原幣未稅計算)。
Gtrrama(G進貨單)
- XAML 全面 stale binding 修正(
TsERP/C.GeneralAffair/Gtrrama.xaml,主檔+明細+進貨費用三層全英文舊名):
- 主檔:倉單號/單號/隸屬倉庫/序號前置碼/交易日期/廠商代號Binding/廠商簡稱/幣別/匯率/付款方式碼/收付條件號/說明/
發票號碼/發票日期/發票金額/稅別/名稱/稅額/提單號碼/報單號碼/分攤費用/運送方式碼/交易備註/轉入備註/轉出備註/
總費用/總原幣未稅/總本幣未稅/總關稅分攤/總其他分攤。
- 明細:序號/品號Binding/品名/客廠品號/交易別碼/轉出倉儲/轉入倉儲/數量Binding/單位/單價Binding/其他金額Binding/
原幣未稅/關稅稅率/關稅分攤/其他分攤/本幣未稅/單位成本/成本/微調本幣/備註/採購單pkid/採購單號/轉入單pkid/訂單pkid/
其他資料1/其他資料2/途程序號/工程代號/批號別/批號/預訂交期/待轉入倉/待轉出倉/轉帳款數量/分攤品號/分攤群組/庫存管制。
- 進貨費用:序號/費用代碼/費用說明/科目代號/科目名稱/客廠部代號/客廠部簡稱/幣別/匯率/原幣未稅/本幣未稅Binding/是否為成本/費用備註/轉出備註。
- 合計面板死綁定
DueAmountWithCost/ContainerValue改為稅額/本幣應收付(對應 VFP 含稅本幣)。- 刪除無對應欄的死欄位:Transaction Method(C202 交易條件,gtrrama 無此欄)、Declaration Date、Ship Of Origin、
LCNum、Invoice、CompleteAllocation、Notes1、DefectReasonCode、TemporaryDocumentNoA、InventoryControlDescription、
費用表的 InvoiceNo/IsPosted。
Gtrsama(G出貨單 C-090)— 未修(整支未完工)
- 現況:僅有
TsERP/C.GeneralAffair/Gtrsama.xamlView 殼(且 binding 全為英文舊名);
無 GtrsamaViewModel、無 Save/Edit、無任何程式開啟此 View;
docs/C-GeneralAffair/gtrsama.md狀態planned。- Source/Model(
Twork_gen_vw_gtrsamaSource/gtrsadeSource)已存在,後續補 ViewModel + Save(可比照 GtrlimaViewModel + GinventorySave 家族)即可完工。
未修清單(🟡,記錄備查)
- 共通:工作流程/快速審核/流程樣板/審核欄位 → 新版集中式 workflow(等價,不比)。
- Gppurch:採購別 無 UI 且未驗證(預設 1);請購說明/傳真日期/詢比議記錄/聯絡單ID 欄位未做;
需求轉單(GPRTOPP)未移植;廠商代號 LostFocus 自動帶 送貨地點/運送方式碼/幣別 未做;
預訂交期 不得小於今日的驗證未做(新版改為存檔時補今日);送貨地點 prgpar 4003 預設(銓育專屬)未做;
明細多數參考欄(用途/廠牌/分攤*/匯率/預估單價/預估金額/是否結案/採購單號…)UI 簡化未顯示;
VM
DataFromSource屬性為 dead code;savevalid 聯絡單 viewxml 連動(COMMPR)未移植。- Gpptopu(請購轉採購):仍繼承 TransferBll(已知刻意不大改);其
TWORK_TUR_GPPTOPUSP 僅存在 darbzdcsa1(英文欄名版),
中文 schema DB(darbnogicsa1)未部署 → 此轉單在中文庫 runtime 會失敗,需另行部署中文版 SP。
- Gpurch:結案鈕(else5 特殊修改:單價只可調低/備註/是否結案)未移植(含「特殊修改單價不得大於原單價」防呆);
修改交期(PURCH_E 批次改交期)、進貨查詢(GPURCH_S/else6)未移植;
反推稅率/反推未稅價鈕 未移植;交易條件/付款方式/運送方式 主檔欄無 UI;
廠商帶出僅 收付條件/幣別(VFP 另帶 送貨地點/交易條件/付款方式/運送方式);
ExtendedFunction1仍走已廢棄WindowHelper().OpenWindow。- Gtrlima:統計鈕(else4 GSHIPPING)未移植;GMFTOMG 鈕在 VFP 即無 Caption(沒做)不比;
運費轉入鈕(禾久/台賓 Excel)公司專屬不做;品號離焦即時庫存查詢改由 IStockQuery 面板(等價)。
- Gtrrama:送修轉入(else4 GMFTOMG)未移植;明細 請購人員 空白帶 usercode 未做;
費用列 原幣未稅<=0 自動標刪(VFP)新版未做(僅靠分攤平衡驗證擋)。
- 四支表單 XAML Label 仍多為英文字串(未包 DisplayMeta),僅 Gppurch 走 DisplayMeta;後續可跑 xaml-label-to-displaymeta。
Breaking Changes
無資料結構變更。Gpurch/Gtrrama/Gtrlima 删除的皆為綁定失效的死欄位;
Gppurch
金額改按 需求數量 計算屬 bug fix(原值恆 0)。Migration Notes
- 本批未動共用登錄檔、未動 DB schema。
- XAML/ViewModel 變更需在 Visual Studio 內 build 驗證(dotnet CLI 撞 MSB4803 為既有工具鏈問題)。
- runtime 驗收重點:四支表單開窗欄位是否正常顯示/可輸入、Gppurch 金額與 Total 即時計算、
Gpurch 存檔後主檔原幣/本幣金額、Gtrlima 批號輸入、Gtrrama 費用分攤存檔驗證。
- XAML stale binding 修正(
-
06-12 scx_gen-ginvent-gsplace-gsppdt-gtrinout-fixes ▸
2026-06-12 scx_gen 對比修補:ginvent / gsplace / gsppdt / gtrinout
摘要
VFP
scx_gen四支 class(G庫存主檔 ginvent、G倉庫表 gsplace、G廠商報價 gsppdt、G入出庫申請單 gtrinout)與新版 TsERP
C.GeneralAffair模組深度對比後的修補。主軸是 2025-10 英→中改名後殘留的 stale English binding(欄位永遠空白、輸入不會存檔)、
缺驗證、缺預設值與一支呼叫不存在 SP 的查詢。
新增
Ginvent(G庫存主檔)
- 主畫面補上 VFP 有但新版漏掉的欄位:規格、模具型別、模具尺寸、科目代號(AcclSearch)、中文描述、備註。
- 新增「產生品名」按鈕(VFP 產生品名鈕):品名 = 族群名稱(去掉第一段代號)+ 各分類內容串接,截斷 120 字。
Twork_gen_vw_ginventSource.SetDisabledDate():停用='Y' 補停用日期、取消停用清空(對應 VFP else4click 停用鈕,新版改存檔時處理,與 D.Bom Invent 一致)。
- 新增時預設 新增日期=當天(VFP addagain)。
Gsplace(G倉庫表)
- 主畫面補上 送貨地點 欄位(gstkbas 有欄、VFP 有顯示、新版漏掉)。
Gsppdt(G廠商報價)
- 存檔驗證補齊 VFP allowsave:廠商代號 / 報價日期 / 收付條件號 必填。
- 存檔時 幣別空白補本位幣、匯率<=0 補 1、明細「品號+工程代號皆空」列標記刪除。
- 輸入廠商代號自動帶 幣別(VFP sqlnm_sp1.LostFocus;原本只帶收付條件號)。
- 明細表補欄位:內箱包裝數、關稅稅率、特別要求。
- 主畫面補 簽決單號 欄位。
Gtrinout(G入出庫申請單)
- 存檔驗證補:申請日期、申請部門 必填(VFP allowsave)。
- 存檔時:明細 需求部門=申請部門、主檔 幣別=本位幣+匯率=1(VFP「畫面上無幣別」)、
主檔 原幣金額/本幣金額 = 明細原幣未稅合計(VFP sum加總)。
- 主畫面補 廠商代號 欄位(MF 廠商報價查價用)、轉入備註(唯讀)。
- 明細表補欄位:規格、交易別碼、單位(下拉)、其他金額、參考單價、批號別、批號、用途、預訂交期、是否結案。
變更(stale binding / 錯誤修正)
Ginvent.xaml
CreatedDate→新增日期、IsDisabled→停用、英文品名→英文描述、GroupDescription→群組說明
(以上原 binding 在 Source 都不存在,欄位永遠空白且不存檔)。
Gsplace
- Quantity Query(現有數)整段修復:原呼叫不存在的
DARB_QRY_GSPLACE(DB 無此 SP、proc_param 未登錄),
改呼叫 VFP 原本的
DARB_TUR_GSPLACE(查詢別=2,已登錄)。GsplaceQuantityPoco屬性由英文改為中文(倉儲代號/品號/途程序號/工程代號/批號別/批號/現有數量/現有金額/設立說明),
對齊 SP 回傳欄名(DataTable→Poco 按名稱對應,原本全部對不上)。
- 現有數 grid 欄位 binding/標題同步改中文。
Gsppdt.xaml
- 主檔:
VendorCodeBinding→廠商代號Binding、廠商名稱→廠商簡稱、PaymentTermDescription→說明、
ActivityStartDateBinding/ActivityEndDateBinding→活動起始日Binding/活動截止日Binding。- 明細:
LineNo_→序號、SKUBinding→品號Binding、MaterialChargeBinding/ProcessingChargeBinding/UnitPriceBinding
→
材料單價Binding/代工單價Binding/單價Binding、最低採購量→最低採購量Binding。Gtrinout.xaml(全表單 rebind — 原本整張表單 binding 全是英文舊名,欄位全空)
- 主檔:
ApplicationNo→申請單號、ApplyDate→申請日期、DocumentPrefix→序號前置碼、ApplyType→申請原因、
Applicant/ApplicantName→申請人員/姓名、DefaultWarehouse→隸屬倉庫、CustVendCodeBinding/CustVendName→申請部門/部門簡稱(改用 DeptSearch)、TurnOutNote→轉出備註。- 明細:
SKUBinding→品號Binding、SKUDescription→品名、Notes→備註、QuantityBinding→申請量Binding、
UnitPriceBinding→單價Binding、CurrencyAmountWithoutTaxBinding→原幣未稅Binding、DestinationBin→倉儲代號(FilterCondition 改綁MasterItem.隸屬倉庫)、ProcessingCode→工程代號、GivenQuantity→核發量。- 明細 grid 補
DataManager="{Binding DetailData}"。
GtrinoutSave
- 移除「廠商代號必填」(VFP 非必填,僅 MF 查價用;原本畫面又沒有廠商欄位,等於永遠存不了檔)。
刪除
- Ginvent.xaml:
顏色下拉(Source/DB 皆無此欄,從 D.Bom Invent 複製殘留的死 UI)。
- Gsplace.xaml:
管制負數、LotCodeControl兩個下拉(gstkbas 無此欄,binding 永遠落空,僅 stkbas 產銷存版才有 管制負數)。
- Gsppdt.xaml:
生效日期欄(Source 無此屬性)、明細數量欄(=最低採購量 的重複唯讀別名)、代工廠商欄(Source/DB 無此欄)。
- Gtrinout.xaml:
Free Samplecheckbox 與明細FreeSample/Pending/Restocked/Billed欄(Source 皆無對應屬性,死 UI)。
已知未修(🟡,刻意留待後續)
- gsplace 開帳導入(else1):VFP 跑
DARB_LOG_GINVSTK_RECOUNT(含放行碼),新版完全未移植;
現在 IOther1 開的 Gstkbas_1 對應的是 VFP else2 批次關帳。
- gtrinout 轉交易單(else3 → GTRINOUTE):新版 GtrapplyToGtrlima 流程呼叫的
TWORK_TUR_GTRAPPLYTOGTRLIMA/TWORK_QRY_GTRAPPLYPICK在本機 DB 不存在也未登錄 proc_param,且其 Poco 屬性為英文、
DARB_TUR_GTRINOUTE回傳中文欄名——整段轉單流程在本機環境不可用,需另案處理。- gtrinout 轉入倉儲/轉出倉儲 W/T 推導與倉儲代號驗證(VFP allowsave 依 LCL交易別 轉入/轉出部門設定):未移植。
- gtrinout 反推稅率/反推未稅價鈕:未移植。
- ginvent 自動編碼(LCL系統參數表 項目=4 時品號自動編碼、改驗群組代號):未移植。
- ginvent 庫存管制強制 'Y'(VFP「銓育都要管制庫存」存檔時強制):新版改為新增預設 Y + 使用者可改,視為設計決策保留。
- ginvent 分群碼 + 帶分群資料鈕:新版全系統皆無分群碼 UI,未補。
- TsGBinSearchColumn(共用控件) SeekCondition="Bin"/SeekColumn="Description" 疑為英文舊名
(vwseek_gsplace 已是中文欄),屬共用控件不在本次範圍,待確認。
- gstkbas.可用(新版欄位,非 VFP)以 YesNoComboBox(Y/N) 綁 byte 0/1,型別不符恐顯示空白,沿用現狀待確認。
Breaking Changes
無資料結構變動;僅 UI binding、驗證與一支 SP 呼叫名修正。
Migration Notes
- 無需 DB migration。
DARB_TUR_GSPLACE既有且已登錄 proc_param。
- XAML/ViewModel 改動需在 Visual Studio 內建置驗證(dotnet CLI 會撞 MSB4803 ResolveComReference,屬工具鏈問題)。
- 全部修補均未經 runtime 驗證,四支表單建議各做一次 新增→存檔→修改→刪除 煙霧測試。
-
06-12 rtaxma-port ▸
2026-06-12 報關沖退稅/出口報單(RTAXMA,選單 E-120)VFP 移植
摘要
按 VFP 舊版
RTAXMA在 TsERP V2 新增「報關沖退稅(出口報單)」Master+Detail 單據,走 canonical TsView + ItemsBindingManager 範本(比照 Orssma)。
rtaxma/rtaxde 無 view,Source 直接映射表;子表鍵欄為「項次」。
此單據無審核/工作流程(表無審核三欄與聯絡單id/工作流程欄位)。
新增
TsERP\E.Order\Rtaxma.xaml(.cs):主檔欄位 + 明細 TsRadGridView(欄序依 VFP grid1 ColumnOrder)+ 底部合計列
ViewModel\E.Order\RtaxmaViewModel.cs
LogicBll\Ade\E.Order\RtaxmaSave.cs(刪除無 VFP 客製檢查,走預設 DeleteBll)
Model\Source\E.Order\RtaxmaSource.cs / RtaxdeSource.cs
Common\Model\E.Order\RtaxmaModel.cs / RtaxdeModel.cs
- 多語系
Common\Lang\Xaml\Rtaxma.json(同步併入TsERP\Lang\Xaml1\Xaml.json)
- 登錄:TableMap(rtaxma/rtaxde 直接映射表名)、ClassAliasMap 4 筆、LocalDbContext DbSet、App.xaml DataTemplate
行為(VFP 還原)
- 編號:前置碼 RT + 彙總日期年月 + 5 碼流水(
_sheetno既有設定,server 端產號);新增時彙總日期預設今天
- 箱號計算(txt起始箱號/txt截止箱號.LostFocus):箱數 = 截止箱號 − 起始箱號 + 1
- 計算材積鈕(cmdbtn11.Click,逐列):單箱材積 = ROUND(箱長×箱寬×箱高/1,000,000×35.3147, 2),限編輯模式
- sum加總(排除品號空白與刪除列):總箱數=Σ箱數、總淨重=Σ ROUND(單箱淨重×箱數,2)、
總毛重=Σ ROUND(單箱毛重×箱數,2)、總材積=Σ ROUND(單箱材積×箱數,2)、
總金額=Σ ROUND(單箱數量×單價×IIF(截止箱號=0,1,箱數),2)、總數量=按單位分組 Σ數量 串列
- 存檔驗證(allowsave):彙總日期/客戶代號必填;品號空白明細列視為刪除(CINO 檢查在 VFP 已註解,維持不檢查)
- 列上 數量/淨重/毛重 依 VFP 註解公式自動帶:虛擬箱數=IIF(截止箱號=0,1,箱數)、
數量=ROUND(單箱數量×虛擬箱數,0)、淨重=ROUND(單箱淨重×箱數,2)、毛重=ROUND(單箱毛重×箱數,2)
(VFP 上線版此三欄由轉入帶值後手動維護,新版改為自動計算)
變更(與 VFP 不同處,刻意)
- 明細多一欄唯讀「數量」(VFP grid 未顯示該欄,但合計用得到,可視化計算結果)
- 明細 客戶代號 欄為一般文字欄(VFP sql_cuno 標準驗證,未掛 seek 欄位)
待辦
- 轉入機制未移植:VFP addclick 進新增模式後
DO FORM rtaxma_m,由 modal 挑 PK/CI 出貨單據彙總轉入
明細並回寫主檔「轉入單號」(220 字寬、可多張)。rtaxma_m 原始碼不在抽取檔內,先上手動輸入版;
TODO 註記在
RtaxmaViewModelclass 註解- 報表 RTAXMA_P 未移植(本次刻意不做)
- runtime 未驗收
-
06-12 pi-port ▸
2026-06-12 — PI Proforma Invoice(E-130)按 VFP 還原
摘要
依 VFP 舊版
PI(scx_ord.vcx,1237 行)完美還原 Proforma Invoice 主明細表單到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 最新範本(結構比照 CI 商業發票)。主檔
pi_m、明細pi_d直接綁資料表(無 view)。> ⚠️ pi_m / pi_d 資料表尚未建立(所有本機 DB 皆無),DDL 在
>
.claude/tmp/pi-tables.sql待使用者放行後執行。程式碼(Model/Source/VM/XAML/Save/登錄點)> 已全部照 DDL 完成;_sheetno 的 PI 列既有(pi_m/pino/pi_d),不需 INSERT/UPDATE。
新增
Common/Model/E.Order/Pi_mModel.cs、Pi_dModel.cs
Model/Source/E.Order/Pi_mSource.cs、Pi_dSource.cs
LogicBll/Ade/E.Order/PiSave.cs
ViewModel/E.Order/PiViewModel.cs
TsERP/E.Order/Pi.xaml(.cs)(TsTabControl:明細資料編修 / 頁首資料編修,還原 VFP PF 兩頁)
Common/Lang/Xaml/Pi.json(+ Common.csproj Content)
.claude/tmp/pi-tables.sql(CREATE TABLE pi_m/pi_d + PK/索引,未執行)
PI DDL 摘要
pi_m:pino nvarchar(20)、客戶代號(10)、pi日期(10)、公司代碼 int、幣別(8)、匯率 numeric(14,4)、
報價單號(12)、聯絡人(30)、客戶訂單號(20)、商品名稱(100)、預訂交期(10)、產品描述別(4)、
交易條件碼 int、交易條件(30)、頁首備註/頁尾備註/正麥 nvarchar(max) + 共用欄(照 rtaxma:
pkid 非 IDENTITY、linkid NULL DEFAULT 0);PK=pkid、
IX_pi_mUNIQUE(pino)(比照 ci_m)pi_d:pino(20)、序號(6)、客戶品號(30)、品號(30)、產品描述 nvarchar(max)、數量 numeric(15,4)、
單位(4)、單價 numeric(16,6)、報價單位(4)、備註(30) + 共用欄(照 rtaxde);
PK=pkid、
IX_pi_d(linkid)(比照 ci_d)- 同名欄位型別照 ci_m/ci_d;商品名稱 VFP mask X40 但取 ci_m 的 nvarchar(100)(PI→CI 下游複製不截斷);
欄名「正麥」照 VFP(ci_m 為「正嘜」,是不同欄)
VFP 行為對照
VFP 新版 allowsave: PI日期未輸入/客戶代號未輸入PiSave.AllowSaveGetInputMessageallowsave:明細 數量=0→ 增刪修 'D'Pi_dSource.NeedDeleteFunction(數量==0)+MarkZeroQuantityDetailDeleted雙保險keyfldvalue=PINO(無 is_noduplicate) pino 必填 + IsDocNoDuplicate(DARB_GETDATA4 查 pi_m)— 比照 ESTSAL 範本補上sum加總: SUM 數量, ROUND(數量*單價, TWD/JPY?0:2) FOR 增刪修<>'D' AND NOT EMPTY(品號)PiViewModel.RecalculateTotals:TotalQuantity/TotalAmount,小數位改用幣別小數位設定OpenDbfTable.GetDecimalPlaces(TWD/JPY=0、一般=2,語意等價);ListenerHelper 監聽 數量Binding/單價Binding/幣別 即時重算grid1.Refresh → SUM加總 IMoveRecord.AfterMoverRecord導覽後重算 + 帶客戶簡稱幣別.LostFocus: 匯率 = U_BLRATE(幣別,'1','賣',PI日期)TsCurrency(Currency=幣別、Date=pi日期、FXRate=匯率、SearchType="Sell")changeopmode:報價單號 僅 OPMODE=1(新增)ENABLED XAML AddOnlyTextBoxStyle(DataTrigger on Status=Add/Copy)明細 Replace PINO With PI主檔_V.PINO+ son1fld=序號PiSave.HandleDataBeforeEndEdit回填 pino、空白序號補流水(D3);新增列OnAddListener即時編號grid col品號 sql_mno1dovalid=1品號Binding→SetProduct():驗證(查無→「查無品號 !!!」)+ 依主檔 產品描述別 帶 產品描述/單位(比照 CI 同款邏輯)主檔 產品描述別 sqlcombo(中文,英文) ItemDescriptionTypeSource(EnumManager),切換時重帶全部明細 產品描述(比照 CI)公司代碼 sqlcombotxt c_type=101 / 交易條件 c_type=202 TsComboBoxWithDescriptionBySqlTableAlias C101 / C202數量總額/金額總額 唯讀(txt_color=2) TotalQuantity/TotalAmount 唯讀 TsNumericTextBox (無對應)交易條件 文字欄 比照 CiSave:存檔時 交易條件 空白由 交易條件碼 帶出 變更(既有檔案)
TsERP/Lang/TableMap.json:修正預留映射 —"pi_m"/"pi_d": "twork_ord_vw_pi_*"→"pi_m"/"pi_d"(無 view,照表名)
TsERP/Lang/ClassAliasMap.json:Twork_ord_vw_pi_*預留別名改Pi_m*/Pi_d*
Model/LocalDbContext.cs:DbSet<Pi_mSource> Pi_m、DbSet<Pi_dSource> Pi_d
TsERP/App.xaml:PiViewModel DataTemplate
TsERP/Lang/Xaml1/Xaml.json:Pi區塊
Common/ProgramClass.cs:PI既有,未改
刪除
無。
Breaking Changes
無(新功能;DB 端需另行放行建表)。
Migration Notes / 未還原項目
- DB Migration(待放行):執行
.claude/tmp/pi-tables.sql建pi_m/pi_d後本表單才可運作;
未建表前開窗導覽會因 server 查無資料表而失敗。
- 報表 TODO:VFP 報表程式
PI_P(SCX_ORDP) 尚未移植。
- pi_m 無任何審核欄位 → 不掛集中式審核。
- VFP 已註解(dead code)未還原:報價單號.Valid 複製客報價單、搜尋客號鈕(依客戶歷史訂單帶客戶品號)、
搜尋單價鈕(抓最近訂單單價)、客戶訂單號 重複檢查、sqlnm_cu LostFocus 帶幣別/聯絡人/交易條件/停用檢查、
txtlabel3.Click 頁首備註自動產生。
- VFP page2 公司簡稱 為 attachment_btn(附件鈕):附件行為未還原(公司代碼於頂部以 C101 combo 呈現)。
- VFP changeopmode 新增時自動切到頁首頁籤/焦點控制:未還原(焦點機制不同)。
- runtime 未驗。
-
06-12 pdtsal-port ▸
2026-06-12 — PDTSAL 產銷表(E-940)按 VFP 還原
摘要
依 VFP 舊版
PDTSAL(scx_ord.vcx,773 行)完美還原產銷表 主明細表單到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 最新範本(比照 Estsal/Claim)。主檔
pdtsal_m(DB 無 vw_pdtsal_m,直接綁資料表)、明細走vw_pdtsalview(pdtsal LEFT JOIN vwseek_invent 帶 品名);明細無單號欄位,與主檔以 linkid 關聯(框架標準行為)。
新增
Common/Model/E.Order/Pdtsal_mModel.cs、Vw_pdtsalModel.cs
Model/Source/E.Order/Pdtsal_mSource.cs、Vw_pdtsalSource.cs
LogicBll/Ade/E.Order/PdtsalSave.cs
ViewModel/E.Order/PdtsalViewModel.cs
TsERP/E.Order/Pdtsal.xaml(.cs)
Common/Lang/Xaml/Pdtsal.json(+ Common.csproj Content)
VFP 行為對照
VFP 新版 allowsave:年度/月份/版次 必填( 請輸入年度/月份/版次)PdtsalSave.AllowSave逐項 GetInputMessageallowsave: EMPTY(品號)→ 增刪修 'D'Vw_pdtsalSource.NeedDeleteFunction+MarkEmptyDetailDeleted雙保險keyfldvalue=單號(無 is_noduplicate) 單號必填 + IsDocNoDuplicate(DARB_GETDATA4 查 pdtsal_m)— VFP 由 sqledit 鍵值機制隱含,比照 ESTSAL 範本補上changeopmode:年度/月份/版次 僅 OPMODE=1(新增)ENABLED XAML AddOnlyTextBoxStyle(DataTrigger onAdeViewModel.Status= Add/Copy)grid col品號 sql_mno1dovalid=1品號Binding→SetSkuData(),查無→「查無品號 !!!」grid Column17 U_SEEKNM('SK_INVENT',品號,'品名')+moverec_sk_cursorSK_INVENT 快取明細直接走 vw_pdtsal.品名(navigate 載入即有),編輯時 SetSkuData 重抓grid col客戶代號 sql_cuno1TsCustomerSeekGridViewColumn數量系欄 mask 99,999,999.99(上月庫存~預售計劃4) PlaceEnum TwoPlace(DB money 19,4) 單價 mask 9,999,999,999.999999 PlaceEnum SixPlace(DB numeric 16,6) Init: '單價'$THIS.IS_備註才顯示單價欄(站台設定)新版固定顯示單價欄(無對應站台參數機制,從寬處理) 變更(既有檔案)
TsERP/Lang/TableMap.json:修正預留映射 —
"pdtsal_m": "twork_ord_vw_pdtsal_m"→"pdtsal_m"(DB 無該 view)、"pdtsal": "twork_ord_vw_pdtsal"→"vw_pdtsal"(DB 實際 view 名)TsERP/Lang/ClassAliasMap.json:Twork_ord_vw_pdtsal_m*預留別名改Pdtsal_m*(照表名命名)、
Twork_ord_vw_pdtsal*改Vw_pdtsal*(照 DB view 名,比照 Claim)Model/LocalDbContext.cs:DbSet<Pdtsal_mSource> Pdtsal_m、DbSet<Vw_pdtsalSource> Pdtsal
TsERP/App.xaml:PdtsalViewModel DataTemplate
TsERP/Lang/Xaml1/Xaml.json:Pdtsal區塊
Common/ProgramClass.cs:PDTSAL既有,未改
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
PDTSAL_P(SCX_ORDP) 尚未移植。
- pdtsal_m 無任何審核欄位 → 不掛集中式審核。
- VFP Init 註解掉的 DYNAMICBACKCOLOR(刪除列紅字、單價<=0 綠底)為 dead code,未還原。
- VFP 單價欄「
'單價'$IS_備註才顯示」的站台開關未還原,新版固定顯示。
- runtime 未驗(_sheetno PDTSAL 列既有、pdtsal_m/pdtsal/vw_pdtsal DB 物件既有,無 DB 變更需求)。
-
06-12 orssma-port ▸
2026-06-12 調撥指示單(ORSSMA,選單 E-080)VFP 移植
摘要
按 VFP 舊版
ORSSMA(scx_ord.vcx,調撥通知)在 TsERP V2 新增「調撥指示單」Master+Detail 單據,走 canonical TsView + ItemsBindingManager 範本(比照 Ormast/Trsama)。
新增
TsERP\E.Order\Orssma.xaml(.cs):主檔欄位 + 明細 TsRadGridView(欄序依 VFP grid1 ColumnOrder)
ViewModel\E.Order\OrssmaViewModel.cs
LogicBll\Ade\E.Order\OrssmaSave.cs / OrssmaDelete.cs
Model\Source\E.Order\Vw_orssmaSource.cs / Vw_orssdeSource.cs
Common\Model\E.Order\Vw_orssmaModel.cs / Vw_orssdeModel.cs
- 多語系
Common\Lang\Xaml\Orssma.json(同步併入TsERP\Lang\Xaml1\Xaml.json)
行為(VFP 還原)
- 編號:前置碼 KU + 受訂日期年月 + 5 碼流水(
_sheetno既有設定,server 端產號)
- 新增預設:訂單別=2、受訂日期=今天、本位幣+匯率1、明細出貨別=1(VFP addagain)
- 客戶代號帶預設:交易方式/業務員/收付條件/幣別/交易條件/運送方式/交易類別/港口/稅別
(沿用 DB 既有
DARB_QRY_ORSSMA查詢別 3);匯率由 TsCurrency 依受訂日期自動帶(買進)- 品號驗證:查無品號/品號停用/匯率未輸入擋下;單價 = ROUND(平均成本/匯率,5)(無平均用標準成本);
客戶品號/單位/製程別抓該客戶最近一張調撥通知(
DARB_QRY_ORSSMA查詢別 4)- 金額:數量×單價=原幣未稅,含稅/本幣按稅別稅率與匯率(TaxCalculator);
orssde 無微調欄位,尾差直接併回明細列金額(對應 VFP 把差額塞最大列)
- 存檔驗證:受訂日期/客戶代號必填;交易類別限 D/I/L;出貨別限 1/2;訂單分類限 A–E;
品號空白或數量 0 的列視為刪除
- 客戶訂單號失焦補空白明細;複製明細鈕還原 VFP 複製鈕
變更(與 VFP 不同處,刻意)
- 工作流程/快速審核:改走集中式(工作流程頁籤 + 審核鈕),不再各表單自寫
- 庫存量/在製品查詢面板(VFP cmdbtn11 + grid2):改用集中式「庫存」查詢頁籤
待辦
- 報表 ORSSMA_P 未移植(本次刻意不做)
_sheetno.流程類別為空 → 工作流程頁籤停用;要啟用需 DB 設定流程類別
- runtime 未驗收
-
06-12 invent1-port ▸
2026-06-12 產品序號表(INVENT1)移植
摘要
依 VFP 舊版
scx_ord.vcx / invent1完整移植「產品序號表」(選單 E-160,保固卡主檔)到 TsERP V2。單檔主檔(主表
invent1、主表 viewvw_invent1,無明細),編號依_sheetno(單據別 INVENT1、編碼方式 1、srno 長度 3、保固卡號 = 序號前置碼(品號) + 流水號)。
新增
Common\Model\E.Order\Vw_invent1Model.cs
Model\Source\E.Order\Vw_invent1Source.cs— view 顯示欄位 客戶簡稱/客戶簡稱1/品名 僅存 Source 不上傳
ViewModel\E.Order\Invent1ViewModel.cs—ERPProgramViewModel+ IMoveRecord + IOther1
LogicBll\Ade\E.Order\Invent1Save.cs— 反射命名LogicBll.Ade.Invent1Save
TsERP\E.Order\Invent1.xaml(.cs)— TsView 單檔主檔
Common\Lang\Xaml\Invent1.json+TsERP\Lang\Xaml1\Xaml.json併入 Invent1 區段
TsControl\Themes\TsTextBoxGeneric.xaml:新增ProductSerialNoSearch樣式(invent1.保固卡號,供 CLAIM 等表單 F2 查詢)
登錄點
TsERP\Lang\TableMap.json:"invent1": "vw_invent1"
Model\LocalDbContext.cs:DbSet<Vw_invent1Source> Invent1
Common\ProgramClass.cs:INVENT1(之前盤點缺 entry,本次補上)
TsERP\App.xaml:Invent1ViewModel → Invent1DataTemplate
TsERP\Lang\ClassAliasMap.json:Vw_invent1Model/Source → Vw_invent1
Common\Common.csproj:Lang\Xaml\Invent1.jsonContent
VFP 行為對照
VFP 新版 allowsave:客戶代號/品號/購買日期空白擋存Invent1Save.AllowSaveallowsave:REPLACE 序號前置碼 WITH 品號Invent1Save.HandleDataBeforeEndEdit保固期限別.Valid:限 0 或 1Invent1Save.AllowSave(請輸入 0 或 1)銷貨單號.Valid:倉單號=倉庫+銷貨單號 查 trsama 帶公司代碼/客戶代號/集團代號/購買日期(交易日期),保固期限=0→12,倉單號相同不回填銷貨單號Binding → SetShippingData()(DARB_GETDATA4 trsama)倉庫/銷貨單號.Refresh(OPMODE=0):LEFT(倉單號,6) / SUBSTR(倉單號,7)SyncWarehouseDisplay()(VMAfterMoverRecord呼叫)未保養天數.Refresh(U_NOSERVICEDAYS):停用→'停用';否則今天−前次保養日(repair 最大結案日期,無則購買日期);無卡號→'無'SetNoServiceDays()(DARB_GETDATA4 repair,VMAfterMoverRecord呼叫)客戶代號/集團代號(sqlnm_cu)帶簡稱客戶代號Binding/集團代號Binding → DescriptionHelper.GetCustomerName(view 欄 客戶簡稱/客戶簡稱1)品號(sql_mno dovalid=1)帶品名、查無提示品號Binding → SetSkuData()(查無品號 !!!)else1click取得附件:OPMODE=0 → 特殊修改 → GETFILE(附件上限 _prgpar 8 MB)→ U_SAVEFILE2(保固_保固卡號)→ 回填附件 → 立即存檔,失敗取消Invent1ViewModel.ExtendedFunction1(IOther1;ERPIO.SaveToDigitalLibrary,子目錄=年月、檔名前綴=年月保固卡號,與 LEFT(附件,6)=年月 開檔規則一致)顯示附件鈕.Click:U_OpenFile(數位目錄\LEFT(附件,6)\附件)ShowAttachmentCommand(Process.Start UseShellExecute)txtlabel21(保固內容).Click:編輯中_GETMEMO 'M211'帶入保固內容WarrantyMemoCommand(DARB_GETDATA4 smemsd 類別編號='M211' 取敘述,限編輯模式)公司代碼 sqlcombotxt c_type=101 TsComboBoxWithDescriptionBySql TableAlias="C101"機器序號/DATECODE/廠牌/停用 ReadOnly 顯示 唯讀 TsTextBox(資料由出貨/批次程序寫入,本表單不編輯) 無審核三欄 不掛集中式審核 SP 依賴:僅
DARB_GETDATA4(已登錄),無需新 SP。未還原項目
- 報表
INVENT1_P(SCX_ORDP)/printclick(DO FORM INVENT_Q查詢視窗)— TODO(VM 註解)。
注意:
TworkReportPluginOfficial\Invent1.cs現況是 BOR 通用報表來源(ReportBll.GetBorReport),與本維護畫面/invent1 資料表無關,未動。
moverec_sk_cursor(SK_CUDATA/SK_INVENT 快取游標)— 新版 view JOIN 取代,不需要
- else1 鈕的
其他1說明/可否其他1為 DBprgsct1設定(取得附件),需 DB 端設定權限,程式端已實作 IOther1
Runtime 未驗
全部畫面/存檔/附件流程僅 build 驗證,未實機開窗測試。
-
06-12 gtrsama-port ▸
2026-06-12 — GTRSAMA G出貨單(C-090)按 VFP 還原
摘要
依 VFP 舊版
GTRSAMA(scx_gen.vcx,1948 行,sqledittr 子類)還原 G出貨單(主檔 trgama 單據別 '3'、明細 trgade)到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 範本(比照對稱單據 Gtrrama G進貨單)。動庫存單據(_sheetno 查庫存=1)→ 存檔走
GinventorySavebase(倉儲/批號/關帳/權限檢核),修改走
GinventoryEditbase(IA 鎖單/關帳/轉出備註已轉應收)。雙編碼(倉單號+單號,前置碼自 Tritem1、編碼方式 3、srno 5)走 AdeBll.AddBll + _sheetno(GTRSAMA 列既有,pkid 52)。
新增
ViewModel/C.GeneralAffair/GtrsamaViewModel.cs
LogicBll/Ade/C.GeneralAffair/GtrsamaSave.cs、GtrsamaEdit.cs
Common/Lang/Xaml/Gtrsama.json(+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 d_單據別 = 3.總務出貨;新增預設 交易日期=今日 GtrsamaViewModel.AfterAddNew(單據別='3'、公司代碼=1、幣別=本位幣+匯率1)allowsave:匯率<=0 → U_BLRATE(幣別,'1','買',交易日期)GtrsamaSave.AllowSave→Util2017.U_Blrate(Accounting/Buy)txt數量/txt單價/txt其他金額.Valid:原幣未稅=ROUND(數量×單價,幣別小數位)+其他金額 即時: Twork_gen_vw_gtrsadeSource.數量Binding/單價Binding/其他金額Binding(既有)→ TaxCalculator.SetDetail;存檔再算一次GtrsamaSave.AllowSavesum加總:金額總額=Σ原幣未稅(品號非空白)、本國幣總額=ROUND(總×匯率,小數位) 主檔 總原幣未稅/總本幣未稅(TaxCalculator.SetDetail 即時維護;本次補 OnPropertyChanged 讓畫面合計即時更新);存檔GtrsamaSave.TaxCalculatesqlnm_cu1.代號.Valid(ControlSource=交易部門):SEEK SK_CUDATA 帶 幣別/稅別/運送方式碼/業務員編號 Twork_gen_vw_gtrsamaSource.客戶代號Binding(DescriptionHelper.GetCustomer,有找到才帶;幣別變更由 TsCurrency 自動帶匯率)幣別.LostFocus:匯率=U_BLRATE('1','買') TsCurrency 控件(SearchType 預設 Buy,Date=交易日期) sql_gmno1.LostFocus:品號≠MISC 帶品名/單位;MISC 僅空白帶入;改品號查庫存(DARB_QUERY_STK1 'trgade',LCL_trga_stk_s) 品號Binding→ SetISKU(既有)+IStockQuery(StockQueryKey=明細選取列,新增時 SwitchToStockTab)空白明細(品號空白)刪除 GinventorySave.HandleDataBeforeEndEdit標增刪修='D'(base 既有)交易別碼空白帶預設交易別、倉同儲帶轉入/轉出倉儲、批號管制檢核、關帳日、倉庫權限 GinventorySavebase(同 Gtrrama/Gtrlima)allowedit(無自訂,sqledittr 基底):IA 不可改/關帳/已轉應收鎖單 GtrsamaEdit : GinventoryEdit(空殼承接 base 規則)changeopmode:單位/交易別碼 欄僅 新增/修改/複製 可改 單位=UOM 下拉、交易別碼=lcl_tritem1 下拉(框架編輯模式統一控管可編輯性) grid1 29 欄(依 ColumnOrder) TsRadGridView 29 欄 + pkid(順序照 VFP ColumnOrder;原幣未稅/本幣未稅/單位成本/成本/待轉出倉/待轉入倉/轉帳款數量 唯讀同 VFP Enabled=.F.) CMDELSE1 工作流程(WKFLOW_ADD G出貨單送審)/ CMDELSE2 快速審核 / 流程樣板號 / 審核人員/審核日期/已審核 新版集中式 workflow(_sheetno 聯絡單view=vwcommpr_gtrsama 既有),不另做;審核欄不上畫面(同 Gtrrama) 變更(既有檔案)
Model/Source/C.GeneralAffair/Twork_gen_vw_gtrsamaSource.cs:
-
客戶代號Binding補客戶連動(幣別/稅別/運送方式碼/業務員編號/客戶簡稱)-
總原幣未稅/總本幣未稅改為 Notify 屬性(畫面合計即時更新)Model/LocalDbContext.cs:#region C.總務追加Trgama/TrgadeDbSet
(DbSet 名刻意取 server 表名 trgama/trgade,navigate 寫入的本機 SQLite 表才會與 EF
Set<T>對上;與 Greqma 等不同是因 GTRSAMA 的 _sheetno 表名 ≠ view 名)
TsERP/App.xaml:C.總務 region 追加 Gtrsama DataTemplate(xmlns 既有)
Common/Common.csproj:Gtrsama.json Content
TsERP/Lang/Xaml1/Xaml.json:併入Gtrsama區塊
TsERP/Lang/ClassAliasMap.json:新增Twork_gen_vw_gtrsama(ma/de) Model/Source4 條別名
TsERP/Lang/TableMap.json:trgama/trgade 條目既有未改(指向twork_gen_vw_gtrgama/gtrgade,
該 view/類別不存在=陳年 stale 條目;ItemsBindingManager 上傳不走 TableMap,不影響本單據,僅記錄)
Common/ProgramClass.cs:GTRSAMA 既有,未改
刪除
無(原 Gtrsama.xaml 為英文 stale binding 空殼,整檔重做為中文 binding)。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
GTRSAMA_P(SCX_GENP)(SPDARB_RPT_GTRSAMADB 既有)尚未移植(VM 留 TODO 註解)。
- 信用額度/已用額度:VFP 畫面兩個 unbound sqltext(prg 內無賦值邏輯,疑由外部 moverec 填)→ 不移植,視同 dead control。
- 聯絡單ID/工作流程/審核人員/審核日期/已審核/PKID 系統欄不上畫面(集中式 workflow / 框架管理,同 Gtrrama)。
- 交易別碼下拉:VFP sqlcombo 的 RowSource 由基底依 browsetype(-GTRS) 篩選;新版列出全部 lcl_tritem1(無可靠對應篩選依據),空白時存檔由 lcl_tritem 預設交易別補。
- 品名/單位帶入:
SetISKU走 invent(生產品號)查找,G 專屬品號由TsGSKUSearchColumn選取時帶 Description(同 Gtrrama 既有折衷)。
- grid 唯讀控制細節:VFP 品名/單位 欄位 MISC 才可改 → 新版品名開放編輯(非 MISC 由品號帶入覆寫),從寬處理(同 GREQMA 決策)。
- runtime 未驗(trgama 本機 DB 目前無 單據別='3' 資料;_sheetno GTRSAMA 列、vw_gtrsama/vwcommpr_gtrsama/DARB_BD_GTRSADE 等 DB 物件皆既有,無 DB 變更需求)。
-
06-12 greqma-port ▸
2026-06-12 — GREQMA G請購需求(C-030)按 VFP 還原
摘要
依 VFP 舊版
GREQMA(scx_gen.vcx,1823 行)還原 G請購需求(主檔 greqma + 明細 greqde)到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 範本(比照同模組 Gppurch/Gpurch)。編號走 _sheetno(前置碼 PR、srno 5 碼、主表 view
vw_greqma)。VFP grid2「廠商比價表」(查價鈕
DARB_BIZ_SPPDTG+ 回傳鈕)以GUnitPriceQueryViewModel+GUnitPriceSpecialQuery(含 Return 鈕寫回 預估單價)還原。新增
ViewModel/C.GeneralAffair/GreqmaViewModel.cs
LogicBll/Ade/C.GeneralAffair/GreqmaSave.cs、GreqmaEdit.cs
TsERP/C.GeneralAffair/Greqma.xaml(.cs)
Common/Lang/Xaml/Greqma.json(+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 addagain:需求日期=今日、需求人員=USERCODE、需求部門=USER部門代號、採購別=1、倉儲代號=系統參數4001 GreqmaViewModel.AfterAddNew(倉儲代號Context.User.U_Prgpar("4001"))addagain: REPLACE 品號 WITH 'MISC' FOR EMPTY(品號)移至存檔 GreqmaSave.HandleDataBeforeEndEdit:需求數量>0 且 品號空白 → 'MISC'allowedit:轉出備註 非空 → 已轉請購單不得修改 GreqmaEdit.AllowEditHandle→AlreadyTransferedToOtherCannotEditallowsave:需求日期/需求部門/採購別 必填 GreqmaSave.AllowSave逐項 GetInputMessageallowsave:需求數量>0 且 (預訂交期空 或 用途空) → 擋 GreqmaSave.AllowSave(拆成兩則訊息,附 LineNo)allowsave SCAN:明細需求部門空白帶主檔、需求數量<=0 標 'D' GreqmaSave.HandleDataBeforeEndEditsql_gmno1.LostFocus:品號≠MISC 帶品名/單位;MISC 僅空白帶入 Twork_gen_vw_greqdeSource.品號Binding(MISC 保留使用者輸入)txt需求數量/預估單價.Valid:預估金額=ROUND(需求數量×預估單價, 幣別小數位) 需求數量Binding/預估單價Binding→SetAmount()(LocalDecimal,幣別固定本位幣,比照 Gppurch)col預訂交期 Valid:不得小於今日 預訂交期BindingSetErrors(輸入當下驗證,紅框提示)需求人員.代號.Valid:帶部門(VFP 原碼誤寫 G請購單主檔_v.請購部門) 需求人員Binding:GetPerdata 帶 需求部門/姓名/部門簡稱grid1 17 欄(搜尋/全搜鈕除外 15 資料欄) TsRadGridView 16 欄(含 查價 按鈕欄;全搜未做,見下) 查價鈕(DARB_BIZ_SPPDTG,需求日期查價)+ grid2 廠商比價表 + 回傳鈕 查價按鈕欄 → GUnitPriceQueryViewModel.GetDifferentVendorLatestUnitPrice(採購+報價跨廠商);底部GUnitPriceSpecialQueryReturn 鈕寫回 預估單價並重算 預估金額CMDELSE1 工作流程 / CMDELSE2 快速審核 / 流程樣板號 / 審核三欄 新版集中式 workflow,不另做 changeopmode:單位欄僅編輯模式可改、幣別欄停用 幣別欄 ForceReadOnly;單位欄走框架編輯模式控制 grid1.AfterRowColChange:品名僅 MISC 列可改 品名欄開放編輯(非 MISC 由品號帶入覆寫),從寬處理 變更(既有檔案)
Model/Source/C.GeneralAffair/Twork_gen_vw_greqmaSource.cs:新增需求人員Binding(帶部門/姓名)
Model/Source/C.GeneralAffair/Twork_gen_vw_greqdeSource.cs:實作ISKU/IUnitPrice,新增
品號Binding/需求數量Binding/預估單價Binding/預訂交期Binding/SetAmount/單價Binding/數量Model/LocalDbContext.cs:新增#region C.總務(Greqma/Greqde DbSet,置於 D.BOM 前)
TsERP/App.xaml:新增 xmlnsgeneralaffair/generalaffair1+<!--#region C.總務-->(置於 採購管理 後)+ Greqma DataTemplate
Common/Common.csproj:Greqma.json Content
TsERP/Lang/Xaml1/Xaml.json:Greqma區塊
TsERP/Lang/TableMap.json:greqma/greqde 既有條目核對正確(→ Twork_gen_vw_* Model 類名),未改
TsERP/Lang/ClassAliasMap.json:4 條既有別名核對正確,未改
Common/ProgramClass.cs:GREQMA 既有,未改
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
GREQMA_P(SCX_GENP) 尚未移植(VM 留 TODO 註解)。
- 全搜鈕未做:VFP grid Column17「全搜」走
DARB_BIZ_SPPDTG1(無日期上限版查價);新版僅保留 查價(GppurchBll.GetUnitPrice跨廠商最新報價)。
- 公司專屬未做:
IF PUB_公司名稱='朝陽'(品別=5 → 倉儲代號帶 2.物料倉/1.總務倉)為公司專屬邏輯,不移植。
- VFP 隱藏欄位 需求備註/需求說明(2012/02/02 阿美要求隱藏,Visible=.F.)不在畫面呈現;DB 欄位仍在 Source 可日後啟用。
- VFP 查價鈕「需求日期空白 → 請先輸入需求日期」改為以今日代查(不擋)。
- 回傳鈕僅寫回 預估單價(VFP 另帶 幣別;新版明細幣別固定本位幣概念、欄位唯讀,故不帶)。
- 聯絡單ID/工作流程/pkid/審核人員/審核日期/已審核 等系統欄不在畫面呈現(集中式 workflow / 框架管理)。
- runtime 未驗(_sheetno GREQMA 列既有、greqma/greqde/vw_greqma DB 物件既有,無 DB 變更需求)。
-
06-12 gpurama-port ▸
2026-06-12 — GPURAMA G暫收單(C-060)按 VFP 還原
摘要
依 VFP 舊版
GPURAMA(scx_gen.vcx,1508 行)還原 G暫收單(採購到貨暫收;主檔 gpurama + 明細 gpurade)到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 範本(比照同模組 Greqma/Gpurch/Gtrrama)。編號走 _sheetno(前置碼 TP、srno 5 碼、主表 view
vw_gpurama、查庫存=0 →SaveBll不過庫存)。VFP 標籤「廠商代號」實際存欄位
生產部門(sqlnm_sp),照舊保留欄位名、畫面顯示 廠商代號+廠商簡稱(view JOIN)。新增
ViewModel/C.GeneralAffair/GpuramaViewModel.cs
LogicBll/Ade/C.GeneralAffair/GpuramaSave.cs
TsERP/C.GeneralAffair/Gpurama.xaml(.cs)
Common/Lang/Xaml/Gpurama.json(+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 addagain:建檔日期=DATETIME() GpuramaViewModel.AfterAddNew(另比照範本帶 公司代碼=1、暫收日期=今日、幣別=本位幣)allowsave:暫收日期/公司代碼 必填 GpuramaSave.AllowSave逐項 GetInputMessageallowsave SCAN:品號空白 或 數量=0 → 增刪修 'D';否則 幣別 空白帶主檔 幣別 GpuramaSave.HandleDataBeforeEndEdit檢驗完畢.Valid:編輯中勾 'Y' → 明細 檢驗日期 空白者補今日 GpuramaViewModel.ReceiveWeakEvent(ListenerHelper 監聽 檢驗完畢)sql_gmno1.LostFocus:品號≠MISC 一律帶 品名/單位;MISC 僅空白帶入 Twork_gen_vw_gpuradeSource.品號Binding(比照 Greqde MISC 模式改寫)sqlnm_sp1(廠商代號→生產部門)帶 廠商簡稱 Twork_gen_vw_gpuramaSource.生產部門Binding(DescriptionHelper.GetVendor)grid1.AfterRowColChange:入庫數量≠0 → 序號/品號/數量/NG數量/特採數量/檢驗日期/檢驗結果/入庫日期 鎖定 Twork_gen_vw_gpuradeSource.CanEdit(整列鎖,見下)grid1 33 欄(依 ColumnOrder) TsRadGridView 33 欄全數還原(含 採購單/派工單/生產單 PKID 唯讀欄) 須否成績表/是否結案(sqloption1)/檢驗完畢(InputMask Y) TsCheckBox + YesNoConverter moverec_sk_cursor(SK_SPDATA/SK_GINVENT seek 快取) 不需要:廠商簡稱 由 vw_gpurama JOIN、品名 走 DescriptionHelper CMDELSE1 工作流程(WKFLOW_ADD G暫收單送審)/ CMDELSE2 快速審核(已註解) 新版集中式 workflow,不另做 changeopmode:col是否結案 須程式備註(IS_備註)含「結案」才開放 未還原 per-program 備註開關,編輯模式恆開放(見未還原) 變更(既有檔案)
Model/Source/C.GeneralAffair/Twork_gen_vw_gpuramaSource.cs:新增生產部門Binding(帶 廠商簡稱)
Model/Source/C.GeneralAffair/Twork_gen_vw_gpuradeSource.cs:
-
品號Binding改 MISC 模式(非 MISC 強制帶 品名/單位;MISC 僅空白帶入)-
CanEdit由鋪底的採購單pkid <= 0改為入庫數量 == 0(VFP 採轉暫收列仍可登打檢驗結果,已入庫才鎖)Model/LocalDbContext.cs:#region C.總務追加 Gpurama/Gpurade DbSet
TsERP/App.xaml:<!--#region C.總務-->追加 Gpurama DataTemplate
Common/Common.csproj:Gpurama.json Content
TsERP/Lang/Xaml1/Xaml.json:Gpurama區塊
TsERP/Lang/TableMap.json:gpurama/gpurade 既有條目核對正確(→ twork_gen_vw_*),未改
TsERP/Lang/ClassAliasMap.json:4 條既有別名核對正確,未改
Common/ProgramClass.cs:GPURAMA 既有,未改
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- CMDELSE3 採轉暫收未移植:VFP
DO FORM PUTOTP WITH '4'(採購單轉暫收挑單);新版 Gputora(採購轉進貨)無 '4' 暫收模式,
需另開轉單功能(比照 GputoraViewModel 增加目的單據參數),列為功能缺口。
- 報表 TODO:VFP 報表程式
GPURAMA_P(SCX_GENP) 尚未移植(VM 留 TODO 註解)。
- 是否結案欄開關:VFP 依程式備註(IS_備註 含「結案」)決定該欄可否編輯,屬 per-program 客製設定;新版編輯模式恆開放。
- 列鎖定粒度:VFP 入庫數量≠0 僅鎖 8 個欄位(備註/問題點/確認/儲位等仍可改);新版以
CanEdit整列鎖定,從嚴處理。
- VFP 畫面的 pkid / 輸入日期 唯讀欄位不另呈現(框架/審核軌跡管理)。
- 明細 單價/金額/幣別/最小包裝數/外箱數量 欄位(gpurade 有、VFP grid 未顯示)不上畫面;單價×數量→金額 既有 Binding 保留。
- 主檔 採購別/聯絡單id/工作流程 欄位 VFP 未顯示,不上畫面。
- vw_gpurama 無 審核人員/審核日期/已審核 欄(vw_greqma 有);Source 鋪底的這 3 個屬性保留(載入/上傳皆容錯),
若日後要掛集中式審核需先擴充 view。
- runtime 未驗(_sheetno GPURAMA 列既有、gpurama/gpurade/vw_gpurama DB 物件既有,無 DB 變更需求)。
-
06-12 ginvrec-port ▸
2026-06-12 — GINVREC G盤點單(C-130)按 VFP 還原
摘要
依 VFP 舊版
GINVREC(scx_gen.vcx,1363 行)還原 G盤點單(主檔 ginvrecm + 明細 ginvrecd)到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 範本,行為比照同構的 H.Inventory
INVREC(盤點單 H-110)新版實作。編號走 _sheetno(無前置碼、編碼方式 1、srno 5 碼、無主表 view,以實體表 ginvrecm/ginvrecd 為準)。
三顆其他鈕(重算帳列/執行確認/轉盤點單)走
LOG_SYS_INPUT(DARB_LOG_GINVREC_RECOUNT/CONFIRM/TO_AA);「新增查詢」(VFP
DO FORM GINVREC_M)以GinvrecmViewModel彈窗還原,走DARB_GINVREC(帶入庫存產生盤點資料)。新增
ViewModel/C.GeneralAffair/GinvrecViewModel.cs(IOther1/2/3;報表 TODO 註解)
ViewModel/C.GeneralAffair/GinvrecmViewModel.cs(新增查詢彈窗,ERPProgramContentWindowViewModel + ShowContentWindow)
LogicBll/Ade/C.GeneralAffair/GinvrecSave.cs、GinvrecEdit.cs
LogicBll/C.GeneralAffair/Ginvrec/GinvrecBll.cs(DARB_LOG_GINVREC_* 三支 SP 呼叫)
TsERP/C.GeneralAffair/Ginvrec.xaml(.cs)、Ginvrecm.xaml(.cs)
Common/Lang/Xaml/Ginvrec.json(+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 allowsave:製單日期=' ' OR EMPTY(隸屬倉庫) → 請先輸入製單日期及隸屬倉庫 GinvrecSave.AllowSave逐項 GetInputMessageallowsave:REPLACE 增刪修 'D' FOR EMPTY(倉儲代號) AND EMPTY(品號) GinvrecSave.AllowSave/HandleDataBeforeEndEdit(AND 條件照舊版)盤點別.Valid:請輸入 0 或 1 GinvrecSave.AllowSave(存檔把關 + DataIsIncorrect 訊息)allowedit:盤點備註 非空(已轉盤點調整單)→ 不得刪除、修改 GinvrecEdit.AllowEditHandle→AlreadyTransferedToOtherCannotEditelse1click 重算帳列(DARB_LOG_GINVREC_RECOUNT + 放行碼) IOther1.ExtendedFunction1→GinvrecBll.RecalculateQuantityelse2click 執行確認(DARB_LOG_GINVREC_CONFIRM) IOther2.ExtendedFunction2→GinvrecBll.ConfirmQuantityelse3click 轉盤點單(帳列數≠確認盤點數 才可、YesNo 確認、DARB_LOG_GINVREC_TO_AA → trgama 'AA' 單) IOther3.ExtendedFunction3→GinvrecBll.TransferToInventoryAdjustDocument(QuantityAndConfirmedQuantityIsEqual / TransferToInventoryAdjustDocument 訊息)else1/2/3 共同把關:盤點單號未輸入 / 盤點備註非空不得再執行 / ALLOWEDITBASIC 放行碼 GinvrecViewModel.CheckData(IsDataExist + GetPassNumber)else4click 快速審核 / 工作流程 / 審核三欄 新版集中式 workflow,不另做 查詢鈕「新增查詢」:IF OPMODE=1 → DO FORM GINVREC_M AddNewCommand(僅 Add 狀態可執行)→GinvrecmViewModel彈窗GINVREC_M(原始 scx 不可得)→ DARB_GINVREC(篩選別/品號條件/數量別/製單日期/隸屬倉庫/起訖倉儲/異動天數/隨機數) 彈窗 UI 按 SP 參數還原(篩選別 1全部/2品號/3群組/4品別/5儲位/6異動天數/7隨機;數量別 1全部/2≠0/3<0),查詢後回寫主檔 製單日期/隸屬倉庫 並重建明細(盤點卡號 依序編號) sql_gmno1.LostFocus:品號≠MISC 帶品名/單位;MISC 僅空白帶入 Twork_gen_vw_ginvrecdSource.品號Binding(比照 greqde/gcostd)grid 計算欄:初盤差異量=初盤數-帳列數、額=ROUND(量*單位成本,0);複盤/抽盤=IIF(EMPTY(x),0,VAL(x)-帳列數)(Valid 寫回已註解) 初盤數Binding/複盤數Binding/抽盤數Binding輸入當下回寫實體差異欄(比照 H.Inventory Invrec 新版)複盤數/抽盤數 文字欄(InputMask X12,VAL 計算) 維持 string 欄 + TsGridViewDataColumn,差異計算 decimal.TryParse(VAL 語意,非數字=0) changeopmode:單位欄僅編輯可改、品名瀏覽唯讀 框架編輯模式控制(單位 = TsGridViewComboBoxColumn + GetUOM,VFP sqlcombo c_type=104) 盤調單pkid(盤點調整單) 唯讀 + IsHyperLink → GTRLIMA(TO_AA 產生 trgama 單據別 2 'AA') grid1 23 欄(依 ColumnOrder) TsRadGridView 23 欄全還原;帳列數/確認盤點數/差異 6 欄/單位成本 唯讀;差異額 3 欄+單位成本 依檢視單價權限顯示(比照 H Invrec 新版) 變更(既有檔案)
Model/Source/C.GeneralAffair/Twork_gen_vw_ginvrecdSource.cs:實作ISKU,新增
品號Binding/初盤數Binding/複盤數Binding/抽盤數Binding(含 VAL 語意解析);既有屬性未動Model/LocalDbContext.cs:#region C.總務追加 Ginvrecm/Ginvrecd DbSet
Common/DataBaseObjectEnum/Procedure.cs:新增DARB_GINVREC、DARB_LOG_GINVREC_RECOUNT/CONFIRM/TO_AA
TsERP/App.xaml:C.總務 region 追加 Ginvrec + Ginvrecm DataTemplate
Common/Common.csproj:Ginvrec.json Content
TsERP/Lang/Xaml1/Xaml.json:Ginvrec區塊
TsERP/Lang/TableMap.json:ginvrecm/ginvrecd 既有條目核對正確(→ twork_gen_vw_*),未改
TsERP/Lang/ClassAliasMap.json:4 條既有別名核對正確,未改
Common/ProgramClass.cs:GINVREC 既有(line 212),未改
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
GINVREC_P(SCX_GENP)(DB 另有DARB_RPT_GINVREC)尚未移植(VM 留 TODO 註解)。
- 匯出鈕「測試匯出」不移植:VFP
COPY TO C:\TEMPS\G盤點單為測試碼。
- GINVREC_M.scx 原始檔不可得:彈窗 UI 依
DARB_GINVRECSP 參數 + 同構 H.InventoryInvrecm還原;
H 版查詢後另補 100 張空白盤點卡,G 版不補(VFP G allowsave 會把 倉儲代號+品號 全空列標 'D',空白卡存不下來)。
- 品別篩選以文字輸入(H 版用 C204 代碼表 combo;G ginvent 品別 對應代碼表未確認,避免掛錯 alias)。
- 品號帶品名/單位(鍵盤輸入路徑)沿用模組既有
DescriptionHelper.GetInvent/SetISKU,查的是vwseek_invent(B 品號檔)而非vwseek_ginvent(G 品號檔)——greqde/gcostd/gpurch 同此模式(搜尋欄 TsGSKUSearchColumn 本身查 G 表,挑選路徑正確);如 G 品號不在 B 品號檔,鍵入後不自動帶品名,屬模組既有行為。
- txt初盤數/抽盤數/複盤數.Valid 在 VFP 已整段註解(差異欄寫回停用);新版比照 H Invrec 於輸入當下寫回實體差異欄(display 與 stored 一致化)。
- VFP 隱藏系統欄 聯絡單ID/工作流程/pkid/審核人員/審核日期/已審核 不在畫面呈現(集中式 workflow / 框架管理)。
- 公司專屬邏輯:本支 VFP 無
PUB_公司名稱分支。
- dead column:ginvrecd.儲位/品別/群組代號 在 VFP grid 不顯示(由 GINVREC_M 查詢塞值);新版同樣不顯示但查詢時照塞。
- runtime 未驗(DB 物件 ginvrecm/ginvrecd/DARB_GINVREC*/DARB_LOG_GINVREC_* 與 _sheetno GINVREC 列皆既有,無 DB 變更需求)。
-
06-12 ginvbook-port ▸
2026-06-12 — GINVBOOK G庫存帳冊(C-100)按 VFP 還原
摘要
依 VFP 舊版
GINVBOOK(scx_gen.vcx,3582 行,sql_qrya 查詢程式)還原 G庫存帳冊到 TsERP V2,走
ERPProgramWithQueryViewModel<DefaultParameters, DefaultQueryCondition>+SqlQry查詢程式範本(比照 Invbk1 庫存帳冊)。純查詢程式,不在 _sheetno、無 Source/DataManager(Dapper DataSet → Poco),不動 TableMap/LocalDbContext/ClassAliasMap。
兩支既有 SP(darbnogicsa1,proc_param 已登錄,本次核對簽章與 VFP 呼叫一致,無需修正腳本):
DARB_GINVBOOK(6 參數:隸屬倉庫/品號條件/起迄倉儲/起迄日期;5 個結果集)— 分類進出帳,
每個範圍內 gstkbas 隸屬倉庫呼叫一次,期初(最近 gcostm 成本月份+期前 trgama 異動)/明細拆轉入轉出/結餘 由 client 計算
DARB_GINVBOOK1(7 參數:起迄倉庫/品號條件/起迄倉儲/起迄日期;1 個結果集)— 日記帳,單號 RD 開頭列 數量/其他金額/金額 取負
新增
LogicBll/C.GeneralAffair/Ginvbook/GinvbookBll.cs(含 條件別/單據別/索引別 三個 enum)
LogicBll/C.GeneralAffair/Ginvbook/GinvbookSqlPocos.cs(DARB_GINVBOOK 5 個結果集 Poco)
LogicBll/C.GeneralAffair/Ginvbook/GinvbookMaster.cs、GinvbookDetail.cs(GINVBKM/GINVBKD cursor 對應)
LogicBll/C.GeneralAffair/Ginvbook/GinvbookDetail2Poco.cs(GINVBKD2 日記帳)
ViewModel/C.GeneralAffair/GinvbookViewModel.cs
TsERP/C.GeneralAffair/Ginvbook.xaml(.cs)(TsView + SqlQry 條件區 + 兩個 Tab:分類進出帳 主明細 grid、日記帳 grid)
Common/Lang/Xaml/Ginvbook.json(61 keys;+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 Init:起始/截止倉庫=sk_gstkbas 第一筆、倉儲/品號/群組/儲位 ''~'zzzzzz'、日期=今日~今日 GinvbookViewModelctor(GetGstkbas 第一筆)+GinvbookBll屬性預設值起始倉庫.LostFocus → 帶入截止倉庫 起始倉庫setter(非空白即帶)查詢鈕:起迄倉庫皆空 → 擋;查無隸屬倉庫 → 擋 CheckWarehouse()(兩則 VFP 訊息)條件別(品號/群組代號)組 L_品號條件+儲位範圍 GinvbookBll.Query/QueryJournal條件字串(同 VFP 字面)每個隸屬倉庫 LOG_SYS_EXEC('GINVBOOK','DARB_GINVBOOK',6 參數) Log_Sys_Exec(out _, "GINVBOOK", Procedure.DARB_GINVBOOK.Name, ...)TMP品名(RS0∪RS1∪RS2 抓品名/單位) dic品名(首見先贏)不分儲位/不分工程/不分批號 → 鍵值合併(倉儲→隸屬倉庫、途程/工程/批號別→空白、批號→0) ProcessWarehouse對 master/明細/成本表/期前表 一致套用GINVBKD:SQLRESULT2 拆 轉入/轉出 兩列,不在 #depotno 的倉儲不出列 CreateDetail×2(dic倉儲 lookup 失敗即跳過)期初數量=TMP成本表.期初+TMP期前表.(入庫-出庫);期初<>0 或 有明細 → 補「 期 初」明細列 ProcessWarehouse主表迴圈(期初列 交易日期=' 期 初',結餘=期初)3.計算交易進出明細:單號 AA 開頭=盤差,其餘入/出庫;逐列結餘 CalculateRunningBalance(OrderKey:期初列最先→交易日期→入庫先於出庫)期末數量/金額 = 期初+入庫-出庫+盤差 GinvbookMaster.期末數量/期末金額computed property期末不為0 → 刪期末=0;否則刪全零且明細≤1(2016/07/21 一筆期初也過濾) DeleteMaster(multiDetailKeys = 明細筆數>1 的 key)分類1~6(grpm)+尺寸(gitemspec 分類='尺寸') Set分類(資料保留供 Excel 匯出;VFP grid 本來就不顯示,僅模具表報表用)品號結尾:每品號群組最後一筆=.T. Set品號結尾索引別(倉庫排序/品號排序),查詢後重設=倉庫排序 索引別enum 屬性(切換即重排 Master);Query()重設日記帳查詢鈕:DARB_GINVBOOK1(7 參數);單據別=進貨 → + LEFT(a.單號,2) IN ('RC','RD','MG');RD 取負;SET ORDER TO 品號QueryJournal(StartsWith("RD") 取負、OrderBy 品號);單據別預設=進貨(VFP Value=2)GINVBKM↔GINVBKD SET RELATION(鍵=隸屬倉庫+倉儲代號+品號+其他鍵) SelectedMaster→Key→dic(ToDictionaryList)切 DetailEXCEL 匯出(U_ToExcel) IExcel.GenerateExcel(分類進出帳/進出明細/日記帳 三張工作表)變更(既有檔案)
Common/ProgramClass.cs:新增GINVBOOK(GCOST 與 GINVENT 之間,字母序)
Common/DataBaseObjectEnum/Procedure.cs:新增DARB_GINVBOOK、DARB_GINVBOOK1
TsERP/App.xaml:C.總務 region 追加 Ginvbook DataTemplate
Common/Common.csproj:Ginvbook.json Content
TsERP/Lang/Xaml1/Xaml.json:Ginvbook區塊(61 keys)
刪除
無。
Breaking Changes
無(純新增)。
Migration Notes / 未還原項目
- DB 無變更:兩支 SP 既存且 proc_param 已登錄(DARB_GINVBOOK param_qty=6、DARB_GINVBOOK1 param_qty=7,databaseid=C);
本次核對 SP 參數順序/型別與 VFP 呼叫一致、回傳欄位與 Poco 一致,不需 ginvbook-sp.sql。
- 報表 TODO:VFP 報表選擇(明細
GINVBOOK1/ 彙總GINVBK1M/ 模具表GINVBKMD,含 2013/04/22 鈞寶模具
TMPMOLDSTOCK 母模/上模/下模/中棒 統計).frx 未移植(VM 留 TODO 註解)。
- 樞紐分析鈕未移植:VFP 分析鈕走本機
LCL樞紐分析表+ Excel 樞紐檔(GETOBJECT EXCEL.APPLICATION),
屬舊機制;新版 SqlQry 框架內建 PivotSelector 取代。
- 條件區合併:VFP 有兩組獨立條件(PF1.Page1 分類進出帳、PF.Page2 日記帳,後者倉庫預設 ''~'zzzzzz');
新版合併為一組共用條件(預設值取 PF1:倉庫=第一筆 gstkbas)。日記帳要查全部倉庫時請自行放寬起迄倉庫。
- VFP dead column 不移植(VFP 也從未填值,永遠空白):
- 主表:品別/舊品號/群組代號/說明/儲位/現有數量/現有金額/標準成本/新增備註/起始~截止 條件回填欄
- 明細:材料成本/人工成本/加工金額/製造費用/轉入單號/派工單號
- 日記帳:採購單號(SP 只回傳 採購單pkid)
- VFP 起迄倉庫空白訊息原文「請先輸入起迄倉儲代號」為舊版筆誤(檢查的是倉庫欄位),新版訊息改為「起迄倉庫代號」。
- 公司專屬邏輯:模具表(鈞寶)僅在報表層,未涉及;無其他
IF PUB_公司名稱分支。
- runtime 未驗(build 綠燈:Common/LogicBll/ViewModel;TsERP.csproj XAML 編譯由主線統一跑)。
-
06-12 gcost-port ▸
2026-06-12 — GCOST G成本表(C-120)按 VFP 還原
摘要
依 VFP 舊版
GCOST(scx_gen.vcx,2420 行)還原 G成本表(主檔 gcostm + 明細 gcostd)到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 範本(比照同模組 Greqma/Gpurama)。本單據 _sheetno 無前置碼/無編碼方式/srno=0、無主表 view:單號 = 年度月份(使用者輸入鍵值,
InputMask
9999/99、is_noduplicate="gcostm"重複檢查、僅新增模式可輸入)。明細為 76 欄成本彙總 grid(倉儲交易 數/金 對 + 單位成本/計算成本/平均單價 + 期末與完工 材料/人工/製費/加工)。
新增
ViewModel/C.GeneralAffair/GcostViewModel.cs
LogicBll/Ade/C.GeneralAffair/GcostSave.cs
TsERP/C.GeneralAffair/Gcost.xaml(.cs)
Common/Lang/Xaml/Gcost.json(+ Common.csproj Content + TsERP/Lang/Xaml1/Xaml.json 併入)
VFP 行為對照
VFP 新版 年度月份 InputMask="9999/99"、dovalid=1 GcostSave.AllowSave:必填 + 格式 `^\d{4}/(0[1-9]1[0-2])$` 驗證 年度月份 is_noduplicate="gcostm"GcostSave.IsDocNoDuplicate:DARB_GETDATA4查 gcostm年度月份=N'..' AND pkid<>..(比照 EstsalSave)changeopmode:OPMODE=1(新增) 年度月份 ENABLED,其餘停用 GcostViewModel.YearMonthIsEnabled(AdeViewModel.Status 監聽);新版 Copy 也開放(鍵值需重新輸入,否則必撞重複檢查)allowsave: REPLACE 增刪修 WITH 'D' FOR EMPTY(倉儲代號) OR EMPTY(品號) OR EMPTY(隸屬倉庫)GcostSave.MarkEmptyDetailDeleted(AllowSave + HandleDataBeforeEndEdit)+Twork_gen_vw_gcostdSource.NeedDeleteFunctionsql_gmno1.LostFocus:品號≠MISC 一律帶品名(U_SEEKNM SK_GINVENT);MISC 僅品名空白帶入 Twork_gen_vw_gcostdSource.品號Binding(Context.DescriptionHelper.GetInvent,比照 greqde)grid1 76 欄(依 ColumnOrder:隸屬倉庫→倉儲代號→品號→途程序號→工程代號→…→完工加工) TsRadGridView 76 欄同序還原;數量欄 PlaceEnum=PurchaseQuantity、金額欄Local、單位成本/計算成本/平均單價UnitCost倉儲代號 sql_gsplaceno / 品號 sql_gmno / 工程代號 sql_procno 搜尋欄 TsGBinSearchColumn/TsGSKUSearchColumn/TsProcessingSearchColumn隸屬倉庫 sql_gstkbas 搜尋欄 一般 TsGridViewDataColumn(grid 無 G倉庫 搜尋欄型,見未還原)無 addagain(主檔無預設值) 不實作 IAdd(年度月份由使用者輸入) else1click 倉庫表導入(DO FORM gsplace) VFP 原碼已整段註解 = dead code,不移植 變更(既有檔案)
Model/Source/C.GeneralAffair/Twork_gen_vw_gcostdSource.cs:新增品號Binding(MISC 邏輯)+NeedDeleteFunction(三欄任一空白)
Model/LocalDbContext.cs:#region C.總務內新增 Gcostm/Gcostd DbSet
TsERP/App.xaml:C.總務 region 內新增 Gcost DataTemplate
Common/Common.csproj:Gcost.json Content
TsERP/Lang/Xaml1/Xaml.json:Gcost區塊(80 鍵)
TsERP/Lang/TableMap.json:gcostm/gcostd 既有條目核對正確(→ twork_gen_vw_gcostm/gcostd),未改
TsERP/Lang/ClassAliasMap.json:4 條既有別名核對正確,未改
Common/ProgramClass.cs:GCOST 既有,未改
Model/Source/C.GeneralAffair/Twork_gen_vw_gcostmSource.cs:與 DB gcostm 比對,業務欄(年度月份)已齊;既有
建檔日期/已審核/審核日期/審核人員/工作流程/聯絡單id 屬性保留未動(DB 實體表無此 6 欄,見 Migration Notes)
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
GCOST_P(SCX_GENP) 尚未移植(VM 留 TODO 註解)。
- 隸屬倉庫 grid 搜尋欄:VFP 為 sql_gstkbas(G倉庫)搜尋控件;TsControl 無對應的 G倉庫 grid 搜尋欄型
(TsWarehouseSearchColumn 指向 H 模組 stkbas),暫以一般文字欄還原,待補欄型後再換。
- 倉儲代號搜尋未帶隸屬倉庫過濾:VFP sql_gsplaceno 依列上 隸屬倉庫 過濾;
TsGBinSearchColumn.FilterCondition
既有用法只支援 MasterItem 層級(Gtrinout 模式),明細列級過濾暫不掛,搜尋顯示全部 G倉儲位置。
- gcostm 無審核/工作流程欄位:DB 實體表 gcostm 只有 年度月份 + 系統欄;既有 Source 的
建檔日期/已審核/審核日期/審核人員/工作流程/聯絡單id 屬性保留(audit 欄框架慣例,上傳走 XML/SP 映射),
但畫面不呈現、不掛集中式審核(審核三欄在 DB 不存在)。
- changeopmode 差異:VFP 僅 OPMODE=1 開放 年度月份;新版 Copy 模式也開放(複製後鍵值必須改,否則重複檢查擋存檔)。
- 年度月份格式驗證訊息(YYYY/MM)為新版補強(VFP 靠 InputMask 限制輸入,無訊息)。
- runtime 未驗(gcostm/gcostd DB 物件既有、TableMap/_sheetno 列既有,無 DB 變更需求)。
-
06-12 estsal-port ▸
2026-06-12 — ESTSAL 年度預估(E-950)按 VFP 還原
摘要
依 VFP 舊版
ESTSAL(scx_ord.vcx,646 行)完美還原年度預估 主明細表單到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 最新範本(比照 Claim)。主檔
estsalm(DB 無 vw_estsalm,直接綁資料表)、明細走vw_estsaldview(JOIN invent 帶 品名)。新增
Common/Model/E.Order/EstsalmModel.cs、Twork_ord_vw_estsaldModel.cs
Model/Source/E.Order/EstsalmSource.cs、Twork_ord_vw_estsaldSource.cs
LogicBll/Ade/E.Order/EstsalSave.cs
ViewModel/E.Order/EstsalViewModel.cs
TsERP/E.Order/Estsal.xaml(.cs)
Common/Lang/Xaml/Estsal.json(+ Common.csproj Content)
VFP 行為對照
VFP 新版 addagain: REPLACE 幣別 WITH m.指定幣別, 匯率 WITH 1EstsalViewModel.AfterAddNew(IAdd):幣別=Context.Env.LocalCurrency、匯率=1(VFP 指定幣別=本位幣)allowsave:年度/年預估分類/版次/客廠部代號 必填 EstsalSave.AllowSave逐項 GetInputMessage(年預估分類 int → ==0 視為空)單號 is_noduplicate="estsalm"EstsalSave.IsDocNoDuplicate:DARB_GETDATA4 查 estsalm單號=N'x' AND pkid<>current;另補單號必填(_sheetno 無編碼方式,空白單號無法存)allowsave: EMPTY(品號)→ 增刪修 'D'NeedDeleteFunction+MarkEmptyDetailDeleted雙保險grid sql_mno1dovalid=1(品號驗證帶品名)Twork_ord_vw_estsaldSource.品號Binding→SetSkuData(),查無→「查無品號 !!!」grid Column9 U_SEEKNM('SK_INVENT',品號,'品名')+moverec_sk_cursor明細直接走 vw_estsald.品名(navigate 載入即有),編輯時 SetSkuData 重抓grid col單位 sqlcombo c_type=104(changeopmode 控 enable) TsGridViewComboBoxColumn+ComboBoxItemsSource.GetUOM()(Cmb_C104);編輯閘門由 grid 全域 Ade 狀態控制客廠部代號 sqlnm_cuspdp1(代號+簡稱) 客廠部代號Binding+ CuspSearch 樣式,簡稱走DescriptionHelper.GetCustVendDeptName計算屬性幣別 sqlcombo c_type=1 TsCurrency數量 mask .9999 / 單價 mask .999999 / 匯率 mask .9999 PlaceEnum FourPlace / SixPlace / FXRate 輸入日期/審核人員/審核日期 唯讀(txt_color=2) XAML IsReadOnly=True 變更(既有檔案)
TsERP/Lang/TableMap.json:修正預留映射 —
"estsalm": "twork_ord_vw_estsalm"→"estsalm"(DB 無該 view)、"estsald": "twork_ord_vw_estsald"→"vw_estsald"(DB 實際 view 名)TsERP/Lang/ClassAliasMap.json:Twork_ord_vw_estsalm*預留別名改為Estsalm*(照表名命名);
Twork_ord_vw_estsald*預留別名沿用(view 存在)Model/LocalDbContext.cs:DbSet<EstsalmSource> Estsalm、DbSet<Twork_ord_vw_estsaldSource> Estsald
TsERP/App.xaml:EstsalViewModel DataTemplate
TsERP/Lang/Xaml1/Xaml.json:Estsal區塊
Common/ProgramClass.cs:ESTSAL既有,未改
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
ESTSAL_P(SCX_ORDP) 尚未移植。
- 跨單據整合 TODO:preord 預示表的 estsal 補充數量機制(
PreordControlViewModel既有待辦)本次只還原單據本體,整合另案處理(VM 註解已標 TODO)。
- estsalm 僅有 審核人員/審核日期 兩欄、無 已審核 欄 → 依「審核三欄才掛」原則不掛集中式審核,兩欄唯讀顯示。
- VFP 註解掉的單號自動組碼(年度+分類+版次+客廠部代號)為 dead code,未還原。
- runtime 未驗。
-
06-12 darb-sp-repoint ▸
2026-06-12 六支轉單/查詢改接 VFP 原版 DARB SP(TWORK 新版不移植)
摘要
C# 端有 6 個呼叫點指向資料庫不存在的
TWORK_*SP(從未部署,功能開窗即錯)。**使用者裁定:不移植 TWORK 新版 SP,直接改接 darbnogicsa1 既有的 VFP 原版
DARB_*SP。**程式 原呼叫(不存在) 改接(darbnogicsa1 既有) 庫存帳冊 Invbk1 TWORK_INVBK1DARB_INVBK1(6 參數 9 結果集)庫存查詢 Qry_Invstk TWORK_QRY_INVSTKDARB_QRY_INVSTK(2 參數)備料呆滯轉單 Trlost_A TWORK_TUR_TRLOST_ADARB_TUR_TRLOST_A(2 參數)總務請轉採 Gpptopu TWORK_TUR_GPPTOPUDARB_TUR_GPPTOPU(2 參數)總務倉庫關帳 Gstkbas_1 TWORK_TUR_GSTKBASDARB_TUR_GSTKBAS(2 參數)G申請出入轉交易單 GtrapplyToGtrlima TWORK_TUR_GTRAPPLYTOGTRLIMA<br>TWORK_QRY_GTRAPPLYPICKDARB_TUR_GTRINOUTE(2 參數)<br>DARB_TUR_GSPLACE@查詢別=2(挑單庫存)決策依據
- Gpptopu 選
DARB_TUR_GPPTOPU而非已登錄的DARB_TUR_GPPTOPU1:
vfpcode/scx_gen.prggpurchelse3click:IF .T. → DO FORM GPPTOPU(2018/03/12 起設為預設),GPPTOPU1 為備用分支(
gpptopu1.prgdatafunc=DARB_TUR_GPPTOPU1)。照 VFP 實際使用者選 GPPTOPU。- GtrapplyToGtrlima 挑單:VFP GTRINOUTE 表單原始碼不在 repo、DB 也無任何 pick SP;
挑單庫存改用已登錄的
DARB_TUR_GSPLACE查詢別=2(gstkbas/gsplace/ginvstk JOIN,總務庫存),以該申請單品號
IN (...)過濾,與 SplaceBll 既有用法同模式。變更
行為(使用者可見)
- 上述 6 支功能由「開窗查詢即 SP 不存在錯誤」變為可正常查詢/轉單(runtime 未驗收)。
- Gpptopu 篩選:
DARB_TUR_GPPTOPUWHERE 為固定條件(轉出備註空、數量>已訂購、廠商代號非空、未結案),
忽略
@查詢條件;畫面的請購單號/請購日期範圍改在 client 端過濾,結果等價。- Gpptopu 廠商品號:原版 SP 結果無
廠商品號欄,轉出之採購明細該欄為空(VFP 原版同)。
- GtrapplyToGtrlima 挑單:
- 庫存來源為總務
ginvstk(原 TWORK 設計疑似查產銷存 invstk,無從對證——SP 從未存在)。-
ForCustomerCode(工程代號保留客戶)原版查詢無此欄→空字串:帶工程代號的庫存不會自動配置,仍會列在挑單畫面供手動挑。
-
QuantityPerCarton(箱數)gtrinoutd 無此欄→0,轉出 trlist.箱數=0。- 庫存列無交易日期(ginvstk 無此欄),同數量時排序略有差異。
- Qry_Invstk:DARB 版第 3 結果集(採購未入/訂單未交)與第 5 結果集(暫收明細)無
隸屬倉庫欄;
「指定倉庫」(WarehouseOnly)非 all 時這兩類列會被 client filter 全濾掉(原 TWORK 合約無從對證,先按原版)。
程式
Common/DataBaseObjectEnum/Procedure.cs:
- 新增
DARB_INVBK1、DARB_QRY_INVSTK、DARB_TUR_TRLOST_A、DARB_TUR_GPPTOPU、DARB_TUR_GSTKBAS、DARB_TUR_GTRINOUTE、DARB_TUR_GSPLACE。- 移除 7 個無其他引用的死 enum:
TWORK_INVBK1、TWORK_QRY_INVSTK、TWORK_TUR_TRLOST_A、TWORK_TUR_GPPTOPU、TWORK_TUR_GSTKBAS、TWORK_TUR_GTRAPPLYTOGTRLIMA、TWORK_QRY_GTRAPPLYPICK。LogicBll/C.GeneralAffair/Gpptopu/GpptopuBll.cs:主子合併單表 → 依請購單號拆 Master/Detail
(合成 pkid/linkid;子檔 pkid←請購pkid、序號←請購序號)+ client 端範圍過濾。
LogicBll/C.GeneralAffair/Gpptopu/GpptopuLockedSource.cs:補中文TsColumnName映射。
LogicBll/C.GeneralAffair/GtrapplyToGtrlima/GtrapplyToGtrlimaBll.cs:改接 + 依申請單號合成 pkid_m
+挑單改
DARB_TUR_GSPLACE(隸屬倉庫由OpenDbfTable.GetGsplace()對照補上)。LogicBll/C.GeneralAffair/GtrapplyToGtrlima/GtrapplyToGtrlimaPoco.cs:補中文TsColumnName映射。
LogicBll/C.GeneralAffair/GtrapplyToGtrlima/Twork_qry_gtrapplypickPoco.cs:set-only 中文別名屬性
承接 倉儲代號/品號/現有數量(基底為共用 picking poco 不便加屬性標記)。
LogicBll/C.GeneralAffair/Gstkbas_1/Stkbas_1TmpPoco.cs:EditingUser補[TsColumnName("修改人員")]。
LogicBll/H.Inventory/Qry_Invstk/Tmp.cs:品別int→byte、leadtimeint→short
(DB 為 tinyint/smallint,DataTable→Poco 映射不做數值轉型,原型別 runtime 會丟 ArgumentException)。
Invbk1Bll.cs/InvstkBll.cs/Trlost_ABll.cs/Gstkbas_1Bll.cs:SP 名改接(參數/結果集既已對齊 DARB 中文欄名)。
待辦(不要執行 DB 寫入,主線跑)
.claude/tmp/proc-param-register.sql:DARB_TUR_GPPTOPU、DARB_TUR_GSTKBAS兩筆 proc_param 登錄
(其餘 5 支已登錄)。未登錄前這兩支轉單仍會失敗。
- 6 支表單 runtime 驗收(本批次僅靜態對齊+build 綠燈)。
Migration Notes
- 已刪除
.claude/tmp/scx_stk/TWORK_TUR_TRLOST_A.sql(原擬新建 SP 的草稿;原版已存在不需要)。
- 無資料庫 schema 變更;僅 proc_param 兩筆 INSERT(見上)。
- Gpptopu 選
-
06-12 cungma-port ▸
2026-06-12 不良處理單(CUNGMA)移植
摘要
依 VFP 舊版
scx_ord.vcx / cungma完整移植「不良處理單」(選單 H-140)到 TsERP V2。Master+Detail 單據(主表
cungma、子表cungde,無 view),編號依_sheetno(單據別 CUNGMA、前置碼 N、編碼方式 4、srno 長度 4)。
新增
Common\Model\E.Order\CungmaModel.cs/CungdeModel.cs
Model\Source\E.Order\CungmaSource.cs/CungdeSource.cs
ViewModel\E.Order\CungmaViewModel.cs—ErpProgramWithDetailViewModel+ IAdd
LogicBll\Ade\E.Order\CungmaSave.cs— 反射命名LogicBll.Ade.CungmaSave
TsERP\E.Order\Cungma.xaml(.cs)— TsView + TsRadGridView 明細
Common\Lang\Xaml\Cungma.json+TsERP\Lang\Xaml1\Xaml.json併入 Cungma 區段
登錄點
TsERP\Lang\TableMap.json:"cungma": "cungma"、"cungde": "cungde"
Model\LocalDbContext.cs:DbSet<CungmaSource>、DbSet<CungdeSource>
Common\ProgramClass.cs:CUNGMA
TsERP\App.xaml:CungmaViewModel → CungmaDataTemplate
TsERP\Lang\ClassAliasMap.json:Cungma/Cungde Model+Source
Common\Common.csproj:Lang\Xaml\Cungma.jsonContent
VFP 行為對照
VFP 新版 addagain:公司代碼=1、日期=今天CungmaViewModel.AfterAddNewallowsave:公司代碼/日期空白擋存CungmaSave.AllowSaveallowsave:異常chk1~5,A / 確認chk1~5 組 異常狀況/確認狀況(固定 1~5,A 順序補滿 10 位)CungmaSource的異常Chk*/確認Chk*bool 屬性即時雙向維護字串changeopmode:依 異常狀況/確認狀況 還原勾選同上(屬性 get 從字串解析,移動筆自動刷新) allowsave:SCAN 檢測項目空白 → 增刪修='D'CungmaSave+CungdeSource.NeedDeleteFunction客戶代號.Valid:cudata 帶客戶簡稱/聯絡人1/公司電話/公司傳真客戶代號Binding → SetCustomerData()(DARB_GETDATA4,查無時清空,不另提示=VFP 行為)廠商代號.Valid:spdata 帶廠商簡稱廠商代號Binding → SetVendorData()品號.Valid:invent 帶品名/廠牌品號Binding → SetSkuData()里程數.Refresh:里程數=維修里程-更換里程(不存檔)CungmaSource.里程數NotMapped 計算屬性真因分析選項(sqlcombo c_type=274)TsComboBoxBySql TableAlias="C274"(環境 SQLite CMB_274)綁 VM真因分析選項cmdbtn_yes1(產生鈕):smemsd 摘要=選項 取敘述逐行拆「檢測項目;標準數據」填空白列;未選/已有檢測項目擋下CungmaViewModel.GenerateDetailCommand(限編輯模式)公司代碼 sqlcombotxt c_type=101 TsComboBoxWithDescriptionBySql TableAlias="C101"明細 grid:序號/檢測項目/標準數據/實際數據/OK? TsRadGridView 同欄位 無審核三欄 不掛集中式審核 SP 依賴:僅
DARB_GETDATA4(darbnogilog1.proc_param 已登錄,param_qty=3),無需新 SP。未還原項目
- 報表
CUNGMA_P(SCX_ORDP)— TODO(VM 註解)
- EDI 鈕
else1click(DO FORM EDI_CUNGMA轉入+權限檢查)— 不在本次範圍,TODO(VM 註解)
客戶電話.DblClickSkype 撥號(U_IELINK)— 不移植
- VFP
單號.is_noduplicate(手動輸入單號防重)— 新版單號由_sheetno自動編號(唯讀),不需要
- ⚠️ 真因分析選項清單內容依環境 SQLite
CMB_274;本機smemsd無 C274 類別資料時清單為空(runtime 待驗)
Runtime 未驗
全部畫面/存檔流程僅 build 驗證,未實機開窗測試。
-
06-12 culbl-port ▸
2026-06-12 客戶標籤檔(CULBL)移植
摘要
依 VFP 舊版
scx_ord.vcx / culbl完整移植「客戶標籤檔」(選單 H-130)到 TsERP V2。單檔主檔(無明細、無 view,直接映射
culbl表),編號依_sheetno(單據別 CULBL、編碼方式 0、srno 長度 3)。新增
Common\Model\E.Order\CulblModel.cs(前手已建,欄位與 DB 核對無誤沿用)
Model\Source\E.Order\CulblSource.cs— 中文屬性對映 DB 欄位
ViewModel\E.Order\CulblViewModel.cs—ERPProgramViewModel單檔主檔
LogicBll\Ade\E.Order\CulblSave.cs— 反射命名LogicBll.Ade.CulblSave
TsERP\E.Order\Culbl.xaml(.cs)— TsView 版面
Common\Lang\Xaml\Culbl.json+TsERP\Lang\Xaml1\Xaml.json併入 Culbl 區段
登錄點
TsERP\Lang\TableMap.json:"culbl": "culbl"
Model\LocalDbContext.cs:DbSet<CulblSource> Culbl
Common\ProgramClass.cs:CULBL
TsERP\App.xaml:CulblViewModel → CulblDataTemplate
TsERP\Lang\ClassAliasMap.json:CulblModel/CulblSource → Culbl
Common\Common.csproj:Lang\Xaml\Culbl.jsonContent
VFP 行為對照
VFP 新版 allowsave:日期空白擋存「請先輸入日期 !!!」CulblSave.AllowSave以 GetInputMessage 提示客戶代號.LostFocus:查 cudata 帶客戶名稱/公司地點/公司電話,查無提示「查無客戶代號 !!!」CulblSource.客戶代號Binding → SetCustomerData()(DARB_GETDATA4)無 addclick/addagain 預設值 不設預設(日期由存檔檢查強制) 無審核三欄 不掛集中式審核 未還原項目
- 報表
CULBL_P(SCX_ORDP)— TODO(VM 註解)
公司地點.DblClick開地圖、公司電話.DblClickSkype 撥號(U_IELINK 桌面整合)— 不移植
-
06-12 cmplain-port ▸
2026-06-12 — CMPLAIN 抱怨單(E-210)按 VFP 還原
摘要
依 VFP 舊版
CMPLAIN(scx_ord.vcx,548 行)完美還原抱怨單 主明細表單到 TsERP V2,走
ErpProgramWithDetailViewModel+ItemsBindingManager+ TsView/TsRadGridView 最新範本(比照 Claim)。資料表
cmplain_m/cmplain_d(無編輯 view,直接綁資料表)。新增
Common/Model/E.Order/Cmplain_mModel.cs、Cmplain_dModel.cs
Model/Source/E.Order/Cmplain_mSource.cs、Cmplain_dSource.cs
LogicBll/Ade/E.Order/CmplainSave.cs
ViewModel/E.Order/CmplainViewModel.cs
TsERP/E.Order/Cmplain.xaml(.cs)
Common/Lang/Xaml/Cmplain.json(+ Common.csproj Content)
VFP 行為對照
VFP 新版 allowsave:公司代碼=0 擋存 CmplainSave.AllowSaveGetInputMessageallowsave: DTOC(CTOD(年度月份+'/01'))驗證DateTime.TryParseExact(yyyy/MM/dd),訊息「請先輸入正確之年度月份 !!!」allowsave: REPLACE 單號 WITH STR(公司代碼,1)+年度月份HandleDataBeforeEndEdit組前置碼,_sheetno 編碼方式 4 由 server 補 3 碼流水allowsave:明細 日期 非空且 日期<>年度月份(VFP = 比對 LEFT 7 碼)擋存StartsWith(年度月份)檢查,訊息「明細資料日期輸入錯誤 !!!」allowsave:日期空白且抱怨事項空白 → 增刪修 'D' NeedDeleteFunction+MarkEmptyDetailDeleted雙保險sql_cuno1.Valid:DARB_GETDATA4 cudata(客戶代號 OR 對照碼)帶 客戶代號/客戶簡稱/聯絡人1/聯絡1電話;查無→「查無客戶代號 !!!」;含 ?[] 不處理Cmplain_dSource.客戶代號Binding→SetCustomerData(),比照Vw_claim_mSourceBinding 模式主檔 備註 ReadOnly XAML IsReadOnly=True 公司代碼 sqlcombotxt c_type=101 TsComboBoxWithDescriptionBySql TableAlias="C101"完成與否 InputMask "Y" TsGridViewCheckBoxColumn+ YesNoConverter(Y/空白)變更(既有檔案,僅登錄點)
TsERP/Lang/TableMap.json:cmplain_m/cmplain_didentity 登錄(DB 無編輯 view)
Model/LocalDbContext.cs:DbSet<Cmplain_mSource> Cmplain_m、DbSet<Cmplain_dSource> Cmplain_d
Common/ProgramClass.cs:新增CMPLAIN
TsERP/App.xaml:CmplainViewModel DataTemplate
TsERP/Lang/Xaml1/Xaml.json:Cmplain區塊
TsERP/Lang/ClassAliasMap.json:Cmplain_m/dModel/Source 別名
刪除
無。
Breaking Changes
無。
Migration Notes / 未還原項目
- 報表 TODO:VFP 報表程式
CMPLAIN_P(SCX_ORDP) 尚未移植。
- 無審核三欄(cmplain_m 無 已審核/審核人員/審核日期)→ 不掛集中式審核。
- VFP
STR(公司代碼,1)公司代碼 >9 時會變*;新版取字串第 1 碼(公司代碼為 C101 單碼代碼,實務上等價)。
- runtime 未驗(瀏覽 view
vwbd_cmplain/DARB_BD_CMPLAIN為 server 端既有設定,未改動)。
-
06-12 claim-port ▸
2026-06-12 索賠單(CLAIM)移植
摘要
依 VFP 舊版
scx_ord.vcx / claim完整移植「索賠單」(選單 E-180,保固卡索賠)到 TsERP V2。Master+Detail 單據(主表
claim_m、子表claim_d,viewvw_claim_m/vw_claim_d),編號依
_sheetno(單據別 CLAIM、前置碼 T、編碼方式 4、srno 長度 4)。⚠️ 與既有「應收扣款 ARCLAIM(Arclaim)」是不同功能,勿混。
新增
Common\Model\E.Order\Vw_claim_mModel.cs/Vw_claim_dModel.cs
Model\Source\E.Order\Vw_claim_mSource.cs/Vw_claim_dSource.cs— view 顯示欄位 品名/客戶簡稱/廠商簡稱 僅存 Source 不上傳
ViewModel\E.Order\ClaimViewModel.cs—ErpProgramWithDetailViewModel+ IMoveRecord + IWeakEventListener(sum加總)
LogicBll\Ade\E.Order\ClaimSave.cs— 反射命名LogicBll.Ade.ClaimSave
TsERP\E.Order\Claim.xaml(.cs)— TsView + TsRadGridView 明細
Common\Lang\Xaml\Claim.json+TsERP\Lang\Xaml1\Xaml.json併入 Claim 區段
TsControl\Themes\TsTextBoxGeneric.xaml:新增RepairNoSearch樣式(repair.叫修單號);保固卡號用同批新增的ProductSerialNoSearch
登錄點
TsERP\Lang\TableMap.json:"claim_m": "vw_claim_m"、"claim_d": "vw_claim_d"
Model\LocalDbContext.cs:DbSet<Vw_claim_mSource> Claim_m、DbSet<Vw_claim_dSource> Claim_d
Common\ProgramClass.cs:CLAIM(原本不存在,本次新增)
TsERP\App.xaml:ClaimViewModel → ClaimDataTemplate
TsERP\Lang\ClassAliasMap.json:Vw_claim_m/Vw_claim_dModel+Source
Common\Common.csproj:Lang\Xaml\Claim.jsonContent
VFP 行為對照
VFP 新版 allowsave:客戶代號/公司代碼(=0)/登入日期空白擋存ClaimSave.AllowSaveallowsave:REPLACE 增刪修 WITH 'D' FOR EMPTY(品號)ClaimSave(AllowSave + HandleDataBeforeEndEdit)+Vw_claim_dSource.NeedDeleteFunction保固卡號.LostFocus:查 invent1 帶 客戶代號/品號/機器序號/datecode/購買日期(值不同才回填、查無不提示)保固卡號Binding → SetWarrantyData()(DARB_GETDATA4 invent1)叫修單號.LostFocus:查 repair(客反應主檔) 帶 保固卡號/客戶代號/品號/機器序號/檢修日期/處理情形叫修單號Binding → SetRepairData()(DARB_GETDATA4 repair)sqlnm_sp1.代號.LostFocus:查 spdata 帶幣別廠商代號Binding → SetVendorData()(廠商簡稱 + DARB_GETDATA4 spdata 幣別)客戶代號(sqlnm_cu)帶簡稱客戶代號Binding → DescriptionHelper.GetCustomerName(view 欄 客戶簡稱)品號(sql_mno dovalid=1,主檔與 grid 明細)帶品名、查無提示主檔/明細 品號Binding → SetSku*()(查無品號 !!!)sum加總:總計 = Σ(明細 數量*單價,排除 D 列與空白品號) + 工資;grid1.Refresh 觸發ClaimViewModel.SumTotal():AfterMoverRecord+ 工資/數量/單價/品號 ListenerHelper 即時重算(NotMapped總計)grid col金額:ROUND(數量*單價,2)計算欄Vw_claim_dSource.金額NotMapped 計算屬性(數量/單價 set 連動刷新)保固卡號.is_exist="invent1.保固卡號"/叫修單號.is_exist="repair.叫修單號"ProductSerialNoSearch/RepairNoSearchTsSearchTextBox 樣式(F2 查詢)公司代碼 sqlcombotxt c_type=101 TsComboBoxWithDescriptionBySql TableAlias="C101"幣別 sqlcombo c_type=1 TsCurrency(僅幣別,claim_m 無匯率欄)城市國家/機器序號/DATECODE/品名 ReadOnly 顯示 唯讀 TsTextBox(品名為 view U_SEEKNM 對應欄) 無審核三欄 不掛集中式審核 SP 依賴:僅
DARB_GETDATA4(已登錄),無需新 SP。與 VFP 的刻意差異
- VFP
datecode文字框 ControlSource 誤綁索賠單主檔_V.機器序號(複製貼上 bug,
與
叫修單號.LostFocus寫回DATECODE欄位的程式互相矛盾)。新版 DATE CODE 欄位綁定正確的
datecode欄。未還原項目
- 報表
CLAIM_P(SCX_ORDP)— TODO(VM 註解)
moverec_sk_cursor(SK_CUDATA/SK_SPDATA/SK_INVENT 快取游標)— 新版 view JOIN 取代,不需要
Runtime 未驗
全部畫面/存檔/連動流程僅 build 驗證,未實機開窗測試。
-
06-11 scx-qry-batch-port ▸
2026-06-11 — 主管資訊(EIS)查詢 11 支批次移植完工
摘要
VFP
scx_qry查詢報表庫缺口一次補完:9 支整支新移植 + 2 支半成品完工,主管資訊選單(M 模組)與 H-11/J-05 全部查詢程式自此可在新版開啟。新增
選單 程式 內容 M-03 交期回覆統計(RB_RATIO) 明細 18 欄 + 底部合計(訂單/OK/NG 筆數、回覆即時率%);工時計算 set-based M-04 最近進價與售價(PX_QRY) 售價/進價兩頁,最近+最高+最低三組價格合併一列 M-06 流動狀況表(INV_QRY4) 不分儲位/分儲位兩頁,滯庫天數篩選 M-08 呆料查詢(NOUSE) 期初有庫存且期間交易量低於百分比門檻;查詢後可再按倉庫/說明篩選 M-10 標準成本與進貨比較(CHKRA) 比較單價一頁 M-11 集團資料查詢(CUQRY) 報價/訂單/出貨/待收帳款/授信額度 5 頁(各含子公司+明細) M-15 訂單存貨計劃(ORD_QRY4) 訂單存貨 61 天 + 材料用量 91 天動態日欄、安全庫存連動列 M-17 庫齡呆料分析(STOCKLIFE) 庫齡分析/庫齡明細/呆料分析/交叉分析 4 頁 H-11 例外出入庫查詢(EXCE_INOUT) 例外出入明細 + 組立價/銷售價推估 變更(半成品完工)
- M-18 客戶延納統計(ORD_QRY3)、J-05 廠商延納統計(PUR_QRY3):原中文 ViewModel 是選單反射找不到的孤兒殼,重建為
Ord_qry3ViewModel/Pur_qry3ViewModel並修正對比發現的錯誤(延納率除零、急單參數誤用採購值、延交件數判定不完整、grid binding typo「訂購日期」、月報表捨入位數等共 19 項)。
- 與 VFP 行為的刻意差異(修正 VFP 原生 bug):CUQRY 未轉帳出貨補客戶條件(原版每子公司重複累加全公司出貨)、RB_RATIO 接通「回覆交期」欄(原版欄名錯位永遠空白)、NOUSE 最近購價改取真正最近一筆(原版 per 廠商多列重複)。
刪除
ViewModel/M.EIS/客戶延納統計ViewModel.cs、廠商延納統計ViewModel.cs(孤兒殼)及廠商延納統計三個全註解 Source。
Breaking Changes
無(全部是新增入口;既有程式無行為變更)。
Migration Notes
- 新 SP ×9 需在目標公司資料庫部署:
sql/TWORK_QRY_{INV_QRY4,CHKRA,EXCE_INOUT,RB_RATIO,NOUSE,PX_QRY,CUQRY,ORD_QRY4,STOCKLIFE}_darbnogicsa1.sql,並執行各檔尾darbnogilog1.proc_param登錄(漏登錄會靜默查無資料)。本機 darbnogicsa1 已全數部署+登錄。
- 列印(.frx)鈕未移植(多為 Excel 匯出,grid 內建匯出取代);ORD_QRY3 沿用既有三支 .frx。
- 不在本公司選單的 9 支 scx_qry class 刻意不移植,詳見 ADR-0034。
- M-18 客戶延納統計(ORD_QRY3)、J-05 廠商延納統計(PUR_QRY3):原中文 ViewModel 是選單反射找不到的孤兒殼,重建為
-
06-11 rp-per-form-sqlite-staging ▸
rp 系表單本機 staging 表隔離(修復交錯編輯存檔失敗)
日期:2026-06-11
相關 ADR:0033-rp-per-form-sqlite-staging
摘要
付款單(paymnt)、收款單(receive)、費用申請(payapply_kc)、預付(prepaid)、
其他應收付(otherrp)、零用金(ftrlima)六支表單原本共用同一張本機 SQLite
staging 表。交錯操作(A 表單載單 → B 表單載單 → 回 A 表單編輯存檔)會把 A 的
本機列清掉,造成存檔失敗(DbUpdateConcurrencyException)或改動靜默漏存。
本次讓每支表單使用自己的本機 staging 表,互不干擾。
變更
- 六支表單的本機 SQLite staging 各自獨立(PaymntRp_m/d、ReceiveRp_m/d、
Payapply_kcRp_m/d、PrepaidRp_m、OtherrpRp_m、FtrlimaRp_m/d)。
- navigate 寫入本機的表名改走
ItemsBindingManager.GetLocalTablesName()映射;
server 端上傳表名(rp_m / rp_d)完全不變。
- 舊共用表
Rp_m/Rp_d降級為轉單 BLL(Ftrlima_4/5)scratch 區。
使用者可見影響
- 修復:兩支以上 rp 表單交錯編輯時存檔報「資料庫並行例外」或存檔後改動消失。
- 無 UI / 欄位 / 流程變動;無資料 migration(本機 staging 每次登入重建)。
Breaking Changes
無(server 端資料與 API 不變)。
已知殘餘限制
- 同一支表單在兩個容器同時編輯仍共用同一張 staging 表。
- 若兩個程式代號共用同一 ViewModel 類(疑似 ARALLOWANCE↔RECEIVE、
PAYAPPLY_ZD↔PAYAPPLY_KC),該兩支程式之間仍共表。
-
06-11 prodplan-shortage-cashflow-simulation ▸
生產計劃查詢:庫存缺口/金流預測/模擬插單/樞紐分析
日期:2026-06-11
模組:M.EIS 生產計劃查詢 (pd_qry7)
摘要
生產計劃查詢從三個結果頁籤擴充為七個,新增庫存缺口判斷、金流預測圖表、
what-if 模擬插單與樞紐分析,成為查詢+決策模擬一體的功能。
新增
- 庫存缺口 頁籤:每筆需求(成品=生產計畫、材料=使用量)對「現有庫存+在途採購」
滾動計算可用量、缺口量、最早短缺日;缺口列紅底標示
- 樞紐分析 頁籤:訂單預示預估的 RadPivotGrid 樞紐視角,預設 客戶×品號 對 年度×月份
的 Σ金額/Σ數量,右側欄位清單可拖拉重組
- 金流預測 頁籤:上半月份圖表(應收正向柱/應付負向柱堆疊+累計淨額折線+零軸線
+資金警戒紅線),下半金流明細。四層來源:未兌票據/未沖帳款/在途採購/計劃預測,
各帶可信度(高/中/低)供判讀
- 模擬插單 頁籤:插入假想訂單(品號/數量/交期/客戶,單價空白自動帶客戶報價)→
「套用模擬」自動展 BOM 連動缺口與金流,圖表並排顯示基準/模擬雙組對比,
摘要顯示短缺品號數與累計淨額最低點變化;「清除模擬」即還原。模擬不寫入任何資料庫
- 條件面板新增:帳款立帳起日(金流預測未沖帳款的回溯範圍,預設近一年)、
資金警戒線(金流圖表紅線)
變更
- 條件面板步驟③說明文字更新(列出新頁籤)
刪除
無
Breaking Changes
無(既有三個頁籤行為不變)
Migration Notes
- 需在資料庫執行
sql\TWORK_QRY_PRODPLAN_EXT_darbnogicsa1.sql(兩支新 SP+
darbnogilog1.proc_param 登錄;proc_param 沒登錄查詢會靜默回空)
- 金流「帳款」層的 R/P/A 分類與票貼/質押票據口徑,建議上線後拿票據查詢/帳齡報表對數確認
-
06-11 ftrlima-turn-sliy-date-range ▸
Ftrlima 轉傳票改用立帳日期區間查詢
日期:2026-06-11
模組:總帳 / 財務單轉傳票(SliyTurn — Ftrlima 分頁)
摘要
財務單轉傳票(ftrlima → SLIY 傳票)的查詢條件,從「立帳日期 = 單一日期」改為「立帳日期 起迄區間」,
與既有的應付(Ap)、應收(Ar)轉傳票一致。產生的每張傳票各自採用其來源財務單的立帳日期當傳票日期。
變更
- 查詢條件:
立帳日期 = '{日期}'→立帳日期 BETWEEN '{起}' AND '{迄}'。
- 查詢畫面(SliyTurn 的 Ftrlima 分頁):單一日期欄位 → 起迄兩個日期欄位(
起 ~ 迄),版面對齊 Ap 分頁。
- 傳票日期語意:原本整批傳票都記在使用者輸入的單一日期;現在每張傳票用來源財務單自己的立帳日期
(
Twork_acc_vw_sliymSource.傳票日期 = 來源.立帳日期),與 Ap/Ar 行為一致。零用金(FJ)摘要內的日期也跟著改用來源立帳日期。- 預設區間:起日 = 今天 −7 天、迄日 = 今天(對齊 Ap 分頁預設)。
Breaking Changes
- 轉出的傳票日期不再是「轉檔當下選的那一天」,而是各來源財務單的立帳日期;跨多天的財務單會產生多個不同日期的傳票。
Migration Notes
- 純功能調整,無資料庫 schema 變更。
- 後端 stored proc
DARB_TUR_SLIY_FTRLIMA沿用既有機制(查詢條件以字串注入 WHERE、lp_1傳區間起日),
與
DARB_TUR_SLIY_AP/DARB_TUR_SLIY_AR同款做法(那兩支早已是區間查詢)。上線後仍請實機驗證:起迄區間有正確篩選、各傳票日期 = 來源立帳日期、鎖定清單(LockedSource)與筆數正常。
- 查詢條件:
-
06-11 ftrlima-turn-sliy-account-fixes ▸
ftrlima 轉傳票:票據兌現/電付兌現 科目代號與借貸修正
日期:2026-06-11
範圍:
LogicBll/Other/SliyTurn/Ftrlima/FtrlimaQueryHandle.cs(查詢產生傳票預覽,不影響已存傳票)摘要
runtime 驗收發現付票兌現(BE)/電付兌現(BL)傳票的銀行列科目代號空白。
與 VFP
sliyturn.scx逐段對照後修正四處移植錯誤。根因:FI(付兌提出)的帳戶代號依 LCL交易別設定(轉出部門=B)寫在
轉出倉儲,C# 誤讀轉入倉儲;VFP 的 SEEK 是補空白比對所以舊版容錯,C# 字典是精確比對,key 拿錯直接空值。
修正
- BE 付票兌現:FI 貸方列科目代號改查
轉出倉儲(原誤讀轉入倉儲,永遠空白)。
- BL 電付兌現:
- FI 貸方列分組鍵與科目查找改用
轉出倉儲,且改取銀行科目(原誤取帳戶代號,填進去的不是總帳科目)。
- FI 列金額由借方欄位改放貸方欄位(原本借貸全在借方,傳票不平衡)。
- 序號補遞增(原本全部列都是 000)。
- CU 借方摘要尾端改去除逗號(對齊 VFP,原誤寫成去除句點)。
同日追加:客廠代號補帶入
- B4 收票兌現:CE 貸方(應收票據)列補帶來源明細的
客廠代號。
- BE 付票兌現:CR 借方(應付票據)列補帶來源明細的
客廠代號。
- 依 VFP
SCAT MEMV語意:這兩種列的m.客廠代號=''在 VFP 被註解
(CE 處註記「要客廠代號」),即保留來源值;C# 物件初始化漏設導致空白。
- 其餘列(銀行借方/FI 貸方/匯差)VFP 主動清空,C# 行為一致,不變。
不受影響
- B4 收票兌現與 FJ 零用金撥補路徑與 VFP 對照一致,未改動。
- server 端資料、已轉出的傳票不受影響;此為查詢預覽階段的產生邏輯。
- BE 付票兌現:FI 貸方列科目代號改查
-
06-11 eisdash-dashboard ▸
2026-06-11 主管儀表板(EISDASH)
摘要
新增「主管儀表板」頁面(M.主管資訊選單 M-21):一頁看全公司——8 張 KPI 卡片、4 張互動圖表、2 張警示清單,支援日期快切、自動刷新、點擊直達既有查詢頁。
新增
- KPI 卡片列(8 張,含迷你趨勢線與紅色警示副標):本期受訂、本期出貨、未交訂單(逾期金額)、應收帳款(90天+)、應付帳款(90天+)、庫存金額(呆滯占比)、客戶延納率(當月)、廠商延納率。
- 圖表區(2×2):受訂/出貨趨勢(面積+折線雙序列)、銀行結餘趨勢(含票據預估)、應收帳齡分佈(環圈圖,中央顯示總額)、廠商延納率 Top 10(長條圖)。
- 警示清單:客戶逾期未交 Top 10、呆料金額 Top 10。
- 日期快切:本月 / 本季 / 本年 / 自訂區間 segmented 按鈕,切換即重查。
- 自動刷新:預設每 5 分鐘(可在條件面板調整分鐘數或關閉;切到其他頁面時不會打資料庫)。
- Drill-down:點 KPI 卡片、圖表或「明細 →」直接導航到對應查詢頁(客戶查詢/應收帳齡/應付帳齡/庫齡呆料分析/客戶延納統計/廠商延納統計/銀行流水/呆料查詢)並自動帶入日期條件查詢,上一頁按鈕可回儀表板。
- 單一 KPI 讀取失敗只影響該卡片(顯示「讀取失敗」紅字,滑鼠停留看錯誤訊息),其餘區塊照常顯示。
- 新 SP:
TWORK_QRY_DASH_SALES(受訂/出貨趨勢+合計)、TWORK_QRY_DASH_INVSUM(庫存總額+呆滯+呆料Top)、TWORK_QRY_DASH_BACKLOG(未交/逾期+客戶逾期Top)。
變更
- 無既有功能行為變更(純新增頁面;共用檔僅加註冊行)。
刪除
- 無。
Breaking Changes
- 無。
Migration Notes
部署到其他資料庫環境需三段(漏任何一段該區塊會顯示讀取失敗或選單不出現):
1. darbnogicsa1:執行
sql/TWORK_QRY_DASH_{SALES,INVSUM,BACKLOG}_darbnogicsa1.sql的 CREATE。2. darbnogilog1:執行各檔尾 proc_param 登錄 block。
3. 選單:
EXEC dbo.usp_新增程式 @程式代號=N'EISDASH', @程式名稱=N'主管儀表板', @序號='M-21', @按鈕名稱=N'M.主管資訊', @建立單號=0。本機(localhost)三段已完成。
已知限制(二期候選)
- 品質 KPI(不良率/達成率)未納入第一版(見 ADR-0036)。
- 受訂/出貨/未交的 drill-down 導到客戶查詢頁但不自動查詢(該頁需指定客戶)。
- 客戶延納率取「截止日期當月」單月資料(沿用 ORD_QRY3 SP 的年度月份參數設計)。
-
06-10 scx-pur-pending-fixes ▸
2026-06-10 — 採購模組(scx_pur)對比待修清單收尾
摘要
接續 VFP
scx_pur.vcx對比後留下的待修清單,本次處理三項:1. spdata(廠商資料)存檔驗證補回:VFP
allowsave的「廠商代號必填(且不得為+++)」「幣別必填」兩道驗證在新版被註解掉(且註解內引用已改名的英文屬性VendorCode),本次依 VFP 原邏輯補回;另補「聯絡人空姓名列存檔時自動設刪除」(VFPREPLACE 增刪修 WITH 'D' FOR EMPTY(姓名))。2. purch(採購單)補回「確認」按鈕:VFP
else7click(瀏覽狀態下進編輯 → 主檔「確認」欄蓋目前使用者帳號 → 立即存檔)在新版未接線。PurchViewModel新增IOther4/ExtendedFunction4()實作同流程,存檔失敗自動取消編輯。寫法比照OrmastViewModel.ExtendedFunction3(審核章)。3. Ppurch_c(取消採購/批次結案)上傳表名修正:
UploadTableNames原寫請購表ppurma/ppurde,但實際結案寫回的是採購單purchm(SetUpdateSource建Twork_pur_vw_purchmSource、UploadPrgClass=PURCH),屬 copy-paste 殘留;已改為Purchm/Twork_pur_vw_purch,對齊姊妹類PptopuBll。新增
PurchViewModel:IOther4+ExtendedFunction4()(確認章)。按鈕標題由程式參數/權限(資料端)控制。
變更
SpdataSave.AllowSave:廠商代號(空或+++)、幣別為空時擋存檔,訊息用多語系欄位名(ProgramClass.SPDATA)。
SpdataSave.HandleDataBeforeEndEdit:聯絡人(廠商資料表_1)姓名為空的列設增刪修='D'。
Ppurch_cBll.UploadTableNames:Ppurma/Ppurde→Purchm/Twork_pur_vw_purch。
刪除
- 無。
Breaking Changes
- spdata 原本可存「無廠商代號 / 無幣別」的廠商資料,現在會被擋下(回到 VFP 行為)。既有缺幣別的舊資料下次編輯存檔時需補上幣別。
Migration Notes
- purch「確認」按鈕的顯示/標題由資料端程式權限參數控制,若按鈕未出現請確認 DB 端 PURCH 的其他功能 4 已設定。
備註
- 建置:LogicBll、ViewModel 以 VS MSBuild 建置通過(僅既有警告)。
- scx_pur 殘餘待辦(皆屬功能新建,未動):PPUR_SUG(請購建議→請購單)、purch 修改交期(
_CHANGEDATE)、進貨查詢(PURCH_S);OrmastToPP 轉訂單待 runtime 驗證。
-
06-10 ppur-sug ▸
2026-06-10 — 新增「請購建議表」(PPUR_SUG,VFP 移植)
摘要
移植 VFP
ppur_sug(請購建議表,2149 行)為新版獨立選單程式PPUR_SUG。依需求月份統計 12 期出貨量,套用 VFP 公式推算建議請購量,並把建議量 > 0 的列轉成一張請購單(ppurma/ppurde)。計算公式(忠實 VFP):
- 平均銷貨數 = ROUND(前六月出貨總計 / 6, 0)
- 需求量 = 平均銷貨數 / 30 × Leadtime − 預計可用量(目前可用量+在途量+採購未交量)
- 最低請購量 = MAX(需求量, 最小採購量);建議請購量依內箱包裝數進位
新增
LogicBll/G.Purchasing/Ppur_sug/Ppur_sugBll.cs:查詢(族群/品號/廠商三模式,接TWORK_QRY_PPUR_SUG)、AllowSave 驗證(防重複轉單、預訂交期/倉儲必填、無需求擋存)、SetUpdateSource(單一主檔+建議量>0 明細、報價階梯選價、外幣U_Blrate帶率)、計算金額(2)(含稅 4 欄+尾差調整,純靜態可單測)。
Model/SQLProcedure/Twork_Qry_Ppur_Sug/PpurSugCalculator.cs:相對期別、出貨累加、需求量/建議量演算法、報價階梯選價(靜態純函式)。
ViewModel/G.Purchasing/Ppur_sugViewModel.cs:查詢條件、雙 grid(26 欄主表+C1~C12 月份表)、二次篩選(低於安全庫存/僅需請購)、轉單後鎖查詢。
TsERP/G.Purchasing/Ppur_sug.xaml(.cs):TsView+TsRadGridView;code-behind 依查詢結果把 C1~C12 欄標題換成實際月份(比照Preord.xaml.cs)。
Common/Lang/Xaml/Ppur_sug.json+TsERP/Lang/Xaml1/Xaml.json增Ppur_sug區段(12 個介面文字 key)。
Common/ProgramClass.cs:新增PPUR_SUG;TsERP/App.xaml:新增Ppur_sugViewModel → Ppur_sugDataTemplate。
變更
Twork_Qry_Ppur_SugBll(與 E.Order Preord 共用的查詢引擎):
-
Query()第二參數改傳呼叫端ProgramClass(成本遮罩權限改動態);- 最近進貨/出貨日改
GroupBy().First()取最近一筆(原ToDictionary同品號多列會丟例外);- 演算法搬到
PpurSugCalculator共用。Twork_Qry_Ppur_SugDemandPoco:修正季平均運算優先級 bug(C1+C2+C3/3→(C1+C2+C3)/3)、平均數改MidpointRounding.AwayFromZero、改以相對期別累加。
PreordControlViewModel(E.Order):配合查詢引擎簽名改動;月份欄改新→舊排序、起始月改 -11 月(C1~C12 共 12 期,對齊 VFP)。
刪除
- 無。
Breaking Changes
- 無(Preord 月份欄順序改為新→舊,屬顯示順序對齊 VFP,資料不變)。
Migration Notes
- 新程式為獨立選單程式(VFP 是 ppurch else6 按鈕開啟):DB 選單需新增
PPUR_SUG項目才能進入(同PPURCH_C模式,靠ProgramClass反射啟動)。
- 第一期排除(後續再補):月份欄右鍵出貨明細(VFP
PPUR_SUS)、Excel 匯出/列印。
備註
- 建置:TsERP(含 Common/Model/LogicBll/ViewModel)VS MSBuild 通過,僅既有警告。
- 待 runtime 驗證:查詢三模式、轉請購單上傳、轉單後 Ppurch 開啟確認。
-
06-10 hyperlink-underline-mingliu ▸
2026-06-10 — 超連結欄位底線修復(新細明體 × Display 模式)
摘要
全系統超連結欄位(
TsTextBox設IsHyperLink="True",如傳票號碼、出納/沖帳傳票號、單號連結)長期只有藍字、沒有底線。根因:WPF 的TextOptions.TextFormattingMode="Display"配上系統字型新細明體(MingLiU)時不會渲染TextDecorations底線(TextBlock/TextBox 皆然,指定 Pen 或 PenOffset 都無效)。變更
TsControl/Themes/TsTextBoxGeneric.xaml、TsControl/Themes/V2Generic.xaml(兩處):IsHyperLink=Truetrigger 內加TextOptions.TextFormattingMode="Ideal"——僅超連結欄位切回 Ideal 文字模式,底線恢復顯示;其他欄位維持 Display 模式的點陣銳利渲染。
使用者可見影響
- 超連結欄位現在會顯示藍字+底線(之前只有藍字)。
- 超連結欄位的字體渲染從點陣銳利改為平滑(Ideal 模式),與相鄰欄位略有差異,屬預期取捨。
Migration Notes
- 無需資料或設定變更。若未來全域字型改為微軟正黑體等向量字型,此 workaround 可移除(Display 模式配向量字型可正常畫底線)。
-
06-10 document-json-transfer ▸
2026-06-10 單據匯出/匯入(JSON 交換檔)
摘要
主視窗「目前表單功能」選單新增「匯出單據」與「匯入單據」:可把當前開啟的單據
(主檔+明細)存成
*.tsdoc.json交換檔,拿到另一個資料庫環境的同一支表單匯入成新單據。新增
- 選單「(表單名)功能」→「匯出單據」:非編輯狀態下,把目前單據存成 JSON 交換檔,
預設檔名為
表單類別_單號.tsdoc.json- 選單「(表單名)功能」→「匯入單據」:選擇交換檔後自動進入新增狀態並帶入資料,
使用者檢查內容後按「儲存」完成匯入
- 匯入時自動重新編號(單號不沿用),審核狀態、建檔人員/日期、權限表設定的不複製欄位
一律清空重產,規則與「複製」按鈕一致
變更
- 選單「編輯本表單參數」下方新增分隔線與上述兩個項目
刪除
無
Breaking Changes
無
Migration Notes
- 僅支援走新式資料管理(ItemsBindingManager)的單據表單;舊式表單點選時會提示「此表單不支援」
- 交換檔屬於哪支表單會記錄在檔內,匯入到不同表單會被拒絕
- 目的資料庫若缺少交換檔引用的基本資料(廠商、品號等),儲存時會由既有驗證擋下,
需先補齊基本資料再匯入
-
06-09 progressbar-content-window-sizing-and-flow ▸
2026-06-09 — 進度條彈窗:自動縮放視窗 + 邊顯示邊做事
摘要
修正 ContentWindow 系列彈窗在
IsSizeToContent時仍被撐到主視窗大小、不會縮成內容大小的問題;並把工作流程 PDF 產生的進度條流程,從「開窗 → 等使用者關掉 → 才開始做事」改成正確的「開窗 → 進度條持續轉動、PDF 同時產生 → 做完視窗自動關閉」。對使用者而言,產 PDF 時會看到一個剛好包住進度條、置中在主視窗上的小視窗,期間進度條動畫表示「處理中」,完成即自動消失。新增
IContentWindowLoadedAsync(Common/Context/IContentWindowLoadedAsync.cs):通用 hook 介面。ContentWindow 的內容 VM 實作後,視窗 Loaded 會自動await OnContentWindowLoadedAsync()一次。用於「開窗即做事、做完自動關窗」情境,不綁死 ProgressBar,日後其他彈窗可共用。
ProgressBarViewModel.WorkAsync(ViewModel/ProgressBarViewModel.cs):Func<Task>屬性。指派後,視窗顯示期間執行該工作,finally中設ContentWindowViewModel.DialogResult = true自動關窗(含例外也會關)。未指派時維持原本由呼叫端/使用者關閉的行為。
變更
- ContentWindow / NoBorderContentWindow 尺寸邏輯(
TsERP/Other/ContentWindow.xaml.cs、TsERP/Other/NoBorderContentWindow.xaml.cs):IsSizeToContent為true時只設SizeToContent = true、不再指派顯式Width/Height(保持NaN,讓 RadWindow 量測內容自行縮放);否則才套用原本算好的寬高。非 SizeToContent 的彈窗行為不變。
ContentWindow.Window_Loaded(TsERP/Other/ContentWindow.xaml.cs):改為async,並保存內容 VM 參考;視窗顯示後若該 VM 實作IContentWindowLoadedAsync即 await 其工作。
WorkflowPDFHelper.CreatePdfAndShowProgressBar(ViewModel/Other/TodoList/WorkflowPDFHelper.cs):改用ProgressBarViewModel.WorkAsync = () => CreatePdf(...),工作在視窗顯示期間執行;結果以區域變數outcome帶出,失敗才TsMsgBox.ShowError。簽章由async Task改為Task(方法本體已無await,回傳Task.CompletedTask),呼叫端await不受影響。
Breaking Changes
- 無。對外 API(
CreatePdfAndShowProgressBar回傳Task、ShowContentWindow介面)不變。
Migration Notes
- 無需資料或設定異動。
- 既有以舊流程依賴「先關窗才產 PDF」的隱性行為已不存在——原流程實際上需 DialogResult 為 true 才會產 PDF,而進度視窗並無設 true 再關的路徑,屬於原本就可疑的時序;新流程確保 PDF 一定在顯示期間產生。
備註
- 運作原理:
ShowDialog()是模態阻塞,但跑的是巢狀 Dispatcher 訊息迴圈,await CreatePdf的 continuation 仍會回到 UI 執行緒執行,進度條動畫照常;工作完成才設DialogResult關窗,ShowContentWindow才返回,此時outcome已是最終結果。
- 重點:
Telerik RadWindow.SizeToContent型別是bool(非 WPF 原生SizeToContentenum),原程式賦值本身正確,問題在於先設了顯式Width/Height蓋掉縮放。
- 建置:
TsERP(含Common/ViewModel/TsControl)以 VS MSBuild 建置通過。UnitTest1既有 target framework 不符錯誤與本次變更無關。
-
06-09 perdata-signature-view-col ▸
2026-06-09 — vwseek_perdata 加「簽名圖檔1」欄
摘要
員工資料查詢 view
vwseek_perdata補上簽名圖檔1欄,供簽核 / 報表帶出員工簽名圖檔。DBA 部署時執行下列 SQL。(同批
20260609.sql內另含vwlcl_rptdat加「單據別」欄,該段已記於 2026-06-09-db-sql-scripts-backfill,會自動上頁,故此處不重複收錄。)變更
vwseek_perdataview 欄位清單末端新增簽名圖檔1,並sp_refreshview。
Migration Notes
vwseek_perdata 員工查詢 view 加「簽名圖檔1」欄
> 來源:
20260609.sql。員工資料 viewvwseek_perdata補上簽名圖檔1欄並sp_refreshview,供簽核流程 / 報表取用員工簽名圖檔。ALTER VIEW [dbo].[vwseek_perdata] AS SELECT 員工編號, 姓名, 部門代號, email, 公司代碼, 身份證字號, 性別, 到職日期, 銀行帳號, 本國人, 員工別, 員工類別, 職稱, 職級, 簽名圖檔1 FROM dbo.perdata GO EXEC sp_refreshview 'vwseek_perdata'; GO -
06-09 db-sql-scripts-backfill ▸
2026-06-09 — 資料庫 SQL 腳本彙整(SQL 更新頁補錄)
摘要
將先前散落於
c:\temps\sqlscript但尚未進入「SQL 更新」頁的資料庫部署腳本補錄於此,使對外資訊網的 SQL 更新頁能完整顯示。每段為實際可執行的 SQL,DBA 部署時依序執行。(
更新票據系統.sql、alter.sql(procno/bom_m)已分別記於 2026-05-22-cheque-system-workflow-fields、2026-05-21-procno-bom-m-cols,會自動上頁,故此處不重複。)Migration Notes
vwlcl_rptdat 報表清單 view 加「單據別」欄
> 來源:
改變vwlcl_rptdat.sql。報表清單 viewvwlcl_rptdat補上單據別欄並sp_refreshview,供報表依單據別篩選。/*--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ ALTER VIEW [dbo].[vwlcl_rptdat] AS SELECT TOP (100) PERCENT 報表編號, 報表分類, 報表用途, 報表名稱, excel檔名, 語言版本, 報表尺寸, 排序, 報表抬頭, 報表位置, 國家區域, sqlite, 可顯示, 插件名稱, 是否為遠端, 註腳, 單據別 FROM dbo._rptdat ORDER BY 報表編號 GO EXEC sp_refreshview 'vwlcl_rptdat';rp_m / rp_d / rpsht 加欄位 + view 重建
> 來源:
更新rp_m.sql。應收/收款相關表rp_m/rp_d/rpsht_m/rpsht_d加建檔日期、原幣稅額、含稅欄位等,並重建對應 view。對應 changelog 2026-05-29-rp-m-schema-extend。ALTER TABLE rp_m add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE rp_m add [原幣稅額] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_m add [總原幣未稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_m add [總本幣未稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_m add [含稅別] [char](1) NOT NULL DEFAULT ''; ALTER TABLE rp_d add [原幣稅額] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [折扣] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [代工價含稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [其他金含稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [微調原含稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [微調本含稅] [decimal](19,4) NOT NULL DEFAULT 0; ALTER TABLE rp_d add [備註] [nvarchar](120) NOT NULL DEFAULT ''; ALTER TABLE rpsht_m add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE rpsht_d add [分類索引4] [nvarchar](30) NOT NULL DEFAULT ''; ALTER TABLE rpsht_d add [單別3] [char](2) NOT NULL DEFAULT ''; ALTER TABLE rpsht_d add [單號3] [nvarchar](20) NOT NULL DEFAULT ''; go ALTER VIEW [dbo].[vw_rpsht_m] AS SELECT dbo.rpsht_m.收付款單號, dbo.rpsht_m.收付款日期, dbo.rpsht_m.收付款別, dbo.rpsht_m.公司代碼, dbo.rpsht_m.客戶代號, dbo.vwseek_cudata.客戶簡稱, dbo.rpsht_m.廠商代號, dbo.vwseek_spdata.廠商簡稱, dbo.rpsht_m.業務員編號, dbo.vwseek_salesmen.姓名, dbo.rpsht_m.備註, dbo.rpsht_m.沖帳備註, dbo.rpsht_m.出納傳票號, dbo.rpsht_m.沖帳傳票號, dbo.rpsht_m.聯絡單id, dbo.rpsht_m.工作流程, dbo.rpsht_m.審核人員, dbo.rpsht_m.審核日期, dbo.rpsht_m.已審核, dbo.rpsht_m.輸入日期, dbo.rpsht_m.輸入人員, dbo.rpsht_m.輸入地點, dbo.rpsht_m.增刪修, dbo.rpsht_m.選擇, dbo.rpsht_m.管制碼, dbo.rpsht_m.srvdbid, dbo.rpsht_m.pkid, dbo.rpsht_m.logid, dbo.rpsht_m.linkid, dbo.rpsht_m.沖帳方式, dbo.rpsht_m.廠商代號1, dbo.rpsht_m.廠商代號2, dbo.rpsht_m.付款匯率日, ISNULL(dbo.vwseek_cudata.付款方式碼, 0) AS 客付方式碼, ISNULL(dbo.vwseek_cudata.付款方式, N'') AS 客付款方式, ISNULL(dbo.vwseek_cudata.收付條件號, N'') AS 客付條件號, ISNULL(dbo.vwseek_cudata.付款條件, N'') AS 客付款條件, dbo.rpsht_m.建檔日期 FROM dbo.rpsht_m LEFT OUTER JOIN dbo.vwseek_salesmen ON dbo.rpsht_m.業務員編號 = dbo.vwseek_salesmen.業務員編號 LEFT OUTER JOIN dbo.vwseek_spdata ON dbo.rpsht_m.廠商代號 = dbo.vwseek_spdata.廠商代號 LEFT OUTER JOIN dbo.vwseek_cudata ON dbo.rpsht_m.客戶代號 = dbo.vwseek_cudata.客戶代號 GO GO ALTER VIEW [dbo].[vw_rpsht_d] AS SELECT dbo.rpsht_d.序號, dbo.rpsht_d.科目代號, ISNULL(dbo.accl.科目名稱, N'') AS 科目名稱, dbo.rpsht_d.摘要, dbo.rpsht_d.客廠代號, dbo.rpsht_d.幣別, dbo.rpsht_d.匯率, dbo.rpsht_d.原借方金額, dbo.rpsht_d.原貸方金額, dbo.rpsht_d.本借方金額, dbo.rpsht_d.本貸方金額, dbo.rpsht_d.部門代號, dbo.rpsht_d.員工編號, dbo.rpsht_d.項目編號, dbo.rpsht_d.專案代號, dbo.rpsht_d.分類索引1, dbo.rpsht_d.分類索引2, dbo.rpsht_d.分類索引3, dbo.rpsht_d.單別1, dbo.rpsht_d.單號1, dbo.rpsht_d.單別2, dbo.rpsht_d.單號2, dbo.rpsht_d.財務單id, dbo.rpsht_d.財務明細id, dbo.rpsht_d.輸入日期, dbo.rpsht_d.輸入人員, dbo.rpsht_d.輸入地點, dbo.rpsht_d.增刪修, dbo.rpsht_d.選擇, dbo.rpsht_d.管制碼, dbo.rpsht_d.srvdbid, dbo.rpsht_d.pkid, dbo.rpsht_d.logid, dbo.rpsht_d.linkid, dbo.rpsht_d.產品群組, dbo.rpsht_d.品號, dbo.rpsht_d.到期日, dbo.rpsht_d.其他id, dbo.rpsht_d.收付款日, dbo.rpsht_d.帳戶代號, ISNULL(dbo.rp_m.單號, N'') AS 單號, ISNULL(dbo.rp_m.發票號碼, N'') AS 發票號碼, ISNULL(dbo.rp_m.備註, N'') AS 備註, dbo.rpsht_d.分類索引4, dbo.rpsht_d.單別3, dbo.rpsht_d.單號3 FROM dbo.rpsht_d LEFT OUTER JOIN dbo.rp_m ON dbo.rpsht_d.單號2 = dbo.rp_m.財務單號 LEFT OUTER JOIN dbo.accl ON dbo.rpsht_d.科目代號 = dbo.accl.科目代號 GO ALTER VIEW [dbo].[vw_rp_m] AS SELECT dbo.rp_m.公司代碼, dbo.rp_m.財務類別, dbo.rpdef.單據名稱, dbo.rp_m.財務單號, dbo.rp_m.收付款單號, dbo.rp_m.相關單號, dbo.rp_m.客廠部代號, dbo.rp_m.收付客廠號, dbo.rp_m.帳款期別, dbo.rp_m.立帳日期, dbo.rp_m.發票日期, dbo.rp_m.發票號碼, dbo.rp_m.回轉日期, dbo.rp_m.單號, dbo.rp_m.參考單號, dbo.rp_m.獎金日期, dbo.rp_m.業務員編號, dbo.rp_m.消費者, dbo.rp_m.原幣應收付, dbo.rp_m.本幣應收付, dbo.rp_m.稅額, dbo.rp_m.幣別, dbo.rp_m.匯率, dbo.rp_m.沖帳原幣, dbo.rp_m.沖帳本幣, dbo.rp_m.稅別, dbo.rp_m.發票抬頭, dbo.rp_m.統一編號, dbo.rp_m.發票金額, dbo.rp_m.收付條件號, dbo.vwseek_payterm.說明, dbo.rp_m.收付款日, dbo.rp_m.到期日, dbo.rp_m.傳票號碼, dbo.rp_m.進銷分類, dbo.rp_m.備註, dbo.rp_m.申請部門, dbo.rp_m.申請人, dbo.rp_m.使用人, dbo.rp_m.申請日期, dbo.rp_m.事由, dbo.rp_m.受款人, dbo.rp_m.付款方式碼, dbo.rp_m.審核人員, dbo.rp_m.審核日期, dbo.rp_m.其他方式, dbo.rp_m.單據張數, dbo.rp_m.月結廠商, dbo.rp_m.隨貨附發票, dbo.rp_m.轉入備註, dbo.rp_m.訂單編號, dbo.rp_m.訂金比率, dbo.rp_m.輸入日期, dbo.rp_m.輸入人員, dbo.rp_m.輸入地點, dbo.rp_m.增刪修, dbo.rp_m.選擇, dbo.rp_m.管制碼, dbo.rp_m.srvdbid, dbo.rp_m.pkid, dbo.rp_m.logid, dbo.rp_m.linkid, dbo.vwseek_salesmen.姓名, dbo.vwseek_taxtype.名稱, dbo.vwseek_dept.部門簡稱, dbo.vwseek_cusp.客廠部簡稱, vwseek_cusp_1.客廠部簡稱 AS 客廠簡稱1, dbo.rp_m.程式類別, dbo.rp_m.使用日期, dbo.rp_m.使用部門, dbo.rp_m.帳款起始日, dbo.rp_m.聯絡單id, dbo.rp_m.工作流程, dbo.rp_m.已審核, dbo.perdata.姓名 AS 申請人姓名, h.姓名 AS 使用人姓名, dbo.rp_m.數量合併, dbo.rp_m.傳票號碼1, dbo.rp_m.交易日期, dbo.rp_m.專案代號, dbo.rp_m.關係人, dbo.rp_m.群組代號, dbo.aproj.專案簡稱, dbo.rp_m.使用截止日, dbo.rp_m.折讓金額, dbo.rp_m.折讓稅額, dbo.rp_m.暫估原幣, dbo.rp_m.暫估本幣, dbo.rp_m.建檔日期, dbo.rp_m.原幣稅額, dbo.rp_m.總原幣未稅, dbo.rp_m.總本幣未稅, dbo.rp_m.含稅別 FROM dbo.rp_m INNER JOIN dbo.rpdef ON dbo.rp_m.財務類別 = dbo.rpdef.財務類別 LEFT OUTER JOIN dbo.aproj ON dbo.rp_m.專案代號 = dbo.aproj.專案代號 LEFT OUTER JOIN dbo.vwseek_cusp AS vwseek_cusp_1 ON dbo.rp_m.收付客廠號 = vwseek_cusp_1.客廠部代號 LEFT OUTER JOIN dbo.vwseek_cusp ON dbo.rp_m.客廠部代號 = dbo.vwseek_cusp.客廠部代號 LEFT OUTER JOIN dbo.vwseek_payterm ON dbo.rp_m.收付條件號 = dbo.vwseek_payterm.收付條件號 LEFT OUTER JOIN dbo.vwseek_salesmen ON dbo.rp_m.業務員編號 = dbo.vwseek_salesmen.業務員編號 LEFT OUTER JOIN dbo.vwseek_dept ON dbo.rp_m.申請部門 = dbo.vwseek_dept.部門代號 LEFT OUTER JOIN dbo.vwseek_taxtype ON dbo.rp_m.稅別 = dbo.vwseek_taxtype.稅別 LEFT OUTER JOIN dbo.perdata ON dbo.rp_m.申請人 = dbo.perdata.員工編號 LEFT OUTER JOIN dbo.perdata AS h ON dbo.rp_m.使用人 = h.員工編號 GO ALTER VIEW [dbo].[vw_rp_d] AS SELECT dbo.rp_d.序號, dbo.rp_d.期別調整, dbo.rp_d.單號pkid, dbo.rp_d.幣別, dbo.rp_d.匯率, dbo.rp_d.科目代號, dbo.rp_d.轉入倉儲, dbo.rp_d.轉出倉儲, dbo.rp_d.交易別碼, dbo.rp_d.品號, dbo.rp_d.品名, dbo.rp_d.客廠品號, dbo.rp_d.其他鍵, dbo.rp_d.數量, dbo.rp_d.單位, dbo.rp_d.單價, dbo.rp_d.代工單價, dbo.rp_d.其他金額, dbo.rp_d.原幣未稅, dbo.rp_d.原幣含稅, dbo.rp_d.本幣未稅, dbo.rp_d.本幣含稅, dbo.rp_d.沖帳原幣, dbo.rp_d.沖帳本幣, dbo.rp_d.單價別, dbo.rp_d.摘要, dbo.rp_d.客廠代號, dbo.rp_d.客廠名稱, dbo.rp_d.統一編號, dbo.rp_d.發票號碼, dbo.rp_d.發票日期, dbo.rp_d.稅別, dbo.rp_d.其他憑證, dbo.rp_d.稅額, dbo.rp_d.發票pkid, dbo.rp_d.輸入日期, dbo.rp_d.輸入人員, dbo.rp_d.輸入地點, dbo.rp_d.增刪修, dbo.rp_d.選擇, dbo.rp_d.管制碼, dbo.rp_d.srvdbid, dbo.rp_d.pkid, dbo.rp_d.logid, dbo.rp_d.linkid, dbo.accl.科目名稱, dbo.rp_d.單號, dbo.rp_d.交易記錄號, dbo.rp_d.需求部門, dbo.rp_d.收付款pkid, dbo.rp_d.產品群組, dbo.grpm.說明, dbo.grpm.分類1, dbo.grpm.分類2, dbo.grpm.分類3, dbo.rp_d.員工編號, dbo.rp_d.缺件說明, dbo.rp_d.缺件後補日, dbo.rp_d.缺件已補, dbo.rp_d.海關代徵號, dbo.rp_d.單據張數1, ISNULL(dbo.vwseek_dept.部門簡稱, N'') AS 部門簡稱, ISNULL(dbo.cusp.客廠部簡稱, N'') AS 客廠部簡稱, dbo.rp_d.含稅單價, dbo.rp_d.客廠訂單號, dbo.rp_d.日期1, dbo.rp_d.微調原幣, dbo.rp_d.微調本幣, dbo.rp_d.原幣稅額, dbo.rp_d.折扣, dbo.rp_d.代工價含稅, dbo.rp_d.其他金含稅, dbo.rp_d.微調原含稅, dbo.rp_d.微調本含稅, dbo.rp_d.備註 FROM dbo.rp_d LEFT OUTER JOIN dbo.cusp ON dbo.rp_d.客廠代號 = dbo.cusp.客廠部代號 LEFT OUTER JOIN dbo.accl ON dbo.rp_d.科目代號 = dbo.accl.科目代號 LEFT OUTER JOIN dbo.grpm ON dbo.rp_d.產品群組 = dbo.grpm.群組代號 LEFT OUTER JOIN dbo.vwseek_dept ON dbo.rp_d.需求部門 = dbo.vwseek_dept.部門代號 GO EXEC sp_refreshview N'dbo.vw_rp_m'; EXEC sp_refreshview N'dbo.vw_rp_d'; EXEC sp_refreshview N'dbo.vw_rpsht_m'; EXEC sp_refreshview N'dbo.vw_rpsht_d';datatpld 任職經歷範本資料 (CMSA 專屬)
> 來源:
adddatapl.sql。datatpld寫入「任職經歷」P1_4_B 範本欄位定義(客戶 CMSA 專屬資料種子)。INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'1 ', N'原任職公司 ', N'C', 30, 0, N'服務機關名稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 1, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'2 ', N'原部門 ', N'C', 30, 0, N'部門/職稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 2, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'3 ', N'原任職日期 ', N'C', 10, 0, N'到職日', N'9999/99/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2019-04-18T17:18:41.633' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 3, 215195, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'4 ', N'原離職日期 ', N'C', 10, 0, N'離職日', N'9999/99/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2019-04-18T17:18:41.633' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 4, 215195, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'5 ', N'原待遇 ', N'N', 18, 6, N'薪資(月)', N'999,999,999', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 5, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'6 ', N'原工作內容 ', N'C', 80, 0, N'主要工作', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 6, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'7 ', N'原離職原因 ', N'C', 80, 0, N'離職原因', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 7, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'8 ', N'學校名稱 ', N'C', 30, 0, N'學校名稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 8, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'9 ', N'院系科別 ', N'C', 30, 0, N'院系科別', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 9, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'10 ', N'修業年月起 ', N'C', 7, 0, N'修業起始年月', N'9999/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 10, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'11 ', N'修業年月迄 ', N'C', 7, 0, N'修業結束年月', N'9999/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 11, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'12 ', N'是否畢業 ', N'C', 1, 0, N'畢/肄', N'Y', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 12, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'13 ', N'學位 ', N'C', 30, 0, N'學位', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 13, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'14 ', N'眷屬稱謂 ', N'C', 10, 0, N'稱謂', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 14, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'15 ', N'眷屬姓名 ', N'C', 10, 0, N'姓名', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 15, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'16 ', N'眷屬出生 ', N'C', 10, 0, N'出生日期', N'9999/99/99', N'CHKDATE', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-09T00:04:00.727' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 16, 64740, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'17 ', N'眷屬職業 ', N'C', 20, 0, N'職業', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 17, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'18 ', N'緊急聯絡人 ', N'C', 20, 0, N'姓名', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2022-10-13T17:20:14.240' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 18, 526961, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'19 ', N'緊急關係 ', N'C', 10, 0, N'關係', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 19, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'20 ', N'緊急電話 ', N'C', 20, 0, N'電話', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 20, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'21 ', N'緊急地址 ', N'C', 80, 0, N'地址', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 21, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'48 ', N'身份證號 ', N'C', 14, 0, N'身份證號', N'XXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 55, 64734, 3) GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'49 ', N'眷屬關係 ', N'C', 10, 0, N'眷屬關係', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 56, 64734, 3) GO INSERT [dbo].[datatplm] ([資料模板號], [說明], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'P1 ', N'人事明細資料', CAST(N'2012-10-04T15:32:02.280' AS DateTime), N'令狐沖', N'WXWG101234 # wg101', N' ', N' ', 0, 1, 3, 2109, 0) GOTWORK_AI_QUERY 預存程序 (AI 查詢)
> 來源:
TWORK_AI_QUERY.sql。AI 智慧查詢預存程序TWORK_AI_QUERY(含白名單檢查)。亦版控於 SqlBI/TWORK_AI_QUERY.sql。對應 changelog 2026-04-22 / 2026-06-02。USE [darbnogicsa1] GO /****** Object: StoredProcedure [dbo].[TWORK_AI_QUERY] Script Date: 2026/6/2 下午 06:40:06 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- 預存程序:TWORK_AI_QUERY -- 參數(配合 Log_Sys_Exec 的 LP 慣例): -- LP_DATAEVENT 事件名稱(Log 用) -- LP_P1 使用者代號 -- LP_P2 AI 生成的 SELECT 語句 -- LP_P3 使用者原始問題描述 -- LP_P4 最大回傳筆數(字串,預設 "200") -- ============================================= ALTER PROCEDURE [dbo].[TWORK_AI_QUERY] @LP_P1 NVARCHAR(50) = '', -- UserId @LP_P2 NVARCHAR(MAX) = '', -- GeneratedSQL @LP_P3 NVARCHAR(500) = '', -- Description @LP_P4 NVARCHAR(10) = '200' -- MaxRows AS BEGIN SET NOCOUNT ON; DECLARE @ErrorMsg NVARCHAR(500); DECLARE @FinalSQL NVARCHAR(MAX); DECLARE @UpperSQL NVARCHAR(MAX); DECLARE @MaxRows INT = TRY_CAST(@LP_P4 AS INT); IF @MaxRows IS NULL OR @MaxRows <= 0 SET @MaxRows = 200; -- ----------------------------------------------- -- 1. 基本驗證 -- ----------------------------------------------- IF @LP_P2 IS NULL OR LTRIM(RTRIM(@LP_P2)) = '' BEGIN SET @ErrorMsg = 'SQL 語句不可為空白'; INSERT INTO _ai_query_log (使用者代號, 查詢描述, 執行SQL, 執行結果) VALUES (@LP_P1, @LP_P3, @LP_P2, @ErrorMsg); RAISERROR(@ErrorMsg, 16, 1); RETURN; END SET @UpperSQL = UPPER(LTRIM(RTRIM(@LP_P2))); -- ----------------------------------------------- -- 2. 只允許 SELECT -- ----------------------------------------------- IF LEFT(@UpperSQL, 6) <> 'SELECT' BEGIN SET @ErrorMsg = '只允許 SELECT 查詢語句'; INSERT INTO _ai_query_log (使用者代號, 查詢描述, 執行SQL, 執行結果) VALUES (@LP_P1, @LP_P3, @LP_P2, @ErrorMsg); RAISERROR(@ErrorMsg, 16, 1); RETURN; END -- ----------------------------------------------- -- 3. 禁止危險關鍵字 -- ----------------------------------------------- IF @UpperSQL LIKE '%INSERT%' OR @UpperSQL LIKE '%UPDATE%' OR @UpperSQL LIKE '%DELETE%' OR @UpperSQL LIKE '%DROP%' OR @UpperSQL LIKE '%CREATE%' OR @UpperSQL LIKE '%ALTER%' OR @UpperSQL LIKE '%TRUNCATE%' OR @UpperSQL LIKE '%MERGE%' OR @UpperSQL LIKE '%EXEC%' OR @UpperSQL LIKE '%EXECUTE%' OR @UpperSQL LIKE '%XP[_]%' OR @UpperSQL LIKE '%SP[_]%' OR @UpperSQL LIKE '%;%' OR @UpperSQL LIKE '%--' OR @UpperSQL LIKE '%OPENROWSET%' OR @UpperSQL LIKE '%OPENDATASOURCE%' BEGIN SET @ErrorMsg = '偵測到不允許的 SQL 語法,查詢已被拒絕'; INSERT INTO _ai_query_log (使用者代號, 查詢描述, 執行SQL, 執行結果) VALUES (@LP_P1, @LP_P3, @LP_P2, @ErrorMsg); RAISERROR(@ErrorMsg, 16, 1); RETURN; END -- ----------------------------------------------- -- 3.5 白名單檢查:FROM/JOIN 後的表名必須登記在 _ai_schema -- (防 AI 幻覺 / prompt injection 超出白名單) -- ----------------------------------------------- DECLARE @scan NVARCHAR(MAX) = ' ' + @UpperSQL + ' '; SET @scan = REPLACE(REPLACE(REPLACE(@scan, CHAR(13), ' '), CHAR(10), ' '), CHAR(9), ' '); DECLARE @tables TABLE (tbl NVARCHAR(200)); DECLARE @searchFrom INT, @pos INT, @tokStart INT, @tokEnd INT, @token NVARCHAR(200); -- 掃 FROM SET @searchFrom = 1; WHILE 1 = 1 BEGIN SET @pos = CHARINDEX(' FROM ', @scan, @searchFrom); IF @pos = 0 BREAK; SET @tokStart = @pos + 6; WHILE SUBSTRING(@scan, @tokStart, 1) = ' ' SET @tokStart += 1; SET @tokEnd = @tokStart; WHILE @tokEnd <= LEN(@scan) AND CHARINDEX(SUBSTRING(@scan, @tokEnd, 1), ' ,;()') = 0 SET @tokEnd += 1; SET @token = SUBSTRING(@scan, @tokStart, @tokEnd - @tokStart); SET @token = REPLACE(REPLACE(@token, '[', ''), ']', ''); IF CHARINDEX('.', @token) > 0 SET @token = SUBSTRING(@token, CHARINDEX('.', @token) + 1, 500); IF LEN(@token) > 0 INSERT INTO @tables (tbl) VALUES (LOWER(@token)); SET @searchFrom = @tokEnd + 1; END -- 掃 JOIN(INNER/LEFT/RIGHT/FULL/CROSS JOIN 都會命中 ' JOIN ') SET @searchFrom = 1; WHILE 1 = 1 BEGIN SET @pos = CHARINDEX(' JOIN ', @scan, @searchFrom); IF @pos = 0 BREAK; SET @tokStart = @pos + 6; WHILE SUBSTRING(@scan, @tokStart, 1) = ' ' SET @tokStart += 1; SET @tokEnd = @tokStart; WHILE @tokEnd <= LEN(@scan) AND CHARINDEX(SUBSTRING(@scan, @tokEnd, 1), ' ,;()') = 0 SET @tokEnd += 1; SET @token = SUBSTRING(@scan, @tokStart, @tokEnd - @tokStart); SET @token = REPLACE(REPLACE(@token, '[', ''), ']', ''); IF CHARINDEX('.', @token) > 0 SET @token = SUBSTRING(@token, CHARINDEX('.', @token) + 1, 500); IF LEN(@token) > 0 INSERT INTO @tables (tbl) VALUES (LOWER(@token)); SET @searchFrom = @tokEnd + 1; END -- 比對 _ai_schema.sql_name(不分大小寫) IF EXISTS ( SELECT 1 FROM @tables t WHERE NOT EXISTS ( SELECT 1 FROM _ai_schema s WHERE LOWER(LTRIM(RTRIM(s.sql_name))) = t.tbl ) ) BEGIN SET @ErrorMsg = '查詢包含不在白名單 (_ai_schema) 的資料表,已被拒絕'; INSERT INTO _ai_query_log (使用者代號, 查詢描述, 執行SQL, 執行結果) VALUES (@LP_P1, @LP_P3, @LP_P2, @ErrorMsg); RAISERROR(@ErrorMsg, 16, 1); RETURN; END -- ----------------------------------------------- -- 4. 加上 TOP 限制 -- ----------------------------------------------- IF PATINDEX('%SELECT TOP %', @UpperSQL) = 0 AND PATINDEX('%SELECT TOP(%', @UpperSQL) = 0 AND PATINDEX('%SELECT DISTINCT TOP %', @UpperSQL) = 0 AND @UpperSQL NOT LIKE '%FETCH NEXT%' BEGIN DECLARE @SelectPos INT = CHARINDEX('SELECT', @UpperSQL); SET @FinalSQL = LEFT(@LP_P2, @SelectPos + 5) + ' TOP (' + CAST(@MaxRows AS NVARCHAR(10)) + ') ' + SUBSTRING(@LP_P2, @SelectPos + 7, LEN(@LP_P2)); END ELSE BEGIN SET @FinalSQL = @LP_P2; END -- ----------------------------------------------- -- 5. 記錄 Log -- ----------------------------------------------- INSERT INTO _ai_query_log (使用者代號, 查詢描述, 執行SQL, 執行結果) VALUES (@LP_P1, @LP_P3, @FinalSQL, 'OK'); -- ----------------------------------------------- -- 6. 執行查詢 -- ----------------------------------------------- BEGIN TRY EXEC sp_executesql @FinalSQL; END TRY BEGIN CATCH DECLARE @CatchMsg NVARCHAR(500) = ERROR_MESSAGE(); UPDATE _ai_query_log SET 執行結果 = 'ERROR: ' + @CatchMsg WHERE pkid = SCOPE_IDENTITY(); RAISERROR(@CatchMsg, 16, 1); END CATCH ENDDARB_LOG_SYS_AI_EXEC 預存程序 (AI log 轉發)
> 來源:
DARB_LOG_SYS_EXEC_AI.sql。log 庫 AI 執行轉發預存程序DARB_LOG_SYS_AI_EXEC(複製 DARB_LOG_SYS_EXEC 改寫 log_sys_ai)。對應 changelog 2026-06-05。USE [darbnogilog1] GO /****** Object: StoredProcedure [dbo].[DARB_LOG_SYS_EXEC] Script Date: 2026/6/5 下午 04:42:41 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO Create PROCEDURE [dbo].[DARB_LOG_SYS_AI_EXEC] (@languagen INT,@eventtype nvarchar(10),@dataevent nvarchar(30),@datafunc nvarchar(30),@param1 nvarchar(500) OUTPUT,@param2 nvarchar(MAX), @param3 nvarchar(1000),@param4 nvarchar(200),@param5 nvarchar(200),@param6 nvarchar(200),@param7 nvarchar(200), @param8 nvarchar(200),@param9 nvarchar(200),@param10 nvarchar(200),@param11 nvarchar(200),@param12 nvarchar(200), @inputstaff nvarchar(20),@localtime datetime,@inputplace nvarchar(18),@srvdbid int,@log_sys_pkid int output,@result nchar(254) output) --2010/12/08 將 @param2 nvarchar(200) 改成 @param2 nvarchar(2000),配合 DARB_BROWSE WITH EXECUTE AS 'foxrunprg' AS BEGIN SET NOCOUNT ON; DECLARE @status1 nchar(6),@errornumber INT,@errormessage NCHAR(238),@sqlstring NVARCHAR(200), @databaseid char(1),@param_qty smallint,@paramoutput CHAR(1),@is_fail char(1), @csadbname nvarchar(20)=SUBSTRING(DB_NAME(),1,CHARINDEX('log',DB_NAME())-1)+'csa'+SUBSTRING(DB_NAME(),CHARINDEX('log',DB_NAME())+3,3) ; SELECT @errornumber='',@errormessage='',@is_fail='N' INSERT INTO dbo.log_sys_ai (languagen,eventtype,dataevent,datafunc, param1,param2,param3,param4,param5,param6,param7,param8,param9,param10,param11,param12, status1,inputstaff,localtime,inputplace,servertime,starttime,srvdbid) VALUES (@languagen,@eventtype,@dataevent,@datafunc, @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10,@param11,@param12, '',@inputstaff,@localtime,@inputplace,GETDATE(),GETDATE(),@srvdbid); SET @log_sys_pkid=scope_identity()--log_sys 的pkid 是 自動加 1 SELECT @databaseid=databaseid,@param_qty=param_qty,@paramoutput=paramoutput FROM proc_param where datafunc=@datafunc IF @@ROWCOUNT=1 BEGIN IF @databaseid='C' -- 代表是darbcsa 1~N SET @sqlstring=@csadbname+'.dbo.'+@datafunc; --N'darbcsa'+SUBSTRING(DB_NAME(),8,6)+'.dbo.'+@datafunc; ELSE -- 代表是darblog 1~N SET @sqlstring='dbo.'+@datafunc; BEGIN TRY IF @paramoutput='Y' --只有第一個參數 OUTPUT BEGIN --IF @param_qty=0 應該要有參數 OUTPUT -- EXEC @sqlstring IF @param_qty=1 EXEC @sqlstring @param1 OUTPUT IF @param_qty=2 EXEC @sqlstring @param1 OUTPUT,@param2 IF @param_qty=3 EXEC @sqlstring @param1 OUTPUT,@param2,@param3 IF @param_qty=4 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4 IF @param_qty=5 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5 IF @param_qty=6 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6 IF @param_qty=7 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7 IF @param_qty=8 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7,@param8 IF @param_qty=9 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9 IF @param_qty=10 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10 IF @param_qty=11 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10,@param11 IF @param_qty=12 EXEC @sqlstring @param1 OUTPUT,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10,@param11,@param12 END ELSE BEGIN IF @param_qty=0 EXEC @sqlstring IF @param_qty=1 EXEC @sqlstring @param1 IF @param_qty=2 EXEC @sqlstring @param1,@param2 IF @param_qty=3 EXEC @sqlstring @param1,@param2,@param3 IF @param_qty=4 EXEC @sqlstring @param1,@param2,@param3,@param4 IF @param_qty=5 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5 IF @param_qty=6 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6 IF @param_qty=7 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7 IF @param_qty=8 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8 IF @param_qty=9 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9 IF @param_qty=10 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10 IF @param_qty=11 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10,@param11 IF @param_qty=12 EXEC @sqlstring @param1,@param2,@param3,@param4,@param5,@param6,@param7,@param8,@param9,@param10,@param11,@param12 END END TRY BEGIN CATCH set @status1='NG' UPDATE dbo.log_sys_ai SET status1='NG',endtime=GETDATE() WHERE srvdbid=@srvdbid and pkid=@log_sys_pkid insert into log_error(logid,錯誤代碼,錯誤嚴重性,錯誤狀態碼,錯誤程序,錯誤行號,錯誤訊息,srvdbid) select -@log_sys_pkid,error_number() as 錯誤代碼,error_severity() as 錯誤嚴重性, error_state() as 錯誤狀態碼,error_procedure() as 錯誤程序, error_line() as 錯誤行號,error_message() as 錯誤訊息,@srvdbid ; select @errornumber=error_number(),@errormessage=error_message() SET @is_fail='Y' END CATCH IF @is_fail='N' BEGIN UPDATE dbo.log_sys_ai SET status1='OK',endtime=GETDATE() WHERE srvdbid=@srvdbid and pkid=@log_sys_pkid set @status1='OK' END set @result=@status1+N','+convert(nchar(6),@errornumber)+N','+@errormessage END ENDBreaking Changes
- 無(皆為加欄位 / 建立物件 / 資料種子,向後相容)。
-
06-08 supportpanel-attachment-workflow-hint ▸
2026-06-08 — 操作面板:附件 / 工作流程分頁有資料時標題顯示筆數
摘要
在表單操作面板右側的支援分頁(SupportPanel)中,「附件」與「工作流程」分頁的清單若有資料,分頁標題文字旁會以紅字顯示筆數「(N)」(hover 顯示提示「此頁籤資料筆數」),讓使用者不必逐一點開分頁,就能一眼看出目前單據帶有幾筆附件或工作流程。
新增
TabViewModel.HasData/TabViewModel.DataCount(ViewModel/Control/Layout/Tab/TabViewModel.cs):分頁基底新增bool HasData(預設false,控制提示是否顯示)與int DataCount(清單筆數,供標題顯示「(N)」)。其他分頁不設定即維持false/0(不顯示)。
- SupportPanel 分頁標題筆數提示(
TsControl/PageParts/SupportPanel.xaml):TabControl.ItemTemplate由單純文字改為「文字 + 筆數」;筆數為紅字TsTextBlock,Text綁DataCount並以StringFormat=({0})格式化,Visibility綁HasData(透過新增的BooleanToVisibilityConverter資源HasDataToVisibility),並附ToolTip="此頁籤資料筆數"。
變更
AttachmentTabViewModel.Attachmentsetter(ViewModel/Control/Layout/Tab/AttachmentTabViewModel.cs):設定DataCount = value?.Count ?? 0、HasData = DataCount > 0。SetDataGrid()載入實際附件後即反映;Init()/Clear()設空清單時為0/false。
WorkflowTabViewModel.Workflowsetter(ViewModel/Control/Layout/Tab/WorkflowTabViewModel.cs):設定DataCount = value?.Count ?? 0、HasData = DataCount > 0。SetWorkFlowDataGrid()載入後反映;無工作流程時為0/false。
Breaking Changes
- 無。純新增 UI 提示,不影響既有行為與資料。
備註
- 提示來源是分頁實際載入的清單(附件走
LocalDbContext.Attachment、工作流程走LocalDbContext.WorkflowStep),清單一旦重新載入(換單據/查詢)即時更新提示點。
- 建置:
ViewModel與TsControl專案以 VS MSBuild 建置通過(dotnet build因 Office COM 參考的MSB4803 ResolveComReference無法用,需用 VS 版 MSBuild)。
-
06-08 scx-pdt-compare-and-alltrim-binding-fixes ▸
2026-06-08 生產模組(scx_pdt)VFP 對比+ALLTRIM/binding 修正
摘要
對 VFP
scx_pdtlibrary(生產模組,14 個 class)完成 VFP↔新版逐項對比,並修補兩類確認的 bug:1.
ALLTRIM(...)被當字面字串塞進 SQL —PdtinfEdit/WkpaperEdit的「已耗料/已領料/已排程不得修改」防呆全部失效。2. Pdtinf.xaml 中英 binding typo — 品名、單位欄綁到不存在的英文屬性,永遠空白且寫不回。
對比同時發現 F.Production 三支單據(pdtinf/wkpaper/wkday)有更大的「載入層未完成」🔴(Source 未註冊 LocalDbContext),本批未修,列於下方待辦。
變更
修正 1 — ALLTRIM 字面 SQL(LogicBll,已 dotnet build 通過)
VFP 原意
ALLTRIM(派工單_V.派工單號)是將注入值去空白,新版誤將整段ALLTRIM(...)當字串寫進 SQL 條件(如WorkOrderNo LIKE 'ALLTRIM(PD0001)%'),永遠 match 不到 → 防呆形同虛設。改在 C# 端.Trim(),運算子維持原樣:WkpaperEdit.cs:55(CheckMaterialUsage,精確比對=)
WkpaperEdit.cs:75(CheckWorkOrderPicking,前綴LIKE %)
PdtinfEdit.cs:47(CheckMaterialUsage,LIKE %)
PdtinfEdit.cs:67(CheckWorkOrderPicking,LIKE %)
PdtinfEdit.cs:87(CheckWorkOrderScheduling,LIKE %)+ 順手移除假別名A./B.:此方法為單表查詢無 join,欄位都在主表 vw_wkpaper,原本 copy-paste 自有 join 的 picking 方法導致 SQL 必錯(不修則 ALLTRIM 修了也無效)。
加
(x ?? "")防 null,與舊行為一致。修正 2 — Pdtinf.xaml binding typo(TsERP,需 VS build 驗證)
Source 公開屬性是中文
品名(Twork_pdt_vw_pdtinfmaSource.cs:717)、單位(:177),英文名只有 private 欄位:Pdtinf.xaml:96{Binding SKUDescription}→{Binding 品名}(搜尋框描述)
Pdtinf.xaml:115{Binding SKUDescription}→{Binding 品名}(唯讀品名框)
Pdtinf.xaml:154{Binding UnitOfMeasurement}→{Binding 單位}(單位 combo)
已交叉比對 Pdtinf.xaml 全部 binding path,確認無其他漏網 typo。
行為變更提醒
- 修改/刪除防呆恢復:拿一張已耗料/已領料/已排程的製通單(pdtinf)或派工單(wkpaper)去改,會被擋下或跳通知(先前完全不作用)。
- 製通單品名/單位顯示:輸入品號後品名欄、單位欄會正確帶值並可儲存(先前永遠空白)。
- ⚠️ 上述兩項目前 runtime 還測不到 — F.Production 三支單據因 Source 未註冊 LocalDbContext,開窗載入即例外,需先解該載入層問題才能實測。
對比結果:scx_pdt 移植狀態
VFP class 內容 狀態 pdtinf 製造通知單 ⚠️ 有,載入層+按鈕斷線、本批修了 ALLTRIM/binding wkpaper 派工單 ⚠️ 有,載入層斷線、4 功能鈕全缺、本批修了 ALLTRIM wkday 生產實績(含 wkday2 工時) ⚠️ 有,載入層斷線 mrp MRP 計算 🔴 引擎有單元測試但 UI 開不起來/查不出 wkday2 生產工時 🟢 已併入 Wkday perdata1 人事資料(精簡) 🟢 R.HumanResource/Perdata 已涵蓋 wkng 例不良單 🟡 只有 Model/Source,無 UI/VM wknpdt 非生產工時 🟡 只有 Model/Source,無 UI/VM perdmd 要員需求(樞紐) ❌ 未移植 pd_qry5 缺料/進度查詢 ❌ 未移植 pd_qry9 OEE 查詢 ❌ 未移植 wkpaper_brow 樞紐分析 🟢 通用樞紐已覆蓋 wkpaper_bd 委外派工單報表 🟡 含金額兩版報表未實作 尚未處理(已對比出、待後續)
- 🔴 F.Production 載入層未完成:pdtinf/wkpaper/wkday(及 OutSourcingFillRate)的 Source 型別全未註冊進
LocalDbContext的 DbSet,新 DataManager 堆疊Load()走_db.Set<T>()會丟例外 → 開窗載入即崩。wkday 另有英文[TsColumnName]對不上中文 DB view,補註冊後仍需中文化。
- pdtinf:Pdtinf_1/_2(轉單/計畫表)BLL 完整但 DataContext=null、VM 孤兒(疑似十多個轉單視窗系統性未完成);「改數量」(DARB_TUR_PDTINF_QTY SP 已在等)/「特殊修改」未移植;輸入訂單 pkid 不自動帶客戶代號。
- wkpaper:設變/製程表/排程/特殊修改 4 鈕全缺;AllowSave 缺工程代號必填;缺「單價=代工+代料」自動計算;opmode 權限欄管制消失。
- mrp:
MrpViewModel.Query()結果未接回 VM;{StaticResource TwoDecimalPlaces}全 repo 無定義(XamlParseException);SPTWORK_QRY_MRP不存在;替換後品號 stub;轉請購/轉製通(MRP 閉環)整批未移植。
- wkday:刪耗料用
MaterialUsageTransactionPkid但 view 無此欄;工時自動計算(UPDT_WKTIME)、作業者在職驗證未移植。
- 未移植 class:wkng/wknpdt(半成品)、perdmd/pd_qry5/pd_qry9(無對應)待規劃。
- 被開的 .scx 子表單(PDTINF_QTY/DESIGNC/WKPAPER_T_NEW/WKPAPERH/WKDAY_TR 等)原始碼在
C:\DARB_FOX\NOGIHISA\FORMS\未匯出.prg,遞迴對比需另匯出。
Migration Notes
無需資料遷移。
LogicBlldotnet build 通過(0 errors);Pdtinf.xaml屬 TsERP.csproj,dotnet CLI 撞既有 MSB4803,需 VS MSBuild 驗證。 -
06-08 payapply-compare-fixes ▸
2026-06-08 費用申請(payapply_kc)VFP 對比修正
摘要
對 SCX_ARP library 最後一支
payapply_kc(費用申請)完成 VFP↔新版逐項對比(欄位 / allowsave / allowedit / addagain / 事件 / 按鈕 / DB schema),修掉反推未稅金額錯誤、付款條件到期日與匯率查詢日的日期連動、明細欄誤綁、日期連動帶值、以及補上統一編號檢查碼驗證。至此 scx_arp 全 15 class 對比完成。按鈕接線本就完整(轉傳票
IOther1→PayapplyToGl、特殊修改IOther2→SpecialEdit、工作流程/快速審核走集中式 workflow);PayapplySave/PayapplyEdit命名「Payapply」為正確命名(非孤兒,工廠正常載入),本次未動。變更
金額計算(Model)
- 反推未稅除數修正(
Rp_dForPayapplyBindingSource.反推未稅)
- 原
本幣未稅 = 本幣含稅 / (taxRate / 100),稅率 5% 時等於 ÷0.05 = ×20。- 改為
本幣未稅 = 本幣含稅 / (1 + taxRate / 100),對齊 VFP本幣含稅/(100+稅率)*100與正向CalculateTax慣例(GetTaxRate回傳百分比數字,5 代表 5%)。日期連動(Model / ViewModel / XAML)
- 付款條件到期日/付款日、TsCurrency 匯率查詢日改用申請日期
- VFP 付款條件
U_PAYTERMDATE與匯率U_BLRATE使用日期皆以申請日期為基準,但新版SetDueDate()與TsCurrency Date綁的是交易日期,而 payapply 全程從未設過交易日期(恆為空)→ 到期日/付款日算不出、外幣匯率查不到。-
Rp_mForPayapplyBindingSource新增申請日期Binding:設申請日期時同步寫入交易日期,驅動SetDueDate與TsCurrency。-
Payapply.xaml申請日期欄改綁申請日期Binding。-
Payapply_kcViewModel.AfterAddNew補交易日期 = 申請日期,新單即具備匯率日/到期基準。- 申請日期/立帳日期改值連動 帳款期別、使用日期、使用截止日(對應 VFP
申請日期.LostFocus/立帳日期.LostFocus)
- 新增共用
SetUsagePeriod():帳款期別 = 日期前 7 碼;使用日期(月初)、使用截止日(月末)空白才帶(不覆蓋使用者輸入)。-
Rp_mForPayapplyBindingSource新增立帳日期Binding,Payapply.xaml立帳日期欄改綁立帳日期Binding;申請日期亦透過申請日期Binding連動。明細欄位(XAML)
- 「原幣稅額」欄修正綁定:原綁
稅額(本幣稅額),改綁原幣稅額。該欄位於原幣未稅/原幣含稅之間,標題與內容原本不符。
- 發票日期欄改為可輸入:移除
ForceReadOnly="True"(VFPcol發票日期為可輸入,特殊修改模式另開放)。
- 採購單號(缺件說明)欄改為可寫回:
Mode=OneWay→Mode=TwoWay, UpdateSourceTrigger=LostFocus,原本使用者輸入不會存。
新增單據預設值(ViewModel)
- 進銷分類預設改為沿用前一筆,無前一筆則「費用支出」(
Payapply_kcViewModel,對應 VFP addagain:抓當前筆進銷分類,新空白筆若空就帶,前一筆有值用前一筆否則1.費用支出)
- 新增欄位
last進銷分類,於AfterMoverRecord擷取目前顯示這筆的進銷分類(導覽/存檔後皆更新);新增流程Add()不呼叫AfterMoverRecord,故新增當下不會被空白筆覆蓋。-
AfterAddNew移除原本寫死的進銷分類 = "6"(直接沖帳)與重複賦值,改為沿用last進銷分類、空則DocumentCategoryEnum.Expense.Code(="1" 費用支出)。統一編號檢查碼(LogicBll)
- 主檔/明細統一編號補檢查碼驗證(
PayapplySave.AllowSave,對應 VFP 主檔統一編號.Valid與明細text1.Valid),共用Util2017.CheckTaxID(InvoiceArea.T, …):
- 主檔:
00000000豁免 → 8 碼走統編檢查碼 → 10 碼放行 → 其餘長度回「請輸入正確的資料」。- 明細:
'A'開頭豁免(人事資料轉來)→ 同 8/10/其他長度規則。- A 方案:10 碼身分證僅放行、不驗檢查碼(repo 無 ROC 身分證檢查碼工具,且 payapply 多為公司行號)。與 VFP 差異:VFP 明細嚴格只做 8 碼 T1,此處比照主檔放行 10 碼,避免誤擋個人 ID。
Breaking Changes / Migration Notes
無資料結構變更。皆為驗證/連動/綁定行為修正。
- 反推未稅鈕的結果由錯誤(×20)變為正確,舊單若曾用該鈕產生過金額,重存時會被正向
HandleDataBeforeEndEdit重算修正。
- 統編檢查碼上線後,原本存有非法統編(非 00000000、非 8 碼合法、非 10 碼、非 'A' 開頭)的單據在再次存檔時會被擋下,須修正統編後才能存。
驗證
dotnet build Model/Model.csproj、dotnet build LogicBll/LogicBll.csproj皆 0 錯誤。
- XAML/ViewModel 變更需於 Visual Studio build 確認(dotnet CLI 對 TsERP/ViewModel 會撞既有 MSB4803,與本次無關)。
- 業務面驗收:新增→輸入廠商→確認到期日/付款日自動算、外幣依申請日期帶匯率;改申請日期→帳款期別跟著變、使用日期/截止日空白時自動帶月初月末;反推未稅鈕金額正確;輸入非法統編存檔被擋。
- 反推未稅除數修正(
-
06-06 wkflowt-enum-fixes-and-chinese ▸
2026-06-06 工作流程樣板列舉修正 + TodoList 列舉系統值改中文
摘要
修正工作流程樣板(
WKFLOWT)明細的處理事項/狀態/優先順序下拉連動,新增處理事項選擇時的自動帶值規則,並將 TodoList 三組列舉的
SystemDescription(存 DB 的系統值)由英文改為中文。新增
- Wkflowt 處理事項下拉連動(
Twork_sys_vw_wkflowt_dSource.JobCodeEnum):
- 選「發行」→ 自動帶
GetSender預設值(審核順序 0、序號 00、狀態已完成、完成率 100…),處理部門設為登入者佔位符#I#(pkid/linkid 保留由 DataManager 管理)- 選「初審」「複審」→
流程結束 = A(核准)- 選「核定」→
流程結束 = Y(結束)- 選其他(通知/確認/承認)→
流程結束清空Twork_com_vw_commpr_2Source.SetSignInUserWhenPlaceholder()幫助方法:
處理部門為
#I#時清空部門並帶入登入者為處理人(含 email)。變更
TodoListJobCodeEnum/TodoListStatusCodeEnum/TodoListPriorityCodeEnum的
SystemDescription由英文(Notify、NotHappen、Normal…)改為中文(
通知、未開始、中…);兩份語言 JSON(Common/Lang/Xaml/Shared.json、TsERP/Lang/Xaml1/Xaml.json)對應區段同步 re-key,各語言譯文不變(英文介面仍顯示英文)。JobCodeEnum/StatusCodeEnum/PriorityCodeEnumsetter 修正:正確寫回對應的
「碼」欄位與系統值欄位;getter 加依碼回查 fallback,既有資料載入時下拉正確顯示
(原
StatusCodeEnumsetter 誤用_PriorityCodeEnum有 NRE 風險,已修)。RecordWorkflowRegionViewModel的#I#取代改用共用幫助方法後,會跟 Commpr 版一樣
連 email 一起帶入登入者(原本漏帶)。
刪除
- 無。
Breaking Changes
- DB 存值變動:之後新存的
處理事項/狀態/優先順序文字欄位為中文;
既有舊資料仍為英文字串。畫面顯示一律走「碼」欄位回查列舉,不受影響;
已全 repo 檢查無任何程式碼以英文字串比對這三個文字欄位。
Migration Notes
- 若有外部報表/查詢直接依
處理事項等文字欄位過濾英文字串,需改為依「碼」欄位
(
處理事項碼/狀態碼/優先順序碼)或同時相容中英文值。 - Wkflowt 處理事項下拉連動(
-
06-06 receive-compare-fixes ▸
2026-06-06 應收帳款主檔(receive)VFP 對比批次修正
摘要
對 SCX_ARP library 的
receive(應收帳款主檔)完成 VFP↔新版逐項對比。按鈕接線(銷貨轉入 Recepdt、暫估轉AR Recepdt2、轉傳票 ArToGl、修改客戶 TempAllow 流程)與 XAML 欄位本就比 paymnt 完整;問題集中在ReceiveSave的驗證缺漏與「金額回填邏輯整段躺在死方法Old()」。paymnt 批次的共用 Source 修正(廠商帶入、明細重算通知、代工單價Binding)自動惠及 receive。變更
批次 1 — 存檔/編輯驗證與金額回填(LogicBll)
- 稅別必填驗證恢復(
ReceiveSave.AllowSave):新增/複製/修改時必填,財務類別 25暫收/23待抵/26折扣/21退貨 除外;特殊修改可免(對應 VFP 2016/11/07)。
- 匯率必須大於 0 才能存檔。
- 立帳日期必填(原僅驗交易日期)。
- 訊息翻譯 key 由誤植的
PAYMNT改為RECEIVE(交易日期/帳款期別/客廠部代號/幣別/倉庫/原幣未稅 等多處 copy-paste)。
- 財務類別金額回填從死方法
Old()移入正式存檔路徑,並對齊 VFP:
- 15 稅金:應收付(原幣/本幣)= 稅額。
- 19 原幣調整 / 26 折扣:原幣應收付 = 發票金額+稅額;本幣 = ×匯率。
- 22 折讓:應收付 = 發票金額+稅額 改為無條件回填(原版只在無明細時)。
- 死方法
Old()刪除。- 自動算稅範圍收斂回 VFP:僅 11訂金/12出貨/21退貨/31非應收發票/14雜項 且
轉入備註為空 才跑TaxCalculator(對應 VFP 2012/09/12「轉入不得重新計算」)。原版對所有財務類別<>25(含轉入單、15/19/26/23/24)每次存檔都重算,會把轉入單與特殊類別的金額蓋掉。
- 財務類別<>25 時補
程式類別='R'(對應 VFP;原只靠選單帶入,直接開程式新增可能存成空白),並補外幣時本幣應收付=原幣×匯率尾差同步。
- 「舊資料」判斷由完全相等改為包含(
ReceiveEdit),對應 VFP'舊資料'$轉入備註。
批次 2 — 連動與顯示(Model/ViewModel)
- 交易日期輸入後自動帶帳款期別(
Rp_mForARAPBindingSource.交易日期Binding,對應 VFP交易日期.Valid:帳款期別=LEFT(交易日期,7))。共用 Source,paymnt 端交易日期側同步生效(立帳日期側前一批已做)。
- 瀏覽時倉庫欄顯示(
ReceiveViewModel.AfterMoverRecord,對應 VFP倉庫.Refresh:倉庫=LEFT(單號,6))。
行為變更提醒
- 自動算稅收斂後:23待抵/24預收/15/19/26/轉入單存檔不再被 TaxCalculator 重算(與 VFP 一致)。若有流程依賴了原本的「全類別重算」行為需注意。
- 存檔驗證變嚴:稅別空白(指定類別外)、匯率≤0、立帳日期空白 會被擋下。
尚未處理(已對比出、待業務確認)
- 批改客戶(
_CHANGENO_1)、轉入折讓(RECEPDT_DISC)、發票統計(RP_S 'AR')三顆按鈕未接(EF6/EF7 死方法、未宣告 IOther6/7)
- 修改客戶(EF5):用廢棄
WindowHelper.OpenWindow;VFP 改完暫收客戶自動建收款單+沖帳的自動化未移植
- 發票金額輸入不自動算稅額(×稅率);複製限制(VFP 僅 22 折讓可複製)未做
- 傳票號碼未顯示/無連結、相關單號未顯示、查詢收款單頁籤(lcl_rsheet)未移植
- RECEPDT / RECEPDT_2 / RECEPDT_DISC 為獨立 .scx,遞迴對比需另取得 VFP 原始碼
Migration Notes
無需資料遷移。
LogicBlldotnet build 通過、ViewModelVS MSBuild 通過(0 errors)。 - 稅別必填驗證恢復(
-
06-06 paymnt-compare-fixes ▸
2026-06-06 應付帳款主檔(paymnt)VFP 對比批次修正
摘要
對 SCX_ARP library 的
paymnt(應付帳款主檔)完成 VFP↔新版逐項對比(欄位 / allowsave / allowedit / addagain / 事件 / 按鈕),並修掉第一、二批問題。按鈕接線(進貨轉入 Paypdt、暫估轉AP Paypdt2、轉傳票 ApToGl、特殊修改)本就完整,問題集中在存檔驗證缺漏、特定財務類別金額計算、與明細重算連動。變更
批次 1 — 存檔/編輯驗證(LogicBll)
- 匯率必須大於 0 才能存檔(
PaymntSave.AllowSave)
- 對應 VFP「請輸入正確的匯率」。原程式呼叫
U_Blrate但回傳值丟棄(且參數為 Prepaid 殘留),等於沒做;已移除該死碼,改為存檔前驗證並阻擋。- 稅別必填驗證恢復(
PaymntSave.AllowSave)
- 財務類別非 5B(退貨應付)/66(DM折讓)/67(損害賠償)時稅別必填,原驗證整段被註解。
- 立帳日期必填驗證補上(
PaymntSave.AllowSave),原僅驗交易日期。
- 財務類別 55(進貨費用/成本分攤)不得修改或刪除(
PaymntEdit.AllowEditHandle)
- 對應 VFP「進貨費用,不得修改或刪除,請刪除 51進貨單」。原版 55 單可被直接刪除,造成與來源進貨單脫鉤。新增訊息
PurchaseFeeCannotEditOrDeletePleaseDeletePurchaseDocument(Message.json已補中英文)。- 「舊資料」判斷由完全相等改為包含(
PaymntEdit),對應 VFP'舊資料'$轉入備註。
- 財務類別 59:應收付金額 = 發票金額 + 稅額(
PaymntSave.HandleDataBeforeEndEdit)
- 並將 59 排除在自動算稅之外(對應 VFP 2021/11/08 新增段)。
- 財務類別 5B/66/67:應收付金額自動帶出(
PaymntSave.HandleDataBeforeEndEdit)
- 本幣應收付 = 發票金額 + 稅額;原幣應收付 = 本幣 / 匯率(依幣別小數位數四捨五入)。對應 VFP
稅額.Valid;原版這三類單的應收付恆為 0。- 本幣應收付 = 原幣應收付 × 匯率 尾差校正(
SetDueAmount(),對應 VFP allowsave 開頭的 REPLACE)。
批次 2 — 明細重算與預設值(Model/ViewModel/XAML)
- 代工單價參與重算:明細 grid 代工單價欄改綁新的
代工單價Binding,輸入後即重算原幣未稅(公式數量×(單價+代工單價)+其他金額)。原綁定純屬性,改代工單價不會重算。
- 數量 / 其他金額輸入後 grid 即時刷新:
數量Binding/其他金額Bindingsetter 補 raise原幣未稅Binding(原本只有單價Binding有),修正改數量後原幣未稅欄不即時更新。
- 新增單據預設 進銷分類 = 內採(P1)(
PaymntViewModel.AfterAddNew),對應 VFP addagain進銷分類='1.內採'。
- 立帳日期輸入後自動帶帳款期別:主檔立帳日期改綁新的
立帳日期Binding,離焦後帳款期別 = 立帳日期前 7 碼(yyyy/MM),對應 VFP立帳日期.LostFocus。
批次 3 — 輸入廠商帶入廠商資料(業務裁定後實作)
- 新增單據預設維持 本位幣+匯率 1(現行行為,業務確認)。
- 輸入收付客廠號時帶入廠商主檔資料(
Twork_arp_vw_rp_mSource.SetTransactionCustVendDept,對應 VFP收付客廠號.代號.LostFocus):
- 新增帶入:幣別(廠商幣別非空才覆蓋,空則維持本位幣)、帳款起始日、關係人。
- 幣別變更後匯率由
TsCurrency控件自動查匯回填(同手動改幣別的行為)。- 帳款起始日改在 收付條件號 之前設定,到期日/付款日計算(
SetDueDate)使用新起始日。- 此 Source 與應收(receive)共用,應收端同步生效。
- 輸入廠商資料(客廠部代號)時,若付款廠商空白則同步補入(
Rp_mForARAPBindingSource.客廠部代號Binding,對應 VFPsqlnm_sp1.代號.LostFocus):補入後走同一條帶入鏈(幣別/帳款起始日/關係人/收付條件…)。
- 修正既有 binding 通知 bug:
收付客廠號Bindingsetter 原為OnPropertyChanged(客廠部代號Binding)——把屬性「值」當屬性名 raise,導致輸入付款廠商後 廠商資料 欄不會即時刷新;更正為nameof(客廠部代號Binding)。
尚未處理(已對比出、待業務確認)
- 發票統計按鈕(
IOther5宣告但空實作;VFPDO FORM RP_S WITH 'AP',新版無 RP_S 對應)
- else6 更新資料(
_CHANGENO更新進出貨發票)無對應
- 特殊修改稅額尾差攤提整段註解、且金額欄位特殊修改下恐不可編輯
- 「查詢付款單」頁籤(lcl_psheet)未移植;傳票號碼未顯示、無 DblClick 連結
- 主檔 相關單號/訂單編號/回轉日期/暫估/折讓 欄位未顯示;明細 科目代號 等欄在 XAML 註解區
- PAYPDT / PAYPDT_2 子表單內部邏輯待取得 VFP 原始碼後遞迴對比
Breaking Changes
無。皆為回復 VFP 行為的修正;存檔驗證變嚴(匯率≤0、稅別空白、55 刪改會被擋下)。
Migration Notes
無需資料遷移。
LogicBll以dotnet build通過、ViewModel/TsERP以 VS MSBuild 建置通過(0 errors)。 - 匯率必須大於 0 才能存檔(
-
06-06 otherrp-grpmaccl-prepaid-compare-fixes ▸
2026-06-06 代收付/費用科目群組/預付(otherrp・grpmaccl・prepaid)VFP 對比批次修正
摘要
SCX_ARP 三支主檔類對比+第一批修正。最重大發現:預付(PREPAID)的存檔驗證與沖帳防呆整組是孤兒——BLL 類別命名
TemporarySave/TemporaryEdit與工廠反射約定(ProgramClass=PREPAID →PrepaidSave/PrepaidEdit)不符,永遠 fallback 到無驗證的 base,已改名接上。變更
prepaid(預付/暫付申請,View=Temporary.xaml)
TemporarySave→PrepaidSave、TemporaryEdit→PrepaidEdit(改名接線) 🔴
- 接上後生效:財務類別/申請日期/帳款期別/事由/受款人/幣別/原幣金額>0/付款方式/收付款日/到期日 共 10 條存檔驗證 + 已沖帳不得修改防呆 + 備註=事由、收付客廠號、立帳日期=申請日期 等存檔補值。
- 補 客廠部代號(廠商)必填(對應 VFP)。
- 修 匯率≤0 自動補匯率:原
U_Blrate回傳值丟棄(等於沒補),改為填入匯率並重算本幣應收付。
otherrp(代收付)
- 本幣應收付存檔時計算(
SetDueAmount(),對應 VFP 原幣應收付/匯率.LostFocus)——原版完全沒人算,本幣恆 0/stale。
- 修 匯率≤0 自動補匯率(同上
U_Blrate丟棄回傳值病灶)。
- 補 申請日期必填(對應 VFP『申請日期未輸入』)。
OtherrpViewModel實作IAdd:新增預設 申請日期=今天、帳款期別=當月、幣別=本位幣、進銷分類=內銷(DomesticOrder R1,對應 VFP addagain'1.內採')。
grpmaccl(費用科目群組)
- 補 群組科目別(主鍵)必填/
+++檢查(VFP 第一條驗證)。
- 補 借貸別必填(D/C 值域已由 ComboBox 限制)。
- 明細刪列條件補上 群組代號空白→D(對應 VFP
REPLACE ALL 增刪修 WITH 'D' FOR EMPTY(群組代號));保留原有「科目代號空白→D」為新版額外防呆。
已確認非缺漏
- otherrp/prepaid 的「工作流程」「快速審核」按鈕 → 新版集中式 workflow(架構決策)。
- 借貸別 D/C
Valid→ ComboBox 值域取代。
尚未處理(待業務確認)
- otherrp:客廠部代號輸入不帶 幣別/收付條件/帳款起始日/關係人/受款人;收付條件不算付款日/到期日;申請部門→使用部門、申請人→使用人、申請日期→使用日期 空白補值連動(VM 用裸 Source、XAML 綁 plain 屬性,要做需換 BindingSource 衍生類+改 XAML)
- prepaid:匯率手改不重算本幣(匯率 plain 綁定);收付條件 lookup 欄位未移植;使用日期/使用部門/使用人 欄位未移植;
PrepaidEdit用沖帳原幣 vs VFP 沖帳本幣(外幣尾差邊角)
Migration Notes
無需資料遷移。注意:預付單接上驗證後,過去存得進去的不完整單(無廠商、無事由、無受款人…)將開始被擋下,屬預期行為。
LogicBlldotnet build、ViewModelVS MSBuild 皆 0 errors。 -
06-05 ai-log-sys-dispatcher ▸
2026-06-05 AI 查詢與 catalog 全面改走 Log_Sys dispatcher + AI 專用資料庫帳號
摘要
AI 智慧助理的所有 DB 存取(查詢 + catalog 載入)從「直連 proc/資料表」改為比照 ERP 標準
Log_Sys 模式:client 只連 log 資料庫,經
DARB_LOG_SYS_AI_EXECdispatcher(寫
log_sys_ai稽核表、依proc_param以位置參數轉發)執行 csa 庫的目標 proc。同時支援 AI 專用最小權限帳號(
_prgpar的AI_DB_CONN),不再固定使用 ERP 主連線。變更
- 新增共用
LogSysAiDispatcher(TsErp.Ai.Tools/Data):比照SetLogSysExecCommand的參數組法
呼叫
DARB_LOG_SYS_AI_EXEC;@result非 OK 或為空(proc_param未登錄)時丟明確錯誤。AiQueryExecutor:經 dispatcher 轉發TWORK_AI_QUERY(@param1~4=使用者/SQL/描述/筆數上限)。
CatalogSqlReader:catalog 也經 dispatcher——TWORK_AI_GET_USER_SCHEMA(view 清單)與
新 proc
TWORK_AI_GET_VIEW_COLUMNS(view 欄位+型別,describe_view lazy 用),不再直連 csa 庫。TWORK_AI_QUERY(SqlBI 腳本):移除@LP_DATAEVENT參數——dispatcher 是位置參數轉發
(
EXEC target @param1, @param2…),第一個位置就是@param1,保留LP_DATAEVENT會錯位吃到 UserId。另補
@LP_P5~P12預留參數。- 新增
SqlBI/TWORK_AI_GET_VIEW_COLUMNS.sql(csa 庫,查 INFORMATION_SCHEMA 欄位/型別)。
- 新增
SqlBI/TWORK_AI_SYNC_PERMISSION.sql(csa 庫):同步 AI 帳號(預設 foxaiexec)的 view SELECT,
先清空既有再依
_ai_schema重建(idempotent,白名單移除的 view 會被收回)。由
TWORK_AI_GET_SCHEMA末尾自動呼叫,亦可單獨EXEC TWORK_AI_SYNC_PERMISSION '帳號名'。ChatAgentViewModel:AI 連線改讀_prgpar的AI_DB_CONN(AI 專用帳號、指向 log 庫);
未設定時退回 ERP 主連線(舊行為,過渡用)。
Migration Notes(DB 部署清單)
log 庫(darbXXXlogN):
1.
DARB_LOG_SYS_AI_EXECproc(複製DARB_LOG_SYS_EXEC,改寫log_sys_ai)— 已由 DBA 建立2.
log_sys_ai表(複製log_sys結構,pkid需保留 IDENTITY)3.
proc_param登錄三筆轉發規則:```sql
INSERT INTO dbo.proc_param (datafunc, databaseid, param_qty, paramoutput) VALUES
('TWORK_AI_QUERY', 'C', 4, 'N'),
('TWORK_AI_GET_USER_SCHEMA', 'C', 1, 'N'),
('TWORK_AI_GET_VIEW_COLUMNS', 'C', 1, 'N');
```
4. AI 帳號
foxaiexec:同時是連線帳號與 dispatcher 的執行身分。dispatcher 的
WITH EXECUTE AS 'foxrunprg'改成WITH EXECUTE AS 'foxaiexec'(DBA 重部署)。ALTER DATABASE [<log庫>] SET TRUSTWORTHY ON(跨庫 token)。建帳號與授權見
SqlBI/AI_ACCOUNT_SETUP.sql(log 庫:EXECUTE dispatcher + 稽核表權限)。csa 庫(darbXXXcsaN):
1. 部署更新後的
SqlBI/TWORK_AI_QUERY.sql(無LP_DATAEVENT版)、SqlBI/TWORK_AI_GET_SCHEMA.sql、新的
SqlBI/TWORK_AI_GET_VIEW_COLUMNS.sql、SqlBI/TWORK_AI_SYNC_PERMISSION.sql2.
foxaiexecuser +GRANT EXECUTE三支 AI proc(見AI_ACCOUNT_SETUP.sql)3.
EXEC TWORK_AI_GET_SCHEMA(填_ai_schema白名單;末尾自動呼叫TWORK_AI_SYNC_PERMISSION同步 foxaiexec 的 view SELECT)
第二道防線:foxaiexec 在 csa 庫只有白名單 view 的 SELECT(由
TWORK_AI_SYNC_PERMISSION先清空再重建)。
TWORK_AI_QUERY內的動態sp_executesql以 foxaiexec 權限執行——AI 的 SQL即使騙過字串掃描白名單,非白名單 view 仍因無 SELECT 權限被 DB 擋下。
系統參數(
_prgpar):AI_DB_CONN=Data Source=<server>;Initial Catalog=<log庫>;User ID=foxaiexec;Password=<密碼>;TrustServerCertificate=True
Breaking Changes
- 舊版(直呼
TWORK_AI_QUERY/直查_ai_schema)的 client 與新部署不相容,程式與 SqlBI 腳本需一起部署。
proc_param三筆未登錄時,dispatcher 會回空@result,C# 端丟出含修復指引的錯誤。
- 新增共用
-
06-04 sliy-excel-import-bulk-perf ▸
2026-06-04 總帳傳票 Excel 匯入:大批效能、驗證與崩潰修正
摘要
總帳傳票(SLIY)的「Excel 匯入」在匯入大量分錄時又慢又會崩潰、且不合法資料照匯。本次將大批匯入降到秒級、修正崩潰,並在匯入前整批驗證、不合法即中止。
變更
- 匯入大幅加速:6,000+筆從數十秒/分鐘級降到秒級。原本每多 500 列耗時不降反升(O(N²)),現已消除。
- 不合法資料不再被匯入:匯入前先驗證所有列的科目代號(須存在且「可輸入傳票」)。只要有任一列不合法,整批中止,並以單一視窗列出所有問題列(標示 Excel 實際列號與原因),不再逐列跳出大量訊息框。
- 讀檔失敗有明確提示:Excel 檔損毀/被開啟/格式不符時,顯示明確訊息而非讓程式崩潰。
修正
- 修正大批匯入時偶發的程式崩潰(
ExecutionEngineException)。
刪除
- 無(移除的是開發期間的暫時性效能量測碼,對使用者無影響)。
Breaking Changes
- 無。匯入後的金額、匯率、借貸合計與修正前一致。
Migration Notes
- 無需資料或設定遷移,更新版本後即生效。
詳見 ADR 0028。
-
06-04 scx-arp-query-fixes ▸
2026-06-04 應收應付查詢類(SCX_ARP)VFP 對比批次修正
摘要
對 SCX_ARP library 的 5 支查詢/報表類(
pay_qry0/pay_qry1/rec_qry0/rec_qry1/rp_balance)完成 VFP↔新版逐項對比,並修掉第一批「純 bug、不涉業務判斷」的問題。SP 接線與報表頁結構本就移植完整,問題集中在 copy-paste 殘留與日期基準語意。變更
- 應收帳齡 / 應付帳齡:帳齡分界基準日
- 「截止日期」查詢模式下,帳齡桶與會計師帳齡的分界改以使用者輸入的截止日為基準(對應 VFP
L_DATE=CTOD(截止日期)),不再一律用今天。「現有餘額」模式維持以今天為基準。- 影響:
ApAgeHelper/ApAgeBll、ArAgeHelper/ArAgeBll(新增BaseDate,傳入兩個 helper 並用於會計師帳齡)。- 應收帳款查詢(Rec_qry0)年度統計表
- 兩個年度統計 grid 的
ProgramClass由誤植的Pay_qry0改為Rec_qry0(修正欄位設定/權限抓錯模組)。- 欄頭由「廠商代號 / 廠商名稱」改為「客戶代號 / 客戶名稱」。
- Excel 匯出頁籤名由「應付帳款…」改為「應收帳款…」(彙總/明細/年度共 5 個頁籤)。
- 應收 / 應付帳款查詢明細表:統一編號欄
-
Rec_qry0與Pay_qry0明細的taxIDColumn原綁定稅別(與前一欄重複、統一編號永遠看不到),更正為綁定並顯示統一編號。- 應收應付餘額表(Rp_balance)本期沖帳區間
- 本期沖帳日期條件由半開區間
< 截止日改為閉區間<= 截止日(對應 VFP),截止日當天的沖帳不再被漏算。- 查詢條件預設值:截止廠商 / 截止客戶
- 上界預設由
zzzz(4 碼)改回zzzzzz(6 碼),避免代號 >4 碼且以 z 開頭時漏抓尾端資料。涉及ApageParameters/ArageParameters/Pay_qry0Parameters/Rec_qry0Parameters。批次 2(2026-06-04 同日)
- 應付帳齡 / 應收帳齡:結帳年月預設改為上月
-
ApageParameters/ArageParameters的 結帳年度/結帳月份 預設由「當月」改為AddMonths(-1)(上月),對應 VFPDATE()-30並與Pay_qry0/Rec_qry0一致。修正月初查詢時前期/本期分欄歸屬。- 應收帳齡:截止日期模式結帳年月
/0bug
- 移除
ArAgeBll在截止日期模式下用EndingDate.Substring(4,2)覆寫結帳月份的程式碼:截止日格式為yyyy/MM/dd,該寫法取到"/0"而非月份,導致前期/本期分界全錯。改為一律採用使用者輸入的結帳年度/月份(對應 VFP,且與應付帳齡ApAgeBll一致)。- 應收帳齡:移除「報表別」誤解的死碼
-
ArAgeBll內以財務類別 24/29 過濾的註解碼為對 VFP「報表別」的誤解,已移除並加正解說明。VFP「報表別(一般/會計師簡表)」實為 應收明細 頁的 Excel 匯出選項(會計師簡表=精簡欄位、僅未收原幣<>0),非資料過濾。Breaking Changes
無。皆為回復 VFP 行為的修正。
Migration Notes
無需資料遷移。
LogicBll已dotnet build通過(0 errors);XAML / ViewModel 變動(binding/header/匯出標題)需於 Visual Studio 重新建置確認。批次 3 — 逐欄 binding 掃描(2026-06-04 同日)
對 5 支查詢 XAML 做逐欄
DataMemberBinding↔ Poco 屬性 cross-check,又揪出 3 個「binding path 打錯、不會 build error 但欄位永遠空白」的 bug:Pay_qry0.xaml:262出納分錄「收付款日」欄綁收付款日,但Group4Poco屬性是收付款日期→ 改綁收付款日期。
Arage.xaml:546應收明細「公司」欄綁公司名稱,但ArDetailPoco屬性是公司簡稱→ 改綁公司簡稱(Header 一併改為公司簡稱)。
Arage.xaml:602應收明細「收款日期」欄綁收款日期,但ArDetailPoco屬性是收款日→ 改綁收款日。
其餘 4 支(Rec_qry0 / Apage / Rp_balance 全綁定正確;Pay_qry0 僅此一處)。掃描共驗約 500+ 欄。
Rec_qry0另有 2 處 Header 與欄位名語意不同(明細「財務分類」綁單據名稱、產品「財務名稱」綁單據分類)— 資料正常顯示,疑似刻意改標題,未動,待業務確認。批次 4 — 會計師簡表匯出(2026-06-04 同日)
- 應收帳齡 / 應付帳齡:Excel 多加「會計師簡表」頁籤(對應 VFP
rec_qry1/pay_qry1報表別=會計師簡表)。
- 精簡欄位:
立帳日期, 傳票號碼, 帳款單號(=財務單號), 客戶/廠商代號, 客戶/廠商簡稱, 幣別, 原幣餘額(=未收/未付原幣), 本幣餘額(=未收/未付本幣), 到期日。- 過濾與排序比照 VFP:僅
未收/未付原幣<>0,依 客戶/廠商代號 + 立帳日期 排序。- 實作:新增
AccountantArSimplePoco/AccountantApSimplePoco兩個精簡 DTO;Rec_qry1ViewModel.GenerateExcel/Pay_qry1ViewModel.GenerateExcel各加一個會計師簡表頁籤。決策:採「多加一個頁籤」而非新增 UI 切換或取代明細頁籤。- 順手修
Pay_qry1ViewModel.GenerateExcel的複製貼上錯誤(AP 模組沿用了 AR 字樣):頁籤名「未收帳款彙總表/明細表」→「未付帳款彙總表/明細表」;匯出檔名"Arage"→"Apage"。
待確認(仍未實作,需業務拍板)
- 會計師 24 個月帳齡表(表A)、Rp_balance 蘇州
RP_BALANCECN版屬公司特定客製,預設不做。
-
06-04 psheet-closingbook-param ▸
2026-06-04 付款單(Psheet)存檔關帳日參數修正
摘要
VFP→TsERP 對比
psheet(付款單主檔)時發現存檔(allowsave)的關帳日檢查用錯系統參數,已修正。變更
PsheetSave.AllowSave的關帳日期檢查由U_Prgpar("2033")(收款單關帳日期,疑似複製自RsheetSave)改為new Util2017(Context).U_PrgparSql("2001")(會計參數表禁修日期)。
- 對應 VFP
psheetallowsave 的U_PRGPARSQL(2001),並與同模組PsheetEdit.AllowEditHandle(本來就用 2001)一致。- 修正前:付款單存檔與修改/刪除走「不同關帳閘門」(save 用 2033、edit 用 2001),可能在禁修日後仍能存檔、或被收款單關帳日誤擋。
Breaking Changes
無。回復 VFP 行為。
Migration Notes
LogicBll已dotnet build通過(0 errors)。待處理(同次對比發現、未在本次修)
psheet/rsheet 尚有數項偏離 VFP(addagain 未清沖帳備註、rsheet 公司代碼 Save 未補預設、rsheet 沖帳方式無輸入欄、批次電匯仍用舊 WindowHelper、FsheetEdit 缺關帳日檢查)與需業務確認項(rsheet 轉票據 else7 受參數 2035 控制、工作流程 else5、付款匯率日整套)。詳見 memory
scx-arp-query-compare-progress(含主檔段)。 -
06-03 sliy-forbidden-voucher-early-prompt ▸
總帳傳票(sliy)「禁止輸入傳票」改為科目格子當下攔截、焦點留在格內
摘要
總帳傳票(
Sliy,程式代號 SLIY,另含 Budget、Sliyyear)輸入會計科目時,若該科目「輸入傳票」非 Y(統制/標題科目),原本只在整列提交(RowValidating)時才擋;現改為在離開科目代號格子前(CellValidating)就攔截,提示「本科目禁止輸入傳票」並把焦點留在科目格子內,游標不會跳到下一格,逼使用者當下改正。變更
InjectAcclValidationRuleBehavior:除原本的RowValidating外,新增訂閱CellValidating。只針對「科目代號」欄(依DataMemberBinding路徑判斷),輸入禁止入帳的科目時設e.IsValid = false(取消提交、焦點留格內)+e.ErrorMessage,並顯示訊息。
AcclValidation.CanInputVoucher(glAccountCode, out msg):新增的輕量檢查方法,只驗「輸入傳票」必須為 Y;查無科目時不在此擋(交給 RowValidating 完整檢查)。
- 「禁止輸入傳票」的攔截集中在 CellValidating,不放在
OnDetailGLCodeChanged(該處於格子提交後才執行、留不住焦點);常用摘要自動帶入仍維持在OnDetailGLCodeChanged。
新增 / 刪除 / Breaking Changes
無資料欄位異動;無 Breaking Changes。
Migration Notes
- 整列提交時的
RowValidating完整驗證(科目存在性、控制方式 1~9、客廠別等)維持不變,仍為存檔前最後防線。
- 其他需整列欄位齊全才能判斷的控制驗證(索引/部門/客廠等)仍留在 RowValidating 階段,未改於離開單一格子時觸發。
- 程式化批次填入(如 Excel 匯入)不經過 UI 編輯、不觸發 CellValidating,禁止科目仍由 RowValidating/存檔驗證攔下。
-
06-03 accl-default-memo ▸
會計科目(accl)新增「常用摘要」欄位
摘要
會計科目主檔(
Accl,程式代號 ACCL)新增「常用摘要」輸入欄位。資料模型、DB view 與總帳傳票(sliy)帶入邏輯原本就支援此欄位,僅缺主檔的輸入介面,本次補上。新增
Accl.xaml:在「英文名稱」與「大分類」之間(原 Row 3 空列)新增「常用摘要」標籤 + 文字輸入框,綁定常用摘要屬性(Twork_acc_vw_acclSource,長度 80)。
- 多語系字串
常用摘要(DefaultMemo):加入Common/Lang/Xaml/Accl.json與TsERP/Lang/Xaml1/Xaml.json。
變更
無。
刪除
無。
Breaking Changes
無。
Migration Notes
- 無需資料庫異動:
常用摘要欄位於Twork_acc_vw_acclview 既已存在。
- 行為延續:在會計科目設定「常用摘要」後,於總帳傳票(sliy)輸入該科目且該列摘要為空時,會自動帶入此摘要(既有邏輯,見
SliyViewModel.OnDetailGLCodeChanged)。
-
06-02 sliy-save-checks-and-excel-import ▸
2026-06-02 總帳傳票(Sliy):存檔檢查補強 + Excel 匯入分錄
摘要
依 VFP 舊版 sliy 補齊三項:原幣借貸不平衡會跳提示、存檔時擋無效/空白傳票日期、新增「Excel 匯入」分錄按鈕。
新增
- 傳票編輯區新增「Excel 匯入」按鈕:可從 Excel 匯入分錄(第 1 列為標題,第 2 列起 A 欄=科目代號、C 欄=原借方金額、D 欄=原貸方金額),匯入時自動帶本位幣、匯率 1 並換算本幣金額。對應舊版 excel轉入鈕。
變更
- 存檔時若原幣借貸不平衡,會跳提示(僅提示、不阻擋存檔;本幣借貸不平衡仍阻擋)。先前此提示不會出現。
- 存檔時若傳票日期空白或非有效日期,會阻擋並提示(對應舊版檢查)。
- 科目代號驗證新增「本科目禁止輸入傳票」檢查:科目的「輸入傳票」非 Y(統制/標題科目)時,該分錄列驗證不通過、無法存檔(對應舊版 sql_acclno1.Valid,先前漏移植)。新增訊息
ThisGLAccountCannotInputVoucher。
- 科目控制方式驗證(分類索引/部門/客廠/項目/員工/專案/產品群組必填)改為「新增(A)與修改(E)的列」都驗證;先前只驗新增列,編輯既有列不重驗。
- 輸入科目代號時的自動補平金額改為「本幣設精確、原幣=本幣÷匯率」(對應舊版);先前以原幣四捨五入回算本幣,外幣情況可能造成本幣借貸差 1 而擋存。
- 輸入科目代號時,若科目有設「常用摘要」且該列摘要為空,自動帶入常用摘要(對應舊版,先前未做)。
- 明細的「金額」改為隨數量/單價/折扣自動計算:金額 = 四捨五入(數量 × 單價 × 折扣, 幣別小數位);新增明細的折扣預設為 1(對應舊版,先前完全沒做此計算、折扣預設 0 會算出 0)。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。Excel 匯入的欄位格式:A=科目代號、C=原借方金額、D=原貸方金額,資料自第 2 列開始。
-
06-02 radgridview-horizontal-scroll-fix ▸
2026-06-02 修正 RadGridView 水平捲軸間歇拖不動
摘要
修正資料表(RadGridView)水平捲軸「有時拖得動、有時拖不動」的問題,常見於傳票 Sliy 等欄位很多的明細頁。修正後水平捲軸可穩定拖曳、可捲到最右側欄位。
變更
- 全系統資料表關閉「欄虛擬化」(
EnableColumnVirtualization=False),改在共用樣式統一設定。原因是寬表的 off-screen 欄未被量測會讓水平捲動範圍算錯,導致捲軸拖不動。詳見 ADR 0026。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。
- 全系統資料表關閉「欄虛擬化」(
-
06-02 ftrlima4-fsheetimport-edge-fixes ▸
2026-06-02 零用金支出/財傳單快速輸入:邊角補齊
摘要
依 VFP 舊版補齊零用金支出(Ftrlima_4)與財傳單快速輸入(FsheetImport)幾項細節。
新增
- 零用金支出:新增「全選 / 全部不選」按鈕,一鍵全勾/全不勾並即時更新金額彙總(對應舊版全選鈕/不選鈕)。
變更
- 財傳單快速輸入:載入既有分錄時,略過沒有科目代號或已標記刪除的列(對應舊版只載入有效分錄)。
- 財傳單快速輸入:新增空白列時,摘要自動帶入上一列摘要,省去重複輸入(對應舊版摘要自動帶值)。
- 財傳單快速輸入:查詢匯率時,外幣有帳戶的列改為「貸方(付款)用銀行日報表帳戶匯率、借方(收款)用掛牌買價」,與舊版一致(先前一律用銀行帳戶匯率)。
已知未調整
- 財傳單快速輸入查詢匯率的「掛牌買價取前一營業日(T-1)」日期慣例尚未調整,待確認新版匯率 SP 與「付款匯率日」是否已內含 T-1,避免重複位移。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。
-
06-02 ftrlima4-amount-summary ▸
2026-06-02 零用金支出:補本幣/原幣金額彙總顯示
摘要
「零用金支出」(Ftrlima_4) 視窗補上舊版有、新版漏掉的「原幣金額彙總/本幣金額彙總」即時顯示。勾選/取消勾選主檔列時,下方會即時顯示目前已勾選單據其明細的原幣含稅、本幣含稅合計。
新增
- 視窗底部左側顯示「原幣金額彙總」「本幣金額彙總」兩個唯讀金額欄。
- 數值 = 所有已勾選主檔列其明細的
原幣含稅/本幣含稅加總,隨勾選即時更新。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。
-
06-02 fsheetimport-copy-group-and-currency-balance ▸
2026-06-02 財傳單快速輸入:複製分組修正 + 原幣不平衡提示
摘要
「財傳單快速輸入」(FsheetImport) 的「複製」會把複製出來的分錄列沿用原本的組數,導致之後「查詢匯率」計算各組匯兌損益時把原組與複製組混在一起算錯。已修正為複製時掛新組數。另補上原幣借貸不平衡的提示(對應舊版行為)。
變更
- 複製:複製出來的分錄列改掛新的組數(
Detail.Max(組數)+1),成為獨立分組,匯兌損益依組正確計算。
- 確認/存回時:原幣借貸不平衡會跳提示(僅提示、不阻擋存檔);本幣借貸不平衡維持原本的阻擋。
影響
- 複製分錄後再查詢匯率,匯兌損益分組計算正確。
- 原幣借貸不一致時會多一個提示視窗(不影響可否存檔)。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。
- 複製:複製出來的分錄列改掛新的組數(
-
06-02 fsheet1-bill-wire-fx-recompute ▸
2026-06-02 批次改財傳單日期:補票據/電匯外幣匯率重算
摘要
「批次改財傳單日期」(fsheet_1) 在變更付款日期時,原本只重算沖帳分錄的匯率,票據與電匯的外幣匯率沒有跟著新日期更新(電匯本幣金額也未重算)。對照 VFP 舊版
修正匯率補齊,使三類資料一致。變更
Fsheet_1Bll.ChangeRate()新增票據(Detail1)、電匯(Detail2) 兩段重算:幣別=本位幣→匯率 1;金額>0 取匯率表(使用匯率),否則取帳戶日報表匯率。電匯另以CalculateAmount()重算本幣金額(=金額×匯率,依幣別小數位)。
影響
- 含外幣票據/電匯的財傳單,批次改日期後其匯率與電匯本幣金額會更新為新付款日期對應的匯率(先前維持查詢當下的舊值)。本位幣資料不受影響。
Breaking Changes
無。
Migration Notes
無需操作;更新版本後即生效。
-
06-02 ai-agent-mcp ▸
2026-06-02 — 全新 MCP-first 內嵌 AI 智慧助理
摘要
主視窗 AI 按鈕改開啟全新的「AI 智慧助理」對話視窗:使用者用自然語言查詢 ERP 唯讀資料、或要求分析出圖(Vega-Lite,WebView2 渲染)。底層採 MCP-first 架構,工具由本機 stdio MCP server 暴露,同一支 server 也能掛進 Claude Desktop / Claude Code。資料存取走 DB 既有的
TWORK_AI_QUERY閘道(LLM 寫 SELECT → proc 驗證/白名單/限筆/稽核後執行)。同時清理數支舊 AI 試作(含一支外洩 OpenAI key 的檔案)。新增
- 新專案:
-
TsErp.Ai.Core:ClaudeClient(串流 + 工具迴圈 + prompt caching)、IAiTool/ErpToolContext、McpClientHost、VegaSpecBuilder、McpServerLocator、JsonDefaults(中文不 escape)。-
TsErp.Ai.Tools:4 支工具list_views/describe_view/run_sql/run_analysis;AiQueryExecutor(呼叫dbo.TWORK_AI_QUERY)、CatalogSqlReader(catalog 直查_ai_schema/INFORMATION_SCHEMA)、ViewCatalogLoader、ErpAiToolRegistry。-
TsErp.Ai.Mcp.Server:MCP-over-stdio(JSON-RPC 2.0)server exe。- WPF:
ViewModel/AIQuery/ChatAgentViewModel.cs+TsERP/AIQuery/ChatAgentView.xaml(.cs)(TelerikRadChat+ WebView2 圖表區);App.xaml加ChatAgentViewModelDataTemplate。
- 可查資料:以 DB 的
_ai_schema為準(執行期載入;實測 darbnogicsa1 有 272 個可查 view),唯讀。加可查表 = 改_ai_schema,不需改程式。
.mcp.json加tserp條目,供 Claude Code / Desktop 掛載同一支 server(Windows 驗證免帳密;env 帶TSERP_AI_RO_CONN/TSERP_AI_DB)。
資料存取(LLM 寫 SQL → TWORK_AI_QUERY)
run_sql/run_analysis接收 LLM 寫的 SELECT,經dbo.TWORK_AI_QUERY執行:該 proc 強制只准 SELECT、擋寫入/危險關鍵字、FROM/JOIN表須在_ai_schema白名單、自動TOP限筆、寫_ai_query_log稽核。
- 初版的「結構化參數 + 程式直查 + 程式白名單」(
QueryDataTool/WhitelistSql/PlanRunner/ReadOnlySqlExecutor) 已移除,改由 DB 閘道把關(見 ADR 0027 演進紀錄)。
變更
- 主視窗 AI 按鈕(
MainWindowBtnAIViewModel.Execute)→ 開啟新ChatAgentViewModel(ShowAiWindow())。
WindowService.ShowAiWindow():由舊AIQueryViewModel改為ChatAgentViewModel。
FoundryPlanService:移除把 AI 輸出寫死到C:\temps\tt.json的 debug 寫檔(此服務仍由Qc_qry3使用,未刪)。
刪除
Common/AI/ChatGptHelper.cs(含明文 OpenAI service-account key,僅一處註解引用,已刪除;該金鑰應於 OpenAI 後台撤銷)。
- 舊 AIQuery 視窗:
ViewModel/AIQuery/AIQueryViewModel.cs、TsERP/AIQuery/AIQueryView.xaml(.cs)、LogicBll/AI/AIQueryBll.cs、App.xaml對應 DataTemplate。
- 語音 AI:
ViewModel/MainWindowPage/AIPageViewModel.cs、TsERP/AIRightSide.xaml(.cs)、Common/TsAzure/SpeechHelper.cs,及其 DI 註冊與 MainWindow VM 注入。
設定需求(系統參數表 `_prgpar`)
CLAUDE_API_KEY(必填):Anthropic Claude API 金鑰。
CLAUDE_MODEL(選填):預設claude-sonnet-4-6。
AI_MCP_SERVER_PATH(選填):MCP server exe 路徑,預設自動尋找。
Breaking Changes
- 舊「AI 資料查詢助理」(AIQuery,自行產 SQL 執行)已移除,由新「AI 智慧助理」取代;查詢改走白名單工具,行為與可查範圍不同。
- 語音 AI 頁面移除。
Migration Notes
- 建置
TsErp.Ai.Mcp.Server(已設為 TsERP 建置相依,會自動先建)。WPF 端由McpServerLocator自動定位 exe;部署時請確保 server 輸出檔與主程式同目錄或以AI_MCP_SERVER_PATH指定。
- 唯讀保證目前以
ApplicationIntent=ReadOnly暫代,建議後續改用專用唯讀 SQL 帳號(DB 層防寫)。
- 安全:請至 OpenAI 後台撤銷舊
ChatGptHelper內的 service-account key。
相關
- [[ADR 0027 — MCP-first 內嵌 AI Agent]](../decisions/0027-mcp-first-ai-agent.md)
-
06-01 usp-新增程式-stored-proc ▸
2026-06-01 新增 `usp_新增程式` 預存程序
摘要
新增一支 SQL Server 預存程序
dbo.usp_新增程式,用來「一次登錄一支新程式」,自動寫入下列 5 張系統表,省去逐表手動 INSERT。已部署於 darbnogicsa1。
程式碼版控於
sql/usp_新增程式.sql。新增
sql/usp_新增程式.sql— 預存程序原始碼。
- 一次寫入:
| 表 | 列數 | pkid |
|----|------|------|
|
_menum(程式主檔)| 1 | 手動 MAX+1 ||
_menud(選單明細/所屬模組)| 1 | 手動 MAX+1 ||
_sheetno(單號設定)| 1 | identity 自動 ||
_tableseq(資料表序號)| 1(該表不存在才補)| 手動 MAX+1 ||
prgsct1(程式權限)| 每使用者 1 列 | 手動 MAX+1 連號 |行為重點
- 跨表關聯鍵:
_menum.類別名稱/_sheetno.單據別/prgsct1.類別名稱= 英文
ProgramClass;
_menum.程式名稱/_menud.程式名稱= 中文顯示名稱。- prgsct1 每使用者一筆:對既有
prgsct1的DISTINCT linkid(= 全部使用者)
逐一產生一列,
linkid即使用者鍵。- 6 個主要權限(瀏覽/明細/修改/新增/刪除/列印)由參數帶入。
- 其餘權限欄位(其他 1–36、看單價、xls、pivot、mail、流程、附件、複製、審核、
自動審核等)一律重設為 0/空白,不繼承任何範本。
- 不讀取
secret1帳密表。- 共通系統欄位:
srvdbid取自現有資料、logid=0、管制碼=0、增刪修/選擇空白、
輸入日期/人員/地點自動帶入。- 防呆:程式代號/選單序號重複、
prgsct1無資料、@建立單號=1卻缺@資料表名稱
皆會
RAISERROR並中止;全程包在BEGIN TRAN+SET XACT_ABORT ON。呼叫範例
EXEC dbo.usp_新增程式 @程式代號 = N'CHKRB', @程式名稱 = N'標準成本與進貨比較B', @序號 = N'M-11', @按鈕名稱 = N'K.成本管理', @說明事項 = N'標準成本與進貨比較B', @資料表名稱 = N'chkrb_m', @前置碼 = N'CB';Migration Notes
- 目前僅部署於 darbnogicsa1(VFP 原始表名
_menum/_menud/_sheetno/_tableseq/prgsct1)。
- 其他客戶庫若採
twork_sys_*前綴 schema(如 darbzdcsa1),欄名與 identity 設定不同,
需另寫版本,不可直接套用本程序。
-
06-01 secretbrowsepage-detail-radgridview ▸
SecretBrowsePage 明細改用 TsBrowseRadGridView
摘要
TsERP/BrowsePage/SecretBrowsePage.xaml(權限瀏覽頁)的明細 grid 從舊的TsControl:TsDataGrid改成tsTelerik:TsBrowseRadGridView,與主檔一致,並對齊通用瀏覽頁TsControl/Layout/ErpBrowse.xaml的 master/detail pattern。變更
- 明細 grid 由
TsControl:TsDataGrid→tsTelerik:TsBrowseRadGridView(x:Name="DgDetail")。
- 改綁
DetailViewModel(TsBrowseDataGridViewModel)的DataView/Schemas,AutoGenerateColumns="True"依 DB schema 動態產生欄位。
- GridSplitter 加上
Visibility="{Binding DetailViewModel.Visibility}",與通用瀏覽頁一致。
- 移除明細寫死的 35+ 個
DataGridTextColumn/DataGridTemplateColumn(Allow* 權限 checkbox)與TsView.Resources內僅供舊欄位用的HeaderCenter、Chkstyle。
修正
- 舊明細 grid 綁
ItemsSource="{Binding DataTableItemsSource}",但其 DataContextDetailViewModel是TsBrowseDataGridViewModel,該型別沒有DataTableItemsSource屬性(只有TsDataGridViewModel才有)。主檔早先已遷移到 browse VM,明細卻未同步,導致明細實際綁不到資料。本次一併修正。
Breaking Changes
無。明細為唯讀瀏覽,欄位改由 schema 動態產生(與其他模組瀏覽頁行為一致);權限旗標以欄位值呈現,不再是唯讀 checkbox。
Migration Notes
無需資料庫或設定變更。
- 明細 grid 由
-
06-01 radgridview-session-sort-persist ▸
TsRadGridView 臨時排序跨畫面切換自動保留
摘要
TsControl/TsTelerik/TsRadGridView.cs新增「執行階段版型暫存」機制:使用者在 grid 上臨時排序(或調欄寬、欄序、群組)後,切到別的畫面再切回來時排序會自動保留,不需要手動點右鍵的「記憶格式」。此機制對全 App 所有TsRadGridView(含繼承的TsBrowseRadGridView)一體生效。背景
本專案切畫面採「換 VM + DataTemplate 重建畫面」模式,切回來時 grid 是全新實例。Telerik
RadGridView的排序狀態(SortDescriptors)只活在該 grid 控件實例上、不在資料來源(DataManager.GridView)上,且原本只有按「記憶格式」(Serialize()寫入 SQL) 才會被保存。因此臨時排序在切畫面後就消失。新增
- 靜態記憶體快取
_sessionFormatCache(Dictionary<string,string>,key =TsDataGridTag=ProgramClass + grid 名稱)。
SaveSessionFormat():Unloaded時用現成的PersistenceManager.Save把目前版型(含排序/欄寬/欄序/群組)序列化存入快取。
變更
TsRadGridView_Unloaded在解除事件掛勾後,多呼叫一次SaveSessionFormat()。
LoadSetting():在讀完 SQL 永久版型後,再套用 session 快取的版型(較新,覆蓋上去),讓切回來的新 grid 還原臨時排序。
行為
- 純記憶體、不寫 SQL:不影響、也不取代「記憶格式」功能(永久保留仍走「記憶格式」→ SQL)。
- App 關閉後快取清空(下次開啟回到 SQL 永久版型或預設)。
- 套用順序:SQL 永久版型 → session 暫存版型(session 較新者勝)。
- 因走整份
PersistenceManager版型,連同欄寬/欄序/群組也會一併在切換間保留,而不只是排序。
Breaking Changes
無。屬於行為增強;既有「記憶格式」(SQL) 流程與資料不受影響。
Migration Notes
無需資料庫或設定變更。
---
修正(2026-06-05):排序/群組改走獨立記憶體快取
問題
上述機制原以為靠
PersistenceManager.Save/Load即可保留排序,實際上排序完全沒被保留。根因:全域註冊的
TsGridViewCustomPropertyProvider只持久化Columns,SortDescriptors/GroupDescriptors的持久化被註解掉,且InitializeObject在還原時主動Clear()排序與群組。因此經 PersistenceManager 的版型一律不含排序。
決策
- 「記憶格式」(SQL 永久版型) 刻意不含排序 —— 維持現狀。
- 排序/群組只在執行階段記憶體快取裡跨畫面保留。
兩個關鍵根因
1. 排序不掛在
this.SortDescriptors。 本專案多數 grid 的ItemsSource綁的是QueryableCollectionView(DataManager.GridView,或直接{Binding Xxx.GridView}而未設DataManagerDP)。Telerik 文件明載:ItemsSource 若已是 QCV,grid 直接使用該實例,排序/群組進的是那個 QCV 的
SortDescriptors/GroupDescriptors,this.SortDescriptors恆為空。所以連
CollectionChanged都不會在this.SortDescriptors上觸發。2. 不能等到
Unloaded才讀。 切畫面Unloaded會 detachItemsSource,太晚。變更(hook 綁定 QCV + eager capture)
_sessionFormatCache值型別由string改為SessionFormat(Xml+Sorts+Groups)。
- 排序/群組改用
Proxies.cs既有的SortDescriptorProxy/GroupDescriptorProxy存進記憶體,
繞過 PersistenceManager,因此不會被「記憶格式」一起寫進 SQL。
- 新增
BoundQcv(ItemsSource as IQueryableCollectionView ?? DataManager?.GridView)與
EffectiveSortDescriptors/EffectiveGroupDescriptors:排序真正掛的集合(綁 QCV 走 QCV,否則退回 grid 自身)。
- 排序/群組改為「變更當下即時寫快取」:
Loaded後HookSortGroupChanged()掛勾
綁定 QCV 的
SortDescriptors.CollectionChanged/GroupDescriptors.CollectionChanged(記住實例
_hookedSorts/_hookedGroups,detach 後仍能正確解掛);任何排序/群組變動立刻由CacheSortGroupNow()從該集合讀取寫入快取。SaveSessionFormat()(Unloaded)只更新欄寬/欄序/隱藏的Xml,不動 Sorts/Groups;
Unloaded一開始就UnhookSortGroupChanged()。- 切畫面回寫防護:切畫面 detach 會把
ItemsSource設 null、連帶清空 QCV 排序並觸發
CollectionChanged。OnSortGroupChanged以!IsLoaded || ItemsSource == null擋掉這種「teardown 清空」——此時
ItemsSourceDP 已是 null(DP 先賦值、再跑變更處理清排序),守門成立,不會用空排序蓋掉快取。正常使用中
IsLoaded=true、ItemsSource有值,照常即時寫。LoadSetting()的ApplySessionSortGroup()還原時套回EffectiveSortDescriptors(即綁定 QCV),
期間以
_suppressSortCache抑制回寫。- 同時支援
ColumnSortDescriptor(UI 排序)與普通SortDescriptor(VM 直接 add,帶Member)兩種型別:
capture 用
SortDescriptorBase/GroupDescriptorBase取鍵(Column.UniqueName或Member),restore 以
ResolveColumnByKey(比UniqueName→SortMemberPath→DataMemberBinding路徑)找回欄位,對得到還原成
ColumnSortDescriptor(含表頭箭頭),對不到則退回普通SortDescriptor(至少資料有排序)。(原本只吃
ColumnSortDescriptor,遇到 VM 預設的普通SortDescriptor(如WkcaldViewModel)會被濾光。)TsGridViewCustomPropertyProvider.cs與Proxies.cs未改。
修正前文校正
本文「新增/變更/行為」段落原稱「
PersistenceManager.Save把目前版型(含排序…)序列化」、「連同…群組也會一併在切換間保留」——就排序/群組而言當時並未成立,以本節為準:
排序/群組走記憶體快取,欄寬/欄序/隱藏才走 PersistenceManager Xml。
- 靜態記憶體快取
-
06-01 operationpanel-ctrl-f12-my-input ▸
2026-06-01 — 操作面板 Ctrl+F12:查詢「我輸入過的資料」
摘要
在表單操作面板新增鍵盤快捷鍵 Ctrl+F12:以「輸入人員 = 目前登入者」為條件,用
DARB_BROWSE的最近輸入筆數模式跑查詢,列出「我最近輸入的 20 筆、依輸入日期由新到舊」,結果直接灌進導覽區的「瀏覽」分頁,停留在目前表單頁面、不切換到瀏覽頁。讓使用者快速看到自己在該表單剛建立過的單據。新增
OperationPanelViewModel.QueryMyInputCommand(ViewModel/Control/PageParts/OperationPanelViewModel.cs)
- 條件:
輸入人員 = N'{Context.User.UserName}'(即「我建的單」)。- 查詢模式:
BrowseQuery(..., lpP3:"1", lpP4:"20"),即DARB_BROWSE @browsecondtype=1(最近輸入筆數)→SELECT TOP 20 ... WHERE 輸入人員=我 ORDER BY 輸入日期 DESC。- 重用既有瀏覽查詢路徑(
BrowseBll.BrowseQuery→DARB_BROWSE→ SQLite 虛擬化IBrowseProvider),主檔表名換成瀏覽用 view(SheetNoMethod.GetBrowseViewName),與ErpBrowseBaseViewModel.GetTablesName一致。- 結果寫進
SupportPanelViewModel.TsBrowseDataGridViewModel,作法比照TsSeekTextBoxViewModel.Seek的 "B"(瀏覽)分支。- 順便把導覽模式切到「瀏覽」:設定
DataNavigatorViewModel.NavigationModeEnum = Browse,等同勾選導覽列的「瀏覽」radio——其 setter 會自動SwitchToBrowseTab(),且讓上一筆/下一筆/第一筆/最後一筆導覽鈕改為操作這份查出來的瀏覽清單(在清單內移動並帶動表單定位)。- 防呆:主檔表為空、或目前在增刪修編輯狀態時不動作(避免覆蓋輸入中的內容);查無資料時於狀態列提示
MessageEnum.NoData。ErpProgramLayout.xaml新增KeyBinding(Key=F12、Modifiers=Control)綁定OperationPanelViewModel.QueryMyInputCommand。放在表單版面層(表單內容與操作面板的共同祖先),焦點在表單任何欄位時都能觸發,作法比照ERPSystemContainerView的全域快捷鍵。
變更
BrowseBll(LogicBll/BrowseAndQuery/BrowseBll.cs)參數化LP_P3/LP_P4:BrowseQuery與GetSqlIntoSqlite原本把DARB_BROWSE的@browsecondtype寫死"2"、@查詢筆數寫死"0",改成可傳參數lpP3="2"、lpP4="0"(預設值不變,現有呼叫端行為不受影響)。讓呼叫端可選lpP3:"1"(最近輸入筆數)並指定lpP4的 TOP N。
- 保底:當
lpP3="1"但lpP4="0"時,自動把lpP4改成"1",避免SELECT TOP 0查不到任何資料。- 方法上方補了完整的 XML 參數說明(
lpP3/lpP4對應的 proc 參數與兩種模式行為)。Breaking Changes
- 無。
備註
- 整合方式為使用者確認後的決策:採「重用既有瀏覽查詢(DARB_BROWSE)」而非直接用
darb_getdata的 DataSet——因為瀏覽格是虛擬化、由 SQLite provider 讀取,無法直接吃darb_getdata的 DataSet;並要求不切換頁面,故灌進導覽區「瀏覽」分頁。
- 建置:
ViewModel與TsControl專案以 VS MSBuild 建置通過(dotnet build因 Office COM 參考的MSB4803 ResolveComReference無法用,需用 VS 版 MSBuild)。TsERPapp 目前另有與本改動無關的 XAML 編譯錯誤(TsERP/Other/Psheet_2.xamldg-to-radgrid 遷移半成品,TsRadGridView.Columns套到TsDataGrid),非本功能造成。
- 前提假設:主檔瀏覽 view 含
輸入人員欄位(標準審核欄位)。若某程式的瀏覽 view 無此欄位,查詢會丟例外並於狀態列顯示錯誤訊息(已 try/catch)。
-
06-01 extension-panel-audit-fields ▸
擴充面板 Popup 新增建檔/輸入/工作流程/聯絡單欄位
摘要
TsControl/PageParts/ExtensionPanel.xaml與TsControl/PageParts/FinancialExtensionPanel.xaml的「加號展開 Popup」中,原本只顯示審核日期 / 審核人員,新增 6 個欄位:建檔日期、輸入日期、輸入人員、輸入地點、工作流程、聯絡單id。新增
兩支面板的 Popup grid 由 2 列擴成 8 列,於審核資訊下方依序新增(皆唯讀):
欄位 控件 備註 建檔日期 TsTextBox 唯讀 string 輸入日期 TsTextBox 唯讀 DateTime→StringFormat=yyyy/MM/dd輸入人員 TsTextBox 唯讀 輸入地點 TsTextBox 唯讀 工作流程 TsTextBox 唯讀 聯絡單id TsTextBox 唯讀 int→StringFormat=N0、靠右- 全部綁
Content.MasterItem.<欄位>,label 用DisplayMeta[<欄位>](FallbackValue 給中文),與既有審核日期/審核人員完全同模式。
- 標籤顏色沿用各面板既有主色:
ExtensionPanel用ImportantColor、FinancialExtensionPanel用SystemGenerateColor。
變更
- 新增欄位皆設
IsReadOnly="True":建檔、輸入、工作流程、聯絡單id 屬系統審核資訊,不開放手動編輯(審核日期/審核人員維持原樣可編輯)。
Breaking Changes
無。屬 UI 顯示增強,不影響資料與既有審核欄位行為。
Migration Notes
- 無需資料庫或設定變更。
輸入日期/輸入人員/輸入地點在SourceBase(每個 master poco 皆有);建檔日期/工作流程/聯絡單id僅存在於部分 Source 類別。
- 面板綁定的
Content.MasterItem為object(任意 master poco),採「字串路徑綁定」:poco 有該屬性即顯示值,沒有則顯示空(FallbackValue)並在 debug 輸出留 binding 訊息,不會 crash。此行為與既有已審核/審核日期/審核人員(同樣非 SourceBase 通用欄位)一致。
- 若要僅在具備這些欄位的特定畫面顯示,可比照
FinancialExtensionPanel對相關單號/傳票號碼的Visibility綁定方式另行控制。
- 全部綁
-
06-01 crash-recovery-no-popup-loop ▸
畫面 render 崩潰不再無限跳窗,改為自動移除壞畫面
摘要
修正當某個程式畫面在 render 途中拋例外(典型如
XamlParseException)時,錯誤視窗會無限重複跳出的問題。改為:同一錯誤只跳一次窗,隨即把壞掉的畫面從導覽移除、清空主內容區,讓 app 繼續可用,而不是反覆洗版或直接關閉整個程式。背景(原因)
「一直跳窗」並非崩潰本身造成,而是復原流程的缺陷:
1. 壞掉的 view 仍是容器(
ErpSystemContainerViewModel)的當前內容,沒有被移除。2. 錯誤用 modal
MessageBox呈現,對話框關閉時觸發主視窗 relayout → 又 render 壞 view → 再拋例外 → 再跳窗,形成迴圈。3.
App_OnDispatcherUnhandledException的迴圈偵測原本用「500ms 內才算重複」的時間窗,但 modal 對話框顯示時間必然 > 500ms,導致重複計數每次被重置、永遠到不了關閉門檻 → 無限跳窗。變更
TsERP/App.xaml.cs—App_OnDispatcherUnhandledException
- 迴圈偵測由「時間差」改為「例外簽章(型別 + 訊息)」比對,不再被 modal 對話框時間打亂。
- 同一錯誤只在第一次跳窗,之後重複只寫 log,不再洗版。
- 每次處理後呼叫復原(見下);同簽章持續重複且復原無效並超過門檻時,才顯示「即將關閉」並
Shutdown。- 新增
TryRecoverFromBrokenView(),從 DI 取IProgramNavigator並呼叫復原(全程 try/catch,復原本身不會再炸)。新增
Common/Interface/IProgramNavigator.cs— 新增bool RecoverFromBrokenCurrentView()。
ViewModel/ProgramNavigator.cs— 實作RecoverFromBrokenCurrentView():把壞掉的當前程式從_programContexts移除、_currentProgramClass設為 null,再SetContainerContext(true)將容器內容清成 null。壞畫面離開視覺樹後 render 迴圈停止;主視窗導覽列保留,使用者可改點其他程式,無需關閉整個 app。下次重新點選該程式會重新建立 context。
Breaking Changes
無 API 破壞性變更(
IProgramNavigator為內部介面,新增方法已在唯一實作ProgramNavigator補齊)。屬全域例外處理策略的行為變更。行為變化與取捨
- 之前:畫面 render 崩潰 → 錯誤視窗無限重複跳出(且因時間窗 bug,原訂的「重複 N 次自動關閉」實際上幾乎不會觸發)。
- 之後:跳一次錯誤訊息 → 自動移除壞畫面、app 續用;真正持續無法復原才關閉。
- 取捨:同一個壞掉的程式若立即再次點選,因例外簽章相同只會靜默復原、不再跳窗(log 仍會記錄)。使用者已看過一次錯誤,可接受。
Migration Notes
無需資料庫或設定變更。
📅 2026 年 5 月 (40 篇)
-
05-29 sppdt-vfp-fixes ▸
2026-05-29 — sppdt(廠商報價)VFP 對比修正
摘要
對比 VFP
scx_pur.vcx的sppdt(廠商報價)後,補回allowsave中三段遺漏的存檔邏輯到SppdtSave。變更
- 無幣別/匯率時預設本幣 + 1:存檔時若
幣別為空且匯率未填(<=0),自動帶入本幣(Context.Env.LocalCurrency)與匯率1(SppdtSave.HandleDataBeforeEndEdit)。未採用 VFP 的U_BLRATE匯率表查詢/無條件覆寫(業務決策)——外幣報價的匯率由使用者自行輸入,已輸入者不覆寫。
- 空明細列自動標記刪除:存檔時,
品號與工程代號皆為空白的明細列自動標增刪修='D',對應 VFPREPLACE 增刪修 WITH 'D' FOR EMPTY(品號) AND EMPTY(工程代號)(SppdtSave.HandleDataBeforeEndEdit)。
新增
- 活動期間驗證:已輸入「活動起始日」但未輸入「活動截止日」時擋存並提示(
SppdtSave.AllowSave),對應 VFP allowsave 同名檢查。
Breaking Changes
- 無。只有在「幣別為空且匯率未填」時才補本幣 + 1;使用者已輸入的幣別/匯率不會被覆寫(業務決策,與 VFP 無條件
U_BLRATE覆寫不同)。
- 備註:新增時
SppdtViewModel.AfterAddNew已預設幣別=本幣、匯率=1,故此存檔保險僅在資料幣別被清空等邊界情況才會觸發。
備註
- VFP 另有事件層邏輯未移植(次要):
幣別.LostFocus即時帶匯率(改由存檔時統一帶)、工程代號對 BOMproces的存在性驗證(VFP 僅提示不擋)。品號歷史單價查詢新版已由 detail listener →QueryCommand涵蓋。
- 建置:
dotnet build LogicBll通過(0 錯誤)。SaveBll 行為面建議由使用者實測:新增→輸外幣→存,確認匯率被帶入;輸活動起始日但留空截止日→存,確認擋下。
- 無幣別/匯率時預設本幣 + 1:存檔時若
-
05-29 rp-m-schema-extend ▸
2026-05-29 — 收付款/財務單(rp_m / rp_d / rpsht)schema 擴充
摘要
替 AR/AP 財務單主子檔(
rp_m/rp_d)與收付款單主子檔(rpsht_m/rpsht_d)新增多個欄位(稅額、含稅金額、備註、建檔日期、第三組單別/單號等),並同步更新對應的 4 個 view 把新欄位帶出來。對應 SQL 腳本:C:\temps\sqlscript\更新rp_m.sql。新增
資料表欄位
rp_m:建檔日期(char 10)、原幣稅額(decimal 19,4)、總原幣未稅(decimal 19,4)、總本幣未稅(decimal 19,4)、含稅別(char 1)
rp_d:原幣稅額、折扣、代工價含稅、其他金含稅、微調原含稅、微調本含稅(皆 decimal 19,4)、備註(nvarchar 120)
rpsht_m:建檔日期(char 10)
rpsht_d:分類索引4(nvarchar 30)、單別3(char 2)、單號3(nvarchar 20)
View 更新(帶出上述新欄位 + sp_refreshview)
vw_rp_m:加建檔日期、原幣稅額、總原幣未稅、總本幣未稅、含稅別
vw_rp_d:加原幣稅額、折扣、代工價含稅、其他金含稅、微調原含稅、微調本含稅、備註
vw_rpsht_m:加建檔日期
vw_rpsht_d:加分類索引4、單別3、單號3(備註改抓rp_m.備註)
變更
- 無(既有欄位/邏輯未改)
刪除
- 無
Breaking Changes
- 無。新欄位皆
NOT NULL DEFAULT,既有資料列以預設值回填,舊程式不受影響。
Migration Notes
- 執行腳本
更新rp_m.sql(依序:ALTER TABLE 加欄位 → ALTER VIEW 4 支 →sp_refreshview)。可整段執行。
- 已修正:原
rpsht_d的單別3/單號3重複 ALTER 已移除;rp_d.備註的 DEFAULT 已由0改為''。
- 對應的 Model/Source(
Twork_arp_*等)若要使用新欄位,需另跑/db-model-compare補上屬性後才會在程式端可用。
-
05-29 remove-rp-m-receipt-xml ▸
2026-05-29 — 移除 RP_M 收據xml 欄位(停用 9B 收據/發票 XML)
摘要
移除 RP_M(rp_m)的
收據xml欄位與其相關的發票 XML 序列化/還原流程。影響財務類別 9B 單據的發票號碼重建。詳見 ADR 0025。變更
- 付款/收款/暫存存檔不再產生
收據xml。
- 9B 單據轉單(RpfZero / Psheet_1)不再從
收據xml還原並覆寫多行「發票號碼」。
- Psheet_1 票據檢核/現金流程的發票號碼累計(
invoiceNO/receiptCount)不再填值(恆為空 / 0)。
新增
無。
刪除
Twork_arp_vw_rp_mModel/Twork_arp_vw_rp_mSource的收據xml屬性。
- 6 處寫入(含
FillXML產生器)、5 處讀取邏輯、語系項ReceiptXML。
- (順帶)Source 端誤掛在
收據xml上的[TsColumnName(使用人)]重複對應。
Breaking Changes
- 9B 單據不再自動把多發票合併顯示在「發票號碼」。
- 依賴 Psheet_1 票據發票號累計的下游(票據分頁/票面發票號)需確認影響。
Migration Notes
- DB 的
收據xml欄位由 DBA 自行處理(移除或保留皆可,程式已不讀寫)。
- DB 內既有的 收據xml 資料不再被使用。
- 付款/收款/暫存存檔不再產生
-
05-29 purch-special-edit ▸
2026-05-29 — purch(採購單)補回「特殊修改」
摘要
對比 VFP
scx_pur.vcx的purch(採購單)發現「特殊修改」按鈕(VFPelse8click,OPMODE=9)在新版未接線——PurchViewModel未宣告IOther3,姊妹類ppurch/fsheet都有。本次補上。變更
- 無
新增
- 特殊修改功能:
PurchViewModel新增IOther3介面與ExtendedFunction3(),呼叫框架AdeViewModel.SpecialEdit(),對應 VFPpurch.else8click(特殊修改 / OPMODE=9)。與姊妹類FsheetViewModel.ExtendedFunction3寫法一致。
Breaking Changes
- 無。新增一顆「其他」功能按鈕(特殊修改);按鈕標題由程式參數/權限設定(資料端)控制。
SpecialEdit刻意比一般編輯寬鬆、不走AllowEditHandle(與 VFP else8 未做 AllowEdit 防呆一致),故未額外加防呆。
備註
- 建置:
dotnet build ViewModel僅剩既有的MSB4803 ResolveComReference工具鏈錯誤(與本改動無關),無 C# 編譯錯誤;最終請在 Visual Studio 內 build 確認。
- purch 仍有未移植項待處理(屬功能新建,本次未動):修改交期(VFP
_CHANGEDATE)、進貨查詢(VFPPURCH_S)、確認(VFP else7,蓋確認章;現有PurchBll.Confirm()為 PO/訂單量差異報告,語意不同且未接線)。見 memoryscx-pur-compare-progress。
-
05-27 sliya5-void-stamp ▸
2026-05-27 傳票 A5 報表補回「本張作廢」章與簽核欄
摘要
比對 VFP 舊報表
sliya5.frx與 FastReport 版Sliy_a5.frx,發現新版漏移植了「本張作廢」作廢章、簽核欄與輸入人員。本次補齊,行為對齊 VFP。新增
- 本張作廢章:傳票
已審核 = 'X'(作廢)時,傳票報表頁首印出紅色作廢章。對齊 VFPsliya5的列印條件已審核='X'。三個版型皆已加入:
-
Sliy_a5.frx(A5)、Sliy.frx(中一刀)→「本張作廢」-
Sliy_e.frx(英文 Letter)→「VOID」- 簽核欄:A5 版(
Sliy_a5.frx)頁尾加「核准/覆核/會計/出納/製單」簽名列。
- 輸入人員:A5 版傳票區塊顯示輸入人員。
- 英文科目名稱:
Sliy_e.frx的科目名稱欄改用英文名稱(英文科目名稱),資料原本已由GetReportSource()由accl.英文名稱帶出。
- 英文公司名稱:
Sliy_e.frx標頭公司名稱由中文[CompanyName]改綁英文[CompanyNameEng](取代,英文報表只顯示英文)。FastReportExtension.SetDefaultReportParameter新增送出CompanyNameEng = EnvironmentSetting.CustomCompanyName(即公司英文名);該參數只有Sliy_e宣告,其他報表不受影響(SetReportParameter只對有宣告的參數設值)。
變更
Model/Rpt/Rpt_N010_SliyReportPoco.cs:新增已審核(C1)屬性。
ViewModel/N.GeneralLedger/GeneralLedger/SliyPrintViewModel.cs:GetReportSource()投影補已審核 = a.已審核,讓匯出到 SQLiterpt_n010_sliy_report1的資料帶上作廢旗標(資料原本已在 masterTworkAccVwSliymRpt.已審核,只是投影時漏掉)。
FastReport/Sliy_a5.frx:資料源加已審核欄;新增TextVoid_BeforePrintscript 依已審核 == "X"控制作廢章顯示;GroupHeader加作廢章與輸入人員;GroupFooter加簽核欄並加高 band。
刪除
無。
Breaking Changes
無。
Migration Notes
- 「作廢」判定沿用 VFP 的
已審核 == "X"。若新系統實際以其他值/欄位標記傳票作廢,需同步調整三張.frx的TextVoid_BeforePrint判斷與後端投影。
Sliy_e.frx的作廢章文字採用英文「VOID」;如需與中文版一致改回「本張作廢」,改該物件Text即可。
- A5 版的簽核欄/輸入人員尚未套用到
Sliy.frx、Sliy_e.frx(本次僅依需求補作廢章);如需一致,比照Sliy_a5.frx加物件。
- 各物件座標為對齊現有版面的擺放,可於 FastReport 設計器微調。
- 本張作廢章:傳票
-
05-27 ppurch-vfp-fixes ▸
2026-05-27 — ppurch(請購單)VFP 對比修正
摘要
對比 VFP
scx_pur.vcx的ppurch(請購單)+ 其開啟的子表單_CSAEDIT(請購單改期別)後,修正一個靜默 binding bug,並補回期別自動分類邏輯。變更
- 請購備註欄位修正:主檔「備註」輸入框原本綁定
{Binding 備註},但 Source 屬性實際是請購備註→ 該欄永遠空白且存不進去;改綁請購備註(Ppurch.xaml)。
- 期別自動分類(補回
_CSAEDIT邏輯):存檔時,若主檔已設「本期」起始日,依各明細的建議行動日落在哪個期間,自動把期別設為 本期 / 下一期 / 下二期 / 其他(PpurchSave.HandleDataBeforeEndEdit)。
- 期別日期遞增驗證:存檔時,若有設期別,檢查 本期A2≥本期A1、下一期A1>本期A2、… 等遞增關係,不符則擋存(
PpurchSave.AllowSave)。
新增
- 無
Breaking Changes
- 無。期別分類與遞增驗證都僅在主檔「本期a1」有值(期別功能使用中)時才生效,未使用期別的請購單存檔行為不變。
備註
- VFP
_CSAEDIT另有「輸入本期A1 自動帶下一/下二期日期(+30/+31/+150/+151/+300 天)」功能,因該天數為特定客戶(凱琦)專屬設定,本次未移植;使用者自行輸入三組期別日期即可,期別分類照樣運作。
- ppurch「轉訂單」(訂單轉請購 / OrmastToPP) 原為半成品,本次重建完成(照 VFP
ODTOPP):OrmastToPPBll.SpecialAdeQuery改接既有 SPDARB_TUR_ODTOPP(手動將中文欄位 map 成英文 Poco),SetUpdateSource補上按「訂單×廠商」分組建立 ppurma/ppurde(金額用既有SetFxRate()/SetAmount());新增Procedure.DARB_TUR_ODTOPP。程式碼編譯乾淨,但尚未 runtime 測試,且外幣匯率取得與分組策略有 caveat(見 memoryscx-pur-compare-progress)。
- 請購備註欄位修正:主檔「備註」輸入框原本綁定
-
05-27 bankfcst-spbank-vfp-fixes ▸
2026-05-27 — bankfcst / spbank / ftrlima / fsheet VFP 對比修正
摘要
對比 VFP
scx_chk.vcx的bankfcst(預估資金表)、spbank(廠商帳戶表)、ftrlima(財務雜項單據)、fsheet(收付款單)後,修正四個與舊系統行為不一致、UI 重複或缺少防呆的問題。另記錄一個待辦(spbank 異動轉檔)。bankacqry(銀行存提表)、bankday(資金日報表)同批對比確認為忠實移植,無需修改。變更
- bankfcst 本幣金額小數位:
存入本幣金額/提出本幣金額原本用外幣(幣別)的小數位數四捨五入,改為用本幣小數位(Context.Env.LocalDecimal),與 VFPROUND(存入金額*匯率,0)及姊妹類 checkrec 的本幣金額算法一致。外幣(例如 USD)預估資金的本幣換算金額顯示位數會因此修正。
- spbank 自訂群組自動帶值:輸入廠商代號時,若「自訂群組」為空白,自動帶入廠商代號本身(還原 VFP
廠商代號.Valid行為)。
- ftrlima 明細移除重複欄:明細 grid 原本有兩個完全相同的「需求部門」欄(複製貼上殘留),移除其中一個。
新增
- fsheet 編輯/刪除防呆(
FsheetEdit):還原 VFPfsheet.allowedit。收付款單若已有「出納傳票號」(已轉票據匯款)、「沖帳備註」(已沖帳)或「沖帳傳票號」(已轉傳票),不得修改或刪除。新版原本缺少FsheetEdit(走 baseEditBll無條件允許),與同表姊妹類PsheetEdit(應付)/RsheetEdit(應收)不一致——本次補齊。保留IsCancelStike例外(取消沖帳流程下允許編輯,對應 VFPIF NOT 取消沖帳)。
Breaking Changes
- 行為變更:先前可以修改/刪除「已轉傳票或已沖帳」的收付款單(F 類),補上防呆後將被擋下並提示。此為還原舊系統與姊妹類既有保護,屬預期行為。
備註
- VFP
fsheet.allowedit僅有上述三條轉檔/沖帳防呆;姊妹類PsheetEdit/RsheetEdit另含「禁修日期(closing book)」檢查。本次FsheetEdit先只還原 VFP 既有的三條,未加禁修日期檢查(若要與 Psheet/Rsheet 完全一致可後續再補)。
新增
- 無
刪除
- 無
Breaking Changes
- 無
Migration Notes
- 無需 DB migration。bankfcst 本幣金額為畫面即時計算(未持久化),僅影響顯示;既有資料不受影響。
待辦(規劃中)
- spbank「異動轉檔」:VFP
spbank.else1click(CMDELSE1,Caption=「異動轉檔」)會匯出台新銀行付款檔(DO FORM SPBANK_E),新版尚未實作對應IOther1.ExtendedFunction1。經確認屬公司專屬需求,暫列待辦、未排程實作。
對使用者的影響
- 「預估資金表」外幣單據的本幣換算金額顯示位數修正為本幣位數。
- 「廠商帳戶表」新增/輸入廠商代號時,自訂群組會自動帶入廠商代號(原本留空)。
- bankfcst 本幣金額小數位:
-
05-27 accself-poco-chinese-columns ▸
2026-05-27 Accself 報表資料源欄位改中文(修好空白問題)
摘要
Accself 系列報表(Accself1~10、Accselfm 等)的 FastReport
.frx都綁中文欄名,但其資料源 POCORpt_N130_AccrptReportPoco1是英文屬性名。ExportToSqlite直接用屬性名當 SQLite 欄名(GetColumnString的translateToLocalColumn實為 no-op),所以匯出的是英文欄 → 與 .frx 的中文綁定對不上 → 報表月份/金額欄空白。本次把該 POCO 屬性名改成中文(對照Model.json既有英中對照、與 .frx 欄名一致),讓資料源欄位與報表綁定吻合。變更
Model/Rpt/Rpt_N130_AccrptReportPoco1.cs:~60 個屬性英文→中文(如ReportTitle→報表抬頭、Year0And01→今年01、Budget01→預算01、DecimalLength→小數位數…)。計算屬性、當期月份setter、NeedShow()內部引用一併中文化,邏輯不變。輔助類Rpt_N130_AccrptReportPoco1Parameter維持英文(不匯出)。
Model/Bll/SelfrptSource.cs:ToRptN130物件初始化左側(POCO 屬性)改中文;右側(SelfrptSource 自身英文屬性 / para)不變。
TworkReportPluginOfficial/N.GeneralLedger/:11 支 plugin 修正對該 POCO 的引用——
- Accself1~6、9、10、Accselfm:
item.ReportTitle/QueryDate→報表抬頭/查詢日期- Accselfm、Accselfm1、Accselfm2:建立 POCO 的物件初始化左側改中文(右側
item.*為 SelfrptSource 英文屬性,不動)Accself7/8/Accselfsimple不受影響(它們的目標是另一支早已中文化的Rpt_N130_AccrptReportPoco,且讀的是 SelfrptSource 英文屬性)。
刪除
無(屬性改名,非刪除)。
Breaking Changes
- 匯出表
rpt_n130_accself_report1的欄名由英文變中文。FastReport.frx已是中文綁定,故報表端不需改;但任何直接以英文欄名讀此表的程式/查詢都需同步改中文(目前未發現此類使用)。
Migration Notes
.frx無需修改、無需重新部署到 Reports 夾。本次純後端改名,需重新編譯部署 app才生效。
- 命名以
TsERP/Lang/Model1/Model.json的Rpt_N130_AccrptReportPoco1英中對照為準,與 .frx 欄名一致。
- 同類別的其他報表 POCO(Sliy、Sliybrowd 等)本來就是中文屬性名,不受影響。
-
05-27 accself-account-name-indent ▸
2026-05-27 Accself 報表科目名稱還原前導縮排空格
摘要
Acc_selfrpt(自訂財報)報表的科目名稱在讀取 SQL 公式表時,前導縮排空格被吃掉,導致報表層級縮排消失(呈現扁平)。本次在讀取後從原始 DataTable 還原前導空格。
變更
LogicBll/N.GeneralLedger/Acc_selfrpt/Acc_selfrptBll.cs:GetTmpmoverecs在dt.ToList<AccselfrptSource>()後,從原始DataTable的「科目名稱」欄還原值(只TrimEnd、保留前導縮排),讓使用者在公式中打的層級縮排空格能呈現於報表。
根因
Common/ListDataTable/DataTableToList.cs對所有字串欄位一律value.ToString().Trim()(全域共用),把使用者在「科目名稱」前面打的縮排空格清掉。自動產生列(ACC_BSAUTO / ACC_BSCE)因為空格是在 ToList 之後用new string(' ', n)補的,所以不受影響——故「自動列有縮排、自訂列沒有」。影響範圍
- 僅 Acc_selfrpt;未改動全域
DataTableToList(避免影響其他報表/查詢)。
- 一般自訂公式列(
FormulaGenerator.GenerateFormula的 else 直通分支)會帶回縮排。
Migration Notes
- 純後端修正,
.frx無需修改、無需重新部署 Reports 夾;需重新編譯部署 app 才生效。
-
05-26 asset-amortization-monthly ▸
2026-05-26 — 財產資料(ASSET) 折舊計算與預留殘值
摘要
財產資料的「計算折舊」改回與舊系統一致的月折舊法;輸入「年限」時自動帶出建議的「預留殘值」。對應 VFP
scx_ast對比結果。變更
- 計算折舊算法:由逐日比例攤提改為月折舊(年折舊額/12、年底補差、最後一期補總差),折舊明細金額分佈與舊系統一致。
- 年限 → 預留殘值自動帶入:在「金額與年限」區改「年限」並離開欄位時,自動填入
預留殘值 = 四捨五入(取得原價(或改良成本) ÷ (年限+1)),可手動覆寫。新增與修改模式皆會觸發。
新增
無新欄位 / 無新畫面。
刪除
無。
Breaking Changes
無。既有已存檔的折舊明細不受影響。
Migration Notes
- 不需 migration。
- 若某筆財產要套用新(月折舊)算法,請重新按「計算折舊」重產折舊明細。
-
05-24 sliy-budget-project-cascade ▸
2026-05-24 — Sliy / Budget 主表專案代號自動帶入明細 + 顯示專案簡稱
摘要
Sliy(總帳傳票)與Budget(預算傳票)兩支畫面:主表「專案代號」變更時,自動把專案代號與專案簡稱覆蓋寫入所有現存明細列;新增明細列時也自動帶入。明細區下方說明區新增「專案簡稱」欄位。Budget 明細表 grid 補上原本沒有的「專案代號 / 專案簡稱」兩欄,跟 Sliy 對齊。新增
ViewModel/N.GeneralLedger/GeneralLedger/SliyVirtual.cs:
-
CascadeProjectToAllDetails()— master 專案代號a 變更時,查Vwseek_aproj取得專案簡稱後,覆蓋所有增刪修 != "D"的明細列-
DetailListenerHelper_OnAddListener()— 新增明細列時依 master 專案代號a 帶入;以AdeViewModel.Status == Normal防呆,避免載入舊資料時誤觸發 DB 查詢Model/Source/N.GeneralLedger/Twork_acc_vw_sliyyearmSource.cs:補專案代號a屬性(純記憶體 stub;該年度匯總類別 DB 端無此欄位,僅為滿足ISliymSource)
TsERP/N.GeneralLedger/Sliy.xaml:下方說明區(DetailSelectedItem)新增 Row 4:專案簡稱 label + read-only textbox
TsERP/N.GeneralLedger/Budget.xaml:
- 明細 grid 新增
TsArpojSeekGridViewColumn(專案代號 seek)+ 專案簡稱顯示欄- 下方說明區新增 Row 4:專案簡稱
變更
Model/Source/N.GeneralLedger/ISliymSource.cs:interface 新增string 專案代號a { get; set; }
Model/Source/N.GeneralLedger/ISliySource.cs:interface 新增string 專案代號 { get; set; }與string 專案簡稱 { get; set; }
SliyVirtual建構子:
- 給
detailListenerHelper掛上OnAddListener事件- 新增
masterListenerHelper(監聽ISliymSource.專案代號a)並呼叫MasterData.AddListener()SliyVirtual.ReceiveWeakEvent():增加sender is T && PropertyName == 專案代號a分支,觸發CascadeProjectToAllDetails()
刪除
無
Breaking Changes
ISliymSource/ISliySource介面擴增屬性:所有實作這兩個介面的類別必須有對應屬性。本次掃過的所有實作(Twork_acc_vw_sliymSource、Twork_acc_vw_budgetmSource、Twork_acc_vw_sliySource、Twork_acc_vw_budgetSource、Twork_acc_vw_sliyyearSource、Twork_acc_vw_sliyyearmSource、Sliy1Source)皆已有或補上對應屬性。外部專案若有自寫實作需自行調整
Migration Notes
無 schema 變更;DB 端的
專案代號欄位本來就存在於 detail 表,本次只是把主表的值同步進去。既有資料不受影響。對使用者的影響
- Sliy:
- 主表輸入或修改「專案代號」後,所有明細列的「專案代號 / 專案簡稱」立即被覆蓋為 master 同值(包含使用者自行調整過的列)。如需明細列各自設定不同專案,請在 master 設好後再個別調整明細
- 下方說明區點選明細列後可看到該列的「專案簡稱」
- Budget:
- 同 Sliy 行為
- 明細表 grid 多出兩欄「專案代號 / 專案簡稱」(先前 Budget grid 沒有露出這兩欄)
- 載入既有傳票時不會觸發 cascade(僅在 Add / Edit 狀態下觸發),不會造成回歸
-
05-24 btn-styles-unify ▸
2026-05-24 — 操作按鈕 Style 統一基準
摘要
TsControl/Themes/Generic.xaml內 6 個TsButtonStyle(BtnSave / BtnReturn / BtnTurn / BtnConfirm / BtnCancel / BtnExit)統一視覺基準與內容寫法,並把唯一漏掉多語系的BtnConfirm文字改成 DisplayMeta 綁定。變更
- 共通基準:6 個按鈕全部對齊
Height="40"+HorizontalContentAlignment="Left"
-
BtnSave補上HorizontalContentAlignment="Left"-
BtnTurn補上Height="40"與HorizontalContentAlignment="Left",移除 Image / TsTextBlock 多餘的HorizontalAlignment="Center"- 內容寫法統一改用
ContentTemplate:BtnConfirm/BtnCancel/BtnExit原本用<Setter Property="Content">直接內嵌StackPanel,已改成ContentTemplate+DataTemplate,避免同一個 UI 元件實例被多顆按鈕共用而觸發 WPF「元件不可有多重父容器」例外
BtnConfirm文字多語系化:Text="Confirm"改為Text="{Binding ElementName=View, Path=DataContext.DisplayMeta[Confirm], FallbackValue=Confirm}"
Migration Notes
- 若有專案資源覆寫
BtnConfirm的 Content Template,請改寫成ContentTemplate
Common/Lang/Xaml/與TsERP/Lang/Xaml1/Xaml.json需確認Confirmkey 已存在(既有其他按鈕已用,理論上已有)
影響檔案
TsControl/Themes/Generic.xaml
未處理(後續)
BtnConfirm圖示目前是返回00.png(與 BtnReturn 同),疑似 copy-paste 錯誤;本次依使用者指示先不動
- 共通基準:6 個按鈕全部對齊
-
05-24 bankflow-chart-fixes ▸
2026-05-24 — Bankflow 全部銀行帳戶折線圖顯示修正
摘要
修正 2026-05-22 加入的「全部銀行帳戶」折線圖三個顯示問題:X 軸日期重複擠在一起、X 軸標籤重疊、Y 軸出現科學記號。
變更
ViewModel/O.Check/BankflowViewModel.cs
-
Bankflow03Chart改為依「日期」分組後取每組Last():Bankflow03是 running balance,同一天多筆交易會在同一個 X category 上重疊;只取每日最後一筆即當日收盤結餘。TsERP/O.CAandCL/Bankflow.xaml
-
CategoricalAxis加LabelInterval="5"+MajorTickInterval="5",搭配既有的LabelFitMode="Rotate",避免標籤密集重疊。-
LinearAxis加LabelFormat="{}{0:N0}",Y 軸金額顯示千分位整數,停用科學記號(如1.23E+6)。Breaking Changes
無。
Bankflow03Chart是純讀取屬性,呼叫端只有 XAML chart binding;分組後資料筆數變少但 schema 不變。Migration Notes
無 DB / 設定遷移。重新 build TsERP 即生效。
相關
- [[Changelog 2026-05-22 — Bankflow Baseline + Chart]](2026-05-22-bankflow-baseline-chart.md)(原始功能)
- [[ADR 0021 — Bankflow chart 採用 Telerik RadCartesianChart]](../decisions/0021-bankflow-chart-telerik.md)
-
05-24 asset-accexp-workflow-fields ▸
2026-05-24 — 固定資產 asset / accexp 加工作流程欄位 + view 同步
摘要
固定資產模組(
Q.FixedAsset)的asset(財產主檔)與accexp(費用主檔)兩張表統一加入工作流程簽核 6 欄(建檔日期/聯絡單id/工作流程/審核人員/審核日期/已審核),讓固定資產主檔也能掛上簽核流程,並同步更新vw_asset/vw_accexpview 加入新欄位。延續 [[2026-05-22-cheque-system-workflow-fields]] 票據系統的相同 pattern。新增
asset/accexp各新增以下 6 欄(搭配 Source/Model 已有對應屬性):
-
[建檔日期] char(10) NOT NULL DEFAULT ''-
[聯絡單id] int NOT NULL DEFAULT 0-
[工作流程] varchar(6) NOT NULL DEFAULT ''-
[審核人員] nvarchar(20) NOT NULL DEFAULT ''-
[審核日期] varchar(10) NOT NULL DEFAULT ''-
[已審核] char(1) NOT NULL DEFAULT ''變更
vw_assetview 重建,SELECT 清單末端加入建檔日期/聯絡單id/工作流程/審核人員/審核日期/已審核
vw_accexpview 重建,SELECT 清單末端加入相同 6 欄
- 兩個 view 重建後執行
sp_refreshview刷新中介資料
刪除
- 無
Breaking Changes
- 無。所有新欄位
NOT NULL DEFAULT,既有 row 直接補預設值
Migration Notes
SQL Server 端必跑 — 升級資料庫到本 commit 前先執行以下 script:
ALTER TABLE accexp add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE accexp add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE accexp add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE accexp add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE accexp add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE accexp add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE asset add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE asset add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE asset add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE asset add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE asset add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE asset add [已審核] [char](1) NOT NULL DEFAULT ''; go ALTER VIEW [dbo].[vw_asset] AS SELECT dbo.asset.財產編號, dbo.asset.資產別, dbo.asset.財產名稱, dbo.asset.財產分類碼, dbo.asset.廠商代號, dbo.spdata.廠商簡稱, dbo.asset.廠牌, dbo.asset.規格, dbo.asset.單位, dbo.asset.部門代號, dbo.asset.數量, dbo.asset.取得日期, dbo.asset.取得原價, dbo.asset.改良成本, dbo.asset.預留殘值, dbo.asset.現有狀況碼, dbo.asset.年限, dbo.asset.備註, dbo.asset.資產減科目, dbo.asset.費用科目, dbo.asset.處分日期, dbo.asset.再提年限, dbo.asset.處分金額, dbo.asset.再提殘值, dbo.asset.輸入日期, dbo.asset.輸入人員, dbo.asset.輸入地點, dbo.asset.增刪修, dbo.asset.選擇, dbo.asset.管制碼, dbo.asset.srvdbid, dbo.asset.pkid, dbo.asset.logid, dbo.asset.linkid, dbo.dept.部門簡稱, dbo.asset.保固年限, dbo.asset.原始金額, dbo.asset.附加費用, dbo.vwcmb223_財產分類.field2 AS 財產分類, dbo.vwcmb224_現有狀況.field2 AS 現有狀況, dbo.asset.傳票號碼, dbo.asset.財務單號, dbo.asset.置放地點, dbo.asset.建檔日期, dbo.asset.聯絡單id, dbo.asset.工作流程, dbo.asset.審核人員, dbo.asset.審核日期, dbo.asset.已審核 FROM dbo.asset LEFT OUTER JOIN dbo.dept ON dbo.asset.部門代號 = dbo.dept.部門代號 LEFT OUTER JOIN dbo.spdata ON dbo.asset.廠商代號 = dbo.spdata.廠商代號 LEFT OUTER JOIN dbo.vwcmb223_財產分類 ON dbo.asset.財產分類碼 = dbo.vwcmb223_財產分類.field1 LEFT OUTER JOIN dbo.vwcmb224_現有狀況 ON dbo.asset.現有狀況碼 = dbo.vwcmb224_現有狀況.field1 GO ALTER VIEW [dbo].[vw_accexp] AS SELECT dbo.accexp.費用編號, dbo.accexp.費用類別碼, dbo.vwcmb226_費用類別.field2 AS 費用類別, dbo.accexp.費用名稱, dbo.accexp.製單日期, dbo.accexp.廠商代號, dbo.accexp.保單號碼, dbo.accexp.費用起始日, dbo.accexp.費用截止日, dbo.accexp.費用金額, dbo.accexp.資產科目, dbo.accexp.費用科目1, dbo.accexp.費用科目2, dbo.accexp.費用科目3, dbo.accexp.費用科目4, dbo.accexp.百分比1, dbo.accexp.百分比2, dbo.accexp.百分比3, dbo.accexp.百分比4, dbo.accexp.備註, dbo.accexp.輸入日期, dbo.accexp.輸入人員, dbo.accexp.輸入地點, dbo.accexp.增刪修, dbo.accexp.選擇, dbo.accexp.管制碼, dbo.accexp.srvdbid, dbo.accexp.pkid, dbo.accexp.logid, dbo.accexp.linkid, dbo.spdata.廠商簡稱, dbo.accexp.財務單pkid, dbo.accexp.傳票號碼, dbo.accexp.財務單號, dbo.accexp.部門代號, dbo.dept.部門簡稱, dbo.accexp.建檔日期, dbo.accexp.聯絡單id, dbo.accexp.工作流程, dbo.accexp.審核人員, dbo.accexp.審核日期, dbo.accexp.已審核 FROM dbo.accexp LEFT OUTER JOIN dbo.dept ON dbo.accexp.部門代號 = dbo.dept.部門代號 LEFT OUTER JOIN dbo.spdata ON dbo.accexp.廠商代號 = dbo.spdata.廠商代號 LEFT OUTER JOIN dbo.vwcmb226_費用類別 ON dbo.accexp.費用類別碼 = dbo.vwcmb226_費用類別.field1 GO EXEC sp_refreshview 'vw_accexp' EXEC sp_refreshview 'vw_asset'對使用者的影響
- 固定資產主檔(
asset)與費用主檔(accexp)開始支援工作流程簽核欄位(DB 端已備齊;UI 是否暴露簽核控制依 XAML / ViewModel 設定,搭配本次TsERP/Q.FixedAsset/Accexp.xaml調整)
vw_asset/vw_accexpview 多了 6 個欄位,下游 browse / 報表若需顯示審核狀態可直接取用
-
05-23 checkpay-checkrec-single-column-layout ▸
2026-05-23 — Bank / Checkpay / Checkrec 改 GroupBox 分區版型
摘要
銀行帳戶(
Bank.xaml)、應付票據(Checkpay.xaml)、應收票據(Checkrec.xaml)三個 Master 編輯區統一改成「外層 2 欄、每欄一個 StackPanel 堆 GroupBox」的版型,把欄位依語意分組(基本資料 / 交易資訊 / 金額匯率 / 票況 / 其他 …)。每個 GroupBox 內部維持 2 欄 Grid(label / 輸入),每組欄位各佔一個Grid.Row。先前版本把多組獨立欄位塞進同一個StackPanel(例如 Bank 的「帳戶代號 + 帳戶簡稱 + 日報表」「支票字軌 + 票號長度 + 票據號碼」、Checkpay 的「票據單號 + 公司代碼」、Checkrec 的「禁止轉讓 + 平行線」「票況 + 異動日期」),造成欄位上下對不齊、巢狀子元素還掛著無效的Grid.Row/Grid.Column屬性,這次一併清掉。變更
TsERP/O.CAandCL/Bank.xaml
- 左欄 GroupBox「基本資料 / 支票設定」、右欄 GroupBox「銀行資訊 / 會計科目 / 其他」
TsERP/O.CAandCL/Checkpay.xaml
- 第一個 tab(應付票據):左欄 GroupBox「基本資料 / 金額匯率」、右欄 GroupBox「交易資訊 / 票況 / 其他」
- 第二個 tab(LC):左欄 GroupBox「基本資料 / 日期」、右欄 GroupBox「金額匯率 / 還款利息 / 其他 / 保險」
- 修正
Orientation=" Horizontal"多空白的小瑕疵TsERP/O.CAandCL/Checkrec.xaml
- 左欄 GroupBox「基本資料 / 金額匯率」、右欄 GroupBox「開票資訊 / 票況 / 其他資訊」
- 統一帳戶代號欄位的 Margin / VerticalAlignment 風格
新增
- 無
刪除
- StackPanel 子元素上殘留的無效
Grid.Row/Grid.Column屬性
Breaking Changes
- 無。純 XAML 排版調整,未動 binding 路徑、未動
x:Name、未動 code-behind
Migration Notes
- 無需 DB / 設定遷移
對使用者的影響
- 應付票據、應收票據新增 / 編輯畫面的欄位排列依語意分區,GroupBox 標題能一眼看出該區欄位的用途(基本資料、金額匯率、票況…)
- 外層左右兩欄擺放 GroupBox,整體高度比單欄全部上下堆疊版本矮,較符合一般螢幕長寬比
DisplayMeta 多語系待補
各 GroupBox 標題以下 key 走 DisplayMeta,目前 fallback 為中文,正式上線前請在
Common/Lang/Xaml/與TsERP/Lang/Xaml1/Xaml.json補對應 JSON:基本資料、交易資訊、金額匯率、票況、其他、日期、還款利息、保險、開票資訊、其他資訊、支票設定、銀行資訊、會計科目
-
05-22 perdata-other-multi-row ▸
2026-05-22 — Perdata「眷屬資料」改為多筆 + perdata_d 序號 schema 兩位前綴
摘要
人事資料(PERDATA)的「眷屬資料」(原 Other)從單組固定欄位 key-value 表單改成多筆同 schema 表格,跟眷屬與聯絡人 / 學歷 / 任職經歷一致。同時把
perdata_d.序號的區塊前綴從一位數統一成兩位數。變更
UI / Storage 行為改變
- 「眷屬資料」grid 從 3 欄寫死(序號 / 標題 / 內容)→ 動態欄位(眷屬稱謂 / 眷屬姓名 / 眷屬出生 / 眷屬職業 / 身份證號 / 眷屬關係),一個員工可以填多筆眷屬
- 右鍵選單支援「新增數筆」(每次補 10 列空白)
- 儲存進
perdata_d的格式從「同 序號='2'、不同 欄位 共 6 筆」→「每一列拆 6 筆,序號 = '02' + 列序號 (如 '0201'/'0202')」
程式碼
ViewModel/R.HumanResource/PerdataViewModel.cs
-
Other屬性型別:List<其他資料Poco>→DataTable- 新增
otherRelatives(List<TsTemplateRelative>) +OtherAdder(IDataGridAdd)-
otherSturcuture建構移除false參數 → 走預設加IsVirtualEmpty/NeedDelete/序號系統欄-
AfterAddNew/EditBll_OnAfterEdit/AfterMoverRecord/SaveBll_OnBeforeAllowSave改成 DataTable 模式(跟其他三個一致)LogicBll/Ade/R.HumanResource/PerdataSave.cs
-
Other屬性型別:List<其他資料Poco>→TemplateDynamicDataGridPoco-
HandleDataBeforeEndEdit改用Action<T>版的Transfer,把detail.AddItem作為 callback 傳入(直接傳detail.ObservableCollection會炸Collection is read-only,因為它是ReadOnlyObservableCollection<T>)- 同步把其他三個 prefix 補 0:
"1"→"01"、"3"→"03"、"4"→"04",跟 [[2026-05-21-perdata-add-multiple-rows]] 內AfterMoverRecord已改成的兩位數StartsWith對齊- 刪除
OtherHandleprivate method 與其他資料PococlassCommon/Model/Vwseek_datatpl.cs
-
TemplateDynamicDataGridPoco.Transfer加Action<T>版 overload;舊IList<T>版改成委派到新版(呼叫detail.Add)。新版讓呼叫端能傳IDataManager.AddItem避開 ReadOnly Collection 問題- 同個 bug 也存在於
SpdataSave(傳ObservableCollection給Transfer),本次未修,視情況另外處理TsERP/R.HumanResource/Perdata.xaml
-
DgOther移除寫死的 3 個 Columns;加DataGridAdd="{Binding OtherAdder}"、ItemsSource="{Binding Other.DefaultView}"TsERP/R.HumanResource/Perdata.xaml.cs
-
Perdata_OnLoaded加new DataGridCreator(Context, "perdata", "P1", "P1_2").SetDataGridColumn(DgOther);Breaking Changes
perdata_d.序號schema 從一位前綴變兩位前綴,沒有遷移會讀不到舊資料:區塊 舊 schema 新 schema 眷屬與聯絡人 1XX01XX眷屬資料 (Other) 2(固定,6 筆同序號)02XX學歷 3XX03XX任職經歷 4XX04XXMigration Notes
對每個目標 DB 執行以下 SQL。先 備份
perdata_d整表再跑。-- 1. Contact / Education / WorkExperience:1XX / 3XX / 4XX → 0XXX (補 0 前綴) UPDATE perdata_d SET 序號 = '0' + RTRIM(序號) WHERE LEFT(RTRIM(序號), 1) IN ('1', '3', '4') AND LEN(RTRIM(序號)) BETWEEN 2 AND 3; -- 2. Other 那組:原本固定 序號='2',每個 perdata master 只有一組 6 筆 → 改成 '0201'(合併成第 1 列) UPDATE perdata_d SET 序號 = '0201' WHERE RTRIM(序號) = '2'; GO注意事項
- 程式讀回時
GetDataTableAndRelatives用序號當 group key,舊 6 筆 ('0201') 會 lookup 成同 1 個 DataRow,UI 自然顯示為「眷屬資料第 1 列已填」。後續使用者新增列從'0202'開始遞增
- 若
perdata_d.序號為char(N)固定長度,RTRIM處理尾端空白後比對應該安全;若為varchar則直接序號 IN ('1', '2', ...)也可
- migration 前先
SELECT 序號, COUNT(*) FROM perdata_d GROUP BY 序號 ORDER BY 序號確認資料現況,再決定 WHERE 條件邊界
相關
- [[2026-05-21-perdata-add-multiple-rows]] — 上一輪先把 Contacts/Education/WorkExperience 接「新增數筆」 + 修 DataTable binding error
-
05-22 inventquery-tab-column-fix ▸
2026-05-22 — InventQuery 切換 tab 後預設 column 殘留修復
摘要
InventQuery系列(客戶報價/訂單/出貨、廠商報價/採購/收貨/工單、Trwkma 等)放在TsTabControl內。原本切走 tab 再切回來時,已經 AutoGenerate 出的真實資料 column 會被「沒 binding 的預設 header column」蓋掉。改完後切回 tab 維持查詢結果的 column。根因
TsTabControl.ContentTemplate每次切換都會重建InventQuery控件樹 → 連帶重建TsBrowseRadGridView。原本「是否已生成預設 column」的旗標isGenerateDefaultColumnHeader是 grid 控件 instance 的 field,跨重建會 reset;但Schemas(在 ViewModel)保留 → 切回時OnSchemasChanged又跑GenerateDefaultColumnHeader,把預設 header-only column 加回來。新增
ViewModel.Control.TsBrowseDataGridViewModel.IsAutoGenerated屬性
- 跨 grid 控件生命週期存活(ViewModel 不會被 tab 切換重建)
-
CreateDataView()結尾設true-
SetNull()重置為false變更
TsControl/TsTelerik/TsBrowseRadGridView.cs
-
OnSchemasChanged開頭加判斷:若DataContext is TsBrowseDataGridViewModel { IsAutoGenerated: true }→ 直接 return,不再呼叫GenerateDefaultColumnHeaderViewModel/Control/TsBrowseDataGridViewModel.cs
-
CreateDataView()末尾追加IsAutoGenerated = true-
SetNull()末尾追加IsAutoGenerated = false刪除
無。
Breaking Changes
無。
IsAutoGenerated是新屬性,預設false→ 第一次查詢前的行為與舊版一致。Migration Notes
無 DB / 設定遷移。重新 build TsERP 即生效。
影響範圍
所有使用
TsBrowseRadGridView+TsBrowseDataGridViewModel+ 動態 Schemas 的查詢頁面。InventQuery系列受惠最大,其他用同一機制的 browse-grid 也順帶修復同類型潛在問題。驗收
1. 進
Invent_bs(或任何掛 InventQuery 的程式)2. 在第一個 tab 按查詢 → 看到真實資料 column
3. 切到第二個 tab → 切回第一個 tab
4. 預期:column 仍是真實資料 column(不是 header-only 預設 column)
-
05-22 cheque-system-workflow-fields ▸
2026-05-22 — 票據系統 7 張表加工作流程欄位 + bank 加票據號碼
摘要
票據系統相關 7 張表(
bank/checkpay/checkrec/bankfcst/bankfxrm/spbank)統一加入工作流程簽核欄位(建檔日期/聯絡單id/工作流程/審核人員/審核日期/已審核),讓票據主檔也能掛上簽核流程。bank表另外補上票據號碼欄位。同時修正_sheetno內BANKFXR單據別的子表 view 名稱為vw_bankfxrd。新增
- 7 張票據相關表新增以下 6 欄(搭配 Source/Model 已有對應屬性):
-
[建檔日期] char(10) NOT NULL DEFAULT ''-
[聯絡單id] int NOT NULL DEFAULT 0-
[工作流程] varchar(6) NOT NULL DEFAULT ''-
[審核人員] nvarchar(20) NOT NULL DEFAULT ''-
[審核日期] varchar(10) NOT NULL DEFAULT ''-
[已審核] char(1) NOT NULL DEFAULT ''bank表額外新增[票據號碼] nvarchar(40) NOT NULL DEFAULT ''
變更
_sheetno內單據別 = 'BANKFXR'的子表1view從原值更新為vw_bankfxrd,配合新版Twork_chk_vw_bankfxrdview 命名
刪除
- 無
Breaking Changes
- 無。所有新欄位
NOT NULL DEFAULT,既有 row 直接補預設值
Migration Notes
SQL Server 端必跑 — 升級資料庫到本 commit 前先執行以下 script:
update _sheetno set 子表1view ='vw_bankfxrd' where 單據別 = 'BANKFXR' ALTER TABLE bank add [票據號碼] [nvarchar](40) NOT NULL DEFAULT ''; ALTER TABLE bank add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE bank add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE bank add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE bank add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE bank add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE bank add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE checkpay add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE checkpay add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE checkpay add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE checkpay add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE checkpay add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE checkpay add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE checkrec add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE checkrec add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE checkrec add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE checkrec add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE checkrec add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE checkrec add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE bankfcst add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE bankfcst add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE bankfcst add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE bankfcst add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE bankfcst add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE bankfcst add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE bankfxrm add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE bankfxrm add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE bankfxrm add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE bankfxrm add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE bankfxrm add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE bankfxrm add [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE spbank add [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE spbank add [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE spbank add [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE spbank add [審核人員] [nvarchar](20) NOT NULL DEFAULT ''; ALTER TABLE spbank add [審核日期] [varchar](10) NOT NULL DEFAULT ''; ALTER TABLE spbank add [已審核] [char](1) NOT NULL DEFAULT '';對使用者的影響
- 票據相關 7 個程式(銀行帳戶、應付/應收票據、預估資金表、銀行日報主檔、廠商帳戶表)開始支援工作流程簽核欄位(DB 端已備齊;UI 是否暴露簽核 UI 依 Source/ViewModel 設定)
bank表(公司銀行帳戶)多了「票據號碼」欄位
- 銀行日報明細的 view 名稱統一為
vw_bankfxrd,相關報表 / browse 設定一致化
-
05-22 bankflow-baseline-chart ▸
2026-05-22 — Bankflow 全部銀行帳戶加結餘趨勢圖 + BaseLine 警示
摘要
Bankflow(資金預估表 O110)的「全部銀行帳戶」分頁加上結餘金額趨勢圖與 BaseLine 警示功能:原本只有純表格,現在右側顯示折線圖、警示線會跟著查詢條件的 BaseLine 即時移動,結餘跌破 BaseLine 的列在 grid 上會自動顯紅底。
新增
- BankflowCondition 的 BaseLine 欄位實際生效:之前只是 UI 上一個 TextBox 沒接後續,現在輸入後會:
1. 第三個 tab 折線圖上畫一條紅色水平警示線
2. 同 tab grid 的列在
結餘金額 < BaseLine時上半透明紅底- 全部銀行帳戶 tab 折線圖:X = 日期、Y = 結餘金額,資料來源
Bankflow03
TsControl/Converter/BankflowBaseLineRowBackgroundConverter.cs:MultiValueConverter,輸入[結餘金額, BaseLine],回 Brush
變更
TsERP/O.CAandCL/Bankflow.xaml
- 加
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"-
TsView.Resources加入 converter 引用- 第三個 tab Grid 加入
RadCartesianChart(Grid.Column=1)-
bankflow03DataGrid加RowStyle(MultiBinding結餘金額+View.DataContext.QueryConditionViewModel.BaseLine)ViewModel/O.Check/BankflowViewModel.cs拿掉舊 LiveCharts 殘留:
- 刪除
UIUpdateoverride、CreateChartmethod- 刪除
Labels、YFormatter屬性、註解掉的SeriesCollection區塊- 對應拿掉
System.Windows.Media、System.Windows.Threading、System.Text、System.Threading.Tasksusing刪除
無外部 API / DB 欄位 / 設定值刪除。
Breaking Changes
無。
BaseLine仍維持在BankflowConditionViewModel的 local field(沒搬進BankflowQueryParameters),未影響任何序列化 / 設定檔。Migration Notes
無 DB / 設定遷移需要。重新 build TsERP 即生效。
相關
- [[ADR 0021 — Bankflow 全部銀行帳戶 tab 折線圖採用 Telerik RadCartesianChart]](../decisions/0021-bankflow-chart-telerik.md)
-
05-21 tserp-info-site ▸
2026-05-21 — 對外資訊網 manual.yanyue.io
摘要
建立對外公開資訊網
manual.yanyue.io(Cloudflare Pages),三頁 + 既有 mkdocs 手冊整合:- 系統地圖:259 個程式扁平單一清單,可搜尋 / 過濾 / 排序
- 修改紀錄:28 篇按月分組
- SQL 更新:4 個 migration(從 changelog
## Migration Notes抽)
- 使用手冊:mkdocs Material build,每頁頂部自動注入「程式資訊」框
詳細決策見 ADR 0020。
新增
docs/
docs/system-map/_subsystems.yml— 18 子系統對照(key + name + 排序 + 短描述 + TsERP / ViewModel / ProgramClass 三端路徑映射)
docs/system-map/README.md— 編輯指南(兩分鐘新增一個程式)
- **
docs/<sub>/*.md× 259** — 系統地圖骨架,bootstrap 自動產出
- 含 YAML frontmatter(id / name / status / features / xaml)
- 含自動產生 body(用途 / 主要欄位 / 操作步驟草稿 / 待確認,全標 ⚠️)
- 14 個 dead-code 候選跳過(見
docs/_scan/follow-ups.md)- 4 個變體標
variant_of:收編tools/release-notes/
工具與腳本:
檔 用途 build.ps1主 build 入口 publish.ps1build + wrangler pages deploybootstrap-system-map.ps1從 snapshot 一次性產 .md 骨架 Fill-Features.ps1從 XAML + VM 抽 features lib/Parse-Frontmatter.ps1YAML + body 解析 lib/Parse-SystemMap.ps1掃 docs/<sub>/*.md lib/Parse-Changelog.ps1掃 changelog lib/Parse-Sql.ps1從 changelog 抽 SQL block lib/Validate-SystemMap.ps1frontmatter 驗證(含 Levenshtein 拼錯建議) lib/Render-Html.ps1markdown → HTML、template token 替換 lib/Preprocess-Docs.ps1注入 metadata admonition 給 mkdocs templates/*.html× 5_layout / index / system-map / changelog / sql public/style.css純 CSS(無 framework) public/search.jsvanilla JS:搜尋 / 排序 / chip filter / URL state / 列展開 變更
docs/_template/feature-template.md— 在最上方補 frontmatter 段(id / name / status / features / xaml 等選填欄位)
.gitignore— 加入docs/_scan/、tools/release-notes/dist/、tools/release-notes/docs-built/、mkdocs-built.yml
刪除
無
Breaking Changes
無 — 純新增,不影響既有 ERP 程式碼、不改 DB、不動 mkdocs nav。
Migration Notes
部署到 manual.yanyue.io(首次)
# 1. 設環境變數 [Environment]::SetEnvironmentVariable('CLOUDFLARE_API_TOKEN', '<token>', 'User') [Environment]::SetEnvironmentVariable('CLOUDFLARE_ACCOUNT_ID', '<account-id>', 'User') # 關 PowerShell 重開 # 2. Build + Deploy cd C:\ERPV2\.claude\worktrees\hungry-brahmagupta-825ce9 pwsh tools\release-notes\publish.ps1publish.ps1 會:
1. 跑 build(驗證 → 解析 → 渲染 → mkdocs build)
2.
wrangler pages project create tserp-info(若不存在)3.
wrangler pages deploy ./dist --project-name=tserp-info首次部署後到 Cloudflare Dashboard → Pages → tserp-info → Custom domains 加
manual.yanyue.io。後續更新
只要編輯
docs/<sub>/*.md、docs/changelog/*.md或docs/system-map/_subsystems.yml,然後重跑publish.ps1即可。環境需求
- PowerShell 7+(pwsh)
- powershell-yaml:
Install-Module powershell-yaml -Scope CurrentUser
- Node.js 20+(wrangler 3 支援)
- mkdocs material:
pip install -r docs/requirements.txt
- Cloudflare API Token(權限 Account → Cloudflare Pages → Edit)
對使用者的影響
- 客戶可在
manual.yanyue.io看到系統有哪些功能、最新變動、要跑哪些 SQL
- 我們維護方式不變(編
docs/<sub>/*.md或docs/changelog/*.md),多了 frontmatter 那段
- depth-C 自動草稿需人工複核(用途 / 操作步驟 / 主要欄位 / 待確認,全部標 ⚠️)
連結
- 掃描原始:
docs/_scan/INDEX.md(gitignored,留本機參考)
- follow-up bug 清單:
docs/_scan/follow-ups.md
- 編輯指南:
docs/system-map/README.md
-
05-21 procno-bom-m-cols ▸
2026-05-21 — procno / bom_m schema 更新 + 人事資料模板種子
摘要
兩組獨立 DB 變動:
1. Schema —
procno(工程代號表)新增 4 個欄位以支援會簽流程與建檔日追蹤;bom_m(BOM 主檔)新增建檔日期欄位。同步更新vw_wkcent、vw_procno、vw_bom_m三個 view 把新欄位納入查詢結果。2. 種子資料 — 新增人事資料模板
P1(人事明細資料),含 23 筆datatpld欄位定義 + 1 筆datatplm主檔,分 4 個子群組(緊急聯絡人 / 眷屬資料 / 學歷 / 任職經歷)。變更
Schema
procno:新增 4 個欄位
-
建檔日期char(10)NOT NULL DEFAULT ''-
聯絡單idintNOT NULL DEFAULT 0-
工作流程varchar(6)NOT NULL DEFAULT ''-
已審核char(1)NOT NULL DEFAULT ''bom_m:新增 1 個欄位
-
建檔日期char(10)NOT NULL DEFAULT ''vw_wkcent:SELECT 補入聯絡單id、工作流程、審核人員、審核日期、已審核、建檔日期
vw_procno:SELECT 補入建檔日期、聯絡單id、工作流程、已審核
vw_bom_m:SELECT 補入建檔日期
種子資料
datatplm/datatpld:新增人事資料模板P1(人事明細資料)
-
P1_1_B_緊急聯絡人:4 欄位(緊急聯絡人 / 緊急關係 / 緊急電話 / 緊急地址)-
P1_2_B_眷屬資料:6 欄位(眷屬稱謂 / 眷屬姓名 / 眷屬出生 / 眷屬職業 / 身份證號 / 眷屬關係)-
P1_3_B_學歷:6 欄位(學校名稱 / 院系科別 / 修業年月起 / 修業年月迄 / 是否畢業 / 學位)-
P1_4_B_任職經歷:7 欄位(原任職公司 / 原部門 / 原任職日期 / 原離職日期 / 原待遇 / 原工作內容 / 原離職原因)Migration Notes
對每個目標 DB 依序執行以下兩段 SQL。
1. 加欄位
ALTER TABLE procno ADD [建檔日期] [char](10) NOT NULL DEFAULT ''; ALTER TABLE procno ADD [聯絡單id] [int] NOT NULL DEFAULT 0; ALTER TABLE procno ADD [工作流程] [varchar](6) NOT NULL DEFAULT ''; ALTER TABLE procno ADD [已審核] [char](1) NOT NULL DEFAULT ''; ALTER TABLE bom_m ADD [建檔日期] [char](10) NOT NULL DEFAULT ''; GO2. 更新 view 定義
ALTER VIEW [dbo].[vw_wkcent] AS SELECT dbo.wkcent.中心群組, dbo.wkcent.中心代號, dbo.wkcent.中心說明, dbo.wkcent.報價費率, dbo.wkcent.產能, dbo.wkcent.人工費率, dbo.wkcent.間接費比例, dbo.wkcent.每週天數, dbo.wkcent.部門代號, dbo.wkcent.輸入日期, dbo.wkcent.輸入人員, dbo.wkcent.輸入地點, dbo.wkcent.增刪修, dbo.wkcent.選擇, dbo.wkcent.管制碼, dbo.wkcent.srvdbid, dbo.wkcent.pkid, dbo.wkcent.logid, dbo.wkcent.linkid, ISNULL(dbo.vwseek_grpm1.說明, N'') AS 說明, ISNULL(dbo.dept.部門簡稱, N'') AS 部門簡稱, dbo.wkcent.聯絡單id, dbo.wkcent.工作流程, dbo.wkcent.審核人員, dbo.wkcent.審核日期, dbo.wkcent.已審核, dbo.wkcent.建檔日期 FROM dbo.wkcent LEFT OUTER JOIN dbo.vwseek_grpm1 ON dbo.wkcent.中心群組 = dbo.vwseek_grpm1.群組代號 LEFT OUTER JOIN dbo.dept ON dbo.wkcent.部門代號 = dbo.dept.部門代號; GOALTER VIEW [dbo].[vw_procno] AS SELECT dbo.procno.工程代號, dbo.procno.工程簡稱, dbo.procno.報價簡稱, dbo.procno.工程說明, dbo.procno.中心群組, dbo.procno.重要度, dbo.procno.重要項目, dbo.procno.圖檔名稱, dbo.procno.製造規格, dbo.procno.檢驗規格, dbo.procno.審核人員, dbo.procno.審核日期, dbo.procno.損耗率, dbo.procno.輸入日期, dbo.procno.輸入人員, dbo.procno.輸入地點, dbo.procno.增刪修, dbo.procno.選擇, dbo.procno.管制碼, dbo.procno.srvdbid, dbo.procno.pkid, dbo.procno.logid, dbo.procno.linkid, dbo.vwseek_grpm1.說明, dbo.procno.建檔日期, dbo.procno.聯絡單id, dbo.procno.工作流程, dbo.procno.已審核 FROM dbo.procno LEFT OUTER JOIN dbo.vwseek_grpm1 ON dbo.procno.中心群組 = dbo.vwseek_grpm1.群組代號; GOALTER VIEW [dbo].[vw_bom_m] AS SELECT dbo.bom_m.組件編號, dbo.vwseek_invent.品名, dbo.vwseek_invent.品別, dbo.vwseek_invent.停用說明, dbo.vwseek_invent.設變編號, dbo.vwseek_invent.設變資料, dbo.bom_m.機種別, dbo.bom_m.銷售地區, dbo.bom_m.客戶, dbo.bom_m.生產轉入倉, dbo.bom_m.流程樣板號, dbo.bom_m.聯絡單id, dbo.bom_m.工作流程, dbo.bom_m.審核人員, dbo.bom_m.審核日期, dbo.bom_m.已審核, dbo.bom_m.輸入日期, dbo.bom_m.輸入人員, dbo.bom_m.輸入地點, dbo.bom_m.增刪修, dbo.bom_m.選擇, dbo.bom_m.管制碼, dbo.bom_m.srvdbid, dbo.bom_m.pkid, dbo.bom_m.logid, dbo.bom_m.linkid, dbo.vwseek_invent.零件編號, dbo.bom_m.建檔日期 FROM dbo.bom_m LEFT OUTER JOIN dbo.vwseek_invent ON dbo.bom_m.組件編號 = dbo.vwseek_invent.品號; GO執行順序:先加欄位再更新 view,避免 view 引用未存在欄位失敗。
3. 人事資料模板種子(datatpld + datatplm)
跑過會在
datatplm留一筆P1主檔、datatpld留 23 筆欄位定義。若目標 DB 已有相同 pkid 會衝突,視情況決定是否先 DELETE。INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'1 ', N'原任職公司 ', N'C', 30, 0, N'服務機關名稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 1, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'2 ', N'原部門 ', N'C', 30, 0, N'部門/職稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 2, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'3 ', N'原任職日期 ', N'C', 10, 0, N'到職日', N'9999/99/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2019-04-18T17:18:41.633' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 3, 215195, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'4 ', N'原離職日期 ', N'C', 10, 0, N'離職日', N'9999/99/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2019-04-18T17:18:41.633' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 4, 215195, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'5 ', N'原待遇 ', N'N', 18, 6, N'薪資(月)', N'999,999,999', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 5, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'6 ', N'原工作內容 ', N'C', 80, 0, N'主要工作', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 6, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'7 ', N'原離職原因 ', N'C', 80, 0, N'離職原因', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_4_B_任職經歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 7, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'8 ', N'學校名稱 ', N'C', 30, 0, N'學校名稱', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 8, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'9 ', N'院系科別 ', N'C', 30, 0, N'院系科別', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 9, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'10 ', N'修業年月起 ', N'C', 7, 0, N'修業起始年月', N'9999/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 10, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'11 ', N'修業年月迄 ', N'C', 7, 0, N'修業結束年月', N'9999/99', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 11, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'12 ', N'是否畢業 ', N'C', 1, 0, N'畢/肄', N'Y', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 12, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'13 ', N'學位 ', N'C', 30, 0, N'學位', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_3_B_學歷', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 13, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'14 ', N'眷屬稱謂 ', N'C', 10, 0, N'稱謂', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 14, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'15 ', N'眷屬姓名 ', N'C', 10, 0, N'姓名', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 15, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'16 ', N'眷屬出生 ', N'C', 10, 0, N'出生日期', N'9999/99/99', N'CHKDATE', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-09T00:04:00.727' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 16, 64740, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'17 ', N'眷屬職業 ', N'C', 20, 0, N'職業', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 17, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'18 ', N'緊急聯絡人 ', N'C', 20, 0, N'姓名', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2022-10-13T17:20:14.240' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 18, 526961, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'19 ', N'緊急關係 ', N'C', 10, 0, N'關係', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 19, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'20 ', N'緊急電話 ', N'C', 20, 0, N'電話', N'XXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 20, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'21 ', N'緊急地址 ', N'C', 80, 0, N'地址', N'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_1_B_緊急聯絡人', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 21, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'48 ', N'身份證號 ', N'C', 14, 0, N'身份證號', N'XXXXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 55, 64734, 3); GO INSERT [dbo].[datatpld] ([序號], [欄位], [資料型態], [長度], [小數位數], [標題], [輸入遮罩], [valid方法], [公式], [參照資料], [輸入方式], [輸入內容], [允許輸入], [搜尋方式], [權限], [備註], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'49 ', N'眷屬關係 ', N'C', 10, 0, N'眷屬關係', N'XXXXXXXXXX', N'', N'', N'', N'SQLTEXT ', N'', N' ', N'', N'', N'P1_2_B_眷屬資料', CAST(N'2014-06-08T23:59:14.177' AS DateTime), N'Gary', N'CMSA-SERVER # cmsa', N' ', N' ', 0, 1, 56, 64734, 3); GO INSERT [dbo].[datatplm] ([資料模板號], [說明], [輸入日期], [輸入人員], [輸入地點], [增刪修], [選擇], [管制碼], [srvdbid], [pkid], [logid], [linkid]) VALUES (N'P1 ', N'人事明細資料', CAST(N'2012-10-04T15:32:02.280' AS DateTime), N'令狐沖', N'WXWG101234 # wg101', N' ', N' ', 0, 1, 3, 2109, 0); GO執行順序:schema → view → 種子資料皆獨立,可分批執行。種子資料若已存在會 PK 衝突,需先評估是否清除舊資料。
-
05-21 perdata-add-multiple-rows ▸
2026-05-21 — Perdata 右鍵「新增數筆」支援動態 DataTable detail
摘要
人事資料(PERDATA)的三個動態欄位 grid(眷屬與聯絡人 / 學歷 / 任職經歷)現在支援 RadGridView 右鍵選單的「新增數筆」。每按一次補 10 列空白,序號接著當前最大值往下排。
變更
ViewModel/R.HumanResource/PerdataViewModel.cs
- 新增
ContactsAdder/EducationAdder/WorkExperienceAdder三個IDataGridAdd屬性- 新增私有巢狀類別
CallbackGridAdd,把Action包成IDataGridAdd- 三個 adder 在建構子內建立,呼叫既有的
AddLineNo(dt)對Contacts/Education/WorkExperienceDataTable 加列TsERP/R.HumanResource/Perdata.xaml
-
DgContact、DgEducation、DgWorkExperience各加DataGridAdd="{Binding XxxAdder}"背景
TsRadGridView.AddNewRecordsExecute()有兩條路:DataGridAdd != null → DataGridAdd.AddItem() ← 客製化 detail 否則 → AdeViewModel.AddNewRecord(DataManager, ...) ← ObservableCollection-based detailPerdata 的 detail 不是
DataManager<TSource>+ObservableCollection,而是用TsTemplateDataTable從datatpld動態產欄位後綁DataTable,沒有DataManager可用,必須走DataGridAdd路徑。DgOther是固定的List<其他資料Poco>(沒有「新增更多筆」的概念),不接此功能。不影響
- 不影響原本進入新增 / 編輯模式時預先塞 10 列空白的行為(
AfterAddNew/EditBll_OnAfterEdit)
- 不影響
SaveBll_OnBeforeAllowSave把四個 detail 包成TemplateDynamicDataGridPoco的儲存流程
- 不影響其他模組的
TsRadGridView右鍵選單行為
-
05-18 scx_ord-db-model-sync ▸
2026-05-18 — SCX_ORD DB vs Model/Source 同步
摘要
跑
/db-model-compare SCX_ORD比對資料庫 view/table 欄位與Common/Model/E.Order+Model/Source/E.Order內各 Model/Source 類別,做了三層修補:1. 補 92 個 DB 欄位到 Model/Source(之前 Source 沒包到的中文欄位)
2. 補 64 處
[NotMapped]/[Browsable(false)]標記(Source 端的 UI helper props 沒打標記)3. 砍掉英文 stale 屬性 + caller 改名:原本英文 DB 改成中文 DB 後,部分 Source 還留著綁到不存在英文欄位的舊屬性,這次清掉並把 caller(C# + XAML)改用新中文名
變更
1) Model 補欄位(90 個屬性、18 個檔組)
每個檔組(Model + Source pair)都把 DB view/table 內的中文欄位補進
Common/Model/E.Order/<Name>Model.cs與Model/Source/E.Order/<Name>Source.cs:- Twork_ord_vw_ormast(24 model + 26 source)
- Twork_ord_vw_ordetl(31 + 31)
- Twork_ord_vw_cuqtm(3 + 3)
- Twork_ord_vw_cuinve(5 + 5)
- Twork_ord_vw_cupdt(6 + 6)
- Twork_ord_vw_ci_m(5 + 5)
- Twork_ord_vw_preord_d(4 + 4)
- Twork_ord_vw_cupdma(2 + 2)
- Twork_ord_vw_salema(3 + 3)
- Twork_ord_vw_salede(3 + 3)
- 其他 8 個小檔(cuqtd、pkde、cuinvema、pkma、cudata、cudataspec、preord_m、cuqtd1)共 4 + 4
2) Source 補 NotMapped/Browsable(false) 標記(64 處)
凡是 Source 屬性沒對到 DB 欄位、又沒打
[NotMapped]或[Browsable(false)]標記的(多半是 UI binding helper),都補上:- Twork_ord_vw_ormast(18)
- Twork_ord_vw_ordetl(11)
- Twork_ord_vw_cuqtm(8)
- 其他 17 個檔共 27 處
3) 砍英文 stale 屬性 + caller 改名
Source 端砍掉
Source 砍掉 取代為(已存在) Twork_ord_vw_cuinve QuantityPerCarton包裝量_箱Twork_ord_vw_cuqtd VendorName+_VendorNamefield廠商簡稱Twork_ord_vw_cuqtm VendorName+CustomerName+ 2 backing fields廠商簡稱/客戶簡稱Twork_ord_vw_ordetl ETA,ShippedQuantity預訂交期/已交數量Twork_ord_vw_preord_m CustomerName+_CustomerNamefield客戶簡稱RmamModel + RmamSource SysEntryDate / SysEntryUser / SysEntryMachine / SysRowStatus / SysIsChosen / SysControlCode(6 個英文版重複 ModelBase 中文版的審核欄位)ModelBase 內建 輸入日期 / 輸入人員 / 輸入地點 / 增刪修 / 選擇 / 管制碼判斷依據:
vw_cuinve.QuantityPerCarton、vw_ordetl.ETA / ShippedQuantity由 modeljson 確認舊→新(DB 已有對應中文欄)
CustomerName / VendorName同 Source 內已存在我這批新加入的客戶簡稱 / 廠商簡稱,舊版只是 UI helper、DB 沒有對應英文欄位
- Rmam 系列 6 個審核欄位重複 ModelBase 的 Chinese 版本,砍掉後乾淨繼承
C# caller 改名(10 處 LogicBll + 4 處 ViewModel)
LogicBll/E.Order/Cuqt/CuqtBll.cs:VendorName = ...→廠商簡稱 = ...
LogicBll/E.Order/Odtosl/OdtoslBll.cs、OdtosladdiBll.cs:nameof(ETA)/nameof(ShippedQuantity)→ 中文
LogicBll/Ade/E.Order/OrmastSave.cs、OrmastDelete.cs:d.ShippedQuantity/d.ETA→ 中文
LogicBll/E.Order/Darbedittool/DarbedittoolBll.cs:d.ETA = ...→d.預訂交期 = ...
ViewModel/D.Bom/Invent/Condition/SalesOrderConditionViewModel.cs:query condition string 內nameof(ShippedQuantity)→nameof(已交數量)
ViewModel/E.Order/OrmastStockQueryViewModel.cs:同上
ViewModel/E.Order/OrmastViewModel.cs:o.ETA = ...→o.預訂交期 = ...
ViewModel/E.Order/Ormast_sViewModel.cs:LINQ projection 內a.ETA/a.ShippedQuantity→ 中文
XAML caller 改名(5 檔、13 處)
XAML binding 改名 TsERP/E.Order/Cuinve.xaml {Binding QuantityPerCarton}→{Binding 包裝量_箱}TsERP/E.Order/Cuqt.xaml CustomerName× 2 /VendorName× 3 → 中文(master + grid column)TsERP/E.Order/Ormast.xaml ETA/ShippedQuantitygrid column → 中文TsERP/E.Order/Ormast_US.xaml 同 Ormast 3 處 TsERP/E.Order/Preord.xaml CustomerName× 2 →客戶簡稱工具鏈調整
- 4 個檔(vw_ormast、vw_pkde、vw_cupdt)原本 agent 寫
[TsDecimalPrecision(...)],但專案內只有TsDecimalLengthAttribute,統一改[TsDecimalLength(...)]
Breaking Changes
對「外部 caller / plugin」:
Twork_ord_vw_ordetlSource上沒了ETA、ShippedQuantity屬性,要用預訂交期/已交數量
Twork_ord_vw_cuqtmSource/Twork_ord_vw_cuqtdSource上沒了VendorName、CustomerName,要用廠商簡稱/客戶簡稱
Twork_ord_vw_cuinveSource上沒了QuantityPerCarton,要用包裝量_箱
Twork_ord_vw_preord_mSource上沒了CustomerName,要用客戶簡稱
RmamModel/RmamSource上沒了SysEntryDate / SysEntryUser / SysEntryMachine / SysRowStatus / SysIsChosen / SysControlCode,要透過 ModelBase 繼承的輸入日期/輸入人員等中文版
對使用者的影響
- 原本英文屬性綁的畫面:本次同步後改用中文版,runtime 行為應該等價(畢竟英文版本來就沒接到實際 DB 欄位、值是空的)
- vw_ormast 修活:原本 Source 沒包到
訂單編號 / 訂單別 / 客戶簡稱等核心欄位,畫面上對應欄位都是空的(XAML binding 找不到屬性靜默失敗);本次補上後 grid 該顯示正常
待人工複查 / 還沒清的部分
仍有 ~140 個英文 stale 屬性(多半在 ormast,SHEMAIL / CARDTYPE / AUDIT0X 等 EDI / legacy 欄位)沒清,分類如下:
- NoChange (69):modeljson 說欄位沒重命名,但實際 DB 查不到 → modeljson 過時或欄位廢除
- Orphan (73):modeljson 完全沒記載 → 多半是 ormast 內 EDI / legacy 英文欄位
- Renamed but no DB match (1):vw_ordetl 的
ETD(modeljson 說預計出貨日但 DB 沒此欄)
- SemanticGuess (1):vw_cuqtm 的
GroupDescription同檔沒中文版可配對
這些要等下一輪掃過再決定砍 / 補 / 保留為純 UI 屬性。
Build 狀態
Common.csproj/Model.csproj/ViewModel.csproj/LogicBll.csproj/TsERP.csproj全部 0 CS / 0 MC 錯誤、0 BG1002
連結
- 相關 skill:
.claude/skills/db-model-compare
- modeljson 權威來源:
D:\visualstudio\Generator\類別產生器\類別產生器\bin\Debug\net8.0-windows\modeljson\
-
05-17 tspage-to-tsview-batch ▸
2026-05-17 — TsPage → TsView 大批次遷移 + 拆 SqlEdit wrapper + RadGridView header 寫死中文
摘要
接續本日的 obs-to-datamanager(
fccf4d73)與 dg-to-radgrid(b9473cff)兩個批次,把同一批 52 個畫面遷移到TsView:1. 階段 A:42 個 XAML 從
TsPage改成TsView(含x:Name、ElementName、AncestorType、code-behind base class)2. 階段 B:同 42 個 XAML 移除
SqlEdit/SqlEditInventory外層 wrapper3. 階段 C′:C.GeneralAffair 4 個 XAML 把
RadGridView的Header={Binding DataContext.DisplayMeta[X]}寫死成Header="X",共 29 處4. 順手把 Ppurch.xaml(已 TsView)殘留的 2 處
ElementName=Page修掉剩下 10 個檔(C.GeneralAffair 6 + G.Purchasing Ppurch/Purch/Sppdt + R.HumanResource/Persmems)昨天遷移階段已轉好 TsView,今天不動。
變更
階段 A(42 個 XAML + 42 個 .xaml.cs)
XAML 內每檔做:
<TsControl:TsPage>/</TsControl:TsPage>→TsControl:TsView(含.TsPage.Resources→.TsView.Resources)
x:Name="Page"→x:Name="View"
ElementName=Page→ElementName=View
AncestorType=Page→AncestorType=TsControl:TsView
.xaml.cs內:: TsPage→: TsView。階段 B(42 個 XAML)
刪掉外層 wrapper(單行或多行):
<TsControl:SqlEdit ...>↔</TsControl:SqlEdit>
<TsControl:SqlEditInventory ...>↔</TsControl:SqlEditInventory>(H.Inventory 的 Trlima/Trlost/Trrama/Trsama)
內嵌使用的
TsControl:SqlEditTurn不動。階段 C′(4 個 XAML,29 處 header)
Header="{Binding DataContext.DisplayMeta[X], ElementName=View, FallbackValue=X}"→Header="X":- Ginvent (2 處)
- Gppurch (12 處)
- Gsplace (3 處)
- Gsppdt (12 處)
只動
tsTelerik:TsRadGridView內的 columnHeader;TsLabel/TsTextBlock的Content維持走 DisplayMeta 多語系。Breaking Changes
對「外部 caller / plugin」:
- View 類型從
TsPage(System.Windows.Controls.Page)變成TsView(UserControl)。原本靠 WPF Page navigation 開啟畫面的程式碼會壞,要改成 ContentControl swap(這套專案的 navigation 用 VM + DataTemplate 切換,主流程影響很小)
- code-behind 任何
(TsPage)this.xxx強制轉型會壞,要改TsView
- 外層 SqlEdit 沒了,下游的
BindingData推 DataContext 行為消失;如果有 binding 假設BindingData推下來的 DataContext,要手動補DataContext="{Binding ...}"
對使用者的影響:丟失的屬性
11 個檔失去 `HaveWorkflow="True"`
檔 原本行為 Purchasing/G.Purchasing/VendorDefect.xaml workflow 按鈕 / ADE 編輯狀態切換 Purchasing/G.Purchasing/VendorFillRate.xaml 同上 TsERP/E.Order/Ci.xaml 同上 TsERP/E.Order/Cupdma.xaml 同上 TsERP/E.Order/Pk.xaml 同上 TsERP/E.Order/Preord.xaml 同上 TsERP/F.Production/OutSourcingFillRate.xaml 同上 TsERP/G.Purchasing/VendorDefect.xaml 同上 TsERP/G.Purchasing/VendorEvaluation.xaml 同上 TsERP/G.Purchasing/VendorFillRate.xaml 同上 TsERP/H.Inventory/Trinout.xaml 同上 VM 若沒自行處理,這些頁面會失去 workflow 功能。需要後續補回(可考慮在 VM constructor 設旗標,或在 View 內加上其他 workflow 控制元件)。
其他失去的屬性
- TsERP/D.Bom/Invent_prime.xaml:
FirstRowSpace="25"+PkidVisibility="{Binding PkidVisibility}"
- TsERP/E.Order/Ormast_US.xaml:
FirstRowSpace="25"
FirstRowSpace主要影響表頭第一列的間距,視覺差異;PkidVisibility影響 Pkid 欄是否可見,邏輯影響。Column Header 寫死中文(C′)
C.GeneralAffair 4 檔的 grid header 不再走 DisplayMeta 取多語系,目前只顯示中文。
Common/Lang/Xaml/<檔名>.json內的 key 仍保留供TsLabel/TsTextBlock使用。過程中要修的問題
階段 B 的 worker agent 在 14 個檔(G.Purchasing+J.QC+K.Cost+M.EIS+P.Invoice 共 14 個)把
</TsControl:SqlEdit>替換成</Grid>而不是直接刪除,多出 1 個</Grid>close tag。Build 拋 MC3000 抓到,已用 PowerShell regex 統一拔掉檔尾多餘的</Grid>。Build 狀態
TsERP.csproj:連續 2 次 clean build 都是 0 XAML/CS 錯誤、0 BG1002 cascading
- 沒有看到 MC1000 mscorlib 工具鏈 hiccup(前兩個批次的常見 noise)
待人工複查
1. 11 個失去 HaveWorkflow 的檔:如果原本有用 workflow,要決定怎麼補回(VM 內處理 / View 內加控制 / 跳過)
2. Invent_prime 的
PkidVisibility:Pkid 欄顯隱規則重要,建議加回 VM 控制3. Ormast_US.xaml 的 SqlEdit 內直接子元素是
TsControl:TsTabControl不是Grid。TsView 只能一個直接子元素 — 目前編譯過了,runtime 行為要實測4. 縮排:刪 wrapper 後內層內容多了一層縮排,沒整理。要的話另跑 formatter
連結
- 本日批次:
- obs-to-datamanager:
fccf4d73- dg-to-radgrid + 5 個新 SeekGridViewColumn:
b9473cff- tspage-to-tsview(本檔)
- 範本:
TsERP/N.GeneralLedger/Accl.xaml(Master only)、TsERP/N.GeneralLedger/Sliy.xaml(Master + Detail)
- 相關 skill:
.claude/skills/tspage-to-tsview
-
05-17 obs-to-datamanager-batch ▸
2026-05-17 — ObservableCollection → DataManager 大批次轉換
摘要
把剩餘 67 個 ViewModel 的
ObservableCollection<T> Master/Detail/DetailN全面轉成DataManager<T> MasterData/DetailData/DetailNData,並同步更新對應 XAML 與外部 caller。此前已有 ~30 個 VM 在歷次零散轉換中完成,本次把剩下的全部清掉,達到專案內主資料 binding source 一致統一。順帶修活了多支「XAML 已寫成
{Binding MasterItem}但 VM 沒呼叫 Register、實際畫面空白」的程式(典型範例:Jobcode)。執行流程:分 B1(pilot 1 個)→ B2(單 Master 12 個)→ B3(Master+Detail 30 個)→ B4(3-5 sources 14 個)→ B5(部分轉換 cleanup 10 個含 Splace)。每批跑
dotnet build驗證。變更
ViewModel 層(67 檔,按模組分布)
模組 檔數 代表檔 C.GeneralAffair 9 Gtrlima, Gtrinout, Gsppdt, Gppurch, Gsplace, Gpurch, Ginvent, Gtrrama, Persmems(R) E.Order 14 Ci, Cudatam, Cuinve, Cupdma, Fillrate, Pk, Preord, Rma, Salema, Sample, Ormast, Cuqt, WarrantyCard, Shiptoaddress, Visit P.Invoice 10 Tother, Ticks, Ticksr, Tickr, Tickmin, Ticka_voidrp, Ticka_rej, Ticka_disc, Tick3, Ticka H.Inventory 11 Jobcode, Invrec, Bol, Splace, Trlost, Trinout, Trlima, Trrama, Trsama, MasterFile, (含 Splace cleanup) G.Purchasing 7 Purch, Ppurch, TrrafeePrime, Sppdt, VendorDefect, VendorFillRate, VendorEvaluation J.QC 5 Wkrama, Twrama, Repair, Purama, Complain F.Production 4 Wkpaper, Wkday, Pdtinf, OutSourcingFillRate Q.FixedAsset 2 Asset, Accexp D.Bom, K.Cost, M.EIS, Z.System 各 1 Invent_prime, Cost, ProductionPlan, Contract 每個 VM 的處理:
public ObservableCollection<T> XxxName { get/set + _backing }→public DataManager<T> XxxNameData { get; private set; }
- 構造子加
XxxNameData = ItemsBindingManager.Register<T>();(順序對應原本GetBindingSourcesPropertyName的 obj[n] 順序)
- 若 binding sources 全轉了,整段刪除
GetBindingSourcesPropertyName()override
- usages 替換:
.Count > 0→.FirstItem != null、[0]→.FirstItem、[idx]→.ObservableCollection[idx]、foreach→.ObservableCollection、.Add→.AddItem、.Clear→.Clear、= new ObservableCollection<T>(query)視語意改SeedFromRemote或AddRange
masterListenerHelper.SetProperty(ref _Master, value)→ 構造子裡MasterData.AddListener(helper)
XAML 層(~60 檔)
{Binding MasterItem}→{Binding MasterData.GridView.CurrentItem}
{Binding Master[0]}→{Binding MasterData.GridView.CurrentItem}
ItemsSource="{Binding Master}"→ItemsSource="{Binding MasterData.GridView}"
ItemsSource="{Binding Detail}"→ItemsSource="{Binding DetailData.GridView}"
ItemsSource="{Binding DetailN}"→ItemsSource="{Binding DetailNData.GridView}"
{Binding Master.Prop}→{Binding MasterData.GridView.CurrentItem.Prop}
含
Purchasing\G.Purchasing\VendorFillRate.xaml與Purchasing\G.Purchasing\VendorDefect.xaml(重複位置)一併修。外部 caller 與 BLL 簽章(17 處)
修了非主目標但會 reference
viewModel.Master/.Detail的下游:ViewModel/E.Order/WarrantyContentSpecialQueryViewModel.cs
ViewModel/E.Order/Ci_m1ViewModel.cs
ViewModel/E.Order/PreordControlViewModel.cs
ViewModel/E.Order/OrmastStockQueryViewModel.cs
ViewModel/E.Order/Ormast_sViewModel.cs
ViewModel/H.Inventory/InvrecmViewModel.cs
ViewModel/H.Inventory/WhseChangeViewModel.cs
ViewModel/H.Inventory/ItemTransferViewModel.cs
ViewModel/H.Inventory/PickingAdjustViewModel.cs
ViewModel/H.Inventory/StkMoveViewModel.cs
ViewModel/H.Inventory/BOLImportViewModel.cs
ViewModel/H.Inventory/TrramaAllocationViewModel.cs
ViewModel/H.Inventory/TrramaAllocationQueryViewModel.cs
ViewModel/H.Inventory/TrramaAPQueryViewModel.cs
ViewModel/H.Inventory/TrsamaPickingQueryViewModel.cs
ViewModel/C.GeneralAffair/GtrramaAllocationQueryViewModel.cs
LogicBll/E.Order/Cuqt/CuqtBll.cs:Import/AddDetail/AddDetail1參數從ObservableCollection<T>改DataManager<T>、.Add→.AddItem
Breaking Changes
對「外部 caller」(非本批內的 production code,例如 plugin / 自訂 BLL):
- VM 的
Master/Detail/DetailN屬性消失,改用MasterData/DetailData/DetailNData,且改成{ get; private set; }(不能再從外部賦值)
- 若外部要對清單操作:
.Add(item)→.AddItem(item)、.Clear()→.Clear()、.Count→.ObservableCollection.Count、[0]→.FirstItem
- 若外部要替換整批資料:原本
vm.Master = new ObservableCollection<T>(data)不能用,改vm.MasterData.SeedFromRemote(data.ToList())(不標 dirty)或vm.MasterData.AddRange(data)(會標 IsNew/IsDirty)
CuqtBll公開方法簽章變更:呼叫端要傳DataManager<T>而非ObservableCollection<T>
對使用者的影響
- 終端使用者大部分操作無感
- 修活畫面:原本 XAML 寫
{Binding MasterItem}但 VM 沒 Register 的程式(典型如 H.Inventory\Jobcode),本來開啟畫面什麼都沒有,現在正常顯示與編輯
- 可能行為改變:6 處
Detail.Insert(index, item)被改成DetailData.AddItem(item)(append 到尾端),如果原本有業務邏輯依賴「插入到特定位置」,使用者觀察到的順序會不同。詳見「待人工複查」
待人工複查
1. Insert(index) → AddItem 行為改變(6 處,已在原位用 `// NOTE:` 標註)
DataManager<T>目前沒有Insert(int index, T item)API,全改成 append。若這些位置有業務語意,要考慮在DataManager<T>補InsertItem(int index, T item):ViewModel/E.Order/Ci_m1ViewModel.cs:~166
ViewModel/E.Order/PreordControlViewModel.cs:~282
ViewModel/G.Purchasing/PurchViewModel.cs:~219
ViewModel/H.Inventory/TrlimaViewModel.cs:~340(2 處)
ViewModel/H.Inventory/WhseChangeViewModel.cs:~242
ViewModel/H.Inventory/PickingAdjustViewModel.cs:~146
2. 測試檔已壞,未修
下列測試檔用了
viewModel.Master = new ObservableCollection<>()物件初始化器語法,現在 setter 拿掉了會編譯失敗:UnitTest1/UploadTest/PurchasingTests.cs
UnitTest1/UploadTest/InventoryTests.cs:46, 134
Test_SqlModify/UploadTest/PurchasingTests.cs
Test_SqlModify/UploadTest/InventoryTests.cs:46, 134
Migration:物件初始化器中的
Master = new ObservableCollection<T> { ... }改成在arrange後另寫一句viewModel.MasterData.AddRange(new[] { ... })。Detail 同理。3. MasterFileViewModel 無對應獨立 XAML
ViewModel/H.Inventory/Edi_Export/MasterFileViewModel.cs是 nested VM、沒有獨立 .xaml 檔。VM 已轉,但實際上Edi_Export.xaml內並未綁定到它(tab DataContext 是Edi856ViewModel/Edi810ViewModel)。需要再確認這個 VM 是否還有用,若無可考慮整檔刪除。Build 狀態
ViewModel.csproj:exit 0、0 errors
TsERP.csproj:exit 0、0 errors
UnitTest1.csproj/Test_SqlModify.csproj:4 個檔需修才會通過(見「待人工複查 2」)
還剩什麼 ObservableCollection?
完成後仍有
ObservableCollection使用的檔案大多屬於:- ComboBox / dropdown 來源(非 binding source,不需轉)
- 統計查詢、暫存 list、UI 內部 buffer
- Helper / infrastructure(
ObservableCollectionExtensions、HistoryViewModel等)
不在這次轉換目標內。
-
05-17 dg-to-radgrid-batch ▸
2026-05-17 — TsDataGrid → TsRadGridView 大批次轉換 + 補建 SeekGridViewColumn
摘要
接續上午的
ObservableCollection → DataManager遷移(commitfccf4d73),把同一批 52 個 XAML 的TsDataGrid全部換成TsRadGridView,並補上對應DataManager="{Binding XxxData}"、把所有欄位類型/屬性照新版 API 改掉。過程中發現 6 個常用 Seek 欄位(Customer / Vendor / SalesRep / Bin / SKUGroup / Processing)在 Telerik 版下沒有對應類別,補建 5 個新類別(Processing 沿用既有)。變更
新增類別(5 個,`TsControl/TsTelerik/TsRadGridViewColumn/`)
類別 預設 Header / SeekCondition / SeekColumn ExistTable TsCustomerSeekGridViewColumn客戶代號 / 客戶代號 / 客戶簡稱 Cudata TsVendorSeekGridViewColumn廠商代號 / 廠商代號 / 廠商簡稱 Spdata TsSalesRepSeekGridViewColumn業務員編號 / 業務員編號 / 姓名 salesmen TsBinSeekGridViewColumn倉儲代號 / 倉儲代號 / 倉儲說明 Splace TsSKUGroupSeekGridViewColumn群組代號 / 群組代號 / 說明(DataMemberBinding=產品群組) Grpm 全部繼承
TsSeekGridViewColumn,行為與 V2 / DataGridV2 版本對等。預設綁中文欄位;XAML 若有需要可用DataMemberBinding覆寫。XAML(52 + 8 + 6 = 60 處/檔次)
容器與欄位
<TsControl:TsDataGrid>/<local:TsDataGrid>→<tsTelerik:TsRadGridView>
<DataGrid.Columns>/<TsControl:TsDataGrid.Columns>→<tsTelerik:TsRadGridView.Columns>
- 加上
xmlns:tsTelerik、xmlns:tsRadGridViewColumn
- Style key
ERPDataGrid→ErpDataGridView
- 每個
ItemsSource="{Binding XxxData.GridView}"補DataManager="{Binding XxxData}"
欄位類型對照
舊 新 TsDataGridTextColumnTsGridViewDataColumnTsDataGridNumericColumnTsGridViewDataNumericColumnTsDataGridTemplateColumnTsGridViewDataColumn(含 CellTemplate)TsDataGridComboBoxColumnTsGridViewComboBoxColumn(搭 BindingProxy)v2:TsDateColumnV2TsGridViewDataDateColumnTsSKUSearchColumn/TsSkuSeekColumnTsSkuSeekGridViewColumnTsCuspSearchColumnTsCuspSeekGridViewColumnTsBankAccountSeekColumnTsBankaccountSeekGridViewColumnTsDepartmentSearchColumnTsDepartmentSeekGridViewColumnTsGLAccountSearchColumnTsGLAccountSeekGridViewColumnTsGroupSeekColumnTsGroupSeekGridViewColumnTsIndexSearchColumnTsSortSeekGridViewColumnTsSKUFixedAssetSearchColumnTsSkuFixedAssetSeekGridViewColumnv2:TsUomColumnTsUomGridViewColumnTsVendorSearchColumn★TsVendorSeekGridViewColumnTsSalesRepSearchColumn★TsSalesRepSeekGridViewColumnTsBinSearchColumn★TsBinSeekGridViewColumnTsCustomerSeekColumn★TsCustomerSeekGridViewColumnTsSKUGroupSeekColumn★TsSKUGroupSeekGridViewColumnTsProcessingSearchColumn/TsProcessingSeekColumnTsProcessingSeekGridViewColumn★ 標記者本次新建類別。
屬性轉換
Binding="{Binding X}"→DataMemberBinding="{Binding X}"
MaskInfo="ShortDate"(在日期欄位)→ForceReadOnly="True"
BindingName="X"(V2 日期欄位)→DataMemberBinding="{Binding X}"
- Seek 欄位
Description="{Binding X, ...}"→DescriptionBindingPath="X"
- 欄位
Visibility=+VisibilityConverter→IsVisible=(容器 Visibility 維持)
- 移除:
ProgramClass、SelectFirstOnItemsChanged、ClipboardContentBinding="{x:Null}"、NeedTranslate、CheckValidate、CanUserReorder、AvoidEdit、欄位上殘留的DataGridTextColumn.ElementStyle/EditingElementStyle
TsGridViewComboBoxColumn用 BindingProxy 處理ItemsSourceBinding
- ElementStyle/EditingElementStyle 內含的 TextWrapping / AcceptsReturn 改用
CellTemplate/CellEditTemplate重做(Ormast_US、Persmems)
- Button template 改
TsButtonInCell+CellStyle="{StaticResource ButtonCell}"
涵蓋檔案(52 XAML)
C.GeneralAffair (6):Ginvent、Gppurch、Gsplace、Gsppdt、Gtrlima、Gtrrama
E.Order (13):Ci、Cudatalimit、Cuinve、Cupdma、Cuqt、Fillrate、Ormast、Ormast_US、Pk、Preord、Rma、Salema、Sample
F.Production (4):OutSourcingFillRate、Pdtinf、Wkday、Wkpaper
G.Purchasing (6+2):Ppurch、Purch、Sppdt、VendorDefect、VendorEvaluation、VendorFillRate(+ Purchasing 專案 mirror 2 個)
H.Inventory (8):Bol、Invrec、Splace、Trinout、Trlima、Trlost、Trrama、Trsama
J.QC (4):Complain、Purama、Twrama、Wkrama
P.Invoice (5):Ticka、Ticka_disc、Tickr、Ticks、Ticksr
其他:K.Cost/Cost、M.EIS/ProductionPlan、D.Bom/Invent_prime、R.HumanResource/Persmems
Breaking Changes
對「外部 caller / plugin」:
- 上述 52 個 XAML 的 grid x:Name 仍可用,但是元件類型變了。code-behind 若有
(TsDataGrid)detailDataGrid.xxx強制轉型會壞 — 全部要改成TsRadGridView。
- 舊 column 類別屬性差異會影響 templated style:
-
Binding→DataMemberBinding-
Description字串 →DescriptionBindingPath字串(只取 path,不接 Binding 標記)- column 上
Visibility不能用,改IsVisible(bool)TsDataGrid上的下列 API 在新版不存在:NeedTranslate、CheckValidate、CanUserReorder(column)、AvoidEdit、column 上ProgramClass、SelectFirstOnItemsChanged
- 新建 5 個 SeekGridViewColumn 預設 binding 用中文(客戶代號 / 廠商代號 / 業務員編號 / 倉儲代號 / 產品群組);若 row 物件屬性為英文,XAML 必須用
DataMemberBinding覆寫
對使用者的影響
- 一般操作無感
- 修活的畫面:Jobcode 之類「XAML 寫對但 VM 沒 Register」的程式(昨天 obs-to-datamanager 那批同樣狀況)正常顯示
- 行為觀察點:
-
TsProcessingSeekGridViewColumn中文預設(SeekCondition=工程代號)被 Cuqt / Wkpaper / Gsppdt 用英文 DataMemberBinding 覆寫綁;seek popup 查 PROCNOS 表的欄位是中文,要確認該表中英欄位齊全-
TsSalesRepSeekGridViewColumn中文預設被 Cuinve 用英文(SalesRepCode)覆寫,同樣風險-
TsCustomerSeekGridViewColumn在 Cudatalimit 沒 DataMemberBinding 覆寫 → 會用類別預設客戶代號,需要該 row 物件有此屬性才綁得到待人工複查
1. Invent_prime.xaml 內側仍有一個
TsControl:TsVirtualGrid(不是TsRadGridView),inner columns 已還原為TsDataGridTextColumn/TsDataGridTemplateColumn(與容器搭配正確)。但同檔另一個獨立的tsTelerik:TsRadGridView(DetailData)少設DataManager="{Binding DetailData}",仍可用但建議補上以保留 DataManager 行為。2. Pk.xaml 原始 source 有個 typo
BindingName="{Binding 結關日期}"(BindingName 接的是字串 path),E.Order worker 直接轉成DataMemberBinding="{Binding 結關日期}",runtime 行為可能改變,要確認原意。3. 6 處
Detail.Insert(index, item)改成AddItem(append)(屬於昨天 obs-to-datamanager 留下的// NOTE:標註):若DataManager<T>之後補InsertItem(int, T),這些位置可一併還原。4.
TsBinSearchColumn→TsBinSeekGridViewColumn還原時保留了FilterCondition="{Binding WarehouseFilter}"/FilterCondition="{Binding FilterCondition}",行為應等價。Build 狀態
TsERP.csproj:0 XAML 編譯錯誤、0 CS 錯誤
- 多次 build 中偶發
MC1000檔案鎖定 / mscorlib 解析警告,屬於 .NET SDK 10 MSBuild WPF MarkupCompile 工具鏈問題,與本次內容無關
連結
- 相關 skill:
.claude/skills/dg-to-radgrid
-
05-13 per-customer-config ▸
2026-05-13 — 客戶端設定檔同步機制
對應 ADR 0019。
摘要
- 新增
DatabaseListSourcePath設定,TsERP 啟動時依此路徑將客戶專屬DatabaseList.xml同步到本機目的地
- 拿掉「找不到
DatabaseList.xml時自動產生預設清單」的行為
- 新增
deploy/deploy-customer.ps1部署腳本,給 IT 人員在客戶機器一鍵建立設定檔
TsERP.SchedulerWorker同步支援此機制
新增
appsettings.json新欄位DatabaseListSourcePath(TsERP / SchedulerWorker 皆有)
Common\Environment\XmlSqlLocation.EnsureDatabaseList()靜態方法
deploy/deploy-customer.ps1:參數化部署腳本
docs/deployment/per-customer-setup.md:部署 SOP 文件
變更
XmlSqlLocation.GetSqlDataBase()不再呼叫CreateList(),僅讀檔
TsERP/App.xaml.cs:在 DI 註冊前呼叫EnsureDatabaseList(),失敗以MessageBox提示 +Shutdown(1)
TsERP.SchedulerWorker/Program.cs:同樣在 DI 註冊前呼叫EnsureDatabaseList()
刪除
XmlSqlLocation.CreateList()/EditToNewDatabase()/GetData()(含寫死的預設清單)
Breaking Changes
- 開發機若依賴自動產生的預設
DatabaseList.xml會啟動失敗。處理方式:
1. 手動在
c:/TEMPS/SqlLocation/DatabaseList.xml放開發環境清單,或2. 在
%ProgramData%\TsERP\appsettings.local.json設DatabaseListSourcePath指向 dev XML,或3. 跑
deploy/deploy-customer.ps1把開發環境當客戶處理- 新客戶部署流程改變:除了裝 TsERP 本體,需先跑部署腳本(或手動準備
DatabaseList.xml)
Migration Notes
客戶端
- 已部署、且
DatabaseList.xml已存在的客戶:啟動行為無變化
- 新客戶:請參照
docs/deployment/per-customer-setup.md
集中管理客戶設定
DatabaseListSourcePath可指向網路磁碟路徑(例:\\fileserver\TsERPConfig\客戶A\DatabaseList.xml)
- IT 在中央位置更新後,所有客戶下次啟動會依
LastWriteTime自動同步
- 新增
-
05-09 mailqueue-channel ▸
2026-05-09 — 排程信件改走 mailqueue + Mailgun(Database Mail 不再必要)
摘要
SchedulerJob加入 Phase 3DequeueMailAsync:AutoPilot SP 把組好的信件寫進新表twork_skd_mailqueue,由 SchedulerWorker 統一透過既有 Mailgun 通道寄出。客戶端 SQL Server 不再需要設定 Database Mail。新增
- 資料表
twork_skd_mailqueue:排程信件佇列(中文欄位、狀態碼 N/R/Y/F/D 對齊既有已通知/已完成風格)
- SP
TWORK_SKD_MAILQUEUE_DEQUEUE:批次撈待寄信件 + 殭屍回收(>10 分鐘卡 R 自動回 N)
- SP
TWORK_SKD_MAILQUEUE_UPDATE_STATUS:寄送結果回寫,含指數退避(30/60/120/240/480 秒)與死信判定
Procedure.TWORK_SKD_MAILQUEUE_DEQUEUE/TWORK_SKD_MAILQUEUE_UPDATE_STATUSenum
SchedulerJob.DequeueMailAsync:第三 phase,每輪 dequeue 20 筆 → Mailgun → 更新狀態
變更
IMailService.SendAsync新增 optionalisHtml = false參數;MailGunService 在isHtml=true時改用 Mailgun 的html欄位(之前只走text)
SchedulerJob.RunOnceAsync對每個 DB 從 2 phase 變 3 phase(Notify → AutoPilot → DequeueMail)
FakeMailService同步補isHtml參數
刪除
無
Breaking Changes
無:
IMailService.SendAsync是 optional 參數;mailqueue 是新增表。AutoPilot SP 內仍走EXEC msdb.dbo.sp_send_dbmail的客戶不會壞,可漸進改寫。Migration Notes
1. DBA:對每個目標 DB 跑 schema script
SqlBI/twork_skd_mailqueue.sql -- 建表 + index SqlBI/TWORK_SKD_MAILQUEUE_DEQUEUE.sql -- 出列 SP SqlBI/TWORK_SKD_MAILQUEUE_UPDATE_STATUS.sql -- 結果回寫 SP2. AutoPilot SP 改寫範本(漸進式)
把:
EXEC msdb.dbo.sp_send_dbmail @profile_name = N'qq', @recipients = ..., @subject = @subject, @body = @body, @body_format = N'HTML';換成:
INSERT dbo.twork_skd_mailqueue (收件人, 主旨, 內文, 是否HTML, 來源預存程序, 執行guid) VALUES (@recipients, @subject, @body, 'Y', OBJECT_NAME(@@PROCID), @execguid);HTML 組裝(
FOR XML PATH)整段保留,不必重寫。3. 部署順序
1. 先建新 SP / 新表
2. 再升級 SchedulerWorker
3. 一支一支改寫 AutoPilot SP(PoC 推薦從
TWORK_MOLD_SENDMAIL開始)4. 監控查詢
SELECT 狀態, COUNT(*) FROM dbo.twork_skd_mailqueue GROUP BY 狀態; -- 死信檢視 SELECT pkid, 主旨, 重試次數, 最後錯誤, 來源預存程序 FROM dbo.twork_skd_mailqueue WHERE 狀態 = 'D' ORDER BY 建立時間 DESC;相關 ADR
- 資料表
-
05-05 sql-connection-tuning ▸
2026-05-05 — SQL 連線字串補上效能與安全參數
摘要
使用者反映「連 SQL 執行命令有時候比較久」。實測冷啟動 145 ms vs 熱連線 2-3 ms,差距 50 倍。
Microsoft.Data.SqlClient4.0+ 預設Encrypt=True會在內網每次新連線多一段 TLS 交涉。本次在DataBaseParameter.ConnectionString補上Encrypt(依 Azure 旗標切換)、Min Pool Size=1、Connection Timeout=15。詳細決策見 ADR 0016。變更
Common\Environment\DataBaseParameter.cs:ConnectionStringgetter 加入:
-
Encrypt=False(地端)/Encrypt=True(Azure,依Poco.IsAzure)-
Min Pool Size=1— 確保連線池常駐至少一條熱連線-
Connection Timeout=15— 顯式寫出(雖是預設值),方便日後微調對使用者的影響
- 終端使用者:地端連線冷啟動更快;閒置一段時間後第一次操作不會再卡頓
- 管理員 / DBA:無需動 SQL Server 設定
- 開發者:若新增「公網但非 Azure」的連線目標,需要評估
Encrypt=False是否安全;目前判斷依據是DatabaseList.xml的<IsAzure>元素
不在本次範圍
DataBaseDal\PrimeConn.cs與PrimeBll\PrimeConn.cs內各自硬編的ConnectionString未一併修改。Prime 模組相關功能(佣金生成、Prime AR/AP)的連線字串仍是舊格式,若使用者使用該功能且需要相同優化,需後續另開 task
-
05-05 scheduler-log-dedicated-folder ▸
2026-05-05 — SchedulerWorker 改用 SchedulerLog,log 寫到獨立資料夾
摘要
SchedulerWorker 原本透過
Console.WriteLine(正式環境會被丟棄)與DebugLog(只在 catch 區塊呼叫)記錄歷程,導致正式環境完全看不到正常運作訊息。本次新增SchedulerLoghelper,把所有歷程統一寫到C:\temps\scheduler\yyyy-MM-dd.txt,每天一個檔。詳細決策見 ADR 0017。新增
TsERP.SchedulerWorker\SchedulerLog.cs:
- 寫到
C:\temps\scheduler\yyyy-MM-dd.txt- 兩個層級:
Info/Error- 行格式:
yyyy-MM-dd HH:mm:ss [LEVEL] 訊息- 同步輸出到 Console(保留手動執行時可見)
-
lock保護併發;try/catch吃掉 logging 失敗變更
TsERP.SchedulerWorker\SchedulerJob.cs:所有Console.WriteLine/Console.Error.WriteLine/new DebugLog().WriteLog(...)→SchedulerLog.Info(...)/SchedulerLog.Error(...)
TsERP.SchedulerWorker\Program.cs:同上
docs/admin/scheduler.md:更新所有 log 路徑說明,從c:\temps\SCHED\與C:\ERPDeploy\Scheduler\logs\統一改為C:\temps\scheduler\;新增行格式範例
Migration Notes
部署 server 端必做:
# 建立 log 資料夾並設權限 New-Item -Path "C:\temps\scheduler" -ItemType Directory -Force icacls "C:\temps\scheduler" /grant "<服務帳號>:(OI)(CI)M"資料夾不存在時
SchedulerLog會自動建立,但服務帳號必須對C:\temps\有寫入權,否則 logging 會靜默失敗。舊的
C:\temps\debuglog\內 SchedulerWorker 歷史 log 保留,未來不再寫入。對使用者的影響
- 終端使用者:無感
- 管理員:
- 首次能在正式環境看完整歷程(每個 DB 跑了什麼、處理了哪些 pkid、exit code)
- 看 log 的位置從
c:\temps\SCHED\/C:\ERPDeploy\Scheduler\logs\(先前實際也不存在,文件腐爛)改成C:\temps\scheduler\yyyy-MM-dd.txt- DBA / IT:部署需多一步建資料夾與設權限(見 Migration Notes)
- 開發者:未來在 SchedulerWorker 內加新訊息,請使用
SchedulerLog.Info/SchedulerLog.Error,不要回去用Console.WriteLine或DebugLog
-
05-04 skd-sp-split ▸
2026-05-04 — TWORK_SKD_NOTIFYEVENT 拆兩支 + 修積累 bug
摘要
TWORK_SKD_NOTIFYEVENT原本一支 SP 透過@QueryType包了「待 Email 通知」與「待 AutoPilot 自動執行」兩個無關查詢,且@QueryType=2分支累積兩個 bug(停用應是是否停用、殭屍判定還在用退役狀態碼'X')。本次拆成兩支單一職責 SP 並順手修掉。詳細決策見 ADR 0015。新增
- SP
TWORK_SKD_GET_PENDING_NOTIFY(SqlBI/TWORK_SKD_GET_PENDING_NOTIFY.sql):撈待 Email 通知事件,取代原@QueryType=1分支
- SP
TWORK_SKD_GET_PENDING_AUTOEXEC(SqlBI/TWORK_SKD_GET_PENDING_AUTOEXEC.sql):撈待 AutoPilot 自動執行事件,取代原@QueryType=2分支
Procedure.cs加 2 個對應 enum:TWORK_SKD_GET_PENDING_NOTIFY、TWORK_SKD_GET_PENDING_AUTOEXEC
變更
TsERP.SchedulerWorker/SchedulerJob.cs:
-
NotifyAsync:改打TWORK_SKD_GET_PENDING_NOTIFY,移除lp_p1="1"魔術數字-
AutoPilotAsync:改打TWORK_SKD_GET_PENDING_AUTOEXEC,移除lp_p1="2"魔術數字- 兩處
Update已通知/Update已完成(pkid, "X", ...)→"R"(對齊 ADR 0013,先前漏改)Common/DataBaseObjectEnum/Procedure.cs:舊TWORK_SKD_NOTIFYEVENT標[Obsolete],註解指向 ADR 0015
- SP
TWORK_SKD_GET_PENDING_AUTOEXEC內 bug 修復(相對於原@QueryType=2):
-
停用 <> 'Y'→是否停用 <> 'Y'(對齊Twork_skd_vw_eventitemModel.是否停用)-
已完成 <> 'X'→已完成 <> 'R'(殭屍判定恢復作用)-
DATEADD(MINUTE, -10, GETDATE())→DATEADD(MINUTE, -10, @datetime)(基準時間可由 caller 控制)刪除
- 無 — 舊 SP
TWORK_SKD_NOTIFYEVENT留在 DB 與 enum 中,標[Obsolete]漸進淘汰(Migration Notes 第 4 步說明何時可 drop)
Breaking Changes
- DB schema 必動:兩支新 SP 必須先在 DB 建立才能升 SchedulerWorker,否則 worker 跑不起來
- 殭轉判定真的會生效:先前
'X'bug 等於沒判殭屍;現改'R'後,超過 10 分鐘還在執行中的事件會被視為前一輪 crash 而重撈。若 production 真有合法跑超過 10 分鐘的事件,會被重複撈 → 重複跑。建議先觀察一輪執行開始時間分布,視情況調大殭屍 timeout(目前 hardcode 10 分鐘)
- 直呼舊 SP
TWORK_SKD_NOTIFYEVENT的外部腳本 / 排程不受影響(SP 還在),但建議遷移到新 SP
Migration Notes
DBA 端(每個目標 DB 必跑)
-- 1. 建立待通知 SP CREATE PROCEDURE [dbo].[TWORK_SKD_GET_PENDING_NOTIFY] (@datetime datetime) AS BEGIN SET NOCOUNT ON; SELECT * FROM dbo.twork_vw_calendarevent WHERE 已審核 = 'Y' AND 是否停用 <> 'Y' AND 通知 = 'Y' AND 通知帳號 <> '' AND 已通知 <> 'Y' AND @datetime >= 通知時間; END GO -- 2. 建立待自動執行 SP CREATE PROCEDURE [dbo].[TWORK_SKD_GET_PENDING_AUTOEXEC] (@datetime datetime) AS BEGIN SET NOCOUNT ON; SELECT TOP 20 * FROM twork_vw_calendarevent WHERE 已完成 NOT IN ('Y', 'F') AND (已完成 <> 'R' OR 執行開始時間 < DATEADD(MINUTE, -10, @datetime)) AND 已審核 = 'Y' AND 是否停用 <> 'Y' AND 是否自動執行 = 'Y' ORDER BY 預定時間 ASC; END GO完整 script 在
SqlBI/TWORK_SKD_GET_PENDING_NOTIFY.sql與SqlBI/TWORK_SKD_GET_PENDING_AUTOEXEC.sql。部署順序
1. DBA 先建新 SP(上述兩個
CREATE PROCEDURE)2. Build & deploy 新版
TsERP.SchedulerWorker3. 觀察 1-2 輪正常運轉:看
c:\temps\SCHED\內 log 有Notify pkid=.../AutoPilot pkid=...紀錄4. 可選清理:確認穩定後
DROP PROCEDURE TWORK_SKD_NOTIFYEVENT順序顛倒會在升級 gap 期間 SchedulerWorker 找不到 SP 而 crash。
對使用者的影響
- 終端使用者:無感,UI / 行為不變
- 管理員:殭屍事件回收機制現在真的有作用 — 若有事件卡在
R狀態超過 10 分鐘會被視為前一輪 crash 重撈
- DBA:必跑兩個
CREATE PROCEDUREscript
- 開發者:撈待辦事件不再透過
@QueryType魔術數字,新增類似查詢時直接命名新 SP 即可
- SP
-
05-04 rightcalendar-ux-overhaul ▸
2026-05-04 — RightSideCalendar UX 全面改造(圓點著色 / 過期紅色 / 已完成灰階 / 按鈕下排 / async 月快取)
摘要
接續同日
2026-05-04-rightcalendar-event-dot-fix.md的事件圓點修復,本次再做一輪視覺與資料層的改進:日曆圓點按擁有者類別著色、過期未完成事件標紅、已完成事件灰階加刪除線、4 顆操作按鈕從事件右側移到下排,事件清單寬度大幅增加;資料層改 async + 月份快取,切月份不再卡 UI、同月切換不重抓 server;ViewModel 的 4 個Show*屬性整併成OwnerFilterscollection,新增擁有者類別不必再 patch 4 個屬性。詳細決策見 ADR 0014。
新增
ViewModel/MainWindowPage/OwnerFilterItem.cs:擁有者篩選 item POCO(OwnerType/DisplayName/IsVisible/IsChecked)
CalendarPageViewModel.OwnerFilters:ObservableCollection<OwnerFilterItem>,4 顆 toggle 的 binding 來源
CalendarPageViewModel.EventSummaryByDate:Dictionary<DateTime, DayEventSummary>,每日Count+DominantOwnerType,給日曆圓點著色用
CalendarPageViewModel.HasNoEventsToday/HasFilteredOutAll:空狀態分流;前者是「該日完全無事件」,後者是「該日有事件但全被 toggle 篩掉」
CalendarPoco.已過期未完成:衍生屬性(預定時間 < Now && 已完成 != "Y"),給事件 row 標紅用
EventDayTemplateSelector新增 4 個 owner 變體 template:EventTemplatePersonal/Department/Company/System
RightSideCalendar.xamlUserControl.Resources新增 9 個 brush:EventDatePrimaryBrush/EventOwnerSecondaryBrush/EventItemBackgroundBrush/EventEmptyHintBrush/EventOverdueBrush/OwnerColorPersonal/OwnerColorDepartment/OwnerColorCompany/OwnerColorSystem
- 內部欄位
_monthCache: Dictionary<(int Year, int Month), List<CalendarPoco>>:client-side 月份事件快取
- 新增
LoadEventsForMonthAsync(DateTime, bool)private method 取代舊 sync 版
變更
ViewModel/MainWindowPage/CalendarPageViewModel.cs:
- 移除
Show個人 / Show部門 / Show公司 / Show系統屬性與對應欄位- 移除
_show系統UserSet旗標、CanSee系統唯讀屬性、EventDates(HashSet<DateTime>)- 移除 public
GetEvent(string date)(唯一外部呼叫已被註解,改全部走LoadEventsForMonthAsync)- 移除
LoadEventsForMonth同步版,改LoadEventsForMonthAsync-
IsOwnerVisible從 byte switch (0/1/2/9) 改成查OwnerFilters,magic number 消失-
RefreshUserPermission簡化:只看IsAdmin()變化來決定要不要同步系統 toggle 的IsVisible/IsChecked,不再用_show系統UserSet旗標-
DisplayDate.set/Refresh()用_ = LoadEventsForMonthAsync(...)fire-and-forget- 例外處理改為
try/catch + TsMsgBox.ShowError包在LoadEventsForMonthAsync內,避免 fire-and-forget 例外被吞掉-
HasNoEvents拆成HasNoEventsToday+HasFilteredOutAllLogicBll/Calendar/CalendarPoco.cs:
-
已完成Binding.set連帶通知已過期未完成屬性變更(取消勾選後紅色立即恢復)TsControl/Calendar/EventDayTemplateSelector.cs:
- 從原本 1 個
EventTemplate加 fallback 變成 5 個(4 種 owner + fallback gray)-
SelectTemplate改用vm.EventSummaryByDate查DominantOwnerType,再透過vm.Context.EnumManager.EventOwner把 byte 對應到 enumTsControl/Calendar/RightSideCalendar.xaml:
- 4 個獨立
TsToggleButton改成ItemsControl綁OwnerFilters+UniformGrid Columns=4+DataTemplate- 4 顆操作按鈕(導航 / 執行 / 附件 / 報告)從事件 row 右側
Grid.Column=2移到下排Grid.Row=1,用UniformGrid Columns=4等寬排列-
EventControlDataTemplate 內:根 Grid 已完成時Opacity=0.5、EventDate過期未完成 Foreground 變紅、EventTitle已完成加TextDecorations="Strikethrough"- 新增 5 個 EventTemplate XAML block 對應 4 種擁有者類別 + 1 fallback
- 硬編色(
#FF000000/#FF686868/#FFEBEBEB/#FF888888)改用StaticResource引用UserControl.Resources內的 brush- 空狀態 TextBlock 拆兩個:「今日無事件」綁
HasNoEventsToday、「事件已被篩選」綁HasFilteredOutAllViewModel/Common/DataNavigateHelperV2.cs:
- 順手清掉先前診斷 row scroll 問題暫加的
Debug.WriteLine(無功能影響)刪除
CalendarPageViewModel.GetEvent(string date)public method(唯一 caller 已被註解,無實際使用)
CalendarPageViewModel.EventDates(HashSet<DateTime>) 屬性(被EventSummaryByDate取代)
CalendarPageViewModel.Show個人 / Show部門 / Show公司 / Show系統屬性與對應 fields
CalendarPageViewModel.CanSee系統屬性
CalendarPageViewModel._show系統UserSet旗標
CalendarPageViewModel.HasNoEvents屬性(拆成兩個)
Breaking Changes
- 任何外部 XAML / code 若 binding 過
Show個人 / Show部門 / Show公司 / Show系統 / CanSee系統 / EventDates / HasNoEvents,會 binding error。grep 後本 repo 內無此 caller。
CalendarPageViewModel.GetEvent(string)已移除;外部呼叫者請改用Refresh()。本 repo 內無 caller。
Migration Notes
- 無 SQL / 設定變更
- 多語系:新增一條 key
事件已被篩選;未設定時 fallback 到中文字面值,不會 crash
- 顏色與資源:所有 brush 集中在
RightSideCalendar.xaml的UserControl.Resources,未來若要抽到 theme dictionary 一處改即可
對使用者的影響
- 切月份順了:DB 抓資料推到背景 thread,UI thread 不再被卡;同月份切回來不重抓 server
- 過期事件醒目:日期已過但未勾「已完成」的事件,事件 row 上方時間文字會變紅
- 已完成事件視覺淡化:整個 row
Opacity=0.5、標題加刪除線;列表上一眼分辨「已處理」與「待處理」
- 日曆圓點上色:每日事件圓點顏色反映「該日事件最多者」的擁有者類別 — 橘=個人、綠=部門、藍=公司、深灰=系統。掃過月曆能看出主要事件來源
- 事件文字變寬:4 顆操作按鈕從右側移到下排,事件標題與說明的可用寬度從約 60px 增加到約 180px,內容不再被截
- 空狀態分流:當天若資料庫真的無事件,顯示「今日無事件」;若有事件但全被 4 個擁有者 toggle 篩掉,改顯示「事件已被篩選」,避免使用者誤以為資料消失
- 管理員系統 toggle 行為更直觀:admin 第一次開日曆會把「系統」toggle 設成可見且勾選;admin 在 session 內手動取消勾選後,後續
Refresh()不會再被打回去(除非IsAdmin()權限本身變化)
-
05-04 rightcalendar-event-dot-fix ▸
2026-05-04 — RightSideCalendar 事件圓點修復、擁有者篩選與重構
摘要
右側
RightSideCalendar的當日事件圓點之前只有時間正好是 00:00:00 的事件才顯示,其他時間的事件會被當作「無事件」漏掉。同時CalendarPageViewModel的屬性 setter 內含 DB 抓取與 filter 副作用,月切換每格都跑 LINQ。順手把死碼清掉、加上個人 / 部門 / 公司 / 系統四類擁有者的多選 toggle 篩選(系統需 admin 權限),並加上空狀態提示與錯誤處理。新增
- 擁有者類別篩選:右側日曆下方 4 顆 ToggleButton(個人 / 部門 / 公司 / 系統),多選;預設個人+部門+公司開啟、系統依
Context.User.IsAdmin()決定是否顯示
CalendarPageViewModel.Show個人 / Show部門 / Show公司 / Show系統:篩選 toggle binding 屬性
CalendarPageViewModel.CanSee系統:唯讀屬性,控制系統 toggle 的顯示與可勾性,等於IsAdmin()
CalendarPageViewModel.HasEvents / HasNoEvents:給「今日無事件」空狀態提示用的衍生屬性
CalendarPageViewModel.EventDates:HashSet<DateTime>,在Events被指派時一次算好;給EventDayTemplateSelectorO(1) 查詢用
- 內部欄位
_eventsByDate(ILookup<DateTime, CalendarPoco>):以日為鍵預先 group,SelectedDate變更時 O(1) 過濾
- 「今日無事件」空狀態文字:當所選日期 / 篩選條件下無事件時顯示
變更
TsControl/Calendar/EventDayTemplateSelector.cs:
- 從
Events.Select(...).Any(x => x.預定時間 == content.Date)改為vm.EventDates.Contains(content.Date.Date)- 順帶修掉
預定時間(含時分)對content.Date(午夜)的不對等比較 → 以.Date正規化為日比對TsControl/Calendar/RightSideCalendar.xaml:
- ListBoxItem 內 7 處
ElementName=Grid, Path=DataContext.XxxCommand→ 改用RelativeSource AncestorType=UserControl,不再依賴 root grid 命名- 新增 4 顆
TsToggleButton篩選列(UniformGrid 4 欄)- 新增「今日無事件」空狀態 TextBlock,與 ListBox 互斥顯示
- 移除死碼:
StepTemplate、TaskStepListBoxStyle、EventCardTemplateSelector整段ViewModel/MainWindowPage/CalendarPageViewModel.cs:
-
Events.set內預建_eventsByDate與EventDates,並觸發RefreshFiltered()-
SelectedDate.set移除 LINQ filter;改呼叫RefreshFiltered()-
DisplayDate.set移除if (NeedGetEvents) ...內聯邏輯;改呼叫LoadEventsForMonth(value, force:false)- 新增
RefreshFiltered()/LoadEventsForMonth(monthDate, force)/IsOwnerVisible(poco)三個 private method-
Refresh()從 hack 寫法 (DisplayDate = default; DisplayDate = date;) 改為LoadEventsForMonth(date, force:true)-
已完成Execute/NavigateExecute包 try/catch +TsMsgBox.ShowError;已完成Execute失敗時還原 UI 勾選避免 UI/DB 不一致- 兩個 setter 改為只有值變動才觸發(加
if (_xxx == value) return;),減少不必要的 PropertyChanged- 移除未被任何 XAML 使用的
EventText、LayoutText屬性 與QueryCommandLogicBll/Calendar/CalendarPoco.cs:
-
Get擁有者類別描述()從 if/else 寫死 (0/1/2) 改成委派給Context.EnumManager.EventOwner.GetEventOwner(...).Description,正確處理9 = 系統(之前回空字串)刪除
TsControl/Calendar/EventCardTemplateSelector.cs整檔(XAML 已不再 reference,本次連 selector 一起拿掉)
Breaking Changes
- 無;
Events/SelectedDate/DisplayDate/Refresh()公開介面與行為均維持相容
Refresh()仍會把SelectedDate對齊月初(與原版一致),外部呼叫者 (EventSelfViewModel.OnAfterAudit、EventProjectViewModel.AfterMoverRecord) 行為不變
Migration Notes
- 無 SQL / 設定變更,純 .NET 端重構
- 多語系:toggle 文字以
DisplayMeta[個人 / 部門 / 公司 / 系統]取得,未設定時 fallback 到中文字面值
對使用者的影響
- 圓點正確顯示:右側日曆中,只要該日有事件(不論時間是幾點),日期格底下都會出現灰色圓點。原本只有 00:00 事件才顯示
- 月份切換較順:日曆 render 從 O(N×天數) LINQ 降到 O(1) HashSet 查表
- 可依擁有者篩選:4 顆 toggle 自由切換顯示哪幾類事件
- 管理員專屬:「系統」toggle 僅 admin 可見可選;非 admin 即使資料有系統事件也不會顯示在清單
- 空狀態提示:當天無事件(或被篩選掉)時顯示「今日無事件」
- 錯誤可見:勾選「已完成」或點「導航」失敗時顯示錯誤訊息,不再吞掉
- 擁有者類別篩選:右側日曆下方 4 顆 ToggleButton(個人 / 部門 / 公司 / 系統),多選;預設個人+部門+公司開啟、系統依
-
05-03 remove-commpr2-org-titles ▸
2026-05-03 — 移除 commpr_2 的「單位」「職稱」欄位
摘要
從
Twork_com_vw_commpr_2Model移除單位與職稱兩個欄位,並同步清理上下游:兩個 Source、TodoListPoco 衍生屬性、Emailsender 頁面欄位、多語系設定。刪除
Twork_com_vw_commpr_2Model.單位Twork_com_vw_commpr_2Model.職稱兩個 string property
Twork_com_vw_commpr_2Source與WorkflowStepSource對外曝露的單位職稱property wrapper
TodoListPoco.OrganizationTodoListPoco.Titles衍生屬性與其在SetData(Twork_com_vw_commpr_2Source)/SetData(WorkflowStepSource)中的賦值
Emailsender.xaml中 detail grid 的「單位」「職稱」兩欄
- 多語系:
Common/Lang/Xaml/Emailsender.json與Common/Lang/Model/Twork_com_vw_commpr_2.json內對應 key
變更
無(本次純刪除,無功能調整)。
新增
無。
Breaking Changes
- 凡讀取
Twork_com_vw_commpr_2Source.單位/.職稱、WorkflowStepSource.單位/.職稱、或TodoListPoco.Organization/.Titles的外部程式碼會編譯失敗。
- DB view
twork_com_vw_commpr_2端若仍保留這兩個欄位,目前 Dapper 反射映射會忽略它們,不會炸;建議由 DBA 視情況決定是否同步移除。
Migration Notes
若有外掛或自訂程式需要顯示處理人的單位/職稱,請改從
Context.DescriptionHelper.GetPerdata(處理人編號)即時查詢人事檔取得。 -
05-03 eventitem-status-r-completion-time ▸
2026-05-03 — EventItem 狀態:X → R + 完成時間自動寫入
摘要
twork_skd_eventitem的「執行中」狀態碼從'X'(視覺上像失敗)改為'R'(Running)。已完成 = 'Y'時 SP 自動寫完成時間 = GETDATE()。AutoPilotHelper.ExecuteMethod補完整生命週期:執行前標'R'、成功標'Y'、失敗標'F',這樣執行開始時間 / 完成時間才會被填。詳細決策見 ADR 0013。新增
- 無新增類別;只是把既有的
Twork_skd_vw_eventitemModel.完成時間欄位真的開始用
變更
AutoPilot/AutoPilotHelper.cs::ExecuteMethod:
- 執行前
bll.Update已完成(pkid, "R", DateTime.Now)(標執行中 + 寫 執行開始時間)- 成功 +
執行後完成 == "Y":bll.Update已完成(pkid, "Y")—— SP 收到後自動寫完成時間 = GETDATE()- 失敗:
bll.Update已完成(pkid, "F")- 快取
bll變數,避免重複new CalendarBll(Context)- SQL
TWORK_SKD_UPDATE_EVENT_STATUSprocedure:
-
已完成分支多寫[完成時間] = CASE WHEN @LP_P3 = 'Y' THEN GETDATE() ELSE [完成時間] END- 加
[是否停用] = CASE WHEN @LP_P3 = 'Y' THEN 'Y' ELSE '' END同步行為-
LP_P3預期值文件從'X' / 'Y' / 'F' / ''改為'R' / 'Y' / 'F' / ''LogicBllTests/Calendar/CalendarBllTests.cs:
- 所有
"X"字面 →"R"-
LP_P1assertion:已通知系列改"1"、已完成系列改"2",與目前CalendarUpdateTypeenum 值對齊(已通知=1, 已完成=2)- 測試方法名
..._status_X_...→..._status_R_...docs/admin/scheduler.md:狀態碼表格與範例 SQL 同步更新
刪除
- 無
Breaking Changes
- 狀態字面
'X'退役:production 端 grep 過後沒有 active caller 寫'X',所以技術上沒有任何 client 程式會壞。但若有外部系統(手寫 SQL update、其他程式直接寫 DB)使用'X'標執行中,需配合改為'R'。
Migration Notes
1. SQL Server 端必跑:升級
TWORK_SKD_UPDATE_EVENT_STATUSprocedure```sql
ALTER PROCEDURE [dbo].[TWORK_SKD_UPDATE_EVENT_STATUS]
@LP_P1 varchar(1), -- 1 = 已通知, 2 = 已完成
@LP_P2 varchar(50), -- pkid
@LP_P3 varchar(1), -- 'R' / 'Y' / 'F' / ''
@LP_P4 varchar(20) -- yyyy/MM/dd HH:mm:ss 或 ''
AS
BEGIN
SET NOCOUNT ON;
DECLARE @StartTime datetime = NULL;
IF @LP_P4 <> ''
SET @StartTime = CONVERT(datetime, @LP_P4, 111);
IF @LP_P1 = '1'
UPDATE [twork_skd_eventitem]
SET [已通知] = @LP_P3,
[執行開始時間] = CASE WHEN @LP_P4 = '' THEN [執行開始時間] ELSE @StartTime END
WHERE [pkid] = @LP_P2;
ELSE IF @LP_P1 = '2'
UPDATE [twork_skd_eventitem]
SET [已完成] = @LP_P3,
[執行開始時間] = CASE WHEN @LP_P4 = '' THEN [執行開始時間] ELSE @StartTime END,
[完成時間] = CASE WHEN @LP_P3 = 'Y' THEN GETDATE() ELSE [完成時間] END,
[是否停用] = CASE WHEN @LP_P3 = 'Y' THEN 'Y' ELSE '' END
WHERE [pkid] = @LP_P2;
END
```
2. 歷史資料相容(可選):若資料庫殘留
已完成 = 'X'的 row,可一次性轉換:```sql
UPDATE twork_skd_eventitem SET 已完成 = 'R' WHERE 已完成 = 'X';
```
不轉換也不會壞,只是畫面會繼續顯示
X。3. SchedulerWorker / TsERP 升級至此 commit 後,新觸發的 EventItem 才有
執行開始時間 / 完成時間值。歷史資料一律 NULL,無法回填。對使用者的影響
- EventItem 列表新狀態:
R(Running)取代X,視覺上不再像「失敗 / 取消」
- 完整時間軸有資料:
執行開始時間在每次排程觸發時自動填、完成時間在事件成功時自動填
- 失敗事件可分辨:scheduler 跑失敗的事件
已完成 = 'F',可從 EventProject 列表一眼看出
- EventResultView 模態(同日 2026-05-03 changelog)的 header 看到的時間欄位開始有實際值
- 無新增類別;只是把既有的
-
05-03 eventitem-result-viewer ▸
2026-05-03 — EventItem 執行結果檢視畫面 + AutoPilot 執行GUID
摘要
EventItem(行事曆事件項目,由AutoPilotHelper.ExecuteMethod觸發)跑完後,使用者現在可以從Eventproject明細列右鍵「查看執行結果」,開啟一個動態欄位的檢視畫面,看到該次執行寫進結果表的列。為了支援上述查看,
AutoPilotHelper在每次執行 task 前會自動產生「執行GUID」、寫回 EventItem 的執行guid欄位,並把 task JSON 內所有"{guid}"token 替換成實際 guid(opt-in:只有 template 寫了"{guid}"的欄位才會被替換)。新增
Common/AutoPilot/SchedulePlaceholders.cs:
- 新常數
ExecutionGuid = "{guid}",與既有的Today = "{d}"/PreviousMonthEnd = "{-d1}"同一套 token 模式- 新方法
ReplaceExecutionGuidTokens(JObject json, string executionGuid):把 JSON 頂層 string 屬性內的{guid}換成實際 guidLogicBll/Calendar/CalendarBll.cs::UpdateExecutionGuid(int pkid, string executionGuid, out string msg):read-modify-write EventItem.執行guid(沿用同檔Update()的AdeUploadBll模式)
ViewModel/L.Communication/EventResultViewModel.cs:modal VM,繼承ERPProgramContentWindowViewModel,建構式收IAppContext + Twork_skd_vw_eventitemSource。Load 時走Log_Sys_Exec+Procedure.DARB_GETDATA4,condition執行guid = '<guid>',從 EventItem 的結果表撈整列回來,bindable 為DataTable ResultTable
TsERP/L.Communication/EventResultView.xaml+.xaml.cs:<TsControl:TsView>根,上方 5 個 metadata label(執行方法 / 結果表 / 預定時間 / 執行開始時間 / 執行GUID),下方<telerik:RadGridView AutoGenerateColumns="True" IsReadOnly="True" ItemsSource="{Binding ResultTable}" />
Eventproject.xamldetail TsRadGridView 加 row context menu「查看執行結果」
變更
AutoPilot/AutoPilotHelper.cs::ExecuteMethod:執行前Guid.NewGuid()→CalendarBll.UpdateExecutionGuid(item.pkid, guid)→SchedulePlaceholders.ReplaceExecutionGuidTokens(json, guid)。GUID 是框架統一管的,所有 task type 都會生成;JSON 替換只動明確寫"{guid}"的欄位
AutoPilot/AutopilotMethod_LogSysExec.cs:DefaultParameter["LP_P1"]預設值改為SchedulePlaceholders.ExecutionGuid(即"{guid}");doc summary 說明 token 用法
ViewModel/L.Communication/EventProjectViewModel.cs:加ICommand ViewResultCommand+ViewResultExecute(),handler 開EventResultViewModelmodal;空執行guid/結果表/ 沒選 row 時跳訊息
TsERP/App.xaml:加<DataTemplate DataType="{x:Type communication:EventResultViewModel}"><schedule:EventResultView /></DataTemplate>
刪除
- 無
Breaking Changes
- 無(沒有覆蓋使用者既有設定的行為;GUID 替換是 opt-in token)
Migration Notes
1. 既有 EventItem 的
執行guid欄位都是空的:本次升級之前跑過的歷史紀錄,沒有 guid 可查。檢視畫面會顯示「該事件無執行紀錄,請先執行排程」。沒辦法回填。2. 想接 GUID 的使用者建立的 LogSysExec 排程:在想接 guid 的 LP_Px 欄位填字面值
{guid}(或留 default 的 LP_P1)。框架在執行那一刻會替換成實際 guid。沒填{guid}的欄位完全不會被改動。3. 新建/維護中的 SQL Procedure:要走「LogSysExec → 寫結果表 → viewer 撈」流程的 procedure,請確認:
- 對應的
結果表有執行guid欄位(typevarchar(36)或nvarchar(36))- Procedure body INSERT 結果列時把對應
LP_Px(接{guid}那個)寫進執行guid欄位4. EventItem.結果表 由使用者建 EventItem 時填:框架不會自動產生這個值,是 EventItem template 的設定。
對使用者的影響
- 新功能:在「事件項目」頁面(Eventproject)的明細列上右鍵就能看到「查看執行結果」。點下去開模態視窗,顯示該次執行的 metadata(執行方法 / 結果表 / 時間 / GUID)+ 結果表撈出來的對應列
- 欄位是動態自動產生的:依
結果表的 schema 即時組欄位;read-only,不能直接編輯
- 沒跑過的事件:右鍵點下去會跳訊息「該事件無執行紀錄,請先執行排程」
- GUID 對使用者是顯式 opt-in:在 template 參數放
{guid}才會收到;不放就跟之前完全一樣
-
05-03 autopilot-task-unify ▸
2026-05-03 — IAutoPilotTask 收攏參數產生與顯示
摘要
把排程「執行」與「參數產生」兩條原本互相不知道對方存在的程式碼路徑收攏到
IAutoPilotTask一個介面下。AutoPilotGenerator廢除,參數格式統一改 JSON,SelectedMethod改成從 registry 反查、setter 補設執行方法。詳情見
docs/decisions/0012-autopilot-task-unify.md。新增
IAutoPilotTask.BuildScheduledParameter(JObject, DateTime)—— 把 template 的參數骨架(含{d}/{-d1}placeholder)展開成 eventitem 的實際參數。
IAutoPilotTask.FormatDisplay(JObject)—— 給eventitem.參數顯示用的人話字串。
Common/AutoPilot/SchedulePlaceholders.cs—— 集中{d}、{-d1}的解析。
- 三個新 task:
Bcurrenm_FxRate、Pivot_Get、Word_MailMerge。AutoPilotRegistry現在註冊全部 7 個 task(原本只註冊 1 個)。
變更
IAutoPilotTask子類的Name屬性統一改用英文 C# 識別字風格:
-
SliyAutoPilot_CloseBook.Name"關帳"→"CloseBook"-
Balance_Balance.Name"CreateBalanceSheet"→"BalanceReport"-
Paymntpq_Query.Name"CreateEmail"→"PaymntpqQuery"-
SliyAutoPilot_CloseBook.ProgramClass修為Common.ProgramClass.SLIY.Name(原為 null)。- 中文顯示走多語系
DisplayName,key 是ProgramClass.AUTOPILOTMETHOD。Twork_skd_vw_eventtemplatedSource.SelectedMethod:
- getter 從
_registry.GetTask(單據別, 執行方法)反查(原本只回傳快取欄位)。- setter 補設
執行方法 = value.Name,原本只設單據別與參數。- setter 改走
原始Jsonsetter(與TranslateJson()同一條路),不再有兩條互相打架。-
單據別/執行方法setter 加上OnPropertyChanged(nameof(SelectedMethod))。Twork_skd_vw_eventtemplatedSource.CreateEventItem改用task.BuildScheduledParameter+task.FormatDisplay。
刪除
Model/AutoPilotGenerator.cs整支移除。
AutoPilot/AutoPilot.cs整支移除;FxRate/GetPivot/GetWordMailMerge三個 method 的邏輯 inline 進對應 task 的Execute。
AutoPilot/AutoPilotHelper.cs內的AutoPilotResult死碼私有 method 與註解掉的 CSVExecuteMethodoverload 一併清掉。
AutoPilotTask.GetParameterFormula移除(原本宣告JObject卻沒 return 的壞掉 stub)。
Breaking Changes
1. DB 中
執行方法欄位的值需要更新。原本存關帳、CreateEmail、CreateBalanceSheet等舊值的 row,registry lookup 會 miss,排程不會跑。2.
參數欄位 CSV 格式變 JSON。原本"Y,2026/05/03"這種要改成{"CloseType":"Y","CloseDate":"2026/05/03"}。Migration Notes
UPDATE twork_skd_vw_eventtemplated SET 執行方法 = 'CloseBook' WHERE 執行方法 = '關帳'; UPDATE twork_skd_vw_eventitem SET 執行方法 = 'CloseBook' WHERE 執行方法 = '關帳'; UPDATE twork_skd_vw_eventtemplated SET 執行方法 = 'BalanceReport' WHERE 執行方法 = 'CreateBalanceSheet'; UPDATE twork_skd_vw_eventitem SET 執行方法 = 'BalanceReport' WHERE 執行方法 = 'CreateBalanceSheet'; UPDATE twork_skd_vw_eventtemplated SET 執行方法 = 'PaymntpqQuery' WHERE 執行方法 = 'CreateEmail'; UPDATE twork_skd_vw_eventitem SET 執行方法 = 'PaymntpqQuery' WHERE 執行方法 = 'CreateEmail';參數欄位 CSV → JSON 建議讓使用者進排程模板編輯介面重新選一次「執行方法」載入新的預設骨架(DefaultParameter)後再填值。多語系
AUTOPILOTMETHOD多語系檔需要補上新Name對應的中文翻譯(CloseBook→關帳、BalanceReport→資產負債表等),讓 ComboBox 顯示維持中文。 -
05-03 addevent-task-picker ▸
2026-05-03 — 排程模板:合併「單據別 + 執行方法」並加上參數提示
摘要
AddEventContent.xaml的「自動化參數」區塊原本要使用者先選「單據別」再選「執行方法」兩個下拉選單,現整併成一個「執行項目」下拉,顯示文字為「程式名稱 - 方法名稱」。同時在「參數」TextBox 下方加上占位符說明,讓使用者直接看到{d}/{-d1}等可用 token,不必去翻SchedulePlaceholders原始碼。新增
Twork_skd_vw_eventtemplatedSource.AutoPilotTaskOptions— 把 registry 內所有IAutoPilotTask與使用者權限可瀏覽的ProgramClass做交集,包成AutoPilotTaskOption(含Display = "{程式名稱} - {方法 DisplayName}")。
Twork_skd_vw_eventtemplatedSource.SelectedTaskOption— 提供給合併後的 ComboBox 雙向綁定;setter 直接轉發到SelectedMethod,由原有 setter 同步寫入單據別/執行方法/原始Json。
- 「參數」TextBox 下方新增黃底提示框,列出占位符對照表,並動態顯示目前選定方法的
Description(例:「本項目:關帳」)。
- 參數 TextBox 加上
AcceptsReturn=True與FontFamily=Consolas,讓 JSON 多行顯示與閱讀更容易。
變更
- 「單據別 / 執行方法」兩個下拉合併為「執行項目」一個下拉。
- 「執行後完成」「是否自動執行」整理成同一列,標籤改為「執行旗標」並改用 CheckBox 內建 Content 顯示文字。
刪除
無(
AutoPilotProgramClassList/AutoPilotMethodList/SelectedMethod/UpdateMethodListByProgramClass仍保留,內部CreateEventItem流程未變動)。Breaking Changes
無。
單據別與執行方法仍以原本格式寫入 DB;只是 UI 改成由單一下拉一次設定。Migration Notes
無需 DB 或設定檔遷移。
- 既有資料的
單據別/執行方法載入後會自動 round-trip 為對應的SelectedTaskOption。
- 若 registry 內某個 task 的
ProgramClass不在使用者的權限表內,該選項不會出現在下拉中(與舊版「單據別必須先在權限表」一致)。
-
05-02 readme-setup ▸
2026-05-02 — 新增 README 與新機器初始設定指引
摘要
repo 根目錄新增
README.md,集中記錄新機器(含 CI)首次設定 Telerik 私有 NuGet 認證、Telerik 授權檔位置、Telerik MCP tools 安裝步驟。同時把.tools/加入.gitignore。新增
README.md:新機器初次設定流程
- 推薦用
NuGetPackageSourceCredentials_telerik環境變數(Username=...;Password=...)配置 Telerik NuGet 憑證,而非寫進NuGet.Config或dotnet nuget update source --store-password-in-clear-text- Telerik 授權檔位置
%APPDATA%\Telerik\telerik-license.txt-
dotnet tool update --tool-path ./.tools Telerik.WPF.MCP/Telerik.Documents.MCP安裝指令- 常用 build / test / publish / mkdocs 指令彙整
變更
.gitignore:新增.tools/,避免把 dotnet local tool 的二進位與dotnet-tools.json帶進版控
對使用者的影響
- 終端使用者無感
- 開發者 / 新進工程師:新機器只要設一次 user-level 環境變數
NuGetPackageSourceCredentials_telerik,就能 restore Telerik 套件、安裝 MCP tools;不需動NuGet.Config,可避免不小心把帳密 commit 進 repo
- CI/CD:同樣以 secret env var 注入
NuGetPackageSourceCredentials_telerik即可,不需另外建立 credential file
Migration Notes
舊有開發機若先前已透過
dotnet nuget update source telerik --username ... --password ... --store-password-in-clear-text把帳密寫進%AppData%\NuGet\NuGet.Config,建議:1. 設定 user-level 環境變數
NuGetPackageSourceCredentials_telerik2. 從
%AppData%\NuGet\NuGet.Config移除<packageSourceCredentials>區塊內的 telerik 條目3. 重開終端確認
dotnet restore仍能通過無此需求者不必處理。
-
05-02 bom-flow-tree-tab ▸
2026-05-02 — Bom_flow 新增「製程明細(樹狀)」tab + 修 RadDiagram 不顯示
摘要
D.Bom\Bom_flow多一個 tab「製程明細(樹狀)」,原 tab 不動;同時修掉「流程圖圖形」tab 內 RadDiagram 因樣式覆寫導致連線/節點不顯示與一連串 binding error 的問題。新增
- 新 tab「製程明細(樹狀)」(
DisplayMeta[製程明細(樹狀)]),位置:原「製程明細表」之後、「多階材料用量清單」之前
- 用
telerik:RadTreeListView+TreeListViewTableDefinition以組件編號 → 品號自連結建階層- 顯示欄位:品號 / 品名 / 生產部門 / 部門簡稱 / 數量 / 單位 / 損耗率 / 標準工時 / 整備工時 / 移轉天數 / 注意事項 / 生效日期 / 失效日期 / 零件編號 / 顯示序號 / 組件編號
DisplayProcessingPoco.Children屬性(in-memory,給 tree 用,不參與 DB mapping)
Bom_flowViewModel.DisplayProcessingTreeRoots屬性 +BuildTree()私有方法,跟SelectedPartNo連動
變更
RadDiagram.ShapeStyle/ConnectionStyle加BasedOn="{StaticResource {x:Type telerik:RadDiagramShape/Connection}}",保留主題 ControlTemplate
- 修掉 4 條
EndBezierPoint / StartPoint / StartBezierPoint / EndPoint對LineSegment.Point/PathFigure.StartPoint的 binding error- 修掉「流程圖圖形」tab 內 RadDiagram 沒畫出節點/連線的問題
2026-05-03 後續
- 樹狀 tab 把查詢組件本身當成第一層唯一根節點,原本的第一層子項全部掛在它底下,便於整體展開檢視
- 為了能「合成」一個根節點,
DisplayProcessingPoco多一個只吃IAppContext的建構子(原(TMP製程表, IAppContext)不變)-
BuildTree多吃一個IAppContext參數刪除
- 無(原「製程明細表」tab 與其雙擊展開邏輯完全保留)
Breaking Changes
- 無
Migration Notes
- 終端使用者:自動多一個 tab,無操作變更
- 開發者:新 DisplayMeta key
製程明細(樹狀)兩份 JSON 都已更新
-
Common\Lang\Xaml\Bom_flow.json-
TsERP\Lang\Xaml1\Xaml.json- 重 build 前要先關掉執行中的
TsERP.exe,否則bin/Debug/net8.0-windows/*.dll會被鎖住複製失敗(與本次改動無關,是 dev 環境常見現象)
- 新 tab「製程明細(樹狀)」(
📅 2026 年 4 月 (10 篇)
-
04-29 batchedit-itemsbindingmanager ▸
2026-04-29 — BatchEditBll 改用 ItemsBindingManager + EF ChangeTracker
摘要
BatchEditBll(批次編輯 BLL 抽象基底;目前唯一實作為SecretBll,用於權限批次設定)從原本的「adeDataBackup自製 diff +AdeUploadBll.UpdateData」改為「ItemsBindingManager集中管理 + EF ChangeTracker 偵測變動 +UploadToSql」。詳細決策見 ADR 0010。新增
Model/Source/A.SystemData/PrgsctBatch.cs:從LogicBll/Other/Secret/PrgsctBatch.cs搬過來(namespace 改Model),兩個 in-memory only 屬性使用者代號/使用者姓名加[NotMapped]
Model/LocalDbContext.cs新增DbSet<PrgsctBatch> PrgsctBatch:OnModelCreating用HasBaseType((Type)null).ToTable("PrgsctBatch")跟父類別 entity 解綁 + 對到獨立 SQLite 表PrgsctBatch
DataManager<T>.SeedFromRemote(IEnumerable<T> data):取代/重寫先前的DirectSaveToSqliteAndLoad;主動清IsDirty=false/IsNew=false/增刪修=""後 upsert 到 SQLite 並Load()接管 EF tracker
變更
LogicBll/Ade/Transfer/BatchEditBll.cs:
- 抽象屬性
IList[] EditSource→ItemsBindingManager-
Save()流程:UpdateBefore→SetUploadData(保留為 hook,預設無動作)→ItemsBindingManager.SaveAll()→ItemsBindingManager.UploadToSql(Status, out msg)- 移除壞掉的
adeDataBackup.DataBackup/adeDataBackup.GetUpdateData殘留LogicBll/Other/SecretBll.cs:
- 改實作
protected sealed override ItemsBindingManager ItemsBindingManager { get; }- 新增
private readonly DataManager<PrgsctBatch> prgsctData-
PrgsctBatchproperty 從List<PrgsctBatch>(auto-property)改為IList<PrgsctBatch>直接回傳prgsctData.ObservableCollection(live view)-
SqlQuery改用prgsctData.SeedFromRemote(list),不再設EditSource- 移除
using LogicBll.Other.Secret;(不再存在)LogicBll/ItemsBindingManager.cs:
-
DirectSaveToSqliteAndLoad改名SeedFromRemote、加清 dirty/IsNew/增刪修 邏輯、移除冗餘 try/finally-
DataManager.Save()加if (_db == null) return;null guard,避免對未Load/SeedFromRemote的 manager 呼叫SaveAll時 NRELogicBll/LocalDbService.cs+Common/Context/ILocalDbService.cs:UpsertBatchMarkDirty<T>→UpsertBatch<T>(原名誤導;實際上不主動標 dirty,dirty 是由 caller 端先設好)
ViewModel/A.SystemData/PermissionSettingViewModel.cs:
- 移除
using LogicBll.Other.Secret;-
PrgsctBatch型別List<PrgsctBatch>→IEnumerable<PrgsctBatch>(XAMLItemsSourcebinding 不受影響)刪除
LogicBll/Other/Secret/整個資料夾(內只有PrgsctBatch.cs,已搬到 Model)
BatchEditBll.EditSource(抽象屬性)
Breaking Changes
PrgsctBatch型別改隸屬 Model 專案 / namespace 從LogicBll.Other.Secret改為Model:所有 caller 的using需要改。本次掃過的:SecretBll.cs、PermissionSettingViewModel.cs。其他若有依賴需自行調整
BatchEditBll子類別必須提供ItemsBindingManager而非EditSource:目前唯一 subclassSecretBll已調整。任何下游若在自寫 BatchEdit subclass 需重構
DataManager.SeedFromRemote取代DirectSaveToSqliteAndLoad:方法名變更,外部 caller 需更名
UpsertBatchMarkDirty→UpsertBatch:ILocalDbServiceinterface 上的方法名變更
SecretBll.PrgsctBatch不再可寫:原本是{ get; set; }的List<PrgsctBatch>,現在是只讀的IList<PrgsctBatch>(指向DataManager.ObservableCollection)。caller 不能再SecretBll.PrgsctBatch = ...或對它呼叫Add/Remove
Migration Notes
1. 第一次跑這版的 client 端 SQLite:本機資料庫多了一張
PrgsctBatch表- 如果使用
EnsureCreated/ migration:自動處理- 如果手動管理 schema:需建立
PrgsctBatch表,schema 同Prgsct12. caller 的
using升級:所有using LogicBll.Other.Secret;改為using Model;3.
SecretBll.PrgsctBatch用法檢查:以前可能透過此 property 對 listAdd/ 重新賦值,現在這條路被擋掉;若有需求請改透過DataManagerAPI(AddItem/Clear等)4. 若有自寫
BatchEditBllsubclass:- 改實作
ItemsBindingManager抽象屬性(建構子建好後Register<T>())-
SqlQuery把EditSource賦值改為對應DataManager.SeedFromRemote(list)-
WhenSqlQueryTrue等 hook 維持原本 mutation 邏輯即可(mutation 落在dm.ObservableCollection的 instance 上,EF 會自動偵測)對使用者的影響
- 終端使用者無 UI 操作改變
- 權限批次設定(PermissionSetting / SECRET)的「儲存」行為從「diff 我自己算」變「EF 自動判定」;只有真的有變更的 row 才會送上去。對使用者體感應該是一致或更精準
- 第一次跑新版時若 SQLite 沒升級到含
PrgsctBatch表,畫面會在查詢時拋例外;DBA / 升級腳本要先處理本機 schema
-
04-28 scheduler-worker ▸
2026-04-28 — TimerBll 拆出獨立排程 exe(TsERP.SchedulerWorker)
!!! note "後續更新"
本 changelog 描述的 SP
TWORK_SKD_NOTIFYEVENT在 2026-05-04 已被拆成TWORK_SKD_GET_PENDING_NOTIFY與TWORK_SKD_GET_PENDING_AUTOEXEC兩支單一職責 SP,並修正「停用應為是否停用」與「殭屍判定狀態碼還用'X'沒對齊 ADR 0013」兩個積累 bug。詳見 ADR 0015 與 2026-05-04 changelog。摘要
行事曆通知與 AutoPilot 自動化批次的 5 分鐘排程從 WPF App 內的
DispatcherTimer(LogicBll/Timer/TimerBll.cs)拆出來,做成獨立 console exeTsERP.SchedulerWorker,由 Windows 工作排程器每 5 分鐘觸發。從此通知與 AutoPilot 不再依賴「有人開著 ERP」才會跑。詳細決策見 ADR 0009。新增
TsERP.SchedulerWorker/整個專案(net8.0-windows、UseWPF=true、OutputType=Exe)
-
TsERP.SchedulerWorker.csproj-
Program.cs:top-level entry,Global\TsERP_Schedulernamed Mutex 防重疊,exit code0=成功 /1=失敗 /2=被 mutex 擋-
SchedulerJob.cs:取代TimerBll,提供Task<int> RunOnceAsync()-
SchedulerSettings.cs:config POCO-
SchedulerUser.cs:IUserheadless 實作(UserId=SCHED)-
appsettings.json:Scheduler區段(Databases/AlertRecipients/ZombieTimeoutMinutes/BatchSize/DefaultSrvdbid)- 新 SP
TWORK_SKD_UPDATE_EVENT_STATUS:原子化更新事件狀態 + 時間戳
- 行事曆事件「執行中」狀態
'X':已通知/已完成欄位多一個值,配合新執行開始時間欄位做殭屍紀錄回收
變更
LogicBll/Calendar/CalendarBll.cs:新增 3-arg 多載Update已通知(pkid, status, DateTime?)與Update已完成(pkid, status, DateTime?),支援'X'狀態與時間戳。原 2-arg 簽章保留
ViewModel/PageControl/MainWindow/MainWindowBtnTimerViewModel.cs:拿掉TimerBll欄位(VM 殼保留,避免影響 XAML binding)
TsERP.sln:加入TsERP.SchedulerWorker專案
- SP
TWORK_SKD_NOTIFYEVENT行為改變:
- 加
TOP 20、ORDER BY ASC:每次只拿 20 筆- QueryType=2 移除原本 1 小時時間窗
- filter 改為
已完成 NOT IN ('Y','F')+ 殭屍回收('X'超過ZombieTimeoutMinutes視為前一輪 crash 自動拉回)- 失敗事件處理改變:標
'F'後不再自動重跑,需要管理員手動把狀態改回'N'或空
刪除
- 無(
LogicBll/Timer/TimerBll.cs保留為 fallback,未來確認穩定後再評估移除)
Breaking Changes
- DB schema 變更:
twork_skd_eventitem(base table)需新增執行開始時間 datetime NULL欄位
- SP
TWORK_SKD_NOTIFYEVENT行為改變:見上方「變更」段;如有外部程式直接呼叫此 SP 並依賴原 1 小時時間窗或全部撈出的行為,需重新驗證
- 新增 SP
TWORK_SKD_UPDATE_EVENT_STATUS:CalendarBll 新多載呼叫;DB 端必須先建立此 SP 才能升級 ERP / SchedulerWorker
- 失敗事件不再自動重跑:標
'F'後跳過,需要管理員手動處理;先前依賴「自動重試直到成功」的事件流程需要調整 SOP
Migration Notes
1. DBA 端:對每個 darb DB 執行
-
ALTER TABLE twork_skd_eventitem ADD 執行開始時間 datetime NULL-
ALTER PROCEDURE TWORK_SKD_NOTIFYEVENT(加TOP 20、ORDER BY ASC、移除 1 小時時間窗、改 filter 為已完成 NOT IN ('Y','F')+ 殭屍回收)-
CREATE PROCEDURE TWORK_SKD_UPDATE_EVENT_STATUS2. Build & publish
TsERP.SchedulerWorker到 server(建議放D:\TsERP\Scheduler\,self-contained 發布)3. 建專屬服務帳號(例如
TsERP\schedsvc),加入本機 Administrators 群組,密碼設「永不過期」4. 建立 Windows 工作排程:
- 觸發:每 5 分鐘
- 動作:執行
TsERP.SchedulerWorker.exe- 設定:「不要啟動新執行個體」(與 named mutex 雙保險)
- 帳號:上一步建立的服務帳號,勾「不論使用者是否登入皆執行」
5. (可選)監控建議:
- Mailgun dashboard 看寄信統計變化
- SQL Server agent log 看 SP 觸發次數
- 工作排程器歷程記錄看 exit code(
0=成功 /1=失敗 /2=被 mutex 擋)- 定期巡檢
已完成 = 'F'的事件,避免長期堆積對使用者的影響
- 終端使用者無 UI 操作改變
- 行事曆事件通知與 AutoPilot 觸發改由 server 端排程,不再受「有人開著 ERP」影響;下班與週末時段通知也會照常發送
- 若事件第一次失敗(
'F'),不會再自動重試,需聯繫系統管理員處理
-
04-24 mold ▸
2026-04-24 — D.Bom 新增「模具資料表維護」模組
摘要
D.Bom 工程資料模組新增「模具資料表維護」頁面,提供模具主檔(
mold)、品號明細(moldmno)、管制紀錄(moldctrl)三張表的查詢/新增/編輯/刪除,加上「償卻重算」與「Excel 匯出」兩個專屬動作。償卻金額計算統一走 SPDARB_QRY_MOLD,避免畫面、報表、匯出三處邏輯漂移。詳細決策見 ADR 0008。新增
- D.Bom → 模具資料表維護:完整 CRUD + 償卻重算 + Excel 匯出
- 主檔含模具編號、圖號、開模廠商、模具費用、基準/償卻台數、起始分攤日等 67 欄
- 品號明細維護該模具對應的客戶品號與內部品號
- 管制紀錄維護模具維修/送修/報廢等事件時序
-
重算償卻:統一呼叫DARB_QRY_MOLD更新模具分攤費-
Excel 匯出:逐筆呼叫DARB_QRY_MOLD匯出全部模具(非僅當前查詢結果)- 手冊頁:
docs/D-Bom/mold.md
變更
TsERP/Lang/TableMap.json:修正"moldctrl"原本錯誤對應到自己的問題,改為對應"twork_bom_vw_moldctrl";新增"mold"→"twork_bom_vw_mold"、"moldmno"→"twork_bom_vw_moldmno"映射
TsERP/Lang/ClassAliasMap.json:新增Twork_bom_vw_moldctrl{Model,Source}完整別名;移除舊的Moldctrl{Model,Source}短名別名(原短名會跟未來可能加入的moldctrl實體表衝突)
刪除
ClassAliasMap.json中舊的MoldctrlModel/MoldctrlSource短名別名
Breaking Changes
- 外部整合若依賴
moldctrl短名別名:透過ClassAliasMap反射取型別的程式碼(例如自訂報表、整合腳本),若用MoldctrlModel/MoldctrlSource會取不到,需改成完整名Twork_bom_vw_moldctrlModel/Twork_bom_vw_moldctrlSource
Migration Notes
- 升級後如使用外部整合依賴
moldctrl表名別名,請改用完整twork_bom_vw_moldctrl
- DB 端需確認
DARB_QRY_MOLD、DARB_GETDATA4SP 皆存在於目標環境(多數既有環境已部署)
- 首次開啟頁面若顯示權限不足,請檢查使用者是否具備
D-Bom-Mold相關動作權限
- 使用 Excel 匯出前建議先確認模具筆數;超過 5000 筆時匯出時間會隨筆數線性增加
-
04-24 bom-flow-diagram-tab ▸
2026-04-24 — Bom_flow 新增「流程圖(圖形)」tab
摘要
D.Bom\Bom_flow多一個 tab「流程圖圖形」,用 Telerik RadDiagram 把 BOM 樹渲染成節點 + 連線圖,提供放大縮小、垂直/水平切換、自動縮放等互動。新增
- 第 4 個 tab「流程圖圖形」(
DisplayMeta[流程圖圖形]),位於 Bom_flow 右側 TabControl 的最末
- Toolbar 5 顆按鈕:放大、縮小、自動縮放、垂直排列、水平排列、重新排版
- 節點形狀自動切換:
- 根節點(查詢組件):深色圓角矩形
- 物料節點:白底矩形
- 製程節點:淺黃底橢圓
- 每個節點顯示 4 行:品號/部門工程 / 品名 / 數量單位或工時 / 層數+上階+序號
變更
- 無
刪除
- 無(原 90 欄「流程圖」tab 完全保留)
Breaking Changes
- 無
Migration Notes
- 終端使用者無操作改變;開新 tab 自動出現
- 開發者:若要新增 DisplayMeta key,兩份 JSON 都要更新:
-
Common\Lang\Xaml\Bom_flow.json(Debug fallback 來源)-
TsERP\Lang\Xaml1\Xaml.json(Release 來源) - 第 4 個 tab「流程圖圖形」(
-
04-22 velopack-updating-window ▸
2026-04-22 — Velopack 自動更新加上「正在更新」提示視窗
摘要
Velopack 自動更新流程原本完全無聲:啟動後背景檢查、背景下載、下載完直接
ApplyUpdatesAndRestart關閉重開,使用者體感像是登入畫面正在操作時突然被踢掉。現在在發現更新後顯示一個小型 Topmost 視窗,告知使用者「正在下載更新」與進度百分比,下載完成後顯示「即將重新啟動」再執行ApplyUpdatesAndRestart。新增
TsERP/UpdatingWindow.xaml/.xaml.cs:380×130 無邊框置中視窗
-
Topmost="True"、ShowInTaskbar="False"、ResizeMode="NoResize"、無 caption- 一行狀態文字 + 不定/定量進度條
- 公開方法:
SetStatus(string)/SetProgress(int)(呼叫SetProgress時進度條切為定量模式)變更
TsERP/App.xaml.csCheckForUpdatesAsync:偵測到更新時顯示UpdatingWindow
- 發現更新 → 狀態文字:「發現新版本,正在下載更新...」
- 下載進度回呼 → 「正在下載更新(N%)...」+ 進度條填色
- 下載完成 → 「更新下載完成,即將重新啟動...」
-
ApplyUpdatesAndRestart(update)關閉 App,視窗隨程序結束消失- 例外路徑會 Dispatcher 關閉視窗,避免 UI 殘留
- 改用
DownloadUpdatesAsync(update, progress)重載(Velopack 0.0.1298 支援)刪除
- 無
Breaking Changes
- 無(行為變化屬於 UX 提示,不影響更新結果或版本流程)
Migration Notes
- 使用者端無需動作,下次自動更新即生效
- 已知限制:
ApplyUpdatesAndRestart觸發的 VelopackUpdate.exe在切換過程仍可能短暫閃現其自身 UI,本次調整不處理該閃窗。如需完全無縫,需改走WaitExitThenApplyUpdates並搭配外部重啟腳本,成本較高,暫不納入
- 若 debugger 附加中(
Debugger.IsAttached),維持原本略過更新流程的行為,開發環境不會看到此視窗
-
04-22 aiquery-table-whitelist ▸
2026-04-22 — AIQuery 加上表名白名單驗證
摘要
AIQuery 的
TWORK_AI_QUERYSP 在執行前多做一層「FROM/JOIN 後的表名必須登記在_ai_schema」的驗證,同時強化 Claude system prompt,禁止使用sys.*、INFORMATION_SCHEMA.*、以底線開頭的系統表與 CTE。目的在防止 AI 幻覺或 prompt injection 寫出白名單外的查詢。詳細決策見 ADR 0007。新增
SqlBI/TWORK_AI_QUERY.sql:新增步驟 3.5「白名單檢查」
- 掃描 SQL 中
FROM與JOIN後的表名 token- 去掉
[]與schema.前綴後,逐一與_ai_schema.sql_name比對- 任一不符即
RAISERROR並寫入_ai_query_log,錯誤訊息:「查詢包含不在白名單 (_ai_schema) 的資料表,已被拒絕」變更
LogicBll/AI/AIQueryBll.csBuildSystemPrompt:system prompt 新增三條規則
- 嚴禁查詢
sys.*、INFORMATION_SCHEMA.*、任何以底線開頭的系統表- 超出白名單的查詢請求應拒絕並說明,不得自行臆測表名
- 禁止使用 CTE (
WITH ... AS),需用子查詢或 JOIN 改寫刪除
- 無
Breaking Changes
- 使用 CTE 的舊查詢會被擋下:若既有流程或 AI 回答慣例會使用
WITH ... AS,現在會被 SP 回「不在白名單」錯誤。已透過 prompt 指引 Claude 改用子查詢/JOIN
- 字串常數含特定模式可能誤殺:
WHERE 備註 LIKE '%FROM XX%'之類、字串內剛好包含FROM的查詢,token 抽取會誤判。若遇到可調整問法
Migration Notes
- DB 端要執行
SqlBI/TWORK_AI_QUERY.sql(CREATE OR ALTER PROCEDURE)套用新版 SP
_ai_schema表的維運更關鍵:要讓 AI 能查新表,必須先在_ai_schema登記,否則即使有 SELECT 權限也會被 SP 擋下
- 使用者若反映「AI 以前能回答、現在說被拒絕」,先查
_ai_query_log.執行結果:
- 「查詢包含不在白名單」→ 表名未登記 → 補
_ai_schema- 「偵測到不允許的 SQL 語法」→ 關鍵字黑名單擋(維持既有行為)
-
04-20 velopack-upload-incremental ▸
2026-04-20 — Velopack 上傳改為逐檔增量
摘要
release-velopack.ps1的上傳邏輯從az storage blob upload-batch --overwrite(每次全覆蓋)改為先查遠端清單、逐檔決定 NEW / OVER / SKIP。每次發布頻寬從 ~970MB 降至 ~360MB(約 60% 節省)。同時修掉 PS 5.1 +$ErrorActionPreference='Stop'對 az CLI stderr 警告過敏的問題。詳細決策見 ADR 0005。新增
- 無
變更
TsERP/release-velopack.ps1上傳區塊:
- 上傳前先
az storage blob list取得遠端 blob + size map- 逐檔決策:遠端沒有 → upload;遠端有 + 是 nupkg → skip;遠端有 + size 相同 → skip;其他 → overwrite
- az 呼叫包在
$ErrorActionPreference='Continue'的 try/finally,避免 az CLI 寫 stderr 的 info/warning 被 PS 5.1 升級為NativeCommandError終止 script- 個別
az storage blob upload加--only-show-errors抑制雜訊- Console 輸出格式:每檔一行
NEW/OVER/SKIP <name> (<size>),最末印統計NEW x / OVER y / SKIP z刪除
upload-batch --overwrite單次呼叫(被逐檔 upload 取代)
- 中途嘗試過的
az storage blob sync版本(依賴 AzCopy、使用者機器 DNS 被擋 → 失敗退回)
Breaking Changes
- 無(遠端 container 內容與 upload-batch --overwrite 結果等價)
Migration Notes
- 使用者端無需動作
- 發布端改動已在
release-velopack.ps1,下次執行自動生效
- 若未來 Velopack 在
Releases/新增其他「每版都改內容、檔名固定」的檔案類型,現有 size 比對邏輯自動處理;若新增「每版檔名改、內容固定」的類型則視同 new file 上傳、行為正確
- 若未來容器 blob 數量成長到 10000+,
az storage blob list需評估分頁(目前單次呼叫 return 完整清單)
-
04-20 velopack-sign-exe-only ▸
2026-04-20 — Velopack 簽章只簽 EXE
摘要
release-velopack.ps1的vpk pack加上--signExclude '.*\.dll',發布時只簽主程式 EXE,不再簽所有內部 DLL。發布簽章時間從 ~7 分鐘縮短為數秒,USB token PIN 彈窗從 60+ 次降至 2–3 次。詳細決策見 ADR 0004。新增
- 無
變更
TsERP/release-velopack.ps1:vpk pack參數新增--signExclude '.*\.dll'
- 僅在
-SkipSign未指定時生效- 實際被簽的檔案:
TsERP.exe+ Velopack 產出的Setup.exe/Update.exe- 本專案各 DLL(
Common.dll/ViewModel.dll/LogicBll.dll/Model.dll/TsControl.dll/AutoPilot.dll/ 各領域模組)不再簽章刪除
- 無
Breaking Changes
- 無(主 EXE 仍簽章,SmartScreen 發行者顯示不變)
Migration Notes
- 使用者端無需動作,下次 Velopack 自動更新即套用
- 若未來遇到 AppLocker / WDAC 嚴格環境擋未簽 DLL,走 publisher allowlist 或 hash allowlist 處理;尚無此類客訴
- 若未來要改為全面簽章但保留速度,評估遷移至 Azure Trusted Signing(見 ADR 0004 Alternatives Considered)
-
04-20 velopack-release-pipeline ▸
2026-04-20 — Velopack 發布管線
摘要
新增 Velopack 一鍵發布腳本,整合版號遞增、publish、簽章、Azure 上傳、git commit。詳細決策見 ADR 0003。
新增
TsERP/release-velopack.ps1:Velopack 發布主腳本
- 自動把 csproj 的
<VelopackVersion>patch 段 +1-
dotnet publish->vpk download->vpk pack(USB 硬體簽章)->az storage blob upload-batch->git commit- 四個逃生開關:
-SkipDownload(首次發布)、-SkipSign(USB 未插)、-SkipUpload(本地驗證)、-SkipCommitTsERP.csproj新增<VelopackVersion>1.0.1</VelopackVersion>標籤
變更
- 無(既有 ClickOnce 腳本
autodeploy.ps1/darbtestDeploy.ps1完全不動)
刪除
MainWindow.xaml.cs的CheckForUpdate()方法與其在Window_Loaded的呼叫
- 原本會彈「發現新版本 / 是否立即重啟套用」MessageBox
- 與
App.xaml.cs:63Startup 事件裡的靜默自動更新並行執行,兩個UpdateManager同時寫入%LocalAppData%\YanYue.ERP\packages\會產生 file lock 錯誤- 保留
App.xaml.cs的靜默版(啟動時檢查 → 下載 →ApplyUpdatesAndRestart),使用者完全不介入- MainWindow.xaml.cs 不再 using
Velopack/Velopack.Sources,MessageBoxalias 也移除(除了 CheckForUpdate 沒別處用)
Breaking Changes
- 無(Velopack 更新通道
darb-vpk目前僅有App.xaml.cs讀取,使用者端安裝的 ClickOnce 版不受影響)
Migration Notes
首次發布步驟
darb-vpkcontainer 若尚無RELEASES檔,第一次跑要加-SkipDownload:cd C:\ERPV2\TsERP .\release-velopack.ps1 -SkipDownload之後每次發布:
.\release-velopack.ps1前置需求
1. 已安裝
dotnetSDK、vpk全域工具(dotnet tool install -g vpk)、azCLI、git2. USB 硬體簽章 token 已插上(憑證指紋
66AE9BC65D5516A65B8F4860F4F815F56F5CFBFB)3. PowerShell 執行原則若限制未簽章腳本,需用
Set-AuthenticodeSignature幫release-velopack.ps1簽一次(同autodeploy.ps1的做法)手動介入情境
- pack 或 upload 失敗、csproj 版號已寫回但還沒 commit:直接重跑,失敗前的新版號會繼續被用
- git commit 之後才發現 upload 有問題:
git reset --soft HEAD~1退回 commit,處理完再重推
版本號升級
- 預設 patch +1:
1.0.1→1.0.2→1.0.3…
- Major / Minor bump 需要時直接編 csproj 的
<VelopackVersion>(腳本下次執行會從該值繼續 +1)
-
04-17 operator-alignment ▸
2026-04-17 — 查詢條件運算子對齊 Telerik
摘要
全系統查詢畫面的「運算子」下拉重新整理,文字、行為與排序全部對齊 Telerik RadGridView 內建 filter。詳細設計決策見 ADR 0001,使用者操作說明見 查詢條件運算子。
新增
- 真正的「等於」(代碼 A):產生
col = 'x'
- 真正的「不等於」(代碼 B):產生
col <> 'x'
- 結尾為 / EndsWith(代碼 H):產生
col LIKE '%x'
- 被包含 / IsContainedIn(代碼 K):產生
col IN (x,y,z),值用逗號分隔
- 不被包含 / IsNotContainedIn(代碼 L):產生
col NOT IN (...)
- 不等於Null / IsNotNull(代碼 N):產生
col IS NOT NULL
- 不等於空白 / IsNotEmpty(代碼 P)
變更
- 下拉排序:改為 Telerik 自然順序(等於 → 不等於 → 大於 → … → StartsWith → EndsWith → Contains → …)
- 預設運算子:維持重構前的行為,使用 不等於 / IsNotEqualTo(新代碼 B,對應舊 index [2] 的 Not Equal(<>))
- 中文文字修正:
- 舊「等於(=)」實際是 StartsWith → 改稱「開始於」
- 舊「不等於(<>)」實際是 DoesNotStartWith → 整合為「不包含」
- 其他 label 全面對齊 Telerik 繁中 UI 用字
刪除
- 開頭不為 / DoesNotStartWith(舊 C):無 Telerik 對等,遷移到「不包含」
- 多關鍵字包含 / Multi-Keyword Contains(舊 J):無 Telerik 對等,遷移到「包含」。若需多關鍵字查詢,請改用多個「包含」條件以 OR 串接
Breaking Changes
Twork_sys_vw_zcond_define.SymbolNo所有代碼的意義都變了。部署前必須跑 migration SQL(見 ADR 0001 末尾),否則所有客戶既有自訂查詢條件會靜默變意義
- FilterWindow 下拉原本硬限制只顯示代碼
<= "H",現改為白名單顯示 A–Q(排除自家延伸 R/S)
BrowseInitialzation.GetConditionSourceByNoSqlDefaultValue取預設值不再用SymbolNoList[2],改為按代碼"B"(不等於)明確查找
Migration
1. 備份
Twork_sys_vw_zcond_define2. 於測試 DB 執行 ADR 0001 提供的
UPDATE ... CASE WHEN腳本3. 驗證筆數與抽樣結果
4. 正式機執行
5. 若有客戶自訂條件使用到舊 C 或舊 J,執行完 migration 後會被遷移到語意接近但不完全相同的 operator,建議通知使用者重新確認
影響檔案
- 核心 4 個:
LCLZcondOperator.cs、Xaml.json、BrowseConditionHelper.cs、SQLiteConditionHelper.cs
- 連帶 7 個:
BindingListCollectionViewFilterHelper.cs、BrowseInitialzation.cs、FilterWindowViewModel.cs、FilterMethod.cs、BrowseKeyWord.cs、ConditionPoco.cs、加上 9 個業務 ViewModel 的硬編碼遷移
後續修正(同日 hotfix)
- 預設運算子回正:重構初版誤改成
"G"(StartsWith),還原為"B"(不等於)以維持歷史行為
Common/Lang/Xaml/Shared.json補 O–S:DEBUG 模式優先讀Lang/Xaml/分檔,初版漏改此檔導致下拉 O 以後的新運算子顯示不出說明文字。Release 模式讀Lang/Xaml1/Xaml.json不受影響
- 真正的「等於」(代碼 A):產生