feat(backend): 出入库编码搜索双路匹配+建单填快照;finance 趋势/日期区间;partner/product 拼音搜索
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JJ1g8XV1YhhmHRzhwWEW7o
This commit is contained in:
@@ -2,6 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -25,10 +26,13 @@ func (h *FinanceHandler) ListRecords(c *gin.Context) {
|
||||
shopID := middleware.GetShopID(c)
|
||||
|
||||
var q struct {
|
||||
Type string `form:"type"`
|
||||
Month string `form:"month"` // e.g. "2026-04"
|
||||
Page int `form:"page,default=1"`
|
||||
PageSize int `form:"page_size,default=50"`
|
||||
Type string `form:"type"`
|
||||
Month string `form:"month"` // e.g. "2026-04"
|
||||
StartDate string `form:"start_date"` // YYYY-MM-DD(区间过滤,优先于 month)
|
||||
EndDate string `form:"end_date"`
|
||||
PartnerID uint64 `form:"partner_id"`
|
||||
Page int `form:"page,default=1"`
|
||||
PageSize int `form:"page_size,default=50"`
|
||||
}
|
||||
if err := c.ShouldBindQuery(&q); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
@@ -43,7 +47,18 @@ func (h *FinanceHandler) ListRecords(c *gin.Context) {
|
||||
if q.Type != "" {
|
||||
base = base.Where("type = ?", q.Type)
|
||||
}
|
||||
if q.Month != "" {
|
||||
if q.PartnerID != 0 {
|
||||
base = base.Where("partner_id = ?", q.PartnerID)
|
||||
}
|
||||
// 日期过滤:区间(本季/自定义)优先;否则按单月。日期串比较跨 MySQL/SQLite 可移植。
|
||||
if q.StartDate != "" || q.EndDate != "" {
|
||||
if q.StartDate != "" {
|
||||
base = base.Where("record_date >= ?", q.StartDate)
|
||||
}
|
||||
if q.EndDate != "" {
|
||||
base = base.Where("record_date <= ?", q.EndDate)
|
||||
}
|
||||
} else if q.Month != "" {
|
||||
base = base.Where("DATE_FORMAT(record_date, '%Y-%m') = ?", q.Month)
|
||||
}
|
||||
|
||||
@@ -161,6 +176,47 @@ func (h *FinanceHandler) CloseByRef(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true})
|
||||
}
|
||||
|
||||
// Trend GET /api/v1/finance/trend?months=6 — 近 N 个自然月收支趋势
|
||||
// in=当月出库(销售)额、out=当月入库(采购)额;与 stock Summary 同口径
|
||||
// (按 order_date、不筛状态、deleted_at IS NULL),日期串比较跨 MySQL/SQLite 可移植。
|
||||
func (h *FinanceHandler) Trend(c *gin.Context) {
|
||||
shopID := middleware.GetShopID(c)
|
||||
months := 6
|
||||
if v := c.Query("months"); v != "" {
|
||||
if n, err := strconv.Atoi(v); err == nil && n >= 1 && n <= 24 {
|
||||
months = n
|
||||
}
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
first := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
||||
type point struct {
|
||||
Month string `json:"month"`
|
||||
In float64 `json:"in"`
|
||||
Out float64 `json:"out"`
|
||||
}
|
||||
sum := func(table, from, to string) float64 {
|
||||
var v float64
|
||||
h.db.Table(table).
|
||||
Where("shop_id = ? AND deleted_at IS NULL AND order_date >= ? AND order_date < ?",
|
||||
shopID, from, to).
|
||||
Select("COALESCE(SUM(total_amount),0)").Scan(&v)
|
||||
return v
|
||||
}
|
||||
const f = "2006-01-02"
|
||||
points := make([]point, 0, months)
|
||||
for i := months - 1; i >= 0; i-- {
|
||||
mStart := first.AddDate(0, -i, 0)
|
||||
mEnd := mStart.AddDate(0, 1, 0)
|
||||
points = append(points, point{
|
||||
Month: mStart.Format("2006-01"),
|
||||
In: sum("stock_out_orders", mStart.Format(f), mEnd.Format(f)),
|
||||
Out: sum("stock_in_orders", mStart.Format(f), mEnd.Format(f)),
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"data": points})
|
||||
}
|
||||
|
||||
// Summary GET /api/v1/finance/summary — 按往来单位汇总未结清
|
||||
func (h *FinanceHandler) Summary(c *gin.Context) {
|
||||
shopID := middleware.GetShopID(c)
|
||||
|
||||
Reference in New Issue
Block a user