diff --git a/app/admin/apis/erpordermanage/erp_order.go b/app/admin/apis/erpordermanage/erp_order.go index 1020028..fa30c98 100644 --- a/app/admin/apis/erpordermanage/erp_order.go +++ b/app/admin/apis/erpordermanage/erp_order.go @@ -35,6 +35,8 @@ func ErpOrderCreate(c *gin.Context) { return } + tools.RoundFloatFields(req) + // 如果用户是会员,手机号不能为空 if req.MemberType == model.ErpOrderMemberTypeMember && req.Tel == "" { app.Error(c, http.StatusBadRequest, errors.New("参数错误:缺少会员手机号"), "参数错误:缺少会员手机号") diff --git a/app/admin/models/commodity.go b/app/admin/models/commodity.go index 8f265dc..f27a2fd 100644 --- a/app/admin/models/commodity.go +++ b/app/admin/models/commodity.go @@ -11,6 +11,7 @@ import ( "go-admin/tools/config" "golang.org/x/sync/errgroup" "gorm.io/gorm" + "math" "math/rand" "sort" "strconv" @@ -1232,13 +1233,13 @@ func (m *StockImporter) processErpStocks(erpStocks []ErpStockCommodity) error { }) } - err := m.ErpStockCountUpdate(begin) //更新or插入库存表 + err := errGroup.Wait() if err != nil { begin.Rollback() return err } - err = errGroup.Wait() + err = m.ErpStockCountUpdate(begin) //更新or插入库存表 if err != nil { begin.Rollback() return err @@ -1262,8 +1263,26 @@ func createStockList(begin *gorm.DB, stockList []ErpStockCommodity) error { return nil } +// 合并导入数据的辅助函数 +func mergeCensusMap(censusMap map[uint32]map[uint32]uint32) map[uint32]map[uint32]uint32 { + mergedMap := make(map[uint32]map[uint32]uint32) + for storeId, commodities := range censusMap { + if mergedMap[storeId] == nil { + mergedMap[storeId] = make(map[uint32]uint32) + } + for commodityId, count := range commodities { + mergedMap[storeId][commodityId] += count + } + } + return mergedMap +} + func (m *StockImporter) ErpStockCountUpdate(gdb *gorm.DB) error { - for k1, v1 := range m.CensusMap { + // 合并导入数据,避免同一商品多次重复处理 + mergedCensusMap := mergeCensusMap(m.CensusMap) + + //for k1, v1 := range m.CensusMap { + for k1, v1 := range mergedCensusMap { for k2, v2 := range v1 { exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d", k1, k2)) if err != nil { @@ -2440,8 +2459,8 @@ type ErpStockCommodityListResp struct { Total int `json:"total"` // 数据总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 - TotalWholesalePrice int `json:"total_wholesale_price"` // 入库采购价之和 - TotalStaffPrice int `json:"total_staff_price"` // 入库员工成本价之和 + TotalWholesalePrice float64 `json:"total_wholesale_price"` // 入库采购价之和 + TotalStaffPrice float64 `json:"total_staff_price"` // 入库员工成本价之和 ExportUrl string `json:"export_url"` } @@ -2550,8 +2569,8 @@ func (m *ErpStockCommodityListReq) GetDetailList(c *gin.Context, nType uint32) ( resp.Total = int(count) resp.PageIndex = page + 1 resp.PageSize = m.PageSize - resp.TotalWholesalePrice = int(nTotalCount.TotalWholesalePrice) - resp.TotalStaffPrice = int(nTotalCount.TotalStaffCostPrice + nTotalCount.TotalWholesalePrice) + resp.TotalWholesalePrice = math.Round(nTotalCount.TotalWholesalePrice*100) / 100 + resp.TotalStaffPrice = math.Round((nTotalCount.TotalStaffCostPrice+nTotalCount.TotalWholesalePrice)*100) / 100 return resp, nil } diff --git a/app/admin/models/erp_order.go b/app/admin/models/erp_order.go index 3c59f25..2516426 100644 --- a/app/admin/models/erp_order.go +++ b/app/admin/models/erp_order.go @@ -1497,9 +1497,25 @@ func mergeOrderCommodities(orderCommodities []ErpOrderCommodity) []ErpOrderCommo // 将map转换回orderCommodities列表 var mergedCommodities []ErpOrderCommodity for _, commodity := range commodityMap { + // 对float64类型的字段进行四舍五入处理 + commodity.SalesProfit = tools.RoundFloat(commodity.SalesProfit) + commodity.StaffProfit = tools.RoundFloat(commodity.StaffProfit) + commodity.SaleDiscount = tools.RoundFloat(commodity.SaleDiscount) + commodity.MemberDiscount = tools.RoundFloat(commodity.MemberDiscount) + commodity.ReceivedAmount = tools.RoundFloat(commodity.ReceivedAmount) + commodity.RejectedPrice = tools.RoundFloat(commodity.RejectedPrice) + commodity.RejectedAmount = tools.RoundFloat(commodity.RejectedAmount) + commodity.StaffCostPrice = tools.RoundFloat(commodity.StaffCostPrice) + commodity.WholesalePrice = tools.RoundFloat(commodity.WholesalePrice) + mergedCommodities = append(mergedCommodities, *commodity) } + // 对mergedCommodities按ErpCommodityId进行排序 + sort.Slice(mergedCommodities, func(i, j int) bool { + return mergedCommodities[i].ID < mergedCommodities[j].ID + }) + return mergedCommodities } @@ -4236,12 +4252,12 @@ func queryRetailDetailByJoin(req *ErpOrderRetailDetailReq, c *gin.Context) (*Erp // 退货订单支付汇总:目前零售退货订单暂时不展示各个方式的付款金额 var rejectedCashier TotalCashierData - //rejectedCashierQs := qs - //rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected) - //if err != nil { - // logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err)) - // return resp, err - //} + rejectedCashierQs := qs + rejectedCashier, err = getTotalCashierData(rejectedCashierQs, RetailTypeRejected) + if err != nil { + logger.Error("query erp_order_pay_way sum data err:", logger.Field("err", err)) + return resp, err + } // 计算销售订单和退货订单汇总后的支付数据 cashier = subtractCashierData(cashier, rejectedCashier) @@ -5056,6 +5072,8 @@ func CreateErpOrder(req *ErpOrderCreateReq, c *gin.Context) error { if err != nil { return err } + // 四舍五入 + tools.RoundFloatFields(req) begin := orm.Eloquent.Begin() if req.Tel != "" { @@ -5436,8 +5454,8 @@ func checkOrderData(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) { req.ErpOrderCommodities[i].MemberDiscount = req.ErpOrderCommodities[i].MemberDiscount / float64(req.ErpOrderCommodities[i].Count) // 单个商品实收金额 req.ErpOrderCommodities[i].ReceivedAmount = req.ErpOrderCommodities[i].ReceivedAmount / float64(req.ErpOrderCommodities[i].Count) - // 单个商品退货金额 - req.ErpOrderCommodities[i].RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].Count) + //// 单个商品退货金额 + //req.ErpOrderCommodities[i].RejectedAmount = req.ErpOrderCommodities[i].RejectedAmount / float64(req.ErpOrderCommodities[i].Count) for j := 0; j < int(req.ErpOrderCommodities[i].Count); j++ { stockIdList, _ := stringToIntArray(req.ErpOrderCommodities[i].ErpStockCommodityID) @@ -5560,6 +5578,7 @@ func checkOrderData(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) { } req.ErpOrderCommodities = respErpOrderCommodities + tools.RoundFloatFields(erpOrder) // 判断线上支付金额是否>0 if req.RetailType == RetailTypeSale { @@ -5606,7 +5625,7 @@ func checkOrderData(req *ErpOrderCreateReq, c *gin.Context) (*ErpOrder, error) { // 订单总优惠 if req.RetailType == RetailTypeSale { - erpOrder.TotalDiscount = erpOrder.TotalRetailPrice - erpOrder.TotalAmount + erpOrder.TotalDiscount = math.Round((erpOrder.TotalRetailPrice-erpOrder.TotalAmount)*100) / 100 } return erpOrder, nil diff --git a/app/admin/models/inventory_allot.go b/app/admin/models/inventory_allot.go index 7c7641d..b343f36 100644 --- a/app/admin/models/inventory_allot.go +++ b/app/admin/models/inventory_allot.go @@ -786,6 +786,33 @@ func MergeCommodities(commodities []ErpInventoryAllotCommodity) []ErpInventoryAl return mergedCommodities } +// MergeAllCommodities 遍历库存调拨商品信息,将商品id相同的所有商品进行合并,数量累加即可 +func MergeAllCommodities(commodities []ErpInventoryAllotCommodity) []ErpInventoryAllotCommodity { + // 用于存储合并后的商品信息 + mergedCommodities := make([]ErpInventoryAllotCommodity, 0) + // 用于记录无串码商品的合并信息 + commodityMap := make(map[uint32]*ErpInventoryAllotCommodity) + + for _, commodity := range commodities { + if existing, found := commodityMap[commodity.CommodityId]; found { + // 如果相同商品 ID 的无串码商品已存在,则数量累加 + existing.Count += commodity.Count + commodityMap[commodity.CommodityId] = existing + } else { + // 否则,加入到 commodityMap 中 + newCommodity := commodity + commodityMap[commodity.CommodityId] = &newCommodity + } + } + + // 将合并后的无串码商品加入到合并后的列表中 + for _, commodity := range commodityMap { + mergedCommodities = append(mergedCommodities, *commodity) + } + + return mergedCommodities +} + // MergeChangeCommodities 遍历库存变动商品信息,将商品id相同的非串码商品进行合并,数量累加即可 func MergeChangeCommodities(commodities []ErpInventoryChangeCommodity) []ErpInventoryChangeCommodity { // 用于存储合并后的商品信息 @@ -1043,13 +1070,15 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error // 遍历库存调拨商品信息 for _, v := range trimCommodities { var stockCommodity []ErpStockCommodity - err := orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+ + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+ "AND state = ? AND imei = ?", v.CommodityId, inventoryAllotOrder.DeliverStoreId, InAllot, v.IMEI). Find(&stockCommodity).Error if err != nil { + begin.Rollback() return fmt.Errorf("查询商品库存失败:[%s]", err.Error()) } if len(stockCommodity) == 0 { + begin.Rollback() return fmt.Errorf("未找到商品库存信息") } @@ -1059,18 +1088,37 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error stockCommodity[i].StoreName = inventoryAllotOrder.ReceiveStoreName stockCommodity[i].State = InStock stockCommodity[i].StockTime = time.Now() - err = begin.Model(&ErpStockCommodity{}).Where("id = ?", stockCommodity[i].ID). - Updates(stockCommodity[i]).Error + err = begin.Where("id", stockCommodity[i].ID).Omit("created_at").Save(&stockCommodity[i]).Error + //err = begin.Model(&ErpStockCommodity{}).Where("id = ?", stockCommodity[i].ID). + // Updates(stockCommodity[i]).Error if err != nil { begin.Rollback() return fmt.Errorf("更新商品库存失败:%s", err.Error()) } } + } + + // 遍历库存调拨商品信息,将商品id相同的非串码商品进行合并,数量累加即可 + trimAllCommodities := MergeAllCommodities(trimCommodities) + for _, v := range trimAllCommodities { + var stockCommodity []ErpStockCommodity + err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? AND store_id = ? "+ + "AND state = ? AND imei = ?", v.CommodityId, inventoryAllotOrder.DeliverStoreId, InAllot, v.IMEI). + Find(&stockCommodity).Error + if err != nil { + begin.Rollback() + return fmt.Errorf("查询商品库存失败:[%s]", err.Error()) + } + if len(stockCommodity) == 0 { + begin.Rollback() + return fmt.Errorf("未找到商品库存信息") + } // 更新调入门店的库存数量 exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_stock WHERE store_id=%d AND erp_commodity_id=%d", inventoryAllotOrder.ReceiveStoreId, v.CommodityId)) if err != nil { + begin.Rollback() logger.Errorf("exist err:", err) return err } @@ -1101,6 +1149,7 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error } err = begin.Create(stock).Error if err != nil { + begin.Rollback() logger.Errorf("create stock err:", err) return err } @@ -1121,6 +1170,7 @@ func ReceiveAllotInventory(req *InventoryAllotReceiveReq, c *gin.Context) error "UPDATE erp_stock SET dispatch_count = dispatch_count-%d WHERE store_id=%d AND erp_commodity_id=%d", v.Count, inventoryAllotOrder.DeliverStoreId, v.CommodityId)).Error if err != nil { + begin.Rollback() logger.Errorf("update stock err:", err) return err } diff --git a/app/admin/models/purchase.go b/app/admin/models/purchase.go index 7c30889..96c4d0c 100644 --- a/app/admin/models/purchase.go +++ b/app/admin/models/purchase.go @@ -4343,10 +4343,10 @@ func getReportByCommodityFromCommon(req *ErpPurchaseReportByCommodityReq, c *gin } resp.PlanCount = totalData.PlanCount - resp.PlanAmount = totalData.PlanAmount - resp.Amount = totalData.Amount + resp.PlanAmount = math.Round(totalData.PlanAmount*100) / 100 + resp.Amount = math.Round(totalData.Amount*100) / 100 resp.Count = totalData.Count - resp.NonExecutionAmount = totalData.NonExecutionAmount + resp.NonExecutionAmount = math.Round(totalData.NonExecutionAmount*100) / 100 resp.NonExecutionCount = totalData.NonExecutionCount if req.IsExport == 1 { @@ -4434,8 +4434,10 @@ func getPurchaseOrderAndCommodityData(orderID, commodityId uint32) (ErpCommodity purchaseOrderData.Amount = purchaseData.Amount purchaseOrderData.Price = purchaseData.Price purchaseOrderData.Count = purchaseData.Count - purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount - purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount + if purchaseOrder.State != ErpPurchaseOrderEnd { + purchaseOrderData.NonExecutionAmount = purchaseData.NonExecutionAmount + purchaseOrderData.NonExecutionCount = purchaseData.NonExecutionCount + } return purchaseOrderData, commodityData, nil } diff --git a/tools/utils.go b/tools/utils.go index a39cd96..dc7fa11 100644 --- a/tools/utils.go +++ b/tools/utils.go @@ -6,6 +6,7 @@ import ( "gorm.io/gorm" "log" "math" + "reflect" "runtime" "strconv" "time" @@ -134,3 +135,32 @@ func StringSliceContains(slice []string, val string) bool { } return false } + +// RoundFloat 保留 float64 两位小数 +func RoundFloat(f float64) float64 { + return math.Round(f*100) / 100 +} + +// RoundFloatFields 递归处理结构体中的 float64 字段,四舍五入保留两位小数 +func RoundFloatFields(v interface{}) { + val := reflect.ValueOf(v).Elem() + + for i := 0; i < val.NumField(); i++ { + field := val.Field(i) + switch field.Kind() { + case reflect.Float64: + // 对 float64 类型进行四舍五入 + field.SetFloat(RoundFloat(field.Float())) + case reflect.Struct: + // 递归处理子结构体 + RoundFloatFields(field.Addr().Interface()) + case reflect.Slice: + // 对于 slice 中的结构体,逐个处理 + for j := 0; j < field.Len(); j++ { + if field.Index(j).Kind() == reflect.Struct { + RoundFloatFields(field.Index(j).Addr().Interface()) + } + } + } + } +}