# Story 005.001: 创建飞鹅打印模块

## Status
Ready for Review

## Story
**As a** 系统管理员
**I want** 能够集成飞鹅打印API
**so that** 实现订单支付成功后自动打印小票

## Acceptance Criteria
1. [x] 创建`feie_printer_mt`表，存储打印机配置信息
2. [x] 创建`feie_print_task_mt`表，记录打印任务（包含防退款延迟相关字段）
3. [x] 创建`feie_config_mt`表，存储基础打印配置
4. [x] 实现飞鹅API客户端，支持小票打印接口
5. [x] 提供打印机管理服务（添加、查询、删除打印机）
6. [x] 提供打印任务管理服务（提交任务、查询状态、取消任务）
7. [x] 实现防退款延迟打印调度器（默认2分钟延迟）
8. [x] 编写单元测试覆盖核心逻辑

## Tasks / Subtasks
- [x] 任务1：创建多租户飞鹅打印模块包 (AC: 1,2,3,4,5,6,7)
  - [x] 在 `packages/` 目录下创建 `@d8d/feie-printer-module-mt` 包
  - [x] 配置包的基本结构：`package.json`、`tsconfig.json`、`vitest.config.ts`
  - [x] 创建数据库实体定义文件
  - [x] 创建服务层文件
  - [x] 创建数据验证Schema文件
  - [x] 创建API路由文件
  - [x] 创建类型定义文件
- [x] 任务2：实现数据库实体 (AC: 1,2,3)
  - [x] 创建 `feie-printer.mt.entity.ts` 实体
  - [x] 创建 `feie-print-task.mt.entity.ts` 实体
  - [x] 创建 `feie-config.mt.entity.ts` 实体
  - [x] 配置实体关系和多租户支持
- [x] 任务3：实现飞鹅API客户端服务 (AC: 4)
  - [x] 创建 `feie-api.service.ts` 服务
  - [x] 实现飞鹅API接口封装：`Open_printerAddlist`、`Open_printerDelList`、`Open_queryPrinterStatus`、`Open_printMsg`、`Open_queryOrderState`
  - [x] 实现错误处理和重试逻辑
  - [x] 实现API签名验证
- [x] 任务4：实现打印机管理服务 (AC: 5)
  - [x] 创建 `printer.service.ts` 服务
  - [x] 实现打印机添加、查询、删除功能
  - [x] 实现打印机状态管理
  - [x] 实现默认打印机设置
- [x] 任务5：实现打印任务管理服务 (AC: 6)
  - [x] 创建 `print-task.service.ts` 服务
  - [x] 实现打印任务提交、查询、取消功能
  - [x] 实现打印状态更新和同步
  - [x] 实现打印失败重试机制
- [x] 任务6：实现防退款延迟打印调度器 (AC: 7)
  - [x] 创建 `delay-scheduler.service.ts` 服务
  - [x] 实现延迟任务调度逻辑（默认2分钟延迟）
  - [x] 实现退款事件监听和任务取消
  - [x] 实现调度器健康检查和故障恢复
- [x] 任务7：实现API路由 (AC: 5,6)
  - [x] 创建打印机管理API路由
  - [x] 创建打印任务管理API路由
  - [x] 创建打印配置管理API路由
  - [x] 实现多租户路由中间件
- [x] 任务8：编写单元测试 (AC: 8)
  - [x] 为每个服务编写单元测试
  - [x] 为API客户端编写集成测试
  - [x] 为调度器编写测试
  - [x] 确保测试覆盖率 > 80%
- [x] 任务9：补齐集成测试用例 (AC: 8)
  - [x] 实现配置管理API测试（获取配置、更新配置、配置验证）
  - [x] 实现调度器管理API测试（状态查询、启动停止、健康检查）
  - [x] 实现打印任务详情API测试
  - [x] 实现打印机状态和更新API测试
  - [x] 实现打印机删除API测试
  - [x] 实现打印任务重试和取消API测试
  - [x] 实现调度器触发API测试
  - [x] 实现更多边界条件测试
- [x] 任务10：新增集成测试用例覆盖更多场景 (AC: 8)
  - [x] 实现创建打印机API测试（正常流程、必填字段验证、默认打印机）
  - [x] 实现打印任务状态查询API测试（状态查询、不存在的任务、不同状态的任务）
  - [x] 实现分页和排序功能测试（打印机列表分页、打印任务列表分页、创建时间倒序排序、打印机类型筛选）
  - [x] 实现更多错误场景测试（无效打印机类型、无效打印类型、负数延迟时间、重试次数超限、不存在的配置键）

