189 lines
6.1 KiB
Go
189 lines
6.1 KiB
Go
package controllers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"server/models"
|
|
"server/pkg/jwtutil"
|
|
"server/services/payment"
|
|
|
|
beego "github.com/beego/beego/v2/server/web"
|
|
)
|
|
|
|
// PlatformPaymentReconcileController 平台端对账管理(差异列表 / 标记处理 / 账单导入 / 执行对账)
|
|
type PlatformPaymentReconcileController struct {
|
|
beego.Controller
|
|
}
|
|
|
|
func (c *PlatformPaymentReconcileController) platformClaims() (*jwtutil.Claims, error) {
|
|
return paymentPlatformClaims(&c.Controller)
|
|
}
|
|
|
|
func (c *PlatformPaymentReconcileController) jsonErr(httpStatus, bizCode int, msg string) {
|
|
c.Ctx.Output.SetStatus(httpStatus)
|
|
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
|
|
_ = c.ServeJSON()
|
|
}
|
|
|
|
func (c *PlatformPaymentReconcileController) ok(data interface{}) {
|
|
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
|
|
_ = c.ServeJSON()
|
|
}
|
|
|
|
func reconcileDiffDTO(row *models.PlatformPaymentReconcileDiff) map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"id": row.ID, "channel": row.Channel, "bill_date": row.BillDate,
|
|
"batch_no": row.BatchNo, "local_trade_no": row.LocalTradeNo, "channel_trade_no": row.ChannelTradeNo,
|
|
"local_amount": row.LocalAmount, "channel_amount": row.ChannelAmount, "diff_amount": row.DiffAmount,
|
|
"diff_type": row.DiffType, "handle_status": row.HandleStatus,
|
|
"handle_user_id": row.HandleUserID, "handle_user_name": row.HandleUserName,
|
|
"handle_time": row.HandleTime, "remark": row.Remark,
|
|
"create_time": row.CreateTime, "update_time": row.UpdateTime,
|
|
}
|
|
}
|
|
|
|
// ListReconcile GET /platform/payment/reconcile 对账差异列表
|
|
func (c *PlatformPaymentReconcileController) ListReconcile() {
|
|
if _, err := c.platformClaims(); err != nil {
|
|
c.jsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
page, _ := strconv.Atoi(c.GetString("page", "1"))
|
|
pageSize, _ := strconv.Atoi(c.GetString("pageSize", "10"))
|
|
rows, total, err := payment.ListReconcileDiffs(payment.ReconcileListInput{
|
|
Channel: strings.TrimSpace(c.GetString("channel")),
|
|
BillDate: strings.TrimSpace(c.GetString("bill_date")),
|
|
DiffType: strings.TrimSpace(c.GetString("diff_type")),
|
|
HandleStatus: strings.TrimSpace(c.GetString("handle_status")),
|
|
Page: page,
|
|
PageSize: pageSize,
|
|
})
|
|
if err != nil {
|
|
c.jsonErr(500, 500, "查询失败: "+err.Error())
|
|
return
|
|
}
|
|
if rows == nil {
|
|
rows = []models.PlatformPaymentReconcileDiff{}
|
|
}
|
|
list := make([]map[string]interface{}, 0, len(rows))
|
|
for i := range rows {
|
|
list = append(list, reconcileDiffDTO(&rows[i]))
|
|
}
|
|
c.ok(map[string]interface{}{"list": list, "total": total, "page": page, "pageSize": pageSize})
|
|
}
|
|
|
|
// HandleReconcile POST /platform/payment/reconcile/:id/handle 标记差异处理
|
|
func (c *PlatformPaymentReconcileController) HandleReconcile() {
|
|
claims, err := c.platformClaims()
|
|
if err != nil {
|
|
c.jsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
|
if err != nil || id == 0 {
|
|
c.jsonErr(400, 400, "无效ID")
|
|
return
|
|
}
|
|
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
var p struct {
|
|
HandleStatus string `json:"handle_status"`
|
|
Remark string `json:"remark"`
|
|
}
|
|
if err := json.Unmarshal(body, &p); err != nil {
|
|
c.jsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
row, err := payment.MarkDiffHandled(context.Background(), payment.MarkDiffHandledInput{
|
|
ID: id, HandleStatus: strings.TrimSpace(p.HandleStatus), Remark: strings.TrimSpace(p.Remark),
|
|
OperatorID: fmt.Sprintf("%d", claims.UserID), OperatorName: claims.Username,
|
|
})
|
|
if err != nil {
|
|
c.jsonErr(400, 400, err.Error())
|
|
return
|
|
}
|
|
c.ok(reconcileDiffDTO(row))
|
|
}
|
|
|
|
// RunReconcile POST /platform/payment/reconcile/run 执行对账比对
|
|
func (c *PlatformPaymentReconcileController) RunReconcile() {
|
|
if _, err := c.platformClaims(); err != nil {
|
|
c.jsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
var p struct {
|
|
Channel string `json:"channel"`
|
|
BillDate string `json:"bill_date"`
|
|
}
|
|
if err := json.Unmarshal(body, &p); err != nil {
|
|
c.jsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
|
|
defer cancel()
|
|
summary, err := payment.RunReconcile(ctx, strings.TrimSpace(p.Channel), strings.TrimSpace(p.BillDate))
|
|
if err != nil {
|
|
c.jsonErr(400, 400, err.Error())
|
|
return
|
|
}
|
|
c.ok(summary)
|
|
}
|
|
|
|
// ImportBill POST /platform/payment/reconcile/import 导入渠道账单
|
|
// 两种方式:multipart 上传 CSV(字段 file + channel + bill_date),或 JSON {channel, bill_date, rows:[...]}
|
|
func (c *PlatformPaymentReconcileController) ImportBill() {
|
|
if _, err := c.platformClaims(); err != nil {
|
|
c.jsonErr(401, 401, err.Error())
|
|
return
|
|
}
|
|
var channel, billDate string
|
|
var rows []payment.BillRow
|
|
|
|
contentType := c.Ctx.Request.Header.Get("Content-Type")
|
|
if strings.Contains(contentType, "multipart/form-data") {
|
|
channel = strings.TrimSpace(c.GetString("channel"))
|
|
billDate = strings.TrimSpace(c.GetString("bill_date"))
|
|
file, header, ferr := c.GetFile("file")
|
|
if ferr != nil || header == nil {
|
|
c.jsonErr(400, 400, "请选择账单文件")
|
|
return
|
|
}
|
|
defer func() { _ = file.Close() }()
|
|
data, rerr := io.ReadAll(file)
|
|
if rerr != nil {
|
|
c.jsonErr(400, 400, "读取账单文件失败: "+rerr.Error())
|
|
return
|
|
}
|
|
rows, _ = payment.ParseChannelBillCSV(data)
|
|
} else {
|
|
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
|
var p struct {
|
|
Channel string `json:"channel"`
|
|
BillDate string `json:"bill_date"`
|
|
Rows []payment.BillRow `json:"rows"`
|
|
}
|
|
if err := json.Unmarshal(body, &p); err != nil {
|
|
c.jsonErr(400, 400, "参数错误")
|
|
return
|
|
}
|
|
channel, billDate, rows = strings.TrimSpace(p.Channel), strings.TrimSpace(p.BillDate), p.Rows
|
|
}
|
|
|
|
if channel == "" || billDate == "" {
|
|
c.jsonErr(400, 400, "channel 与 bill_date 不能为空")
|
|
return
|
|
}
|
|
imported, err := payment.ImportChannelBill(context.Background(), channel, billDate, rows)
|
|
if err != nil {
|
|
c.jsonErr(400, 400, err.Error())
|
|
return
|
|
}
|
|
c.ok(map[string]interface{}{"imported": imported, "channel": channel, "bill_date": billDate})
|
|
}
|