package model import ( "fmt" "github.com/codinl/go-logger" "github.com/jinzhu/gorm" "math/rand" "time" ) const ( ErpOrderStateAudited = "audited" // 已审核 HavePaid = 2 // 已支付 NoPrint = 1 // 未打印 RetailTypeSale = "sale" // 零售销售订单 SysUserIdByAdmin = 1 // 系统管理员id SysUserNameByAdmin = "系统管理员" // 系统管理员名称 SoldOut = 2 // 已售 ) // ErpStock 库存列表 type ErpStock struct { Model StoreId uint32 `json:"store_id" gorm:"index"` // 门店编号 StoreName string `json:"store_name"` // 门店名称 ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id ErpCategoryName string `json:"erp_category_name"` // 分类名称 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编码/串码 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加) RetailPrice float64 `json:"retail_price"` // 指导零售价 MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价 Count uint32 `json:"count"` // 数量 DispatchCount uint32 `json:"dispatch_count"` // 调拨中数量(调拨中调入) DecisionStoreId []uint32 `json:"decision_store_id" gorm:"-"` // 门店编号列表(查询进销存的时候使用) Commodities []ErpStockCommodity `json:"commodities" gorm:"-"` // } // ErpStockCommodity 库存详情 type ErpStockCommodity struct { Model ErpStockId uint32 `json:"erp_stock_id" gorm:"index"` // 库存id StoreId uint32 `json:"store_id" gorm:"index"` // 门店id StoreName string `json:"store_name"` // 门店名称 ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"index"` // 商品编号 ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id ErpCategoryName string `json:"erp_category_name"` // 分类名称 ErpBarcode string `json:"erp_barcode"` // 商品条码 IMEIType uint32 `json:"imei_type"` // 是否串码:1-无串码 2-串码(系统生成) 3-串码(手动添加) IMEI string `json:"imei"` // 商品串码 ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 供应商id ErpSupplierName string `json:"erp_supplier_name"` // 供应商名称 StockTime time.Time `json:"stock_time"` // 最近入库时间 RetailPrice float64 `json:"retail_price"` // 指导零售价 MinRetailPrice float64 `json:"min_retail_price"` // 最低零售价 StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice float64 `json:"wholesale_price"` // 指导采购价 MemberDiscount float64 `json:"member_discount"` // 会员优惠 State uint32 `json:"state"` // 状态:1-在库 2-已售 3-采购退货 4-调拨中 5-销售锁定中 6-产品出库 7-盘点出库 Count uint32 `json:"count"` // 数量 StorageType uint32 `json:"storage_type"` // 入库方式:1-系统入库 2-采购入库 3-产品入库 4-盘点入库 FirstStockTime time.Time `json:"first_stock_time"` // 首次入库时间 StockSn string `json:"stock_sn"` // 库存订单编号(跟采购入库的入库编号关联) OriginalSn string `json:"original_sn" gorm:"index"` // 首次入库订单编号(单据编号) StockStartTime time.Time `json:"stock_start_time" gorm:"-"` // 最近入库开始时间 StockEndTime time.Time `json:"stock_end_time" gorm:"-"` // 最近入库结束时间 Age uint32 `json:"age" gorm:"-"` // 最近库龄 AllAge uint32 `json:"all_age" gorm:"-"` // 总库龄 Remark string `json:"remark"` // 备注 CategoryNumber string `json:"category_number" gorm:"-"` // 商品分类编号 } // ErpCommodity 商品表 type ErpCommodity struct { Model SerialNumber string `json:"serial_number"` // 商品编号 Number uint32 `json:"number"` // 商品数量 Name string `json:"name"` // 商品名称 ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 商品分类id ErpCategoryName string `json:"erp_category_name"` // 商品分类名称 ErpBarcode string `json:"erp_barcode"` // 商品条码 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码(系统生成) 3-串码(手动添加) IMEI string `json:"imei"` // 串码 ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 主供应商id ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称 RetailPrice uint32 `json:"retail_price"` // 指导零售价 MinRetailPrice uint32 `json:"min_retail_price"` // 最低零售价 StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 Brokerage1 float64 `json:"brokerage_1"` // 销售毛利提成 Brokerage2 float64 `json:"brokerage_2"` // 员工毛利提成 MemberDiscount float64 `json:"member_discount"` // 会员优惠 Origin string `json:"origin"` // 产地 Remark string `json:"remark" gorm:"type:varchar(512)"` // 备注 Img string `json:"img"` // 图片 StopPurchase uint32 `json:"stop_purchase"` // 0-未勾选,正常采购;1-勾选,停止采购 ManufacturerCode string `json:"manufacturer_code"` // 厂家编码 IsSyncedToMall uint32 `json:"is_synced_to_mall"` // 是否同步到小程序商城:0-否;1-是 GoodsId uint32 `json:"goods_id"` // 小程序商城-商品ID SaleStatus uint32 `json:"sale_status"` // 小程序商城-在售状态 1-在售 2-下架 ErpCategory *ErpCategory `json:"erp_category" gorm:"-"` } // ErpCategory 商品分类 type ErpCategory struct { Model Name string `json:"name"` // 名称 Priority string `json:"priority"` // 分类 Number uint32 `json:"number"` // FullNum uint32 `json:"full_num"` // State uint32 `json:"state"` // 1-未使用 2-使用 3-隐藏 Level uint32 `json:"level"` // 分类层级 Pid uint32 `json:"pid" gorm:"index"` // Sort uint32 `json:"sort"` // SubCats []ErpCategory `json:"sub_cats" gorm:"-"` // 子列表 } // ErpOrder 零售订单表 type ErpOrder struct { Model BillSn string `json:"bill_sn" gorm:"index"` // 单据编号 RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 GoodsOrderId uint32 `json:"goods_order_id" gorm:"index"` // 小程序商城订单id Uid int `json:"uid"` // 用户id UserType int `json:"user_type"` // 会员类别:1-普通会员 2-黄金会员 4-白金会员 5-黑金会员 6-尊享会员 7-黄金&尊享 8-白金&尊享 9-黑金&尊享 Tel string `json:"tel" gorm:"index"` // 客户手机号 StoreId uint32 `json:"store_id" gorm:"index"` // 门店id StoreName string `json:"store_name"` // 门店名称 MakerId uint32 `json:"maker_id" gorm:"index"` // 制单人id MakerName string `json:"maker_name"` // 制单人名称 MakerTime time.Time `json:"maker_time"` // 制单时间 AuditorId uint32 `json:"auditor_id" gorm:"index"` // 审核人id AuditorName string `json:"auditor_name"` // 审核人姓名 AuditTime *time.Time `json:"audit_time"` // 审核时间 CashierList string `json:"cashier_list" gorm:"type:text"` // 付款方式,存储json数据 SalesmanList string `json:"salesman_list" gorm:"type:text"` // 销售员信息,存储json数据 MemberType string `json:"member_type"` // 会员类型:general 普通; member 会员 State string `json:"state" gorm:"index"` // 订单状态:un_audit 待审核; audited 已审核 TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价 TotalAmount float64 `json:"total_amount"` // 订单实收金额 TotalCount int32 `json:"total_count"` // 订单商品数量 TotalSalesProfit float64 `json:"total_sales_profit"` // 订单总销售毛利 TotalStaffProfit float64 `json:"total_staff_profit"` // 订单总员工毛利 VmCount uint32 `json:"vm_count"` // 使用会员积分 SaleOrderId uint32 `json:"sale_order_id"` // 销售订单id PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 ;1-待支付; 2-已支付 IsPrint uint32 `json:"is_print"` // 是否打印小票 1-未打印 2-已打印 PrintCount uint32 `json:"print_count"` // 小票打印次数 InvoiceCode string `json:"invoice_code"` // 发票代码 InvoiceNumber string `json:"invoice_number"` // 发票编码 RejectedTotalAmount float64 `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额 RejectedTotalCount uint32 `json:"rejected_total_count" gorm:"-"` // 订单总退货数量 StorePer float64 `json:"store_per"` // 门店提成:订单总员工毛利X该门店设置好的提成比例,保留到小数后两位多余舍去 TotalDiscount float64 `json:"total_discount"` // 订单总优惠:订单所有商品零售优惠+会员优惠+会员积分抵扣之和 BankTrxNo string `json:"bank_trx_no" gorm:"-"` // 银行流水号 Commodities []ErpOrderCommodity `json:"commodities" gorm:"-"` // 零售订单商品信息 Cashiers []ErpOrderCashier `json:"cashiers" gorm:"-"` // 收付款方式 Salesman []ErpOrderSales `json:"salesman" gorm:"-"` // 销售员信息 } // ErpOrderSales 销售员信息 type ErpOrderSales struct { Model ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id(后端生成) Uid uint32 `json:"userId" binding:"required"` // 销售员用户ID(20240322:更换为系统用户表主键id) Name string `json:"name"` // 销售员用户姓名 SalesProfitPer float64 `json:"sales_profit_per"` // 销售毛利提成:每个商品销售毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去 StaffProfitPer float64 `json:"staff_profit_per"` // 员工毛利提成:每个商品员工毛利X其对应的提成比例后求和;如果是两个销售员参与则分别除以2 ,保留到小数后两位多余舍去 SalesmanPer float64 `json:"salesman_per"` // 销售员提成:订单总员工毛利X该销售员设置好的提成比例;如果是两个销售员参与,那么两个人算出的提成均除以2,保留到小数后两位多余舍去 } // ErpOrderCashier 订单收款方式 type ErpOrderCashier struct { CashierId uint32 `json:"cashier_id"` // 收付款方式id Name string `json:"name"` // 收付款方式名称 Amount float64 `json:"amount"` // 金额 } // ErpOrderCommodity 零售订单商品表 type ErpOrderCommodity struct { Model ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id(后端生成) ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id ErpCategoryName string `json:"erp_category_name"` // 分类名称 ErpCommodityId uint32 `json:"erp_commodity_id" gorm:"index"` // 商品id ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 ErpSupplierId uint32 `json:"erp_supplier_id" gorm:"index"` // 主供应商id ErpSupplierName string `json:"erp_supplier_name"` // 主供应商名称 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei" gorm:"index"` // 串码 PresentType uint32 `json:"present_type"` // 赠送类型:1-非赠送 2-赠送 RetailPrice float64 `json:"retail_price"` // 指导零售价 SalePrice float64 `json:"sale_price"` // 零售价 Count int32 `json:"count"` // 销售数量 SaleDiscount float64 `json:"sale_discount"` // 零售优惠 MemberDiscount float64 `json:"member_discount"` // 会员优惠 VmDiscount float64 `json:"vm_discount"` // 会员积分抵扣 CouponID uint32 `json:"coupon_id"` // 优惠券ID CouponDiscount float64 `json:"coupon_discount"` // 优惠券抵扣 CouponCode string `json:"coupon_code"` // 优惠券券码 CouponName string `json:"coupon_name"` // 优惠券名称 Amount float64 `json:"amount"` // 实际零售价 ReceivedAmount float64 `json:"received_amount"` // 商品实收金额 Remark string `json:"remark"` // 销售备注 RejectedRemark string `json:"rejected_remark"` // 退货备注 RejectedPrice float64 `json:"rejected_price"` // 退货单价 RejectedCount uint32 `json:"rejected_count"` // 退货数量 RejectedAmount float64 `json:"rejected_amount"` // 退货金额 RejectedOrderCommodityId uint32 `json:"rejected_order_commodity_id"` // 退货订单商品id StaffCostPrice float64 `json:"staff_cost_price"` // 员工成本价加价(如:加价50,不是加价后的价格) WholesalePrice float64 `json:"wholesale_price"` // 指导采购价 SalesProfit float64 `json:"sales_profit"` // 销售毛利:实际零售价-采购单价;如果为退货订单,则为实际退货价-采购单价 StaffProfit float64 `json:"staff_profit"` // 员工毛利:实际零售价-员工成本价;如果为退货订单,则为实际退货价-员工成本价 ErpStockCommodityID string `json:"erp_stock_commodity_id"` // 库存商品表主键id StaffPrice float64 `json:"staff_price" gorm:"-"` // 员工成本价 CommoditySerialNumber string `json:"commodity_serial_number" gorm:"-"` // 商品编号 CategoryNumber string `json:"category_number" gorm:"-"` // 商品分类编号 } // NewErpBillSn 生成零售订单号 func NewErpBillSn() string { nowTime := time.Now() rand.Seed(nowTime.UnixNano()) max := 1 for { if max > 5 { logger.Error("create sn err") return "" } random := rand.Int31n(9999) + 1000 sn := fmt.Sprintf("%s%d", nowTime.Format("060102"), random) exist, err := QueryRecordExist(fmt.Sprintf("SELECT * FROM erp_order WHERE bill_sn='%s'", sn)) if err != nil { logger.Error("exist sn err") } if !exist { return sn } max++ } } // SelectDeliveryStock 选择发货库存 // commodityId: 商品ID // storeId: 指定门店ID(0 表示不指定) // return: 选中的库存记录 func SelectDeliveryStock(commodityId, storeId uint32) (*ErpStockCommodity, error) { // 先校验门店 if storeId == 0 { return nil, fmt.Errorf("无法确定最近门店,请先设置 NearestStoreId") } var stock ErpStockCommodity // 1️⃣ 优先指定门店 err := DB.Table("erp_stock_commodity"). Where("erp_commodity_id = ? AND store_id = ? AND state = 1 AND count > 0", commodityId, storeId). Order("first_stock_time ASC"). First(&stock).Error if err == nil { return &stock, nil } // 2️⃣ 如果指定门店无库存,则报错(不允许跨门店) return nil, fmt.Errorf("商品 %d 在门店 %d 无可用库存", commodityId, storeId) } //func SelectDeliveryStock(commodityId, storeId uint32) (*ErpStockCommodity, error) { // var stock ErpStockCommodity // // // 1️⃣ 优先指定门店 // if storeId > 0 { // err := DB.Table("erp_stock_commodity"). // Where("erp_commodity_id = ? AND store_id = ? AND state = 1 AND count > 0", commodityId, storeId). // Order("first_stock_time ASC"). // First(&stock).Error // if err == nil { // return &stock, nil // } // } // // // 2️⃣ 其他门店,优先库龄最久 // var otherStocks []ErpStockCommodity // err := DB.Table("erp_stock_commodity"). // Where("erp_commodity_id = ? AND state = 1 AND count > 0", commodityId). // Order("first_stock_time ASC"). // Find(&otherStocks).Error // if err != nil { // return nil, err // } // if len(otherStocks) == 0 { // return nil, fmt.Errorf("无可用库存") // } // // // 3️⃣ 多个相同库龄,随机一个 // oldestTime := otherStocks[0].FirstStockTime // var oldestStocks []ErpStockCommodity // for _, s := range otherStocks { // if s.FirstStockTime.Equal(oldestTime) { // oldestStocks = append(oldestStocks, s) // } else { // break // } // } // // rand.Seed(time.Now().UnixNano()) // chosen := oldestStocks[rand.Intn(len(oldestStocks))] // return &chosen, nil //} //// CreateErpOrder 根据小程序订单生成ERP零售订单 //func CreateErpOrder(goodsOrder *GoodsOrder, goods *Goods) error { // logger.Infof("enter CreateErpOrder") // logger.Infof("goods: %+v", goods) // logger.Infof("goodsOrder: %+v", goodsOrder) // tx := DB.Begin() // if tx.Error != nil { // return tx.Error // } // // defer func() { // if r := recover(); r != nil { // logger.Errorf("事务 panic 回滚: %v", r) // tx.Rollback() // } // }() // // // 1. 查找用户信息 // var user User // if err := tx.Where("uid = ?", goodsOrder.Uid).First(&user).Error; err != nil { // logger.Infof("用户 %d 不存在", goodsOrder.Uid) // return fmt.Errorf("用户不存在: %w", err) // } // // var orderCommodities []ErpOrderCommodity // var totalAmount, totalRetailPrice, totalSalesProfit, totalStaffProfit float64 // var totalCount int32 // // // 遍历小程序订单的商品明细 // // 选择库存:优先指定门店 → 其他门店库龄最久 // stock, err := SelectDeliveryStock(goods.ErpCommodityId, goodsOrder.NearestStoreId) // if err != nil { // tx.Rollback() // logger.Infof("商品 %d 无库存: %v", goods.ErpCommodityId, err) // return fmt.Errorf("商品 %d 无库存: %v", goods.ErpCommodityId, err) // } // logger.Infof("stock: %+v", stock) // // // 扣减库存 // err = tx.Table("erp_stock_commodity").Where("id = ?", stock.ID). // Updates(map[string]interface{}{ // "state": SoldOut, // "updated_at": time.Now(), // }).Error // 状态更新为已销售 // if err != nil { // logger.Error("update erp_stock_commodity err:", err) // tx.Rollback() // return fmt.Errorf("库存扣减失败: %v", err) // } // // err = tx.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ? AND count > 0", // stock.StoreId, stock.ErpCommodityId). // Updates(map[string]interface{}{ // "count": gorm.Expr("count - ?", 1), // "updated_at": time.Now(), // }).Error // 库存数量-1 // if err != nil { // logger.Error("update erp_stock err:", err) // tx.Rollback() // return fmt.Errorf("库存不足") // } // // // 金额计算 // receivedAmount := float64(goodsOrder.Quantity) * float64(goods.PriceRm/100) // salesProfit := receivedAmount - stock.WholesalePrice*float64(goodsOrder.Quantity) // staffProfit := receivedAmount - (stock.WholesalePrice+stock.StaffCostPrice)*float64(goodsOrder.Quantity) // // orderCommodities = append(orderCommodities, ErpOrderCommodity{ // ErpCategoryId: stock.ErpCategoryId, // ErpCategoryName: stock.ErpCategoryName, // ErpCommodityId: stock.ErpCommodityId, // ErpCommodityName: stock.ErpCommodityName, // ErpSupplierId: stock.ErpSupplierId, // ErpSupplierName: stock.ErpSupplierName, // IMEIType: stock.IMEIType, // IMEI: "", // PresentType: 1, // RetailPrice: stock.RetailPrice, // SalePrice: float64(goods.PriceRm / 100), // Count: int32(goodsOrder.Quantity), // Amount: receivedAmount, // ReceivedAmount: receivedAmount, // StaffCostPrice: stock.StaffCostPrice, // WholesalePrice: stock.WholesalePrice, // SalesProfit: salesProfit, // StaffProfit: staffProfit, // ErpStockCommodityID: fmt.Sprintf("%d", stock.ID), // }) // logger.Infof("orderCommodities 长度: %d", len(orderCommodities)) // // totalAmount += receivedAmount // totalRetailPrice += stock.RetailPrice * float64(goodsOrder.Quantity) // totalSalesProfit += salesProfit // totalStaffProfit += staffProfit // totalCount += int32(goodsOrder.Quantity) // // nowTime := time.Now() // // ERP订单 // order := ErpOrder{ // BillSn: NewErpBillSn(), // GoodsOrderId: goodsOrder.OrderId, // RetailType: RetailTypeSale, // Uid: int(goodsOrder.Uid), // UserType: int(user.MemberLevel), // Tel: user.Tel, // StoreId: stock.StoreId, // StoreName: stock.StoreName, // MakerId: SysUserIdByAdmin, // MakerName: SysUserNameByAdmin, // MakerTime: nowTime, // AuditorId: SysUserIdByAdmin, // AuditorName: SysUserNameByAdmin, // AuditTime: &nowTime, // State: ErpOrderStateAudited, // TotalRetailPrice: totalRetailPrice, // TotalAmount: totalAmount, // TotalCount: totalCount, // TotalSalesProfit: totalSalesProfit, // TotalStaffProfit: totalStaffProfit, // PayStatus: HavePaid, // 已支付 // IsPrint: NoPrint, // 未打印 // PrintCount: 0, // } // // if err = tx.Create(&order).Error; err != nil { // logger.Infof("新建erp零售订单失败: %v", err) // tx.Rollback() // return fmt.Errorf("新建erp零售订单失败: %v", err) // } // // // 绑定订单ID // for i := range orderCommodities { // orderCommodities[i].ErpOrderId = order.ID // if err = tx.Create(&orderCommodities[i]).Error; err != nil { // logger.Errorf("新建erp零售订单商品信息失败: %v", err) // tx.Rollback() // return fmt.Errorf("新建erp零售订单商品信息失败: %v", err) // } // } // // if err = tx.Commit().Error; err != nil { // logger.Infof("提交事务失败: %v", err) // return fmt.Errorf("提交事务失败: %v", err) // } // // logger.Infof("leave CreateErpOrder") // return nil //} // CreateErpOrder 根据小程序订单生成ERP零售订单(支持多商品) func CreateErpOrder(goodsOrder *GoodsOrder, commodities []GoodsOrderCommodity) error { logger.Infof("enter CreateErpOrder") tx := DB.Begin() if tx.Error != nil { return tx.Error } defer func() { if r := recover(); r != nil { logger.Errorf("事务 panic 回滚: %v", r) tx.Rollback() } }() // 1. 查找用户信息 var user User if err := tx.Where("uid = ?", goodsOrder.Uid).First(&user).Error; err != nil { logger.Infof("用户 %d 不存在", goodsOrder.Uid) return fmt.Errorf("用户不存在: %w", err) } var orderCommodities []ErpOrderCommodity var totalAmount, totalRetailPrice, totalSalesProfit, totalStaffProfit float64 var totalCount int32 for _, commodity := range commodities { var goods Goods err := NewGoodsQuerySet(tx).GoodsIdEq(commodity.GoodsId).One(&goods) if err != nil { logger.Errorf("商品不存在: %d, err: %v", commodity.GoodsId, err) tx.Rollback() return err } // 选择库存 stock, err := SelectDeliveryStock(goods.ErpCommodityId, goodsOrder.NearestStoreId) if err != nil { tx.Rollback() logger.Infof("商品 %d 无库存: %v", goods.ErpCommodityId, err) return fmt.Errorf("商品 %d 无库存: %v", goods.ErpCommodityId, err) } // 扣减库存 err = tx.Table("erp_stock_commodity").Where("id = ?", stock.ID). Updates(map[string]interface{}{"state": SoldOut, "updated_at": time.Now()}).Error if err != nil { tx.Rollback() return fmt.Errorf("erp_stock_commodity 扣减库存失败: %v", err) } err = tx.Table("erp_stock").Where("store_id = ? AND erp_commodity_id = ? AND count > 0", stock.StoreId, stock.ErpCommodityId).Updates(map[string]interface{}{ "count": gorm.Expr("count - ?", commodity.Quantity), "updated_at": time.Now(), }).Error if err != nil { tx.Rollback() return fmt.Errorf("erp_stock 扣减库存失败: %v", err) } // 金额计算 receivedAmount := float64(commodity.Quantity) * float64(goods.PriceRm/100) salesProfit := receivedAmount - stock.WholesalePrice*float64(commodity.Quantity) staffProfit := receivedAmount - (stock.WholesalePrice+stock.StaffCostPrice)*float64(commodity.Quantity) orderCommodities = append(orderCommodities, ErpOrderCommodity{ ErpCategoryId: stock.ErpCategoryId, ErpCategoryName: stock.ErpCategoryName, ErpCommodityId: stock.ErpCommodityId, ErpCommodityName: stock.ErpCommodityName, ErpSupplierId: stock.ErpSupplierId, ErpSupplierName: stock.ErpSupplierName, IMEIType: stock.IMEIType, IMEI: "", PresentType: 1, RetailPrice: stock.RetailPrice, SalePrice: float64(goods.PriceRm / 100), Count: int32(commodity.Quantity), Amount: receivedAmount, ReceivedAmount: receivedAmount, StaffCostPrice: stock.StaffCostPrice, WholesalePrice: stock.WholesalePrice, SalesProfit: salesProfit, StaffProfit: staffProfit, ErpStockCommodityID: fmt.Sprintf("%d", stock.ID), }) totalAmount += receivedAmount totalRetailPrice += stock.RetailPrice * float64(commodity.Quantity) totalSalesProfit += salesProfit totalStaffProfit += staffProfit totalCount += int32(commodity.Quantity) } // 创建ERP订单 nowTime := time.Now() order := ErpOrder{ BillSn: NewErpBillSn(), GoodsOrderId: goodsOrder.OrderId, RetailType: RetailTypeSale, Uid: int(goodsOrder.Uid), UserType: int(user.MemberLevel), Tel: user.Tel, StoreId: goodsOrder.NearestStoreId, StoreName: goodsOrder.NearestStoreName, MakerId: SysUserIdByAdmin, MakerName: SysUserNameByAdmin, MakerTime: nowTime, AuditorId: SysUserIdByAdmin, AuditorName: SysUserNameByAdmin, AuditTime: &nowTime, State: ErpOrderStateAudited, TotalRetailPrice: totalRetailPrice, TotalAmount: totalAmount, TotalCount: totalCount, TotalSalesProfit: totalSalesProfit, TotalStaffProfit: totalStaffProfit, PayStatus: HavePaid, IsPrint: NoPrint, PrintCount: 0, } if err := tx.Create(&order).Error; err != nil { tx.Rollback() return fmt.Errorf("创建ERP订单失败: %v", err) } // 绑定商品明细 for i := range orderCommodities { orderCommodities[i].ErpOrderId = order.ID if err := tx.Create(&orderCommodities[i]).Error; err != nil { tx.Rollback() return fmt.Errorf("创建ERP商品明细失败: %v", err) } } if err := tx.Commit().Error; err != nil { return fmt.Errorf("提交事务失败: %v", err) } logger.Infof("leave CreateErpOrder") return nil }