## Dev Notes

### 技术栈信息 [Source: architecture/tech-stack.md]
- **运行时**: Node.js 20.18.3
- **框架**: Hono 4.8.5 (Web框架和API路由，RPC类型安全)
- **数据库**: PostgreSQL 17 (通过TypeORM)
- **ORM**: TypeORM 0.3.25 (数据库操作抽象，实体管理)
- **测试框架**: Vitest 2.x (单元测试框架)
- **定时任务**: node-cron latest (定时任务调度库)
- **认证**: JWT 9.0.2 (用户认证和安全，Bearer Token)

### 项目结构信息 [Source: architecture/source-tree.md]
- **项目根目录**: `/mnt/code/186-175-template-22`
- **包位置**: `packages/@d8d/feie-printer-module-mt/`
- **包架构层次**: 多租户模块层（-mt后缀），支持租户数据隔离
- **多租户架构**: 基于Epic-007方案，通过复制单租户包创建多租户版本
- **租户隔离**: 通过租户ID实现数据隔离，支持多租户部署

### 包结构规范 [Source: architecture/source-tree.md#多租户包架构]
```
packages/@d8d/feie-printer-module-mt/
├── src/
│   ├── entities/                  # 实体定义
│   │   ├── feie-printer.mt.entity.ts
│   │   ├── feie-print-task.mt.entity.ts
│   │   ├── feie-config.mt.entity.ts
│   │   └── index.ts
│   ├── services/                  # 服务层
│   │   ├── feie-api.service.ts    # 飞鹅API客户端（小票打印）
│   │   ├── printer.service.ts     # 打印机管理服务
│   │   ├── print-task.service.ts  # 打印任务服务
│   │   ├── delay-scheduler.service.ts  # 延迟打印调度器
│   │   └── index.ts
│   ├── schemas/                   # 数据验证
│   │   └── index.ts
│   ├── routes/                    # API路由
│   │   └── index.ts
│   ├── types/                     # 类型定义
│   │   └── index.ts
│   └── index.ts                   # 主入口文件
├── tests/                         # 测试文件
├── tsconfig.json                  # TypeScript配置
├── vitest.config.ts               # 测试配置
└── package.json
```

### 数据库设计 [Source: docs/prd/epic-005-feie-printer-integration.md#数据库设计]
```sql
-- 飞鹅打印机配置表
CREATE TABLE feie_printer_mt (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
  printer_sn VARCHAR(50) NOT NULL COMMENT '打印机序列号',
  printer_key VARCHAR(100) NOT NULL COMMENT '打印机密钥',
  printer_name VARCHAR(100) COMMENT '打印机名称',
  printer_type VARCHAR(20) DEFAULT '58mm' COMMENT '打印机类型: 58mm, 80mm',
  printer_status VARCHAR(20) DEFAULT 'ACTIVE' COMMENT '打印机状态: ACTIVE, INACTIVE, ERROR',
  is_default TINYINT DEFAULT 0 COMMENT '是否默认打印机(0:否,1:是)',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_tenant_printer_sn (tenant_id, printer_sn),
  INDEX idx_tenant_id (tenant_id),
  INDEX idx_status (printer_status)
) COMMENT='飞鹅打印机配置表';

-- 飞鹅打印任务表（支持防退款延迟打印）
CREATE TABLE feie_print_task_mt (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
  task_id VARCHAR(100) NOT NULL COMMENT '飞鹅任务ID',
  order_id INT UNSIGNED COMMENT '关联订单ID',
  printer_sn VARCHAR(50) NOT NULL COMMENT '打印机序列号',
  content TEXT NOT NULL COMMENT '打印内容',
  print_type VARCHAR(20) NOT NULL COMMENT '打印类型: RECEIPT(小票), SHIPPING(发货单), ORDER(订单)',
  print_status VARCHAR(20) DEFAULT 'PENDING' COMMENT '打印状态: PENDING, DELAYED(延迟等待), PRINTING, SUCCESS, FAILED, CANCELLED(已取消)',
  error_message VARCHAR(500) COMMENT '错误信息',
  retry_count INT DEFAULT 0 COMMENT '重试次数',
  max_retries INT DEFAULT 3 COMMENT '最大重试次数',
  scheduled_at TIMESTAMP NULL COMMENT '计划打印时间（用于延迟打印）',
  printed_at TIMESTAMP NULL COMMENT '打印完成时间',
  cancelled_at TIMESTAMP NULL COMMENT '取消时间',
  cancel_reason VARCHAR(100) COMMENT '取消原因: REFUND(退款), MANUAL(手动取消), TIMEOUT(超时)',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_task_id (task_id),
  INDEX idx_tenant_order (tenant_id, order_id),
  INDEX idx_status (print_status),
  INDEX idx_scheduled (scheduled_at),
  INDEX idx_created (created_at)
) COMMENT='飞鹅打印任务表';

-- 打印配置表
CREATE TABLE feie_config_mt (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  tenant_id INT UNSIGNED NOT NULL COMMENT '租户ID',
  config_key VARCHAR(50) NOT NULL COMMENT '配置键',
  config_value TEXT COMMENT '配置值',
  config_type VARCHAR(20) DEFAULT 'STRING' COMMENT '配置类型: STRING, JSON, BOOLEAN, NUMBER',
  description VARCHAR(200) COMMENT '配置描述',
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  UNIQUE KEY uk_tenant_key (tenant_id, config_key),
  INDEX idx_tenant_id (tenant_id)
) COMMENT='飞鹅打印配置表';
```

### API设计 [Source: docs/prd/epic-005-feie-printer-integration.md#API设计]
#### 飞鹅打印模块API
1. `GET /api/feie/printers` - 查询打印机列表
2. `POST /api/feie/printers` - 添加打印机
3. `DELETE /api/feie/printers/{printerSn}` - 删除打印机
4. `POST /api/feie/print` - 提交打印任务（支持延迟打印）
5. `GET /api/feie/tasks/{taskId}` - 查询打印任务状态
6. `GET /api/feie/tasks` - 查询打印任务列表
7. `POST /api/feie/tasks/{taskId}/cancel` - 取消打印任务
8. `POST /api/feie/tasks/{taskId}/retry` - 重试打印任务
9. `GET /api/feie/config` - 查询打印配置
10. `PUT /api/feie/config` - 更新打印配置

#### 飞鹅API接口（需要封装）
1. **打印机管理**
   - `Open_printerAddlist` - 添加打印机
   - `Open_printerDelList` - 删除打印机
   - `Open_queryPrinterStatus` - 查询打印机状态

2. **打印任务管理**
   - `Open_printMsg` - 打印小票
   - `Open_queryOrderState` - 查询订单打印状态
   - `Open_queryOrderInfoByDate` - 根据时间查询订单

### 编码标准 [Source: architecture/coding-standards.md]
- **代码风格**: TypeScript严格模式，一致的缩进和命名
- **测试框架**: 使用Vitest + Testing Library + hono/testing
- **测试位置**: `__tests__` 文件夹与源码并列
- **覆盖率目标**: 核心业务逻辑 > 80%
- **测试类型**: 单元测试、集成测试、E2E测试
- **RPC客户端架构**: 使用单例模式的客户端管理器，类型安全的Hono RPC

### 测试标准
- **测试文件位置**: 每个包独立的 `tests/` 目录
- **测试框架**: Vitest 2.x
- **测试模式**: 单元测试覆盖核心逻辑，集成测试验证API功能
- **覆盖率要求**: 核心业务逻辑 > 80%
- **测试数据**: 使用测试数据库，避免污染生产数据
- **错误处理测试**: 测试各种错误场景和边界条件

### 多租户实现要求
- **包命名**: 使用 `-mt` 后缀表示多租户包
- **租户ID字段**: 所有实体必须包含 `tenant_id` 字段
- **数据隔离**: 通过租户ID实现数据查询隔离
- **路由中间件**: 实现多租户路由中间件，自动注入租户上下文
- **权限控制**: 确保租户只能访问自己的数据

### 防退款延迟打印机制
- **默认延迟时间**: 120秒（2分钟）
- **状态管理**: 打印任务状态包括 `PENDING`、`DELAYED`、`PRINTING`、`SUCCESS`、`FAILED`、`CANCELLED`
- **取消场景**: `REFUND`（退款）、`MANUAL`（手动取消）、`TIMEOUT`（超时）
- **调度器设计**: 使用 `node-cron` 实现定时任务调度
- **退款监听**: 监听订单退款事件，自动取消延迟打印任务

### 项目结构对齐说明
- 新包 `@d8d/feie-printer-module-mt` 应放置在 `packages/` 目录下
- 包结构应遵循现有的多租户模块包模式
- 需要与现有的 `@d8d/orders-module-mt` 集成，监听订单支付成功事件
- API路由应遵循现有的RESTful API设计模式

