From ed3d037a6e5506503d32b57716ad0ca6c42b12f8 Mon Sep 17 00:00:00 2001 From: chenlin Date: Fri, 23 Feb 2024 18:06:21 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=96=B0=E5=A2=9E=E9=87=87=E8=B4=AD=E9=9C=80?= =?UTF-8?q?=E6=B1=82=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/admin/apis/basic/commodity.go | 12 + app/admin/apis/purchasemanage/purchase.go | 127 +- app/admin/apis/system/sysuser.go | 2 + app/admin/models/erp_order.go | 66 +- app/admin/models/file.go | 34 +- app/admin/models/purchase.go | 1531 ++++++++++++++++++--- app/admin/models/sysuser.go | 1 + app/admin/router/purchasemanage.go | 21 +- docs/docs.go | 461 ++++++- docs/swagger.json | 461 ++++++- docs/swagger.yaml | 331 ++++- 11 files changed, 2713 insertions(+), 334 deletions(-) diff --git a/app/admin/apis/basic/commodity.go b/app/admin/apis/basic/commodity.go index bcba97d..cc15bc5 100644 --- a/app/admin/apis/basic/commodity.go +++ b/app/admin/apis/basic/commodity.go @@ -362,6 +362,18 @@ func CommodityDel(c *gin.Context) { return } + // 检查商品是否存在 + if !models.IsExistingCommodity(req.ErpCommodityId) { + app.Error(c, http.StatusInternalServerError, errors.New("该商品不存在"), "该商品不存在") + return + } + + // 删除商品之前需要判断该商品是否有库存 + if models.CheckCommodityIsHavaStock(req.ErpCommodityId) { + app.Error(c, http.StatusInternalServerError, errors.New("该商品有库存不可删除"), "该商品有库存不可删除") + return + } + err := orm.Eloquent.Table("erp_commodity").Where("id=?", req.ErpCommodityId).Delete(&models.ErpCommodity{}).Error if err != nil { //logger.Error("erp commodity err:", err) diff --git a/app/admin/apis/purchasemanage/purchase.go b/app/admin/apis/purchasemanage/purchase.go index 233264c..b6a24ae 100644 --- a/app/admin/apis/purchasemanage/purchase.go +++ b/app/admin/apis/purchasemanage/purchase.go @@ -2,6 +2,7 @@ package purchasemanage import ( "errors" + "fmt" "github.com/gin-gonic/gin" model "go-admin/app/admin/models" orm "go-admin/common/global" @@ -154,6 +155,12 @@ func ErpPurchaseDetail(c *gin.Context) { app.Error(c, http.StatusBadRequest, err, "获取失败") return } + if purchaseOrder.ID == 0 { + logger.Error("purchase commodities err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, err, fmt.Sprintf("未查询到采购订单[%d]", req.ErpPurchaseOrderId)) + return + } + var purchaseCommodities []model.ErpPurchaseCommodity err = orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id=?", req.ErpPurchaseOrderId). Find(&purchaseCommodities).Error @@ -162,9 +169,26 @@ func ErpPurchaseDetail(c *gin.Context) { app.Error(c, http.StatusBadRequest, err, "获取失败") return } - purchaseOrder.Commodities = purchaseCommodities - // todo 需要添加实际采购入库信息 + // 添加实际采购入库信息 + var commodityList []model.ErpPurchaseCommodity + for _, v := range purchaseCommodities { + result, err := model.GetTotalsAndAveragesByCommodityID(v.ErpCommodityId) + if err != nil { + logger.Error("GetTotalsAndAveragesByCommodityID err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, err, "获取失败") + return + } + + v.ExecutionCount = result.TotalCount + v.ExecutionAmount = result.TotalAmount + v.ExecutionEmployeePrice = result.AvgEmployeePrice + v.ExecutionPrice = result.AvgImplementationPrice + commodityList = append(commodityList, v) + } + + purchaseOrder.Commodities = commodityList + app.OK(c, purchaseOrder, "") return } @@ -355,7 +379,7 @@ func ErpPurchaseInventory(c *gin.Context) { return } - app.OK(c, nil, "") + app.OK(c, nil, "操作成功") return } @@ -437,6 +461,101 @@ func ErpPurchaseExecute(c *gin.Context) { return } - app.OK(c, resp, "") + app.OK(c, resp, "执行成功") + return +} + +// ErpPurchaseDemandCreate 创建采购需求 +// @Summary 创建采购需求 +// @Tags 采购需求, V1.3.0 +// @Produce json +// @Accept json +// @Param request body models.CreateErpPurchaseDemandReq true "创建采购需求模型" +// @Success 200 {object} app.Response +// @Router /api/v1/erp_purchase/demand/create [post] +func ErpPurchaseDemandCreate(c *gin.Context) { + req := new(model.CreateErpPurchaseDemandReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") + return + } + + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + err = model.CreateErpPurchaseDemand(req, sysUser) + if err != nil { + logger.Error("CreateErpPurchaseDemand err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "创建失败:"+err.Error()) + return + } + + app.OK(c, nil, "创建成功") + return +} + +// ErpPurchaseDemandGet 获取采购需求 +// @Summary 获取采购需求 +// @Tags 采购需求, V1.3.0 +// @Produce json +// @Accept json +// @Param request body models.GetErpPurchaseDemandReq true "获取采购需求模型" +// @Success 200 {object} models.GetErpPurchaseDemandResp +// @Router /api/v1/erp_purchase/demand/get [post] +func ErpPurchaseDemandGet(c *gin.Context) { + req := new(model.GetErpPurchaseDemandReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") + return + } + + resp, err := model.GetErpPurchaseDemand(req) + if err != nil { + logger.Error("GetErpPurchaseDemand err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "获取失败:"+err.Error()) + return + } + + app.OK(c, resp, "获取成功") + return +} + +// ErpPurchaseDemandFinish 完成采购需求 +// @Summary 完成采购需求 +// @Tags 采购需求, V1.3.0 +// @Produce json +// @Accept json +// @Param request body models.FinishErpPurchaseDemandReq true "完成采购需求模型" +// @Success 200 {object} app.Response +// @Router /api/v1/erp_purchase/demand/finish [post] +func ErpPurchaseDemandFinish(c *gin.Context) { + req := new(model.FinishErpPurchaseDemandReq) + if err := c.ShouldBindJSON(&req); err != nil { + logger.Error("ShouldBindJSON err:", logger.Field("err", err)) + app.Error(c, http.StatusBadRequest, errors.New("para err"), "参数错误") + return + } + + sysUser, err := model.GetSysUserByCtx(c) + if err != nil { + logger.Error("sys user err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败") + return + } + + err = model.FinishErpPurchaseDemand(req, sysUser) + if err != nil { + logger.Error("CreateErpPurchaseDemand err:", logger.Field("err", err)) + app.Error(c, http.StatusInternalServerError, err, "操作失败:"+err.Error()) + return + } + + app.OK(c, nil, "操作成功") return } diff --git a/app/admin/apis/system/sysuser.go b/app/admin/apis/system/sysuser.go index 96f7139..4a4b7ed 100644 --- a/app/admin/apis/system/sysuser.go +++ b/app/admin/apis/system/sysuser.go @@ -183,6 +183,7 @@ func InsertSysUser(c *gin.Context) { CooperativeBusinessId: req.CooperativeBusinessId, CooperativeName: req.CooperativeName, SalesCommRate: SalesCommRateFloat, + Uid: req.Uid, }, } @@ -241,6 +242,7 @@ func UpdateSysUser(c *gin.Context) { CooperativeBusinessId: req.CooperativeBusinessId, CooperativeName: req.CooperativeName, SalesCommRate: SalesCommRateFloat, + Uid: req.Uid, }, } diff --git a/app/admin/models/erp_order.go b/app/admin/models/erp_order.go index 13d53b4..2593c6e 100644 --- a/app/admin/models/erp_order.go +++ b/app/admin/models/erp_order.go @@ -1400,8 +1400,10 @@ func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManage logger.Error("QueryStoreManageData count err:", logger.Field("err", err)) return nil, err } - resp.Total = len(storeManageDataList) - storeManageDataList = nil + + finalStoreManageDataList := constructFinalStoreManageDataList(storeManageDataList, req) + resp.Total = len(finalStoreManageDataList) + finalStoreManageDataList = nil if req.IsExport == 1 { //导出excel // 查询数据 @@ -1426,7 +1428,8 @@ func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManage storeName = storeInfo.Name } - filePath, err := storeManageDataExport(storeManageDataList, storeName) + finalStoreManageDataList = constructFinalStoreManageDataList(storeManageDataList, req) + filePath, err := storeManageDataExport(finalStoreManageDataList, storeName) if err != nil { logger.Error("StoreManageDataExport err:", logger.Field("err", err)) return nil, err @@ -1448,7 +1451,8 @@ func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManage return nil, err } - resp.List = storeManageDataList + finalStoreManageDataList = constructFinalStoreManageDataList(storeManageDataList, req) + resp.List = finalStoreManageDataList resp.PageIndex = req.PageIndex resp.PageSize = req.PageSize } @@ -1456,6 +1460,46 @@ func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManage return resp, nil } +// 查询门店经营数据,为空的日期默认填充数据为0 +func constructFinalStoreManageDataList(storeManageDataList []StoreManageData, req *ErpOrderStoreManageDataReq) []StoreManageData { + // Create a map to store data by date for easier processing + storeDataMap := make(map[string]StoreManageData) + for _, data := range storeManageDataList { + storeDataMap[data.Date] = data + } + + // Construct the final response with consecutive dates and defaulting to 0 for missing data + var finalStoreManageDataList []StoreManageData + startDate, err := time.Parse(QueryTimeFormat, req.StartTime) + if err != nil { + logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err)) + return storeManageDataList + } + endDate, err := time.Parse(QueryTimeFormat, req.EndTime) + if err != nil { + logger.Error("constructFinalStoreManageDataList time Parse err:", logger.Field("err", err)) + return storeManageDataList + } + + for d := startDate; d.Before(endDate) || d.Equal(endDate); d = d.AddDate(0, 0, 1) { + dateStr := d.Format("2006-01-02") + data, found := storeDataMap[dateStr] + if !found { + data = StoreManageData{ + Date: dateStr, + TotalSalesAmount: 0, + PromotionFee: 0, + SalesProfit: 0, + StaffProfit: 0, + Count: 0, + } + } + finalStoreManageDataList = append(finalStoreManageDataList, data) + } + + return finalStoreManageDataList +} + // StoreManageDataExport 导出门店经营数据 func storeManageDataExport(list []StoreManageData, storeName string) (string, error) { file := excelize.NewFile() @@ -2054,17 +2098,17 @@ func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai qs = qs.Where("erp_order.store_id=?", req.StoreId) } if req.Salesman != 0 { // 销售员 - qs = qs.Where("erp_order.salesman1 = ? or erp_order.salesman2 = ?", req.Salesman, req.Salesman) + qs = qs.Where("JSON_CONTAINS(erp_order.salesman_list, ?)", fmt.Sprintf(`{"uid":%d}`, req.Salesman)) } if req.StartTime != "" { // 审核开始时间 - parse, err := time.Parse(DateTimeFormat, req.StartTime) + parse, err := time.Parse(QueryTimeFormat, req.StartTime) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("erp_order.audit_time > ?", parse) } if req.EndTime != "" { // 审核结束时间 - parse, err := time.Parse(DateTimeFormat, req.EndTime) + parse, err := time.Parse(QueryTimeFormat, req.EndTime) if err != nil { logger.Errorf("err:", err) } @@ -2304,7 +2348,7 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai qs = qs.Where("retail_type=?", req.RetailType) } if req.Uid != 0 { // 用户ID - qs = qs.Where("uid=?", req.Uid) + qs = qs.Where("erp_order.uid=?", req.Uid) } if req.Tel != "" { // 用户手机号 qs = qs.Where("tel=?", req.Tel) @@ -2313,17 +2357,17 @@ func queryRetailDetailCommon(req *ErpOrderRetailDetailReq) (*ErpOrderRetailDetai qs = qs.Where("store_id=?", req.StoreId) } if req.Salesman != 0 { // 销售员 - qs = qs.Where("salesman1 = ? or salesman2 = ?", req.Salesman, req.Salesman) + qs = qs.Where("JSON_CONTAINS(salesman_list, ?)", fmt.Sprintf(`{"uid":%d}`, req.Salesman)) } if req.StartTime != "" { // 审核开始时间 - parse, err := time.Parse(DateTimeFormat, req.StartTime) + parse, err := time.Parse(QueryTimeFormat, req.StartTime) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("audit_time > ?", parse) } if req.EndTime != "" { // 审核结束时间 - parse, err := time.Parse(DateTimeFormat, req.EndTime) + parse, err := time.Parse(QueryTimeFormat, req.EndTime) if err != nil { logger.Errorf("err:", err) } diff --git a/app/admin/models/file.go b/app/admin/models/file.go index 2229107..4c9042e 100644 --- a/app/admin/models/file.go +++ b/app/admin/models/file.go @@ -5,10 +5,10 @@ import ( "encoding/json" "errors" "fmt" - "github.com/codinl/go-logger" "github.com/xuri/excelize/v2" "go-admin/app/admin/models/tools" orm "go-admin/common/global" + "go-admin/logger" "gorm.io/gorm" "reflect" "strconv" @@ -132,11 +132,11 @@ func FileExcelReader(d []byte, cols []string) ([]byte, []map[string]interface{}, } } - logger.Info("columnMap:", columnMap) + logger.Info("columnMap:", logger.Field("columnMap", columnMap)) colsMap = append(colsMap, columnMap) } - logger.Info("colsMap:", colsMap) + logger.Info("colsMap:", logger.Field("colsMap", colsMap)) mCols, err := json.Marshal(colsMap) if err != nil { return mCols, nil, fmt.Errorf("marshal error: %v", err) @@ -232,11 +232,11 @@ func FileExcelImport(d []byte, cols []string, nType int) ([]byte, []map[string]i } } - logger.Info("columnMap:", columnMap) + logger.Info("columnMap:", logger.Field("columnMap", columnMap)) colsMap = append(colsMap, columnMap) } - logger.Info("colsMap:", colsMap) + logger.Info("colsMap:", logger.Field("colsMap", colsMap)) mCols, err := json.Marshal(colsMap) if err != nil { return mCols, nil, fmt.Errorf("marshal err: %v", err) @@ -1053,3 +1053,27 @@ func UpdateErpStockAmountInfo(begin *gorm.DB, commodityId, retailPrice, minRetai return nil } + +// CheckCommodityIsHavaStock 检查某个商品是否还有库存 +func CheckCommodityIsHavaStock(commodityId uint32) bool { + var count int64 + err := orm.Eloquent.Table("erp_stock").Where("erp_commodity_id = ? and count > 0", commodityId). + Count(&count).Error + if err != nil { + logger.Error("CheckCommodityIsHavaStock err:", logger.Field("err", err)) + } + + return count > 0 +} + +// IsExistingCommodity 检查是否存在某个商品 +func IsExistingCommodity(commodityId uint32) bool { + var count int64 + err := orm.Eloquent.Table("erp_commodity").Where("id = ?", commodityId). + Count(&count).Error + if err != nil { + logger.Error("IsExistingCommodity err:", logger.Field("err", err)) + } + + return count > 0 +} diff --git a/app/admin/models/purchase.go b/app/admin/models/purchase.go index 25d86c4..0773d51 100644 --- a/app/admin/models/purchase.go +++ b/app/admin/models/purchase.go @@ -7,6 +7,7 @@ import ( "go-admin/logger" "gorm.io/gorm" "math/rand" + "sync" "time" ) @@ -21,6 +22,9 @@ const ( ErpProcureOrder = "procure" // 采购入库订单 ErpRejectOrder = "reject" // 采购退货订单 + + ErpDemandStateWait = 1 // 待采购 + ErpDemandStateFinish = 2 // 完成采购 ) // ErpPurchaseOrder 采购订单表 @@ -32,6 +36,8 @@ type ErpPurchaseOrder struct { StoreName string `json:"store_name"` // 门店名称 ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 + HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id + HandlerName string `json:"handler_name"` // 经手人名称 MakerTime time.Time `json:"maker_time"` // 制单时间 MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id MakerName string `json:"maker_name"` // 制单人名称 @@ -45,87 +51,65 @@ type ErpPurchaseOrder struct { AccountHolder string `json:"account_holder"` // 收款人 OpeningBank string `json:"opening_bank"` // 开户行 BankAccount string `json:"bank_account"` // 银行卡号 - DeliveryTime string `json:"delivery_time"` // 交货日期 + DeliveryTime string `json:"delivery_time"` // 交货日期,如:2024-02-23 Commodities []ErpPurchaseCommodity `json:"commodities" gorm:"-"` } // ErpPurchaseCommodity 采购订单商品表 type ErpPurchaseCommodity struct { Model - ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id - ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id - ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 - CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 - IMEI string `json:"imei"` // 商品串码 - Count uint32 `json:"count"` // 计划采购数量 - Price uint32 `json:"price"` // 计划采购单价 - Amount uint32 `json:"amount"` // 计划采购金额 - Remark string `json:"remark"` // 备注 - RejectedPrice uint32 `json:"rejected_price"` // 计划退货单价 - RejectedCount uint32 `json:"rejected_count"` // 计划退货数量 - RejectedAmount uint32 `json:"rejected_amount"` // 计划退货金额 - InventoryCount int32 `json:"inventory_count"` // 入库数量(=执行数量) - ExecutionCount uint32 `json:"execute_count" gorm:"-"` // 执行数量 - ExecutionPrice uint32 `json:"execute_price" gorm:"-"` // 平均采购单价 - ExecutionEmployeePrice uint32 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价 - ExecutionAmount uint32 `json:"execute_amount" gorm:"-"` // 执行金额 + ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 采购订单id + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + IMEI string `json:"imei"` // 商品串码 + RetailPrice uint32 `json:"retail_price"` // 指导零售价 + Count uint32 `json:"count"` // 计划采购数量 + Price float64 `json:"price"` // 计划采购单价 + Amount float64 `json:"amount"` // 计划采购金额 + Remark string `json:"remark"` // 备注 + RejectedPrice float64 `json:"rejected_price"` // 计划退货单价 + RejectedCount uint32 `json:"rejected_count"` // 计划退货数量 + RejectedAmount float64 `json:"rejected_amount"` // 计划退货金额 + InventoryCount int32 `json:"inventory_count"` // 入库数量(=执行数量) + ExecutionCount uint32 `json:"execute_count" gorm:"-"` // 执行数量 + ExecutionPrice float64 `json:"execute_price" gorm:"-"` // 平均采购单价 + ExecutionEmployeePrice float64 `json:"execute_employee_price" gorm:"-"` // 平均员工成本价 + ExecutionAmount float64 `json:"execute_amount" gorm:"-"` // 执行金额 } -// ErpPurchaseInventory 采购入库执行表 +// ErpPurchaseInventory 采购入库执行信息 type ErpPurchaseInventory struct { Model - SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号 - InventoryType string `json:"inventory_type"` // 采购类型:procure-采购 reject-退货 - ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id - ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id - ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 - CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 - IMEI string `json:"imei"` // 商品串码 - Count uint32 `json:"count"` // 数量 - Price uint32 `json:"price"` // 采购单价 - ImplementationPrice uint32 `json:"implementation_price"` // 执行单价 - EmployeePrice uint32 `json:"employee_price"` // 员工成本价 - InventoryCount int32 `json:"inventory_count"` // 入库数量 - Amount uint32 `json:"amount"` // 入库金额 - Remark string `json:"remark"` // 备注 - - //ErpPurchaseCommodity *ErpPurchaseCommodity `json:"erp_purchase_commodity" gorm:"-"` -} - -// ErpInventoryCommodity 采购入库执行商品表 -type ErpInventoryCommodity struct { - Model - SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号 - InventoryType string `json:"inventory_type"` // - ErpPurchaseInventoryId uint32 `json:"erp_purchase_inventory_id"` // 商品采购入库id - ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id"` // 商品采购订单id - ErpCommodityId uint32 `json:"erp_commodity_id"` // 商品id - ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 - CommoditySerialNumber string `json:"commodity_serial_number"` // 商品编码 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 - IMEI string `json:"imei"` // 串码 - Count uint32 `json:"count"` // - Price uint32 `json:"price"` // - EmployeePrice uint32 `json:"employee_price"` // 员工成本 - ImplementationPrice uint32 `json:"implementation_price"` // - Amount uint32 `json:"amount"` // - Remark string `json:"remark"` // 备注 + ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id + ErpPurchaseCommodityId uint32 `json:"erp_purchase_commodity_id" gorm:"index"` // 采购订单商品表id + PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 + SerialNumber string `json:"serial_number" gorm:"index"` // 入库编号 + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + IMEI string `json:"imei"` // 商品串码 + Count uint32 `json:"count"` // 执行数量 + ImplementationPrice float64 `json:"implementation_price"` // 执行单价 + Amount float64 `json:"amount"` // 执行金额 + EmployeePrice float64 `json:"employee_price"` // 员工成本价 } type ErpPurchaseCreateReq struct { PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号 - StoreId uint32 `json:"store_id" binding:"required"` // 门店id - DeliveryAddress string `json:"delivery_address" binding:"required"` // 交货地址 - MakerId uint32 `json:"maker_id" binding:"required"` // 经手人 - ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 供应商id - ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式 + StoreId uint32 `json:"store_id"` // 门店id + DeliveryAddress string `json:"delivery_address"` // 交货地址 + HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id + HandlerName string `json:"handler_name"` // 经手人名称 + ErpSupplierId uint32 `json:"erp_supplier_id"` // 供应商id + ErpCashierId uint32 `json:"erp_cashier_id"` // 付款方式 AccountHolder string `json:"account_holder"` // 收款人 - OpeningBank string `json:"opening_bank" validate:"required"` // 开户行 - BankAccount string `json:"bank_account" validate:"required"` // 银行卡号 - DeliveryTime string `json:"delivery_time" binding:"required"` // 交货日期 + OpeningBank string `json:"opening_bank" ` // 开户行 + BankAccount string `json:"bank_account" ` // 银行卡号 + DeliveryTime string `json:"delivery_time" ` // 交货日期 Remark string `json:"remark"` // 备注 ErpPurchaseCommodities []ErpPurchaseCommodity `json:"erp_purchase_commodities" binding:"required"` // 采购商品信息 } @@ -136,7 +120,8 @@ type ErpPurchaseEditReq struct { PurchaseOrderSn string `json:"purchase_order_sn"` // 采购退货订单号 StoreId uint32 `json:"store_id" binding:"required"` // 门店id DeliveryAddress string `json:"delivery_address" binding:"required"` // 交货地址 - MakerId uint32 `json:"maker_id" binding:"required"` // 经手人 + HandlerId uint32 `json:"handler_id" gorm:"index"` // 经手人id + HandlerName string `json:"handler_name"` // 经手人名称 ErpSupplierId uint32 `json:"erp_supplier_id" binding:"required"` // 供应商id ErpCashierId uint32 `json:"erp_cashier_id" binding:"required"` // 付款方式 AccountHolder string `json:"account_holder"` // 收款人 @@ -173,9 +158,8 @@ type ErpPurchaseDetailReq struct { // ErpPurchaseInventoryReq 入库(退货)入参;执行(入库/退货)入参 type ErpPurchaseInventoryReq struct { ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" binding:"required"` // 采购订单id - InventoryType string `json:"inventory_type" binding:"required"` // 采购类型:procure-采购 reject-退货 + PurchaseType string `json:"purchase_type" binding:"required"` // 采购类型:procure-采购 reject-退货 Inventories []ErpPurchaseInventory `json:"inventories" binding:"required"` // 采购入库执行信息 - //Commodities []ErpInventoryCommodity `json:"commodities" binding:"required"` } // ErpPurchaseAuditReq 审核采购订单入参 @@ -191,22 +175,96 @@ type ErpPurchaseTerminateReq struct { // ErpPurchaseExecuteResp 执行(入库/退货)出参 type ErpPurchaseExecuteResp struct { - List []ExecuteData `json:"list"` - Total int `json:"total"` // 总条数 - PageIndex int `json:"pageIndex"` // 页码 - PageSize int `json:"pageSize"` // 页面条数 + List []ExecuteData `json:"list"` + Total int `json:"total"` // 总条数 } type ExecuteData struct { - ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id - ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id - ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 - CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 - IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 - IMEI string `json:"imei"` // 商品串码 - Count uint32 `json:"count"` // 数量 - ImplementationPrice uint32 `json:"implementation_price"` // 执行单价 - EmployeePrice uint32 `json:"employee_price"` // 员工成本价 + ErpPurchaseOrderId uint32 `json:"erp_purchase_order_id" gorm:"index"` // 商品采购订单id + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 + IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 + IMEI string `json:"imei"` // 商品串码 + Count uint32 `json:"count"` // 数量 + ImplementationPrice float64 `json:"implementation_price"` // 执行单价 + EmployeePrice float64 `json:"employee_price"` // 员工成本价 +} + +type ErpPurchaseDemand struct { + Model + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 + ErpCommodityName string `json:"erp_commodity_name" gorm:"index"` // 商品名称 + StoreId uint32 `json:"store_id"` // 门店id + StoreName string `json:"store_name"` // 门店名称 + 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"` // 备注 +} + +type ErpPurchaseDemandRecord struct { + Model + ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id + StoreId uint32 `json:"store_id" binding:"required"` // 门店id + StoreName string `json:"store_name" binding:"required"` // 门店名称 + Count uint32 `json:"count"` // 数量 + MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id + State uint32 `json:"state"` // 1-待采购 2-已采购 +} + +type GetErpPurchaseDemandReq struct { + ErpCategoryId uint32 `json:"erp_category_id" binding:"required"` // 商品分类id + HideFlag string `json:"hide_flag"` // 隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 每页展示数据条数 + IsExport uint32 `json:"is_export"` // 1-导出 +} + +type DemandData struct { + ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id + ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + ErpCategoryID uint32 `json:"erp_category_id"` // 商品分类id + ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 + RetailPrice uint32 `json:"retail_price"` // 指导零售价 + LastWholesalePrice float64 `json:"last_wholesale_price"` // 最近采购价 + TotalCount uint32 `json:"total_count"` // 需采购总数量 + TotalAmount float64 `json:"total_amount"` // 需采购总金额 + StoreList []struct { + StoreID uint32 `json:"store_id"` // 门店id + StoreName string `json:"store_name"` // 门店名称 + LastMonthSales uint32 `json:"last_month_sales"` // 上月销售数 + StockCount uint32 `json:"stock_count"` // 库存数量 + NeedCount uint32 `json:"need_count"` // 需采购数 + } `json:"store_list"` +} + +type GetErpPurchaseDemandResp struct { + List []DemandData `json:"list"` + Total int64 `json:"total"` // 数据总条数 + PageIndex int `json:"pageIndex"` // 页码 + PageSize int `json:"pageSize"` // 每页展示条数 + ExportUrl string `json:"export_url"` // 文件路径 +} + +type CreateErpPurchaseDemandReq struct { + ErpCommodityID uint32 `json:"erp_commodity_id"` // 商品id + ErpCommoditySerialNumber string `json:"erp_commodity_serial_number"` // 商品编号 + ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 + Remark string `json:"remark"` // 备注 + List []struct { + StoreID uint32 `json:"store_id"` // 门店id + StoreName string `json:"store_name"` // 门店名称 + NeedCount uint32 `json:"need_count"` // 需采购数 + } `json:"list"` +} + +type FinishErpPurchaseDemandReq struct { + ErpCommodityID uint32 `json:"erp_commodity_id" binding:"required"` // 商品id } func (m *ErpPurchaseOrderListReq) List() (*ErpPurchaseOrderListResp, error) { @@ -317,10 +375,10 @@ func ErpPurchaseCommodityListPerfectInfo(purchaseCommodities []ErpPurchaseCommod //purchaseCommodities[i].IMEI = v.IMEI purchaseCommodities[i].ErpCommodityName = v.Name if purchaseCommodities[i].Count != 0 { - purchaseCommodities[i].Amount = purchaseCommodities[i].Count * purchaseCommodities[i].Price + purchaseCommodities[i].Amount = float64(purchaseCommodities[i].Count) * purchaseCommodities[i].Price } if purchaseCommodities[i].RejectedCount != 0 { - purchaseCommodities[i].RejectedAmount = purchaseCommodities[i].RejectedCount * purchaseCommodities[i].RejectedPrice + purchaseCommodities[i].RejectedAmount = float64(purchaseCommodities[i].RejectedCount) * purchaseCommodities[i].RejectedPrice } } } @@ -384,88 +442,6 @@ func GetPurchaseInventorySn() string { } } -func GetErpPurchaseOrderPurchaseCommodityMap(orderId uint32) (map[uint32]ErpPurchaseCommodity, error) { - commodityMap := make(map[uint32]ErpPurchaseCommodity, 0) - if orderId == 0 { - return commodityMap, nil - } - - var commodities []ErpPurchaseCommodity - err := orm.Eloquent.Table("erp_purchase_commodity").Where("erp_purchase_order_id=?", orderId).Find(&commodities).Error - if err != nil { - logger.Error("commodities err:", logger.Field("err", err)) - return commodityMap, err - } - - for i, _ := range commodities { - commodityMap[commodities[i].ErpCommodityId] = commodities[i] - } - - return commodityMap, nil -} - -func ErpPurchaseInventoryListIdInit(inventories []ErpPurchaseInventory /*commodities []ErpInventoryCommodity,*/, orderId uint32, inventoryType string) error { - //inventorySn := GetPurchaseInventorySn() - ids := make([]uint32, 0, len(inventories)) - for i, _ := range inventories { - ids = append(ids, inventories[i].ErpCommodityId) - } - commodityMap, err := GetErpCommodityMap(ids) - if err != nil { - logger.Error("commodity map err:", logger.Field("err", err)) - return err - } - purchaseCommodityMap, err := GetErpPurchaseOrderPurchaseCommodityMap(orderId) - if err != nil { - logger.Error("purchase commodity map err:", logger.Field("err", err)) - return err - } - commodityCountMap := make(map[uint32]uint32, 0) - //for i, _ := range commodities { - // purchaseCommodity, _ := purchaseCommodityMap[inventories[i].ErpCommodityId] - // v, ok := commodityMap[commodities[i].ErpCommodityId] - // if ok { - // commodities[i].SerialNumber = inventorySn - // commodities[i].InventoryType = inventoryType - // commodities[i].ErpPurchaseOrderId = orderId - // commodities[i].ErpCommodityName = v.Name - // commodities[i].CommoditySerialNumber = v.SerialNumber - // commodities[i].IMEIType = v.IMEIType - // commodities[i].Price = purchaseCommodity.Price - // commodities[i].Amount = commodities[i].Count * commodities[i].ImplementationPrice - // if v.IMEIType == 1 { - // commodityCountMap[v.ID] += commodities[i].Count - // } else { - // commodityCountMap[v.ID] += 1 - // } - // - // //commodities[i].InventoryCount = int32(inventories[i].Count) - // } - //} - - for i, _ := range inventories { - purchaseCommodity, _ := purchaseCommodityMap[inventories[i].ErpCommodityId] - commodityCount, _ := commodityCountMap[inventories[i].ErpCommodityId] - v, ok := commodityMap[inventories[i].ErpCommodityId] - if ok { - inventories[i].ErpPurchaseOrderId = orderId - inventories[i].InventoryType = inventoryType - inventories[i].ErpCommodityName = v.Name - inventories[i].CommoditySerialNumber = v.SerialNumber - inventories[i].IMEIType = v.IMEIType - inventories[i].Price = purchaseCommodity.Price - inventories[i].Count = commodityCount - inventories[i].Amount = inventories[i].Count * inventories[i].ImplementationPrice - inventories[i].InventoryCount = purchaseCommodity.InventoryCount + int32(inventories[i].Count) - if int32(purchaseCommodity.Count) < inventories[i].InventoryCount { - return errors.New(fmt.Sprintf("order id:%d purchase commodity id:%d inventory count err", orderId, purchaseCommodity.ID)) - } - } - } - - return nil -} - // CreateErpPurchaseOrder 新增采购订单 func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPurchaseOrder, error) { var err error @@ -479,6 +455,8 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu StoreId: req.StoreId, ErpSupplierId: req.ErpSupplierId, MakerTime: nowTime, + HandlerId: req.HandlerId, + HandlerName: req.HandlerName, MakerId: uint32(sysUser.UserId), MakerName: sysUser.NickName, State: ErpPurchaseOrderUnAudit, // 1-待审核 @@ -490,6 +468,9 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu } err = purchaseOrder.IdInit() } else if req.PurchaseType == ErpRejectOrder { // 采购退货订单 + if req.PurchaseOrderSn == "" { + return nil, errors.New("新建失败:采购退货订单号为空") + } var erpPurchaseOrder ErpPurchaseOrder err = orm.Eloquent.Table("erp_purchase_order").Where("serial_number=?", req.PurchaseOrderSn).Find(&erpPurchaseOrder).Error if err != nil { @@ -503,10 +484,12 @@ func CreateErpPurchaseOrder(req *ErpPurchaseCreateReq, sysUser *SysUser) (*ErpPu StoreId: erpPurchaseOrder.StoreId, ErpSupplierId: erpPurchaseOrder.ErpSupplierId, MakerTime: nowTime, - MakerId: uint32(req.MakerId), - //MakerName: sysUser.NickName, - State: ErpPurchaseOrderUnAudit, // 1-待审核 - ErpCashierId: req.ErpCashierId, + HandlerId: req.HandlerId, + HandlerName: req.HandlerName, + MakerId: uint32(sysUser.UserId), + MakerName: sysUser.NickName, + State: ErpPurchaseOrderUnAudit, // 1-待审核 + ErpCashierId: req.ErpCashierId, } err = purchaseOrder.IdInit() } else { @@ -568,7 +551,10 @@ func EditErpPurchaseOrder(req *ErpPurchaseEditReq, sysUser *SysUser) (*ErpPurcha // 1-更新采购订单信息 purchaseOrder.StoreId = req.StoreId purchaseOrder.ErpSupplierId = req.ErpSupplierId - purchaseOrder.MakerId = req.MakerId + purchaseOrder.HandlerId = req.HandlerId + purchaseOrder.HandlerName = req.HandlerName + purchaseOrder.MakerId = uint32(sysUser.UserId) + purchaseOrder.MakerName = sysUser.NickName purchaseOrder.ErpCashierId = req.ErpCashierId purchaseOrder.AccountHolder = req.AccountHolder purchaseOrder.OpeningBank = req.OpeningBank @@ -690,10 +676,12 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { begin := orm.Eloquent.Begin() for _, v := range req.Inventories { + v.SerialNumber = GetPurchaseInventorySn() // 更新采购商品表的执行数量 + // todo 如果用户在同一个采购单中新建了同一个商品的2条采购信息,可能采购价不同,需要区分入库的是哪一条(已修改) 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.InventoryCount)).Error + Where("id = ?", v.ErpPurchaseCommodityId). + UpdateColumn("inventory_count", gorm.Expr("inventory_count + ?", v.Count)).Error if err != nil { begin.Rollback() logger.Error("update inventory count err:", logger.Field("err", err)) @@ -706,7 +694,28 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { logger.Error("create erp inventory commodity err:", logger.Field("err", err)) return err } - // todo 更新库存信息表 + } + + // 查询采购订单信息 + var purchaseOrder ErpPurchaseOrder + err = orm.Eloquent.Table("erp_purchase_order").Where("id=?", req.ErpPurchaseOrderId).Find(&purchaseOrder).Error + if err != nil { + logger.Error("purchase order err:", logger.Field("err", err)) + return err + } + + // 更新库存信息表 + if purchaseOrder.PurchaseType == ErpProcureOrder { //采购入库订单 + err = InventoryErpPurchaseUpdateStock(begin, req, purchaseOrder) + } else if purchaseOrder.PurchaseType == ErpRejectOrder { // 采购退货订单 + err = InventoryErpPurchaseUpdateRejectStock(begin, req, purchaseOrder) + } else { + return errors.New("订单类型有误") + } + if err != nil { + begin.Rollback() + logger.Error("update stock err:", logger.Field("err", err)) + return err } err = begin.Commit().Error @@ -719,6 +728,160 @@ func InventoryErpPurchase(req *ErpPurchaseInventoryReq) error { return nil } +// InventoryErpPurchaseUpdateStock 采购订单入库更新库存信息 +func InventoryErpPurchaseUpdateStock(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 { + stock := &ErpStock{ + StoreId: purchaseOrder.StoreId, + StoreName: purchaseOrder.StoreName, + ErpCommodityId: v.ErpCommodityId, + ErpCommodityName: v.ErpCommodityName, + ErpCategoryId: commodityInfo.ErpCategoryId, + ErpCategoryName: commodityInfo.ErpCategoryName, + CommoditySerialNumber: v.CommoditySerialNumber, + IMEIType: v.IMEIType, + RetailPrice: commodityInfo.RetailPrice, + MinRetailPrice: commodityInfo.MinRetailPrice, + Count: v.Count, + DispatchCount: 0, + } + err = gdb.Create(stock).Error + if err != nil { + logger.Errorf("create stock 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: 1, + StorageType: 1, + 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, + } + stockList = append(stockList, stockCommodity) + } + + err := gdb.Debug().Create(&stockList).Error + if err != nil { + logger.Errorf("create stock commodity err:", err) + return err + } + + return nil +} + +// 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 == "" { + return errors.New("串码为空") + } + + // 判断该串码商品是否已经销售 + var stockCommodityInfo ErpStockCommodity + err := orm.Eloquent.Table("erp_stock_commodity").Where("imei = ?", req.Inventories[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) + } 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 // 状态更新为采购退货 + 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). + 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 { // 非串码商品 + 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). + 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") + } + + err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). + Update("state", PurchaseReturn).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). + 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 + } + } + } + + return nil +} + // 校验入参数据,执行数量是否超过总数;串码商品的串码是否重复 func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { // 查询现有的零售订单信息 @@ -729,9 +892,9 @@ func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { return err } - countMap := make(map[uint32]int32) + countMap := make(map[uint32]uint32) for _, inventory := range req.Inventories { - countMap[inventory.ErpCommodityId] += inventory.InventoryCount + countMap[inventory.ErpCommodityId] += inventory.Count // 如果该商品是串码商品,判断其串码是否会重复 if inventory.IMEI != "" { @@ -762,9 +925,16 @@ func checkPurchaseInventory(req *ErpPurchaseInventoryReq) error { // 本次入库的数量超出该商品未入库数量 for _, commodity := range commodities { if inventoryCount, ok := countMap[commodity.ErpCommodityId]; ok { - if int32(commodity.Count)-commodity.InventoryCount < inventoryCount { - return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName, - inventoryCount, int32(commodity.Count)-commodity.InventoryCount) + if req.PurchaseType == ErpProcureOrder { + if commodity.Count-uint32(commodity.InventoryCount) < inventoryCount { + return fmt.Errorf("本次入库商品[%s]数量[%d]超出该商品未入库数量[%d]", commodity.ErpCommodityName, + inventoryCount, int32(commodity.Count)-commodity.InventoryCount) + } + } else if req.PurchaseType == ErpRejectOrder { + if commodity.RejectedCount-uint32(commodity.InventoryCount) < inventoryCount { + return fmt.Errorf("本次退货商品[%s]数量[%d]超出该商品未退货数量[%d]", commodity.ErpCommodityName, + inventoryCount, int32(commodity.Count)-commodity.InventoryCount) + } } } } @@ -786,14 +956,16 @@ func ExecuteErpPurchase(req *ErpPurchaseInventoryReq) (*ErpPurchaseExecuteResp, for _, inventory := range req.Inventories { if inventory.IMEIType == 2 { - // 如果是串码商品,根据 InventoryCount 拆分成对应数量的数据 - for i := 0; i < int(inventory.InventoryCount); i++ { - // 调用函数B生成商品串码 - imei, err := generateIMEI(inventory.ErpCommodityId) - if err != nil { - return nil, err + // 如果是串码商品,根据 Count 拆分成对应数量的数据 + for i := 0; i < int(inventory.Count); i++ { + imei := "" // 默认退货单执行时不需要串码 + if inventory.PurchaseType == ErpProcureOrder { // 采购单 + // 调用函数B生成商品串码 + imei, err = generateIMEI(inventory.ErpCommodityId) + if err != nil { + return nil, err + } } - // 将拆分后的商品信息添加到执行响应中 resp.List = append(resp.List, ExecuteData{ ErpPurchaseOrderId: inventory.ErpPurchaseOrderId, @@ -823,9 +995,12 @@ func ExecuteErpPurchase(req *ErpPurchaseInventoryReq) (*ErpPurchaseExecuteResp, } } + resp.Total = len(resp.List) + return resp, nil } +// 生成串码 func generateIMEI(commodityId uint32) (string, error) { commodity, err := GetCommodity(commodityId) if err != nil { @@ -834,3 +1009,989 @@ func generateIMEI(commodityId uint32) (string, error) { return GenerateSerialCode(commodity.ErpCategoryId) } + +// CreateErpPurchaseDemand 创建采购需求单 +func CreateErpPurchaseDemand(req *CreateErpPurchaseDemandReq, sysUser *SysUser) error { + var demandInfo ErpPurchaseDemand + 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 + demandInfo.StoreName = v.StoreName + demandInfo.Count = v.NeedCount + demandInfo.MakerId = uint32(sysUser.UserId) + demandList = append(demandList, demandInfo) + } + + begin := orm.Eloquent.Begin() + // 查询当前表格,有记录则更新,没有则插入新记录 + for _, v := range demandList { + var demand ErpPurchaseDemand + err := orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? and store_id = ? and state = 1", + v.ErpCommodityId, v.StoreId).Find(&demand).Error + if err != nil { + logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) + return err + } + + if demand.StoreId != 0 { // 有记录 + if demand.Count == v.Count { // 值没变则不更新 + continue + } else { + err = begin.Model(&ErpPurchaseDemand{}).Where("erp_commodity_id = ? and store_id = ? and state = 1", + v.ErpCommodityId, v.StoreId).Updates(v).Error + if err != nil { + begin.Rollback() + logger.Error("update erp_order err:", logger.Field("err", err)) + return err + } + } + } else { // 无记录,新建 + err = begin.Create(&v).Error + if err != nil { + logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) + return err + } + } + } + + err := begin.Commit().Error + if err != nil { + begin.Rollback() + logger.Error("commit err:", logger.Field("err", err)) + return err + } + + return nil +} + +// FinishErpPurchaseDemand 完成采购需求 +func FinishErpPurchaseDemand(req *FinishErpPurchaseDemandReq, sysUser *SysUser) error { + exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_purchase_demand WHERE erp_commodity_id='%d'", + req.ErpCommodityID)) + if err != nil { + logger.Error("exist sn err") + } + if !exist { + return fmt.Errorf("商品编号[%d]的商品不在采购需求单中", req.ErpCommodityID) + } + + // 批量更新状态 + err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id=?", 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 + } + + return nil +} + +//// GetErpPurchaseDemand 获取采购需求 +//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { +// resp := &GetErpPurchaseDemandResp{ +// PageIndex: req.PageIndex, +// PageSize: req.PageSize, +// } +// page := req.PageIndex - 1 +// if page < 0 { +// page = 0 +// } +// if req.PageSize == 0 { +// req.PageSize = 10 +// } +// +// qs := orm.Eloquent.Debug().Table("erp_commodity") +// if req.ErpCategoryId != 0 { +// qs = qs.Where("erp_category_id=?", req.ErpCategoryId) +// } +// +// var commodities []ErpCommodity +// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error +// if err != nil && err != RecordNotFound { +// //logger.Error("erp commodity list err:", err) +// return resp, err +// } +// +// // 组合数据 +// resp, err = convertToDemandResp(commodities) +// +// return resp, nil +//} +// +//func convertToDemandResp(commodities []ErpCommodity) (*GetErpPurchaseDemandResp, error) { +// resp := new(GetErpPurchaseDemandResp) +// var demandData DemandData +// var demandList []DemandData +// +// // 查询所有在线门店信息 +// var stores []Store +// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error +// if err != nil { +// logger.Error("stores err:", logger.Field("err", err)) +// return nil, err +// } +// +// demandData.List = make([]struct { +// StoreID uint32 `json:"store_id"` +// StoreName string `json:"store_name"` +// LastMonthSales uint32 `json:"last_month_sales"` +// StockCount uint32 `json:"stock_count"` +// NeedCount uint32 `json:"need_count"` +// }, len(stores)) +// +// var totalCount uint32 // 总需采购数量 +// +// // 遍历所有商品 +// for _, v := range commodities { +// // 初始化 NeedCount 为 0 +// var totalNeedCount uint32 +// +// for i, store := range stores { +// demandData.List[i].StoreID = store.ID +// demandData.List[i].StoreName = store.Name +// +// // 初始化 NeedCount 为 0 +// demandData.List[i].NeedCount = 0 +// +// // 设置商品相关信息 +// demandData.ErpCommodityID = v.ID +// demandData.ErpCommoditySerialNumber = v.SerialNumber +// demandData.ErpCommodityName = v.Name +// demandData.ErpCategoryID = v.ErpCategoryId +// demandData.ErpCategoryName = v.ErpCategoryName +// demandData.RetailPrice = v.RetailPrice +// // 最近采购价 +// demandData.LastWholesalePrice, _ = GetCommodityLastWholesalePrice(v.ID) +// +// // 查询采购需求单 +// var demand []ErpPurchaseDemand +// err = orm.Eloquent.Table("erp_purchase_demand").Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", +// v.ID, store.ID).Find(&demand).Error +// if err != nil { +// logger.Error("query erp_purchase_demand err:", logger.Field("err", err)) +// return nil, err +// } +// +// if len(demand) > 0 { +// totalNeedCount += demand[0].Count +// demandData.List[i].NeedCount = demand[0].Count +// } +// +// // 查询某个门店某个商品的库存情况 +// demandData.List[i].StockCount, _ = GetCommodityStockByStoreId(v.ID, store.ID) +// // 查询某个门店某件商品的上月销售数量 +// demandData.List[i].LastMonthSales, _ = GetCommodityLastMonthSalesByStoreId(v.ID, store.ID) +// } +// totalCount += totalNeedCount +// demandData.TotalCount = totalCount +// demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice +// demandList = append(demandList, demandData) +// } +// resp.List = demandList +// +// return resp, nil +//} +// +//// GetCommodityStockByStoreId 查询某个门店某个商品的库存情况 +//func GetCommodityStockByStoreId(commodityId, storeId uint32) (uint32, error) { +// var count int64 +// err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? and state = 1", +// commodityId, storeId).Count(&count).Error +// if err != nil { +// logger.Error("GetCommodityStockByStoreId count err:", logger.Field("err", err)) +// return 0, err +// } +// +// return uint32(count), nil +//} +// +//// GetCommodityLastMonthSalesByStoreId 查询某个门店某件商品的上月销售数量 +//func GetCommodityLastMonthSalesByStoreId(commodityId, storeId uint32) (uint32, error) { +// var lastMonthSales uint32 +// +// // 获取当前时间 +// now := time.Now() +// year, month, _ := now.Date() +// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) +// lastDay := firstDay.AddDate(0, 1, -1) +// +// // 执行查询 +// err := orm.Eloquent.Model(&ErpOrderCommodity{}). +// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). +// Select("SUM(erp_order_commodity.count) AS last_month_sales"). +// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ +// "AND erp_order_commodity.created_at BETWEEN ? AND ?", +// HavePaid, commodityId, storeId, firstDay, lastDay). +// Scan(&lastMonthSales).Error +// if err != nil { +// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err)) +// return 0, err +// } +// +// return lastMonthSales, nil +//} +// +//// GetCommodityLastWholesalePrice 查询某个商品的最近采购价 +//func GetCommodityLastWholesalePrice(commodityId uint32) (float64, error) { +// var implementationPrice float64 +// +// // 执行查询 +// err := orm.Eloquent.Table("erp_purchase_inventory"). +// Select("implementation_price"). +// Where("erp_commodity_id = ? AND purchase_type = ?", 167, "procure"). +// Order("created_at DESC"). +// Limit(1). +// Scan(&implementationPrice).Error +// if err != nil { +// logger.Error("GetCommodityLastMonthSalesByStoreId err:", logger.Field("err", err)) +// return 0, err +// } +// +// return implementationPrice, nil +//} + +// 222222222 +//// GetErpPurchaseDemand 获取采购需求 +//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { +// resp := &GetErpPurchaseDemandResp{ +// PageIndex: req.PageIndex, +// PageSize: req.PageSize, +// } +// page := req.PageIndex - 1 +// if page < 0 { +// page = 0 +// } +// if req.PageSize == 0 { +// req.PageSize = 10 +// } +// +// qs := orm.Eloquent.Debug().Table("erp_commodity") +// if req.ErpCategoryId != 0 { +// qs = qs.Where("erp_category_id=?", req.ErpCategoryId) +// } +// +// var commodities []ErpCommodity +// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error +// if err != nil && err != RecordNotFound { +// return resp, err +// } +// +// // 批量查询门店信息 +// stores, err := GetOnlineStores() +// if err != nil { +// return nil, err +// } +// +// // 批量查询商品信息 +// demandDataList := make([]DemandData, 0, len(commodities)) +// for _, v := range commodities { +// demandData, err := convertToDemandData(v, stores) +// if err != nil { +// return nil, err +// } +// demandDataList = append(demandDataList, demandData) +// } +// +// resp.List = demandDataList +// +// return resp, nil +//} +// +//// convertToDemandData 将商品转换为采购需求数据 +//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { +// demandData := DemandData{ +// ErpCommodityID: commodity.ID, +// ErpCommoditySerialNumber: commodity.SerialNumber, +// ErpCommodityName: commodity.Name, +// ErpCategoryID: commodity.ErpCategoryId, +// ErpCategoryName: commodity.ErpCategoryName, +// RetailPrice: commodity.RetailPrice, +// } +// +// // 批量查询最近采购价 +// lastWholesalePrices, err := GetCommodityLastWholesalePrices(commodity.ID) +// if err != nil { +// return DemandData{}, err +// } +// +// for i, store := range stores { +// demandData.List = append(demandData.List, struct { +// StoreID uint32 `json:"store_id"` +// StoreName string `json:"store_name"` +// LastMonthSales uint32 `json:"last_month_sales"` +// StockCount uint32 `json:"stock_count"` +// NeedCount uint32 `json:"need_count"` +// }{ +// StoreID: store.ID, +// StoreName: store.Name, +// }) +// +// // 批量查询库存情况 +// stockCounts, err := GetCommodityStocksByStoreID(commodity.ID, store.ID) +// if err != nil { +// return DemandData{}, err +// } +// demandData.List[i].StockCount = stockCounts[store.ID] +// +// // 批量查询上月销售数量 +// lastMonthSales, err := GetCommodityLastMonthSales(commodity.ID, store.ID) +// if err != nil { +// return DemandData{}, err +// } +// demandData.List[i].LastMonthSales = lastMonthSales +// +// // 设置最近采购价 +// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] +// } +// +// return demandData, nil +//} +// +//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价 +//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { +// // 查询最近采购价 +// var prices []struct { +// CommodityID 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"). +// Order("created_at DESC"). +// Find(&prices).Error +// if err != nil { +// return nil, err +// } +// +// // 构建结果 +// result := make(map[uint32]float64) +// for _, p := range prices { +// result[p.CommodityID] = p.Price +// } +// return result, nil +//} +// +//// GetCommodityStocksByStoreID 批量查询商品的库存情况 +//func GetCommodityStocksByStoreID(commodityID, storeID uint32) (map[uint32]uint32, error) { +// // 查询库存情况 +// var stocks []struct { +// StoreID uint32 +// CommodityID uint32 +// StockCount uint32 +// } +// err := orm.Eloquent.Table("erp_stock_commodity"). +// Select("store_id, erp_commodity_id, COUNT(*) AS stock_count"). +// Where("erp_commodity_id IN (?) AND store_id = ? AND state = 1", commodityID, storeID). +// Group("store_id, erp_commodity_id"). +// Find(&stocks).Error +// if err != nil { +// return nil, err +// } +// +// // 构建结果 +// result := make(map[uint32]uint32) +// for _, s := range stocks { +// result[s.StoreID] = s.StockCount +// } +// return result, nil +//} +// +//// GetCommodityLastMonthSales 批量查询商品的上月销售数量 +//func GetCommodityLastMonthSales(commodityID, storeID uint32) (uint32, error) { +// // 获取上个月的时间范围 +// firstDay, lastDay := GetLastMonthRange() +// +// // 查询上月销售数量 +// var lastMonthSales struct { +// Sales uint32 +// } +// err := orm.Eloquent.Table("erp_order_commodity"). +// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). +// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ +// "AND erp_order_commodity.created_at BETWEEN ? AND ?", +// HavePaid, commodityID, storeID, firstDay, lastDay). +// Select("SUM(erp_order_commodity.count) AS sales"). +// Scan(&lastMonthSales).Error +// if err != nil { +// return 0, err +// } +// +// return lastMonthSales.Sales, nil +//} +// +//// GetLastMonthRange 获取上个月的时间范围 +//func GetLastMonthRange() (time.Time, time.Time) { +// now := time.Now() +// year, month, _ := now.Date() +// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) +// lastDay := firstDay.AddDate(0, 1, -1) +// return firstDay, lastDay +//} +// +//// GetOnlineStores 查询所有在线门店信息 +//func GetOnlineStores() ([]Store, error) { +// var stores []Store +// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error +// if err != nil { +// return nil, err +// } +// return stores, nil +//} + +// 3333 +//// GetErpPurchaseDemand 获取采购需求 +//func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { +// resp := &GetErpPurchaseDemandResp{ +// PageIndex: req.PageIndex, +// PageSize: req.PageSize, +// } +// page := req.PageIndex - 1 +// if page < 0 { +// page = 0 +// } +// if req.PageSize == 0 { +// req.PageSize = 10 +// } +// +// qs := orm.Eloquent.Debug().Table("erp_commodity") +// if req.ErpCategoryId != 0 { +// qs = qs.Where("erp_category_id=?", req.ErpCategoryId) +// } +// +// var commodities []ErpCommodity +// err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error +// if err != nil && err != RecordNotFound { +// return resp, err +// } +// +// // 批量查询门店信息 +// stores, err := GetOnlineStores() +// if err != nil { +// return nil, err +// } +// +// // 并行查询需求数据 +// var wg sync.WaitGroup +// demandDataList := make([]DemandData, len(commodities)) +// +// for i, v := range commodities { +// wg.Add(1) +// go func(index int, commodity ErpCommodity) { +// defer wg.Done() +// demandData, err := convertToDemandData(commodity, stores) +// if err != nil { +// // Handle error +// return +// } +// demandDataList[index] = demandData +// }(i, v) +// } +// +// wg.Wait() +// +// resp.List = demandDataList +// +// return resp, nil +//} +// +//// convertToDemandData 将商品转换为采购需求数据 +//func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { +// demandData := DemandData{ +// ErpCommodityID: commodity.ID, +// ErpCommoditySerialNumber: commodity.SerialNumber, +// ErpCommodityName: commodity.Name, +// ErpCategoryID: commodity.ErpCategoryId, +// ErpCategoryName: commodity.ErpCategoryName, +// RetailPrice: commodity.RetailPrice, +// } +// +// // 并行查询最近采购价、库存情况、上月销售数量 +// var wg sync.WaitGroup +// wg.Add(3) +// +// var lastWholesalePrices map[uint32]float64 +// var stockCounts map[uint32]uint32 +// var lastMonthSales uint32 +// var err1, err2, err3 error +// +// go func() { +// defer wg.Done() +// lastWholesalePrices, err1 = GetCommodityLastWholesalePrices(commodity.ID) +// }() +// +// go func() { +// defer wg.Done() +// stockCounts, err2 = GetCommodityStocksByStoreID(commodity.ID, stores) +// }() +// +// go func() { +// defer wg.Done() +// lastMonthSales, err3 = GetCommodityLastMonthSales(commodity.ID, stores) +// }() +// +// wg.Wait() +// +// if err1 != nil || err2 != nil || err3 != nil { +// // Handle error +// return DemandData{}, err1 +// } +// +// // 构建需求数据 +// demandData.List = make([]struct { +// StoreID uint32 `json:"store_id"` +// StoreName string `json:"store_name"` +// LastMonthSales uint32 `json:"last_month_sales"` +// StockCount uint32 `json:"stock_count"` +// NeedCount uint32 `json:"need_count"` +// }, len(stores)) +// +// for i, store := range stores { +// demandData.List[i].StoreID = store.ID +// demandData.List[i].StoreName = store.Name +// +// demandData.List[i].StockCount = stockCounts[store.ID] +// demandData.List[i].LastMonthSales = lastMonthSales +// +// // 设置最近采购价 +// demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] +// } +// +// return demandData, nil +//} +// +//// GetCommodityLastWholesalePrices 批量查询商品的最近采购价 +//func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { +// // 查询最近采购价 +// var prices []struct { +// CommodityID 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"). +// Order("created_at DESC"). +// Find(&prices).Error +// if err != nil { +// return nil, err +// } +// +// // 构建结果 +// result := make(map[uint32]float64) +// for _, p := range prices { +// result[p.CommodityID] = p.Price +// } +// return result, nil +//} +// +//// GetCommodityStocksByStoreID 批量查询商品的库存情况 +//func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) { +// // 并行查询库存情况 +// var wg sync.WaitGroup +// wg.Add(len(stores)) +// +// result := make(map[uint32]uint32) +// +// for _, store := range stores { +// go func(storeID uint32) { +// defer wg.Done() +// // 查询库存情况 +// var stockCount int64 +// err := orm.Eloquent.Table("erp_stock_commodity"). +// Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID). +// Count(&stockCount).Error +// if err != nil { +// // Handle error +// return +// } +// result[storeID] = uint32(stockCount) +// }(store.ID) +// } +// +// wg.Wait() +// +// return result, nil +//} +// +//// GetCommodityLastMonthSales 批量查询商品的上月销售数量 +//func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) { +// // 获取上个月的时间范围 +// firstDay, lastDay := GetLastMonthRange() +// +// // 并行查询上月销售数量 +// var wg sync.WaitGroup +// wg.Add(len(stores)) +// +// var totalSales uint32 +// var mu sync.Mutex // 用于保护 totalSales 的并发访问 +// +// for _, store := range stores { +// go func(storeID uint32) { +// defer wg.Done() +// // 查询上月销售数量 +// var sales uint32 +// err := orm.Eloquent.Table("erp_order_commodity"). +// Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). +// Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ +// "AND erp_order_commodity.created_at BETWEEN ? AND ?", +// HavePaid, commodityID, storeID, firstDay, lastDay). +// Select("SUM(erp_order_commodity.count) AS sales"). +// Scan(&sales).Error +// if err != nil { +// // Handle error +// return +// } +// +// // 累加销售数量 +// mu.Lock() +// totalSales += sales +// mu.Unlock() +// }(store.ID) +// } +// +// wg.Wait() +// +// return totalSales, nil +//} +// +//// GetLastMonthRange 获取上个月的时间范围 +//func GetLastMonthRange() (time.Time, time.Time) { +// now := time.Now() +// year, month, _ := now.Date() +// firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) +// lastDay := firstDay.AddDate(0, 1, -1) +// return firstDay, lastDay +//} +// +//// GetOnlineStores 查询所有在线门店信息 +//func GetOnlineStores() ([]Store, error) { +// var stores []Store +// err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error +// if err != nil { +// return nil, err +// } +// return stores, nil +//} + +// GetErpPurchaseDemand 获取采购需求 +func GetErpPurchaseDemand(req *GetErpPurchaseDemandReq) (*GetErpPurchaseDemandResp, error) { + page := req.PageIndex - 1 + if page < 0 { + page = 0 + } + if req.PageSize == 0 { + req.PageSize = 10 + } + + resp := &GetErpPurchaseDemandResp{ + PageIndex: page + 1, + PageSize: req.PageSize, + } + + qs := orm.Eloquent.Debug().Table("erp_commodity") + if req.ErpCategoryId != 0 { + qs = qs.Where("erp_category_id=?", req.ErpCategoryId) + } + + var count int64 + if err := qs.Count(&count).Error; err != nil { + logger.Error("count err:", logger.Field("err", err)) + return resp, err + } + + var commodities []ErpCommodity + err := qs.Order("id DESC").Offset(page * req.PageSize).Limit(req.PageSize).Find(&commodities).Error + if err != nil && err != RecordNotFound { + return resp, err + } + + // 批量查询门店信息 + stores, err := GetOnlineStores() + if err != nil { + return nil, err + } + + // 并行查询需求数据 + var wg sync.WaitGroup + demandDataList := make([]DemandData, len(commodities)) + + for i, v := range commodities { + wg.Add(1) + go func(index int, commodity ErpCommodity) { + defer wg.Done() + demandData, err := convertToDemandData(commodity, stores) + if err != nil { + // Handle error + return + } + demandDataList[index] = demandData + }(i, v) + } + + wg.Wait() + + resp.List = demandDataList + resp.Total = count + + return resp, nil +} + +// convertToDemandData 将商品转换为采购需求数据 +func convertToDemandData(commodity ErpCommodity, stores []Store) (DemandData, error) { + demandData := DemandData{ + ErpCommodityID: commodity.ID, + ErpCommoditySerialNumber: commodity.SerialNumber, + ErpCommodityName: commodity.Name, + ErpCategoryID: commodity.ErpCategoryId, + ErpCategoryName: commodity.ErpCategoryName, + RetailPrice: commodity.RetailPrice, + } + + // 查询采购需求单 + demands, err := GetCommodityPurchaseDemands(commodity.ID, stores) + if err != nil { + // Handle error + return DemandData{}, err + } + + // 使用 WaitGroup 进行并行查询 + var wg sync.WaitGroup + wg.Add(3) + + var lastWholesalePrices map[uint32]float64 + var stockCounts map[uint32]uint32 + var lastMonthSales uint32 + + go func() { + defer wg.Done() + lastWholesalePrices, err = GetCommodityLastWholesalePrices(commodity.ID) + }() + + go func() { + defer wg.Done() + stockCounts, err = GetCommodityStocksByStoreID(commodity.ID, stores) + }() + + go func() { + defer wg.Done() + lastMonthSales, err = GetCommodityLastMonthSales(commodity.ID, stores) + }() + + wg.Wait() + if err != nil { + // Handle error + return DemandData{}, err + } + + var totalCount uint32 // 总需采购数量 + // 构建需求数据 + demandData.StoreList = make([]struct { + StoreID uint32 `json:"store_id"` + StoreName string `json:"store_name"` + LastMonthSales uint32 `json:"last_month_sales"` + StockCount uint32 `json:"stock_count"` + NeedCount uint32 `json:"need_count"` + }, len(stores)) + + for i, store := range stores { + demandData.StoreList[i].StoreID = store.ID + demandData.StoreList[i].StoreName = store.Name + + demandData.StoreList[i].StockCount = stockCounts[store.ID] + demandData.StoreList[i].LastMonthSales = lastMonthSales + + // 设置最近采购价 + demandData.LastWholesalePrice = lastWholesalePrices[commodity.ID] + + // 设置采购需求量 + for _, demand := range demands { + if demand.StoreId == store.ID { + demandData.StoreList[i].NeedCount = demand.Count + totalCount += demand.Count + break + } + } + } + + demandData.TotalCount = totalCount + demandData.TotalAmount = float64(totalCount) * demandData.LastWholesalePrice + + return demandData, nil +} + +// GetCommodityPurchaseDemands 查询商品的采购需求单 +func GetCommodityPurchaseDemands(commodityID uint32, stores []Store) ([]ErpPurchaseDemand, error) { + var wg sync.WaitGroup + var mu sync.Mutex + var demands []ErpPurchaseDemand + wg.Add(len(stores)) + + for _, store := range stores { + go func(storeID uint32) { + defer wg.Done() + var demand ErpPurchaseDemand + err := orm.Eloquent.Table("erp_purchase_demand"). + Where("erp_commodity_id = ? AND state = 1 AND store_id = ?", commodityID, storeID). + First(&demand).Error + if err != nil { + // Handle error + return + } + + mu.Lock() + defer mu.Unlock() + demands = append(demands, demand) + }(store.ID) + } + + wg.Wait() + + return demands, nil +} + +// GetCommodityLastWholesalePrices 批量查询商品的最近采购价 +func GetCommodityLastWholesalePrices(commodityID uint32) (map[uint32]float64, error) { + // 查询最近采购价 + var prices []struct { + CommodityID 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"). + Order("created_at DESC"). + Find(&prices).Error + if err != nil { + return nil, err + } + + // 构建结果 + result := make(map[uint32]float64) + for _, p := range prices { + result[p.CommodityID] = p.Price + } + return result, nil +} + +// GetCommodityStocksByStoreID 批量查询商品的库存情况 +func GetCommodityStocksByStoreID(commodityID uint32, stores []Store) (map[uint32]uint32, error) { + // 并行查询库存情况 + var wg sync.WaitGroup + wg.Add(len(stores)) + + result := make(map[uint32]uint32) + + for _, store := range stores { + go func(storeID uint32) { + defer wg.Done() + // 查询库存情况 + var stockCount int64 + err := orm.Eloquent.Table("erp_stock_commodity"). + Where("erp_commodity_id = ? AND store_id = ? AND state = 1", commodityID, storeID). + Count(&stockCount).Error + if err != nil { + // Handle error + return + } + result[storeID] = uint32(stockCount) + }(store.ID) + } + + wg.Wait() + + return result, nil +} + +// GetCommodityLastMonthSales 批量查询商品的上月销售数量 +func GetCommodityLastMonthSales(commodityID uint32, stores []Store) (uint32, error) { + // 获取上个月的时间范围 + firstDay, lastDay := GetLastMonthRange() + + // 并行查询上月销售数量 + var wg sync.WaitGroup + wg.Add(len(stores)) + + var totalSales uint32 + var mu sync.Mutex // 用于保护 totalSales 的并发访问 + + for _, store := range stores { + go func(storeID uint32) { + defer wg.Done() + // 查询上月销售数量 + var sales uint32 + err := orm.Eloquent.Table("erp_order_commodity"). + Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id"). + Where("erp_order.pay_status = ? AND erp_order_commodity.erp_commodity_id = ? AND erp_order.store_id = ? "+ + "AND erp_order_commodity.created_at BETWEEN ? AND ?", + HavePaid, commodityID, storeID, firstDay, lastDay). + Select("SUM(erp_order_commodity.count) AS sales"). + Scan(&sales).Error + if err != nil { + // Handle error + return + } + + // 保护 totalSales 的并发访问 + mu.Lock() + defer mu.Unlock() + totalSales += sales + }(store.ID) + } + + wg.Wait() + + return totalSales, nil +} + +// GetLastMonthRange 获取上个月的时间范围 +func GetLastMonthRange() (time.Time, time.Time) { + now := time.Now() + year, month, _ := now.Date() + firstDay := time.Date(year, month-1, 1, 0, 0, 0, 0, now.Location()) + lastDay := firstDay.AddDate(0, 1, -1) + return firstDay, lastDay +} + +// GetOnlineStores 查询所有在线门店信息 +func GetOnlineStores() ([]Store, error) { + var stores []Store + err := orm.Eloquent.Table("store").Where("is_online = ?", 1).Find(&stores).Error + if err != nil { + return nil, err + } + return stores, nil +} + +type Result struct { + TotalCount uint32 `gorm:"column:total_count"` + AvgImplementationPrice float64 `gorm:"column:avg_implementation_price"` + TotalAmount float64 `gorm:"column:total_amount"` + AvgEmployeePrice float64 `gorm:"column:avg_employee_price"` +} + +// GetTotalsAndAveragesByCommodityID 查询执行数量之和、平均执行单价、执行金额之和和平均员工成本价 +func GetTotalsAndAveragesByCommodityID(commodityID uint32) (Result, error) { + var result Result + err := orm.Eloquent.Table("erp_purchase_inventory"). + Select("SUM(`count`) AS total_count, AVG(`implementation_price`) AS avg_implementation_price, "+ + "SUM(`amount`) AS total_amount, AVG(`employee_price`) AS avg_employee_price"). + Where("erp_commodity_id = ?", commodityID). + Scan(&result).Error + if err != nil { + return Result{}, err + } + + return result, nil +} diff --git a/app/admin/models/sysuser.go b/app/admin/models/sysuser.go index 4781c82..3fc181f 100644 --- a/app/admin/models/sysuser.go +++ b/app/admin/models/sysuser.go @@ -103,6 +103,7 @@ type InsertSysUserReq struct { AccountType uint32 `json:"account_type"` // 账号类型:1-管理端 SalesCommRate string `json:"sales_comm_rate"` // 销售提成比例 StoreList []StoreInfo `json:"store_list"` // 有效门店 + Uid uint32 `json:"uid"` // 用户uid } func (SysUser) TableName() string { diff --git a/app/admin/router/purchasemanage.go b/app/admin/router/purchasemanage.go index 368685f..b1a2522 100644 --- a/app/admin/router/purchasemanage.go +++ b/app/admin/router/purchasemanage.go @@ -10,13 +10,16 @@ import ( func registerErpPurchaseManageRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { r := v1.Group("/erp_purchase").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) - r.POST("create", purchasemanage.ErpPurchaseCreate) // 创建采购订单(入库/退货) - r.POST("edit", purchasemanage.ErpPurchaseEdit) // 编辑采购订单 - r.POST("list", purchasemanage.ErpPurchaseList) // 查询采购订单列表 - r.POST("detail", purchasemanage.ErpPurchaseDetail) // 查询采购订单详情 - r.POST("audit", purchasemanage.ErpPurchaseAudit) // 审核采购订单 - r.POST("delete", purchasemanage.ErpPurchaseDelete) // 删除采购订单 - r.POST("inventory", purchasemanage.ErpPurchaseInventory) // 入库(退货) - r.POST("terminate", purchasemanage.ErpPurchaseTerminate) // 终止 - r.POST("execute", purchasemanage.ErpPurchaseExecute) // 执行 + r.POST("create", purchasemanage.ErpPurchaseCreate) // 创建采购订单(入库/退货) + r.POST("edit", purchasemanage.ErpPurchaseEdit) // 编辑采购订单 + r.POST("list", purchasemanage.ErpPurchaseList) // 查询采购订单列表 + r.POST("detail", purchasemanage.ErpPurchaseDetail) // 查询采购订单详情 + r.POST("audit", purchasemanage.ErpPurchaseAudit) // 审核采购订单 + r.POST("delete", purchasemanage.ErpPurchaseDelete) // 删除采购订单 + r.POST("inventory", purchasemanage.ErpPurchaseInventory) // 入库(退货) + r.POST("terminate", purchasemanage.ErpPurchaseTerminate) // 终止 + r.POST("execute", purchasemanage.ErpPurchaseExecute) // 执行 + r.POST("demand/create", purchasemanage.ErpPurchaseDemandCreate) // 创建采购需求 + r.POST("demand/get", purchasemanage.ErpPurchaseDemandGet) // 获取采购需求 + r.POST("demand/finish", purchasemanage.ErpPurchaseDemandFinish) // 完成采购需求 } diff --git a/docs/docs.go b/docs/docs.go index 8fefb3a..eaae101 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2220,6 +2220,108 @@ const docTemplate = `{ } } }, + "/api/v1/erp_purchase/demand/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "创建采购需求", + "parameters": [ + { + "description": "创建采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CreateErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/erp_purchase/demand/finish": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "完成采购需求", + "parameters": [ + { + "description": "完成采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.FinishErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/erp_purchase/demand/get": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "获取采购需求", + "parameters": [ + { + "description": "获取采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.GetErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.GetErpPurchaseDemandResp" + } + } + } + } + }, "/api/v1/erp_purchase/detail": { "post": { "consumes": [ @@ -2288,6 +2390,40 @@ const docTemplate = `{ } } }, + "/api/v1/erp_purchase/execute": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购管理", + "V1.3.0" + ], + "summary": "执行(入库/退货)", + "parameters": [ + { + "description": "执行(入库/退货)模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.ErpPurchaseInventoryReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.ErpPurchaseExecuteResp" + } + } + } + } + }, "/api/v1/erp_purchase/inventory": { "post": { "consumes": [ @@ -5868,6 +6004,116 @@ const docTemplate = `{ } } }, + "models.CreateErpPurchaseDemandReq": { + "type": "object", + "properties": { + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "need_count": { + "description": "需采购数", + "type": "integer" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + } + }, + "remark": { + "description": "备注", + "type": "string" + } + } + }, + "models.DemandData": { + "type": "object", + "properties": { + "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_commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "last_wholesale_price": { + "description": "最近采购价", + "type": "number" + }, + "retail_price": { + "description": "指导零售价", + "type": "integer" + }, + "store_list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "last_month_sales": { + "description": "上月销售数", + "type": "integer" + }, + "need_count": { + "description": "需采购数", + "type": "integer" + }, + "stock_count": { + "description": "库存数量", + "type": "integer" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + } + }, + "total_amount": { + "description": "需采购总金额", + "type": "number" + }, + "total_count": { + "description": "需采购总数量", + "type": "integer" + } + } + }, "models.DictType": { "type": "object", "properties": { @@ -7170,7 +7416,7 @@ const docTemplate = `{ "properties": { "amount": { "description": "计划采购金额", - "type": "integer" + "type": "number" }, "commodity_serial_number": { "description": "商品编号", @@ -7198,7 +7444,7 @@ const docTemplate = `{ }, "execute_amount": { "description": "执行金额", - "type": "integer" + "type": "number" }, "execute_count": { "description": "执行数量", @@ -7206,11 +7452,11 @@ const docTemplate = `{ }, "execute_employee_price": { "description": "平均员工成本价", - "type": "integer" + "type": "number" }, "execute_price": { "description": "平均采购单价", - "type": "integer" + "type": "number" }, "id": { "description": "数据库记录编号", @@ -7225,28 +7471,32 @@ const docTemplate = `{ "type": "integer" }, "inventory_count": { - "description": "入库数量(已执行数量)", + "description": "入库数量(=执行数量)", "type": "integer" }, "price": { "description": "计划采购单价", - "type": "integer" + "type": "number" }, "rejected_amount": { "description": "计划退货金额", - "type": "integer" + "type": "number" }, "rejected_count": { "description": "计划退货数量", - "type": "integer" + "type": "number" }, "rejected_price": { "description": "计划退货单价", - "type": "integer" + "type": "number" }, "remark": { "description": "备注", "type": "string" + }, + "retail_price": { + "description": "指导零售价", + "type": "integer" } } }, @@ -7259,7 +7509,6 @@ const docTemplate = `{ "erp_cashier_id", "erp_purchase_commodities", "erp_supplier_id", - "maker_id", "opening_bank", "purchase_type", "store_id" @@ -7296,10 +7545,14 @@ const docTemplate = `{ "description": "供应商id", "type": "integer" }, - "maker_id": { - "description": "经手人", + "handler_id": { + "description": "经手人id", "type": "integer" }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "opening_bank": { "description": "开户行", "type": "string" @@ -7344,7 +7597,6 @@ const docTemplate = `{ "erp_purchase_commodities", "erp_purchase_order_id", "erp_supplier_id", - "maker_id", "opening_bank", "purchase_type", "store_id" @@ -7385,10 +7637,14 @@ const docTemplate = `{ "description": "供应商id", "type": "integer" }, - "maker_id": { - "description": "经手人", + "handler_id": { + "description": "经手人id", "type": "integer" }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "opening_bank": { "description": "开户行", "type": "string" @@ -7411,19 +7667,37 @@ const docTemplate = `{ } } }, - "models.ErpPurchaseInventory": { + "models.ErpPurchaseExecuteResp": { "type": "object", "properties": { - "amount": { - "description": "入库金额", + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ExecuteData" + } + }, + "total": { + "description": "总条数", "type": "integer" + } + } + }, + "models.ErpPurchaseInventory": { + "type": "object", + "required": [ + "purchase_type" + ], + "properties": { + "amount": { + "description": "执行金额", + "type": "number" }, "commodity_serial_number": { "description": "商品编号", "type": "string" }, "count": { - "description": "数量", + "description": "执行数量", "type": "integer" }, "createdAt": { @@ -7432,7 +7706,7 @@ const docTemplate = `{ }, "employee_price": { "description": "员工成本价", - "type": "integer" + "type": "number" }, "erp_commodity_id": { "description": "商品id", @@ -7460,22 +7734,10 @@ const docTemplate = `{ }, "implementation_price": { "description": "执行单价", - "type": "integer" + "type": "number" }, - "inventory_count": { - "description": "入库数量", - "type": "integer" - }, - "inventory_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" - }, - "price": { - "description": "采购单价", - "type": "integer" - }, - "remark": { - "description": "备注", + "purchase_type": { + "description": "采购类型:procure-采购 reject-退货", "type": "string" }, "serial_number": { @@ -7488,8 +7750,7 @@ const docTemplate = `{ "type": "object", "required": [ "erp_purchase_order_id", - "inventories", - "inventory_type" + "inventories" ], "properties": { "erp_purchase_order_id": { @@ -7497,15 +7758,11 @@ const docTemplate = `{ "type": "integer" }, "inventories": { - "description": "采购信息", + "description": "采购入库执行信息", "type": "array", "items": { "$ref": "#/definitions/models.ErpPurchaseInventory" } - }, - "inventory_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" } } }, @@ -7562,6 +7819,14 @@ const docTemplate = `{ "description": "供应商名称", "type": "string" }, + "handler_id": { + "description": "经手人id", + "type": "integer" + }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "id": { "description": "数据库记录编号", "type": "integer" @@ -8062,6 +8327,59 @@ const docTemplate = `{ } } }, + "models.ExecuteData": { + "type": "object", + "properties": { + "commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "count": { + "description": "数量", + "type": "integer" + }, + "employee_price": { + "description": "员工成本价", + "type": "number" + }, + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_purchase_order_id": { + "description": "商品采购订单id", + "type": "integer" + }, + "imei": { + "description": "商品串码", + "type": "string" + }, + "imei_type": { + "description": "1-无串码 2-串码", + "type": "integer" + }, + "implementation_price": { + "description": "执行单价", + "type": "number" + } + } + }, + "models.FinishErpPurchaseDemandReq": { + "type": "object", + "required": [ + "erp_commodity_id" + ], + "properties": { + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + } + } + }, "models.GameCard": { "type": "object", "properties": { @@ -8147,6 +8465,61 @@ const docTemplate = `{ } } }, + "models.GetErpPurchaseDemandReq": { + "type": "object", + "required": [ + "erp_category_id" + ], + "properties": { + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "hide_flag": { + "description": "隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有", + "type": "string" + }, + "is_export": { + "description": "1-导出", + "type": "integer" + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页展示数据条数", + "type": "integer" + } + } + }, + "models.GetErpPurchaseDemandResp": { + "type": "object", + "properties": { + "export_url": { + "description": "文件路径", + "type": "string" + }, + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.DemandData" + } + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页展示条数", + "type": "integer" + }, + "total": { + "description": "数据总条数", + "type": "integer" + } + } + }, "models.InsertSysUserReq": { "type": "object", "properties": { @@ -8229,6 +8602,10 @@ const docTemplate = `{ "description": "门店名称", "type": "string" }, + "uid": { + "description": "用户uid", + "type": "integer" + }, "userId": { "description": "编码", "type": "integer" diff --git a/docs/swagger.json b/docs/swagger.json index 2e5a1f7..e6c851a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2209,6 +2209,108 @@ } } }, + "/api/v1/erp_purchase/demand/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "创建采购需求", + "parameters": [ + { + "description": "创建采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.CreateErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/erp_purchase/demand/finish": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "完成采购需求", + "parameters": [ + { + "description": "完成采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.FinishErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/app.Response" + } + } + } + } + }, + "/api/v1/erp_purchase/demand/get": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购需求", + "V1.3.0" + ], + "summary": "获取采购需求", + "parameters": [ + { + "description": "获取采购需求模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.GetErpPurchaseDemandReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.GetErpPurchaseDemandResp" + } + } + } + } + }, "/api/v1/erp_purchase/detail": { "post": { "consumes": [ @@ -2277,6 +2379,40 @@ } } }, + "/api/v1/erp_purchase/execute": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "采购管理", + "V1.3.0" + ], + "summary": "执行(入库/退货)", + "parameters": [ + { + "description": "执行(入库/退货)模型", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.ErpPurchaseInventoryReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.ErpPurchaseExecuteResp" + } + } + } + } + }, "/api/v1/erp_purchase/inventory": { "post": { "consumes": [ @@ -5857,6 +5993,116 @@ } } }, + "models.CreateErpPurchaseDemandReq": { + "type": "object", + "properties": { + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "need_count": { + "description": "需采购数", + "type": "integer" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + } + }, + "remark": { + "description": "备注", + "type": "string" + } + } + }, + "models.DemandData": { + "type": "object", + "properties": { + "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_commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "last_wholesale_price": { + "description": "最近采购价", + "type": "number" + }, + "retail_price": { + "description": "指导零售价", + "type": "integer" + }, + "store_list": { + "type": "array", + "items": { + "type": "object", + "properties": { + "last_month_sales": { + "description": "上月销售数", + "type": "integer" + }, + "need_count": { + "description": "需采购数", + "type": "integer" + }, + "stock_count": { + "description": "库存数量", + "type": "integer" + }, + "store_id": { + "description": "门店id", + "type": "integer" + }, + "store_name": { + "description": "门店名称", + "type": "string" + } + } + } + }, + "total_amount": { + "description": "需采购总金额", + "type": "number" + }, + "total_count": { + "description": "需采购总数量", + "type": "integer" + } + } + }, "models.DictType": { "type": "object", "properties": { @@ -7159,7 +7405,7 @@ "properties": { "amount": { "description": "计划采购金额", - "type": "integer" + "type": "number" }, "commodity_serial_number": { "description": "商品编号", @@ -7187,7 +7433,7 @@ }, "execute_amount": { "description": "执行金额", - "type": "integer" + "type": "number" }, "execute_count": { "description": "执行数量", @@ -7195,11 +7441,11 @@ }, "execute_employee_price": { "description": "平均员工成本价", - "type": "integer" + "type": "number" }, "execute_price": { "description": "平均采购单价", - "type": "integer" + "type": "number" }, "id": { "description": "数据库记录编号", @@ -7214,28 +7460,32 @@ "type": "integer" }, "inventory_count": { - "description": "入库数量(已执行数量)", + "description": "入库数量(=执行数量)", "type": "integer" }, "price": { "description": "计划采购单价", - "type": "integer" + "type": "number" }, "rejected_amount": { "description": "计划退货金额", - "type": "integer" + "type": "number" }, "rejected_count": { "description": "计划退货数量", - "type": "integer" + "type": "number" }, "rejected_price": { "description": "计划退货单价", - "type": "integer" + "type": "number" }, "remark": { "description": "备注", "type": "string" + }, + "retail_price": { + "description": "指导零售价", + "type": "integer" } } }, @@ -7248,7 +7498,6 @@ "erp_cashier_id", "erp_purchase_commodities", "erp_supplier_id", - "maker_id", "opening_bank", "purchase_type", "store_id" @@ -7285,10 +7534,14 @@ "description": "供应商id", "type": "integer" }, - "maker_id": { - "description": "经手人", + "handler_id": { + "description": "经手人id", "type": "integer" }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "opening_bank": { "description": "开户行", "type": "string" @@ -7333,7 +7586,6 @@ "erp_purchase_commodities", "erp_purchase_order_id", "erp_supplier_id", - "maker_id", "opening_bank", "purchase_type", "store_id" @@ -7374,10 +7626,14 @@ "description": "供应商id", "type": "integer" }, - "maker_id": { - "description": "经手人", + "handler_id": { + "description": "经手人id", "type": "integer" }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "opening_bank": { "description": "开户行", "type": "string" @@ -7400,19 +7656,37 @@ } } }, - "models.ErpPurchaseInventory": { + "models.ErpPurchaseExecuteResp": { "type": "object", "properties": { - "amount": { - "description": "入库金额", + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.ExecuteData" + } + }, + "total": { + "description": "总条数", "type": "integer" + } + } + }, + "models.ErpPurchaseInventory": { + "type": "object", + "required": [ + "purchase_type" + ], + "properties": { + "amount": { + "description": "执行金额", + "type": "number" }, "commodity_serial_number": { "description": "商品编号", "type": "string" }, "count": { - "description": "数量", + "description": "执行数量", "type": "integer" }, "createdAt": { @@ -7421,7 +7695,7 @@ }, "employee_price": { "description": "员工成本价", - "type": "integer" + "type": "number" }, "erp_commodity_id": { "description": "商品id", @@ -7449,22 +7723,10 @@ }, "implementation_price": { "description": "执行单价", - "type": "integer" + "type": "number" }, - "inventory_count": { - "description": "入库数量", - "type": "integer" - }, - "inventory_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" - }, - "price": { - "description": "采购单价", - "type": "integer" - }, - "remark": { - "description": "备注", + "purchase_type": { + "description": "采购类型:procure-采购 reject-退货", "type": "string" }, "serial_number": { @@ -7477,8 +7739,7 @@ "type": "object", "required": [ "erp_purchase_order_id", - "inventories", - "inventory_type" + "inventories" ], "properties": { "erp_purchase_order_id": { @@ -7486,15 +7747,11 @@ "type": "integer" }, "inventories": { - "description": "采购信息", + "description": "采购入库执行信息", "type": "array", "items": { "$ref": "#/definitions/models.ErpPurchaseInventory" } - }, - "inventory_type": { - "description": "采购类型:procure-采购 reject-退货", - "type": "string" } } }, @@ -7551,6 +7808,14 @@ "description": "供应商名称", "type": "string" }, + "handler_id": { + "description": "经手人id", + "type": "integer" + }, + "handler_name": { + "description": "经手人名称", + "type": "string" + }, "id": { "description": "数据库记录编号", "type": "integer" @@ -8051,6 +8316,59 @@ } } }, + "models.ExecuteData": { + "type": "object", + "properties": { + "commodity_serial_number": { + "description": "商品编号", + "type": "string" + }, + "count": { + "description": "数量", + "type": "integer" + }, + "employee_price": { + "description": "员工成本价", + "type": "number" + }, + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + }, + "erp_commodity_name": { + "description": "商品名称", + "type": "string" + }, + "erp_purchase_order_id": { + "description": "商品采购订单id", + "type": "integer" + }, + "imei": { + "description": "商品串码", + "type": "string" + }, + "imei_type": { + "description": "1-无串码 2-串码", + "type": "integer" + }, + "implementation_price": { + "description": "执行单价", + "type": "number" + } + } + }, + "models.FinishErpPurchaseDemandReq": { + "type": "object", + "required": [ + "erp_commodity_id" + ], + "properties": { + "erp_commodity_id": { + "description": "商品id", + "type": "integer" + } + } + }, "models.GameCard": { "type": "object", "properties": { @@ -8136,6 +8454,61 @@ } } }, + "models.GetErpPurchaseDemandReq": { + "type": "object", + "required": [ + "erp_category_id" + ], + "properties": { + "erp_category_id": { + "description": "商品分类id", + "type": "integer" + }, + "hide_flag": { + "description": "隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有", + "type": "string" + }, + "is_export": { + "description": "1-导出", + "type": "integer" + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页展示数据条数", + "type": "integer" + } + } + }, + "models.GetErpPurchaseDemandResp": { + "type": "object", + "properties": { + "export_url": { + "description": "文件路径", + "type": "string" + }, + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/models.DemandData" + } + }, + "pageIndex": { + "description": "页码", + "type": "integer" + }, + "pageSize": { + "description": "每页展示条数", + "type": "integer" + }, + "total": { + "description": "数据总条数", + "type": "integer" + } + } + }, "models.InsertSysUserReq": { "type": "object", "properties": { @@ -8218,6 +8591,10 @@ "description": "门店名称", "type": "string" }, + "uid": { + "description": "用户uid", + "type": "integer" + }, "userId": { "description": "编码", "type": "integer" diff --git a/docs/swagger.yaml b/docs/swagger.yaml index dba06fb..aa82201 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -899,6 +899,85 @@ definitions: - wx_app_mchId - wx_app_mchSecret type: object + models.CreateErpPurchaseDemandReq: + properties: + erp_commodity_id: + description: 商品id + type: integer + erp_commodity_name: + description: 商品名称 + type: string + erp_commodity_serial_number: + description: 商品编号 + type: string + list: + items: + properties: + need_count: + description: 需采购数 + type: integer + store_id: + description: 门店id + type: integer + store_name: + description: 门店名称 + type: string + type: object + type: array + remark: + description: 备注 + type: string + type: object + models.DemandData: + properties: + 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_commodity_serial_number: + description: 商品编号 + type: string + last_wholesale_price: + description: 最近采购价 + type: number + retail_price: + description: 指导零售价 + type: integer + store_list: + items: + properties: + last_month_sales: + description: 上月销售数 + type: integer + need_count: + description: 需采购数 + type: integer + stock_count: + description: 库存数量 + type: integer + store_id: + description: 门店id + type: integer + store_name: + description: 门店名称 + type: string + type: object + type: array + total_amount: + description: 需采购总金额 + type: number + total_count: + description: 需采购总数量 + type: integer + type: object models.DictType: properties: createBy: @@ -1844,7 +1923,7 @@ definitions: properties: amount: description: 计划采购金额 - type: integer + type: number commodity_serial_number: description: 商品编号 type: string @@ -1865,16 +1944,16 @@ definitions: type: integer execute_amount: description: 执行金额 - type: integer + type: number execute_count: description: 执行数量 type: integer execute_employee_price: description: 平均员工成本价 - type: integer + type: number execute_price: description: 平均采购单价 - type: integer + type: number id: description: 数据库记录编号 type: integer @@ -1885,23 +1964,26 @@ definitions: description: 1-无串码 2-串码 type: integer inventory_count: - description: 入库数量(已执行数量) + description: 入库数量(=执行数量) type: integer price: description: 计划采购单价 - type: integer + type: number rejected_amount: description: 计划退货金额 - type: integer + type: number rejected_count: description: 计划退货数量 - type: integer + type: number rejected_price: description: 计划退货单价 - type: integer + type: number remark: description: 备注 type: string + retail_price: + description: 指导零售价 + type: integer type: object models.ErpPurchaseCreateReq: properties: @@ -1928,9 +2010,12 @@ definitions: erp_supplier_id: description: 供应商id type: integer - maker_id: - description: 经手人 + handler_id: + description: 经手人id type: integer + handler_name: + description: 经手人名称 + type: string opening_bank: description: 开户行 type: string @@ -1953,7 +2038,6 @@ definitions: - erp_cashier_id - erp_purchase_commodities - erp_supplier_id - - maker_id - opening_bank - purchase_type - store_id @@ -1994,9 +2078,12 @@ definitions: erp_supplier_id: description: 供应商id type: integer - maker_id: - description: 经手人 + handler_id: + description: 经手人id type: integer + handler_name: + description: 经手人名称 + type: string opening_bank: description: 开户行 type: string @@ -2020,28 +2107,37 @@ definitions: - erp_purchase_commodities - erp_purchase_order_id - erp_supplier_id - - maker_id - opening_bank - purchase_type - store_id type: object + models.ErpPurchaseExecuteResp: + properties: + list: + items: + $ref: '#/definitions/models.ExecuteData' + type: array + total: + description: 总条数 + type: integer + type: object models.ErpPurchaseInventory: properties: amount: - description: 入库金额 - type: integer + description: 执行金额 + type: number commodity_serial_number: description: 商品编号 type: string count: - description: 数量 + description: 执行数量 type: integer createdAt: description: 创建时间 type: string employee_price: description: 员工成本价 - type: integer + type: number erp_commodity_id: description: 商品id type: integer @@ -2062,22 +2158,15 @@ definitions: type: integer implementation_price: description: 执行单价 - type: integer - inventory_count: - description: 入库数量 - type: integer - inventory_type: - description: 采购类型:procure-采购 reject-退货 - type: string - price: - description: 采购单价 - type: integer - remark: - description: 备注 + type: number + purchase_type: + description: 采购类型:procure-采购 reject-退货 type: string serial_number: description: 入库编号 type: string + required: + - purchase_type type: object models.ErpPurchaseInventoryReq: properties: @@ -2085,17 +2174,13 @@ definitions: description: 采购订单id type: integer inventories: - description: 采购信息 + description: 采购入库执行信息 items: $ref: '#/definitions/models.ErpPurchaseInventory' type: array - inventory_type: - description: 采购类型:procure-采购 reject-退货 - type: string required: - erp_purchase_order_id - inventories - - inventory_type type: object models.ErpPurchaseOrder: properties: @@ -2136,6 +2221,12 @@ definitions: erp_supplier_name: description: 供应商名称 type: string + handler_id: + description: 经手人id + type: integer + handler_name: + description: 经手人名称 + type: string id: description: 数据库记录编号 type: integer @@ -2501,6 +2592,44 @@ definitions: description: 数据总条数 type: integer type: object + models.ExecuteData: + properties: + commodity_serial_number: + description: 商品编号 + type: string + count: + description: 数量 + type: integer + employee_price: + description: 员工成本价 + type: number + erp_commodity_id: + description: 商品id + type: integer + erp_commodity_name: + description: 商品名称 + type: string + erp_purchase_order_id: + description: 商品采购订单id + type: integer + imei: + description: 商品串码 + type: string + imei_type: + description: 1-无串码 2-串码 + type: integer + implementation_price: + description: 执行单价 + type: number + type: object + models.FinishErpPurchaseDemandReq: + properties: + erp_commodity_id: + description: 商品id + type: integer + required: + - erp_commodity_id + type: object models.GameCard: properties: coverImg: @@ -2564,6 +2693,45 @@ definitions: description: 查看人数 type: integer type: object + models.GetErpPurchaseDemandReq: + properties: + erp_category_id: + description: 商品分类id + type: integer + hide_flag: + description: 隐藏标记(默认关闭):ON-开启,隐藏无采购需求的商品,OFF-关闭,展示所有 + type: string + is_export: + description: 1-导出 + type: integer + pageIndex: + description: 页码 + type: integer + pageSize: + description: 每页展示数据条数 + type: integer + required: + - erp_category_id + type: object + models.GetErpPurchaseDemandResp: + properties: + export_url: + description: 文件路径 + type: string + list: + items: + $ref: '#/definitions/models.DemandData' + type: array + pageIndex: + description: 页码 + type: integer + pageSize: + description: 每页展示条数 + type: integer + total: + description: 数据总条数 + type: integer + type: object models.InsertSysUserReq: properties: account_type: @@ -2625,6 +2793,9 @@ definitions: store_name: description: 门店名称 type: string + uid: + description: 用户uid + type: integer userId: description: 编码 type: integer @@ -6002,6 +6173,72 @@ paths: tags: - 采购管理 - V1.3.0 + /api/v1/erp_purchase/demand/create: + post: + consumes: + - application/json + parameters: + - description: 创建采购需求模型 + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.CreateErpPurchaseDemandReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/app.Response' + summary: 创建采购需求 + tags: + - 采购需求 + - V1.3.0 + /api/v1/erp_purchase/demand/finish: + post: + consumes: + - application/json + parameters: + - description: 完成采购需求模型 + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.FinishErpPurchaseDemandReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/app.Response' + summary: 完成采购需求 + tags: + - 采购需求 + - V1.3.0 + /api/v1/erp_purchase/demand/get: + post: + consumes: + - application/json + parameters: + - description: 获取采购需求模型 + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.GetErpPurchaseDemandReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.GetErpPurchaseDemandResp' + summary: 获取采购需求 + tags: + - 采购需求 + - V1.3.0 /api/v1/erp_purchase/detail: post: consumes: @@ -6046,6 +6283,28 @@ paths: tags: - 采购管理 - V1.3.0 + /api/v1/erp_purchase/execute: + post: + consumes: + - application/json + parameters: + - description: 执行(入库/退货)模型 + in: body + name: request + required: true + schema: + $ref: '#/definitions/models.ErpPurchaseInventoryReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.ErpPurchaseExecuteResp' + summary: 执行(入库/退货) + tags: + - 采购管理 + - V1.3.0 /api/v1/erp_purchase/inventory: post: consumes: