zhangqian
2024-07-01 fe794b385cc1fe28cb6d0731664a3023199843ac
增加月度统计出入库按类型汇总报表查询接口
2个文件已添加
6个文件已修改
544 ■■■■■ 已修改文件
controllers/report_forms_controller.go 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/month_stats.go 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/operation.go 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/operation_details.go 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/warehouse_month_stats.go 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
request/report_forms_request.go 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
router/router.go 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
service/warehouse_month_forms.go 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
controllers/report_forms_controller.go
@@ -437,3 +437,71 @@
    task.MonthStats()
    util.ResponseFormat(c, code.Success, nil)
}
// WarehouseMonthStats
// @Tags      报表
// @Summary   仓库月度统计库存报表
// @Produce   application/json
// @Param     object  body  request.GetMonthStats true  "查询参数"
// @Param     Authorization    header string true "token"
// @Success   200 {object} util.ResponseList{data=[]models.MonthStats}    "成功"
// @Router    /api-wms/v1/forms/warehouseMonthStats [post]
func (slf ReportFormsController) WarehouseMonthStats(c *gin.Context) {
    var params request.GetMonthStats
    if err := c.BindJSON(&params); err != nil {
        util.ResponseFormat(c, code.RequestParamError, "参数解析失败,数据类型错误")
        return
    }
    if params.WarehouseID == 0 {
        util.ResponseFormat(c, code.RequestParamError, "仓库ID参数缺失")
        return
    }
    monthFormsService := service.NewWarehouseMonthFormsService()
    total, err := monthFormsService.Count(params)
    if err != nil {
        logx.Errorf("MonthStats count err:%v", err)
        util.ResponseFormat(c, code.InternalError, "查询总数失败")
        return
    }
    result, err := monthFormsService.Query(params)
    if err != nil {
        logx.Errorf("MonthStats query err:%v", err)
        util.ResponseFormat(c, code.InternalError, "查询失败")
        return
    }
    now := time.Now().Local()
    today := now.Day()
    nowMonth := now.Format("2006-01")
    day, dateStr, _ := service.NewSystemConfigService().GetInventoryCutOffPoint()
    if nowMonth == params.Date && today < day || today == day && now.Format("15:04") < dateStr { //本月未至结算时间点
        productIds := make([]string, 0, len(result))
        for _, item := range result {
            productIds = append(productIds, item.ProductId)
        }
        statsRecords, err := service.GetCurrentWarehouseStats(params.Date, params.WarehouseID, productIds)
        if err != nil {
            util.ResponseFormat(c, code.InternalError, "内部错误")
            return
        }
        statsMap := models.WarehouseMonthStatsMap(statsRecords)
        for k, v := range result {
            if statsMap[v.ProductId] == nil {
                continue
            }
            result[k].OutputAmount = statsMap[v.ProductId].OutputAmount
            result[k].EndAmount = statsMap[v.ProductId].EndAmount
            result[k].InputAmount = statsMap[v.ProductId].InputAmount
            result[k].InputItems = statsMap[v.ProductId].InputItems
            result[k].OutputItems = statsMap[v.ProductId].OutputItems
        }
    }
    util.ResponseFormatList(c, code.Success, result, int(total))
}
models/month_stats.go
@@ -9,7 +9,7 @@
)
type (
    // MonthStats 移动历史
    // MonthStats 月度统计
    MonthStats struct {
        WmsModel
        Id          int    `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
models/operation.go
@@ -196,6 +196,11 @@
    return slf
}
func (slf *OperationSearch) SetWarehouseId(warehouseId int) *OperationSearch {
    slf.WarehouseId = warehouseId
    return slf
}
func (slf *OperationSearch) build() *gorm.DB {
    var db = slf.Orm.Model(&Operation{})
@@ -277,6 +282,10 @@
        db = db.Where("inventory_dealer_type in (?)", slf.InventoryDealerTypeIds)
    }
    if slf.WarehouseId != 0 {
        db = db.Where("warehouse_id = ?", slf.WarehouseId)
    }
    return db
}
models/operation_details.go
@@ -29,6 +29,7 @@
        AuxiliaryUnit    string          `json:"auxiliaryUnit" gorm:"type:varchar(191);comment:辅助单位"`
        Remark           string          `gorm:"type:varchar(1024);comment:备注" json:"remark"`
        IsInternalOutput bool            `json:"isInternalOutput"` //是否调拨产生的出库
        DealerType       string          `json:"dealerType"`       //出入库类型
        Cost      decimal.Decimal `json:"cost" `      //成本单价
        SalePrice decimal.Decimal `json:"salePrice" ` //销售单价
@@ -312,3 +313,20 @@
    }
    return result, nil
}
type GroupByDealerTypeWarehouse struct {
    DealerType string
    ProductID  string
    Sum        decimal.Decimal
}
func (slf *OperationDetailsSearch) GroupMultiSumAmount() ([]*GroupByDealerTypeWarehouse, error) {
    var (
        db     = slf.build()
        result = make([]*GroupByDealerTypeWarehouse, 0)
    )
    if err := db.Select("sum(amount) as sum, dealer_type, product_id").Group("product_id, dealer_type").Scan(&result).Error; err != nil {
        return nil, fmt.Errorf("select group err: %v", err)
    }
    return result, nil
}
models/warehouse_month_stats.go
New file
@@ -0,0 +1,289 @@
package models
import (
    "fmt"
    "github.com/shopspring/decimal"
    "gorm.io/gorm"
    "wms/pkg/mysqlx"
)
type (
    // WarehouseMonthStats 按仓库进行月度统计
    WarehouseMonthStats struct {
        WmsModel
        Id          int             `json:"id" gorm:"column:id;primary_key;AUTO_INCREMENT"`
        WarehouseId int             `json:"warehouseId" gorm:"type:int;not null;default:0"`             //仓库ID
        ProductId   string          `json:"productId" gorm:"type:varchar(255);not null;comment:产品id"`   //产品id
        ProductName string          `json:"productName" gorm:"type:varchar(255);not null;comment:产品名称"` //产品名称
        Unit        string          `json:"unit" gorm:"type:char(10);not null;comment:单位"`              //单位
        SalePrice   decimal.Decimal `gorm:"type:decimal(35,18);comment:销售单价" json:"salePrice"`          //销售单价
        BeginAmount decimal.Decimal `json:"beginAmount" gorm:"type:decimal(30,10);not null;comment:数量"` //期初数量
        EndAmount   decimal.Decimal `json:"amount" gorm:"type:decimal(30,10);not null;comment:数量"`      //期末结余数量
        InputAmount decimal.Decimal        `json:"inputAmount" gorm:"type:decimal(30,10);not null;comment:数量"` //入库数量
        InputItems  []*WarehouseStatsItems `json:"inputMoreUnitsArr"`                                          //入库明细
        OutputAmount decimal.Decimal        `json:"outputAmount" gorm:"type:decimal(30,10);not null;comment:数量"` //出库数量
        OutputItems  []*WarehouseStatsItems `json:"outputMoreUnitsArr"`                                          //出库明细
        Date string `json:"date" gorm:"index;type:varchar(255); not null;default ''"` //日期 2024-04
    }
    WarehouseStatsItems struct {
        WarehouseMonthStatsId int             `json:"warehouseMonthStatsId"`
        Name                  string          `json:"name" gorm:"type:varchar(255);not null;default:''"` //入库来源,出库去处
        Amount                decimal.Decimal `json:"amount" gorm:"type:decimal(30,10);not null;"`       //数量
    }
    WarehouseMonthStatsSearch struct {
        WarehouseMonthStats
        Order    string
        PageNum  int
        PageSize int
        Keyword  string
        Orm      *gorm.DB
        Preload  bool
        Fields   string
    }
)
func (slf *WarehouseMonthStats) TableName() string {
    return "wms_month_stats"
}
func NewWarehouseMonthStatsSearch() *WarehouseMonthStatsSearch {
    return &WarehouseMonthStatsSearch{Orm: mysqlx.GetDB()}
}
func (slf *WarehouseMonthStatsSearch) SetOrm(tx *gorm.DB) *WarehouseMonthStatsSearch {
    slf.Orm = tx
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetPage(page, size int) *WarehouseMonthStatsSearch {
    slf.PageNum, slf.PageSize = page, size
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetOrder(order string) *WarehouseMonthStatsSearch {
    slf.Order = order
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetID(id int) *WarehouseMonthStatsSearch {
    slf.Id = id
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetKeyword(keyword string) *WarehouseMonthStatsSearch {
    slf.Keyword = keyword
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetPreload(preload bool) *WarehouseMonthStatsSearch {
    slf.Preload = preload
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetDate(date string) *WarehouseMonthStatsSearch {
    slf.Date = date
    return slf
}
func (slf *WarehouseMonthStatsSearch) SetFields(fields string) *WarehouseMonthStatsSearch {
    slf.Fields = fields
    return slf
}
func (slf *WarehouseMonthStatsSearch) build() *gorm.DB {
    var db = slf.Orm.Model(&WarehouseMonthStats{})
    if slf.Id != 0 {
        db = db.Where("id = ?", slf.Id)
    }
    if slf.Order != "" {
        db = db.Order(slf.Order)
    }
    if slf.Keyword != "" {
        kw := fmt.Sprintf("%%%v%%", slf.Keyword)
        db = db.Where("product_id like ? or product_name like ?", kw, kw)
    }
    if slf.Date != "" {
        db = db.Where("date = ?", slf.Date)
    }
    if slf.Fields != "" {
        db = db.Select(slf.Fields)
    }
    return db
}
// Create 单条插入
func (slf *WarehouseMonthStatsSearch) Create(record *WarehouseMonthStats) error {
    var db = slf.build()
    if err := db.Create(record).Error; err != nil {
        return err
    }
    return nil
}
// CreateBatch 批量插入
func (slf *WarehouseMonthStatsSearch) CreateBatch(records []*WarehouseMonthStats) error {
    var db = slf.build()
    if err := db.Create(&records).Error; err != nil {
        return fmt.Errorf("create batch err: %v, records: %+v", err, records)
    }
    return nil
}
func (slf *WarehouseMonthStatsSearch) Update(record *WarehouseMonthStats) error {
    var db = slf.build()
    if err := db.Omit("CreatedAt").Updates(record).Error; err != nil {
        return fmt.Errorf("save err: %v, record: %+v", err, record)
    }
    return nil
}
func (slf *WarehouseMonthStatsSearch) UpdateByMap(upMap map[string]interface{}) error {
    var (
        db = slf.build()
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by map err: %v, upMap: %+v", err, upMap)
    }
    return nil
}
func (slf *WarehouseMonthStatsSearch) UpdateByQuery(query string, args []interface{}, upMap map[string]interface{}) error {
    var (
        db = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if err := db.Updates(upMap).Error; err != nil {
        return fmt.Errorf("update by query err: %v, query: %s, args: %+v, upMap: %+v", err, query, args, upMap)
    }
    return nil
}
func (slf *WarehouseMonthStatsSearch) Delete() error {
    var db = slf.build()
    return db.Delete(&WarehouseMonthStats{}).Error
}
func (slf *WarehouseMonthStatsSearch) First() (*WarehouseMonthStats, error) {
    var (
        record = new(WarehouseMonthStats)
        db     = slf.build()
    )
    if err := db.First(record).Error; err != nil {
        return record, err
    }
    return record, nil
}
func (slf *WarehouseMonthStatsSearch) Find() ([]*WarehouseMonthStats, int64, error) {
    var (
        records = make([]*WarehouseMonthStats, 0)
        total   int64
        db      = slf.build()
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find records err: %v", err)
    }
    return records, total, nil
}
func (slf *WarehouseMonthStatsSearch) FindNotTotal() ([]*WarehouseMonthStats, error) {
    var (
        records = make([]*WarehouseMonthStats, 0)
        db      = slf.build()
    )
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find records err: %v", err)
    }
    return records, nil
}
// FindByQuery 指定条件查询.
func (slf *WarehouseMonthStatsSearch) FindByQuery(query string, args []interface{}) ([]*WarehouseMonthStats, int64, error) {
    var (
        records = make([]*WarehouseMonthStats, 0)
        total   int64
        db      = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if err := db.Count(&total).Error; err != nil {
        return records, total, fmt.Errorf("find by query count err: %v", err)
    }
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, total, fmt.Errorf("find by query records err: %v, query: %s, args: %+v", err, query, args)
    }
    return records, total, nil
}
// FindByQueryNotTotal 指定条件查询&不查询总条数.
func (slf *WarehouseMonthStatsSearch) FindByQueryNotTotal(query string, args []interface{}) ([]*WarehouseMonthStats, error) {
    var (
        records = make([]*WarehouseMonthStats, 0)
        db      = slf.Orm.Table(slf.TableName()).Where(query, args...)
    )
    if slf.PageNum*slf.PageSize > 0 {
        db = db.Offset((slf.PageNum - 1) * slf.PageSize).Limit(slf.PageSize)
    }
    if err := db.Find(&records).Error; err != nil {
        return records, fmt.Errorf("find by query records err: %v, query: %s, args: %+v", err, query, args)
    }
    return records, nil
}
func WarehouseMonthStatsMap(records []*WarehouseMonthStats) (m map[string]*WarehouseMonthStats) {
    m = make(map[string]*WarehouseMonthStats, len(records))
    for _, record := range records {
        m[record.ProductId] = record
    }
    return m
}
func (slf *WarehouseMonthStatsSearch) Count() (int64, error) {
    var (
        total int64
        db    = slf.build()
    )
    err := db.Count(&total).Error
    return total, err
}
request/report_forms_request.go
@@ -28,8 +28,9 @@
type GetMonthStats struct {
    PageInfo
    Keyword string `json:"keyword"`
    Date    string `json:"date"`
    Keyword     string `json:"keyword"`
    Date        string `json:"date"`
    WarehouseID int    `json:"warehouseID"`
}
type DoMonthStats struct {
router/router.go
@@ -178,6 +178,8 @@
        reportFormsAPI.POST("monthStats", reportFormsController.MonthStats)                         //获取月度统计报表
        reportFormsAPI.POST("downloadMonthStats", reportFormsController.DownloadMonthStats)         //下载月度统计报表
        reportFormsAPI.POST("doMonthStats", reportFormsController.DoMonthStats)                     //手动跑月度统计库存报表
        reportFormsAPI.POST("warehouseMonthStats", reportFormsController.WarehouseMonthStats) //按仓库获取月度统计报表
    }
    //重订货规则
service/warehouse_month_forms.go
New file
@@ -0,0 +1,151 @@
package service
import (
    "github.com/shopspring/decimal"
    "time"
    "wms/constvar"
    "wms/models"
    "wms/pkg/logx"
    "wms/request"
    "wms/utils"
)
type WarehouseMonthFormsService struct{}
func NewWarehouseMonthFormsService() *WarehouseMonthFormsService {
    return &WarehouseMonthFormsService{}
}
func (slf *WarehouseMonthFormsService) Query(params request.GetMonthStats) (result []*models.WarehouseMonthStats, err error) {
    search := slf.BuildSearch(params)
    search = search.SetPage(params.Page, params.PageSize)
    return search.FindNotTotal()
}
func (slf *WarehouseMonthFormsService) BuildSearch(params request.GetMonthStats) (search *models.WarehouseMonthStatsSearch) {
    search = models.NewWarehouseMonthStatsSearch().SetKeyword(params.Keyword).SetDate(params.Date)
    return search
}
func (slf *WarehouseMonthFormsService) Count(params request.GetMonthStats) (total int64, err error) {
    search := slf.BuildSearch(params)
    return search.Count()
}
func (slf *WarehouseMonthFormsService) FetchAll(params request.GetMonthStats) (list []*models.WarehouseMonthStats, err error) {
    total, err := slf.Count(params)
    if err != nil {
        return nil, err
    }
    list = make([]*models.WarehouseMonthStats, 0, total)
    params.PageSize = 500
    page := 1
    for {
        params.Page = page
        data, err := slf.Query(params)
        if err != nil {
            return nil, err
        }
        if len(data) == 0 {
            break
        }
        list = append(list, data...)
        page++
    }
    return
}
func GetCurrentWarehouseStats(date string, warehouseId int, productIds []string) (statRecords []*models.WarehouseMonthStats, err error) {
    //本月期初数量/上月结余数量
    groupSumList, err := models.NewLocationProductAmountSearch().SetProductIds(productIds).GroupSum("product_id", "amount")
    productIds = make([]string, 0, len(groupSumList))
    for _, groupSum := range groupSumList {
        productIds = append(productIds, groupSum.Class)
    }
    products, err := models.NewMaterialSearch().SetFields("id, name, unit, weight, more_unit, more_unit_value").SetIDs(productIds).FindNotTotal()
    if err != nil {
        logx.Errorf("MonthStats GetCurrentStats get products err:%v", err)
        return
    }
    productMap := models.MaterialMap(products)
    beginTime, endTime := utils.GetLastMonthPeriod()
    inputMap, err := GetStatsMulti(beginTime, endTime, constvar.BaseOperationTypeIncoming, warehouseId)
    if err != nil {
        logx.Errorf("MonthStats GetStatsByOperationType input err:%v", err)
        return
    }
    outputMap, err := GetStatsMulti(beginTime, endTime, constvar.BaseOperationTypeOutgoing, warehouseId)
    if err != nil {
        logx.Errorf("MonthStats GetStatsByOperationType output err:%v", err)
        return
    }
    for _, groupSum := range groupSumList {
        productId := groupSum.Class
        if productMap[productId] == nil {
            continue
        }
        product := productMap[productId]
        amount := groupSum.Sum
        record := models.WarehouseMonthStats{
            WarehouseId:  warehouseId,
            ProductId:    productId,
            ProductName:  product.Name,
            Unit:         product.Unit,
            SalePrice:    product.SalePrice,
            EndAmount:    amount,
            InputAmount:  SumMapAmount(inputMap[productId]),
            InputItems:   GetDealerItems(inputMap[productId]),
            OutputAmount: SumMapAmount(outputMap[productId]),
            OutputItems:  GetDealerItems(outputMap[productId]),
            Date:         date,
        }
        statRecords = append(statRecords, &record)
    }
    return
}
func GetStatsMulti(beginTime, endTime time.Time, operationType constvar.BaseOperationType, warehouseId int) (m map[string]map[string]decimal.Decimal, err error) {
    operationIds, err := models.NewOperationSearch().SetBaseOperationType(operationType).
        SetFields("id").SetTimeBetween(beginTime, endTime).
        SetWarehouseId(warehouseId).
        FindIds()
    if err != nil {
        return
    }
    groupSumList, err := models.NewOperationDetailsSearch().SetOperationIds(operationIds).
        SetFields("product_id, dealer_type, amount").
        GroupMultiSumAmount()
    if err != nil {
        return
    }
    m = make(map[string]map[string]decimal.Decimal)
    for _, v := range groupSumList {
        if m[v.ProductID] == nil {
            m[v.ProductID] = make(map[string]decimal.Decimal)
        }
        m[v.ProductID][v.DealerType] = v.Sum
    }
    return
}
func SumMapAmount(m map[string]decimal.Decimal) (sum decimal.Decimal) {
    for _, v := range m {
        sum = sum.Add(v)
    }
    return
}
func GetDealerItems(m map[string]decimal.Decimal) (items []*models.WarehouseStatsItems) {
    for k, v := range m {
        items = append(items, &models.WarehouseStatsItems{
            Name:   k,
            Amount: v,
        })
    }
    return
}