Files
assets/dao/stock/inventory_count_dao.go
2026-03-18 10:18:03 +08:00

203 lines
6.1 KiB
Go
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.
// 盘点任务DAO层
// 职责盘点任务CRUD、检查未完成任务、更新状态/统计
// 紧密耦合service.InventoryCount、dao.InventoryCountDetail(级联删除)
// 注意HasUncompletedTask使用NoCache()跳过缓存,同一时间只允许一个盘点任务
package dao
import (
"assets/consts/public"
"assets/consts/stock"
dto "assets/model/dto/stock"
entity "assets/model/entity/stock"
"context"
"fmt"
"gitea.com/red-future/common/db/mongo"
"gitea.com/red-future/common/utils"
"github.com/gogf/gf/v2/frame/g"
"go.mongodb.org/mongo-driver/v2/bson"
)
var InventoryCount = new(inventoryCount)
type inventoryCount struct{}
// convertToObjectIDs 将字符串ID列表批量转换为ObjectID列表跳过空值
func convertToObjectIDs(hexIDs []string, label string) ([]*bson.ObjectID, error) {
if len(hexIDs) == 0 {
return nil, nil
}
result := make([]*bson.ObjectID, 0, len(hexIDs))
for _, hex := range hexIDs {
if g.IsEmpty(hex) {
continue
}
id, err := bson.ObjectIDFromHex(hex)
if err != nil {
return nil, fmt.Errorf("%sID格式错误(值:%s): %v", label, hex, err)
}
result = append(result, &id)
}
return result, nil
}
func (d *inventoryCount) Insert(ctx context.Context, req *dto.CreateInventoryCountReq, countNo string) (ids []interface{}, err error) {
result := &entity.InventoryCount{
CountNo: countNo,
Title: req.Title,
Description: req.Description,
CountType: req.CountType,
Scope: req.Scope,
AssigneeID: req.AssigneeID,
AssigneeName: req.AssigneeName,
Participants: req.Participants,
Remark: req.Remark,
Status: stock.InventoryCountStatusInProgress,
}
// 批量转换字符串ID为ObjectID
if result.WarehouseIDs, err = convertToObjectIDs(req.WarehouseIDs, "仓库"); err != nil {
return
}
if result.ZoneIDs, err = convertToObjectIDs(req.ZoneIDs, "库区"); err != nil {
return
}
if result.LocationIDs, err = convertToObjectIDs(req.LocationIDs, "库位"); err != nil {
return
}
if result.AssetSkuIDs, err = convertToObjectIDs(req.AssetSkuIDs, "资产SKU"); err != nil {
return
}
ids, err = mongo.DB().Insert(ctx, []interface{}{result}, public.InventoryCountCollection)
return
}
func (d *inventoryCount) GetOne(ctx context.Context, req *dto.GetInventoryCountReq) (res *entity.InventoryCount, err error) {
filter := bson.M{"_id": req.Id}
err = mongo.DB().FindOne(ctx, filter, &res, public.InventoryCountCollection)
return
}
func (d *inventoryCount) Update(ctx context.Context, req *dto.UpdateInventoryCountReq) (err error) {
var updateData entity.InventoryCount
if err = utils.Struct(req, &updateData); err != nil {
return
}
filter := bson.M{"_id": req.Id}
update := bson.M{"$set": updateData}
_, err = mongo.DB().Update(ctx, filter, update, public.InventoryCountCollection)
return
}
func (d *inventoryCount) Delete(ctx context.Context, req *dto.DeleteInventoryCountReq) (err error) {
filter := bson.M{"_id": req.Id}
_, err = mongo.DB().Delete(ctx, filter, public.InventoryCountCollection)
return
}
func (d *inventoryCount) List(ctx context.Context, req *dto.ListInventoryCountReq) (res []entity.InventoryCount, total int64, err error) {
filter, err := d.buildListFilter(ctx, req)
if err != nil {
return
}
total, err = mongo.DB().Find(ctx, filter, &res, public.InventoryCountCollection, req.Page, req.OrderBy)
return
}
func (d *inventoryCount) buildListFilter(ctx context.Context, req *dto.ListInventoryCountReq) (filter bson.M, err error) {
_ = ctx
filter = bson.M{}
// 兼容单值和数组参数(优先使用数组)
if len(req.WarehouseIDs) > 0 {
// 将字符串数组转为 ObjectID 数组
var oids []bson.ObjectID
for _, id := range req.WarehouseIDs {
if oid, e := bson.ObjectIDFromHex(id); e == nil {
oids = append(oids, oid)
}
}
if len(oids) > 0 {
filter["warehouseIds"] = bson.M{"$in": oids}
}
} else if !g.IsEmpty(req.WarehouseID) {
if wid, e := bson.ObjectIDFromHex(req.WarehouseID); e == nil {
filter["warehouseIds"] = wid
}
}
if len(req.ZoneIDs) > 0 {
// 将字符串数组转为 ObjectID 数组
var oids []bson.ObjectID
for _, id := range req.ZoneIDs {
if oid, e := bson.ObjectIDFromHex(id); e == nil {
oids = append(oids, oid)
}
}
if len(oids) > 0 {
filter["zoneIds"] = bson.M{"$in": oids}
}
} else if !g.IsEmpty(req.ZoneID) {
if zid, e := bson.ObjectIDFromHex(req.ZoneID); e == nil {
filter["zoneIds"] = zid
}
}
if !g.IsEmpty(req.CountType) {
filter["countType"] = req.CountType
}
if !g.IsEmpty(req.Status) {
filter["status"] = req.Status
}
if !g.IsEmpty(req.AssigneeID) {
filter["assigneeId"] = req.AssigneeID
}
if !g.IsEmpty(req.Keyword) {
filter["$or"] = bson.A{
bson.M{"countNo": bson.M{"$regex": req.Keyword, "$options": "i"}},
bson.M{"title": bson.M{"$regex": req.Keyword, "$options": "i"}},
}
}
return
}
// HasUncompletedTask 检查是否存在未完成的盘点任务
func (d *inventoryCount) HasUncompletedTask(ctx context.Context) (has bool, err error) {
filter := bson.M{
"status": stock.InventoryCountStatusInProgress,
}
var result entity.InventoryCount
err = mongo.DB().NoCache().FindOne(ctx, filter, &result, public.InventoryCountCollection)
if err != nil {
return false, err
}
return result.Id != nil, nil
}
// UpdateStatus 更新盘点状态
func (d *inventoryCount) UpdateStatus(ctx context.Context, id *bson.ObjectID, status stock.InventoryCountStatus) (err error) {
filter := bson.M{"_id": id}
update := bson.M{
"$set": bson.M{
"status": status,
},
}
_, err = mongo.DB().Update(ctx, filter, update, public.InventoryCountCollection)
return
}
// UpdateStats 更新盘点统计信息
func (d *inventoryCount) UpdateStats(ctx context.Context, id *bson.ObjectID, totalItems, completedItems, discrepancyItems int) (err error) {
filter := bson.M{"_id": id}
var progress float64
if totalItems > 0 {
progress = float64(completedItems) / float64(totalItems) * 100
}
update := bson.M{
"$set": bson.M{
"totalItems": totalItems,
"completedItems": completedItems,
"discrepancyItems": discrepancyItems,
"progress": progress,
},
}
_, err = mongo.DB().Update(ctx, filter, update, public.InventoryCountCollection)
return
}