feat: Implement initial customer authorization code and invoice management modules with API documentation and configuration.
This commit is contained in:
1 parent
c3d0f4aa2a
commit
b65b4ac801
10 files changed
+708
-251
No files matched your search
@@ -0,0 +1,80 @@
|
||||
# 2026.2.24-用户端发票申请修改
|
||||
|
||||
## 1. 需求背景
|
||||
目前用户申请发票后,如果被管理员驳回(状态为 `rejected`),用户无法修改该申请信息并重新提交。由于每个订单只能关联一个发票记录,用户也无法为该订单重新发起新的申请。因此需要增加一个发票修改接口,允许用户在驳回状态下编辑发票信息并重新进入待处理状态。
|
||||
|
||||
## 2. 业务流程
|
||||
1. **用户侧**:查看发票详情,发现状态为“已驳回”,查看“驳回原因”和“修改建议”。
|
||||
2. **用户侧**:点击修改,编辑发票抬头、税号、邮箱等信息。
|
||||
3. **提交修改**:调用修改接口。
|
||||
- 系统校验发票当前状态必须为 `rejected`。
|
||||
- 系统校验发票所属权。
|
||||
- 系统更新发票信息,并将状态重置为 `pending`。
|
||||
- 系统清空原有的驳回信息(可选,或保留历史但在界面不再作为当前驳回提示)。
|
||||
4. **管理侧**:发票重新出现在待处理列表中。
|
||||
|
||||
## 3. 接口设计
|
||||
|
||||
### 3.1 修改发票申请 (客户端)
|
||||
|
||||
- **接口地址**:`PUT /api/cu/invoices/{id}`
|
||||
- **鉴权**:需要客户端登录态 (`CustomerAuth`)
|
||||
- **请求参数 (JSON Body)**:
|
||||
|
||||
| 字段名 | 类型 | 必填 | 说明 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| invoice_type | string | 是 | 发票类型: personal/enterprise/vat_special |
|
||||
| receiver_email| string | 是 | 收票邮箱 |
|
||||
| title | string | 是 | 发票抬头 |
|
||||
| taxpayer_id | string | 否 | 纳税人识别号 (企业类型必填) |
|
||||
| content | string | 否 | 开票内容 |
|
||||
| remark | string | 否 | 备注 |
|
||||
|
||||
> [!NOTE]
|
||||
> `order_id` 不允许修改,因为发票记录与订单是一一绑定的。
|
||||
|
||||
- **逻辑校验**:
|
||||
1. **存在性校验**:发票 ID 必须存在。
|
||||
2. **权限校验**:发票必须属于当前登录的客户用户 (`cu_user_id`)。
|
||||
3. **状态校验**:只有 `status = 'rejected'` 的发票允许修改。若状态为 `pending` 或 `issued`,则返回错误。
|
||||
4. **字段校验**:与创建发票时的校验逻辑一致(如企业类型必须有税号)。
|
||||
|
||||
- **数据更新**:
|
||||
- 更新传入的业务字段。
|
||||
- `status` 更新为 `pending`。
|
||||
- `updated_at` 更新为当前时间。
|
||||
- `reject_reason`、`suggestion`、`rejected_at`、`rejected_by` 建议清空,以表示这是一次全新的提交。
|
||||
|
||||
### 3.2 响应示例
|
||||
|
||||
**成功响应**:
|
||||
```json
|
||||
{
|
||||
"code": "000000",
|
||||
"message": "成功",
|
||||
"data": {
|
||||
"id": "invoice-uuid",
|
||||
"invoice_no": "INV20260224001",
|
||||
"status": "pending"
|
||||
},
|
||||
"timestamp": "2026-02-24T18:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应 (状态错误)**:
|
||||
```json
|
||||
{
|
||||
"code": "700004",
|
||||
"message": "发票当前状态不允许该操作",
|
||||
"timestamp": "2026-02-24T18:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 影响范围
|
||||
- **后端模型**:需新增 `InvoiceUpdateRequest` 结构体。
|
||||
- **后端服务**:`CuInvoiceService` 新增 `UpdateInvoice` 方法。
|
||||
- **后端接口**:`router.go` 注册新路由。
|
||||
- **前端**:发票详情页增加修改按钮(仅在驳回时显示),跳转至编辑页。
|
||||
|
||||
## 5. 错误码补充
|
||||
- `700006`: 发票当前状态不允许修改 (如果 700004 语义不够具体可以新增,或沿用 700004)。
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
```bash
|
||||
# 使用默认配置
|
||||
go run cmd/main.go
|
||||
cd cmd
|
||||
go run .
|
||||
|
||||
# 指定配置文件
|
||||
cd cmd
|
||||
go run . -config configs/config.dev.yaml
|
||||
```
|
||||
+193
-129
@@ -1,17 +1,10 @@
|
||||
// Package swagger GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
|
||||
// This file was generated by swaggo/swag
|
||||
// Code generated by swaggo/swag. DO NOT EDIT.
|
||||
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"text/template"
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
"github.com/swaggo/swag"
|
||||
)
|
||||
|
||||
var doc = `{
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
@@ -737,11 +730,6 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -755,8 +743,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -912,6 +898,103 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "客户修改已被驳回的发票申请并重新提交",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"发票管理"
|
||||
],
|
||||
"summary": "客户修改发票申请",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "发票ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "发票修改请求",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.InvoiceUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"invoice_no": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "请求参数无效",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "未认证",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "权限不足",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "发票不存在",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器内部错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/cu/invoices/{id}/download": {
|
||||
@@ -1011,22 +1094,12 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
@@ -1052,13 +1125,9 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1220,11 +1289,6 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expire_time": {
|
||||
@@ -1247,8 +1311,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1306,11 +1368,6 @@ var doc = `{
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"license_count": {
|
||||
@@ -1321,8 +1378,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1337,11 +1392,6 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"discount_description": {
|
||||
@@ -1361,8 +1411,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1543,19 +1591,19 @@ var doc = `{
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": ""
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"401": {
|
||||
"description": ""
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"403": {
|
||||
"description": ""
|
||||
"description": "Forbidden"
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
"description": "Not Found"
|
||||
},
|
||||
"409": {
|
||||
"description": ""
|
||||
"description": "Conflict"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1609,11 +1657,6 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expire_time": {
|
||||
@@ -1636,8 +1679,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1697,11 +1738,6 @@ var doc = `{
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -1721,8 +1757,6 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2128,22 +2162,12 @@ var doc = `{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
@@ -2169,13 +2193,9 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6506,7 +6526,11 @@ var doc = `{
|
||||
},
|
||||
"customer_info": {
|
||||
"description": "客户信息(仅在详情接口返回)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.CustomerInfoForAuthCode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"customer_name": {
|
||||
"description": "客户名称",
|
||||
@@ -6815,8 +6839,12 @@ var doc = `{
|
||||
"properties": {
|
||||
"new_authorization_code": {
|
||||
"description": "新生成的授权码信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationCodeShareResponseItem"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.AuthorizationCodeShareResponseItem": {
|
||||
@@ -7133,6 +7161,10 @@ var doc = `{
|
||||
"description": "订单过期时间",
|
||||
"type": "string"
|
||||
},
|
||||
"has_invoice_applied": {
|
||||
"description": "是否已申请发票(根据 invoices 表判断)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"description": "订单ID",
|
||||
"type": "string"
|
||||
@@ -7528,7 +7560,11 @@ var doc = `{
|
||||
},
|
||||
"authorization_stats": {
|
||||
"description": "授权统计信息(仅在详情接口返回)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationStats"
|
||||
}
|
||||
]
|
||||
},
|
||||
"company_size": {
|
||||
"type": "string"
|
||||
@@ -7853,11 +7889,19 @@ var doc = `{
|
||||
"properties": {
|
||||
"period": {
|
||||
"description": "时间段信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TrendPeriod"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"description": "汇总信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TrendSummary"
|
||||
}
|
||||
]
|
||||
},
|
||||
"trend_data": {
|
||||
"description": "趋势数据",
|
||||
@@ -7893,7 +7937,11 @@ var doc = `{
|
||||
},
|
||||
"authorization_info": {
|
||||
"description": "授权信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationInfo"
|
||||
}
|
||||
]
|
||||
},
|
||||
"device_info": {
|
||||
"description": "设备信息",
|
||||
@@ -8489,6 +8537,47 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.InvoiceUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"invoice_type",
|
||||
"receiver_email",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "开票内容,非必填,最多200字符",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
},
|
||||
"invoice_type": {
|
||||
"description": "发票类型,必填,personal-个人/enterprise-企业普票/vat_special-增值税专用发票",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"personal",
|
||||
"enterprise",
|
||||
"vat_special"
|
||||
]
|
||||
},
|
||||
"receiver_email": {
|
||||
"description": "收票邮箱,必填,格式为邮箱地址",
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"description": "备注,可选",
|
||||
"type": "string"
|
||||
},
|
||||
"taxpayer_id": {
|
||||
"description": "纳税人识别号,企业发票必填,个人发票可为空",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "发票抬头,必填,最多200字符",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.InvoiceUploadResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8717,7 +8806,11 @@ var doc = `{
|
||||
},
|
||||
"authorization_code": {
|
||||
"description": "关联字段(用于查询时的JOIN)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationCode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"authorization_code_id": {
|
||||
"type": "string"
|
||||
@@ -9303,7 +9396,11 @@ var doc = `{
|
||||
},
|
||||
"business_order": {
|
||||
"description": "关联的业务订单信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.PaymentBusinessOrder"
|
||||
}
|
||||
]
|
||||
},
|
||||
"payment_no": {
|
||||
"description": "支付单号",
|
||||
@@ -9418,7 +9515,11 @@ var doc = `{
|
||||
},
|
||||
"growth_rate": {
|
||||
"description": "增长率(同比上月)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.GrowthRate"
|
||||
}
|
||||
]
|
||||
},
|
||||
"total_auth_codes": {
|
||||
"description": "总授权码数量(所有授权码的累计总数)",
|
||||
@@ -9512,6 +9613,7 @@ var doc = `{
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"BearerAuth": {
|
||||
"description": "Bearer token for authentication",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
@@ -9519,56 +9621,18 @@ var doc = `{
|
||||
}
|
||||
}`
|
||||
|
||||
type swaggerInfo struct {
|
||||
Version string
|
||||
Host string
|
||||
BasePath string
|
||||
Schemes []string
|
||||
Title string
|
||||
Description string
|
||||
}
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = swaggerInfo{
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "",
|
||||
BasePath: "/",
|
||||
Schemes: []string{"http", "https"},
|
||||
Title: "License Manager API",
|
||||
Description: "Bearer token for authentication",
|
||||
}
|
||||
|
||||
type s struct{}
|
||||
|
||||
func (s *s) ReadDoc() string {
|
||||
sInfo := SwaggerInfo
|
||||
sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
|
||||
|
||||
t, err := template.New("swagger_info").Funcs(template.FuncMap{
|
||||
"marshal": func(v interface{}) string {
|
||||
a, _ := json.Marshal(v)
|
||||
return string(a)
|
||||
},
|
||||
"escape": func(v interface{}) string {
|
||||
// escape tabs
|
||||
str := strings.Replace(v.(string), "\t", "\\t", -1)
|
||||
// replace " with \", and if that results in \\", replace that with \\\"
|
||||
str = strings.Replace(str, "\"", "\\\"", -1)
|
||||
return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1)
|
||||
},
|
||||
}).Parse(doc)
|
||||
if err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
var tpl bytes.Buffer
|
||||
if err := t.Execute(&tpl, sInfo); err != nil {
|
||||
return doc
|
||||
}
|
||||
|
||||
return tpl.String()
|
||||
Description: "软件授权管理平台API文档",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register("swagger", &s{})
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
],
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "Bearer token for authentication",
|
||||
"description": "软件授权管理平台API文档",
|
||||
"title": "License Manager API",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
@@ -726,11 +726,6 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -744,8 +739,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -901,6 +894,103 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "客户修改已被驳回的发票申请并重新提交",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"发票管理"
|
||||
],
|
||||
"summary": "客户修改发票申请",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "发票ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "发票修改请求",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.InvoiceUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.APIResponse"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"invoice_no": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "请求参数无效",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "未认证",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"403": {
|
||||
"description": "权限不足",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "发票不存在",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "服务器内部错误",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/cu/invoices/{id}/download": {
|
||||
@@ -1000,22 +1090,12 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
@@ -1041,13 +1121,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1209,11 +1285,6 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expire_time": {
|
||||
@@ -1236,8 +1307,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1295,11 +1364,6 @@
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"license_count": {
|
||||
@@ -1310,8 +1374,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1326,11 +1388,6 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"discount_description": {
|
||||
@@ -1350,8 +1407,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1532,19 +1587,19 @@
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": ""
|
||||
"description": "Bad Request"
|
||||
},
|
||||
"401": {
|
||||
"description": ""
|
||||
"description": "Unauthorized"
|
||||
},
|
||||
"403": {
|
||||
"description": ""
|
||||
"description": "Forbidden"
|
||||
},
|
||||
"404": {
|
||||
"description": ""
|
||||
"description": "Not Found"
|
||||
},
|
||||
"409": {
|
||||
"description": ""
|
||||
"description": "Conflict"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1598,11 +1653,6 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"expire_time": {
|
||||
@@ -1625,8 +1675,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -1686,11 +1734,6 @@
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
@@ -1710,8 +1753,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2117,22 +2158,12 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
},
|
||||
"user": {
|
||||
"allOf": [
|
||||
{
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer_id": {
|
||||
@@ -2158,13 +2189,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6495,7 +6522,11 @@
|
||||
},
|
||||
"customer_info": {
|
||||
"description": "客户信息(仅在详情接口返回)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.CustomerInfoForAuthCode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"customer_name": {
|
||||
"description": "客户名称",
|
||||
@@ -6804,8 +6835,12 @@
|
||||
"properties": {
|
||||
"new_authorization_code": {
|
||||
"description": "新生成的授权码信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationCodeShareResponseItem"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.AuthorizationCodeShareResponseItem": {
|
||||
@@ -7122,6 +7157,10 @@
|
||||
"description": "订单过期时间",
|
||||
"type": "string"
|
||||
},
|
||||
"has_invoice_applied": {
|
||||
"description": "是否已申请发票(根据 invoices 表判断)",
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"description": "订单ID",
|
||||
"type": "string"
|
||||
@@ -7517,7 +7556,11 @@
|
||||
},
|
||||
"authorization_stats": {
|
||||
"description": "授权统计信息(仅在详情接口返回)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationStats"
|
||||
}
|
||||
]
|
||||
},
|
||||
"company_size": {
|
||||
"type": "string"
|
||||
@@ -7842,11 +7885,19 @@
|
||||
"properties": {
|
||||
"period": {
|
||||
"description": "时间段信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TrendPeriod"
|
||||
}
|
||||
]
|
||||
},
|
||||
"summary": {
|
||||
"description": "汇总信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.TrendSummary"
|
||||
}
|
||||
]
|
||||
},
|
||||
"trend_data": {
|
||||
"description": "趋势数据",
|
||||
@@ -7882,7 +7933,11 @@
|
||||
},
|
||||
"authorization_info": {
|
||||
"description": "授权信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationInfo"
|
||||
}
|
||||
]
|
||||
},
|
||||
"device_info": {
|
||||
"description": "设备信息",
|
||||
@@ -8478,6 +8533,47 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.InvoiceUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"invoice_type",
|
||||
"receiver_email",
|
||||
"title"
|
||||
],
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "开票内容,非必填,最多200字符",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
},
|
||||
"invoice_type": {
|
||||
"description": "发票类型,必填,personal-个人/enterprise-企业普票/vat_special-增值税专用发票",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"personal",
|
||||
"enterprise",
|
||||
"vat_special"
|
||||
]
|
||||
},
|
||||
"receiver_email": {
|
||||
"description": "收票邮箱,必填,格式为邮箱地址",
|
||||
"type": "string"
|
||||
},
|
||||
"remark": {
|
||||
"description": "备注,可选",
|
||||
"type": "string"
|
||||
},
|
||||
"taxpayer_id": {
|
||||
"description": "纳税人识别号,企业发票必填,个人发票可为空",
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"description": "发票抬头,必填,最多200字符",
|
||||
"type": "string",
|
||||
"maxLength": 200
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.InvoiceUploadResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -8706,7 +8802,11 @@
|
||||
},
|
||||
"authorization_code": {
|
||||
"description": "关联字段(用于查询时的JOIN)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.AuthorizationCode"
|
||||
}
|
||||
]
|
||||
},
|
||||
"authorization_code_id": {
|
||||
"type": "string"
|
||||
@@ -9292,7 +9392,11 @@
|
||||
},
|
||||
"business_order": {
|
||||
"description": "关联的业务订单信息",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.PaymentBusinessOrder"
|
||||
}
|
||||
]
|
||||
},
|
||||
"payment_no": {
|
||||
"description": "支付单号",
|
||||
@@ -9407,7 +9511,11 @@
|
||||
},
|
||||
"growth_rate": {
|
||||
"description": "增长率(同比上月)",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/models.GrowthRate"
|
||||
}
|
||||
]
|
||||
},
|
||||
"total_auth_codes": {
|
||||
"description": "总授权码数量(所有授权码的累计总数)",
|
||||
@@ -9501,6 +9609,7 @@
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"BearerAuth": {
|
||||
"description": "Bearer token for authentication",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
|
||||
@@ -109,7 +109,8 @@ definitions:
|
||||
description: 客户ID
|
||||
type: string
|
||||
customer_info:
|
||||
$ref: '#/definitions/models.CustomerInfoForAuthCode'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.CustomerInfoForAuthCode'
|
||||
description: 客户信息(仅在详情接口返回)
|
||||
customer_name:
|
||||
description: 客户名称
|
||||
@@ -337,7 +338,8 @@ definitions:
|
||||
models.AuthorizationCodeShareResponse:
|
||||
properties:
|
||||
new_authorization_code:
|
||||
$ref: '#/definitions/models.AuthorizationCodeShareResponseItem'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.AuthorizationCodeShareResponseItem'
|
||||
description: 新生成的授权码信息
|
||||
type: object
|
||||
models.AuthorizationCodeShareResponseItem:
|
||||
@@ -567,6 +569,9 @@ definitions:
|
||||
expired_at:
|
||||
description: 订单过期时间
|
||||
type: string
|
||||
has_invoice_applied:
|
||||
description: 是否已申请发票(根据 invoices 表判断)
|
||||
type: boolean
|
||||
id:
|
||||
description: 订单ID
|
||||
type: string
|
||||
@@ -860,7 +865,8 @@ definitions:
|
||||
address:
|
||||
type: string
|
||||
authorization_stats:
|
||||
$ref: '#/definitions/models.AuthorizationStats'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.AuthorizationStats'
|
||||
description: 授权统计信息(仅在详情接口返回)
|
||||
company_size:
|
||||
type: string
|
||||
@@ -1094,10 +1100,12 @@ definitions:
|
||||
models.DashboardAuthorizationTrendResponse:
|
||||
properties:
|
||||
period:
|
||||
$ref: '#/definitions/models.TrendPeriod'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.TrendPeriod'
|
||||
description: 时间段信息
|
||||
summary:
|
||||
$ref: '#/definitions/models.TrendSummary'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.TrendSummary'
|
||||
description: 汇总信息
|
||||
trend_data:
|
||||
description: 趋势数据
|
||||
@@ -1122,7 +1130,8 @@ definitions:
|
||||
description: 激活时间
|
||||
type: string
|
||||
authorization_info:
|
||||
$ref: '#/definitions/models.AuthorizationInfo'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.AuthorizationInfo'
|
||||
description: 授权信息
|
||||
device_info:
|
||||
additionalProperties: true
|
||||
@@ -1556,6 +1565,37 @@ definitions:
|
||||
description: 发票总数
|
||||
type: integer
|
||||
type: object
|
||||
models.InvoiceUpdateRequest:
|
||||
properties:
|
||||
content:
|
||||
description: 开票内容,非必填,最多200字符
|
||||
maxLength: 200
|
||||
type: string
|
||||
invoice_type:
|
||||
description: 发票类型,必填,personal-个人/enterprise-企业普票/vat_special-增值税专用发票
|
||||
enum:
|
||||
- personal
|
||||
- enterprise
|
||||
- vat_special
|
||||
type: string
|
||||
receiver_email:
|
||||
description: 收票邮箱,必填,格式为邮箱地址
|
||||
type: string
|
||||
remark:
|
||||
description: 备注,可选
|
||||
type: string
|
||||
taxpayer_id:
|
||||
description: 纳税人识别号,企业发票必填,个人发票可为空
|
||||
type: string
|
||||
title:
|
||||
description: 发票抬头,必填,最多200字符
|
||||
maxLength: 200
|
||||
type: string
|
||||
required:
|
||||
- invoice_type
|
||||
- receiver_email
|
||||
- title
|
||||
type: object
|
||||
models.InvoiceUploadResponse:
|
||||
properties:
|
||||
file_url:
|
||||
@@ -1725,7 +1765,8 @@ definitions:
|
||||
activation_ip:
|
||||
type: string
|
||||
authorization_code:
|
||||
$ref: '#/definitions/models.AuthorizationCode'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.AuthorizationCode'
|
||||
description: 关联字段(用于查询时的JOIN)
|
||||
authorization_code_id:
|
||||
type: string
|
||||
@@ -2139,7 +2180,8 @@ definitions:
|
||||
description: 支付金额,单位元
|
||||
type: number
|
||||
business_order:
|
||||
$ref: '#/definitions/models.PaymentBusinessOrder'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.PaymentBusinessOrder'
|
||||
description: 关联的业务订单信息
|
||||
payment_no:
|
||||
description: 支付单号
|
||||
@@ -2222,7 +2264,8 @@ definitions:
|
||||
description: 即将过期数量(30天内即将过期的授权码,且未被锁定)
|
||||
type: integer
|
||||
growth_rate:
|
||||
$ref: '#/definitions/models.GrowthRate'
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.GrowthRate'
|
||||
description: 增长率(同比上月)
|
||||
total_auth_codes:
|
||||
description: 总授权码数量(所有授权码的累计总数)
|
||||
@@ -2291,7 +2334,7 @@ info:
|
||||
email: support@swagger.io
|
||||
name: API Support
|
||||
url: http://www.swagger.io/support
|
||||
description: Bearer token for authentication
|
||||
description: 软件授权管理平台API文档
|
||||
license:
|
||||
name: MIT
|
||||
url: https://opensource.org/licenses/MIT
|
||||
@@ -2730,9 +2773,7 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
invoice_no:
|
||||
@@ -2806,6 +2847,66 @@ paths:
|
||||
summary: 客户发票详情
|
||||
tags:
|
||||
- 发票管理
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 客户修改已被驳回的发票申请并重新提交
|
||||
parameters:
|
||||
- description: 发票ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
- description: 发票修改请求
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.InvoiceUpdateRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: 成功
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
invoice_no:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
"400":
|
||||
description: 请求参数无效
|
||||
schema:
|
||||
$ref: '#/definitions/models.ErrorResponse'
|
||||
"401":
|
||||
description: 未认证
|
||||
schema:
|
||||
$ref: '#/definitions/models.ErrorResponse'
|
||||
"403":
|
||||
description: 权限不足
|
||||
schema:
|
||||
$ref: '#/definitions/models.ErrorResponse'
|
||||
"404":
|
||||
description: 发票不存在
|
||||
schema:
|
||||
$ref: '#/definitions/models.ErrorResponse'
|
||||
"500":
|
||||
description: 服务器内部错误
|
||||
schema:
|
||||
$ref: '#/definitions/models.ErrorResponse'
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 客户修改发票申请
|
||||
tags:
|
||||
- 发票管理
|
||||
/api/cu/invoices/{id}/download:
|
||||
get:
|
||||
consumes:
|
||||
@@ -2897,15 +2998,11 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
user:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
customer_id:
|
||||
type: string
|
||||
email:
|
||||
@@ -3021,9 +3118,7 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
expire_time:
|
||||
type: string
|
||||
id:
|
||||
@@ -3118,15 +3213,15 @@ paths:
|
||||
schema:
|
||||
$ref: '#/definitions/models.APIResponse'
|
||||
"400":
|
||||
description: ""
|
||||
description: Bad Request
|
||||
"401":
|
||||
description: ""
|
||||
description: Unauthorized
|
||||
"403":
|
||||
description: ""
|
||||
description: Forbidden
|
||||
"404":
|
||||
description: ""
|
||||
description: Not Found
|
||||
"409":
|
||||
description: ""
|
||||
description: Conflict
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 删除订单
|
||||
@@ -3160,9 +3255,7 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
expire_time:
|
||||
type: string
|
||||
order_id:
|
||||
@@ -3209,9 +3302,7 @@ paths:
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
license_count:
|
||||
type: integer
|
||||
package_id:
|
||||
@@ -3227,9 +3318,7 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
discount_description:
|
||||
type: string
|
||||
discount_rate:
|
||||
@@ -3305,9 +3394,7 @@ paths:
|
||||
- properties:
|
||||
data:
|
||||
items:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
max_devices:
|
||||
@@ -3572,15 +3659,11 @@ paths:
|
||||
- $ref: '#/definitions/models.APIResponse'
|
||||
- properties:
|
||||
data:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
user:
|
||||
allOf:
|
||||
- type: object
|
||||
- properties:
|
||||
properties:
|
||||
customer_id:
|
||||
type: string
|
||||
email:
|
||||
@@ -6196,6 +6279,7 @@ schemes:
|
||||
- https
|
||||
securityDefinitions:
|
||||
BearerAuth:
|
||||
description: Bearer token for authentication
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
|
||||
@@ -200,3 +200,54 @@ func (h *CuInvoiceHandler) DownloadInvoice(c *gin.Context) {
|
||||
// 重定向到文件URL
|
||||
c.Redirect(http.StatusFound, fileURL)
|
||||
}
|
||||
|
||||
// UpdateInvoice 客户修改发票申请
|
||||
// @Summary 客户修改发票申请
|
||||
// @Description 客户修改已被驳回的发票申请并重新提交
|
||||
// @Tags 发票管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path string true "发票ID"
|
||||
// @Param request body models.InvoiceUpdateRequest true "发票修改请求"
|
||||
// @Success 200 {object} models.APIResponse{data=object{id=string,invoice_no=string,status=string}} "成功"
|
||||
// @Failure 400 {object} models.ErrorResponse "请求参数无效"
|
||||
// @Failure 401 {object} models.ErrorResponse "未认证"
|
||||
// @Failure 403 {object} models.ErrorResponse "权限不足"
|
||||
// @Failure 404 {object} models.ErrorResponse "发票不存在"
|
||||
// @Failure 500 {object} models.ErrorResponse "服务器内部错误"
|
||||
// @Router /api/cu/invoices/{id} [put]
|
||||
func (h *CuInvoiceHandler) UpdateInvoice(c *gin.Context) {
|
||||
lang := middleware.GetLanguage(c)
|
||||
invoiceID := c.Param("id")
|
||||
|
||||
var req models.InvoiceUpdateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, models.ErrorResponse{
|
||||
Code: "900001",
|
||||
Message: i18n.GetI18nErrorMessage("900001", lang),
|
||||
Timestamp: getCurrentTimestamp(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
invoice, err := h.invoiceService.UpdateInvoice(c.Request.Context(), invoiceID, getCuUserID(c), &req)
|
||||
if err != nil {
|
||||
handleI18nError(c, err, lang)
|
||||
return
|
||||
}
|
||||
|
||||
response := invoice.ToResponse()
|
||||
result := map[string]interface{}{
|
||||
"id": response.ID,
|
||||
"invoice_no": response.InvoiceNo,
|
||||
"status": response.Status,
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, models.APIResponse{
|
||||
Code: "000000",
|
||||
Message: i18n.GetI18nErrorMessage("000000", lang),
|
||||
Data: result,
|
||||
Timestamp: getCurrentTimestamp(),
|
||||
})
|
||||
}
|
||||
@@ -288,6 +288,7 @@ func SetupRouter() *gin.Engine {
|
||||
cuAuth.POST("/invoices", cuInvoiceHandler.CreateInvoice)
|
||||
cuAuth.GET("/invoices", cuInvoiceHandler.GetUserInvoices)
|
||||
cuAuth.GET("/invoices/:id", cuInvoiceHandler.GetUserInvoiceDetail)
|
||||
cuAuth.PUT("/invoices/:id", cuInvoiceHandler.UpdateInvoice)
|
||||
cuAuth.GET("/invoices/summary", cuInvoiceHandler.GetUserInvoiceSummary)
|
||||
cuAuth.GET("/invoices/:id/download", cuInvoiceHandler.DownloadInvoice)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,16 @@ type InvoiceCreateRequest struct {
|
||||
Remark *string `json:"remark,omitempty"` // 备注,可选
|
||||
}
|
||||
|
||||
// InvoiceUpdateRequest 客户端修改发票请求结构
|
||||
type InvoiceUpdateRequest struct {
|
||||
InvoiceType string `json:"invoice_type" binding:"required,oneof=personal enterprise vat_special"` // 发票类型,必填,personal-个人/enterprise-企业普票/vat_special-增值税专用发票
|
||||
ReceiverEmail string `json:"receiver_email" binding:"required,email"` // 收票邮箱,必填,格式为邮箱地址
|
||||
Title string `json:"title" binding:"required,max=200"` // 发票抬头,必填,最多200字符
|
||||
TaxpayerID *string `json:"taxpayer_id,omitempty"` // 纳税人识别号,企业发票必填,个人发票可为空
|
||||
Content string `json:"content" binding:"omitempty,max=200"` // 开票内容,非必填,最多200字符
|
||||
Remark *string `json:"remark,omitempty"` // 备注,可选
|
||||
}
|
||||
|
||||
// InvoiceListRequest 发票列表查询请求结构
|
||||
// 注:apply_date 支持 YYYY-MM-DD 或 RFC3339 时间范围 "start,end"。
|
||||
type InvoiceListRequest struct {
|
||||
|
||||
@@ -17,6 +17,7 @@ type CuInvoiceRepository interface {
|
||||
|
||||
// ========== 通用工具方法 ==========
|
||||
Create(invoice *models.Invoice) error
|
||||
Update(invoice *models.Invoice) error
|
||||
GetByID(id string) (*models.Invoice, error)
|
||||
CheckOrderInvoiceExists(orderID string) (bool, error)
|
||||
}
|
||||
@@ -33,6 +34,12 @@ func (r *cuInvoiceRepository) Create(invoice *models.Invoice) error {
|
||||
return r.db.Create(invoice).Error
|
||||
}
|
||||
|
||||
func (r *cuInvoiceRepository) Update(invoice *models.Invoice) error {
|
||||
// 使用 Select 指定更新字段,确保可以清空某些字段(虽然此处目前主要是业务更新和状态重置)
|
||||
// 或者直接使用 Save 更新全量字段
|
||||
return r.db.Save(invoice).Error
|
||||
}
|
||||
|
||||
func (r *cuInvoiceRepository) GetByID(id string) (*models.Invoice, error) {
|
||||
var invoice models.Invoice
|
||||
err := r.db.Where("id = ? AND deleted_at IS NULL", id).First(&invoice).Error
|
||||
|
||||
@@ -21,6 +21,7 @@ type CuInvoiceService interface {
|
||||
GetUserInvoices(ctx context.Context, cuUserID string, req *models.InvoiceListRequest) (*models.InvoiceListResponse, error)
|
||||
GetInvoiceSummary(ctx context.Context, cuUserID string) (*models.InvoiceSummaryResponse, error)
|
||||
DownloadInvoice(ctx context.Context, invoiceID, cuUserID string) (string, error)
|
||||
UpdateInvoice(ctx context.Context, invoiceID, cuUserID string, req *models.InvoiceUpdateRequest) (*models.Invoice, error)
|
||||
}
|
||||
|
||||
type cuInvoiceService struct {
|
||||
@@ -175,6 +176,54 @@ func (s *cuInvoiceService) DownloadInvoice(ctx context.Context, invoiceID, cuUse
|
||||
return *invoice.InvoiceFileURL, nil
|
||||
}
|
||||
|
||||
func (s *cuInvoiceService) UpdateInvoice(ctx context.Context, invoiceID, cuUserID string, req *models.InvoiceUpdateRequest) (*models.Invoice, error) {
|
||||
lang := pkgcontext.GetLanguageFromContext(ctx)
|
||||
|
||||
// 获取原发票
|
||||
invoice, err := s.repo.GetByID(invoiceID)
|
||||
if err != nil {
|
||||
return nil, i18n.NewI18nError("700001", lang)
|
||||
}
|
||||
|
||||
// 权限校验
|
||||
if invoice.CuUserID != cuUserID {
|
||||
return nil, i18n.NewI18nError("700001", lang)
|
||||
}
|
||||
|
||||
// 状态校验:只有被驳回的发票可以修改
|
||||
if invoice.Status != models.InvoiceStatusRejected {
|
||||
return nil, i18n.NewI18nError("700004", lang)
|
||||
}
|
||||
|
||||
// 业务逻辑校验:发票类型和纳税人识别号
|
||||
if req.InvoiceType != models.InvoiceTypePersonal && (req.TaxpayerID == nil || *req.TaxpayerID == "") {
|
||||
return nil, i18n.NewI18nError("700004", lang)
|
||||
}
|
||||
|
||||
// 更新字段
|
||||
invoice.InvoiceType = req.InvoiceType
|
||||
invoice.Title = req.Title
|
||||
invoice.TaxpayerID = req.TaxpayerID
|
||||
invoice.Content = req.Content
|
||||
invoice.ReceiverEmail = req.ReceiverEmail
|
||||
invoice.Remark = req.Remark
|
||||
|
||||
// 重置状态和驳回信息
|
||||
invoice.Status = models.InvoiceStatusPending
|
||||
invoice.RejectReason = nil
|
||||
invoice.Suggestion = nil
|
||||
invoice.RejectedAt = nil
|
||||
invoice.RejectedBy = nil
|
||||
|
||||
// 更新数据库
|
||||
err = s.repo.Update(invoice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return invoice, nil
|
||||
}
|
||||
|
||||
// ========== 私有辅助方法 ==========
|
||||
|
||||
// fillDisplayFields 填充响应结构的多语言显示字段
|
||||
|
||||
Reference in new issue
Block a user