Files
accounting-system/API_DESIGN.md
Invoice Master 05ea67144f feat: initial project setup
- Add .NET 8 backend with Clean Architecture
- Add React + Vite + TypeScript frontend
- Implement authentication with JWT
- Implement Azure Blob Storage client
- Implement OCR integration
- Implement supplier matching service
- Implement voucher generation
- Implement Fortnox provider
- Add unit and integration tests
- Add Docker Compose configuration
2026-02-04 20:14:34 +01:00

878 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Invoice Master - API 设计文档
**版本**: v3.0
**Base URL**: `https://api.invoice-master.app/api/v1`
**日期**: 2026-02-03
**技术栈**: .NET 8 + ASP.NET Core + MediatR (CQRS)
---
## 1. 概述
### 1.1 多会计系统支持
本 API 支持连接多个会计系统Fortnox, Visma, Hogia 等),通过统一的抽象层提供一致的接口。
**Provider 标识:**
- `fortnox` - Fortnox (瑞典)
- `visma` - Visma eAccounting (北欧)
- `hogia` - Hogia Smart (瑞典)
### 1.2 认证方式
API 使用 **JWT Bearer Token** 进行认证:
```http
Authorization: Bearer <jwt_token>
```
### 1.3 响应格式
所有响应使用 JSON 格式,统一结构:
```json
{
"success": true,
"data": { ... },
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-02-03T10:30:00Z"
}
}
```
错误响应:
```json
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human readable message",
"details": { ... }
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-02-03T10:30:00Z"
}
}
```
### 1.4 HTTP 状态码
| 状态码 | 含义 |
|--------|------|
| 200 | 成功 |
| 201 | 创建成功 |
| 400 | 请求参数错误 |
| 401 | 未认证 |
| 403 | 无权限 |
| 404 | 资源不存在 |
| 409 | 资源冲突 |
| 422 | 业务逻辑错误 |
| 429 | 请求过于频繁 |
| 500 | 服务器错误 |
---
## 2. 认证相关
### 2.1 用户注册
```http
POST /auth/register
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePass123!",
"full_name": "John Doe"
}
```
**响应:**
```json
{
"success": true,
"data": {
"user": {
"id": "uuid",
"email": "user@example.com",
"full_name": "John Doe",
"created_at": "2026-02-03T10:30:00Z"
},
"tokens": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 900
}
}
}
```
### 2.2 用户登录
```http
POST /auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "SecurePass123!"
}
```
**响应:**
```json
{
"success": true,
"data": {
"user": {
"id": "uuid",
"email": "user@example.com",
"full_name": "John Doe",
"connections": [
{
"provider": "fortnox",
"connected": true,
"company_name": "My Company AB"
}
]
},
"tokens": {
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"expires_in": 900
}
}
}
```
### 2.3 刷新 Token
```http
POST /auth/refresh
Content-Type: application/json
{
"refresh_token": "eyJhbGciOiJIUzI1NiIs..."
}
```
### 2.4 登出
```http
POST /auth/logout
Authorization: Bearer <token>
```
---
## 3. 会计系统集成 (通用接口)
### 3.1 获取支持的会计系统列表
```http
GET /accounting/providers
Authorization: Bearer <token>
```
**响应:**
```json
{
"success": true,
"data": {
"providers": [
{
"id": "fortnox",
"name": "Fortnox",
"description": "Swedish accounting software",
"available": true,
"connected": true
},
{
"id": "visma",
"name": "Visma eAccounting",
"description": "Nordic accounting software",
"available": true,
"connected": false
},
{
"id": "hogia",
"name": "Hogia Smart",
"description": "Swedish accounting software",
"available": false,
"connected": false
}
]
}
}
```
### 3.2 获取授权 URL
```http
GET /accounting/{provider}/auth/url
Authorization: Bearer <token>
```
**参数:**
| 参数 | 类型 | 说明 |
|------|------|------|
| provider | string | 会计系统标识 (fortnox, visma, hogia) |
**响应:**
```json
{
"success": true,
"data": {
"provider": "fortnox",
"authorization_url": "https://apps.fortnox.se/oauth-v1/auth?client_id=xxx&redirect_uri=...&scope=...&state=...",
"state": "random_state_string"
}
}
```
### 3.3 OAuth 回调处理
```http
GET /accounting/{provider}/auth/callback?code=xxx&state=xxx
```
**响应:**
```json
{
"success": true,
"data": {
"provider": "fortnox",
"connected": true,
"company_name": "My Company AB",
"company_org_number": "556677-8899",
"connected_at": "2026-02-03T10:30:00Z"
}
}
```
### 3.4 获取用户的所有连接
```http
GET /accounting/connections
Authorization: Bearer <token>
```
**响应:**
```json
{
"success": true,
"data": {
"connections": [
{
"provider": "fortnox",
"connected": true,
"company_name": "My Company AB",
"company_org_number": "556677-8899",
"scopes": ["supplier", "voucher", "account"],
"expires_at": "2026-02-03T11:30:00Z",
"settings": {
"default_voucher_series": "A",
"default_account_code": 5460,
"auto_attach_pdf": true,
"auto_create_supplier": false
}
}
]
}
}
```
### 3.5 获取特定连接状态
```http
GET /accounting/connections/{provider}
Authorization: Bearer <token>
```
**响应:**
```json
{
"success": true,
"data": {
"provider": "fortnox",
"connected": true,
"company_name": "My Company AB",
"company_org_number": "556677-8899",
"scopes": ["supplier", "voucher", "account"],
"expires_at": "2026-02-03T11:30:00Z"
}
}
```
### 3.6 更新连接设置
```http
PATCH /accounting/connections/{provider}/settings
Authorization: Bearer <token>
Content-Type: application/json
{
"default_voucher_series": "A",
"default_account_code": 5460,
"auto_attach_pdf": true,
"auto_create_supplier": false
}
```
### 3.7 断开连接
```http
DELETE /accounting/connections/{provider}
Authorization: Bearer <token>
```
---
## 4. 发票处理
### 4.1 上传发票
```http
POST /invoices
Authorization: Bearer <token>
Content-Type: multipart/form-data
file: <binary>
provider: "fortnox" # 目标会计系统
auto_process: false # 是否自动处理
```
**响应 (预览模式):**
```json
{
"success": true,
"data": {
"id": "inv_uuid",
"status": "preview",
"provider": "fortnox",
"file": {
"name": "Invoice_2024_001.pdf",
"size": 1024567,
"url": "https://blob.azure/..."
},
"extraction": {
"supplier_name": "ABC Company",
"supplier_org_number": "556677-8899",
"invoice_number": "F2024-001",
"invoice_date": "2024-01-15",
"due_date": "2024-02-15",
"amount_total": 1250.00,
"amount_vat": 250.00,
"vat_rate": 25,
"ocr_number": "7350012345678",
"bankgiro": "123-4567",
"currency": "SEK",
"confidence": 0.95
},
"supplier_match": {
"action": "USE_EXISTING",
"supplier_number": "123",
"supplier_name": "ABC Company",
"confidence": 1.0
},
"voucher_preview": {
"series": "A",
"rows": [
{
"account": 5460,
"account_name": "Kontorsmaterial",
"debit": 1000.00,
"credit": 0,
"description": "ABC Company - F2024-001"
},
{
"account": 2610,
"account_name": "Ingående moms",
"debit": 250.00,
"credit": 0,
"description": "Moms 25%"
},
{
"account": 2440,
"account_name": "Leverantörsskulder",
"debit": 0,
"credit": 1250.00,
"description": "Faktura F2024-001",
"supplier_number": "123"
}
]
},
"created_at": "2026-02-03T10:30:00Z"
}
}
```
### 4.2 获取发票列表
```http
GET /invoices?page=1&limit=20&status=imported&provider=fortnox&sort=-created_at
Authorization: Bearer <token>
```
**查询参数:**
| 参数 | 类型 | 说明 |
|------|------|------|
| page | int | 页码,默认 1 |
| limit | int | 每页数量,默认 20最大 100 |
| status | string | 过滤状态 |
| provider | string | 过滤会计系统 |
| sort | string | 排序字段,`-` 前缀表示降序 |
**响应:**
```json
{
"success": true,
"data": {
"items": [
{
"id": "inv_uuid",
"status": "imported",
"provider": "fortnox",
"file_name": "Invoice_2024_001.pdf",
"supplier_name": "ABC Company",
"amount_total": 1250.00,
"invoice_date": "2024-01-15",
"voucher": {
"series": "A",
"number": "1234",
"url": "https://api.fortnox.se/3/vouchers/A/1234"
},
"created_at": "2026-02-03T10:30:00Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 156,
"total_pages": 8
}
}
}
```
### 4.3 获取发票详情
```http
GET /invoices/{id}
Authorization: Bearer <token>
```
### 4.4 更新发票数据 (审核时)
```http
PATCH /invoices/{id}
Authorization: Bearer <token>
Content-Type: application/json
{
"extraction": {
"supplier_name": "Corrected Name",
"supplier_org_number": "556677-8899",
"amount_total": 1300.00,
"vat_rate": 25
},
"voucher_rows": [
{
"account": 6210,
"debit": 1040.00,
"credit": 0
},
{
"account": 2610,
"debit": 260.00,
"credit": 0
},
{
"account": 2440,
"debit": 0,
"credit": 1300.00
}
]
}
```
### 4.5 导入到会计系统
```http
POST /invoices/{id}/import
Authorization: Bearer <token>
Content-Type: application/json
{
"provider": "fortnox",
"create_supplier": false,
"supplier_data": {
"name": "New Supplier",
"organisation_number": "112233-4455"
}
}
```
**响应:**
```json
{
"success": true,
"data": {
"id": "inv_uuid",
"status": "imported",
"provider": "fortnox",
"voucher": {
"series": "A",
"number": "1234",
"url": "https://api.fortnox.se/3/vouchers/A/1234"
},
"supplier": {
"number": "123",
"name": "ABC Company"
},
"attachment": {
"id": "att_xxx",
"uploaded": true
},
"accounting_url": "https://apps.fortnox.se/...",
"imported_at": "2026-02-03T10:35:00Z"
}
}
```
### 4.6 删除发票
```http
DELETE /invoices/{id}
Authorization: Bearer <token>
```
仅允许删除未导入 (`pending`, `preview`, `failed`) 状态的发票。
---
## 5. 供应商管理 (通用接口)
### 5.1 获取供应商列表
```http
GET /accounting/{provider}/suppliers?search=ABC&page=1&limit=50
Authorization: Bearer <token>
```
**响应:**
```json
{
"success": true,
"data": {
"items": [
{
"supplier_number": "123",
"name": "ABC Company",
"organisation_number": "556677-8899",
"address": "Storgatan 1, 123 45 Stockholm",
"phone": "08-123 45 67",
"email": "info@abc.com",
"bankgiro": "123-4567",
"cached_at": "2026-02-03T09:00:00Z"
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 45
},
"from_cache": true
}
}
```
### 5.2 创建供应商
```http
POST /accounting/{provider}/suppliers
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "New Supplier AB",
"organisation_number": "112233-4455",
"address1": "Testgatan 1",
"postcode": "123 45",
"city": "Stockholm",
"phone": "08-123 45 67",
"email": "info@supplier.com",
"bankgiro": "765-4321"
}
```
### 5.3 刷新供应商缓存
```http
POST /accounting/{provider}/suppliers/refresh-cache
Authorization: Bearer <token>
```
---
## 6. 会计科目 (通用接口)
### 6.1 获取科目列表
```http
GET /accounting/{provider}/accounts
Authorization: Bearer <token>
```
**响应:**
```json
{
"success": true,
"data": {
"accounts": [
{
"code": 2440,
"name": "Leverantörsskulder",
"type": "liability"
},
{
"code": 2610,
"name": "Ingående moms",
"type": "liability"
},
{
"code": 5460,
"name": "Kontorsmaterial",
"type": "expense"
}
]
}
}
```
### 6.2 获取科目映射规则
```http
GET /account-mappings?provider=fortnox
Authorization: Bearer <token>
```
### 6.3 创建科目映射规则
```http
POST /account-mappings
Authorization: Bearer <token>
Content-Type: application/json
{
"provider": "fortnox",
"supplier_org_number": "556677-8899",
"keyword": "kontor",
"account_code": 5460,
"vat_rate": 25,
"description_template": "{supplier_name} - Kontorsmaterial",
"priority": 5
}
```
---
## 7. Webhooks
### 7.1 通用 Webhook 接收
```http
POST /webhooks/{provider}
Headers:
X-Provider-Event: voucher.created
X-Provider-Signature: sha256=...
{
"event": "voucher.created",
"provider": "fortnox",
"timestamp": "2026-02-03T10:30:00Z",
"data": {
"voucher_number": "1234",
"series": "A",
"company_org_number": "556677-8899"
}
}
```
### 7.2 注册 Webhook (内部)
```http
POST /webhooks/register
Authorization: Bearer <admin_token>
Content-Type: application/json
{
"provider": "fortnox",
"url": "https://api.invoice-master.app/webhooks/fortnox",
"events": ["voucher.created", "voucher.updated"]
}
```
---
## 8. 健康检查
### 8.1 基础健康检查
```http
GET /health
```
**响应:**
```json
{
"status": "healthy",
"timestamp": "2026-02-03T10:30:00Z",
"version": "2.0.0"
}
```
### 8.2 详细健康检查
```http
GET /health/detailed
Authorization: Bearer <admin_token>
```
**响应:**
```json
{
"status": "healthy",
"timestamp": "2026-02-03T10:30:00Z",
"checks": {
"database": { "status": "healthy", "latency_ms": 5 },
"redis": { "status": "healthy", "latency_ms": 2 },
"providers": {
"fortnox": { "status": "healthy", "latency_ms": 150 },
"visma": { "status": "not_configured" }
},
"ocr_api": { "status": "healthy", "latency_ms": 50 },
"blob_storage": { "status": "healthy", "latency_ms": 30 }
}
}
```
---
## 9. 错误代码表
| 错误代码 | HTTP 状态 | 说明 |
|----------|-----------|------|
| `UNAUTHORIZED` | 401 | Token 无效或过期 |
| `FORBIDDEN` | 403 | 无权限访问 |
| `NOT_FOUND` | 404 | 资源不存在 |
| `VALIDATION_ERROR` | 400 | 请求参数验证失败 |
| `PROVIDER_NOT_SUPPORTED` | 400 | 不支持的会计系统 |
| `PROVIDER_NOT_CONNECTED` | 422 | 用户未连接该会计系统 |
| `PROVIDER_TOKEN_EXPIRED` | 401 | 会计系统 Token 过期 |
| `PROVIDER_RATE_LIMITED` | 429 | 会计系统 API 限流 |
| `OCR_FAILED` | 422 | OCR 提取失败 |
| `INVOICE_ALREADY_IMPORTED` | 409 | 发票已导入 |
| `INVALID_FILE_TYPE` | 400 | 不支持的文件类型 |
| `FILE_TOO_LARGE` | 400 | 文件超过大小限制 |
| `SUPPLIER_NOT_FOUND` | 404 | 供应商不存在 |
| `VOUCHER_CREATE_FAILED` | 422 | 凭证创建失败 |
---
## 10. 速率限制
| 端点 | 限制 |
|------|------|
| `/auth/*` | 10 req/min |
| `/invoices` (POST) | 10 req/min |
| `/invoices/*` | 100 req/min |
| `/accounting/{provider}/*` | 30 req/min |
| 其他 | 100 req/min |
限速响应头:
```http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1643875200
```
---
## 11. OpenAPI 规范
完整的 OpenAPI 3.0 规范可在 `/docs` 端点查看 (Swagger UI)。
```http
GET /docs # Swagger UI
GET /openapi.json # OpenAPI JSON
```
---
## 12. API 变更日志
### v3.0 (2026-02-03)
**技术栈变更:**
- Python/FastAPI → .NET 8 + ASP.NET Core
- 新增 CQRS 模式 (MediatR)
- 新增领域事件 (审计支持)
- 新增审计 API 端点
**新增:**
- `/invoices/{id}/audit-log` - 获取发票审计日志
- `/users/me/audit-log` - 获取用户操作历史
- `/admin/audit-export` - 导出审计报告
### v2.0 (2026-02-03)
**新增:**
- 多会计系统支持
- `/accounting/providers` - 获取支持的会计系统列表
- `/accounting/{provider}/auth/url` - 通用授权 URL 接口
- `/accounting/{provider}/auth/callback` - 通用 OAuth 回调
- `/accounting/connections` - 获取所有连接
- `/accounting/connections/{provider}` - 特定连接管理
**变更:**
- `/fortnox/*` 接口迁移到 `/accounting/{provider}/*`
- `/suppliers` 迁移到 `/accounting/{provider}/suppliers`
- `/accounts` 迁移到 `/accounting/{provider}/accounts`
- 发票上传增加 `provider` 参数
- 发票导入增加 `provider` 参数
**废弃:**
- `/fortnox/*` (旧接口,将在 v3.0 移除)
---
**文档历史:**
| 版本 | 日期 | 作者 | 变更 |
|------|------|------|------|
| 3.0 | 2026-02-03 | Claude Code | 重构为 .NET + CQRS + 审计支持 |
| 2.0 | 2026-02-03 | Claude Code | 添加多会计系统支持 |
| 1.0 | 2026-02-03 | Claude Code | 初始版本 |