sapbuddy-dsh 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,320 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>{{DOC_TITLE}}</title>
7
+ <style>
8
+ /* Claude Design System tokens (from open-claude-ui cds-theme) — archive sheet, no logo */
9
+ :root {
10
+ --brand: #c6613f;
11
+ --cds-clay: #d97757;
12
+ --cds-clay-light: #fbf3ef;
13
+ --cds-gray-0: #fff;
14
+ --cds-gray-10: #fcfcfb;
15
+ --cds-gray-20: #f9f9f7;
16
+ --cds-gray-40: #f3f3f0;
17
+ --cds-gray-100: #e1e0d9;
18
+ --cds-gray-200: #c3c2b7;
19
+ --cds-gray-500: #6d6b67;
20
+ --cds-gray-600: #52514e;
21
+ --cds-gray-850: #151515;
22
+ --cds-text-primary: #151515;
23
+ --cds-text-secondary: #525252;
24
+ --cds-text-muted: #8a8a8a;
25
+ --cds-border: hsla(0, 0%, 8%, 0.10);
26
+ --cds-border-strong: hsla(0, 0%, 8%, 0.20);
27
+ --cds-shadow-sm: 0 1px 2px rgba(0,0,0,.05), 0 2px 8px rgba(0,0,0,.08);
28
+ --cds-shadow-md: 0 2px 4px rgba(0,0,0,.05), 0 6px 16px rgba(0,0,0,.08);
29
+ --radius-md: 6px;
30
+ --radius-lg: 8px;
31
+ --radius-xl: 12px;
32
+ --radius-2xl: 16px;
33
+ --font: "Anthropic Sans", "Segoe UI", "PingFang SC", "Microsoft YaHei", "Noto Sans CJK SC", sans-serif;
34
+ --mono: "Anthropic Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
35
+ }
36
+ * { box-sizing: border-box; }
37
+ body {
38
+ margin: 0;
39
+ min-height: 100vh;
40
+ color: var(--cds-text-primary);
41
+ background: var(--cds-gray-20);
42
+ font: 15px/1.65 var(--font);
43
+ -webkit-font-smoothing: antialiased;
44
+ }
45
+ .sheet {
46
+ max-width: 880px;
47
+ margin: 28px auto 48px;
48
+ padding: 36px 40px 40px;
49
+ background: var(--cds-gray-0);
50
+ border: 1px solid var(--cds-border);
51
+ border-radius: var(--radius-2xl);
52
+ box-shadow: var(--cds-shadow-md);
53
+ }
54
+ .accent-bar {
55
+ height: 3px;
56
+ width: 48px;
57
+ border-radius: 999px;
58
+ background: var(--cds-clay);
59
+ margin-bottom: 18px;
60
+ }
61
+ h1 {
62
+ margin: 0 0 10px;
63
+ font-size: 1.55rem;
64
+ font-weight: 600;
65
+ letter-spacing: -0.02em;
66
+ line-height: 1.3;
67
+ }
68
+ h2 {
69
+ margin: 32px 0 12px;
70
+ padding-bottom: 8px;
71
+ font-size: 1.1rem;
72
+ font-weight: 600;
73
+ letter-spacing: -0.01em;
74
+ border-bottom: 1px solid var(--cds-border);
75
+ }
76
+ h3 {
77
+ margin: 20px 0 8px;
78
+ font-size: 0.98rem;
79
+ font-weight: 600;
80
+ color: var(--cds-text-primary);
81
+ }
82
+ h4 {
83
+ margin: 14px 0 6px;
84
+ font-size: 0.9rem;
85
+ font-weight: 600;
86
+ color: var(--cds-text-secondary);
87
+ }
88
+ p, li { margin: 6px 0; color: var(--cds-text-primary); }
89
+ .lede { color: var(--cds-text-secondary); font-size: 0.92rem; }
90
+ .status {
91
+ display: inline-flex;
92
+ align-items: center;
93
+ gap: 6px;
94
+ margin: 4px 0 18px;
95
+ padding: 4px 10px;
96
+ border-radius: 999px;
97
+ background: var(--cds-clay-light);
98
+ color: var(--brand);
99
+ border: 1px solid color-mix(in srgb, var(--cds-clay) 28%, transparent);
100
+ font-size: 0.78rem;
101
+ font-weight: 500;
102
+ }
103
+ .status::before {
104
+ content: "";
105
+ width: 6px; height: 6px;
106
+ border-radius: 50%;
107
+ background: var(--cds-clay);
108
+ }
109
+ .meta {
110
+ display: grid;
111
+ grid-template-columns: 7.5rem 1fr;
112
+ gap: 8px 14px;
113
+ margin: 0 0 8px;
114
+ padding: 14px 16px;
115
+ background: var(--cds-gray-10);
116
+ border: 1px solid var(--cds-border);
117
+ border-radius: var(--radius-xl);
118
+ font-size: 0.88rem;
119
+ }
120
+ .meta dt { color: var(--cds-text-muted); font-weight: 500; }
121
+ .meta dd { margin: 0; color: var(--cds-text-secondary); }
122
+ table {
123
+ width: 100%;
124
+ border-collapse: separate;
125
+ border-spacing: 0;
126
+ margin: 12px 0 18px;
127
+ font-size: 0.86rem;
128
+ border: 1px solid var(--cds-border);
129
+ border-radius: var(--radius-xl);
130
+ overflow: hidden;
131
+ background: var(--cds-gray-0);
132
+ }
133
+ th, td {
134
+ padding: 9px 11px;
135
+ text-align: left;
136
+ vertical-align: top;
137
+ border-bottom: 1px solid var(--cds-border);
138
+ }
139
+ tr:last-child td { border-bottom: none; }
140
+ th {
141
+ background: var(--cds-gray-40);
142
+ color: var(--cds-text-secondary);
143
+ font-weight: 600;
144
+ }
145
+ tbody tr:nth-child(even) td { background: var(--cds-gray-10); }
146
+ .card {
147
+ margin: 12px 0;
148
+ padding: 12px 14px;
149
+ border: 1px solid var(--cds-border);
150
+ border-radius: var(--radius-xl);
151
+ background: var(--cds-gray-10);
152
+ box-shadow: var(--cds-shadow-sm);
153
+ }
154
+ .card > :first-child { margin-top: 0; }
155
+ pre, code { font-family: var(--mono); font-size: 0.8rem; }
156
+ code {
157
+ padding: 1px 5px;
158
+ border-radius: var(--radius-md);
159
+ background: var(--cds-gray-40);
160
+ color: var(--cds-gray-850);
161
+ }
162
+ .code-block {
163
+ position: relative;
164
+ margin: 10px 0 16px;
165
+ }
166
+ pre {
167
+ margin: 10px 0 16px;
168
+ padding: 14px 16px;
169
+ background: #1e1e1d;
170
+ color: #f5f5f5;
171
+ border-radius: var(--radius-xl);
172
+ border: 1px solid var(--cds-gray-850);
173
+ overflow: auto;
174
+ white-space: pre-wrap;
175
+ word-break: break-word;
176
+ }
177
+ .code-block pre {
178
+ margin: 0;
179
+ padding-top: 40px;
180
+ }
181
+ pre code { background: transparent; color: inherit; padding: 0; }
182
+ .copy-btn {
183
+ position: absolute;
184
+ top: 8px;
185
+ right: 8px;
186
+ z-index: 1;
187
+ padding: 4px 10px;
188
+ font: 500 0.72rem/1.4 var(--font);
189
+ color: var(--cds-gray-600);
190
+ background: var(--cds-gray-10);
191
+ border: 1px solid var(--cds-border-strong);
192
+ border-radius: var(--radius-md);
193
+ cursor: pointer;
194
+ box-shadow: var(--cds-shadow-sm);
195
+ }
196
+ .copy-btn:hover {
197
+ color: var(--brand);
198
+ border-color: color-mix(in srgb, var(--cds-clay) 45%, var(--cds-border-strong));
199
+ background: var(--cds-clay-light);
200
+ }
201
+ .copy-btn.copied {
202
+ color: var(--brand);
203
+ border-color: color-mix(in srgb, var(--cds-clay) 45%, transparent);
204
+ background: var(--cds-clay-light);
205
+ }
206
+ ul { padding-left: 1.2rem; }
207
+ footer {
208
+ margin-top: 36px;
209
+ padding-top: 14px;
210
+ border-top: 1px solid var(--cds-border);
211
+ color: var(--cds-text-muted);
212
+ font-size: 0.75rem;
213
+ }
214
+ /* Explicitly no logo / brand mark images */
215
+ @media print {
216
+ body { background: #fff; }
217
+ .sheet {
218
+ margin: 0; max-width: none;
219
+ border: none; box-shadow: none; border-radius: 0; padding: 0;
220
+ }
221
+ h2, .card, table, pre { break-inside: avoid; }
222
+ }
223
+ </style>
224
+ </head>
225
+ <body>
226
+ <article class="sheet">
227
+ <div class="accent-bar" aria-hidden="true"></div>
228
+ <header>
229
+ <h1>{{DOC_TITLE}}</h1>
230
+ <p class="status">{{STATUS_LINE}}</p>
231
+ <dl class="meta">
232
+ <dt>项目 / 模块</dt><dd>{{PROJECT_MODULE}}</dd>
233
+ <dt>系统与客户端</dt><dd>{{SYSTEM_CLIENT}}</dd>
234
+ <dt>需求提出人</dt><dd>{{REQUESTER}}</dd>
235
+ <dt>类型</dt><dd>{{FS_TYPE}}</dd>
236
+ <dt>更新</dt><dd>{{UPDATED}}</dd>
237
+ </dl>
238
+ </header>
239
+ <div class="body">
240
+ {{BODY_HTML}}
241
+ </div>
242
+ <footer>
243
+ Generated by SapBuddy
244
+ </footer>
245
+ </article>
246
+ <script>
247
+ (function () {
248
+ function getCodeText(pre) {
249
+ var code = pre.querySelector("code");
250
+ return (code || pre).textContent;
251
+ }
252
+ function wrapPre(pre) {
253
+ if (pre.closest(".code-block")) return;
254
+ var wrap = document.createElement("div");
255
+ wrap.className = "code-block";
256
+ pre.parentNode.insertBefore(wrap, pre);
257
+ wrap.appendChild(pre);
258
+ var btn = document.createElement("button");
259
+ btn.type = "button";
260
+ btn.className = "copy-btn";
261
+ btn.setAttribute("aria-label", "复制代码");
262
+ btn.textContent = "复制";
263
+ btn.addEventListener("click", function () {
264
+ var text = getCodeText(pre);
265
+ function ok() {
266
+ btn.textContent = "已复制";
267
+ btn.classList.add("copied");
268
+ setTimeout(function () {
269
+ btn.textContent = "复制";
270
+ btn.classList.remove("copied");
271
+ }, 1500);
272
+ }
273
+ function fail() {
274
+ btn.textContent = "失败";
275
+ setTimeout(function () { btn.textContent = "复制"; }, 1500);
276
+ }
277
+ if (navigator.clipboard && navigator.clipboard.writeText) {
278
+ navigator.clipboard.writeText(text).then(ok).catch(function () {
279
+ try {
280
+ var ta = document.createElement("textarea");
281
+ ta.value = text;
282
+ ta.setAttribute("readonly", "");
283
+ ta.style.position = "fixed";
284
+ ta.style.left = "-9999px";
285
+ document.body.appendChild(ta);
286
+ ta.select();
287
+ document.execCommand("copy");
288
+ document.body.removeChild(ta);
289
+ ok();
290
+ } catch (e) { fail(); }
291
+ });
292
+ } else {
293
+ try {
294
+ var ta2 = document.createElement("textarea");
295
+ ta2.value = text;
296
+ ta2.setAttribute("readonly", "");
297
+ ta2.style.position = "fixed";
298
+ ta2.style.left = "-9999px";
299
+ document.body.appendChild(ta2);
300
+ ta2.select();
301
+ document.execCommand("copy");
302
+ document.body.removeChild(ta2);
303
+ ok();
304
+ } catch (e2) { fail(); }
305
+ }
306
+ });
307
+ wrap.appendChild(btn);
308
+ }
309
+ function init() {
310
+ document.querySelectorAll("pre").forEach(wrapPre);
311
+ }
312
+ if (document.readyState === "loading") {
313
+ document.addEventListener("DOMContentLoaded", init);
314
+ } else {
315
+ init();
316
+ }
317
+ })();
318
+ </script>
319
+ </body>
320
+ </html>
@@ -0,0 +1,93 @@
1
+ <!-- 写作约定(渲染时不可见,生成后删除本段)
2
+ - 只写事实与决定。建议标【建议】;未定标【待确认 Q-xx】;不适用写【不适用:原因】。
3
+ - 编号:R 业务规则、T 验收、Q 待确认、E 证据、M 消息。只在本文件内唯一,不重排。
4
+ - 字段用业务名,就地写清类型、必填、取值来源与格式。同一字段在不同位置格式不同时,各自写清换算。
5
+ - 每条规则必须能判真假,并且能被至少一个 T 用例验证。
6
+ - 不写"不得/禁止/注意"类训诫——生成纪律由技能规则约束,不进正文。
7
+ - 拿不准的内容不要写成事实;宁可留 Q,也不要补一个看似合理的值。
8
+ -->
9
+
10
+ # FS:<需求名称>(<类型>)
11
+
12
+ 状态:草稿 · 待确认 <N> 项 · 更新 <YYYY-MM-DD>
13
+ 项目 / 模块:<项目名 · 模块> | 系统与客户端:<连接名 / Client> | 需求提出人:<角色或姓名>
14
+
15
+ ## 1. 需求与范围
16
+
17
+ **背景与问题**
18
+ <业务现在遇到什么问题,具体表现是什么。>
19
+
20
+ **业务目标**
21
+ <期望达到的可观察结果,而不是"实现某功能"。>
22
+
23
+ **在范围内**
24
+ <业务对象、组织范围、业务入口、时间范围。>
25
+
26
+ **不在范围内**
27
+ <明确排除的部分。>
28
+
29
+ **依赖与前置条件**
30
+ <需要先具备的主数据、配置、外部系统、相关需求。>
31
+
32
+ ## 2. 现状与差异
33
+
34
+ | 环节 | 系统当前行为 | 依据 |
35
+ | --- | --- | --- |
36
+ | <业务环节> | <当前实际怎么处理> | E-01 / 需求确认 |
37
+ | | | |
38
+
39
+ **差异说明**:<这次要改变什么,哪些保持不变。>
40
+
41
+ ## 3. <类型专项:插入 02–05 之一>
42
+
43
+ ## 4. 业务规则
44
+
45
+ ### R-01 <规则名称>
46
+
47
+ - **条件**:<可判真假的条件;涉及金额数量时写清币种、单位、精度、含税口径。>
48
+ - **结果**:<系统应表现出的行为:阻止 / 提示 / 赋值 / 生成单据。>
49
+ - **异常**:<缺失、为空、越界、重复时怎么处理;不命中任何条件时怎样。>
50
+ - **依据**:<业务确认的时间与场合 / E-xx / Q-xx。建议未获确认时写【建议】。>
51
+ - **验收**:T-01
52
+
53
+ <多于一条规则时按 R-02、R-03 复制。规则之间有优先级时,在上一条的「条件」里写清。>
54
+
55
+ ## 5. 权限、消息与运行
56
+
57
+ **权限**
58
+ <角色、组织范围、权限对象;未核实写 Q。不新增权限时写明沿用哪个标准权限。>
59
+
60
+ **消息**
61
+
62
+ | 编号 | 触发条件 | 用户看到的文案 |
63
+ | --- | --- | --- |
64
+ | M-01 | R-01 不通过 | <可直接给用户看的文字> |
65
+
66
+ **运行**
67
+ <前台/后台、频率、单次数据量、时效要求;无特殊要求写「无特殊要求」。>
68
+
69
+ ## 6. 验收
70
+
71
+ ### T-01 <场景名称>
72
+
73
+ - **前置**:<可重复准备的初始状态。>
74
+ - **输入**:<具体取值或操作步骤。>
75
+ - **预期**:<可核对的结果:值、状态、消息、是否保存成功。>
76
+
77
+ <边界、异常、重复提交各有独立用例,按 T-02、T-03 复制。只在真实执行后补记结果。>
78
+
79
+ ## 7. 待确认
80
+
81
+ | 编号 | 问题 | 谁来定 | 影响 |
82
+ | --- | --- | --- | --- |
83
+ | Q-01 | <一个具体问题,不是话题> | <业务 / 技术 / 系统查询> | <影响哪条规则或测试> |
84
+
85
+ ## 附录 A 取证记录
86
+
87
+ | 编号 | 查了什么 | 结果 | 限制与结论 |
88
+ | --- | --- | --- | --- |
89
+ | E-01 | <工具与参数 / 对象与字段 / 查询条件与行数上限> | <客观返回:行数、字段、错误> | <这份证据能证明什么,不能证明什么> |
90
+
91
+ <只记录实际做过的查询。零行 ≠ 对象不存在;样本符合 ≠ 全量正确;对象存在 ≠ 时点与行为已验证。>
92
+
93
+ Generated by SapBuddy
@@ -0,0 +1,60 @@
1
+ <!-- 本片段插入骨架第3节。功能报表会改变业务状态:除查询与展示外,必须写清执行单元、
2
+ 哪些记录共同成功、失败后停在哪里。 -->
3
+
4
+ ## 3. 功能设计
5
+
6
+ ### 3.1 业务动作
7
+
8
+ | 动作 | 业务效果 | 前置状态 | 目标状态 |
9
+ | --- | --- | --- | --- |
10
+ | <批准 / 过账 / 创建 / 重处理> | <具体改变什么业务内容> | <执行前必须满足什么> | <成功后是什么状态> |
11
+
12
+ **实现方式与取舍**:<标准事务码 / 标准功能 / 自建程序;为何选这个;标准功能能否满足。未验证标 Q。>
13
+
14
+ - **不包含的动作**:<明确排除,避免开发自行扩大范围。>
15
+ - **前置确认**:<正式执行前向用户展示哪些对象、数量、金额与不可逆影响。>
16
+
17
+ ### 3.2 输入与候选
18
+
19
+ | 条件 / 字段 | 含义 | 技术名称 | 类型 | 必填 | 输入形式 | 默认值 |
20
+ | --- | --- | --- | --- | --- | --- | --- |
21
+ | 工厂 | 限制可处理工厂 | WERKS | CHAR(4) | 是 | 多选,F4 | 用户默认工厂 |
22
+
23
+ 上面一行为填写示范,生成实际 FS 时替换。
24
+
25
+ - **候选来源**:<从哪些对象、按什么条件筛出可处理记录;关联基数是 1:1 还是 1:N。>
26
+ - **已处理对象**:<是否仍出现在列表中;以什么状态显示;还能执行哪些动作。>
27
+ - **列表到执行的失效**:<展示后状态或数量发生变化时,执行前如何重新校验。>
28
+
29
+ ### 3.3 校验
30
+
31
+ | 顺序 | 校验层级 | 条件 | 未通过时 | 消息 |
32
+ | --- | --- | --- | --- | --- |
33
+ | 1 | 字段 | <…> | 阻止该行 | M-01 |
34
+ | 2 | 单据 | <…> | 阻止整张单据 | M-02 |
35
+ | 3 | 批次 | <…> | 阻止整批 | M-03 |
36
+
37
+ 校验顺序决定用户先看到哪条错误,必须写明;不同层级失败的阻断范围不同。
38
+
39
+ ### 3.4 执行单元与部分成功
40
+
41
+ - **执行单元**:<一行、一张单据还是整批;输入行与执行单元的对应关系。>
42
+ - **单据内原子性**:<同一单据多行是否必须整体成功;不适用时写原因。>
43
+ - **跨单据策略**:<一张失败后其余继续或停止;已成功的如何保留与告知。>
44
+ - **结果记录**:<逐行还是逐单据给出结果;成功与失败数量口径。>
45
+ - **重新处理**:<再次执行时如何排除已成功对象。>
46
+
47
+ ### 3.5 重复、并发与结果未知
48
+
49
+ - **重复判定键**:<哪些业务字段代表同一次意图;不能用每次新生成的批次号。>
50
+ - **重复提交**:<双击、重复导入、后台重跑时分别怎样。>
51
+ - **并发**:<哪些对象不能被同时处理;冲突时拒绝、排队还是重新校验。>
52
+ - **结果未知**:<超时或断连后,先用什么核实真实结果,再决定是否重试。>
53
+ - **恢复起点**:<从未处理单元恢复,还是从失败步骤恢复。>
54
+
55
+ ### 3.6 执行方式
56
+
57
+ - **前台 / 后台**:<是否都支持;不支持时说明。>
58
+ - **试运行**:<是否需要、系统是否具备;能模拟哪些校验、绝不能发生哪些写入。>
59
+ - **数据量与中断**:<单次处理量、时效;取消时已成功部分如何处理。>
60
+ - **日志**:<记录业务键、动作、结果、时间;保留要求。>
@@ -0,0 +1,92 @@
1
+ <!-- 本片段插入骨架第3节。只写与"消息怎么进出、字段怎么换算、什么算成功"有关的内容;
2
+ 权限、消息文案、验收、证据分别在骨架第5、6节和附录A。 -->
3
+
4
+ ## 3. 接口设计
5
+
6
+ ### 3.1 交互边界
7
+
8
+ | 项目 | 定义 |
9
+ | --- | --- |
10
+ | 业务用途与成功标志 | <对方拿到什么、能据此完成什么业务;什么结果才算这次交互成功> |
11
+ | 调用发起方 → 被调用方 | <哪边主动发起> |
12
+ | 业务数据源 → 业务数据目标 | <数据从哪个系统产生、最终落在哪里。可能与调用方向相反> |
13
+ | 协议 / 同步或异步 | <已定的协议;异步时说明返回的是受理还是完成> |
14
+ | 触发方式与频率 | <业务事件 / 定时 / 人工;时间窗口与时区> |
15
+ | 备选方案与取舍 | <考虑过的其它做法,为什么选这个;没有则写「无」> |
16
+
17
+ ### 3.2 消息与字段
18
+
19
+ 消息:<名称>(请求 / 响应 / 回调),方向 <A → B>
20
+
21
+ | 路径 | 含义 | 类型(长度) | 必填 | 取值来源与换算 | 空值处理 |
22
+ | --- | --- | --- | --- | --- | --- |
23
+ | Header.OrderId | 采购订单号 | CHAR(10) | 是 | 取自 EKKO-EBELN,补足前导零 | 为空即拒绝 |
24
+ | Items[].Price | 行项目净价 | DEC(11,2) | 是 | EKPO-NETPR,按价格单位换算为单价 | 0 与空分别处理:0 合法,空拒绝 |
25
+ | Items[].DelivDate | 交货日期 | CHAR(10) | 否 | EKPO-EINDT,`YYYY-MM-DD` | 空表示未定,不参与计算 |
26
+
27
+ <`Items[]` 表示重复集合,路径在全文保持一致。多级结构按实际层级展开,不限制层数。
28
+ 上面三行是填写示范,生成实际 FS 时替换。>
29
+
30
+ 固定部分:编码 <UTF-8 / 其它>;日期格式 <…>;标识类字段保留前导零 <是/否>。
31
+
32
+ ### 3.3 传输范围
33
+
34
+ | 项目 | 规则 |
35
+ | --- | --- |
36
+ | 全量 / 增量 | <哪一种;两者都要时写清切换条件> |
37
+ | 筛选条件 | <组织、业务类型、状态等;可与增量叠加> |
38
+ | 增量依据 | <变更时间 / 序号 / 事件;是否覆盖新增、修改、删除、冲销> |
39
+ | 边界与迟到 | <起止是否包含、时区、同时间戳的次序、迟到记录怎么处理> |
40
+ | 水位推进 | <在哪个节点推进:发送成功 / 受理成功 / 业务成功> |
41
+ | 空批次 | <没有数据时是否发送、如何记录> |
42
+ | 首次与补传 | <初始范围、历史补传、断点恢复> |
43
+
44
+ ### 3.4 结果与失败
45
+
46
+ | 场景 | 期望处理 | 由谁确认结果 |
47
+ | --- | --- | --- |
48
+ | 正常完成 | <响应里返回什么,对端据此判断什么> | <接收方 / 人工核对> |
49
+ | 重复请求 | <业务键是什么;再次到达时返回原结果还是拒绝> | |
50
+ | 同键不同内容 | <比较哪些字段;冲突怎么处理> | |
51
+ | 部分成功 | <业务原子单元是一行、一张单据还是整批;已成功部分是否保留> | |
52
+ | 超时或结果未知 | <先用什么核对真实结果;确认前是否允许重试> | |
53
+ | 需要补偿 | <SAP 与对端各自的实际状态;谁来修> | |
54
+
55
+ 结论层次写清楚:<传输到达 / 已受理 / 业务完成>分别以什么为证据——三者不能相互替代。
56
+
57
+ ### 3.5 日志与对账
58
+
59
+ - **日志**:<记录哪些关联标识、状态、业务编号、错误摘要;保留多久。>
60
+ - **对账**:<用哪些业务键核对数量或金额,在什么时间窗口,容差多少,差异由谁处理。>
61
+ - **技术对象**:<函数 / API / 服务的候选名称与用途,标清是已核实还是待验证。>
62
+ ### 3.6 样例 JSON(归档必出)
63
+
64
+ 按 3.2 字段表整理**一份可联调的示例**(虚构但类型/必填/格式与表一致)。HTML 归档时把下列代码块原样放入「样例 JSON」节。
65
+
66
+ **请求示例**
67
+
68
+ ```json
69
+ {
70
+ "Header": {
71
+ "OrderId": "4500001234"
72
+ },
73
+ "Items": [
74
+ {
75
+ "Price": 12.50,
76
+ "DelivDate": "2026-11-01"
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ **响应示例**
83
+
84
+ ```json
85
+ {
86
+ "Status": "ACCEPTED",
87
+ "BusinessKey": "4500001234",
88
+ "Message": "受理成功"
89
+ }
90
+ ```
91
+
92
+ 说明:路径、嵌套与 3.2 保持一致;空值/0 按表中「空值处理」示范;多消息(请求/响应/回调)各自给一组。未定字段不要编造业务值,标【待确认】或从示例中去掉。
@@ -0,0 +1,55 @@
1
+ <!-- 本片段插入骨架第3节。查询报表只读;若某个操作会改变业务状态,改用功能报表片段。 -->
2
+
3
+ ## 3. 报表设计
4
+
5
+ ### 3.1 输出与粒度
6
+
7
+ | 项目 | 定义 |
8
+ | --- | --- |
9
+ | 报表用途 | <使用者据此判断什么、随后做什么> |
10
+ | 一行代表什么 | <一张单据 / 一个行项目 / 一个期间汇总> |
11
+ | 业务唯一键 | <哪些字段组合唯一确定一行> |
12
+ | 多种视图 | <明细与汇总各自定义粒度;没有则写「仅明细」> |
13
+ | 数据时点 | <查询时点快照 / 实时状态 / 某个业务截止点> |
14
+ | 实现方式与取舍 | <标准事务码 / 标准报表 / 自建程序;为何选这个;标准功能能否满足> |
15
+
16
+ ### 3.2 选择条件
17
+
18
+ | 字段 | 含义 | 技术名称 | 类型 | 必填 | 输入形式 | 默认值 | 校验 |
19
+ | --- | --- | --- | --- | --- | --- | --- | --- |
20
+ | 工厂 | 限制工厂范围 | WERKS | CHAR(4) | 否 | 多选,F4 | <无 / 用户默认> | 必须属于用户权限范围 |
21
+
22
+ - **空值含义**:<未输入表示"不限"还是"必须输入";两者必须选一个。>
23
+ - **条件依赖**:<哪些条件互斥、成组必填、受上级条件约束。>
24
+ - **日期边界**:<用哪个业务日期、起止是否包含、时区。>
25
+ - **最小筛选范围**:<允许全量按组织范围执行,还是必须至少给一个条件。>
26
+
27
+ ### 3.3 输出字段
28
+
29
+ | 显示名 | 来源 / 计算 | 类型(长度,小数) | 格式 | 空值与零的显示 |
30
+ | --- | --- | --- | --- | --- |
31
+ | 采购订单号 | EKKO-EBELN | CHAR(10) | 去前导零,左对齐 | — |
32
+ | 订单净额 | SUM(EKPO-NETWR) | DEC(15,2) | 右对齐,2 位小数 | 无非空行时显示 0.00,不显示留白 |
33
+
34
+ <字段较多时按视图拆表;同一字段在不同视图格式不同,各自写清。>
35
+
36
+ ### 3.4 取数与关联
37
+
38
+ | 来源 | 用于 | 关联键 | 基数 | 无匹配 | 多匹配 |
39
+ | --- | --- | --- | --- | --- | --- |
40
+ | EKKO | 抬头 | EBELN | 1:1 | 排除该行 | 不应发生,出现则报错 |
41
+ | EKPO | 行项目 | EBELN | 1:N | 保留抬头、行值留空 | 正常展开 |
42
+
43
+ - **排除状态**:<删除、取消、冲销、冻结等状态是否纳入;逐个写清。>
44
+ - **当前值 vs 历史值**:<名称、组织归属、价格取当期值还是业务发生时值。>
45
+ - **重复放大风险**:<一对多关联后金额是否会被重复累加;如何避免。>
46
+
47
+ ### 3.5 计算与核对
48
+
49
+ - **计算顺序**:<过滤 → 换算 → 关联 → 汇总,写明先后。>
50
+ - **币种与单位**:<换算汇率类型与取值日期;不换算时说明理由。>
51
+ - **舍入**:<在哪一层舍入、保留几位;累加用未舍入值还是舍入值。>
52
+ - **比率与累计**:<分子分母、期间;不得对百分比直接相加。>
53
+ - **空值传播**:<关键字段缺失时该行不可计算,显示为空而不是 0。>
54
+ - **对账依据**:<用哪张标准报表或独立查询核对;容差与差异说明。>
55
+ - **数据量与时效**:<典型行数、峰值、可接受的响应时间;超出上限时如何提示。>
@@ -0,0 +1,34 @@
1
+ # HTML 归档交付
2
+
3
+ 企业归档除 Markdown(给 AI / 协作)外,**必须同时**生成一份 HTML。
4
+
5
+ ## 产出物
6
+
7
+ 默认目录:`output/fs/<需求名>/`
8
+
9
+ | 文件 | 说明 |
10
+ | --- | --- |
11
+ | `FS.md` | 主规格(AI 友好) |
12
+ | `FS.html` | 归档版:用 `assets/templates/fs-archive.html` 填入 |
13
+ | `io-request.json` / `io-response.json`(仅接口类) | 与正文 3.6 样例一致;若有回调可再加 `io-callback.json` |
14
+
15
+ 用户指定路径时,在同一目录并列输出。
16
+
17
+ ## HTML 规则
18
+
19
+ 1. **禁止 logo**:不放公司徽标、项目 Logo、水印、背景品牌图;页眉只用文字标题与元信息。
20
+ 2. **自包含**:单文件;CSS 内联;无外链脚本/字体 CDN。
21
+ 3. **内容来源**:由已定稿的 `FS.md` 渲染为 HTML 片段填入 `{{BODY_HTML}}`;表格保留为 `<table>`;代码块用 `<pre>`。
22
+ 4. **版式**:清晰层级(h1–h3)、可打印(`@media print` 已在模板);不模仿客户 Word 封面里的企业 VI。
23
+ 5. **替换占位符**:`{{DOC_TITLE}}` `{{STATUS_LINE}}` `{{PROJECT_MODULE}}` `{{SYSTEM_CLIENT}}` `{{REQUESTER}}` `{{FS_TYPE}}` `{{UPDATED}}` `{{BODY_HTML}}`;交付稿不得残留 `{{...}}`。
24
+
25
+ ## 接口类 JSON
26
+
27
+ - 字段表(3.2)是权威;JSON 样例必须与路径/类型/必填/空值处理一致。
28
+ - 至少各一份请求与响应;异步/回调按 3.1 再补。
29
+ - JSON 文件与 HTML 内「样例 JSON」节内容相同,便于联调拷贝。
30
+ - 未知字段不编造:留 Q,或从样例省略并在说明里写清。
31
+
32
+ ## 生成顺序
33
+
34
+ 定稿 Markdown →(接口类)整理 JSON 文件 → 填 HTML 模板 → 自检无 logo、无占位符、接口样例齐全。