package models import ( "encoding/json" "errors" "fmt" "github.com/xuri/excelize/v2" "go-admin/app/admin/apis/pay" orm "go-admin/common/global" "go-admin/logger" "go-admin/tools/config" "gorm.io/gorm" "math/rand" "strconv" "strings" "time" ) const ( ErpOrderStateUnAudit = "un_audit" // 未审核 ErpOrderStateAudited = "audited" // 已审核 ErpOrderMemberTypeGeneral = "general" // 普通 ErpOrderMemberTypeMember = "member" // 会员 RetailTypeSale = "sale" // 零售订单 RetailTypeRejected = "rejected" // 零售退货订单 NoCreatePayOrder = 0 // 未创建 WaitForPaying = 1 // 待支付 HavePaid = 2 // 已支付 NoPrint = 1 // 未打印 HavePrinted = 2 // 已打印 OnlinePay = 1 // 线上支付(微信/支付宝/云闪付扫码) NoPayOrder = "no_pay_order" PayInit = "pay_init" Paying = "paying" PayOk = "pay_ok" PayFailed = "pay_failed" PayUnknown = "pay_unknown" ) type ErpOrder struct { Model BillSn string `json:"bill_sn" gorm:"index"` // 单据编号 RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 Uid int `json:"uid"` // 用户id 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数据 Salesman1 uint32 `json:"salesman_1"` // 销售员一用户ID SalesmanName1 string `json:"salesman_Name1"` // 销售员一用户姓名 Salesman2 uint32 `json:"salesman_2"` // 销售员二用户ID SalesmanName2 string `json:"salesman_Name2"` // 销售员二用户姓名 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 uint32 `json:"total_count"` // 订单商品数量 SalesProfit float64 `json:"sales_profit"` // 销售毛利 StaffProfit float64 `json:"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 uint32 `json:"invoice_code"` // 发票代码 InvoiceNumber uint32 `json:"invoice_number"` // 发票编码 RejectedTotalAmount float64 `json:"rejected_total_amount" gorm:"-"` // 订单总退货金额 RejectedTotalCount uint32 `json:"rejected_total_count" gorm:"-"` // 订单总退货数量 Commodities []ErpOrderCommodity `json:"commodities" gorm:"-"` // 零售订单商品信息 Cashiers []ErpOrderCashier `json:"cashiers" gorm:"-"` // 收付款方式 } 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"` // 商品名称 IMEIType uint32 `json:"imei_type"` // 1-无串码 2-串码 IMEI string `json:"imei" gorm:"index"` // 串码 PresentType uint32 `json:"present_type"` // 赠送类型:1-非赠送 2-赠送 RetailPrice uint32 `json:"retail_price"` // 指导零售价 SalePrice uint32 `json:"sale_price"` // 零售价 Count uint32 `json:"count"` // 销售数量 SaleDiscount float64 `json:"sale_discount"` // 零售优惠 MemberDiscount float64 `json:"member_discount"` // 会员优惠 VmDiscount float64 `json:"vm_discount"` // 会员积分抵扣 Amount float64 `json:"amount"` // 实际零售价 TotalAmount float64 `json:"total_amount"` // 商品实收金额 Remark string `json:"remark"` // 备注 Tel string `json:"tel" gorm:"index"` // 手机号 RejectedPrice float64 `json:"rejected_price"` // 退货单价 RejectedCount uint32 `json:"rejected_count"` // 退货数量 RejectedAmount float64 `json:"rejected_amount"` // 退货金额 RejectedOrderCommodityId uint32 `json:"rejected_order_commodity_id"` // 退货订单商品id StaffCostPrice uint32 `json:"staff_cost_price"` // 员工成本价加价 WholesalePrice uint32 `json:"wholesale_price"` // 指导采购价 } type ErpOrderCashier struct { CashierId uint32 `json:"cashier_id"` // 收付款方式id Name string `json:"name"` // 收付款方式名称 Amount float64 `json:"amount"` // 金额 } type ErpOrderRecord struct { Model ErpOrderId uint32 `json:"erp_order_id" gorm:"index"` // 零售订单id BillSn string `json:"bill_sn" gorm:"index"` // 单据编号 OutOrderNo string `json:"out_order_no"` // 商户订单号 PlatTrxNo string `json:"plat_trx_no"` // 平台交易流水号 BankOrderNo string `json:"bank_order_no"` // 银行订单号 TotalAmount float64 `json:"total_amount"` // 订单总金额 PayWay string `json:"pay_way"` // 支付方式 Status string `json:"status"` // 支付状态 } type ErpOrderCreateReq struct { BillSn string `json:"bill_sn"` // 单据编号 StoreId uint32 `json:"store_id" binding:"required"` // 门店id StoreName string `json:"store_name"` // 门店名称 Salesman1 uint32 `json:"salesman_1" binding:"required"` // 销售员一 Salesman2 uint32 `json:"salesman_2"` // 销售员二 RetailType string `json:"retail_type" binding:"required"` // 销售类型:sale 零售销售; rejected 零售退货 Tel string `json:"tel"` // 会员手机号 MemberType string `json:"member_type"` // 会员类型:general 普通; member 会员 TotalRetailPrice float64 `json:"total_retail_price"` // 订单总指导零售价 TotalAmount float64 `json:"total_amount"` // 订单实收金额 TotalCount uint32 `json:"total_count"` // 订单商品数量 VmAmount uint32 `json:"vm_count"` // 使用会员积分 Cashiers []ErpOrderCashier `json:"cashiers" binding:"required"` // 收付款方式 ErpOrderCommodities []ErpOrderCommodity `json:"erp_order_commodities" binding:"required"` // 零售订单商品信息 } type ErpOrderListReq struct { BillSn string `json:"bill_sn"` // 单据编号 RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 Uid int `json:"uid"` // 用户ID Tel string `json:"tel"` // 客户手机号 Salesman uint32 `json:"salesman"` // 销售人员ID StoreId uint32 `json:"store_id"` // 门店ID State string `json:"state"` // 订单状态 PayStatus uint32 `json:"pay_status"` // 支付状态 0-未创建 ;1-待支付; 2-已支付 StartTime string `json:"start_time"` // 开始时间 EndTime string `json:"end_time"` // 结束时间 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 IsExport uint32 `json:"is_export"` // 1-导出 } type ErpOrderListResp struct { List []ErpOrder `json:"list"` Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 ExportUrl string `json:"export_url"` } // ErpOrderDeleteReq 删除零售订单入参 type ErpOrderDeleteReq struct { BillSn string `json:"bill_sn" binding:"required"` // 单据编号 } // ErpOrderPayReq 收款入参 type ErpOrderPayReq struct { BillSn string `json:"bill_sn" binding:"required"` // 单据编号 AuthCode string `json:"auth_code" binding:"required"` // 用户付款码 } // ErpOrderPayResp 收款出参 type ErpOrderPayResp struct { Status string `json:"status"` // 支付成功:pay_ok;支付失败:pay_failed ;等待支付:paying; 未知状态:pay_unknown; 未创建支付订单:no_pay_order } // ErpOrderAuditReq 审核零售订单入参 type ErpOrderAuditReq struct { BillSn string `json:"bill_sn" binding:"required"` // 单据编号 State int `json:"state" binding:"required"` // 审核操作: 1-审核 2-取消审核 } // ErpOrderAddInvoiceReq 开发票入参 type ErpOrderAddInvoiceReq struct { BillSn string `json:"bill_sn" binding:"required"` // 单据编号 InvoiceCode string `json:"invoice_code" binding:"required"` // 发票代码 InvoiceNumber string `json:"invoice_number" binding:"required"` // 发票编码 } // ErpOrderStoreManageDataReq 查询门店经营入参 type ErpOrderStoreManageDataReq struct { StoreId uint32 `json:"store_id"` // 门店ID StartTime string `json:"start_time"` // 开始时间 EndTime string `json:"end_time"` // 结束时间 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 IsExport uint32 `json:"is_export"` // 1-导出 } // ErpOrderStoreManageDataResp 查询门店经营出参 type ErpOrderStoreManageDataResp struct { List []StoreManageData `json:"list"` Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 ExportUrl string `json:"export_url"` } // StoreManageData 门店经营数据 type StoreManageData struct { Date string `json:"date"` // 时间,如:"2023-12-25" TotalSalesAmount float64 `json:"total_sales_amount"` // 销售额 PromotionFee float64 `json:"promotion_fee"` // 推广费 SalesProfit float64 `json:"sales_profit"` // 销售毛利 StaffProfit float64 `json:"staff_profit"` // 员工毛利 Count uint32 `json:"count"` // 销售数量 } // ErpOrderRetailMarginReq 查询商品零售毛利汇总入参 type ErpOrderRetailMarginReq struct { StoreId uint32 `json:"store_id"` // 门店ID RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 ErpCommodityName string `json:"erp_commodity_name"` // 商品名称 ErpCategoryId uint32 `json:"erp_category_id" gorm:"index"` // 分类id StartTime string `json:"start_time"` // 开始时间 EndTime string `json:"end_time"` // 结束时间 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 页面条数 IsExport uint32 `json:"is_export"` // 1-导出 } // ErpOrderRetailMarginResp 查询商品零售毛利汇总出参 type ErpOrderRetailMarginResp struct { List []RetailMarginData `json:"list"` Total int `json:"total"` // 总条数 PageIndex int `json:"pageIndex"` // 页码 PageSize int `json:"pageSize"` // 每页展示条数 TotalCount uint32 `json:"total_count"` // 总销售数量 TotalSalesAmount float64 `json:"total_sales_amount"` // 总销售/退货金额 TotalSalesCost float64 `json:"total_sales_cost"` // 总销售成本:销售采购价之和 TotalSalesMargin float64 `json:"total_sales_margin"` // 总销售毛利:销售/退货金额-销售成本 TotalGrossMargins string `json:"total_gross_margins"` // 总销售毛利:销售/退货金额-销售成本 ExportUrl string `json:"export_url"` } // RetailMarginData 商品零售毛利数据 type RetailMarginData struct { StoreId uint32 `json:"store_id" gorm:"index"` // 门店id StoreName string `json:"store_name"` // 门店名称 RetailType string `json:"retail_type"` // 销售类型:sale 零售销售; rejected 零售退货 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"` // 分类名称 Count uint32 `json:"count"` // 销售数量 SalesAmount float64 `json:"sales_amount"` // 销售/退货金额 SalesCost float64 `json:"sales_cost"` // 销售成本:销售采购价之和 SalesMargin float64 `json:"sales_margin"` // 销售毛利:销售/退货金额-销售成本 GrossMargins string `json:"gross_margins"` // 销售毛利率:销售毛利/销售/退货金额 } func (m *ErpOrderListReq) List() (*ErpOrderListResp, error) { resp := &ErpOrderListResp{ PageIndex: m.PageIndex, PageSize: m.PageSize, } page := m.PageIndex - 1 if page < 0 { page = 0 } if m.PageSize == 0 { m.PageSize = 10 } qs := orm.Eloquent.Table("erp_order") if m.BillSn != "" { qs = qs.Where("bill_sn=?", m.BillSn) } else { if m.RetailType != "" { qs = qs.Where("retail_type=?", m.RetailType) } if m.Tel != "" { qs = qs.Where("tel=?", m.Tel) } if m.StoreId != 0 { qs = qs.Where("store_id=?", m.StoreId) } if m.Salesman != 0 { qs = qs.Where("salesman1 = ? or salesman2 = ?", m.Salesman, m.Salesman) } if m.PayStatus != 0 { qs = qs.Where("pay_status=?", m.PayStatus) } if m.State != "" { qs = qs.Where("state=?", m.State) } if m.StartTime != "" { parse, err := time.Parse(DateTimeFormat, m.StartTime) if err != nil { logger.Errorf("err:", err) } qs = qs.Where("created_at > ?", parse) } if m.EndTime != "" { parse, err := time.Parse(DateTimeFormat, m.EndTime) if err != nil { logger.Errorf("err:", err) } parse = parse.AddDate(0, 0, 1) qs = qs.Where("created_at < ?", parse) } } var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("count err:", logger.Field("err", err)) return resp, err } var orders []ErpOrder if m.IsExport == 1 { err = qs.Order("id DESC").Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("dailys err:", logger.Field("err", err)) return resp, err } //listExport, err := ErpOrderListExport(orders) //if err != nil { // logger.Error("list export err:", err) //} //resp.ExportUrl = listExport } else { resp.Total = int(count)/m.PageSize + 1 err = qs.Order("id DESC").Offset(page * m.PageSize).Limit(m.PageSize).Find(&orders).Error if err != nil && err != RecordNotFound { logger.Error("erp commodity list err:", logger.Field("err", err)) return resp, err } ErpOrderListSetCashier(orders) resp.List = orders //跟之前保持一致 resp.Total = int(count) resp.PageIndex = page + 1 resp.PageSize = m.PageSize } return resp, nil } // UpdateStock 扣减or添加库存 // 零售订单: // 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"已售"; // 非串码,通过门店id、商品id、商品名称查找库存详情表,找到库存时间最长的,然后更改其状态为"已售"。 // 同时扣减库存表对应的数量,-1 // 零售退货: // 有串码,通过串码查找库存详情表,然后更改对应库存的状态为"在库"; // 非串码,通过门店id、商品id、商品名称查找库存详情表,找到状态为"已售"且时间最近的单,将其状态改为"在库" // 同时扣减库存表对应的数量,+1 func UpdateStock(gdb *gorm.DB, erpOrder ErpOrder, state int) error { var commodities []ErpOrderCommodity err := orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", erpOrder.ID). Find(&commodities).Error if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } if erpOrder.RetailType == RetailTypeSale { // 零售订单 for i, _ := range commodities { if commodities[i].IMEIType == 2 || commodities[i].IMEIType == 3 { // 串码商品 if commodities[i].IMEI == "" { return errors.New("串码为空") } err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI). Update("state", state).Error // 状态更新为销售锁定中 if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } if state == SoldOut { // 已售的订单才更新库存数量 err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", erpOrder.StoreId, commodities[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } } } else { // 非串码商品 var stockCommodity []ErpStockCommodity // 通过门店id,商品id,查找状态为1-在库的非串码商品 err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 1, 1). Order("id DESC").Find(&stockCommodity).Error if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } if stockCommodity == nil || len(stockCommodity) == 0 { return errors.New("find commodity no stock ") } err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). Update("state", state).Error // 状态更新为销售锁定中 if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } if state == SoldOut { // 已售的订单才更新库存数量 err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", erpOrder.StoreId, commodities[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count - ?", 1)}).Error // 库存数量-1 if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return err } } } } } else if erpOrder.RetailType == RetailTypeRejected { // 零售退货订单 for i, _ := range commodities { if commodities[i].IMEIType == 2 { // 串码商品 if commodities[i].IMEI == "" { return errors.New("串码为空") } err = gdb.Table("erp_stock_commodity").Where("imei = ?", commodities[i].IMEI). Update("state", InStock).Error // 状态更新为在库 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", erpOrder.StoreId, commodities[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } else { // 非串码商品 var stockCommodity []ErpStockCommodity // 通过门店id,商品id,查找状态为2-已售的非串码商品 err = orm.Eloquent.Table("erp_stock_commodity").Where("erp_commodity_id = ? and store_id = ? "+ "and state = ? and imei_type = ?", commodities[i].ErpCommodityId, erpOrder.StoreId, 2, 1). Order("id DESC").Find(&stockCommodity).Error if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } if stockCommodity == nil { return errors.New("RetailTypeRejected find no stock commodity") } err = gdb.Table("erp_stock_commodity").Where("id = ?", stockCommodity[0].ID). Update("state", InStock).Error // 状态更新为在库 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } err = gdb.Table("erp_stock").Where("store_id = ? and erp_commodity_id = ?", erpOrder.StoreId, commodities[i].ErpCommodityId). Updates(map[string]interface{}{"count": gorm.Expr("count + ?", 1)}).Error // 库存数量+1 if err != nil { logger.Error("RetailTypeRejected commodities err:", logger.Field("err", err)) return err } } } } else { return errors.New("订单类型错误") } return nil } // CheckIsOnlinePay 检查是否包含线上支付 func CheckIsOnlinePay(jCashier []ErpOrderCashier) bool { for _, cashier := range jCashier { if cashier.CashierId == OnlinePay || strings.Contains(cashier.Name, "微信") || strings.Contains(cashier.Name, "支付宝") { return true } } return false } 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++ } } func NewErpPurchaseSn() 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_purchase_order WHERE serial_number='%s'", sn)) if err != nil { logger.Error("exist sn err") } if !exist { return sn } max++ } } func ErpOrderListSetCashier(list []ErpOrder) { for i, _ := range list { list[i].SetErpCashier() } } func (m *ErpOrder) SetErpCashier() { if m.CashierList != "" { var cashiers []ErpOrderCashier err := json.Unmarshal([]byte(m.CashierList), &cashiers) if err != nil { logger.Error("unmarshal err:", logger.Field("err", err)) } m.Cashiers = cashiers m.CashierList = "" } } func GetErpOrderCommodityMap(ids []uint32) (map[uint32]ErpOrderCommodity, error) { commodityMap := make(map[uint32]ErpOrderCommodity, 0) if len(ids) == 0 { return commodityMap, nil } var commodities []ErpOrderCommodity err := orm.Eloquent.Table("erp_order_commodity").Where("id IN (?)", ids).Find(&commodities).Error if err != nil { logger.Error("commodities err:", logger.Field("err", err)) return commodityMap, err } for i, _ := range commodities { commodityMap[commodities[i].ID] = commodities[i] } return commodityMap, nil } func SetUserInfo(tel string) { var user UserInfo err := orm.Eloquent.Table("user").Where("tel=?", tel).Find(&user).Error if err != nil { logger.Error("user err:", logger.Field("err", err)) return } if user.FirstRetailOrder.IsZero() { err := orm.Eloquent.Table("user").Where("uid=?", user.Uid).Update("first_retail_order", time.Now()).Error if err != nil { logger.Error("update user err:", logger.Field("err", err)) } } } func SetInvoice(req *ErpOrderAddInvoiceReq) error { var orderInfo ErpOrder err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error if err != nil { logger.Error("操作失败,未查询到订单", logger.Field("err", err)) return errors.New("未查询到订单") } if orderInfo.State == ErpOrderStateUnAudit { logger.Errorf("order delete err, state is:", orderInfo.State) return errors.New("订单未审核") } if orderInfo.PayStatus != 2 { logger.Errorf("order delete err, state is:", orderInfo.State) return errors.New("订单未支付") } err = orm.Eloquent.Table("erp_order").Where("id = ?", orderInfo.ID).Updates(map[string]interface{}{ "invoice_code": req.InvoiceCode, "invoice_number": req.InvoiceNumber, }).Error if err != nil { logger.Error("AddInvoice err:", logger.Field("err", err)) return err } return nil } func DeleteOrder(req *ErpOrderDeleteReq) error { var orderInfo ErpOrder err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error if err != nil { logger.Error("order delete err:", logger.Field("err", err)) return errors.New("未查询到订单") } if orderInfo.State != ErpOrderStateUnAudit { logger.Errorf("order delete err, state is:", orderInfo.State) return errors.New("已审核订单不能删除") } var orderCommodities ErpOrderCommodity err = orm.Eloquent.Table("erp_order_commodity").Where("erp_order_id = ?", orderInfo.ID).Find(&orderCommodities).Error if err != nil { logger.Error("order delete err:", logger.Field("err", err)) return errors.New("未查询到订单商品信息") } begin := orm.Eloquent.Begin() err = begin.Delete(orderCommodities).Error if err != nil { begin.Rollback() logger.Error("order delete1 err:", logger.Field("err", err)) return err } err = begin.Delete(orderInfo).Error if err != nil { begin.Rollback() logger.Error("order delete2 err:", logger.Field("err", err)) return err } err = begin.Commit().Error if err != nil { begin.Rollback() logger.Error("order delete3 err:", logger.Field("err", err)) return err } return nil } // 生成序列号 func GenErpOrderSerialNo() string { currentDate := time.Now().Format("20060102") tradeNO := "sale" + currentDate + pay.RandomNumString(10000000, 99999999) return tradeNO } // GetErpOrderSn 生成零售订单号 func GetErpOrderSn() string { var erpOrderSn string for { erpOrderSn = GenErpOrderSerialNo() var count int64 err := orm.Eloquent.Table("erp_order_record").Where("out_order_no=?", erpOrderSn).Count(&count) if err != nil { logger.Error("err:", logger.Field("err", err)) } if count == 0 { break } } return erpOrderSn } // 查询是否有已支付的订单 func checkIsPayOk(billSn string) bool { var count int64 err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayOk). Count(&count).Error if err != nil { logger.Error("checkIsPayOk err:", logger.Field("err", err)) } return count > 0 } // 查询是否有待支付的订单 func checkIsPaying(billSn string) bool { var count int64 err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, Paying). Count(&count).Error if err != nil { logger.Error("checkIsPayOk err:", logger.Field("err", err)) } return count > 0 } // 查询是否有刚初始化的订单 func checkIsPayInit(billSn string) bool { var count int64 err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", billSn, PayInit). Count(&count).Error if err != nil { logger.Error("checkIsPayOk err:", logger.Field("err", err)) } return count > 0 } // ErpOrderPay 零售订单支付 func ErpOrderPay(req *ErpOrderPayReq) (*ErpOrderPayResp, error) { resp := &ErpOrderPayResp{ Status: PayFailed, } //通过单据号查询收款金额 var orderInfo ErpOrder err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", req.BillSn).Find(&orderInfo).Error if err != nil { logger.Error("未查询到订单:", logger.Field("err", err)) return resp, err } if orderInfo.PayStatus == HavePaid { logger.Error("ErpOrderPay err, 订单已支付") return resp, errors.New("订单已支付") } if orderInfo.PayStatus != WaitForPaying { logger.Error("ErpOrderPay err, 订单不是待支付状态") return resp, errors.New("订单不是待支付状态") } var cashiers []ErpOrderCashier err = json.Unmarshal([]byte(orderInfo.CashierList), &cashiers) if err != nil { logger.Error("unmarshal CashierList err:", logger.Field("err", err)) } var amount float64 for i, _ := range cashiers { if cashiers[i].CashierId == OnlinePay { //线上支付 amount = cashiers[i].Amount break } } if amount == 0 { logger.Error("ErpOrderPay err, 订单金额为0") return resp, errors.New("订单金额为0") } // dev环境测试默认金额都为0.1元 if config.ApplicationConfig.Mode == "dev" { amount = 0.1 } // 查询是否有已支付的订单 if checkIsPayOk(req.BillSn) { // 更新零售订单表 err = orm.Eloquent.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID). Update("pay_status", HavePaid).Error if err != nil { logger.Error("ErpOrderPay update erp_order_record err:", logger.Field("err", err)) } resp.Status = PayOk logger.Error("ErpOrderPay err2, 订单已支付") return resp, errors.New("订单已支付") } // 查询是否有待支付订单 if checkIsPaying(req.BillSn) { queryResp, err := QueryErpOrderPayStatus(req.BillSn) if err != nil { logger.Error("查询订单失败", logger.Field("err", err)) return resp, err } // 等待支付或成功支付则返回,否则新建订单 if queryResp.Status == Paying || queryResp.Status == PayOk { resp.Status = queryResp.Status return resp, nil } } // 查询是否有刚初始化的订单 var orderSn string if checkIsPayInit(req.BillSn) { var orderRecordInfo ErpOrderRecord err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status = ?", req.BillSn, PayInit). Find(&orderRecordInfo).Error if err != nil { logger.Error("未查询到订单:", logger.Field("err", err)) return resp, errors.New("未查询到待支付订单") } orderSn = orderRecordInfo.OutOrderNo } else { // 创建支付订单号,并记录到支付记录表,关联零售订单号 orderSn = GetErpOrderSn() var erpOrderRecord ErpOrderRecord erpOrderRecord.ErpOrderId = orderInfo.ID erpOrderRecord.BillSn = orderInfo.BillSn erpOrderRecord.OutOrderNo = orderSn erpOrderRecord.Status = PayInit err = orm.Eloquent.Table("erp_order_record").Create(&erpOrderRecord).Error if err != nil { logger.Error("Create erp_order_record err:", logger.Field("err", err)) return resp, err } } resp.Status = Paying // 发起支付扣款 hmPayResp, err := pay.HmJsPayBToCOrder(orderSn, amount, req.AuthCode, "") if err != nil { logger.Error("HmJsPayBToCOrder err") return resp, err } // 更新支付状态 var payStatus string switch hmPayResp.SubCode { case "SUCCESS": payStatus = PayOk case "FAILED": payStatus = PayFailed case "WAITING_PAYMENT": payStatus = Paying //default: // payStatus = PayUnknown } updateInfo := map[string]interface{}{ "bank_order_no": hmPayResp.BankOrderNo, "plat_trx_no": hmPayResp.PlatTrxNo, "total_amount": hmPayResp.TotalAmount, "pay_way": hmPayResp.PayWay, "status": payStatus, } begin := orm.Eloquent.Begin() err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderSn). Updates(updateInfo).Error if err != nil { begin.Rollback() logger.Error("update erp_order_record err:", logger.Field("err", err)) return resp, err } if payStatus == PayOk { // 支付成功 // 更新零售订单表 err = begin.Model(&ErpOrder{}).Where("id = ?", orderInfo.ID). Update("pay_status", HavePaid).Error if err != nil { begin.Rollback() logger.Error("update erp_order_record err:", logger.Field("err", err)) return resp, err } // 更新库存订单表 err = updateErpStockCommodity(begin, req.BillSn) if err != nil { logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err)) return resp, err } } err = begin.Commit().Error if err != nil { begin.Rollback() return resp, fmt.Errorf("ErpOrderPay[commit err]:%v", err) } resp.Status = payStatus return resp, nil } // QueryErpOrderPayStatus 查询零售订单支付状态 func QueryErpOrderPayStatus(billSn string) (*ErpOrderPayResp, error) { resp := &ErpOrderPayResp{ Status: Paying, } // 查询待支付订单 var orderRecordInfo ErpOrderRecord err := orm.Eloquent.Table("erp_order_record").Where("bill_sn = ? and status in (?)", billSn, []string{Paying, PayOk}). Find(&orderRecordInfo).Error if err != nil { logger.Error("未查询到订单:", logger.Field("err", err)) resp.Status = PayFailed return resp, errors.New("未查询到待支付订单") } if orderRecordInfo.OutOrderNo == "" { logger.Info("还未创建支付订单") resp.Status = NoPayOrder return resp, nil } if orderRecordInfo.Status == PayOk { logger.Info("订单已支付") resp.Status = PayOk return resp, nil } // 查询支付状态 hmQueryResp, err := pay.HmQueryOrder(orderRecordInfo.OutOrderNo) if err != nil { logger.Error("查询失败:", logger.Field("err", err)) return resp, err } // 更新订单状态 var payStatus string switch hmQueryResp.SubCode { case "SUCCESS": payStatus = PayOk case "FAILED": payStatus = PayFailed case "WAITING_PAYMENT": payStatus = Paying //default: // payStatus = PayUnknown } updateInfo := map[string]interface{}{ "bank_order_no": hmQueryResp.BankOrderNo, "plat_trx_no": hmQueryResp.PlatTrxNo, "total_amount": hmQueryResp.TotalAmount, "pay_way": hmQueryResp.PayWayCode, "status": payStatus, } begin := orm.Eloquent.Begin() err = begin.Model(&ErpOrderRecord{}).Where("out_order_no = ?", orderRecordInfo.OutOrderNo). Updates(updateInfo).Error if err != nil { begin.Rollback() logger.Error("query update erp_order_record err:", logger.Field("err", err)) return resp, err } if payStatus == PayOk { // 支付成功 // 更新零售订单表 err = begin.Model(&ErpOrder{}).Where("id = ?", orderRecordInfo.ErpOrderId). Update("pay_status", HavePaid).Error if err != nil { begin.Rollback() logger.Error("query update erp_order_record err:", logger.Field("err", err)) return resp, err } // 更新库存订单表 err = updateErpStockCommodity(begin, billSn) if err != nil { logger.Error("ErpOrderPay updateErpStockCommodity err:", logger.Field("err", err)) return resp, err } } err = begin.Commit().Error if err != nil { begin.Rollback() return resp, fmt.Errorf("QueryErpOrderPayStatus[commit err]:%v", err) } resp.Status = payStatus return resp, nil } // updateErpStockCommodity 更新库存订单表 func updateErpStockCommodity(gdb *gorm.DB, billSn string) error { //通过单据号查询订单 var erpOrderInfo []ErpOrder err := orm.Eloquent.Table("erp_order").Where("bill_sn = ?", billSn).Find(&erpOrderInfo).Error if err != nil { logger.Error("erp_order 未查询到订单:", logger.Field("err", err)) return err } if len(erpOrderInfo) == 0 { return errors.New("未查询到订单") } err = UpdateStock(gdb, erpOrderInfo[0], SoldOut) if err != nil { gdb.Rollback() logger.Error("updateErpStockCommodity UpdateStock err:", logger.Field("err", err)) return errors.New("审核失败:" + err.Error()) } return nil } // CommodityIsHaveStock 查询商品是否有库存 func CommodityIsHaveStock(req ErpOrderCommodity, storeId uint32) bool { qs := orm.Eloquent.Table("erp_stock_commodity") if req.IMEI != "" { // 串码商品 qs.Where("imei = ? and state = ?", req.IMEI, InStock) } else { // 非串码商品 qs.Where("erp_commodity_id = ? and erp_store_id = ? and state = ? and IMEIType = ", req.ErpCommodityId, storeId, InStock, NoIMEICommodity) } var count int64 err := qs.Count(&count).Error if err != nil { logger.Error("CommodityIsHaveStock err:", logger.Field("err", err)) } return count > 0 } // QueryStoreManageData 查询门店经营数据 func QueryStoreManageData(req *ErpOrderStoreManageDataReq) (*ErpOrderStoreManageDataResp, error) { resp := &ErpOrderStoreManageDataResp{ PageIndex: req.PageIndex, PageSize: req.PageSize, } page := req.PageIndex - 1 if page < 0 { page = 0 } if req.PageSize == 0 { req.PageSize = 10 } var storeManageDataList []StoreManageData // 构建查询条件 qs := orm.Eloquent.Model(&ErpOrder{}) if req.StoreId != 0 { qs = qs.Where("store_id = ?", req.StoreId) } if req.StartTime != "" && req.EndTime != "" { startTime, _ := time.Parse("2006-01-02", req.StartTime) endTime, _ := time.Parse("2006-01-02", req.EndTime) qs = qs.Where("maker_time BETWEEN ? AND ?", startTime, endTime) } qs = qs.Where("maker_time IS NOT NULL AND maker_time != '0000-00-00 00:00:00'") es := qs // 获取总条数 err := es.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, SUM(total_amount) AS total_sales_amount, " + "(SUM(total_retail_price) - SUM(total_amount)) AS promotion_fee, " + "SUM(sales_profit) AS sales_profit, SUM(staff_profit) AS staff_profit, SUM(total_count) AS count"). Group("date"). Find(&storeManageDataList).Error if err != nil { logger.Error("QueryStoreManageData count err:", logger.Field("err", err)) return nil, err } resp.Total = len(storeManageDataList) storeManageDataList = nil if req.IsExport == 1 { //导出excel // 查询数据 err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, SUM(total_amount) AS total_sales_amount, " + "(SUM(total_retail_price) - SUM(total_amount)) AS promotion_fee, " + "SUM(sales_profit) AS sales_profit, SUM(staff_profit) AS staff_profit, SUM(total_count) AS count"). Group("date"). Order("date DESC"). Find(&storeManageDataList).Error if err != nil { logger.Error("QueryStoreManageData err:", logger.Field("err", err)) return nil, err } storeName := "所有门店" if req.StoreId != 0 { storeInfo, err := GetStore(req.StoreId) if err != nil { logger.Error("GetStore err:", logger.Field("err", err)) return nil, err } storeName = storeInfo.Name } filePath, err := StoreManageDataExport(storeManageDataList, storeName) if err != nil { logger.Error("StoreManageDataExport err:", logger.Field("err", err)) return nil, err } resp.ExportUrl = filePath } else { // 查询数据 err = qs.Select("DATE_FORMAT(maker_time, '%Y-%m-%d') AS date, SUM(total_amount) AS total_sales_amount, " + "(SUM(total_retail_price) - SUM(total_amount)) AS promotion_fee, " + "SUM(sales_profit) AS sales_profit, SUM(staff_profit) AS staff_profit, SUM(total_count) AS count"). Group("date"). Order("date DESC"). Offset(page * req.PageSize). Limit(req.PageSize). Find(&storeManageDataList).Error if err != nil { logger.Error("QueryStoreManageData err:", logger.Field("err", err)) return nil, err } resp.List = storeManageDataList resp.PageIndex = req.PageIndex resp.PageSize = req.PageSize } return resp, nil } // StoreManageDataExport 导出门店经营数据 func StoreManageDataExport(list []StoreManageData, storeName string) (string, error) { file := excelize.NewFile() streamWriter, err := file.NewStreamWriter("Sheet1") if err != nil { fmt.Println(err) } url := ExportUrl fileName := time.Now().Format(TimeFormat) + storeName + "经营数据" + ".xlsx" fmt.Println("url fileName:", url+fileName) title := []interface{}{"时间", "销售额", "推广费", "销售毛利", "员工毛利", "销售数量"} cell, _ := excelize.CoordinatesToCellName(1, 1) if err = streamWriter.SetRow(cell, title); err != nil { fmt.Println(err) } var row []interface{} nExcelStartRow := 0 for rowId := 0; rowId < len(list); rowId++ { row = []interface{}{ list[rowId].Date, list[rowId].TotalSalesAmount, list[rowId].PromotionFee, list[rowId].SalesProfit, list[rowId].StaffProfit, list[rowId].Count, } cell, _ := excelize.CoordinatesToCellName(1, nExcelStartRow+2) if err := streamWriter.SetRow(cell, row); err != nil { fmt.Println(err) } nExcelStartRow++ } if err := streamWriter.Flush(); err != nil { fmt.Println(err) } fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // RetailMarginDataExport 导出商品零售毛利汇总数据 func RetailMarginDataExport(req *ErpOrderRetailMarginResp, storeName string) (string, error) { file := excelize.NewFile() streamWriter, err := file.NewStreamWriter("Sheet1") if err != nil { fmt.Println(err) } url := ExportUrl fileName := time.Now().Format(TimeFormat) + storeName + "商品零售毛利汇总" + ".xlsx" fmt.Println("url fileName:", url+fileName) title := []interface{}{"店铺名称", "零售类型", "商品名称", "商品分类", "数量", "销售/退货金额", "销售成本", "销售毛利", "销售毛利率"} cell, _ := excelize.CoordinatesToCellName(1, 1) if err = streamWriter.SetRow(cell, title); err != nil { fmt.Println(err) } var row []interface{} nExcelStartRow := 0 for rowId := 0; rowId < len(req.List); rowId++ { var saleType string if req.List[rowId].RetailType == RetailTypeSale { saleType = "零售销售" } else if req.List[rowId].RetailType == RetailTypeRejected { saleType = "零售退货" } else { logger.Error("订单类型异常") return "", errors.New("RetailMarginDataExport, 订单类型异常:" + req.List[rowId].RetailType) } row = []interface{}{ storeName, saleType, req.List[rowId].ErpCommodityName, req.List[rowId].ErpCategoryName, req.List[rowId].Count, req.List[rowId].SalesAmount, req.List[rowId].SalesCost, req.List[rowId].SalesMargin, req.List[rowId].GrossMargins, } cell, _ := excelize.CoordinatesToCellName(1, nExcelStartRow+2) if err := streamWriter.SetRow(cell, row); err != nil { fmt.Println(err) } nExcelStartRow++ } totalData := "汇总 记录数:" + strconv.FormatInt(int64(req.TotalCount), 10) end := []interface{}{totalData, "", "", "", req.TotalCount, req.TotalSalesAmount, req.TotalSalesCost, req.TotalSalesMargin, req.TotalGrossMargins} cell, _ = excelize.CoordinatesToCellName(1, nExcelStartRow+2) if err := streamWriter.SetRow(cell, end); err != nil { fmt.Println(err) } if err := streamWriter.Flush(); err != nil { fmt.Println(err) } fmt.Println("save fileName:", config.ExportConfig.Path+fileName) if err := file.SaveAs(config.ExportConfig.Path + fileName); err != nil { fmt.Println(err) } return url + fileName, nil } // QueryRetailMargin 查询零售毛利汇总数据 func QueryRetailMargin(req *ErpOrderRetailMarginReq) (*ErpOrderRetailMarginResp, error) { resp := &ErpOrderRetailMarginResp{ 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_order_commodity"). Select("erp_order_commodity.*, erp_order.store_id, erp_order.store_name, erp_order.retail_type"). Joins("JOIN erp_order ON erp_order_commodity.erp_order_id = erp_order.id") if req.StoreId != 0 { qs.Where("erp_order.store_id = ?", req.StoreId) } if req.RetailType != "" { qs.Where("erp_order.retail_type = ?", req.RetailType) } if req.ErpCommodityName != "" { qs.Where("erp_order_commodity.erp_commodity_name like" + "%" + req.ErpCommodityName + "%") } if req.ErpCategoryId != 0 { qs.Where("erp_order_commodity.erp_category_id = ?", req.ErpCategoryId) } if req.StartTime != "" { startTime, err := time.Parse(QueryTimeFormat, req.StartTime) if err == nil { qs = qs.Where("erp_order.created_at>?", startTime) } else { logger.Errorf("QueryRetailMargin time start parse err:", err.Error()) } } if req.EndTime != "" { endTime, err := time.Parse(QueryTimeFormat, req.EndTime) if err == nil { qs = qs.Where("erp_order.created_at