## Testing
### 测试框架和标准
- **测试框架**: Vitest 2.x [Source: architecture/tech-stack.md]
- **测试位置**: `__tests__` 文件夹与源码并列 [Source: architecture/coding-standards.md]
- **覆盖率目标**: 核心业务逻辑 > 80% [Source: architecture/coding-standards.md]
- **测试类型**: 单元测试、集成测试 [Source: architecture/coding-standards.md]

### 具体测试要求
1. **单元测试**:
   - 飞鹅API客户端测试
   - 打印机管理逻辑测试
   - 打印任务管理测试
   - 防退款延迟调度器测试

2. **集成测试**:
   - 飞鹅API集成测试（使用模拟API）
   - API路由功能测试
   - 多租户数据隔离测试

3. **测试文件结构**:
   ```
   tests/
   ├── unit/
   │   ├── feie-api.service.test.ts
   │   ├── printer.service.test.ts
   │   ├── print-task.service.test.ts
   │   └── delay-scheduler.service.test.ts
   └── integration/
       ├── api/
       │   ├── printers.test.ts
       │   ├── print-tasks.test.ts
       │   └── config.test.ts
       └── feie-api.integration.test.ts
   ```

## Change Log
| Date | Version | Description | Author |
|------|---------|-------------|--------|
| 2025-12-06 | 1.0 | 初始创建故事文档 | Bob (Scrum Master) |
| 2025-12-11 | 1.1 | 修复TypeScript类型错误：路由返回类型、枚举类型、参数转换等问题 | James (Developer Agent) |
| 2025-12-11 | 1.2 | 补齐集成测试用例：新增28个测试用例，覆盖配置管理、调度器管理、打印任务详情、打印机状态更新、边界条件等 | James (Developer Agent) |
| 2025-12-11 | 1.3 | 新增集成测试用例：补充15个测试用例，覆盖创建打印机API、打印任务状态查询、分页排序功能、更多错误场景等 | James (Developer Agent) |

## Dev Agent Record
*此部分由开发代理在实现过程中填写*

### Agent Model Used
- **代理名称**: James (Developer Agent)
- **模型**: Claude Sonnet 4.5
- **初始执行时间**: 2025-12-06
- **修复执行时间**: 2025-12-11

### Debug Log References
- 创建了完整的飞鹅打印多租户模块包结构
- 实现了所有数据库实体（3个实体）
- 实现了飞鹅API客户端服务
- 实现了打印机管理服务
- 实现了打印任务管理服务
- 实现了防退款延迟打印调度器
- 实现了API路由
- 编写了单元测试和集成测试
- 修复TypeScript类型错误（2025-12-11）：
  - 修复路由处理程序返回类型不匹配：为所有 `c.json(validatedResponse)` 添加状态码
  - 修复枚举类型不匹配：`printerType` 从 `['RECEIPT', 'LABEL']` 改为 `['58mm', '80mm']`
  - 修复 `PrintType` 枚举使用：使用 `z.nativeEnum(PrintType)` 替代字符串字面量
  - 修复服务方法参数类型转换：正确处理 `CreatePrintTaskDto` 转换
  - 修复Schema转换逻辑：使用Zod `transform` 处理 `'ALL'` 选项
  - 修复调度器响应类型：调整响应数据匹配Schema

### Completion Notes List
1. ✅ 任务1：创建多租户飞鹅打印模块包 (`@d8d/feie-printer-module-mt`)
2. ✅ 任务2：实现数据库实体（3个实体文件）
3. ✅ 任务3：实现飞鹅API客户端服务
4. ✅ 任务4：实现打印机管理服务
5. ✅ 任务5：实现打印任务管理服务
6. ✅ 任务6：实现防退款延迟打印调度器
7. ✅ 任务7：实现API路由
8. ✅ 任务8：编写单元测试
9. ✅ 执行完整验证和测试
10. ✅ 任务9：修复TypeScript类型错误（2025-12-11）
    - 修复路由处理程序返回类型不匹配问题
    - 修复枚举类型不匹配问题（printerType、PrintType）
    - 修复服务方法参数类型转换问题
    - 修复Schema转换逻辑问题
    - 修复调度器响应类型不匹配问题
11. ✅ 任务10：补齐集成测试用例（已完成）
    - 分析现有集成测试覆盖度，识别缺失的测试用例
    - 为故事添加新任务：补齐缺失的集成测试用例
    - 实现配置管理API测试（获取配置、更新配置、配置验证）
    - 实现调度器管理API测试（状态查询、启动停止、健康检查、手动触发）
    - 实现打印任务详情API测试（查询详情、不存在的任务）
    - 实现打印机状态和更新API测试（状态查询、更新、删除）
    - 实现打印任务重试和取消API测试
    - 实现更多边界条件测试（序列号重复、内容过长、延迟时间边界、状态转换）
    - 修复测试中的配置清理问题，确保测试独立性
