diff --git a/Makefile b/Makefile index 904c18a..db72f12 100644 --- a/Makefile +++ b/Makefile @@ -23,3 +23,6 @@ dev-windows: dev: GOOS=linux GOARCH=amd64 go build -o dev_mh_goadmin_server main.go + +beta: + GOOS=linux GOARCH=amd64 go build -o test_mh_goadmin_server main.go diff --git a/app/admin/apis/basic/category.go b/app/admin/apis/basic/category.go index 19d2a88..53f703d 100644 --- a/app/admin/apis/basic/category.go +++ b/app/admin/apis/basic/category.go @@ -307,7 +307,7 @@ func CategoryImport(c *gin.Context) { colsMap = colsMap[1:] } - err = models.ImportCategoryData(colsMap, (middleware.GetCooperativeBusinessId(c))) + err = models.ImportCategoryData(colsMap, middleware.GetCooperativeBusinessId(c)) if err != nil { //logger.Error("file excel reader err:", err) app.Error(c, http.StatusInternalServerError, err, err.Error()) diff --git a/app/admin/apis/basic/commodity.go b/app/admin/apis/basic/commodity.go index 55dbf83..fddbd47 100644 --- a/app/admin/apis/basic/commodity.go +++ b/app/admin/apis/basic/commodity.go @@ -20,10 +20,10 @@ type CommodityCreateRequest struct { ErpBarcode string `json:"erp_barcode"` // 商品条码 IMEIType uint32 `json:"imei_type"` // 系统生成串码:2-是(系统生成) 3-否(手动添加) ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 主供应商 - RetailPrice uint32 `json:"retail_price" binding:"required"` // 指导零售价 - MinRetailPrice uint32 `json:"min_retail_price" binding:"required"` // 最低零售价 - StaffCostPrice uint32 `json:"staff_cost_price" binding:"required"` // 员工成本价加价 - WholesalePrice uint32 `json:"wholesale_price" binding:"required"` // 指导采购价 + RetailPrice uint32 `json:"retail_price"` // 指导零售价 + MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价 + StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 + WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成 Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成 MemberDiscount float64 `json:"member_discount"` // 会员优惠 @@ -110,13 +110,14 @@ func CommodityCreate(c *gin.Context) { ErpSupplierName: "", RetailPrice: req.RetailPrice, MinRetailPrice: req.MinRetailPrice, - StaffCostPrice: req.StaffCostPrice + req.WholesalePrice, - WholesalePrice: req.WholesalePrice, - Brokerage1: brokerage1Float, - Brokerage2: brokerage2Float, - MemberDiscount: memberDiscountFloat, - Origin: req.Origin, - Remark: req.Remark, + //StaffCostPrice: req.StaffCostPrice + req.WholesalePrice, + StaffCostPrice: req.StaffCostPrice, + WholesalePrice: req.WholesalePrice, + Brokerage1: brokerage1Float, + Brokerage2: brokerage2Float, + MemberDiscount: memberDiscountFloat, + Origin: req.Origin, + Remark: req.Remark, } err = commodity.SetErpCategory() if err != nil { @@ -217,6 +218,16 @@ func CommodityDetail(c *gin.Context) { commodity.IsIMEI = 1 // 串码 } + // 查询是否有库存 + var count int64 + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and state = ?", + commodity.ID, models.InStock).Count(&count).Error + if err != nil { + app.Error(c, http.StatusInternalServerError, err, "获取商品库存信息失败") + return + } + commodity.StockCount = uint32(count) + app.OK(c, commodity, "") return } @@ -226,12 +237,13 @@ type CommodityEditRequest struct { Name string `json:"name" binding:"required"` // 商品名称 ErpCategoryId uint32 `json:"erp_category_id" binding:"required"` // 商品分类id ErpBarcode string `json:"erp_barcode"` // 商品条码 + IsIMEI uint32 `json:"is_imei" binding:"required"` // 是否串码:1-串码类 2-非串码 IMEIType uint32 `json:"imei_type" binding:"required"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加) ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 主供应商id - RetailPrice uint32 `json:"retail_price" binding:"required"` // 指导零售价 - MinRetailPrice uint32 `json:"min_retail_price" binding:"required"` // 最低零售价 - StaffCostPrice uint32 `json:"staff_cost_price" binding:"required"` // 员工成本价加价 - WholesalePrice uint32 `json:"wholesale_price" binding:"required"` // 指导采购价 + RetailPrice uint32 `json:"retail_price"` // 指导零售价 + MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价 + StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 + WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成 Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成 MemberDiscount float64 `json:"member_discount"` // 会员优惠 @@ -285,13 +297,14 @@ func CommodityEdit(c *gin.Context) { ErpSupplierName: "", RetailPrice: req.RetailPrice, MinRetailPrice: req.MinRetailPrice, - StaffCostPrice: req.StaffCostPrice + req.WholesalePrice, - WholesalePrice: req.WholesalePrice, - Brokerage1: brokerage1Float, - Brokerage2: brokerage2Float, - MemberDiscount: memberDiscountFloat, - Origin: req.Origin, - Remark: req.Remark, + //StaffCostPrice: req.StaffCostPrice + req.WholesalePrice, + StaffCostPrice: req.StaffCostPrice, + WholesalePrice: req.WholesalePrice, + Brokerage1: brokerage1Float, + Brokerage2: brokerage2Float, + MemberDiscount: memberDiscountFloat, + Origin: req.Origin, + Remark: req.Remark, } commodity.ID = req.Id err = commodity.SetErpCategory() @@ -312,6 +325,50 @@ func CommodityEdit(c *gin.Context) { commodity.Number = catCommodity.Number commodity.SerialNumber = catCommodity.SerialNumber + if commodity.ErpCategory != nil && commodity.ErpCategory.ID != 0 { + if commodity.ErpCategory.ID != catCommodity.ErpCategoryId { // 编辑时更换了分类ID + commodity.ErpCategoryId = commodity.ErpCategory.ID + commodity.ErpCategoryName = commodity.ErpCategory.Name + commodity.SerialNumber, err = models.GenerateSerialNumber(commodity.ErpCategoryId) // 更新商品编号 + if err != nil { + app.Error(c, http.StatusInternalServerError, err, err.Error()) + return + } + } else { + commodity.ErpCategory = nil + } + } + + if req.IsIMEI == 2 { // 是否串码:1-串码类 2-非串码 + commodity.IMEIType = 1 // 系统生成串码:2-是(系统生成) 3-否(手动添加) 1表示非串码 + } + + var sysIsIMEI uint32 + switch catCommodity.IMEIType { + case 1: + sysIsIMEI = 2 // 非串码 + case 2: + fallthrough + case 3: + sysIsIMEI = 1 // 串码 + } + + if req.IsIMEI != sysIsIMEI { + // 查询是否有库存 + var count int64 + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and state = ?", + commodity.ID, models.InStock).Count(&count).Error + if err != nil { + app.Error(c, http.StatusInternalServerError, err, "获取商品库存信息失败") + return + } + + if count > 0 { + app.Error(c, http.StatusInternalServerError, err, "该商品已有库存,不能修改串码/非串码选项") + return + } + } + begin := orm.Eloquent.Begin() err = begin.Save(commodity).Error if err != nil { @@ -320,8 +377,8 @@ func CommodityEdit(c *gin.Context) { return } - // 同步更新库存表和库存商品表的"指导零售价"和"最低零售价";库存商品表的"商品条码" - err = models.UpdateErpStockAmountInfo(begin, req.Id, req.RetailPrice, req.MinRetailPrice, barCode) + // 同步更新库存表和库存商品表的"指导零售价"和"最低零售价"、"分类id"、"分类名称";库存商品表的"商品条码" + err = models.UpdateErpStockAmountInfo(begin, req.Id, req.RetailPrice, req.MinRetailPrice, barCode, commodity.ErpCategory) if err != nil { begin.Rollback() logger.Error("UpdateErpStockAmountInfo err:", logger.Field("err", err)) diff --git a/app/admin/apis/erpordermanage/erp_order.go b/app/admin/apis/erpordermanage/erp_order.go index 094a073..cd9bdee 100644 --- a/app/admin/apis/erpordermanage/erp_order.go +++ b/app/admin/apis/erpordermanage/erp_order.go @@ -185,7 +185,16 @@ func ErpOrderAudit(c *gin.Context) { stockState = model.OnSale // 库存-销售锁定 case 2: // 取消审核 orderState = model.ErpOrderStateUnAudit - stockState = model.InStock // 库存-在库 + stockState = model.InStock // 库存-在库 + if erpOrder.RetailType == model.RetailTypeRejected { // 退货单反审核 + if erpOrder.State == model.ErpOrderStateUnAudit { + app.OK(c, nil, "") + return + } + + erpOrder.RetailType = model.RetailTypeSale // 订单改为销售,方便后面流程更新库存 + stockState = model.SoldOut // 状态为已售 + } default: logger.Error("req.State no in (1,2)", logger.Field("req.State", req.State)) app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误,req.State no in (1,2)") @@ -193,14 +202,15 @@ func ErpOrderAudit(c *gin.Context) { } nPayStatus := model.NoCreatePayOrder - if req.State == 1 { // 审核 - // 检查支付方式,如果没有线上支付则默认为支付已完成 - nPayStatus = model.WaitForPaying // 待支付 + if req.State == 1 && erpOrder.RetailType == model.RetailTypeSale { // 审核:销售订单才更新支付状态,退货订单不用更新 var cashiers []model.ErpOrderCashier err = json.Unmarshal([]byte(erpOrder.CashierList), &cashiers) if err != nil { logger.Error("unmarshal CashierList err:", logger.Field("err", err)) } + + nPayStatus = model.WaitForPaying // 待支付 + // 检查支付方式,如果没有线上支付则默认为支付已完成 if !model.CheckIsOnlinePay(cashiers) { nPayStatus = model.HavePaid // 已完成 stockState = model.SoldOut // 库存-已售 diff --git a/app/admin/apis/purchasemanage/purchase.go b/app/admin/apis/purchasemanage/purchase.go index eebb6f9..80c8350 100644 --- a/app/admin/apis/purchasemanage/purchase.go +++ b/app/admin/apis/purchasemanage/purchase.go @@ -9,6 +9,7 @@ import ( "go-admin/logger" "go-admin/tools" "go-admin/tools/app" + "math" "net/http" "time" ) @@ -215,11 +216,26 @@ func ErpPurchaseDetail(c *gin.Context) { app.Error(c, http.StatusBadRequest, err, "获取失败") return } - v.ExecutionCount = result.TotalCount v.ExecutionAmount = result.TotalAmount v.ExecutionEmployeePrice = result.AvgEmployeePrice v.ExecutionPrice = result.AvgImplementationPrice + + v.ExecutionAmount = math.Round(v.ExecutionAmount*100) / 100 + v.ExecutionEmployeePrice = math.Round(v.ExecutionEmployeePrice*100) / 100 + v.ExecutionPrice = math.Round(v.ExecutionPrice*100) / 100 + + // 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量 + nCount, err := model.GetCommodityStockByPurchaseId(purchaseOrder.SerialNumber, v.ErpCommodityId) + if err != nil { + logger.Error("ErpPurchaseDetail GetCommodityStockByPurchaseId err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, err, "获取失败") + return + } + v.EffectiveCount = nCount // 有效数量 + v.ErpCategoryID = erpCommodity.ErpCategoryId + v.ErpCategoryName = erpCommodity.ErpCategoryName + commodityList = append(commodityList, v) } @@ -271,6 +287,7 @@ func ErpPurchaseAudit(c *gin.Context) { return } + begin := orm.Eloquent.Begin() // 判断入参state:1-审核,2-取消审核 orderState := 0 switch req.State { @@ -289,16 +306,23 @@ func ErpPurchaseAudit(c *gin.Context) { app.OK(c, nil, "订单已审核") return } - case 2: // 2-取消审核:2/3可以取消审核 - if erpPurchaseOrder.State == model.ErpPurchaseOrderWaitInventory || erpPurchaseOrder.State == model.ErpPurchaseOrderWaitReject { - orderState = model.ErpPurchaseOrderUnAudit - } else if erpPurchaseOrder.State == model.ErpPurchaseOrderUnAudit { + case 2: // 2-取消审核:5-已终止不能取消,2/3/4其他正常取消,取消后对应的退库或入库 + if erpPurchaseOrder.State == model.ErpPurchaseOrderUnAudit { app.OK(c, nil, "订单已取消审核") return - } else { + } else if erpPurchaseOrder.State == model.ErpPurchaseOrderEnd { logger.Error("order err, erpPurchaseOrder.State is:", logger.Field("erpPurchaseOrder.State", erpPurchaseOrder.State)) - app.Error(c, http.StatusInternalServerError, err, "取消审核失败:[入库/退货中、已终止、已完成]订单不能取消") + app.Error(c, http.StatusInternalServerError, err, "取消审核失败:[已终止]订单不能取消") return + } else { + orderState = model.ErpPurchaseOrderUnAudit + // 更新库存信息 + err = model.CancelAuditUpdateStock(begin, erpPurchaseOrder) + if err != nil { + begin.Rollback() + app.Error(c, http.StatusInternalServerError, err, "审核失败:"+err.Error()) + return + } } default: logger.Error("order err, req.State is:", logger.Field("req.State", req.State)) @@ -306,7 +330,6 @@ func ErpPurchaseAudit(c *gin.Context) { return } - begin := orm.Eloquent.Begin() err = begin.Table("erp_purchase_order").Where("id = ?", erpPurchaseOrder.ID).Updates(map[string]interface{}{ "state": orderState, "auditor_id": sysUser.UserId, @@ -451,6 +474,16 @@ func ErpPurchaseInventory(c *gin.Context) { return } + if req.PurchaseType == model.ErpProcureOrder { + if req.InventoryId == 0 { + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误,入库人id为0") + return + } else if req.InventoryName == "" { + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误,入库人姓名为空") + return + } + } + err := model.InventoryErpPurchase(req) if err != nil { logger.Error("InventoryErpPurchase err:", logger.Field("err", err)) @@ -504,9 +537,16 @@ func ErpPurchaseTerminate(c *gin.Context) { return } + updateRemark := "" + if erpPurchaseOrder.Remark != "" { + updateRemark = erpPurchaseOrder.Remark + "," + req.Remark + } else { + updateRemark = req.Remark + } + err = orm.Eloquent.Table("erp_purchase_order").Where("id = ?", erpPurchaseOrder.ID).Updates(map[string]interface{}{ "state": orderState, - "remark": req.Remark, + "remark": updateRemark, }).Error if err != nil { logger.Error("update erp_purchase_order err:", logger.Field("err", err)) @@ -689,6 +729,7 @@ func ErpPurchaseReportByCommodity(c *gin.Context) { app.Error(c, http.StatusInternalServerError, err, "查询失败:"+err.Error()) return } + fmt.Println(resp) app.OK(c, resp, "查询成功") return diff --git a/app/admin/apis/system/sysuser.go b/app/admin/apis/system/sysuser.go index 4a4b7ed..4ed794e 100644 --- a/app/admin/apis/system/sysuser.go +++ b/app/admin/apis/system/sysuser.go @@ -6,18 +6,26 @@ import ( "github.com/gin-gonic/gin/binding" "github.com/google/uuid" "go-admin/app/admin/models" + orm "go-admin/common/global" "go-admin/logger" "go-admin/tools" "go-admin/tools/app" + "net/http" ) // GetSysUserList // @Summary 列表用户信息数据(update) // @Description 获取JSON // @Tags system/用户 -// @Param username query string false "username" -// @Success 200 {string} string "{"code": 200, "data": [...]}" -// @Success 200 {string} string "{"code": -1, "message": "抱歉未找到相关信息"}" +// @Param username query string false "用户名称" +// @Param status query int false "状态:0-正常,1-停用" +// @Param phone query string false "手机号" +// @Param pageIndex query string false "页码" +// @Param pageSize query string false "页面条数" +// @Param roleId query string false "角色id" +// @Param nickName query string false "昵称" +// @Param storeId query string false "门店id" +// @Success 200 {object} models.SysUserListResp // @Router /api/v1/sysUserList [get] // @Security Bearer func GetSysUserList(c *gin.Context) { @@ -36,9 +44,18 @@ func GetSysUserList(c *gin.Context) { pageIndex, err = tools.StringToInt(index) } - data.Username = c.Request.FormValue("username") - data.Status = c.Request.FormValue("status") - data.Phone = c.Request.FormValue("phone") + data.Username = c.Request.FormValue("username") // 用户名称 + data.Status = c.Request.FormValue("status") // 状态 + data.Phone = c.Request.FormValue("phone") // 手机号 + + strRoleId := c.Request.FormValue("roleId") // 用户角色 + data.RoleId, _ = tools.StringToInt(strRoleId) + + data.NickName = c.Request.FormValue("nickName") // 用户昵称 + + strStoreId := c.Request.FormValue("storeId") // 门店id + nStoreId, _ := tools.StringToInt(strStoreId) + data.StoreId = uint32(nStoreId) postId := c.Request.FormValue("postId") data.PostId, _ = tools.StringToInt(postId) @@ -53,6 +70,7 @@ func GetSysUserList(c *gin.Context) { app.PageOK(c, result, count, pageIndex, pageSize, "") } +// GetSysUser // @Summary 获取用户 // @Description 获取JSON // @Tags system/用户 @@ -164,6 +182,26 @@ func InsertSysUser(c *gin.Context) { tools.HasError(err, "数据解析失败", 500) } + // 判断小程序账号ID是否正常 + if req.Uid != 0 { + userInfo, err := models.GetUserInfoByUid(req.Uid) + if err != nil { + logger.Error("get user info err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID有误,请检查") + return + } + // 是否是真实id + if userInfo.Uid != req.Uid { + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID有误,请检查") + return + } + // 是否已经绑定过账号 + if userInfo.UserType == 2 { + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID重复,请检查") + return + } + } + sysUser := models.SysUser{ SysUserId: req.SysUserId, LoginM: req.LoginM, @@ -195,9 +233,29 @@ func InsertSysUser(c *gin.Context) { } sysUser.StoreData = string(storeDataJSON) } - + begin := orm.Eloquent.Begin() sysUser.CreateBy = tools.GetUserIdStr(c) - id, err := sysUser.Insert() + id, err := sysUser.Insert(begin) + + // 如果添加了小程序id,则需要更新user表的user_type字段为2-店员 + if req.Uid != 0 { + err = models.UpdateUserType(begin, req.Uid, 2) + if err != nil { + begin.Rollback() + logger.Error("UpdateUserType err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "添加失败") + return + } + } + + err = begin.Commit().Error + if err != nil { + begin.Rollback() + logger.Error("commit err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "添加失败") + return + } + tools.HasError(err, "添加失败", 500) app.OK(c, id, "添加成功") } @@ -223,6 +281,26 @@ func UpdateSysUser(c *gin.Context) { tools.HasError(err, "数据解析失败", 500) } + // 判断小程序账号ID是否正常 + if req.Uid != 0 { + userInfo, err := models.GetUserInfoByUid(req.Uid) + if err != nil { + logger.Error("get user info err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID有误,请检查") + return + } + // 是否是真实id + if userInfo.Uid != req.Uid { + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID有误,请检查") + return + } + // 是否已经绑定过账号 + if userInfo.UserType == 2 { + app.Error(c, http.StatusInternalServerError, err, "小程序账号ID重复,请检查") + return + } + } + data := models.SysUser{ SysUserId: req.SysUserId, LoginM: req.LoginM, @@ -255,9 +333,47 @@ func UpdateSysUser(c *gin.Context) { data.StoreData = string(storeDataJSON) } + begin := orm.Eloquent.Begin() data.UpdateBy = tools.GetUserIdStr(c) - result, err := data.Update(data.UserId) + result, err := data.Update(begin, data.UserId) tools.HasError(err, "修改失败", 500) + + // 判断是否修改了uid + sysInfo := models.GetUserById(uint32(req.UserId)) + if sysInfo.Uid == 0 && req.Uid != 0 { // 新增uid,直接更新为2即可 + err = models.UpdateUserType(begin, req.Uid, 2) + } else if sysInfo.Uid != 0 { + if sysInfo.Uid != req.Uid { + if req.Uid != 0 { + // 原uid的状态更新为1 + err = models.UpdateUserType(begin, sysInfo.Uid, 1) + if err != nil { + begin.Rollback() + logger.Error("UpdateUserType err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "修改失败") + return + } + } + + // 新uid状态更新为2 + err = models.UpdateUserType(begin, req.Uid, 2) + } + } + if err != nil { + begin.Rollback() + logger.Error("UpdateUserType err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "修改失败") + return + } + + err = begin.Commit().Error + if err != nil { + begin.Rollback() + logger.Error("commit err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "修改失败") + return + } + app.OK(c, result, "修改成功") } @@ -299,7 +415,7 @@ func InsetSysUserAvatar(c *gin.Context) { sysuser.UserId = tools.GetUserId(c) sysuser.Avatar = "/" + filPath sysuser.UpdateBy = tools.GetUserIdStr(c) - sysuser.Update(sysuser.UserId) + sysuser.Update(nil, sysuser.UserId) app.OK(c, filPath, "修改成功") } diff --git a/app/admin/models/cashier.go b/app/admin/models/cashier.go index a11d3c8..e9dbe06 100644 --- a/app/admin/models/cashier.go +++ b/app/admin/models/cashier.go @@ -47,7 +47,7 @@ type ErpCashierDetail struct { } type ErpCashierListResp struct { - Total int `json:"count"` // 数据总条数 + Total int `json:"total"` // 数据总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 List []ErpCashier `json:"list"` diff --git a/app/admin/models/commodity.go b/app/admin/models/commodity.go index 25dedde..da4083e 100644 --- a/app/admin/models/commodity.go +++ b/app/admin/models/commodity.go @@ -67,20 +67,21 @@ type ErpStockCommodity struct { StockTime time.Time `json:"stock_time"` // 最近入库时间 RetailPrice uint32 `json:"retail_price"` // 指导零售价 MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价 - StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 + StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 MemberDiscount float64 `json:"member_discount"` // 会员优惠 State uint32 `json:"state"` // 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 Count uint32 `json:"count"` // 数量 StorageType uint32 `json:"storage_type"` // 入库方式:1-系统入库 2-采购入库 FirstStockTime time.Time `json:"first_stock_time"` // 首次入库时间 - StockSn string `json:"stock_sn"` // 库存订单编号 + StockSn string `json:"stock_sn"` // 库存订单编号(跟采购入库的入库编号关联) OriginalSn string `json:"original_sn" gorm:"index"` // 首次入库订单编号(单据编号) StockStartTime time.Time `json:"stock_start_time" gorm:"-"` // 最近入库开始时间 StockEndTime time.Time `json:"stock_end_time" gorm:"-"` // 最近入库结束时间 Age uint32 `json:"age" gorm:"-"` // 最近库龄 AllAge uint32 `json:"all_age" gorm:"-"` // 总库龄 Remark string `json:"remark"` // 备注 + //ErpOrderCommodityId uint32 `json:"erp_order_commodity_id"` // 零售订单商品表的主键ID(后端使用,前端忽略) //Commodity ErpCommodity `json:"commodity" gorm:"-"` } @@ -101,13 +102,14 @@ type ErpCommodity struct { ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称 RetailPrice uint32 `json:"retail_price"` // 指导零售价 MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价 - StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 + StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成 Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成 MemberDiscount float64 `json:"member_discount"` // 会员优惠 Origin string `json:"origin"` // 产地 Remark string `json:"remark" gorm:"type:varchar(512)"` // 备注 + StockCount uint32 `json:"stock_count" gorm:"-"` // 库存数量 ErpCategory *ErpCategory `json:"erp_category" gorm:"-"` } @@ -317,7 +319,11 @@ func (m *ErpCommodityListReq) List() (*ErpCommodityListResp, error) { qs = qs.Where("imei=?", m.IMEI) } if m.ErpCategoryId != 0 { - qs = qs.Where("erp_category_id=?", m.ErpCategoryId) + categoryInfo, err := GetErpCategory(m.ErpCategoryId) + if err != nil { + return nil, err + } + qs = qs.Where("serial_number like ?", categoryInfo.Number+"%") } if m.ErpSupplierId != 0 { qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId) @@ -359,6 +365,15 @@ func (m *ErpCommodityListReq) List() (*ErpCommodityListResp, error) { } else { resp.List[i].IsIMEI = 1 // 串码 } + + // 查询库存数量 + var stockCount int64 + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and state = ?", + resp.List[i].ID, InStock).Count(&stockCount).Error + if err != nil { + return nil, err + } + resp.List[i].StockCount = uint32(stockCount) } //跟之前保持一致 @@ -777,8 +792,8 @@ func GenerateSerialCode(categoryID uint32) (string, error) { // 拼接串码 serialCode := categoryStr + dateStr + randomStr - // 检查生成的串码是否已存在 - exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0", serialCode)) + // 检查生成的串码是否已存在 todo 是否需要判断状态,采购退货的可以重复? + exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock_commodity WHERE FIND_IN_SET(%s, imei) > 0 ", serialCode)) if err != nil { logger.Error("exist sn err") } @@ -1134,10 +1149,10 @@ func InventoryDetailListExport(list []ErpStockCommodity) (string, error) { list[rowId].ErpSupplierName, list[rowId].FirstStockTime, storageType, - list[rowId].StockSn, + list[rowId].OriginalSn, list[rowId].StockTime, list[rowId].WholesalePrice, - list[rowId].StaffCostPrice, + list[rowId].WholesalePrice + list[rowId].StaffCostPrice, list[rowId].Age, list[rowId].AllAge, state, @@ -1395,7 +1410,7 @@ func (m *ErpStockListReq) stockIsEmptyList() (*ErpStockListResp, error) { stock.ErpCategoryId = commodity.ErpCategoryId stock.ErpCategoryName = commodity.ErpCategoryName stock.CommoditySerialNumber = commodity.SerialNumber - stock.IMEIType = commodity.IsIMEI + stock.IMEIType = commodity.IMEIType stock.RetailPrice = commodity.RetailPrice stock.MinRetailPrice = commodity.MinRetailPrice stock.Count = 0 @@ -1508,7 +1523,7 @@ func (m *ErpStockListReq) stockNoEmptyList() (*ErpStockListResp, error) { stock.ErpCategoryId = commodity.ErpCategoryId stock.ErpCategoryName = commodity.ErpCategoryName stock.CommoditySerialNumber = commodity.SerialNumber - stock.IMEIType = commodity.IsIMEI + stock.IMEIType = commodity.IMEIType stock.RetailPrice = commodity.RetailPrice stock.MinRetailPrice = commodity.MinRetailPrice stock.Count = uint32(commodity.TotalCount) @@ -1626,7 +1641,7 @@ func (m *ErpStockListReq) allCommodityList() (*ErpStockListResp, error) { stock.ErpCategoryId = commodity.ErpCategoryId stock.ErpCategoryName = commodity.ErpCategoryName stock.CommoditySerialNumber = commodity.SerialNumber - stock.IMEIType = commodity.IsIMEI + stock.IMEIType = commodity.IMEIType stock.RetailPrice = commodity.RetailPrice stock.MinRetailPrice = commodity.MinRetailPrice stock.Count = uint32(commodity.TotalCount) @@ -1737,7 +1752,7 @@ func (m *ErpStockCommodityListReq) GetDetailList() (*ErpStockCommodityListResp, //logger.Error("dailys err:", err) return resp, err } - + ErpStockCommodityListSetAge(commodities) listExport, err := InventoryDetailListExport(commodities) if err != nil { //logger.Error("list export err:", err) @@ -1888,7 +1903,7 @@ func (m *ErpStockCommodityListReq) buildQueryConditions(qs *gorm.DB) { } if m.Sn != "" { //首次入库订单编号 - qs = qs.Where("stock_sn=?", m.Sn) + qs = qs.Where("original_sn=?", m.Sn) } if m.StorageType != 0 { //首次入库方式 diff --git a/app/admin/models/erp_order.go b/app/admin/models/erp_order.go index 6853666..fae9a94 100644 --- a/app/admin/models/erp_order.go +++ b/app/admin/models/erp_order.go @@ -114,10 +114,11 @@ type ErpOrderCommodity struct { RejectedCount uint32 `json:"rejected_count"` // 退货数量 RejectedAmount float64 `json:"rejected_amount"` // 退货金额 RejectedOrderCommodityId uint32 `json:"rejected_order_commodity_id"` // 退货订单商品id - StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 + StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 SalesProfit float64 `json:"sales_profit"` // 销售毛利:实际零售价-采购单价;如果为退货订单,则为实际退货价-采购单价 StaffProfit float64 `json:"staff_profit"` // 员工毛利:实际零售价-员工成本价;如果为退货订单,则为实际退货价-员工成本价 + ErpStockCommodityID string `json:"erp_stock_commodity_id"` // 库存商品表主键id } // ErpOrderCashier 订单收款方式 @@ -142,7 +143,7 @@ type ErpOrderSales struct { Model ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id(后端生成) - Uid uint32 `json:"uid" binding:"required"` // 销售员用户ID + Uid uint32 `json:"userId" binding:"required"` // 销售员用户ID(20240322:更换为系统用户表主键id) Name string `json:"name"` // 销售员用户姓名 SalesProfitPer float64 `json:"sales_profit_per"` // 销售毛利提成:每个商品销售毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去 StaffProfitPer float64 `json:"staff_profit_per"` // 员工毛利提成:每个商品员工毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去 @@ -182,20 +183,22 @@ type ErpOrderCreateReq struct { // ErpOrderListReq 查询零售订单列表入参 type ErpOrderListReq struct { - ScanCode string `json:"scan_code"` // 扫码枪扫码数据:串码 - BillSn string `json:"bill_sn"` // 单据编号 - RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 - CommodityName string `json:"commodity_name"` // 商品名称 - Uid int `json:"uid"` // 用户ID - Tel string `json:"tel"` // 客户手机号 - Salesman uint32 `json:"salesman"` // 销售人员ID - StoreId uint32 `json:"store_id"` // 门店ID - State string `json:"state"` // 订单状态 - PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 ;1-待支付; 2-已支付 - StartTime string `json:"start_time"` // 开始时间 - EndTime string `json:"end_time"` // 结束时间 - PageIndex int `json:"pageIndex"` // 页码 - PageSize int `json:"pageSize"` // 页面条数 + ScanCode string `json:"scan_code"` // 扫码枪扫码数据:串码 + BillSn string `json:"bill_sn"` // 单据编号 + RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 + CommodityName string `json:"commodity_name"` // 商品名称 + Uid int `json:"uid"` // 用户ID + Tel string `json:"tel"` // 客户手机号 + Salesman uint32 `json:"salesman"` // 销售人员ID + StoreId uint32 `json:"store_id"` // 门店ID + State string `json:"state"` // 订单状态 + PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 ;1-待支付; 2-已支付 + MakeTimeStart string `json:"make_time_start"` // 制单开始时间 + MakeTimeEnd string `json:"make_time_end"` // 制单结束时间 + AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 + AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 } // ErpOrderListResp 查询零售订单列表出参 @@ -285,7 +288,7 @@ type ErpOrderRetailMarginResp struct { Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 - TotalCount uint32 `json:"total_count"` // 总销售数量 + TotalCount int32 `json:"total_count"` // 总销售数量 TotalSalesAmount float64 `json:"total_sales_amount"` // 总销售/退货金额 TotalSalesCost float64 `json:"total_sales_cost"` // 总销售成本:销售采购价之和 TotalSalesMargin float64 `json:"total_sales_margin"` // 总销售毛利:销售/退货金额-销售成本 @@ -302,7 +305,7 @@ type RetailMarginData struct { ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id ErpCategoryName string `json:"erp_category_name"` // 分类名称 - Count uint32 `json:"count"` // 销售数量 + Count int32 `json:"count"` // 销售数量 SalesAmount float64 `json:"sales_amount"` // 销售/退货金额 SalesCost float64 `json:"sales_cost"` // 销售成本:销售采购价之和 SalesMargin float64 `json:"sales_margin"` // 销售毛利:销售/退货金额-销售成本 @@ -430,8 +433,8 @@ func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) { } qs := orm.Eloquent.Table("erp_order") - if showConfig.ShowAll == "OFF" { - qs = qs.Where("invoice_code != ?", 0) + if showConfig.ShowAll == "OFF" { // 关闭后未开小票的零售销售订单隐藏 + qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected) } if m.BillSn != "" { qs = qs.Where("bill_sn=?", m.BillSn) @@ -449,7 +452,7 @@ func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) { qs = qs.Where("store_id=?", m.StoreId) } if m.Salesman != 0 { - qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"uid":%d}`, m.Salesman)) + qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"userId":%d}`, m.Salesman)) } if m.PayStatus != 0 { qs = qs.Where("pay_status=?", m.PayStatus) @@ -457,20 +460,35 @@ func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) { if m.State != "" { qs = qs.Where("state=?", m.State) } - if m.StartTime != "" { - parse, err := time.Parse(QueryTimeFormat, m.StartTime) + if m.MakeTimeStart != "" { + parse, err := time.Parse(QueryTimeFormat, m.MakeTimeStart) if err != nil { logger.Errorf("err:", err) } - qs = qs.Where("created_at > ?", parse) + qs = qs.Where("maker_time > ?", parse) } - if m.EndTime != "" { - parse, err := time.Parse(QueryTimeFormat, m.EndTime) + if m.MakeTimeEnd != "" { + parse, err := time.Parse(QueryTimeFormat, m.MakeTimeEnd) if err != nil { logger.Errorf("err:", err) } - parse = parse.AddDate(0, 0, 1) - qs = qs.Where("created_at < ?", parse) + //parse = parse.AddDate(0, 0, 1) + qs = qs.Where("maker_time < ?", parse) + } + if m.AuditTimeStart != "" { + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) + if err != nil { + logger.Errorf("err:", err) + } + qs = qs.Where("audit_time > ?", parse) + } + if m.AuditTimeEnd != "" { + parse, err := time.Parse(QueryTimeFormat, m.AuditTimeEnd) + if err != nil { + logger.Errorf("err:", err) + } + //parse = parse.AddDate(0, 0, 1) + qs = qs.Where("audit_time < ?", parse) } } @@ -507,7 +525,7 @@ func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) { func QueryListByScanCode(scanCode, showConfig string) (*ErpOrderListResp, error) { resp := &ErpOrderListResp{} - var commodity ErpOrderCommodity + var commodity []ErpOrderCommodity err := orm.Eloquent.Table("erp_order_commodity").Where("imei = ?", scanCode).Find(&commodity).Error if err != nil && err != RecordNotFound { logger.Error("get erp_order_commodity err:", logger.Field("err", err)) @@ -515,14 +533,22 @@ func QueryListByScanCode(scanCode, showConfig string) (*ErpOrderListResp, error) } var orders []ErpOrder - if showConfig == "OFF" { - err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ? and invoice_code != ?", commodity.ErpOrderId, HavePaid, 0).Find(&orders).Error - } else { - err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ?", commodity.ErpOrderId, HavePaid).Find(&orders).Error - } - if err != nil && err != RecordNotFound { - logger.Error("get erp_order err:", logger.Field("err", err)) - return resp, err + for _, item := range commodity { + if showConfig == "OFF" { + err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ? and is_print != ?", item.ErpOrderId, HavePaid, NoPrint).Find(&orders).Error + } else { + err = orm.Eloquent.Table("erp_order").Where("id = ? and pay_status = ?", item.ErpOrderId, HavePaid).Find(&orders).Error + } + if err != nil && err != RecordNotFound { + logger.Error("get erp_order err:", logger.Field("err", err)) + return resp, err + } + + if len(orders) == 0 { + continue + } else { + break + } } // 添加付款、销售员、商品信息 @@ -604,6 +630,71 @@ func QueryListByCommodityName(req *ErpOrderListReq, showConfig string) (*ErpOrde return resp, nil } +// 数组转字符串 +func intArrayToString(arr []uint32) string { + var strArr []string + for _, num := range arr { + strArr = append(strArr, fmt.Sprintf("%d", num)) + } + return strings.Join(strArr, ",") +} + +// 字符串转数组 +func stringToIntArray(str string) ([]uint32, error) { + var arr []uint32 + strArr := strings.Split(str, ",") + for _, s := range strArr { + num, err := strconv.Atoi(s) + if err != nil { + return nil, err + } + arr = append(arr, uint32(num)) + } + return arr, nil +} + +// 更新零售订单商品表的库存商品表主键id字段 +func updateErpStockCommodityID(gdb *gorm.DB, id uint32, nIdList []uint32) error { + strId := intArrayToString(nIdList) + err := gdb.Table("erp_order_commodity").Where("id = ?", id). + Update("erp_stock_commodity_id", strId).Error + if err != nil { + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + + return nil +} + +// 找一个可用的库存商品表主键ID +func findRightErpStockCommodityId(idList map[uint32][]uint32, commodityId uint32, stockCommodity []ErpStockCommodity) (uint32, error) { + // 获取给定商品ID对应的ID列表 + existingIds, ok := idList[commodityId] + if !ok || len(existingIds) == 0 { + // 如果对应的ID列表不存在或为空,直接返回第一个库存商品的ID + if len(stockCommodity) > 0 { + return stockCommodity[0].ID, nil + } + return 0, fmt.Errorf("empty stock commodity list") + } + + // 创建一个 map 用于快速查找已有的 ID + existingIdMap := make(map[uint32]bool) + for _, id := range existingIds { + existingIdMap[id] = true + } + + // 遍历库存商品,找到第一个不在已有ID列表中的ID并返回 + for _, item := range stockCommodity { + if _, found := existingIdMap[item.ID]; !found { + return item.ID, nil + } + } + + // 如果所有库存商品的ID都在已有的ID列表中,则返回错误 + return 0, fmt.Errorf("no available ID found for commodity ID: %d", commodityId) +} + // UpdateStock 扣减or添加库存 // 零售订单: // 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"已售"; @@ -622,6 +713,8 @@ func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error { return err } + usedStockCommodityIdList := make(map[uint32][]uint32) // 记录非串码商品已使用的商品库存表主键id + if erpOrder.RetailType == RetailTypeSale { // 零售订单 for i, _ := range commodities { if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品 @@ -647,33 +740,52 @@ func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error { } } else { // 非串码商品 var stockCommodity []ErpStockCommodity - // 通过门店id,商品id,查找状态为1-在库的非串码商品 - err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ - "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 1, 1). - Order("id DESC").Find(&stockCommodity).Error - if err != nil { - logger.Error("commodities err:", logger.Field("err", err)) - return err - } - if stockCommodity == nil || len(stockCommodity) == 0 { - return errors.New("find commodity no stock ") - } - - err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). - Update("state", state).Error // 状态更新为销售锁定中 - if err != nil { - logger.Error("commodities err:", logger.Field("err", err)) - return err - } - - if state == SoldOut { // 已售的订单才更新库存数量 - err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", - erpOrder.StoreId, commodities[i].ErpCommodityId). - Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 + // 添加的一条零售商品包含的非串码商品可能不止1个 + var stockCommodityIdList []uint32 + for j := 0; j < int(commodities[i].Count); j++ { + // 通过门店id,商品id,查找状态为1-在库的非串码商品 + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ + "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 1, 1). + Order("first_stock_time ASC").Find(&stockCommodity).Error if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } + if stockCommodity == nil || len(stockCommodity) == 0 { + return errors.New("find commodity no stock ") + } + + // 找一个可用的库存商品表主键ID + rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList, + commodities[i].ErpCommodityId, stockCommodity) + if err != nil { + return err + } + + // 优先出库库存时间最长的数据 + err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId). + Update("state", state).Error // 状态更新为销售锁定中 + if err != nil { + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + + if state == SoldOut { // 已售的订单才更新库存数量 + err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", + erpOrder.StoreId, commodities[i].ErpCommodityId). + Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 + if err != nil { + logger.Error("commodities err:", logger.Field("err", err)) + return err + } + } + stockCommodityIdList = append(stockCommodityIdList, rightId) + usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId) + } + + err = updateErpStockCommodityID(gdb, commodities[i].ID, stockCommodityIdList) + if err != nil { + return err } } } @@ -700,30 +812,47 @@ func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error { } } else { // 非串码商品 var stockCommodity []ErpStockCommodity - // 通过门店id,商品id,查找状态为2-已售的非串码商品 - err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ - "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 2, 1). - Order("id DESC").Find(&stockCommodity).Error - if err != nil { - logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) - return err - } - if stockCommodity == nil { - return errors.New("RetailTypeRejected find no stock commodity") - } + var stockCommodityIdList []uint32 + // 添加的一条零售商品包含的非串码商品可能不止1个 + for j := 0; j < int(commodities[i].Count); j++ { + // 通过门店id,商品id,查找状态为2-已售的非串码商品 + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ + "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 2, 1). + Order("first_stock_time DESC").Find(&stockCommodity).Error + if err != nil { + logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) + return err + } + if stockCommodity == nil { + return errors.New("RetailTypeRejected find no stock commodity") + } - err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). - Update("state", InStock).Error // 状态更新为在库 - if err != nil { - logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) - return err - } + // 找一个可用的库存商品表主键ID + rightId, err := findRightErpStockCommodityId(usedStockCommodityIdList, + commodities[i].ErpCommodityId, stockCommodity) + if err != nil { + return err + } - err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", - erpOrder.StoreId, commodities[i].ErpCommodityId). - Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1 + err = gdb.Table("erp_stock_commodity").Where("id = ?", rightId). + Update("state", InStock).Error // 状态更新为在库 + if err != nil { + logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) + return err + } + + err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", + erpOrder.StoreId, commodities[i].ErpCommodityId). + Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1 + if err != nil { + logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) + return err + } + stockCommodityIdList = append(stockCommodityIdList, rightId) + usedStockCommodityIdList[commodities[i].ID] = append(usedStockCommodityIdList[commodities[i].ID], rightId) + } + err = updateErpStockCommodityID(gdb, commodities[i].ID, stockCommodityIdList) if err != nil { - logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } @@ -732,23 +861,32 @@ func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error { return errors.New("订单类型错误") } - // 更新用户积分 - var vmCount int - var describe, event string - if erpOrder.RetailType == RetailTypeSale && state == SoldOut { // 零售订单,而且订单已支付,更新用户积分 - describe = "零售销售获得积分" - event = VmEventErpOrderSale - vmCount = tools.RoundFloat64(erpOrder.TotalAmount) - } else if erpOrder.RetailType == RetailTypeRejected { // 退货订单,扣减用户积分 - describe = "零售退货扣除积分" - event = VmEventErpOrderReject - vmCount = 0 - tools.RoundFloat64(erpOrder.TotalAmount) + // 判断用户是不是会员,只有会员才会积分,否则不积分 + userInfo, err := GetUserInfoByUid(uint32(erpOrder.Uid)) + if err != nil { + logger.Error("UpdateStock GetUserInfoByUid err:", logger.Field("err", err)) + return err } - err = UserVmUpdate(gdb, uint32(erpOrder.Uid), vmCount, event, describe) - if err != nil { - logger.Errorf("err:", err) - return err + if IsInMemberLevels(userInfo.MemberLevel) { + // 更新用户积分 + var vmCount int + var describe, event string + if erpOrder.RetailType == RetailTypeSale && state == SoldOut { // 零售订单,而且订单已支付,更新用户积分 + describe = "零售销售获得积分" + event = VmEventErpOrderSale + vmCount = tools.RoundFloat64(erpOrder.TotalAmount) + } else if erpOrder.RetailType == RetailTypeRejected { // 退货订单,扣减用户积分 + describe = "零售退货扣除积分" + event = VmEventErpOrderReject + vmCount = 0 - tools.RoundFloat64(erpOrder.TotalAmount) + } + + err = UserVmUpdate(gdb, uint32(erpOrder.Uid), vmCount, event, describe) + if err != nil { + logger.Errorf("err:", err) + return err + } } return nil @@ -788,6 +926,64 @@ func NewErpBillSn() string { } } +// ErpOrderRetailDetailSetCommodity 添加零售明细中订单的商品信息 +func ErpOrderRetailDetailSetCommodity(list []ErpOrder) { + for i, _ := range list { + list[i].SetRetailDetailCommodity() + } +} + +func (m *ErpOrder) SetRetailDetailCommodity() { + var orderCommodities []ErpOrderCommodity + err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", m.ID).Find(&orderCommodities).Error + if err != nil { + logger.Error("SetCommodity query erp_order_commodity err:", logger.Field("err", err)) + } + + var respOrderCommodities []ErpOrderCommodity + for _, item := range orderCommodities { + if item.IMEIType == 2 || item.IMEIType == 3 || item.IMEI != "" { // 串码 + respOrderCommodities = append(respOrderCommodities, item) + } else { // 非串码 + idList, err := stringToIntArray(item.ErpStockCommodityID) + if err != nil { + respOrderCommodities = append(respOrderCommodities, item) + continue + } + + for _, stockCommodityId := range idList { + var orderCommodity ErpOrderCommodity + orderCommodity = item + orderCommodity.Count = 1 + orderCommodity.SaleDiscount = item.SaleDiscount / float64(item.Count) + //orderCommodity.MemberDiscount = item.MemberDiscount / float64(item.Count) + orderCommodity.VmDiscount = item.VmDiscount / float64(item.Count) + orderCommodity.ReceivedAmount = item.ReceivedAmount / float64(item.Count) + orderCommodity.RejectedAmount = item.RejectedAmount / float64(item.Count) + orderCommodity.SalesProfit = item.SalesProfit / float64(item.Count) + orderCommodity.StaffProfit = item.StaffProfit / float64(item.Count) + + // 查询库存商品信息 + var stockCommodity ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity"). + Where("id = ?", stockCommodityId).Find(&stockCommodity).Error + if err != nil { + respOrderCommodities = append(respOrderCommodities, item) + continue + } + + orderCommodity.ErpSupplierId = stockCommodity.ErpSupplierId + orderCommodity.ErpSupplierName = stockCommodity.ErpSupplierName + orderCommodity.WholesalePrice = stockCommodity.WholesalePrice + orderCommodity.StaffCostPrice = stockCommodity.StaffCostPrice + respOrderCommodities = append(respOrderCommodities, orderCommodity) + } + } + } + + m.Commodities = respOrderCommodities +} + // 添加订单的商品信息 func erpOrderListSetCommodity(list []ErpOrder) { for i, _ := range list { @@ -838,7 +1034,7 @@ func (m *ErpOrder) SetOrderSalesman() error { item.StaffProfitPer = staffProfit / float64(len(salesmanInfo)) // 获取员工毛利 - userInfo, err := GetSysUserInfoByUid(item.Uid) + userInfo, err := GetSysUserInfoById(item.Uid) if err != nil { logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err)) } @@ -892,7 +1088,7 @@ func (m *ErpOrderCreateReq) GetSalesmanList() (string, error) { item.StaffProfitPer = staffProfit / float64(len(m.Salesman)) // 获取员工毛利 - userInfo, err := GetSysUserInfoByUid(item.Uid) + userInfo, err := GetSysUserInfoById(item.Uid) if err != nil { logger.Error("GetSysUserInfoByUid err:", logger.Field("err", err)) } @@ -955,7 +1151,7 @@ func SetUserInfo(tel string) { logger.Error("user err:", logger.Field("err", err)) return } - if user.FirstRetailOrder != nil { + if user.FirstRetailOrder == nil { err := orm.Eloquent.Table("user").Where("uid=?", user.Uid).Update("first_retail_order", time.Now()).Error if err != nil { logger.Error("update user err:", logger.Field("err", err)) @@ -1427,7 +1623,7 @@ func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManage qs = qs.Where("store_id = ?", req.StoreId) } if showConfig.ShowAll == "OFF" { - qs = qs.Where("invoice_code != ?", 0) + qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected) } if req.StartTime != "" && req.EndTime != "" { @@ -1720,7 +1916,7 @@ func QueryRetailMargin(req *ErpOrderRetailMarginReq) (*ErpOrderRetailMarginResp, } } if showConfig.ShowAll == "OFF" { - qs = qs.Where("erp_order.invoice_code != ?", 0) + qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected) } var result []struct { @@ -1729,11 +1925,10 @@ func QueryRetailMargin(req *ErpOrderRetailMarginReq) (*ErpOrderRetailMarginResp, StoreName string RetailType string } - qs.Where("erp_order.pay_status = ?", HavePaid) - es := qs - + qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)", + HavePaid, RetailTypeRejected, ErpOrderStateUnAudit) // 添加排序规则 - qs = qs.Order("erp_order.retail_type ASC, erp_order_commodity.erp_commodity_id ASC, erp_order.store_id ASC") + qs = qs.Order("erp_order_commodity.erp_commodity_id ASC, erp_order.store_id ASC, erp_order.retail_type ASC") if req.IsExport == 1 { //导出excel err := qs.Find(&result).Error @@ -1741,91 +1936,130 @@ func QueryRetailMargin(req *ErpOrderRetailMarginReq) (*ErpOrderRetailMarginResp, logger.Errorf("QueryRetailMargin find err:", err.Error()) return nil, err } - var data RetailMarginData - var list []RetailMarginData - for _, item := range result { - data.StoreId = item.StoreID - data.StoreName = item.StoreName - data.RetailType = item.RetailType - data.ErpCommodityId = item.ErpCommodityId - data.ErpCommodityName = item.ErpCommodityName - data.ErpCategoryId = item.ErpCategoryId - data.ErpCategoryName = item.ErpCategoryName - data.Count = item.Count - data.SalesAmount = item.ReceivedAmount - data.SalesCost = float64(item.WholesalePrice * item.Count) - data.SalesMargin = data.SalesAmount - data.SalesCost - data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount) - if data.RetailType == RetailTypeRejected { - data.SalesAmount = -data.SalesAmount - data.SalesCost = -data.SalesCost - data.SalesMargin = -data.SalesMargin - } - list = append(list, data) - resp.List = list - resp.TotalCount += data.Count - resp.TotalSalesAmount += data.SalesAmount - resp.TotalSalesCost += data.SalesCost - resp.TotalSalesMargin += data.SalesMargin - } - - if resp.TotalSalesAmount != 0 { - resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount) - } - - filePath, err := retailMarginDataExport(resp) - if err != nil { - logger.Error("StoreManageDataExport err:", logger.Field("err", err)) - return nil, err - } - - resp.ExportUrl = filePath } else { err := qs.Find(&result).Offset(page * req.PageSize).Limit(req.PageSize).Error if err != nil { logger.Errorf("QueryRetailMargin find err:", err.Error()) return nil, err } + } - var count int64 - err = es.Count(&count).Error - if err != nil { - logger.Errorf("QueryRetailMargin count err:", err.Error()) - return nil, err + //var data RetailMarginData + var list []RetailMarginData + //for _, item := range result { + // data.StoreId = item.StoreID + // data.StoreName = item.StoreName + // data.RetailType = item.RetailType + // data.ErpCommodityId = item.ErpCommodityId + // data.ErpCommodityName = item.ErpCommodityName + // data.ErpCategoryId = item.ErpCategoryId + // data.ErpCategoryName = item.ErpCategoryName + // data.Count = item.Count + // data.SalesAmount = item.ReceivedAmount + // data.SalesCost = float64(item.WholesalePrice * item.Count) + // data.SalesMargin = data.SalesAmount - data.SalesCost + // data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount) + // if data.RetailType == RetailTypeRejected { + // data.SalesAmount = -data.SalesAmount + // data.SalesCost = -data.SalesCost + // data.SalesMargin = -data.SalesMargin + // } + // list = append(list, data) + // + // resp.TotalCount += data.Count + // resp.TotalSalesAmount += data.SalesAmount + // resp.TotalSalesCost += data.SalesCost + // resp.TotalSalesMargin += data.SalesMargin + //} + // + //if resp.TotalSalesAmount != 0 { + // resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount) + //} + + // 创建一个 map 用来存储已经处理过的数据,key 是 StoreId 和 ErpCommodityId 的组合 + processedData := make(map[string]*RetailMarginData) + + // 遍历 result 中的每一条数据 + for _, item := range result { + // 生成一个唯一的键,可以使用 StoreId 和 ErpCommodityId 的组合 + key := fmt.Sprintf("%d_%d_%s", item.StoreID, item.ErpCommodityId, item.RetailType) + + var nCount int32 + if item.RetailType == RetailTypeRejected { + nCount = -int32(item.Count) + } else { + nCount = int32(item.Count) } + // 检查是否已经处理过这个组合的数据 + if existingData, ok := processedData[key]; ok { + // 如果存在,说明已经有数据,进行合并操作 + existingData.Count += nCount + existingData.SalesAmount += item.ReceivedAmount + existingData.SalesCost += float64(item.WholesalePrice * item.Count) + existingData.SalesMargin = existingData.SalesAmount - existingData.SalesCost + existingData.GrossMargins = float64ToPercentage(existingData.SalesMargin / existingData.SalesAmount) - var data RetailMarginData - var list []RetailMarginData - for _, item := range result { - data.StoreId = item.StoreID - data.StoreName = item.StoreName - data.RetailType = item.RetailType - data.ErpCommodityId = item.ErpCommodityId - data.ErpCommodityName = item.ErpCommodityName - data.ErpCategoryId = item.ErpCategoryId - data.ErpCategoryName = item.ErpCategoryName - data.Count = item.Count - data.SalesAmount = item.ReceivedAmount - data.SalesCost = float64(item.WholesalePrice * item.Count) - data.SalesMargin = data.SalesAmount - data.SalesCost - data.GrossMargins = float64ToPercentage(data.SalesMargin / data.SalesAmount) + // 如果是拒绝的销售,进行相应的处理 + if existingData.RetailType == RetailTypeRejected { + existingData.SalesAmount = -existingData.SalesAmount + existingData.SalesCost = -existingData.SalesCost + existingData.SalesMargin = -existingData.SalesMargin + } + } else { + // 如果不存在,说明是新数据,直接添加到列表中 + data := &RetailMarginData{ + StoreId: item.StoreID, + StoreName: item.StoreName, + RetailType: item.RetailType, + ErpCommodityId: item.ErpCommodityId, + ErpCommodityName: item.ErpCommodityName, + ErpCategoryId: item.ErpCategoryId, + ErpCategoryName: item.ErpCategoryName, + Count: nCount, + SalesAmount: item.ReceivedAmount, + SalesCost: float64(item.WholesalePrice * item.Count), + SalesMargin: item.ReceivedAmount - float64(item.WholesalePrice*item.Count), + GrossMargins: float64ToPercentage((item.ReceivedAmount - float64(item.WholesalePrice*item.Count)) / item.ReceivedAmount), + } + + // 如果是拒绝的销售,进行相应的处理 if data.RetailType == RetailTypeRejected { data.SalesAmount = -data.SalesAmount data.SalesCost = -data.SalesCost data.SalesMargin = -data.SalesMargin } - list = append(list, data) - resp.TotalCount += data.Count - resp.TotalSalesAmount += data.SalesAmount - resp.TotalSalesCost += data.SalesCost - resp.TotalSalesMargin += data.SalesMargin - } - if resp.TotalSalesAmount != 0 { - resp.TotalGrossMargins = float64ToPercentage(resp.TotalSalesMargin / resp.TotalSalesAmount) - } + // 将新数据添加到 map 中 + processedData[key] = data + } + } + + // 将处理过的数据添加到 resp.List 中 + for _, data := range processedData { + list = append(list, *data) + } + + // 计算总数 + for _, data := range list { + resp.TotalCount += data.Count + resp.TotalSalesAmount += data.SalesAmount + resp.TotalSalesCost += data.SalesCost + resp.TotalSalesMargin += data.SalesMargin + } + + // 将结果赋值给 resp.List + resp.List = list + + if req.IsExport == 1 { //导出excel + filePath, err := retailMarginDataExport(resp) + if err != nil { + logger.Error("StoreManageDataExport err:", logger.Field("err", err)) + return nil, err + } + resp.ExportUrl = filePath + } else { resp.List = list - resp.Total = int(count) + resp.Total = len(resp.List) resp.PageIndex = req.PageIndex resp.PageSize = req.PageSize } @@ -2168,13 +2402,14 @@ func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai if err != nil { logger.Errorf("err:", err) } - parse = parse.AddDate(0, 0, 1) + //parse = parse.AddDate(0, 0, 1) qs = qs.Where("erp_order.audit_time < ?", parse) } if showConfig.ShowAll == "OFF" { - qs = qs.Where("erp_order.invoice_code != ?", 0) + qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected) } - qs.Where("erp_order.pay_status = ?", HavePaid) + qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)", + HavePaid, RetailTypeRejected, ErpOrderStateUnAudit) es := qs var sumData RetailDetailTotalData @@ -2310,6 +2545,8 @@ func packData(result []RetailDetailByJoin) []ErpOrder { order = orderIdMap[item.ErpOrderId] } else { // 订单数据 + order.CreatedAt = item.ErpOrderCommodity.CreatedAt + order.ID = item.ErpOrderId order.BillSn = item.BillSn order.RetailType = item.RetailType order.Uid = item.Uid @@ -2343,6 +2580,7 @@ func packData(result []RetailDetailByJoin) []ErpOrder { } // 订单商品数据 + commodity.CreatedAt = item.ErpOrderCommodity.CreatedAt commodity.ErpOrderId = item.ErpOrderId commodity.ErpCategoryId = item.ErpCategoryId commodity.ErpCategoryName = item.ErpCategoryName @@ -2405,7 +2643,7 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai qs := orm.Eloquent.Table("erp_order") if showConfig.ShowAll == "OFF" { - qs = qs.Where("invoice_code != ?", 0) + qs = qs.Where("is_print = ? or retail_type = ?", HavePrinted, RetailTypeRejected) } if req.BillSn != "" { // 订单编号 qs = qs.Where("bill_sn=?", req.BillSn) @@ -2437,11 +2675,12 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai if err != nil { logger.Errorf("err:", err) } - parse = parse.AddDate(0, 0, 1) + //parse = parse.AddDate(0, 0, 1) qs = qs.Where("audit_time < ?", parse) } } - qs.Where("erp_order.pay_status = ?", HavePaid) + qs.Where("erp_order.pay_status = ? or (erp_order.retail_type = ? and erp_order.state != ?)", + HavePaid, RetailTypeRejected, ErpOrderStateUnAudit) es := qs var sumData RetailDetailTotalData @@ -2512,7 +2751,7 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai logger.Error("erp commodity list err:", logger.Field("err", err)) return resp, err } - erpOrderListSetCommodity(orders) + ErpOrderRetailDetailSetCommodity(orders) erpOrderListSetSalesman(orders) fileUrl, err := retailDetailExport(orders, sumData) @@ -2537,7 +2776,7 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai } // 添加付款、销售员、商品信息 - erpOrderListSetCommodity(orders) + ErpOrderRetailDetailSetCommodity(orders) erpOrderListSetCashier(orders) erpOrderListSetSalesman(orders) @@ -2579,6 +2818,23 @@ func QueryReceiptData(req *ErpOrderDeleteReq) (*ErpOrderReceiptDataResp, error) return nil, err } + // 记录打印信息 + if orders[0].IsPrint != HavePrinted { + err = orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Updates(map[string]interface{}{ + "is_print": HavePrinted, + }).Error + if err != nil { + return nil, err + } + } + + err = orm.Eloquent.Model(&ErpOrder{}). + Where("bill_sn = ? ", req.BillSn). + UpdateColumn("print_count", gorm.Expr("print_count + ?", 1)).Error + if err != nil { + return nil, err + } + order := orders[0] resp := new(ErpOrderReceiptDataResp) resp.StoreName = order.StoreName @@ -2644,9 +2900,9 @@ func CreateErpOrder(req *ErpOrderCreateReq, sysUser *SysUser) error { Uid: uint32(erpOrder.Uid), Tel: req.Tel, StoreId: uint64(req.StoreId), - UserType: 1, // 用户 - OpenMemberLevel: 1, // 普通会员 - MemberLevel: 1, // 普通会员 + UserType: UserTypeConsumer, // 用户 + OpenMemberLevel: MemberLevelConsumer, // 普通用户 + MemberLevel: MemberLevelConsumer, // 普通用户 } err = begin.Create(&user).Error if err != nil { @@ -2790,6 +3046,14 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) return nil, errors.New("操作失败:" + err.Error()) } + if req.RetailType == RetailTypeSale { + // 校验商品是否有库存 + err = checkOrderCommodityStock(req) + if err != nil { + return nil, err + } + } + // 通过手机号查询用户id,如果没有,则新建一个用户id userInfo, err := GetUserInfoByTel(req.Tel) if err != nil { @@ -2883,7 +3147,7 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) if req.RetailType == RetailTypeRejected { // 零售退货订单,查零售商品表 ids := make([]uint32, 0, len(req.ErpOrderCommodities)) for i, _ := range req.ErpOrderCommodities { - ids = append(ids, req.ErpOrderCommodities[i].RejectedOrderCommodityId) + ids = append(ids, req.ErpOrderCommodities[i].ErpCommodityId) } orderCommodityMap, err = GetErpOrderCommodityMap(ids) if err != nil { @@ -2893,13 +3157,13 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) } // 校验商品相关金额是否符合要求 - for i, item := range req.ErpOrderCommodities { + for i, _ := range req.ErpOrderCommodities { if req.RetailType == RetailTypeRejected { // 零售退货订单 - if item.RejectedOrderCommodityId == 0 { - logger.Error("rejected_order_commodity_id is null") - return nil, errors.New("rejected_order_commodity_id is null") - } - v, ok := orderCommodityMap[req.ErpOrderCommodities[i].RejectedOrderCommodityId] + //if item.RejectedOrderCommodityId == 0 { + // logger.Error("rejected_order_commodity_id is null") + // return nil, errors.New("rejected_order_commodity_id is null") + //} + v, ok := orderCommodityMap[req.ErpOrderCommodities[i].ErpCommodityId] if ok { v.RejectedPrice = req.ErpOrderCommodities[i].RejectedPrice // 退货单价 v.RejectedCount = req.ErpOrderCommodities[i].RejectedCount @@ -2928,18 +3192,18 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) erpOrder.TotalAmount += req.ErpOrderCommodities[i].ReceivedAmount erpOrder.TotalCount += req.ErpOrderCommodities[i].Count - // 销售毛利 // todo 待测试核实 + // 销售毛利 // todo 待测试核实 备注:产品说有亏本销售的情况,不用判断毛利是否<0 salesProfit := v.ReceivedAmount - float64(v.WholesalePrice*v.Count) - if salesProfit < 0 { - logger.Error("rejected salesProfit less than 0") - return nil, errors.New("商品销售毛利小于0,请检查") - } + //if salesProfit < 0 { + // logger.Error("rejected salesProfit less than 0") + // return nil, errors.New("商品销售毛利小于0,请检查") + //} // 员工毛利 // todo 待测试核实 StaffProfit := salesProfit - float64(v.StaffCostPrice*v.Count) - if StaffProfit < 0 { - logger.Error("rejected TotalStaffProfit less than 0") - return nil, errors.New("商品员工毛利小于0,请检查") - } + //if StaffProfit < 0 { + // logger.Error("rejected TotalStaffProfit less than 0") + // return nil, errors.New("商品员工毛利小于0,请检查") + //} req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利 req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利 @@ -2991,19 +3255,19 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) // 更新订单表总金额和数量 erpOrder.TotalAmount += req.ErpOrderCommodities[i].ReceivedAmount erpOrder.TotalCount += req.ErpOrderCommodities[i].Count - // 销售毛利 + // 销售毛利 备注:产品说有亏本销售的情况,不用判断毛利是否<0 salesProfit := req.ErpOrderCommodities[i].ReceivedAmount - float64(req.ErpOrderCommodities[i].WholesalePrice*req.ErpOrderCommodities[i].Count) - if salesProfit < 0 { - logger.Error("salesProfit less than 0") - return nil, errors.New("商品销售毛利小于0,请检查") - } + //if salesProfit < 0 { + // logger.Error("salesProfit less than 0") + // return nil, errors.New("商品销售毛利小于0,请检查") + //} // 员工毛利 StaffProfit := salesProfit - float64(req.ErpOrderCommodities[i].StaffCostPrice*req.ErpOrderCommodities[i].Count) - if StaffProfit < 0 { - logger.Error("TotalStaffProfit less than 0") - return nil, errors.New("商品员工毛利小于0,请检查") - } + //if StaffProfit < 0 { + // logger.Error("TotalStaffProfit less than 0") + // return nil, errors.New("商品员工毛利小于0,请检查") + //} req.ErpOrderCommodities[i].SalesProfit = salesProfit // 销售毛利 req.ErpOrderCommodities[i].StaffProfit = StaffProfit // 员工毛利 erpOrder.TotalSalesProfit += salesProfit @@ -3023,7 +3287,7 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) if err != nil { return nil, errors.New("操作失败:" + err.Error()) } - erpOrder.StorePer = erpOrder.TotalStaffProfit * store.SalesCommRate + erpOrder.StorePer = erpOrder.TotalStaffProfit * (store.SalesCommRate / 100) // 订单总优惠 erpOrder.TotalDiscount = erpOrder.TotalRetailPrice - erpOrder.TotalAmount @@ -3031,6 +3295,70 @@ func checkOrderData(req *ErpOrderCreateReq, sysUser *SysUser) (*ErpOrder, error) return erpOrder, nil } +// 校验商品是否有库存 +func checkOrderCommodityStock(req *ErpOrderCreateReq) error { + if len(req.ErpOrderCommodities) != 0 { + // 统计串码和非串码商品信息 + commodityMap := make(map[uint32]uint32) // 记录非串码商品id及其数量 + imeiCommodityMap := make(map[uint32]string) // 记录串码商品id及其串码 + commodityNameMap := make(map[uint32]string) // 记录商品名称 + for _, commodity := range req.ErpOrderCommodities { + if commodity.IMEIType == 1 { + _, ok := commodityMap[commodity.ErpCommodityId] + if !ok { // 没有则直接添加 + commodityMap[commodity.ErpCommodityId] = commodity.Count + } else { + commodityMap[commodity.ErpCommodityId] += commodity.Count + } + commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName + } else { + imeiCommodityMap[commodity.ErpCommodityId] = commodity.IMEI + commodityNameMap[commodity.ErpCommodityId] = commodity.ErpCommodityName + } + } + + // 查询库存表,确认是否有库存 + if len(commodityMap) != 0 { // 查询非串码商品库存 + var count int64 + for commodityId, nCount := range commodityMap { + err := orm.Eloquent.Table("erp_stock_commodity"). + Where("erp_commodity_id = ? and store_id = ? and state = ? and imei_type = ?", + commodityId, req.StoreId, InStock, NoIMEICommodity). + Count(&count).Error + if err != nil { + return err + } + + if count < int64(nCount) { + // 获取商品名称 + return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足") + } + } + } + + if len(imeiCommodityMap) != 0 { // 查询串码商品库存 + var count int64 + for commodityId, imei := range imeiCommodityMap { + err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ? and state = ?", imei, InStock). + Count(&count).Error + if err != nil { + return err + } + + if count == 0 { + // 获取商品名称 + return errors.New("商品" + "[" + commodityNameMap[commodityId] + "]库存不足") + } + } + } + + } else { + return errors.New("该零售订单未添加商品") + } + + return nil +} + // updateCommodityData 更新订单商品信息 func updateCommodityData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error { // 查询现有的零售订单信息 @@ -3129,6 +3457,8 @@ func updateSalesData(gdb *gorm.DB, orderId uint32, req *ErpOrderCreateReq) error } } if !found { + reqSales.ID = 0 + reqSales.CreatedAt = Now() newOrderSales = append(newOrderSales, reqSales) } } diff --git a/app/admin/models/file.go b/app/admin/models/file.go index 285ebb7..460b59d 100644 --- a/app/admin/models/file.go +++ b/app/admin/models/file.go @@ -291,19 +291,99 @@ func checkCategoryExcel(sheetCols [][]string) error { return nil } -// 校验名称是否相同,有则false -func hasDuplicateNames(sheetCols [][]string) (string, bool) { - nameMap := make(map[string]struct{}) +//// 校验名称是否相同,有则false +//func hasDuplicateNames(sheetCols [][]string) (string, bool) { +// nameMap := make(map[string]struct{}) +// +// for _, col := range sheetCols { +// for _, name := range col { +// if _, exists := nameMap[name]; exists && name != "" { +// // 有重复的名称 +// return name, true +// } +// nameMap[name] = struct{}{} +// } +// } +// // 没有重复的名称 +// return "", false +//} +//// 校验名称是否相同,有则返回true和重复的名称,备注:只能校验不同的列中不能有重复数据,如:第一列的123,第二列不能有123 +//func hasDuplicateNames(sheetCols [][]string) (string, bool) { +// globalMap := make(map[string]struct{}) +// +// for _, col := range sheetCols { +// colMap := make(map[string]struct{}) +// for _, name := range col { +// // 忽略空名称 +// if name == "" { +// continue +// } +// +// // 检查全局map中是否已存在 +// if _, exists := globalMap[name]; exists { +// return name, true +// } +// +// // 将名称添加到当前列map中 +// colMap[name] = struct{}{} +// } +// +// // 将当前列map中的元素添加到全局map中 +// for name := range colMap { +// globalMap[name] = struct{}{} +// } +// } +// +// // 没有重复的名称 +// return "", false +//} + +// 校验名称是否相同,有则返回true和重复的名称 +// 第二列数据如果重复,需要看第一列同一行的数据是否相同,如果不同则报错。 +// 第三列数据不能有重复的名称 +func hasDuplicateNames(sheetCols [][]string) (string, bool) { + //firstColMap := make(map[string]bool) + secondColMap := make(map[string]string) // Map记录第二列数据的重复情况,以及对应第一列的数据 + thirdColMap := make(map[string]bool) + + // 确保每一列数据都有相同数量的行数 + rowsCount := len(sheetCols[0]) for _, col := range sheetCols { - for _, name := range col { - if _, exists := nameMap[name]; exists && name != "" { - // 有重复的名称 - return name, true - } - nameMap[name] = struct{}{} + if len(col) != rowsCount { + return "每列数据的行数不一致", true } } + + for i := 0; i < rowsCount; i++ { + //// 检查第一列 + //firstColName := sheetCols[0][i] + //if firstColName != "" { + // if _, exists := firstColMap[firstColName]; exists { + // return firstColName, true + // } + // firstColMap[firstColName] = true + //} + + // 检查第二列 + secondColName := sheetCols[1][i] + if secondColName != "" { + if firstCol, exists := secondColMap[secondColName]; exists && firstCol != sheetCols[0][i] { + return secondColName, true + } + secondColMap[secondColName] = sheetCols[0][i] + } + + // 检查第三列 + thirdColName := sheetCols[2][i] + if thirdColName != "" { + if _, exists := thirdColMap[thirdColName]; exists { + return thirdColName, true + } + thirdColMap[thirdColName] = true + } + } + // 没有重复的名称 return "", false } @@ -753,16 +833,31 @@ func ImportCategoryData(colsMap []map[string]interface{}, businessId uint32) err // 判断是否存在重复数据 func hasDuplicateInDb(data []CategoryExcel) (string, bool) { for _, item := range data { - if exists := isCategoryExists(item.FirstCategory); exists { - return item.FirstCategory, true + // 判断是导入几级分类 + nType := 0 + if item.ThreeCategory != "" && item.SecondCategory != "" && item.FirstCategory != "" { + nType = 3 + } else if item.ThreeCategory == "" && item.SecondCategory != "" && item.FirstCategory != "" { + nType = 2 + } else if item.ThreeCategory == "" && item.SecondCategory == "" && item.FirstCategory != "" { + nType = 1 + } else { + return "", true } - if exists := isCategoryExists(item.SecondCategory); exists { - return item.SecondCategory, true - } - - if exists := isCategoryExists(item.ThreeCategory); exists { - return item.ThreeCategory, true + switch nType { + case 1: // 导入一级分类 + if exists := isCategoryExists(item.FirstCategory); exists { + return item.FirstCategory, true + } + case 2: // 导入二级分类 + if exists := isCategoryExists(item.SecondCategory); exists { + return item.SecondCategory, true + } + case 3: // 导入三级分类 + if exists := isCategoryExists(item.ThreeCategory); exists { + return item.ThreeCategory, true + } } } @@ -1068,28 +1163,57 @@ func GenerateSerialNumber(categoryId uint32) (string, error) { } // UpdateErpStockAmountInfo 更新库存和库存商品表的金额:指导零售价、最低零售价 -func UpdateErpStockAmountInfo(begin *gorm.DB, commodityId, retailPrice, minRetailPrice uint32, barCode string) error { - // 更新库存表 - err := begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId). - Updates(map[string]interface{}{ - "retail_price": retailPrice, - "min_retail_price": minRetailPrice, - }).Error - if err != nil { - return err - } +func UpdateErpStockAmountInfo(begin *gorm.DB, commodityId, retailPrice, minRetailPrice uint32, barCode string, + category *ErpCategory) error { + if category != nil && category.ID != 0 { // 分类信息有值 + // 更新库存表 + err := begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId). + Updates(map[string]interface{}{ + "retail_price": retailPrice, + "min_retail_price": minRetailPrice, + "erp_category_id": category.ID, + "erp_category_name": category.Name, + }).Error + if err != nil { + return err + } - // 更新库存商品表 - err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", commodityId). - Updates(map[string]interface{}{ - "retail_price": retailPrice, - "min_retail_price": minRetailPrice, - "erp_barcode": barCode, - }).Error - if err != nil { - return err - } + // 更新库存商品表 + err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", commodityId). + Updates(map[string]interface{}{ + "retail_price": retailPrice, + "min_retail_price": minRetailPrice, + //"staff_cost_price": staffCostPrice, + "erp_barcode": barCode, + "erp_category_id": category.ID, + "erp_category_name": category.Name, + }).Error + if err != nil { + return err + } + } else { + // 更新库存表 + err := begin.Table("erp_stock").Where("erp_commodity_id=?", commodityId). + Updates(map[string]interface{}{ + "retail_price": retailPrice, + "min_retail_price": minRetailPrice, + }).Error + if err != nil { + return err + } + // 更新库存商品表 + err = begin.Table("erp_stock_commodity").Where("erp_commodity_id=? and state not in (2,5)", commodityId). + Updates(map[string]interface{}{ + "retail_price": retailPrice, + "min_retail_price": minRetailPrice, + //"staff_cost_price": staffCostPrice, + "erp_barcode": barCode, + }).Error + if err != nil { + return err + } + } return nil } diff --git a/app/admin/models/mall.go b/app/admin/models/mall.go index 66e725d..0213ca6 100644 --- a/app/admin/models/mall.go +++ b/app/admin/models/mall.go @@ -698,7 +698,7 @@ type MallUserVmRecordReq struct { } type MallUserVmRecordResp struct { - Count int64 `json:"count"` + Count int64 `json:"total"` List []MallUserVmRecordData `json:"list"` PageIndex int `json:"page_index"` PageSize int `json:"page_size"` @@ -752,7 +752,7 @@ func (m *MallUserVmRecordReq) MallUserVmRecordList() ([]MallUserVmRecordData, in qs = qs.Select("user_vm_record.*, user.tel"). Joins("Left JOIN user ON user_vm_record.uid = user.uid") - err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Find(&list).Error + err := qs.Offset(page * m.PageSize).Limit(m.PageSize).Order("created_at desc").Find(&list).Error if err != nil { logger.Errorf("err:", err) return nil, 0, err diff --git a/app/admin/models/order.go b/app/admin/models/order.go index 34ce200..9f5a539 100644 --- a/app/admin/models/order.go +++ b/app/admin/models/order.go @@ -1703,7 +1703,7 @@ func GetUserExpiredCards(userId []uint32) (map[uint32][]OrderCard, error) { err := orm.Eloquent.Table("order_card"). Preload("GameCard"). Where("uid in (?)", userId). - Where("pay_status = ?", 2).Where("card_status in ?", []int{1, 2, 3}). + Where("pay_status = ?", HavePaid).Where("card_status in ?", []int{1, 2, 3}). Find(&oc).Error if err != nil { return m, err diff --git a/app/admin/models/purchase.go b/app/admin/models/purchase.go index 1013370..b5a1e53 100644 --- a/app/admin/models/purchase.go +++ b/app/admin/models/purchase.go @@ -8,6 +8,7 @@ import ( "go-admin/logger" "go-admin/tools/config" "gorm.io/gorm" + "math" "math/rand" "sort" "strconv" @@ -22,8 +23,6 @@ const ( ErpPurchaseOrderWaitReject = 3 // 待退货 ErpPurchaseOrderFinished = 4 // 已完成 ErpPurchaseOrderEnd = 5 // 已终止 - ErpPurchaseOrderInInventory = 6 // 入库中,部分入库 - ErpPurchaseOrderInReject = 7 // 退货中,部分退货 ErpProcureOrder = "procure" // 采购入库订单 ErpRejectOrder = "reject" // 采购退货订单 @@ -49,7 +48,7 @@ type ErpPurchaseOrder struct { AuditTime *time.Time `json:"audit_time"` // 审核时间 AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id AuditorName string `json:"auditor_name"` // 审核人名称 - State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 6-入库中 7-退货中 + State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 RejectedSerialNumber string `json:"rejected_serial_number"` // 退货的采购订单单据编号 ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式/收款方式id ErpCashierName string `json:"erp_cashier_name"` // 付款方式/收款方式名称 @@ -87,6 +86,9 @@ type ErpPurchaseCommodity struct { ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价 ExecutionAmount float64 `json:"execute_amount" gorm:"-"` // 执行金额 DefaultEmployeePrice float64 `json:"default_employee_price" gorm:"-"` // 默认员工成本价 + EffectiveCount uint32 `json:"effective_count" gorm:"-"` // 有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量) + ErpCategoryID uint32 `json:"erp_category_id" gorm:"-"` // 商品分类id + ErpCategoryName string `json:"erp_category_name" gorm:"-"` // 商品分类名称 } // ErpPurchaseInventory 采购入库执行信息 @@ -101,7 +103,7 @@ type ErpPurchaseInventory struct { CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 ErpCategoryID uint32 `json:"erp_category_id" gorm:"index"` // 商品分类id ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加) IMEI string `json:"imei"` // 商品串码 Count uint32 `json:"count"` // 执行数量 ImplementationPrice float64 `json:"implementation_price"` // 执行单价 @@ -109,6 +111,7 @@ type ErpPurchaseInventory struct { EmployeePrice float64 `json:"employee_price"` // 员工成本价 InventoryId uint32 `json:"inventory_id"` // 最近入库人id InventoryName string `json:"inventory_name"` // 最近入库人名称 + ErpStockCommodityID uint32 `json:"erp_stock_commodity_id"` // 库存商品表主键id } // ErpPurchaseCreateReq 新建采购订单入参 @@ -150,17 +153,17 @@ type ErpPurchaseEditReq struct { // ErpPurchaseOrderListReq 查询采购订单列表入参 type ErpPurchaseOrderListReq struct { - SerialNumber string `json:"serial_number"` // 单据编号 - PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货 - StoreId uint32 `json:"store_id"` // 门店id - ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id - AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 - AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 - AuditFlag string `json:"audit_flag"` // 审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成 - State uint32 `json:"state"` // 状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 - HandlerId uint32 `json:"handler_id"` // 经手人id - PageIndex int `json:"pageIndex"` // 页码 - PageSize int `json:"pageSize"` // 页面条数 + SerialNumber string `json:"serial_number"` // 单据编号 + PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货 + StoreId uint32 `json:"store_id"` // 门店id + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id + AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 + AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 + AuditFlag string `json:"audit_flag"` // 审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中 + State []uint32 `json:"state"` // 状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 + HandlerId uint32 `json:"handler_id"` // 经手人id + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 } // ErpPurchaseOrderListResp 查询采购订单列表出参 @@ -180,8 +183,8 @@ type ErpPurchaseDetailReq struct { type ErpPurchaseInventoryReq struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 - InventoryId uint32 `json:"inventory_id" binding:"required"` // 最近入库人id - InventoryName string `json:"inventory_name" binding:"required"` // 最近入库人名称 + InventoryId uint32 `json:"inventory_id"` // 最近入库人id + InventoryName string `json:"inventory_name"` // 最近入库人名称 Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息 } @@ -228,7 +231,7 @@ type ExecuteData struct { EmployeePrice float64 `json:"employee_price"` // 员工成本价 } -// ErpPurchaseDemand 库存执行表 +// ErpPurchaseDemand 采购需求表 type ErpPurchaseDemand struct { Model ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id @@ -239,9 +242,19 @@ type ErpPurchaseDemand struct { Count uint32 `json:"count"` // 需采购数量 State uint32 `json:"state"` // 1-待采购 2-已采购 MakerId uint32 `json:"maker_id"` // 制单人id - PurchaserId uint32 `json:"purchaser_id"` // 采购人id FinishTime *time.Time `json:"finish_time"` // 完成采购时间 - Remark string `json:"remark"` // 备注 + //PurchaserId uint32 `json:"purchaser_id"` // 采购人id + //Remark string `json:"remark"` // 备注 +} + +// ErpPurchaseDemandRemark 采购需求备注表 +type ErpPurchaseDemandRemark struct { + Model + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + State uint32 `json:"state"` // 1-待采购 2-已采购 + MakerId uint32 `json:"maker_id"` // 制单人id + FinishTime *time.Time `json:"finish_time"` // 完成采购时间 + Remark string `json:"remark"` // 备注 } // GetErpPurchaseDemandReq 获取采购需求入参 @@ -312,7 +325,7 @@ type ErpPurchaseReportByOrderReq struct { StoreId []uint32 `json:"store_id"` // 门店id HandlerId uint32 `json:"handler_id"` // 经手人id ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id - State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 + State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止 AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 IsExport uint32 `json:"is_export"` // 1-导出 @@ -326,7 +339,7 @@ type ErpPurchaseReportByOrderResp struct { PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 Amount float64 `json:"amount"` // 已执行金额 - Count uint32 `json:"count"` // 已执行数量 + Count int32 `json:"count"` // 已执行数量 ExportUrl string `json:"export_url"` // 导出excel路径 List []ReportByOrderData `json:"list"` // 采购报表信息 } @@ -337,7 +350,7 @@ type ReportByOrderData struct { Remark string `json:"remark"` // 备注 Amount float64 `json:"amount"` // 已执行金额 Price float64 `json:"price"` // 执行单价 - Count uint32 `json:"count"` // 已执行数量 + Count int32 `json:"count"` // 已执行数量 CommodityData []ErpPurchaseCommodityData `json:"commodity_data"` // 商品信息 } @@ -371,7 +384,7 @@ type ErpPurchaseCommodityData struct { CommodityData Amount float64 `json:"amount"` // 已执行金额 Price float64 `json:"price"` // 已执行单价 - Count uint32 `json:"count"` // 已执行数量 + Count int32 `json:"count"` // 已执行数量 } // ErpPurchaseReportByCommodityReq 采购报表(按商品)入参 @@ -383,7 +396,7 @@ type ErpPurchaseReportByCommodityReq struct { StoreId []uint32 `json:"store_id"` // 门店id HandlerId uint32 `json:"handler_id"` // 经手人id ErpSupplierId []uint32 `json:"erp_supplier_id"` // 供应商id - State uint32 `json:"state"` // 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 + State uint32 `json:"state"` // 2-待入库 3-待退货 4-已完成 5-已终止 AuditTimeStart string `json:"audit_time_start"` // 审核开始时间 AuditTimeEnd string `json:"audit_time_end"` // 审核结束时间 IsExport uint32 `json:"is_export"` // 1-导出 @@ -421,14 +434,14 @@ type TempData struct { // PurchaseData 采购金额和数量 type PurchaseData struct { OrderId uint32 `json:"order_id"` // 采购订单id - PlanCount uint32 `json:"plan_count"` // 计划采购数量 + PlanCount int32 `json:"plan_count"` // 计划采购数量 PlanPrice float64 `json:"plan_price"` // 计划采购单价 PlanAmount float64 `json:"plan_amount"` // 计划采购金额 Amount float64 `json:"amount"` // 已执行金额 Price float64 `json:"price"` // 已执行单价 - Count uint32 `json:"count"` // 已执行数量 + Count int32 `json:"count"` // 已执行数量 NonExecutionAmount float64 `json:"non_execution_amount"` // 未执行金额 - NonExecutionCount uint32 `json:"non_execution_count"` // 未执行数量 + NonExecutionCount int32 `json:"non_execution_count"` // 未执行数量 } // ErpPurchaseReportBySupplierReq 供应商采购汇总入参 @@ -447,30 +460,32 @@ type ErpPurchaseReportBySupplierReq struct { // ErpPurchaseReportBySupplierResp 供应商采购汇总出参 type ErpPurchaseReportBySupplierResp struct { - Total int `json:"total"` // 总条数 - PageIndex int `json:"pageIndex"` // 页码 - PageSize int `json:"pageSize"` // 页面条数 - Count uint32 `json:"count"` // 采购数量 - Amount float64 `json:"amount"` // 采购金额 - RejectAmount float64 `json:"reject_amount"` // 退货金额 - Difference float64 `json:"difference"` // 差额 - ExportUrl string `json:"export_url"` // 导出excel路径 - List []struct { - ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id - StoreId uint32 `json:"store_id"` // 门店id - StoreName string `json:"store_name"` // 门店名称 - PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货 - ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id - ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 - ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id - ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 - ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id - ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 - Count uint32 `json:"count"` // 采购数量 - Amount float64 `json:"amount"` // 采购金额 - RejectAmount float64 `json:"reject_amount"` // 退货金额 - Difference float64 `json:"difference"` // 差额 - } `json:"list"` // 供应商采购汇总信息 + Total int `json:"total"` // 总条数 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 + Count uint32 `json:"count"` // 采购数量 + Amount float64 `json:"amount"` // 采购金额 + RejectAmount float64 `json:"reject_amount"` // 退货金额 + Difference float64 `json:"difference"` // 差额 + ExportUrl string `json:"export_url"` // 导出excel路径 + List []PurchaseReportData `json:"list"` // 供应商采购汇总信息 +} + +type PurchaseReportData struct { + ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id + StoreId uint32 `json:"store_id"` // 门店id + StoreName string `json:"store_name"` // 门店名称 + PurchaseType string `json:"purchase_type"` // 采购类型:procure-采购 reject-退货 + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id + ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 + ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id + ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 + Count uint32 `json:"count"` // 采购数量 + Amount float64 `json:"amount"` // 采购金额 + RejectAmount float64 `json:"reject_amount"` // 退货金额 + Difference float64 `json:"difference"` // 差额 } // ErpPurchaseReportDetailReq 采购明细入参 @@ -501,6 +516,7 @@ type ErpPurchaseReportDetailResp struct { List []struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id OrderSerialNumber string `json:"order_serial_number"` // 单据编号 + SerialNumber string `json:"serial_number"` // 采购入库编号 PurchaseType string `json:"purchase_type"` // 单据类型:procure-采购 reject-退货 ExecuteTime *time.Time `json:"execute_time"` // 出/入库时间 StoreId uint32 `json:"store_id"` // 门店id @@ -535,8 +551,8 @@ func (m *ErpPurchaseOrderListReq) List() (*ErpPurchaseOrderListResp, error) { } qs := orm.Eloquent.Table("erp_purchase_order") var stateList []int - if m.AuditFlag == "ON" { //2-待入库 4-已完成 5-已终止 - stateList = []int{2, 4, 5} + if m.AuditFlag == "ON" { //2-待入库 4-已完成 5-已终止 6-入库中 + stateList = []int{2, 4, 5, 6} qs = qs.Where("state IN ?", stateList) qs = qs.Where("purchase_type=?", ErpProcureOrder) } @@ -552,8 +568,8 @@ func (m *ErpPurchaseOrderListReq) List() (*ErpPurchaseOrderListResp, error) { if m.ErpSupplierId != 0 { qs = qs.Where("erp_supplier_id=?", m.ErpSupplierId) } - if m.State != 0 { - qs = qs.Where("state=?", m.State) + if len(m.State) > 0 { + qs = qs.Where("state IN (?)", m.State) } if m.AuditTimeStart != "" { parse, err := time.Parse(QueryTimeFormat, m.AuditTimeStart) @@ -630,7 +646,7 @@ func NewErpPurchaseSn() string { } } -func ErpPurchaseCommodityListPerfectInfo(purchaseCommodities []ErpPurchaseCommodity) error { +func ErpPurchaseCommodityListPerfectInfo(serialNumber string, purchaseCommodities []ErpPurchaseCommodity) error { commodityIds := make([]uint32, 0, len(purchaseCommodities)) for i, _ := range purchaseCommodities { commodityIds = append(commodityIds, purchaseCommodities[i].ID) @@ -642,6 +658,19 @@ func ErpPurchaseCommodityListPerfectInfo(purchaseCommodities []ErpPurchaseCommod } for i, _ := range purchaseCommodities { + if serialNumber != "" { // 采购退货单才需判断 + // 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量 + nCount, err := GetCommodityStockByPurchaseId(serialNumber, purchaseCommodities[i].ErpCommodityId) + if err != nil { + logger.Error("ErpPurchaseCommodityListPerfectInfo GetCommodityStockByPurchaseId err:", logger.Field("err", err)) + return err + } + // 如果库存数量不够则报错 + if nCount < purchaseCommodities[i].RejectedCount { + return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", purchaseCommodities[i].ErpCommodityName) + } + } + v, ok := commodityMap[purchaseCommodities[i].ErpCommodityId] if ok { purchaseCommodities[i].CommoditySerialNumber = v.SerialNumber @@ -849,7 +878,7 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu logger.Error("info err:", logger.Field("err", err)) return nil, err } - err = ErpPurchaseCommodityListPerfectInfo(req.ErpPurchaseCommodities) + err = ErpPurchaseCommodityListPerfectInfo(req.PurchaseOrderSn, req.ErpPurchaseCommodities) if err != nil { logger.Error("info err:", logger.Field("err", err)) return nil, err @@ -1030,12 +1059,14 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { } begin := orm.Eloquent.Begin() - for _, v := range req.Inventories { + var inventoryList []ErpPurchaseInventory + for i, v := range req.Inventories { v.SerialNumber = GetPurchaseInventorySn() + req.Inventories[i].SerialNumber = v.SerialNumber // 更新采购商品表的执行数量 // todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息,可能采购价不同,需要区分入库的是哪一条(已修改) err = begin.Model(&ErpPurchaseCommodity{}). - Where("id = ?", v.ErpPurchaseCommodityId). + Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId). UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error if err != nil { begin.Rollback() @@ -1045,12 +1076,21 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { v.PurchaseType = req.PurchaseType // 记录采购类型 v.InventoryId = req.InventoryId // 记录入库人id v.InventoryName = req.InventoryName // 记录入库人姓名 - // 新建采购入库记录 - err = begin.Create(&v).Error - if err != nil { - begin.Rollback() - logger.Error("create erp inventory commodity err:", logger.Field("err", err)) - return err + + nCount := v.Count + nAmount := v.Amount + for i := 0; i < int(nCount); i++ { // 采购入库记录表都是单笔数据 + v.ID = 0 + v.Count = 1 + v.Amount = nAmount / float64(nCount) // 前端传的执行金额是总金额 + // 新建采购入库记录 + err = begin.Create(&v).Error + if err != nil { + begin.Rollback() + logger.Error("create erp inventory commodity err:", logger.Field("err", err)) + return err + } + inventoryList = append(inventoryList, v) } } @@ -1062,14 +1102,11 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { return err } - var orderState int // 更新库存信息表 if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单 - orderState = ErpPurchaseOrderInInventory - err = InventoryErpPurchaseUpdateStock(begin, req, purchaseOrder) + err = InventoryErpPurchaseUpdateStock(begin, inventoryList, purchaseOrder) } else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单 - orderState = ErpPurchaseOrderInReject - err = InventoryErpPurchaseUpdateRejectStock(begin, req, purchaseOrder) + err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder) } else { return errors.New("订单类型有误") } @@ -1079,18 +1116,6 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { return err } - // 更新采购订单状态 - if purchaseOrder.State != uint32(orderState) { - err = begin.Table("erp_purchase_order").Where("id = ?", purchaseOrder.ID).Updates(map[string]interface{}{ - "state": orderState, - }).Error - if err != nil { - begin.Rollback() - logger.Error("update erp_purchase_order err:", logger.Field("err", err)) - return err - } - } - err = begin.Commit().Error if err != nil { begin.Rollback() @@ -1098,6 +1123,44 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { return err } + // 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成 + _ = CheckAndUpdatePurchaseOrderState(req.ErpPurchaseOrderId) + + return nil +} + +// CheckAndUpdatePurchaseOrderState +// 查询采购订单商品表入库或退库情况,如果都已经完成了,则更新采购订单的状态为:已完成 +func CheckAndUpdatePurchaseOrderState(orderId uint32) error { + var order ErpPurchaseOrder + if err := orm.Eloquent.Where("id = ?", orderId).First(&order).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return fmt.Errorf("purchase order with ID %d not found", orderId) + } + return err + } + + if order.State == ErpPurchaseOrderFinished { + return nil // Order is already marked as completed + } + + var commodities []ErpPurchaseCommodity + if err := orm.Eloquent.Where("erp_purchase_order_id = ?", orderId).Find(&commodities).Error; err != nil { + return err + } + + for _, commodity := range commodities { + if (order.PurchaseType == "procure" && commodity.Count != uint32(commodity.InventoryCount)) || + (order.PurchaseType == "reject" && commodity.RejectedCount != uint32(commodity.InventoryCount)) { + return nil // Order not completed, exit early + } + } + + // If all commodities are checked and everything is in order, update the state to completed + if err := orm.Eloquent.Model(&order).Update("state", ErpPurchaseOrderFinished).Update("audit_time", time.Now()).Error; err != nil { + return err + } + return nil } @@ -1105,7 +1168,7 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { func GetInventoryIdAndName(orderId uint32) (uint32, string, error) { var purchaseInventory ErpPurchaseInventory err := orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", orderId). - First(&purchaseInventory).Order("created_at DESC").Error + Order("created_at DESC").First(&purchaseInventory).Error if err != nil { logger.Error("purchase order err:", logger.Field("err", err)) return 0, "", err @@ -1115,10 +1178,10 @@ func GetInventoryIdAndName(orderId uint32) (uint32, string, error) { } // InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息 -func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error { +func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error { // 遍历采购入库商品信息 var stockList []ErpStockCommodity - for _, v := range req.Inventories { + for _, v := range list { commodityInfo, err := GetCommodity(v.ErpCommodityId) if err != nil { logger.Errorf("GetCommodity err:", err) @@ -1132,7 +1195,7 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, } if exist { err = gdb.Exec(fmt.Sprintf( - "UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;", + "UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d", v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error if err != nil { logger.Errorf("update stock err:", err) @@ -1186,6 +1249,7 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, MinRetailPrice: commodityInfo.MinRetailPrice, RetailPrice: commodityInfo.RetailPrice, OriginalSn: purchaseOrder.SerialNumber, + StockSn: v.SerialNumber, } stockList = append(stockList, stockCommodity) } @@ -1200,46 +1264,61 @@ func InventoryErpPurchaseUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, } // InventoryErpPurchaseUpdateRejectStock 采购退货更新库存信息 -func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error { - for i, _ := range req.Inventories { - if req.Inventories[i].IMEIType == 2 { // 串码商品 - if req.Inventories[i].IMEI == "" { +func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, list []ErpPurchaseInventory, purchaseOrder ErpPurchaseOrder) error { + usedStockCommodityIdList := make(map[uint32]bool) + for i, _ := range list { + if list[i].IMEIType == 2 { // 串码商品 + if list[i].IMEI == "" { return errors.New("串码为空") } // 判断该串码商品是否已经销售 var stockCommodityInfo ErpStockCommodity - err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI). + err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI). Find(&stockCommodityInfo).Error if err != nil { logger.Error("Inventory RejectStock query commodities err:", logger.Field("err", err)) return err } if stockCommodityInfo.State == SoldOut { - return fmt.Errorf("商品[%s]已经消息,不能退货", stockCommodityInfo.ErpCommodityName) + return fmt.Errorf("商品[%s]已经销售,不能退货", stockCommodityInfo.ErpCommodityName) } else if stockCommodityInfo.State == OnSale { return fmt.Errorf("商品[%s]在销售锁定中,不能退货", stockCommodityInfo.ErpCommodityName) } - err = gdb.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[i].IMEI). - Update("state", PurchaseReturn).Error // 状态更新为采购退货 + err = gdb.Table("erp_stock_commodity").Where("imei = ?", list[i].IMEI). + Updates(&map[string]interface{}{ + "state": PurchaseReturn, + "stock_sn": list[i].SerialNumber, + }).Error // 状态更新为采购退货 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", - purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId). + purchaseOrder.StoreId, list[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } - } else { // todo 非串码商品,需要判断下更新的数量和库存数量是否相同,如果库存数量不够不支持退货 + } else { + // 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量 + nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, list[i].ErpCommodityId) + if err != nil { + logger.Error("InventoryErpPurchaseUpdateRejectStock GetCommodityStockByPurchaseId err:", logger.Field("err", err)) + return err + } + // 如果库存数量不够则报错 + if nCount < list[i].Count { + return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName) + } + var stockCommodity []ErpStockCommodity // 通过门店id,商品id,查找状态为1-在库的非串码商品 - err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ - "and state = ? and imei_type = ?", req.Inventories[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1). + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ + "and state = ? and imei_type = ?", list[i].ErpCommodityId, purchaseOrder.StoreId, InStock, 1). Order("id DESC").Find(&stockCommodity).Error if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) @@ -1249,15 +1328,32 @@ func InventoryErpPurchaseUpdateRejectStock(gdb *gorm.DB, req *ErpPurchaseInvento return errors.New("RetailTypeRejected find no stock commodity") } - err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). - Update("state", PurchaseReturn).Error // 状态更新为采购退货 + var currentID uint32 + // 找一个可用的库存ID + for _, item := range stockCommodity { + _, ok := usedStockCommodityIdList[item.ID] + if !ok { + usedStockCommodityIdList[item.ID] = true + currentID = item.ID + break + } else { + continue + } + } + if currentID == 0 { + return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", list[i].ErpCommodityName) + } + err = gdb.Table("erp_stock_commodity").Where("id = ?", currentID).Updates(&map[string]interface{}{ + "state": PurchaseReturn, + "stock_sn": list[i].SerialNumber, + }).Error // 状态更新为采购退货 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", - purchaseOrder.StoreId, req.Inventories[i].ErpCommodityId). + purchaseOrder.StoreId, list[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) @@ -1302,13 +1398,15 @@ func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { return fmt.Errorf("数据错误,员工成本价不能低于采购执行单价") } - if inventory.EmployeePrice == 0 { // 没有传入员工成本价,则默认按照商品资料设置的员工成本价加价金额 - erpCommodity, err := GetCommodity(inventory.ErpCommodityId) - if err != nil { - logger.Error("checkPurchaseInventory GetCommodity err:", logger.Field("err", err)) - return fmt.Errorf("查询员工成本价报错") - } + erpCommodity, err := GetCommodity(inventory.ErpCommodityId) + if err != nil { + logger.Error("checkPurchaseInventory GetCommodity err:", logger.Field("err", err)) + return fmt.Errorf("查询员工成本价报错") + } + req.Inventories[i].ErpCategoryID = erpCommodity.ErpCategoryId // 分类id,入库的时候前端没传,后端补充 + req.Inventories[i].ErpCategoryName = erpCommodity.ErpCategoryName // 分类名称,入库的时候前端没传,后端补充 + if inventory.EmployeePrice == 0 { // 没有传入员工成本价,则默认按照商品资料设置的员工成本价加价金额 req.Inventories[i].EmployeePrice = inventory.ImplementationPrice + float64(erpCommodity.StaffCostPrice) } } @@ -1340,6 +1438,24 @@ func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName, inventoryCount, int32(commodity.Count)-commodity.InventoryCount) } + + // 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量 + var purchaseOrder ErpPurchaseOrder + err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error + if err != nil { + logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err)) + return err + } + nCount, err := GetCommodityStockByPurchaseId(purchaseOrder.RejectedSerialNumber, commodity.ErpCommodityId) + if err != nil { + logger.Error("checkPurchaseInventory GetCommodityStockByPurchaseId err:", logger.Field("err", err)) + return err + } + // 如果库存数量不够则报错 + if nCount < commodity.RejectedCount { + return fmt.Errorf("商品[%s]采购退货数量超出实际库存数量,请先零售退货", commodity.ErpCommodityName) + } + } } } @@ -1365,11 +1481,16 @@ func ExecuteErpPurchase(req *ErpPurchaseExecuteReq) (*ErpPurchaseExecuteResp, er } for _, inventory := range req.Inventories { - if inventory.IMEIType == 2 || inventory.IMEIType == 3 { + // 获取商品信息 + commodityInfo, err := GetCommodity(inventory.ErpCommodityId) + if err != nil { + return nil, err + } + if commodityInfo.IMEIType == 2 || commodityInfo.IMEIType == 3 { // 如果是串码商品,根据 Count 拆分成对应数量的数据 for i := 0; i < int(inventory.Count); i++ { - imei := "" // 默认退货单执行时不需要串码 - if inventory.PurchaseType == ErpProcureOrder { // 采购单 + imei := "" // 默认退货单执行时不需要串码 + if inventory.PurchaseType == ErpProcureOrder && commodityInfo.IMEIType == 2 { // 采购单 // 调用函数B生成商品串码 imei, err = generateIMEI(inventory.ErpCommodityId) if err != nil { @@ -1389,7 +1510,7 @@ func ExecuteErpPurchase(req *ErpPurchaseExecuteReq) (*ErpPurchaseExecuteResp, er EmployeePrice: inventory.EmployeePrice, }) } - } else if inventory.IMEIType == 1 { + } else if commodityInfo.IMEIType == 1 { // 如果是非串码商品,只需拆分为1条数据 resp.List = append(resp.List, ExecuteData{ ErpPurchaseOrderId: inventory.ErpPurchaseOrderId, @@ -1423,12 +1544,13 @@ func generateIMEI(commodityId uint32) (string, error) { // CreateErpPurchaseDemand 创建采购需求单 func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error { var demandInfo ErpPurchaseDemand + var demandRemark ErpPurchaseDemandRemark var demandList []ErpPurchaseDemand + // 采购需求信息 demandInfo.ErpCommodityId = req.ErpCommodityID demandInfo.ErpCommoditySerialNumber = req.ErpCommoditySerialNumber demandInfo.ErpCommodityName = req.ErpCommodityName - demandInfo.Remark = req.Remark demandInfo.State = ErpDemandStateWait // 待采购 for _, v := range req.List { demandInfo.StoreId = v.StoreID @@ -1438,6 +1560,12 @@ func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) demandList = append(demandList, demandInfo) } + // 采购需求备注信息 + demandRemark.ErpCommodityId = req.ErpCommodityID + demandRemark.State = ErpDemandStateWait // 待采购 + demandRemark.MakerId = uint32(sysUser.UserId) + demandRemark.Remark = req.Remark + begin := orm.Eloquent.Begin() // 查询当前表格,有记录则更新,没有则插入新记录 for _, v := range demandList { @@ -1470,17 +1598,33 @@ func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) } } - // 更新备注 - err := begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and state = 1", - req.ErpCommodityID).Updates(map[string]interface{}{ - "remark": req.Remark, - }).Error + // 更新备注,先查询有无记录,有则更新,没有则插入新记录 + var demandRemarkInfo ErpPurchaseDemandRemark + err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1", + req.ErpCommodityID).Find(&demandRemarkInfo).Error if err != nil { - begin.Rollback() - logger.Error("update erp_order remark err:", logger.Field("err", err)) + logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err)) return err } + if demandRemarkInfo.ErpCommodityId != 0 { // 有记录 + if demandRemarkInfo.Remark != req.Remark { // 备注有变化才更新 + err := begin.Model(&ErpPurchaseDemandRemark{}).Where("erp_commodity_id = ? and state = 1", + req.ErpCommodityID).Updates(demandRemark).Error + if err != nil { + begin.Rollback() + logger.Error("update erp_purchase_demand_remark err:", logger.Field("err", err)) + return err + } + } + } else { // 无记录,新建 + err = begin.Create(&demandRemark).Error + if err != nil { + logger.Error("create erp_purchase_demand_remark err:", logger.Field("err", err)) + return err + } + } + err = begin.Commit().Error if err != nil { begin.Rollback() @@ -1503,7 +1647,18 @@ func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) } // 批量更新状态 - err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=?", req.ErpCommodityID). + err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID). + Updates(map[string]interface{}{ + "state": ErpDemandStateFinish, + "finish_time": time.Now(), + "purchaser_id": sysUser.UserId, + }).Error + if err != nil { + logger.Error("update err:", logger.Field("err", err)) + return err + } + + err = orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id=? and state = 1", req.ErpCommodityID). Updates(map[string]interface{}{ "state": ErpDemandStateFinish, "finish_time": time.Now(), @@ -2138,7 +2293,11 @@ func getErpPurchaseDemandAll(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDeman qs := orm.Eloquent.Debug().Table("erp_commodity") if req.ErpCategoryId != 0 { - qs = qs.Where("erp_category_id=?", req.ErpCategoryId) + categoryInfo, err := GetErpCategory(req.ErpCategoryId) + if err != nil { + return nil, err + } + qs = qs.Where("serial_number like ?", categoryInfo.Number+"%") } if req.ErpCommoditySerialNumber != "" { qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber) @@ -2243,7 +2402,12 @@ func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDema // 查询商品信息 qs := orm.Eloquent.Debug().Table("erp_commodity") if req.ErpCategoryId != 0 { - qs = qs.Where("erp_category_id=?", req.ErpCategoryId) + //qs = qs.Where("erp_category_id=?", req.ErpCategoryId) + categoryInfo, err := GetErpCategory(req.ErpCategoryId) + if err != nil { + return nil, err + } + qs = qs.Where("serial_number like ?", categoryInfo.Number+"%") } if req.ErpCommoditySerialNumber != "" { qs = qs.Where("serial_number=?", req.ErpCommoditySerialNumber) @@ -2329,6 +2493,15 @@ func getErpPurchaseDemandHide(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDema // convertToDemandData 将商品转换为采购需求数据 func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { + // 查询采购商品的备注信息 + var demandRemarkInfo ErpPurchaseDemandRemark + err := orm.Eloquent.Table("erp_purchase_demand_remark").Where("erp_commodity_id = ? and state = 1", + commodity.ID).Find(&demandRemarkInfo).Error + if err != nil { + logger.Error("query erp_purchase_demand_remark err:", logger.Field("err", err)) + return DemandData{}, err + } + demandData := DemandData{ ErpCommodityID: commodity.ID, ErpCommoditySerialNumber: commodity.SerialNumber, @@ -2336,6 +2509,7 @@ func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, er ErpCategoryID: commodity.ErpCategoryId, ErpCategoryName: commodity.ErpCategoryName, RetailPrice: commodity.RetailPrice, + Remark: demandRemarkInfo.Remark, } // 查询采购需求单 @@ -2344,9 +2518,9 @@ func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, er // Handle error return DemandData{}, err } - if len(demands) != 0 { - demandData.Remark = demands[0].Remark - } + //if len(demands) != 0 { + // demandData.Remark = demands[0].Remark + //} // 使用 WaitGroup 进行并行查询 var wg sync.WaitGroup @@ -2447,15 +2621,15 @@ func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurch func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { // 查询最近采购价 var prices []struct { - CommodityID uint32 - Price float64 + ErpCommodityID uint32 + Price float64 } err := orm.Eloquent.Table("erp_purchase_inventory"). Select("erp_commodity_id, implementation_price AS price"). Where("erp_commodity_id IN (?) AND purchase_type = ?", commodityID, "procure"). - Group("erp_commodity_id"). + //Group("erp_commodity_id"). Order("created_at DESC"). - Find(&prices).Error + First(&prices).Error if err != nil { return nil, err } @@ -2463,7 +2637,7 @@ func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, er // 构建结果 result := make(map[uint32]float64) for _, p := range prices { - result[p.CommodityID] = p.Price + result[p.ErpCommodityID] = p.Price } return result, nil } @@ -2497,6 +2671,18 @@ func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32 return result, nil } +// GetCommodityStockByPurchaseId 查询入库商品实际库存详情处剩余有效数,不包含已出库的数量 +func GetCommodityStockByPurchaseId(serialNumber string, orderId uint32) (uint32, error) { + var count int64 + err := orm.Eloquent.Table("erp_stock_commodity").Where("original_sn = ? and erp_commodity_id = ? and state = ?", + serialNumber, orderId, InStock).Count(&count).Error + if err != nil { + return 0, err + } + + return uint32(count), nil +} + // GetCommodityLastMonthSales 批量查询商品的上月销售数量 func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) { // 获取上个月的时间范围 @@ -2844,7 +3030,7 @@ func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq) ( var reportOrderDataList []ReportByOrderData var nTotalAmount float64 - var nTotalCount uint32 + var nTotalCount int32 // 查询采购订单信息 for _, v := range commodityMap { var purchaseOrder ErpPurchaseOrder @@ -2853,18 +3039,10 @@ func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq) ( query := orm.Eloquent.Table("erp_purchase_order") if len(req.ErpSupplierId) > 0 { // 供应商复选 - var supplierIDs []uint32 - for _, supplier := range req.ErpSupplierId { - supplierIDs = append(supplierIDs, supplier) - } - query = query.Where("erp_purchase_order.erp_supplier_id IN (?)", supplierIDs) + query = query.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId) } if len(req.StoreId) > 0 { // 门店复选 - var storeIDs []uint32 - for _, store := range req.StoreId { - storeIDs = append(storeIDs, store) - } - query = query.Where("erp_purchase_order.store_id IN (?)", storeIDs) + query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreId) } err = query.Where("id = ?", v).Find(&purchaseOrder).Error @@ -2903,22 +3081,54 @@ func getReportByOrderFromCommodityOrCategory(req *ErpPurchaseReportByOrderReq) ( } var nAmount float64 - var nCount uint32 + var nCount int32 + // 使用 map 来组合相同 ErpCommodityId 的数据 + commodityMapInfo := make(map[uint32]ErpPurchaseCommodityData) + for _, inventory := range inventoryList { - var commodityData ErpPurchaseCommodityData if inventory.ErpPurchaseOrderId == purchaseOrder.ID { - commodityData.ErpCommodityId = inventory.ErpCommodityId - commodityData.ErpCommodityName = inventory.ErpCommodityName - commodityData.ErpCategoryID = inventory.ErpCategoryID - commodityData.ErpCategoryName = inventory.ErpCategoryName - commodityData.Amount = inventory.Amount - commodityData.Price = inventory.ImplementationPrice - commodityData.Count = inventory.Count - commodityList = append(commodityList, commodityData) - nAmount += inventory.Amount - nCount += inventory.Count + var vCount int32 + var vAmount float64 + if inventory.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值 + vAmount = -inventory.Amount + vCount = -int32(inventory.Count) + } else { + vCount = int32(inventory.Count) + vAmount = inventory.Amount + } + + if existingData, ok := commodityMapInfo[inventory.ErpCommodityId]; ok { + // 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count + existingData.Amount += vAmount + existingData.Count += vCount + existingData.Price = existingData.Amount / float64(existingData.Count) + commodityMapInfo[inventory.ErpCommodityId] = existingData + } else { + // 否则,创建新的数据 + commodityMapInfo[inventory.ErpCommodityId] = ErpPurchaseCommodityData{ + CommodityData: CommodityData{ + ErpCommodityId: inventory.ErpCommodityId, + ErpCommodityName: inventory.ErpCommodityName, + ErpCategoryID: inventory.ErpCategoryID, + ErpCategoryName: inventory.ErpCategoryName, + }, + Amount: vAmount, + Price: inventory.ImplementationPrice, + Count: vCount, + } + } + // 累加总金额和总数量 + nAmount += vAmount + nCount += vCount + } } + + // 将 map 中的值转换为 slice + for _, data := range commodityMapInfo { + commodityList = append(commodityList, data) + } + reportByOrderData.CommodityData = commodityList reportByOrderData.Amount = nAmount reportByOrderData.Count = nCount @@ -2961,8 +3171,8 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseR PageIndex: page + 1, PageSize: req.PageSize, } - qs := orm.Eloquent.Table("erp_purchase_order") - if req.SerialNumber != "" { // 单据编号 + qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1") // 未审核订单不展示 + if req.SerialNumber != "" { // 单据编号 qs = qs.Where("serial_number=?", req.SerialNumber) } else { if req.PurchaseType != "" { // 采购类型 @@ -3002,7 +3212,7 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseR logger.Errorf("erpPurchaseOrderList err:", err) return nil, err } - parse = parse.AddDate(0, 0, 1) + //parse = parse.AddDate(0, 0, 1) qs = qs.Where("audit_time < ?", parse) } } @@ -3028,11 +3238,11 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseR var reportByOrderDataList []ReportByOrderData var nTotalAmount float64 - var nTotalCount uint32 + var nTotalCount int32 for _, v := range orders { var reportByOrderData ReportByOrderData var nAmount float64 - var nCount uint32 + var nCount int32 reportByOrderData.ErpPurchaseOrderId = v.ID reportByOrderData.SerialNumber = v.SerialNumber reportByOrderData.PurchaseType = v.PurchaseType @@ -3067,6 +3277,7 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseR if err != nil { return nil, err } + reportByOrderData.Amount = nAmount reportByOrderData.Count = nCount if nCount != 0 { @@ -3094,9 +3305,10 @@ func getReportByOrderFromCommon(req *ErpPurchaseReportByOrderReq) (*ErpPurchaseR } // 查询采购订单的入库信息 -func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, uint32, error) { +func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityData, float64, int32, error) { var inventoryList []ErpPurchaseInventory - err := orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id = ?", erpPurchaseOrderId). + err := orm.Eloquent.Table("erp_purchase_inventory"). + Where("erp_purchase_order_id = ?", erpPurchaseOrderId). Find(&inventoryList).Error if err != nil { logger.Error("getOrderInventoryInfo err:", logger.Field("err", err)) @@ -3108,21 +3320,52 @@ func getOrderInventoryInfo(erpPurchaseOrderId uint32) ([]ErpPurchaseCommodityDat return nil, 0, 0, nil } - var resp []ErpPurchaseCommodityData + // 使用 map 来组合相同 ErpCommodityId 的数据 + commodityMap := make(map[uint32]ErpPurchaseCommodityData) var nAmount float64 - var nCount uint32 + var nCount int32 + + // 遍历库存列表,组合相同 ErpCommodityId 的数据 for _, v := range inventoryList { - var purchaseCommodityData ErpPurchaseCommodityData - purchaseCommodityData.ErpCommodityId = v.ErpCommodityId - purchaseCommodityData.ErpCommodityName = v.ErpCommodityName - purchaseCommodityData.ErpCategoryID = v.ErpCategoryID - purchaseCommodityData.ErpCategoryName = v.ErpCategoryName - purchaseCommodityData.Amount = v.Amount - purchaseCommodityData.Price = v.ImplementationPrice - purchaseCommodityData.Count = v.Count - resp = append(resp, purchaseCommodityData) - nAmount += v.Amount - nCount += v.Count + var vCount int32 + var vAmount float64 + if v.PurchaseType == ErpRejectOrder { // 退货单金额和数量取负值 + vAmount = -v.Amount + vCount = -int32(v.Count) + } else { + vCount = int32(v.Count) + vAmount = v.Amount + } + + if existingData, ok := commodityMap[v.ErpCommodityId]; ok { + // 如果已经存在相同 ErpCommodityId 的数据,则累加 Amount 和 Count + existingData.Amount += vAmount + existingData.Count += vCount + existingData.Price = existingData.Amount / float64(existingData.Count) + commodityMap[v.ErpCommodityId] = existingData + } else { + // 否则,创建新的数据 + commodityMap[v.ErpCommodityId] = ErpPurchaseCommodityData{ + CommodityData: CommodityData{ + ErpCommodityId: v.ErpCommodityId, + ErpCommodityName: v.ErpCommodityName, + ErpCategoryID: v.ErpCategoryID, + ErpCategoryName: v.ErpCategoryName, + }, + Amount: vAmount, + Price: v.ImplementationPrice, + Count: vCount, + } + } + // 累加总金额和总数量 + nAmount += vAmount + nCount += vCount + } + + // 将 map 中的值转换为 slice + var resp []ErpPurchaseCommodityData + for _, data := range commodityMap { + resp = append(resp, data) } return resp, nAmount, nCount, nil @@ -3174,21 +3417,28 @@ func reportByOrderExport(req *ErpPurchaseReportByOrderResp) (string, error) { orderStatus = "已终止" } + var strTime string + if orderData.AuditTime != nil { + strTime = orderData.AuditTime.Format(TimeFormat) + } else { + strTime = "--" + } + row1 = []interface{}{ - orderData.SerialNumber, // 单据编号 - orderType, // 类型 - orderData.StoreName, // 店铺名称 - orderData.Remark, // 备注 - orderData.ErpSupplierName, // 供应商 - orderData.HandlerName, // 经手人 - orderData.MakerName, // 制单人 - orderData.AuditTime.Format(TimeFormat), // 审核时间 - orderStatus, // 订单状态 - "--", // 商品名称 - "--", // 商品分类 - orderData.Amount, // 已执行金额 - orderData.Price, // 执行单价 - orderData.Count, // 已执行数量 + orderData.SerialNumber, // 单据编号 + orderType, // 类型 + orderData.StoreName, // 店铺名称 + orderData.Remark, // 备注 + orderData.ErpSupplierName, // 供应商 + orderData.HandlerName, // 经手人 + orderData.MakerName, // 制单人 + strTime, // 审核时间 + orderStatus, // 订单状态 + "--", // 商品名称 + "--", // 商品分类 + orderData.Amount, // 已执行金额 + orderData.Price, // 执行单价 + orderData.Count, // 已执行数量 } for j, _ := range row1 { @@ -3420,18 +3670,10 @@ func getPurchaseOrderData(orderID uint32, req *ErpPurchaseReportByCommodityReq) qs := orm.Eloquent.Table("erp_purchase_order") if len(req.ErpSupplierId) > 0 { // 供应商复选 - var supplierIDs []uint32 - for _, supplier := range req.ErpSupplierId { - supplierIDs = append(supplierIDs, supplier) - } - qs = qs.Where("erp_supplier_id IN (?)", supplierIDs) + qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId) } if len(req.StoreId) > 0 { // 门店复选 - var storeIDs []uint32 - for _, store := range req.StoreId { - storeIDs = append(storeIDs, store) - } - qs = qs.Where("store_id IN (?)", storeIDs) + qs = qs.Where("store_id IN (?)", req.StoreId) } err := qs.Where("id = ?", orderID).Find(&purchaseOrder).Error if err != nil { @@ -3481,6 +3723,15 @@ func getPurchaseOrderData(orderID uint32, req *ErpPurchaseReportByCommodityReq) purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount + if purchaseOrder.PurchaseType == ErpRejectOrder { // 退货单 + purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount + purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount + purchaseOrderData.Amount = -purchaseOrderData.Amount + purchaseOrderData.Count = -purchaseOrderData.Count + purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount + purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount + } + return purchaseOrderData, nil } @@ -3530,7 +3781,7 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*ErpP PageIndex: page + 1, PageSize: req.PageSize, } - qs := orm.Eloquent.Table("erp_purchase_order") + qs := orm.Eloquent.Table("erp_purchase_order").Where("state != 1") if req.SerialNumber != "" { // 单据编号 qs = qs.Where("serial_number=?", req.SerialNumber) } else { @@ -3538,18 +3789,10 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*ErpP qs = qs.Where("purchase_type=?", req.PurchaseType) } if len(req.ErpSupplierId) > 0 { // 供应商复选 - var supplierIDs []uint32 - for _, supplier := range req.ErpSupplierId { - supplierIDs = append(supplierIDs, supplier) - } - qs = qs.Where("erp_supplier_id IN (?)", supplierIDs) + qs = qs.Where("erp_supplier_id IN (?)", req.ErpSupplierId) } if len(req.StoreId) > 0 { // 门店复选 - var storeIDs []uint32 - for _, store := range req.StoreId { - storeIDs = append(storeIDs, store) - } - qs = qs.Where("store_id IN (?)", storeIDs) + qs = qs.Where("store_id IN (?)", req.StoreId) } if req.HandlerId != 0 { // 经手人id qs = qs.Where("handler_id=?", req.HandlerId) @@ -3571,7 +3814,7 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*ErpP logger.Errorf("erpPurchaseOrderList err:", err) return nil, err } - parse = parse.AddDate(0, 0, 1) + //parse = parse.AddDate(0, 0, 1) qs = qs.Where("audit_time < ?", parse) } } @@ -3646,13 +3889,19 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*ErpP reportData.ErpCommodityName = v.ErpCommodityName reportData.PlanCount += v.PlanCount - reportData.PlanPrice += v.PlanPrice reportData.PlanAmount += v.PlanAmount reportData.Amount += v.Amount - reportData.Price += v.Price reportData.Count += v.Count reportData.NonExecutionAmount += v.NonExecutionAmount reportData.NonExecutionCount += v.NonExecutionCount + if reportData.PlanCount != 0 { + reportData.PlanPrice = reportData.PlanAmount / float64(reportData.PlanCount) + reportData.PlanPrice = math.Round(reportData.PlanPrice*100) / 100 + } + if reportData.Count != 0 { + reportData.Price = reportData.Amount / float64(reportData.Count) + reportData.Price = math.Round(reportData.Price*100) / 100 + } purchaseOrderData := ErpCommodityPurchaseOrderData{ CommonData{ @@ -3684,6 +3933,22 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq) (*ErpP }, } + if v.PurchaseType == ErpRejectOrder { // 退货单 + reportData.PlanCount = -reportData.PlanCount + reportData.PlanAmount = -reportData.PlanAmount + reportData.Amount = -reportData.Amount + reportData.Count = -reportData.Count + reportData.NonExecutionAmount = -reportData.NonExecutionAmount + reportData.NonExecutionCount = -reportData.NonExecutionCount + + purchaseOrderData.PlanCount = -purchaseOrderData.PlanCount + purchaseOrderData.PlanAmount = -purchaseOrderData.PlanAmount + purchaseOrderData.Amount = -purchaseOrderData.Amount + purchaseOrderData.Count = -purchaseOrderData.Count + purchaseOrderData.NonExecutionAmount = -purchaseOrderData.NonExecutionAmount + purchaseOrderData.NonExecutionCount = -purchaseOrderData.NonExecutionCount + } + if v.MakerTime != nil && v.MakerTime.IsZero() { purchaseOrderData.MakerTime = nil } else { @@ -4045,24 +4310,31 @@ func reportByCommodityExport(req *ErpPurchaseReportByCommodityResp) (string, err orderType = "采购退货" } + var strTime string + if orderData.AuditTime != nil { + strTime = orderData.AuditTime.Format(TimeFormat) + } else { + strTime = "--" + } + row2 = []interface{}{ - "", // 商品名称 - "", // 商品分类 - orderData.SerialNumber, // 单据编号 - orderType, // 类型 - orderData.StoreName, // 店铺名称 - orderData.ErpSupplierName, // 供应商 - orderData.HandlerName, // 经手人 - orderData.MakerName, // 制单人 - orderData.AuditTime.Format(TimeFormat), // 审核时间 - orderData.PlanAmount, // 计划采购金额 - orderData.PlanPrice, // 计划采购单价 - orderData.PlanCount, // 计划采购数量 - orderData.Amount, // 已执行金额 - orderData.Price, // 已执行单价 - orderData.Count, // 已执行数量 - orderData.NonExecutionAmount, // 未执行金额 - orderData.NonExecutionCount, // 未执行数量 + "", // 商品名称 + "", // 商品分类 + orderData.SerialNumber, // 单据编号 + orderType, // 类型 + orderData.StoreName, // 店铺名称 + orderData.ErpSupplierName, // 供应商 + orderData.HandlerName, // 经手人 + orderData.MakerName, // 制单人 + strTime, // 审核时间 + orderData.PlanAmount, // 计划采购金额 + orderData.PlanPrice, // 计划采购单价 + orderData.PlanCount, // 计划采购数量 + orderData.Amount, // 已执行金额 + orderData.Price, // 已执行单价 + orderData.Count, // 已执行数量 + orderData.NonExecutionAmount, // 未执行金额 + orderData.NonExecutionCount, // 未执行数量 } for j, _ := range row2 { @@ -4170,27 +4442,11 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor query = query.Where("erp_purchase_inventory.purchase_type = ?", req.PurchaseType) } if len(req.ErpCommodityName) > 0 { - var commodityNameList []string - for _, commodityName := range req.ErpCommodityName { - commodityNameList = append(commodityNameList, commodityName) - } - query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", commodityNameList) + query = query.Where("erp_purchase_inventory.erp_commodity_name IN (?)", req.ErpCommodityName) } if len(req.ErpCategoryID) > 0 { - var erpCategoryIDs []uint32 - for _, categoryID := range req.ErpCategoryID { - erpCategoryIDs = append(erpCategoryIDs, categoryID) - } - query = query.Where("erp_purchase_inventory.erp_category_id IN (?)", erpCategoryIDs) - } - - if len(req.ErpSupplierId) > 0 { - var supplierIDs []uint32 - for _, supplier := range req.ErpSupplierId { - supplierIDs = append(supplierIDs, supplier) - } - query = query.Where("erp_purchase_inventory.erp_supplier_id IN (?)", supplierIDs) + query = query.Where("erp_purchase_inventory.erp_category_id IN (?)", req.ErpCategoryID) } if req.StartTime != "" { // 入/出库开始时间 @@ -4212,11 +4468,7 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor } if len(req.StoreList) > 0 { - var storeIDs []uint32 - for _, store := range req.StoreList { - storeIDs = append(storeIDs, store) - } - query = query.Where("erp_purchase_order.store_id IN (?)", storeIDs) + query = query.Where("erp_purchase_order.store_id IN (?)", req.StoreList) } // 获取总数 @@ -4229,38 +4481,107 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor if req.IsExport == 1 { // 导出excel err = query.Find(&resp.List).Error } else { - err = query.Offset((req.PageIndex - 1) * req.PageSize).Limit(req.PageSize).Find(&resp.List).Error + //err = query.Offset((req.PageIndex - 1) * req.PageSize).Limit(req.PageSize).Find(&resp.List).Error + err = query.Find(&resp.List).Error } if err != nil { return nil, err } - // 补充关联的供应商和店铺信息 - for i := range resp.List { - var purchaseOrder ErpPurchaseOrder - orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrder) - resp.List[i].StoreId = purchaseOrder.StoreId - resp.List[i].StoreName = purchaseOrder.StoreName - resp.List[i].ErpSupplierId = purchaseOrder.ErpSupplierId - resp.List[i].ErpSupplierName = purchaseOrder.ErpSupplierName + var esData []PurchaseReportData - if resp.List[i].PurchaseType == "reject" { - resp.List[i].Amount = -resp.List[i].Amount - resp.List[i].RejectAmount = -resp.List[i].RejectAmount - resp.List[i].Difference = resp.List[i].Amount + resp.List[i].RejectAmount + if len(req.ErpSupplierId) > 0 { + var purchaseOrder []ErpPurchaseOrder + err = orm.Eloquent.Where("erp_purchase_order.erp_supplier_id IN (?)", req.ErpSupplierId).Find(&purchaseOrder).Error + if err != nil { + return nil, err + } + + // 循环遍历采购订单 + for _, po := range purchaseOrder { + // 在resp.List中查找匹配的订单 + for _, respItem := range resp.List { + if po.ID == respItem.ErpPurchaseOrderId { + // 如果找到匹配的订单,将其添加到esData中 + data := PurchaseReportData{ + ErpPurchaseOrderId: po.ID, + StoreId: po.StoreId, + StoreName: po.StoreName, + PurchaseType: respItem.PurchaseType, + ErpSupplierId: po.ErpSupplierId, + ErpSupplierName: po.ErpSupplierName, + ErpCommodityId: respItem.ErpCommodityId, + ErpCommodityName: respItem.ErpCommodityName, + ErpCategoryID: respItem.ErpCategoryID, + ErpCategoryName: respItem.ErpCategoryName, + Count: respItem.Count, + Amount: respItem.Amount, + RejectAmount: respItem.RejectAmount, + Difference: respItem.Difference, + } + + if data.PurchaseType == "reject" { + data.Amount = -data.Amount + data.RejectAmount = -data.RejectAmount + data.Difference = data.Amount + data.RejectAmount + } + + esData = append(esData, data) + } + } + } + resp.List = esData + } else { + // 补充关联的供应商和店铺信息 + for i := range resp.List { + var purchaseOrderInfo ErpPurchaseOrder + orm.Eloquent.Where("id = ?", resp.List[i].ErpPurchaseOrderId).First(&purchaseOrderInfo) + + resp.List[i].StoreId = purchaseOrderInfo.StoreId + resp.List[i].StoreName = purchaseOrderInfo.StoreName + resp.List[i].ErpSupplierId = purchaseOrderInfo.ErpSupplierId + resp.List[i].ErpSupplierName = purchaseOrderInfo.ErpSupplierName + + if resp.List[i].PurchaseType == "reject" { + resp.List[i].Amount = -resp.List[i].Amount + resp.List[i].RejectAmount = -resp.List[i].RejectAmount + resp.List[i].Difference = resp.List[i].Amount + resp.List[i].RejectAmount + } } } + mergedData := mergeData(resp.List) + // 统计总计数量和金额 var totalAmount float64 var totalCount uint32 - for _, item := range resp.List { + var totalRejectAmount float64 + var totalDifference float64 + for _, item := range mergedData { totalAmount += item.Amount totalCount += item.Count + totalRejectAmount += item.RejectAmount + totalDifference += item.Difference } resp.Amount = totalAmount resp.Count = totalCount + resp.RejectAmount = totalRejectAmount + resp.Difference = totalDifference + resp.Total = len(mergedData) + + // 分页处理 + startIdx := (resp.PageIndex - 1) * resp.PageSize + endIdx := resp.PageIndex * resp.PageSize + + // 确保不超出索引范围 + if startIdx >= len(mergedData) { + resp.List = []PurchaseReportData{} + } else if endIdx > len(mergedData) { + resp.List = mergedData[startIdx:] + } else { + resp.List = mergedData[startIdx:endIdx] + } if req.IsExport == 1 { filePath, err := reportBySupplierExport(resp) @@ -4274,6 +4595,100 @@ func GetReportBySupplier(req *ErpPurchaseReportBySupplierReq) (*ErpPurchaseRepor return resp, nil } +//func mergeData(esData []PurchaseReportData) []PurchaseReportData { +// mergedMap := make(map[string]*PurchaseReportData) +// +// // 遍历 esData 数据 +// for _, data := range esData { +// key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType) +// if _, ok := mergedMap[key]; !ok { +// // 如果键不存在,创建新条目 +// mergedMap[key] = &PurchaseReportData{ +// StoreId: data.StoreId, +// ErpSupplierId: data.ErpSupplierId, +// ErpCommodityId: data.ErpCommodityId, +// StoreName: data.StoreName, +// PurchaseType: data.PurchaseType, +// ErpSupplierName: data.ErpSupplierName, +// ErpCommodityName: data.ErpCommodityName, +// ErpCategoryID: data.ErpCategoryID, +// ErpCategoryName: data.ErpCategoryName, +// Count: data.Count, +// Amount: data.Amount, +// RejectAmount: data.RejectAmount, +// Difference: data.Difference, +// } +// } else { +// // 如果键已存在,进行累加操作 +// mergedMap[key].Count += data.Count +// mergedMap[key].Amount += data.Amount +// mergedMap[key].RejectAmount += data.RejectAmount +// mergedMap[key].Difference += data.Difference +// } +// } +// +// // 将合并后的数据转换为数组返回 +// var mergedData []PurchaseReportData +// for _, v := range mergedMap { +// mergedData = append(mergedData, *v) +// } +// +// return mergedData +//} + +func mergeData(esData []PurchaseReportData) []PurchaseReportData { + mergedMap := make(map[string]*PurchaseReportData) + var keys []string // 用于记录键的顺序 + + // 遍历 esData 数据 + for _, data := range esData { + key := fmt.Sprintf("%d_%d_%d_%s", data.StoreId, data.ErpSupplierId, data.ErpCommodityId, data.PurchaseType) + if _, ok := mergedMap[key]; !ok { + // 如果键不存在,创建新条目 + mergedMap[key] = &PurchaseReportData{ + StoreId: data.StoreId, + ErpSupplierId: data.ErpSupplierId, + ErpCommodityId: data.ErpCommodityId, + StoreName: data.StoreName, + PurchaseType: data.PurchaseType, + ErpSupplierName: data.ErpSupplierName, + ErpCommodityName: data.ErpCommodityName, + ErpCategoryID: data.ErpCategoryID, + ErpCategoryName: data.ErpCategoryName, + Count: data.Count, + Amount: data.Amount, + RejectAmount: data.RejectAmount, + Difference: data.Difference, + } + + if data.PurchaseType == ErpRejectOrder { + mergedMap[key].RejectAmount = mergedMap[key].Amount + mergedMap[key].Amount = 0 + } + keys = append(keys, key) // 将键添加到有序的键列表中 + } else { + // 如果键已存在,进行累加操作 + mergedMap[key].Count += data.Count + mergedMap[key].Amount += data.Amount + mergedMap[key].RejectAmount += data.RejectAmount + mergedMap[key].Difference += data.Difference + + if data.PurchaseType == ErpRejectOrder { + mergedMap[key].RejectAmount = mergedMap[key].Amount + mergedMap[key].Amount = 0 + } + } + } + + // 根据有序的键列表顺序构建返回的数组 + var mergedData []PurchaseReportData + for _, key := range keys { + mergedData = append(mergedData, *mergedMap[key]) + } + + return mergedData +} + // 导出供应商采购汇总excel func reportBySupplierExport(req *ErpPurchaseReportBySupplierResp) (string, error) { file := excelize.NewFile() @@ -4380,6 +4795,7 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR List: make([]struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id OrderSerialNumber string `json:"order_serial_number"` + SerialNumber string `json:"serial_number"` PurchaseType string `json:"purchase_type"` ExecuteTime *time.Time `json:"execute_time"` StoreId uint32 `json:"store_id"` @@ -4402,6 +4818,7 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR qs := orm.Eloquent.Debug().Table("erp_purchase_order"). Select("erp_purchase_order.id as erp_purchase_order_id, "+ "erp_purchase_order.serial_number as order_serial_number, "+ + "erp_purchase_inventory.serial_number, "+ "erp_purchase_order.purchase_type, "+ "erp_purchase_inventory.created_at as execute_time, "+ "erp_purchase_order.store_id, "+ @@ -4472,12 +4889,8 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR } if len(req.StoreId) > 0 { - var storeIDs []uint32 - for _, store := range req.StoreId { - storeIDs = append(storeIDs, store) - } - qs = qs.Where("erp_purchase_order.store_id IN (?)", storeIDs) - countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", storeIDs) + qs = qs.Where("erp_purchase_order.store_id IN (?)", req.StoreId) + countQuery = countQuery.Where("erp_purchase_order.store_id IN (?)", req.StoreId) } var count int64 @@ -4499,10 +4912,20 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR // 根据订单类型调整价格的正负性 for i := range resp.List { + resp.List[i].DifferencePrice = 0 + if resp.List[i].PurchaseType == "reject" { - resp.List[i].Price = -resp.List[i].Price + // 采购退货单查询采购价:根据采购入库编号 + price, err := getPrice(resp.List[i].SerialNumber) + if err != nil { + return nil, err + } + + resp.List[i].Price = -float64(price) resp.List[i].DifferencePrice = -resp.List[i].DifferencePrice resp.List[i].RejectPrice = -resp.List[i].RejectPrice + + resp.List[i].DifferencePrice = resp.List[i].Price - resp.List[i].RejectPrice } } @@ -4521,10 +4944,23 @@ func GetReportDetail(req *ErpPurchaseReportDetailReq) (*ErpPurchaseReportDetailR return resp, nil } +// 根据采购单据号查询入库采购价 +func getPrice(serialNumber string) (uint32, error) { + var stockCommodity ErpStockCommodity + err := orm.Eloquent.Table("erp_stock_commodity").Where("stock_sn = ?", serialNumber). + Find(&stockCommodity).Error + if err != nil { + return 0, err + } + + return stockCommodity.WholesalePrice, nil +} + // 计算价格信息 func calculatePrices(list []struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 采购订单id OrderSerialNumber string `json:"order_serial_number"` + SerialNumber string `json:"serial_number"` PurchaseType string `json:"purchase_type"` ExecuteTime *time.Time `json:"execute_time"` StoreId uint32 `json:"store_id"` @@ -4658,3 +5094,185 @@ func reportDetailExport(req *ErpPurchaseReportDetailResp) (string, error) { } return url + fileName, nil } + +// CancelAuditUpdateStock 反审核后更新库存信息 +// 查询订单有无入库信息 +// 采购单,有入库信息,则退库;如果有已审核的退货单则不能反审核,报错提示 +// 退货单,有入库信息,则入库 +func CancelAuditUpdateStock(begin *gorm.DB, req ErpPurchaseOrder) error { + var purchaseOrder ErpPurchaseOrder + err := orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ID).Find(&purchaseOrder).Error + if err != nil { + logger.Error("checkPurchaseInventory purchase order err:", logger.Field("err", err)) + return err + } + + var inventoryList []ErpPurchaseInventory + err = orm.Eloquent.Table("erp_purchase_inventory").Where("erp_purchase_order_id=?", req.ID). + Find(&inventoryList).Error + if err != nil { + logger.Error("purchase commodities err:", logger.Field("err", err)) + return err + } + + if len(inventoryList) == 0 { // 还没有入库记录,直接取消审核 + return nil + } + + if req.PurchaseType == ErpProcureOrder { // 采购单反审核 + // 查询有无退货订单 + var count int64 + stateList := []int{ErpPurchaseOrderUnAudit, ErpPurchaseOrderEnd} + err = orm.Eloquent.Table("erp_purchase_order").Where("rejected_serial_number = ? and state NOT IN (?)", + req.SerialNumber, stateList).Count(&count).Error + if err != nil { + return err + } + + if count > 0 { // 有已审核的退货单 + return errors.New("取消审核失败:已存在采购退库订单,请先将其取消") + } + + //// 更新入库的商品为"采购退库" + //reqParam := &ErpPurchaseInventoryReq{ + // ErpPurchaseOrderId: req.ID, + // PurchaseType: ErpRejectOrder, + // Inventories: inventoryList, + //} + + // 按照采购退货更新库存 + err = InventoryErpPurchaseUpdateRejectStock(begin, inventoryList, purchaseOrder) + if err != nil { + return fmt.Errorf("取消审核失败:%s", err.Error()) + } + + // 更新采购商品表的入库数量 + for _, v := range inventoryList { + err = begin.Model(&ErpPurchaseCommodity{}). + Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId). + UpdateColumn("inventory_count", gorm.Expr("inventory_count - ?", v.Count)).Error + if err != nil { + logger.Error("update inventory count err:", logger.Field("err", err)) + return err + } + } + } else if req.PurchaseType == ErpRejectOrder { // 退货单反审核 + // 更新入库的商品为"采购退库" + reqParam := &ErpPurchaseInventoryReq{ + ErpPurchaseOrderId: req.ID, + PurchaseType: ErpProcureOrder, + Inventories: inventoryList, + } + + // 采购退货单反审核更新库存 + err = ErpRejectOrderCancelAuditUpdateStock(begin, reqParam, purchaseOrder) + if err != nil { + return fmt.Errorf("取消审核失败:%s", err.Error()) + } + + // 更新采购商品表的入库数量 + for _, v := range inventoryList { + err = begin.Model(&ErpPurchaseCommodity{}). + Where("erp_purchase_order_id = ? and erp_commodity_id = ?", v.ErpPurchaseOrderId, v.ErpCommodityId). + UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error + if err != nil { + logger.Error("update inventory count err:", logger.Field("err", err)) + return err + } + } + } else { + return errors.New("取消审核失败:采购类型有误") + } + + // 删除采购入库的记录 + err = begin.Table("erp_purchase_inventory").Where("erp_purchase_order_id = ? and purchase_type = ?", + req.ID, req.PurchaseType).Delete(&ErpPurchaseInventory{}).Error + if err != nil { + return err + } + + return nil +} + +// ErpRejectOrderCancelAuditUpdateStock 采购退货单反审核更新库存 +func ErpRejectOrderCancelAuditUpdateStock(gdb *gorm.DB, req *ErpPurchaseInventoryReq, purchaseOrder ErpPurchaseOrder) error { + // 遍历采购入库商品信息 + var stockList []ErpStockCommodity + for _, v := range req.Inventories { + commodityInfo, err := GetCommodity(v.ErpCommodityId) + if err != nil { + logger.Errorf("GetCommodity err:", err) + return err + } + exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d", + purchaseOrder.StoreId, v.ErpCommodityId)) + if err != nil { + logger.Errorf("exist err:", err) + return err + } + if exist { + err = gdb.Exec(fmt.Sprintf( + "UPDATE erp_stock SET count=count+%d WHERE store_id=%d AND erp_commodity_id=%d;", + v.Count, purchaseOrder.StoreId, v.ErpCommodityId)).Error + if err != nil { + logger.Errorf("update stock err:", err) + return err + } + } else { + return errors.New("未查询到商品库存信息") + } + + // 更新商品库存信息 + // 串码商品直接更新状态为:在库 + if v.IMEIType == 2 || v.IMEIType == 3 { // 串码商品 + if v.IMEI == "" { + return fmt.Errorf("商品[%s]串码为空", v.ErpCommodityName) + } + + err = gdb.Table("erp_stock_commodity").Where("imei = ?", v.IMEI). + Update("state", InStock).Error // 状态更新为采购退货 + if err != nil { + logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) + return err + } + } + + // 非串码商品则新建 + nowTime := time.Now() + stockCommodity := ErpStockCommodity{ + StoreId: purchaseOrder.StoreId, + StoreName: purchaseOrder.StoreName, + ErpCommodityId: v.ErpCommodityId, + ErpCommodityName: v.ErpCommodityName, + CommoditySerialNumber: v.CommoditySerialNumber, + ErpCategoryId: commodityInfo.ErpCategoryId, + ErpCategoryName: commodityInfo.ErpCategoryName, + ErpSupplierId: purchaseOrder.ErpSupplierId, + ErpSupplierName: purchaseOrder.ErpSupplierName, + StaffCostPrice: uint32(v.EmployeePrice - v.ImplementationPrice), + WholesalePrice: uint32(v.ImplementationPrice), + State: InStock, + StorageType: PurchaseInventory, // 采购入库 + FirstStockTime: nowTime, + StockTime: nowTime, + Count: v.Count, + ErpBarcode: commodityInfo.ErpBarcode, // 240106新增商品条码 + IMEIType: v.IMEIType, + IMEI: v.IMEI, + Remark: "", + MemberDiscount: commodityInfo.MemberDiscount, + MinRetailPrice: commodityInfo.MinRetailPrice, + RetailPrice: commodityInfo.RetailPrice, + OriginalSn: purchaseOrder.SerialNumber, + } + stockList = append(stockList, stockCommodity) + } + + err := gdb.Debug().Create(&stockList).Error + if err != nil { + logger.Errorf("create stock commodity err:", err) + return err + } + + return nil +} diff --git a/app/admin/models/sysuser.go b/app/admin/models/sysuser.go index 3fc181f..9ec3c75 100644 --- a/app/admin/models/sysuser.go +++ b/app/admin/models/sysuser.go @@ -3,6 +3,8 @@ package models import ( "encoding/json" "errors" + "fmt" + "gorm.io/gorm" "log" "strings" @@ -61,7 +63,7 @@ type SysUserB struct { CooperativeName string `json:"cooperative_name"` // 合作商名称 AccountType uint32 `json:"account_type"` // 账号类型:1-管理端 StoreData string `gorm:"type:json" json:"store_data,omitempty"` // 有效门店 - StoreList []StoreInfo `gorm:"-" json:"store_list"` // 有效门店列表 + StoreList []StoreInfo `json:"store_list" gorm:"-" ` // 有效门店列表 SalesCommRate float64 `json:"sales_comm_rate"` // 销售提成比例 Uid uint32 `json:"uid" gorm:"column:uid;unique_index"` // 用户uid todo 待添加 BaseModel @@ -237,10 +239,17 @@ func (e *SysUser) GetList() (SysUserView []SysUserView, err error) { return } +type SysUserListResp struct { + Total int `json:"count"` // 总条数 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 页面条数 + List []SysUserPage `json:"list"` // 采购报表信息 +} + func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, error) { var doc []SysUserPage table := orm.Eloquent.Select("sys_user.*,sys_dept.dept_name").Table(e.TableName()) - table = table.Joins("left join sys_dept on sys_dept.dept_id = sys_user.dept_id") + table = table.Joins("left join sys_dept on sys_dept.dept_id = sys_user.dept_id") //es := orm.Eloquent.Select("sys_user.*,sys_dept.dept_name").Table(e.TableName()) //es = table.Joins("left join sys_dept on sys_dept.dept_id = sys_user.dept_id") if e.Username != "" { table = table.Where("username = ?", e.Username) @@ -253,8 +262,20 @@ func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, erro table = table.Where("sys_user.phone = ?", e.Phone) } + if e.RoleId != 0 { + table = table.Where("sys_user.role_id = ?", e.RoleId) + } + + if e.NickName != "" { + table = table.Where("sys_user.nick_name = ?", e.NickName) + } + + if e.StoreId != 0 { + table = table.Where("JSON_CONTAINS(store_data, ?)", fmt.Sprintf(`{"storeId":%d}`, e.StoreId)) + } + if e.DeptId != 0 { - table = table.Where("sys_user.dept_id in (select dept_id from sys_dept where dept_path like ? )", "%"+tools.IntToString(e.DeptId)+"%") + table = table.Where("sys_user.dept_id in (select dept_id from sys_dept where dept_path like ? )", "%"+tools.IntToString(e.DeptId)+"%") //es = table.Where("sys_user.dept_id in (select dept_id from sys_dept where dept_path like ? )", "%"+tools.IntToString(e.DeptId)+"%") } // 数据权限控制(如果不需要数据权限请将此处去掉) @@ -264,9 +285,20 @@ func (e *SysUser) GetPage(pageSize int, pageIndex int) ([]SysUserPage, int, erro if err != nil { return nil, 0, err } - var count int64 - if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Offset(-1).Limit(-1).Count(&count).Error; err != nil { + es := table + var count int64 + err = es.Count(&count).Error + if err != nil { + //logger.Error("count err:", err) + return nil, 0, err + } + + //if err := table.Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Order("sys_user.created_at DESC").Offset(-1).Limit(-1).Count(&count).Error; err != nil { + // return nil, 0, err + //} + + if err = table.Order("sys_user.user_id DESC").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil { return nil, 0, err } @@ -307,7 +339,7 @@ func (e *SysUser) Encrypt() (err error) { } // 添加 -func (e SysUser) Insert() (id int, err error) { +func (e SysUser) Insert(begin *gorm.DB) (id int, err error) { if err = e.Encrypt(); err != nil { return } @@ -321,7 +353,7 @@ func (e SysUser) Insert() (id int, err error) { } //添加数据 - if err = orm.Eloquent.Table(e.TableName()).Create(&e).Error; err != nil { + if err = begin.Table(e.TableName()).Create(&e).Error; err != nil { return } id = e.UserId @@ -329,7 +361,7 @@ func (e SysUser) Insert() (id int, err error) { } // 修改 -func (e *SysUser) Update(id int) (update SysUser, err error) { +func (e *SysUser) Update(begin *gorm.DB, id int) (update SysUser, err error) { if e.Password != "" { if err = e.Encrypt(); err != nil { return @@ -351,9 +383,13 @@ func (e *SysUser) Update(id int) (update SysUser, err error) { e.StoreData = string(storeDataJSON) } + if begin == nil { + begin = orm.Eloquent + } + //参数1:是要修改的数据 //参数2:是修改的数据 - if err = orm.Eloquent.Table(e.TableName()).Model(&update).Updates(&e).Error; err != nil { + if err = begin.Table(e.TableName()).Model(&update).Updates(&e).Error; err != nil { return } return @@ -381,7 +417,7 @@ func (e *SysUser) SetPwd(pwd SysUserPwd) (Result bool, err error) { return } e.Password = pwd.NewPassword - _, err = e.Update(e.UserId) + _, err = e.Update(nil, e.UserId) tools.HasError(err, "更新密码失败(代码202)", 500) return } @@ -392,3 +428,17 @@ func GetUserById(id uint32) *SysUserB { return u } + +// UpdateUserType 更新uid的user_type为2 +func UpdateUserType(begin *gorm.DB, uid, nType uint32) error { + // 更新库存表 + err := begin.Table("user").Where("uid = ?", uid). + Updates(map[string]interface{}{ + "user_type": nType, + }).Error + if err != nil { + return err + } + + return nil +} diff --git a/app/admin/models/user.go b/app/admin/models/user.go index f753e93..0901edc 100644 --- a/app/admin/models/user.go +++ b/app/admin/models/user.go @@ -18,6 +18,7 @@ import ( "net/http" "os" "sort" + "strconv" "strings" "time" ) @@ -48,6 +49,20 @@ const ( UpgradePlatinumToBlackAuto // 20-白金→黑金(自动) ) +const ( + MemberLevelConsumer = 10 // 普通用户 + MemberLevelUser = 1 // 普通会员 + MemberLevelGold = 2 // 黄金会员 + MemberLevelPeriod = 3 // 短期会员 + MemberLevelPlatinum = 4 // 白金会员 + MemberLevelBlackGold = 5 // 黑金会员 +) + +const ( + UserTypeConsumer = 1 // 普通用户 + UserTypeShopAssistant = 2 // 店员 +) + // gen:qs // //go:generate goqueryset -in user.go @@ -100,11 +115,6 @@ func (m *UserInfo) TableName() string { return "user" } -const ( - UserTypeConsumer = 1 // 普通用户 - UserTypeShopAssistant = 2 // 店员 -) - const ( UNMARK = iota MARK @@ -264,6 +274,8 @@ type NewUserListReq struct { OpenStartTime string `json:"open_startTime"` // 首次开通租卡会员-开始时间 OpenEndTime string `json:"open_endTime"` // 首次开通租卡会员-结束时间 Filter bool `json:"filter"` // 是否过滤无滞纳金已标记用户 + SortField string `json:"sort_field"` // 排序字段:滞纳金传"forfeit_penalty" + SortType string `json:"sort_type"` // 排序类型:desc 降序、asc 升序 IsExport uint32 `json:"is_export"` // 1-导出 } @@ -280,20 +292,26 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { PageIndex: req.PageIndex, PageSize: req.PageSize, } - - users := make([]U, 0) - sortFiled := "id" - sortType := "DESC" req.PageIndex -= 1 - if req.PageIndex < 0 { req.PageIndex = 0 } - if req.PageSize == 0 { req.PageSize = 10 } + if req.SortField == "forfeit_penalty" { + return GetUserListByForfeitPenalty(req) + } + + users := make([]U, 0) + if req.SortField == "" { + req.SortField = "id" + } + if req.SortType == "" { + req.SortType = "DESC" + } + qs := orm.Eloquent.Model(&UserInfo{}).Debug() if req.Tel != "" { @@ -376,9 +394,15 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { currentTime := time.Now() // 子查询,查询消费次数和消费金额 - subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(amount) as order_amount - FROM fund_record - WHERE fund_type NOT IN ('deposit_refund', 'express_fee_refund', 'member_expire_delay', 'recycle_card') + //subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(amount) as order_amount + // FROM fund_record + // WHERE fund_type NOT IN ('deposit_refund', 'express_fee_refund', 'member_expire_delay', 'recycle_card') + // GROUP BY uid + // HAVING COUNT(uid) > 0`) + + subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(total_amount) as order_amount + FROM erp_order + WHERE pay_status = 2 GROUP BY uid HAVING COUNT(uid) > 0`) @@ -392,7 +416,7 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { qs = orm.Eloquent.Table("(?) as a", qs) qs = qs.Select("a.*"). Joins("inner join order_card as oc on a.uid=oc.uid"). - Where("pay_status = ? AND card_status IN (?)", 2, []int{1, 2, 3}). + Where("pay_status = ? AND card_status IN (?)", HavePaid, []int{1, 2, 3}). Group("oc.uid"). Having("count(oc.uid) > 0") @@ -409,13 +433,13 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { } if req.IsExport == 1 { // 导出excel - err = qs.Order(fmt.Sprintf("%s %s", sortFiled, sortType)).Find(&users).Error + err = qs.Order(fmt.Sprintf("%s %s", req.SortField, req.SortType)).Find(&users).Error if err != nil && err != RecordNotFound { logger.Errorf("err:", logger.Field("err", err)) return nil, err } } else { - err = qs.Order(fmt.Sprintf("%s %s", sortFiled, sortType)).Offset(req.PageIndex * req.PageSize).Limit(req.PageSize).Find(&users).Error + err = qs.Order(fmt.Sprintf("%s %s", req.SortField, req.SortType)).Offset(req.PageIndex * req.PageSize).Limit(req.PageSize).Find(&users).Error if err != nil && err != RecordNotFound { logger.Errorf("err:", logger.Field("err", err)) return nil, err @@ -436,6 +460,11 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { logger.Errorf("err:", logger.Field("err", err)) return nil, err } + + // 查询门店信息 + storeList := make(map[uint32]Store) + storeList = GetStoreMap() + for i, u := range users { c, ok := cards[u.Uid] if ok { @@ -445,31 +474,17 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { } // 添加门店信息 - users[i].Store, _ = setStore(u.StoreId) + //users[i].Store, _ = setStore(u.StoreId) + store := storeList[uint32(u.StoreId)] + users[i].Store = &store // 校验时间,如果为01-01-01 08:05,则赋值为空 - if u.MemberExpire != nil && u.MemberExpire.IsZero() { - users[i].MemberExpire = nil - } - if u.OpenMemberTime != nil && u.OpenMemberTime.IsZero() { - users[i].OpenMemberTime = nil - } - if u.MemberOpenTime != nil && u.MemberOpenTime.IsZero() { - users[i].MemberOpenTime = nil - } - if u.LastLoginAt != nil && u.LastLoginAt.IsZero() { - users[i].LastLoginAt = nil - } - if u.InviteTime != nil && u.InviteTime.IsZero() { - users[i].InviteTime = nil - } - //if u.RenewalTime != nil && u.RenewalTime.IsZero() { - // users[i].RenewalTime = nil - //} - if u.FirstRetailOrder != nil && u.FirstRetailOrder.IsZero() { - users[i].FirstRetailOrder = nil - } - + validateZeroTime(&users[i].MemberExpire) + validateZeroTime(&users[i].OpenMemberTime) + validateZeroTime(&users[i].MemberOpenTime) + validateZeroTime(&users[i].LastLoginAt) + validateZeroTime(&users[i].InviteTime) + validateZeroTime(&users[i].FirstRetailOrder) } if req.IsExport == 1 { @@ -481,13 +496,145 @@ func GetNewUserList(req *NewUserListReq) (*NewUserListResp, error) { resp.ExportUrl = exportFile } else { resp.List = users - resp.PageIndex = req.PageIndex - resp.PageSize = req.PageSize } return resp, nil } +// GetUserListByForfeitPenalty 滞纳金排序 +func GetUserListByForfeitPenalty(req *NewUserListReq) (*NewUserListResp, error) { + resp := &NewUserListResp{ + PageIndex: req.PageIndex + 1, + PageSize: req.PageSize, + } + + allUsers := make([]U, 0) + qs := orm.Eloquent.Model(&UserInfo{}) + + var count int64 + err := qs.Count(&count).Error + if err != nil { + logger.Errorf("err:", logger.Field("err", err)) + return nil, err + } + + subQuery := fmt.Sprintf(`SELECT uid, COUNT(*) as order_count, SUM(total_amount) as order_amount + FROM erp_order + WHERE pay_status = 2 + GROUP BY uid + HAVING COUNT(uid) > 0`) + + currentTime := time.Now() + // 查询用户数据,过期天数,消费次数,消费金额---20240308修改:过期会员等级会自动改成1普通会员,所以这里的范围改成,1,2,3, 4, 5 + qs = qs.Select("user.*, COALESCE(fr.order_count, 0) as order_count, COALESCE(fr.order_amount, 0) as "+ + "order_amount, CASE WHEN (user.member_level IN (1, 2, 3, 4, 5) AND user.member_expire < ?) "+ + "THEN DATEDIFF(?, user.member_expire) ELSE 0 END AS member_expire_days", currentTime, currentTime). + Joins(fmt.Sprintf("LEFT JOIN (%s) fr ON user.uid = fr.uid", subQuery)) + + if req.Filter { + qs = orm.Eloquent.Table("(?) as a", qs) + qs = qs.Select("a.*"). + Joins("inner join order_card as oc on a.uid=oc.uid"). + Where("pay_status = ? AND card_status IN (?)", HavePaid, []int{1, 2, 3}). + Group("oc.uid"). + Having("count(oc.uid) > 0") + + qs = qs.Where("member_expire_days > 0").Where("mark = ?", UNMARK) + + err := qs.Find(&allUsers).Error + if err != nil && err != RecordNotFound { + logger.Errorf("err:", logger.Field("err", err)) + return nil, err + } + + count = int64(len(allUsers)) + allUsers = nil + } + + err = qs.Find(&allUsers).Error + if err != nil && err != RecordNotFound { + logger.Errorf("err:", logger.Field("err", err)) + return nil, err + } + + // Fetch expired cards for users with positive MemberExpireDays + var uids []uint32 + for _, u := range allUsers { + if u.MemberExpireDays > 0 { + uids = append(uids, u.Uid) + } + } + cards, err := GetUserExpiredCards(uids) + if err != nil { + logger.Errorf("err:", logger.Field("err", err)) + return nil, err + } + + // 查询门店信息 + storeList := make(map[uint32]Store) + storeList = GetStoreMap() + + // Calculate forfeit penalty and update user data + for i, u := range allUsers { + allUsers[i].OrderCards = cards[u.Uid] + allUsers[i].ForfeitPenalty = calculateForfeitPenalty(allUsers[i]) + + store := storeList[uint32(u.StoreId)] + allUsers[i].Store = &store + + // Validate and adjust zero time values + validateZeroTime(&allUsers[i].MemberExpire) + validateZeroTime(&allUsers[i].OpenMemberTime) + validateZeroTime(&allUsers[i].MemberOpenTime) + validateZeroTime(&allUsers[i].LastLoginAt) + validateZeroTime(&allUsers[i].InviteTime) + validateZeroTime(&allUsers[i].FirstRetailOrder) + } + + // Sorting by forfeit penalty + sort.Slice(allUsers, func(i, j int) bool { + return allUsers[i].ForfeitPenalty < allUsers[j].ForfeitPenalty + }) + if req.SortType == "DESC" || req.SortType == "desc" { + reverseUsers(allUsers) + } + + // Paginate results + startIndex := req.PageIndex * req.PageSize + endIndex := startIndex + req.PageSize + if endIndex > len(allUsers) { + endIndex = len(allUsers) + } + + // Slice the users based on pagination + pagedUsers := allUsers[startIndex:endIndex] + + resp.Total = len(allUsers) + resp.List = pagedUsers + + return resp, nil +} + +// Function to calculate forfeit penalty for a user +func calculateForfeitPenalty(user U) int { + return len(user.OrderCards) * 200 * int(user.MemberExpireDays) +} + +// Function to reverse a slice of users +func reverseUsers(users []U) { + for i := len(users)/2 - 1; i >= 0; i-- { + opp := len(users) - 1 - i + users[i], users[opp] = users[opp], users[i] + } +} + +// Function to validate and adjust zero time values +func validateZeroTime(t **time.Time) { + if *t != nil && (*t).IsZero() { + *t = nil + } +} + func setStore(storeId uint64) (*Store, error) { storeInfo := new(Store) err := orm.Eloquent.Table("store").Where("id=?", storeId).Find(storeInfo).Error @@ -2447,6 +2594,30 @@ func GetSysUserInfoByUid(uid uint32) (SysUser, error) { return userInfo, nil } +func countDigits(n uint32) int { + str := strconv.FormatUint(uint64(n), 10) + return len(str) +} + +func GetSysUserInfoById(id uint32) (SysUser, error) { + var userInfo SysUser + if countDigits(id) == 8 { //历史数据为8位的uid + err := orm.Eloquent.Debug().Table("sys_user").Where("uid = ?", id).Find(&userInfo).Error + if err != nil { + logger.Error("err:", logger.Field("err", err)) + return userInfo, err + } + } else { + err := orm.Eloquent.Debug().Table("sys_user").Where("user_id = ?", id).Find(&userInfo).Error + if err != nil { + logger.Error("err:", logger.Field("err", err)) + return userInfo, err + } + } + + return userInfo, nil +} + type UserDepositRefundRecordListReq struct { //StoreId uint32 `json:"store_id"` // 门店id Uid uint32 `json:"uid"` // 用户id @@ -3660,6 +3831,8 @@ func (m *TelListReq) GetTelList() (*TelListResp, error) { var count int64 qs := orm.Eloquent.Table("user").Where("tel like ?", "%"+m.PhoneNum+"%") + qs = qs.Where("member_level in (?)", + []uint32{MemberLevelUser, MemberLevelGold, MemberLevelPeriod, MemberLevelPlatinum, MemberLevelBlackGold}) err := qs.Count(&count).Error if err != nil { logger.Error("count err:", logger.Field("err", err)) @@ -3731,3 +3904,12 @@ func CreateUid() uint32 { return uid } } + +// IsInMemberLevels 判断用户是不是会员 +func IsInMemberLevels(memberLevel uint32) bool { + if memberLevel == MemberLevelUser || memberLevel == MemberLevelGold || memberLevel == MemberLevelPeriod || + memberLevel == MemberLevelPlatinum || memberLevel == MemberLevelBlackGold { + return true + } + return false +} diff --git a/app/admin/models/user_vm.go b/app/admin/models/user_vm.go index f3c8677..0dbe1e2 100644 --- a/app/admin/models/user_vm.go +++ b/app/admin/models/user_vm.go @@ -55,6 +55,9 @@ func UserVmUpdate(gdb *gorm.DB, uid uint32, amount int, event, describe string) return err } + // 变动前的积分 + nBeforeVm := userVm.Vm + //flag := false begin := gdb if gdb == nil { @@ -62,7 +65,7 @@ func UserVmUpdate(gdb *gorm.DB, uid uint32, amount int, event, describe string) begin = orm.Eloquent.Begin() } - if err == RecordNotFound { + if userVm.Uid == 0 { // 没有积分记录 if amount < 0 { begin.Rollback() logger.Error("amount lt 0") @@ -80,11 +83,11 @@ func UserVmUpdate(gdb *gorm.DB, uid uint32, amount int, event, describe string) } } else { // 如果用户积分不够抵扣,则扣到0为止 - if userVm.Vm == 0 || int(userVm.Vm)+amount <= 0 { - sql := fmt.Sprintf("UPDATE user_vm SET vm = ? WHERE uid=?;") + if int(userVm.Vm)+amount <= 0 { + sql := fmt.Sprintf("UPDATE user_vm SET vm = ? WHERE uid=?") err = begin.Exec(sql, 0, uid).Error } else { - sql := fmt.Sprintf("UPDATE user_vm SET vm = vm+? WHERE uid=?;") + sql := fmt.Sprintf("UPDATE user_vm SET vm = vm+? WHERE uid=?") err = begin.Exec(sql, amount, uid).Error } if err != nil { @@ -96,7 +99,7 @@ func UserVmUpdate(gdb *gorm.DB, uid uint32, amount int, event, describe string) vmRecord := &UserVmRecord{ Uid: uid, - BeforeVm: uint32(userVm.Vm), + BeforeVm: uint32(nBeforeVm), AfterVm: 0, // 默认值为 0 Alter: amount, Event: event, diff --git a/docs/docs.go b/docs/docs.go index 19c9113..520aaf8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -4561,16 +4561,58 @@ const docTemplate = `{ "parameters": [ { "type": "string", - "description": "username", + "description": "用户名称", "name": "username", "in": "query" + }, + { + "type": "integer", + "description": "状态:0-正常,1-停用", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "手机号", + "name": "phone", + "in": "query" + }, + { + "type": "string", + "description": "页码", + "name": "pageIndex", + "in": "query" + }, + { + "type": "string", + "description": "页面条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "string", + "description": "角色id", + "name": "roleId", + "in": "query" + }, + { + "type": "string", + "description": "昵称", + "name": "nickName", + "in": "query" + }, + { + "type": "string", + "description": "门店id", + "name": "storeId", + "in": "query" } ], "responses": { "200": { - "description": "{\"code\": -1, \"message\": \"抱歉未找到相关信息\"}", + "description": "OK", "schema": { - "type": "string" + "$ref": "#/definitions/models.SysUserListResp" } } } @@ -5116,11 +5158,7 @@ const docTemplate = `{ "erp_category_id", "erp_supplier_id", "is_imei", - "min_retail_price", - "name", - "retail_price", - "staff_cost_price", - "wholesale_price" + "name" ], "properties": { "brokerage_1": { @@ -5217,11 +5255,8 @@ const docTemplate = `{ "erp_supplier_id", "id", "imei_type", - "min_retail_price", - "name", - "retail_price", - "staff_cost_price", - "wholesale_price" + "is_imei", + "name" ], "properties": { "brokerage_1": { @@ -5252,6 +5287,10 @@ const docTemplate = `{ "description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)", "type": "integer" }, + "is_imei": { + "description": "是否串码:1-串码类 2-非串码", + "type": "integer" + }, "member_discount": { "description": "会员优惠", "type": "number" @@ -6456,10 +6495,6 @@ const docTemplate = `{ "models.ErpCashierListResp": { "type": "object", "properties": { - "count": { - "description": "数据总条数", - "type": "integer" - }, "list": { "type": "array", "items": { @@ -6473,6 +6508,10 @@ const docTemplate = `{ "pageSize": { "description": "每页展示条数", "type": "integer" + }, + "total": { + "description": "数据总条数", + "type": "integer" } } }, @@ -6611,7 +6650,11 @@ const docTemplate = `{ "type": "string" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", + "type": "integer" + }, + "stock_count": { + "description": "库存数量", "type": "integer" }, "wholesale_price": { @@ -7038,6 +7081,10 @@ const docTemplate = `{ "description": "零售订单id(后端生成)", "type": "integer" }, + "erp_stock_commodity_id": { + "description": "库存商品表主键id", + "type": "string" + }, "erp_supplier_id": { "description": "主供应商id", "type": "integer" @@ -7111,7 +7158,7 @@ const docTemplate = `{ "type": "number" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", "type": "integer" }, "staff_profit": { @@ -7222,6 +7269,14 @@ const docTemplate = `{ "models.ErpOrderListReq": { "type": "object", "properties": { + "audit_time_end": { + "description": "审核结束时间", + "type": "string" + }, + "audit_time_start": { + "description": "审核开始时间", + "type": "string" + }, "bill_sn": { "description": "单据编号", "type": "string" @@ -7230,8 +7285,12 @@ const docTemplate = `{ "description": "商品名称", "type": "string" }, - "end_time": { - "description": "结束时间", + "make_time_end": { + "description": "制单结束时间", + "type": "string" + }, + "make_time_start": { + "description": "制单开始时间", "type": "string" }, "pageIndex": { @@ -7258,10 +7317,6 @@ const docTemplate = `{ "description": "扫码枪扫码数据:串码", "type": "string" }, - "start_time": { - "description": "开始时间", - "type": "string" - }, "state": { "description": "订单状态", "type": "string" @@ -7613,7 +7668,7 @@ const docTemplate = `{ "models.ErpOrderSales": { "type": "object", "required": [ - "uid" + "userId" ], "properties": { "createdAt": { @@ -7644,8 +7699,8 @@ const docTemplate = `{ "description": "员工毛利提成:每个商品员工毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去", "type": "number" }, - "uid": { - "description": "销售员用户ID", + "userId": { + "description": "销售员用户ID(20240322:更换为系统用户表主键id)", "type": "integer" } } @@ -7757,6 +7812,18 @@ const docTemplate = `{ "description": "默认员工成本价", "type": "number" }, + "effective_count": { + "description": "有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量)", + "type": "integer" + }, + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "erp_category_name": { + "description": "商品分类名称", + "type": "string" + }, "erp_commodity_id": { "description": "商品id", "type": "integer" @@ -8119,6 +8186,10 @@ const docTemplate = `{ "description": "商品采购订单id", "type": "integer" }, + "erp_stock_commodity_id": { + "description": "库存商品表主键id", + "type": "integer" + }, "id": { "description": "数据库记录编号", "type": "integer" @@ -8128,7 +8199,7 @@ const docTemplate = `{ "type": "string" }, "imei_type": { - "description": "1-无串码 2-串码", + "description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)", "type": "integer" }, "implementation_price": { @@ -8158,8 +8229,6 @@ const docTemplate = `{ "required": [ "erp_purchase_order_id", "inventories", - "inventory_id", - "inventory_name", "purchase_type" ], "properties": { @@ -8298,7 +8367,7 @@ const docTemplate = `{ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 6-入库中 7-退货中", + "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8315,7 +8384,7 @@ const docTemplate = `{ "type": "object", "properties": { "audit_flag": { - "description": "审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成", + "description": "审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中", "type": "string" }, "audit_time_end": { @@ -8352,7 +8421,10 @@ const docTemplate = `{ }, "state": { "description": "状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", - "type": "integer" + "type": "array", + "items": { + "type": "integer" + } }, "store_id": { "description": "门店id", @@ -8434,7 +8506,7 @@ const docTemplate = `{ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", + "description": "2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8561,7 +8633,7 @@ const docTemplate = `{ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", + "description": "2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8689,65 +8761,7 @@ const docTemplate = `{ "description": "供应商采购汇总信息", "type": "array", "items": { - "type": "object", - "properties": { - "amount": { - "description": "采购金额", - "type": "number" - }, - "count": { - "description": "采购数量", - "type": "integer" - }, - "difference": { - "description": "差额", - "type": "number" - }, - "erp_category_id": { - "description": "商品分类id", - "type": "integer" - }, - "erp_category_name": { - "description": "商品分类名称", - "type": "string" - }, - "erp_commodity_id": { - "description": "商品id", - "type": "integer" - }, - "erp_commodity_name": { - "description": "商品名称", - "type": "string" - }, - "erp_purchase_order_id": { - "description": "采购订单id", - "type": "integer" - }, - "erp_supplier_id": { - "description": "供应商id", - "type": "integer" - }, - "erp_supplier_name": { - "description": "供应商名称", - "type": "string" - }, - "purchase_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" - }, - "reject_amount": { - "description": "退货金额", - "type": "number" - }, - "store_id": { - "description": "门店id", - "type": "integer" - }, - "store_name": { - "description": "门店名称", - "type": "string" - } - } + "$ref": "#/definitions/models.PurchaseReportData" } }, "pageIndex": { @@ -8905,6 +8919,10 @@ const docTemplate = `{ "description": "退货价", "type": "number" }, + "serial_number": { + "description": "采购入库编号", + "type": "string" + }, "store_id": { "description": "门店id", "type": "integer" @@ -9114,7 +9132,7 @@ const docTemplate = `{ "type": "integer" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", "type": "integer" }, "state": { @@ -9126,7 +9144,7 @@ const docTemplate = `{ "type": "string" }, "stock_sn": { - "description": "库存订单编号", + "description": "库存订单编号(跟采购入库的入库编号关联)", "type": "string" }, "stock_start_time": { @@ -10020,9 +10038,6 @@ const docTemplate = `{ "models.MallUserVmRecordResp": { "type": "object", "properties": { - "count": { - "type": "integer" - }, "list": { "type": "array", "items": { @@ -10034,6 +10049,9 @@ const docTemplate = `{ }, "page_size": { "type": "integer" + }, + "total": { + "type": "integer" } } }, @@ -10245,6 +10263,14 @@ const docTemplate = `{ "description": "页面条数", "type": "integer" }, + "sort_field": { + "description": "排序字段:滞纳金传\"forfeit_penalty\"", + "type": "string" + }, + "sort_type": { + "description": "排序类型:desc 降序、asc 升序", + "type": "string" + }, "store_id": { "description": "门店id", "type": "integer" @@ -10716,6 +10742,67 @@ const docTemplate = `{ } } }, + "models.PurchaseReportData": { + "type": "object", + "properties": { + "amount": { + "description": "采购金额", + "type": "number" + }, + "count": { + "description": "采购数量", + "type": "integer" + }, + "difference": { + "description": "差额", + "type": "number" + }, + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "erp_category_name": { + "description": "商品分类名称", + "type": "string" + }, + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_purchase_order_id": { + "description": "采购订单id", + "type": "integer" + }, + "erp_supplier_id": { + "description": "供应商id", + "type": "integer" + }, + "erp_supplier_name": { + "description": "供应商名称", + "type": "string" + }, + "purchase_type": { + "description": "采购类型:procure-采购 reject-退货", + "type": "string" + }, + "reject_amount": { + "description": "退货金额", + "type": "number" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + }, "models.QueryCodeReq": { "type": "object", "required": [ @@ -11908,6 +11995,157 @@ const docTemplate = `{ } } }, + "models.SysUserListResp": { + "type": "object", + "properties": { + "count": { + "description": "总条数", + "type": "integer" + }, + "list": { + "description": "采购报表信息", + "type": "array", + "items": { + "$ref": "#/definitions/models.SysUserPage" + } + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "页面条数", + "type": "integer" + } + } + }, + "models.SysUserPage": { + "type": "object", + "properties": { + "account_type": { + "description": "账号类型:1-管理端", + "type": "integer" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "cooperative_business_id": { + "description": "合作商id", + "type": "integer" + }, + "cooperative_name": { + "description": "合作商名称", + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "deletedAt": { + "description": "删除时间", + "type": "string" + }, + "deptId": { + "description": "部门编码", + "type": "integer" + }, + "deptName": { + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "nickName": { + "description": "昵称", + "type": "string" + }, + "params": { + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + }, + "phone": { + "description": "手机号", + "type": "string" + }, + "postId": { + "description": "职位编码", + "type": "integer" + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "sales_comm_rate": { + "description": "销售提成比例", + "type": "number" + }, + "salt": { + "description": "盐", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "string" + }, + "status": { + "description": "状态", + "type": "string" + }, + "store_data": { + "description": "有效门店", + "type": "string" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_list": { + "description": "有效门店列表", + "type": "array", + "items": { + "$ref": "#/definitions/models.StoreInfo" + } + }, + "store_name": { + "description": "门店名称", + "type": "string" + }, + "uid": { + "description": "用户uid todo 待添加", + "type": "integer" + }, + "updateBy": { + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "userId": { + "description": "编码", + "type": "integer" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, "models.TableData": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index 042ef6f..ffbd05a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -4550,16 +4550,58 @@ "parameters": [ { "type": "string", - "description": "username", + "description": "用户名称", "name": "username", "in": "query" + }, + { + "type": "integer", + "description": "状态:0-正常,1-停用", + "name": "status", + "in": "query" + }, + { + "type": "string", + "description": "手机号", + "name": "phone", + "in": "query" + }, + { + "type": "string", + "description": "页码", + "name": "pageIndex", + "in": "query" + }, + { + "type": "string", + "description": "页面条数", + "name": "pageSize", + "in": "query" + }, + { + "type": "string", + "description": "角色id", + "name": "roleId", + "in": "query" + }, + { + "type": "string", + "description": "昵称", + "name": "nickName", + "in": "query" + }, + { + "type": "string", + "description": "门店id", + "name": "storeId", + "in": "query" } ], "responses": { "200": { - "description": "{\"code\": -1, \"message\": \"抱歉未找到相关信息\"}", + "description": "OK", "schema": { - "type": "string" + "$ref": "#/definitions/models.SysUserListResp" } } } @@ -5105,11 +5147,7 @@ "erp_category_id", "erp_supplier_id", "is_imei", - "min_retail_price", - "name", - "retail_price", - "staff_cost_price", - "wholesale_price" + "name" ], "properties": { "brokerage_1": { @@ -5206,11 +5244,8 @@ "erp_supplier_id", "id", "imei_type", - "min_retail_price", - "name", - "retail_price", - "staff_cost_price", - "wholesale_price" + "is_imei", + "name" ], "properties": { "brokerage_1": { @@ -5241,6 +5276,10 @@ "description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)", "type": "integer" }, + "is_imei": { + "description": "是否串码:1-串码类 2-非串码", + "type": "integer" + }, "member_discount": { "description": "会员优惠", "type": "number" @@ -6445,10 +6484,6 @@ "models.ErpCashierListResp": { "type": "object", "properties": { - "count": { - "description": "数据总条数", - "type": "integer" - }, "list": { "type": "array", "items": { @@ -6462,6 +6497,10 @@ "pageSize": { "description": "每页展示条数", "type": "integer" + }, + "total": { + "description": "数据总条数", + "type": "integer" } } }, @@ -6600,7 +6639,11 @@ "type": "string" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", + "type": "integer" + }, + "stock_count": { + "description": "库存数量", "type": "integer" }, "wholesale_price": { @@ -7027,6 +7070,10 @@ "description": "零售订单id(后端生成)", "type": "integer" }, + "erp_stock_commodity_id": { + "description": "库存商品表主键id", + "type": "string" + }, "erp_supplier_id": { "description": "主供应商id", "type": "integer" @@ -7100,7 +7147,7 @@ "type": "number" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", "type": "integer" }, "staff_profit": { @@ -7211,6 +7258,14 @@ "models.ErpOrderListReq": { "type": "object", "properties": { + "audit_time_end": { + "description": "审核结束时间", + "type": "string" + }, + "audit_time_start": { + "description": "审核开始时间", + "type": "string" + }, "bill_sn": { "description": "单据编号", "type": "string" @@ -7219,8 +7274,12 @@ "description": "商品名称", "type": "string" }, - "end_time": { - "description": "结束时间", + "make_time_end": { + "description": "制单结束时间", + "type": "string" + }, + "make_time_start": { + "description": "制单开始时间", "type": "string" }, "pageIndex": { @@ -7247,10 +7306,6 @@ "description": "扫码枪扫码数据:串码", "type": "string" }, - "start_time": { - "description": "开始时间", - "type": "string" - }, "state": { "description": "订单状态", "type": "string" @@ -7602,7 +7657,7 @@ "models.ErpOrderSales": { "type": "object", "required": [ - "uid" + "userId" ], "properties": { "createdAt": { @@ -7633,8 +7688,8 @@ "description": "员工毛利提成:每个商品员工毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去", "type": "number" }, - "uid": { - "description": "销售员用户ID", + "userId": { + "description": "销售员用户ID(20240322:更换为系统用户表主键id)", "type": "integer" } } @@ -7746,6 +7801,18 @@ "description": "默认员工成本价", "type": "number" }, + "effective_count": { + "description": "有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量)", + "type": "integer" + }, + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "erp_category_name": { + "description": "商品分类名称", + "type": "string" + }, "erp_commodity_id": { "description": "商品id", "type": "integer" @@ -8108,6 +8175,10 @@ "description": "商品采购订单id", "type": "integer" }, + "erp_stock_commodity_id": { + "description": "库存商品表主键id", + "type": "integer" + }, "id": { "description": "数据库记录编号", "type": "integer" @@ -8117,7 +8188,7 @@ "type": "string" }, "imei_type": { - "description": "1-无串码 2-串码", + "description": "1-无串码 2-串码(系统生成) 3-串码(手动添加)", "type": "integer" }, "implementation_price": { @@ -8147,8 +8218,6 @@ "required": [ "erp_purchase_order_id", "inventories", - "inventory_id", - "inventory_name", "purchase_type" ], "properties": { @@ -8287,7 +8356,7 @@ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 6-入库中 7-退货中", + "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8304,7 +8373,7 @@ "type": "object", "properties": { "audit_flag": { - "description": "审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成", + "description": "审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中", "type": "string" }, "audit_time_end": { @@ -8341,7 +8410,10 @@ }, "state": { "description": "状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", - "type": "integer" + "type": "array", + "items": { + "type": "integer" + } }, "store_id": { "description": "门店id", @@ -8423,7 +8495,7 @@ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", + "description": "2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8550,7 +8622,7 @@ "type": "string" }, "state": { - "description": "1-待审核 2-待入库 3-待退货 4-已完成 5-已终止", + "description": "2-待入库 3-待退货 4-已完成 5-已终止", "type": "integer" }, "store_id": { @@ -8678,65 +8750,7 @@ "description": "供应商采购汇总信息", "type": "array", "items": { - "type": "object", - "properties": { - "amount": { - "description": "采购金额", - "type": "number" - }, - "count": { - "description": "采购数量", - "type": "integer" - }, - "difference": { - "description": "差额", - "type": "number" - }, - "erp_category_id": { - "description": "商品分类id", - "type": "integer" - }, - "erp_category_name": { - "description": "商品分类名称", - "type": "string" - }, - "erp_commodity_id": { - "description": "商品id", - "type": "integer" - }, - "erp_commodity_name": { - "description": "商品名称", - "type": "string" - }, - "erp_purchase_order_id": { - "description": "采购订单id", - "type": "integer" - }, - "erp_supplier_id": { - "description": "供应商id", - "type": "integer" - }, - "erp_supplier_name": { - "description": "供应商名称", - "type": "string" - }, - "purchase_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" - }, - "reject_amount": { - "description": "退货金额", - "type": "number" - }, - "store_id": { - "description": "门店id", - "type": "integer" - }, - "store_name": { - "description": "门店名称", - "type": "string" - } - } + "$ref": "#/definitions/models.PurchaseReportData" } }, "pageIndex": { @@ -8894,6 +8908,10 @@ "description": "退货价", "type": "number" }, + "serial_number": { + "description": "采购入库编号", + "type": "string" + }, "store_id": { "description": "门店id", "type": "integer" @@ -9103,7 +9121,7 @@ "type": "integer" }, "staff_cost_price": { - "description": "员工成本价加价", + "description": "员工成本价加价(如:加价50,不是加价后的价格)", "type": "integer" }, "state": { @@ -9115,7 +9133,7 @@ "type": "string" }, "stock_sn": { - "description": "库存订单编号", + "description": "库存订单编号(跟采购入库的入库编号关联)", "type": "string" }, "stock_start_time": { @@ -10009,9 +10027,6 @@ "models.MallUserVmRecordResp": { "type": "object", "properties": { - "count": { - "type": "integer" - }, "list": { "type": "array", "items": { @@ -10023,6 +10038,9 @@ }, "page_size": { "type": "integer" + }, + "total": { + "type": "integer" } } }, @@ -10234,6 +10252,14 @@ "description": "页面条数", "type": "integer" }, + "sort_field": { + "description": "排序字段:滞纳金传\"forfeit_penalty\"", + "type": "string" + }, + "sort_type": { + "description": "排序类型:desc 降序、asc 升序", + "type": "string" + }, "store_id": { "description": "门店id", "type": "integer" @@ -10705,6 +10731,67 @@ } } }, + "models.PurchaseReportData": { + "type": "object", + "properties": { + "amount": { + "description": "采购金额", + "type": "number" + }, + "count": { + "description": "采购数量", + "type": "integer" + }, + "difference": { + "description": "差额", + "type": "number" + }, + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "erp_category_name": { + "description": "商品分类名称", + "type": "string" + }, + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_purchase_order_id": { + "description": "采购订单id", + "type": "integer" + }, + "erp_supplier_id": { + "description": "供应商id", + "type": "integer" + }, + "erp_supplier_name": { + "description": "供应商名称", + "type": "string" + }, + "purchase_type": { + "description": "采购类型:procure-采购 reject-退货", + "type": "string" + }, + "reject_amount": { + "description": "退货金额", + "type": "number" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + }, "models.QueryCodeReq": { "type": "object", "required": [ @@ -11897,6 +11984,157 @@ } } }, + "models.SysUserListResp": { + "type": "object", + "properties": { + "count": { + "description": "总条数", + "type": "integer" + }, + "list": { + "description": "采购报表信息", + "type": "array", + "items": { + "$ref": "#/definitions/models.SysUserPage" + } + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "页面条数", + "type": "integer" + } + } + }, + "models.SysUserPage": { + "type": "object", + "properties": { + "account_type": { + "description": "账号类型:1-管理端", + "type": "integer" + }, + "avatar": { + "description": "头像", + "type": "string" + }, + "cooperative_business_id": { + "description": "合作商id", + "type": "integer" + }, + "cooperative_name": { + "description": "合作商名称", + "type": "string" + }, + "createBy": { + "type": "string" + }, + "createdAt": { + "description": "创建时间", + "type": "string" + }, + "dataScope": { + "type": "string" + }, + "deletedAt": { + "description": "删除时间", + "type": "string" + }, + "deptId": { + "description": "部门编码", + "type": "integer" + }, + "deptName": { + "type": "string" + }, + "email": { + "description": "邮箱", + "type": "string" + }, + "nickName": { + "description": "昵称", + "type": "string" + }, + "params": { + "type": "string" + }, + "password": { + "description": "密码", + "type": "string" + }, + "phone": { + "description": "手机号", + "type": "string" + }, + "postId": { + "description": "职位编码", + "type": "integer" + }, + "remark": { + "description": "备注", + "type": "string" + }, + "roleId": { + "description": "角色编码", + "type": "integer" + }, + "sales_comm_rate": { + "description": "销售提成比例", + "type": "number" + }, + "salt": { + "description": "盐", + "type": "string" + }, + "sex": { + "description": "性别", + "type": "string" + }, + "status": { + "description": "状态", + "type": "string" + }, + "store_data": { + "description": "有效门店", + "type": "string" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_list": { + "description": "有效门店列表", + "type": "array", + "items": { + "$ref": "#/definitions/models.StoreInfo" + } + }, + "store_name": { + "description": "门店名称", + "type": "string" + }, + "uid": { + "description": "用户uid todo 待添加", + "type": "integer" + }, + "updateBy": { + "type": "string" + }, + "updatedAt": { + "description": "更新时间", + "type": "string" + }, + "userId": { + "description": "编码", + "type": "integer" + }, + "username": { + "description": "用户名", + "type": "string" + } + } + }, "models.TableData": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 74b618e..465ec4a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -154,11 +154,7 @@ definitions: - erp_category_id - erp_supplier_id - is_imei - - min_retail_price - name - - retail_price - - staff_cost_price - - wholesale_price type: object basic.CommodityDelRequest: properties: @@ -200,6 +196,9 @@ definitions: imei_type: description: 1-无串码 2-串码(系统生成) 3-串码(手动添加) type: integer + is_imei: + description: 是否串码:1-串码类 2-非串码 + type: integer member_discount: description: 会员优惠 type: number @@ -229,11 +228,8 @@ definitions: - erp_supplier_id - id - imei_type - - min_retail_price + - is_imei - name - - retail_price - - staff_cost_price - - wholesale_price type: object basic.CreateCategoryRequest: properties: @@ -1085,9 +1081,6 @@ definitions: type: object models.ErpCashierListResp: properties: - count: - description: 数据总条数 - type: integer list: items: $ref: '#/definitions/models.ErpCashier' @@ -1098,6 +1091,9 @@ definitions: pageSize: description: 每页展示条数 type: integer + total: + description: 数据总条数 + type: integer type: object models.ErpCategory: properties: @@ -1198,7 +1194,10 @@ definitions: description: 商品编号 type: string staff_cost_price: - description: 员工成本价加价 + description: 员工成本价加价(如:加价50,不是加价后的价格) + type: integer + stock_count: + description: 库存数量 type: integer wholesale_price: description: 指导采购价 @@ -1511,6 +1510,9 @@ definitions: erp_order_id: description: 零售订单id(后端生成) type: integer + erp_stock_commodity_id: + description: 库存商品表主键id + type: string erp_supplier_id: description: 主供应商id type: integer @@ -1566,7 +1568,7 @@ definitions: description: 销售毛利:实际零售价-采购单价;如果为退货订单,则为实际退货价-采购单价 type: number staff_cost_price: - description: 员工成本价加价 + description: 员工成本价加价(如:加价50,不是加价后的价格) type: integer staff_profit: description: 员工毛利:实际零售价-员工成本价;如果为退货订单,则为实际退货价-员工成本价 @@ -1648,14 +1650,23 @@ definitions: type: object models.ErpOrderListReq: properties: + audit_time_end: + description: 审核结束时间 + type: string + audit_time_start: + description: 审核开始时间 + type: string bill_sn: description: 单据编号 type: string commodity_name: description: 商品名称 type: string - end_time: - description: 结束时间 + make_time_end: + description: 制单结束时间 + type: string + make_time_start: + description: 制单开始时间 type: string pageIndex: description: 页码 @@ -1675,9 +1686,6 @@ definitions: scan_code: description: 扫码枪扫码数据:串码 type: string - start_time: - description: 开始时间 - type: string state: description: 订单状态 type: string @@ -1950,11 +1958,11 @@ definitions: staff_profit_per: description: 员工毛利提成:每个商品员工毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去 type: number - uid: - description: 销售员用户ID + userId: + description: 销售员用户ID(20240322:更换为系统用户表主键id) type: integer required: - - uid + - userId type: object models.ErpOrderShowConfig: properties: @@ -2032,6 +2040,15 @@ definitions: default_employee_price: description: 默认员工成本价 type: number + effective_count: + description: 有效数量(该商品实际库存详情处剩余有效数,不包含已出库的数量) + type: integer + erp_category_id: + description: 商品分类id + type: integer + erp_category_name: + description: 商品分类名称 + type: string erp_commodity_id: description: 商品id type: integer @@ -2295,6 +2312,9 @@ definitions: erp_purchase_order_id: description: 商品采购订单id type: integer + erp_stock_commodity_id: + description: 库存商品表主键id + type: integer id: description: 数据库记录编号 type: integer @@ -2302,7 +2322,7 @@ definitions: description: 商品串码 type: string imei_type: - description: 1-无串码 2-串码 + description: 1-无串码 2-串码(系统生成) 3-串码(手动添加) type: integer implementation_price: description: 执行单价 @@ -2344,8 +2364,6 @@ definitions: required: - erp_purchase_order_id - inventories - - inventory_id - - inventory_name - purchase_type type: object models.ErpPurchaseOrder: @@ -2430,7 +2448,7 @@ definitions: description: 单据编号 type: string state: - description: 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 6-入库中 7-退货中 + description: 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 type: integer store_id: description: 门店id @@ -2442,7 +2460,7 @@ definitions: models.ErpPurchaseOrderListReq: properties: audit_flag: - description: 审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成 + description: 审核标记(默认展示所有):ON-订单只展示已审核的采购入库订单,含待入库/已终止/已完成/入库中 type: string audit_time_end: description: 审核结束时间 @@ -2470,7 +2488,9 @@ definitions: type: string state: description: 状态:1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 - type: integer + items: + type: integer + type: array store_id: description: 门店id type: integer @@ -2529,7 +2549,7 @@ definitions: description: 单据编号 type: string state: - description: 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 + description: 2-待入库 3-待退货 4-已完成 5-已终止 type: integer store_id: description: 门店id @@ -2622,7 +2642,7 @@ definitions: description: 单据编号 type: string state: - description: 1-待审核 2-待入库 3-待退货 4-已完成 5-已终止 + description: 2-待入库 3-待退货 4-已完成 5-已终止 type: integer store_id: description: 门店id @@ -2714,50 +2734,7 @@ definitions: list: description: 供应商采购汇总信息 items: - properties: - amount: - description: 采购金额 - type: number - count: - description: 采购数量 - type: integer - difference: - description: 差额 - type: number - erp_category_id: - description: 商品分类id - type: integer - erp_category_name: - description: 商品分类名称 - type: string - erp_commodity_id: - description: 商品id - type: integer - erp_commodity_name: - description: 商品名称 - type: string - erp_purchase_order_id: - description: 采购订单id - type: integer - erp_supplier_id: - description: 供应商id - type: integer - erp_supplier_name: - description: 供应商名称 - type: string - purchase_type: - description: 采购类型:procure-采购 reject-退货 - type: string - reject_amount: - description: 退货金额 - type: number - store_id: - description: 门店id - type: integer - store_name: - description: 门店名称 - type: string - type: object + $ref: '#/definitions/models.PurchaseReportData' type: array pageIndex: description: 页码 @@ -2873,6 +2850,9 @@ definitions: reject_price: description: 退货价 type: number + serial_number: + description: 采购入库编号 + type: string store_id: description: 门店id type: integer @@ -3027,7 +3007,7 @@ definitions: description: 指导零售价 type: integer staff_cost_price: - description: 员工成本价加价 + description: 员工成本价加价(如:加价50,不是加价后的价格) type: integer state: description: 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 @@ -3036,7 +3016,7 @@ definitions: description: 最近入库结束时间 type: string stock_sn: - description: 库存订单编号 + description: 库存订单编号(跟采购入库的入库编号关联) type: string stock_start_time: description: 最近入库开始时间 @@ -3682,8 +3662,6 @@ definitions: type: object models.MallUserVmRecordResp: properties: - count: - type: integer list: items: $ref: '#/definitions/models.MallUserVmRecordData' @@ -3692,6 +3670,8 @@ definitions: type: integer page_size: type: integer + total: + type: integer type: object models.Menu: properties: @@ -3841,6 +3821,12 @@ definitions: pageSize: description: 页面条数 type: integer + sort_field: + description: 排序字段:滞纳金传"forfeit_penalty" + type: string + sort_type: + description: 排序类型:desc 降序、asc 升序 + type: string store_id: description: 门店id type: integer @@ -4175,6 +4161,51 @@ definitions: description: 更新时间 type: string type: object + models.PurchaseReportData: + properties: + amount: + description: 采购金额 + type: number + count: + description: 采购数量 + type: integer + difference: + description: 差额 + type: number + erp_category_id: + description: 商品分类id + type: integer + erp_category_name: + description: 商品分类名称 + type: string + erp_commodity_id: + description: 商品id + type: integer + erp_commodity_name: + description: 商品名称 + type: string + erp_purchase_order_id: + description: 采购订单id + type: integer + erp_supplier_id: + description: 供应商id + type: integer + erp_supplier_name: + description: 供应商名称 + type: string + purchase_type: + description: 采购类型:procure-采购 reject-退货 + type: string + reject_amount: + description: 退货金额 + type: number + store_id: + description: 门店id + type: integer + store_name: + description: 门店名称 + type: string + type: object models.QueryCodeReq: properties: pageIndex: @@ -5041,6 +5072,116 @@ definitions: description: 用户名 type: string type: object + models.SysUserListResp: + properties: + count: + description: 总条数 + type: integer + list: + description: 采购报表信息 + items: + $ref: '#/definitions/models.SysUserPage' + type: array + pageIndex: + description: 页码 + type: integer + pageSize: + description: 页面条数 + type: integer + type: object + models.SysUserPage: + properties: + account_type: + description: 账号类型:1-管理端 + type: integer + avatar: + description: 头像 + type: string + cooperative_business_id: + description: 合作商id + type: integer + cooperative_name: + description: 合作商名称 + type: string + createBy: + type: string + createdAt: + description: 创建时间 + type: string + dataScope: + type: string + deletedAt: + description: 删除时间 + type: string + deptId: + description: 部门编码 + type: integer + deptName: + type: string + email: + description: 邮箱 + type: string + nickName: + description: 昵称 + type: string + params: + type: string + password: + description: 密码 + type: string + phone: + description: 手机号 + type: string + postId: + description: 职位编码 + type: integer + remark: + description: 备注 + type: string + roleId: + description: 角色编码 + type: integer + sales_comm_rate: + description: 销售提成比例 + type: number + salt: + description: 盐 + type: string + sex: + description: 性别 + type: string + status: + description: 状态 + type: string + store_data: + description: 有效门店 + type: string + store_id: + description: 门店id + type: integer + store_list: + description: 有效门店列表 + items: + $ref: '#/definitions/models.StoreInfo' + type: array + store_name: + description: 门店名称 + type: string + uid: + description: 用户uid todo 待添加 + type: integer + updateBy: + type: string + updatedAt: + description: 更新时间 + type: string + userId: + description: 编码 + type: integer + username: + description: 用户名 + type: string + type: object models.TableData: properties: DJ: @@ -8409,15 +8550,43 @@ paths: get: description: 获取JSON parameters: - - description: username + - description: 用户名称 in: query name: username type: string + - description: 状态:0-正常,1-停用 + in: query + name: status + type: integer + - description: 手机号 + in: query + name: phone + type: string + - description: 页码 + in: query + name: pageIndex + type: string + - description: 页面条数 + in: query + name: pageSize + type: string + - description: 角色id + in: query + name: roleId + type: string + - description: 昵称 + in: query + name: nickName + type: string + - description: 门店id + in: query + name: storeId + type: string responses: "200": - description: '{"code": -1, "message": "抱歉未找到相关信息"}' + description: OK schema: - type: string + $ref: '#/definitions/models.SysUserListResp' security: - Bearer: [] summary: 列表用户信息数据(update)