12. ✅ 任务11：新增集成测试用例覆盖更多场景（已完成）
    - 分析测试覆盖度，识别需要补充的测试场景
    - 实现创建打印机API测试（正常流程、必填字段验证、默认打印机）
    - 实现打印任务状态查询API测试（状态查询、不存在的任务、不同状态的任务）
    - 实现分页和排序功能测试（打印机列表分页、打印任务列表分页、创建时间倒序排序、打印机类型筛选）
    - 实现更多错误场景测试（无效打印机类型、无效打印类型、负数延迟时间、重试次数超限、不存在的配置键）
    - 修复TypeScript类型错误（PrintType枚举使用、打印机类型、响应格式匹配）

### File List
**包结构文件**:
- `packages/feie-printer-module-mt/package.json`
- `packages/feie-printer-module-mt/tsconfig.json`
- `packages/feie-printer-module-mt/vitest.config.ts`

**源代码文件**:
- `packages/feie-printer-module-mt/src/index.ts`
- `packages/feie-printer-module-mt/src/entities/feie-printer.mt.entity.ts`
- `packages/feie-printer-module-mt/src/entities/feie-print-task.mt.entity.ts`
- `packages/feie-printer-module-mt/src/entities/feie-config.mt.entity.ts`
- `packages/feie-printer-module-mt/src/entities/index.ts`
- `packages/feie-printer-module-mt/src/services/feie-api.service.ts`
- `packages/feie-printer-module-mt/src/services/printer.service.ts`
- `packages/feie-printer-module-mt/src/services/print-task.service.ts`
- `packages/feie-printer-module-mt/src/services/delay-scheduler.service.ts`
- `packages/feie-printer-module-mt/src/services/index.ts`
- `packages/feie-printer-module-mt/src/schemas/feie.schema.ts`
- `packages/feie-printer-module-mt/src/schemas/index.ts`
- `packages/feie-printer-module-mt/src/routes/feie.routes.ts`
- `packages/feie-printer-module-mt/src/routes/index.ts`
- `packages/feie-printer-module-mt/src/types/feie.types.ts`
- `packages/feie-printer-module-mt/src/types/index.ts`

**修复的文件（TypeScript类型错误修复）**:
- `packages/feie-printer-module-mt/src/routes/printers/create.mt.ts` - 修复路由返回类型，添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/update.mt.ts` - 修复printerType枚举，添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/detail.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/delete.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/set-default.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/status.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/printers/list.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/tasks/create.mt.ts` - 修复PrintType枚举，添加DTO转换，添加状态码
- `packages/feie-printer-module-mt/src/routes/tasks/list.mt.ts` - 修复PrintType/PrintStatus枚举，修复转换逻辑，添加状态码
- `packages/feie-printer-module-mt/src/routes/tasks/status.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/tasks/cancel.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/tasks/retry.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/scheduler/start.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/scheduler/stop.mt.ts` - 添加状态码
- `packages/feie-printer-module-mt/src/routes/scheduler/trigger.mt.ts` - 修复响应类型匹配，添加状态码

**测试文件**:
- `packages/feie-printer-module-mt/tests/unit/feie-api.service.test.ts`
- `packages/feie-printer-module-mt/tests/unit/printer.service.test.ts`
- `packages/feie-printer-module-mt/tests/unit/print-task.service.test.ts`
- `packages/feie-printer-module-mt/tests/unit/delay-scheduler.service.test.ts`
- `packages/feie-printer-module-mt/tests/integration/feie-api.integration.test.ts` - 新增完整的集成测试用例

**新增的集成测试用例文件**:
- `packages/feie-printer-module-mt/tests/integration/feie-api.integration.test.ts` - 已更新，包含：
  - 配置管理API测试（3个测试用例）
  - 调度器管理API测试（4个测试用例）
  - 打印任务详情API测试（2个测试用例）
  - 打印机状态和更新API测试（6个测试用例）
  - 打印机删除API测试（2个测试用例）
  - 打印任务重试和取消API测试（4个测试用例）
  - 调度器触发API测试（1个测试用例）
  - 更多边界条件测试（6个测试用例）
  - 修复了测试配置清理问题
  - **新增测试场景**：
    - 创建打印机API测试（3个测试用例）
    - 打印任务状态查询API测试（3个测试用例）
    - 分页和排序功能测试（4个测试用例）
    - 更多错误场景测试（5个测试用例）

## QA Results
*此部分由QA代理在审查完成后填写*