package bundle import ( "context" "errors" "fmt" "fonchain-fiee/api/accountFiee" "fonchain-fiee/api/bundle" "fonchain-fiee/api/order" "fonchain-fiee/pkg/model/login" "fonchain-fiee/pkg/service" "fonchain-fiee/pkg/service/bundle/common" "fonchain-fiee/pkg/service/bundle/logic" bundleModel "fonchain-fiee/pkg/service/bundle/model" "fonchain-fiee/pkg/service/upload" "strconv" "strings" "time" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" ) func CreateBundleOrderAddSignature(c *gin.Context) { var req bundle.OrderAddRecord if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } if req.Language == "" { service.Error(c, errors.New(common.MissLanguageTypes)) return } if req.BundleUuid == "" { service.Error(c, errors.New(common.MissOrderNo)) return } // 获取用户信息 userInfo := login.GetUserInfoFromC(c) if msg, exists := map[int32]string{ 1: common.Unnamed, 2: common.UnderReview, 3: common.ReviewFailed, }[userInfo.Status]; userInfo.Status != 4 { if exists { service.Error(c, errors.New(msg)) } else { service.Error(c, errors.New(common.UnknownStatus)) } return } // 校验套餐是否已购买 orderRecordReq := bundle.OrderRecordsDetailRequest{ BundleUUID: req.BundleUuid, CustomerID: strconv.FormatUint(userInfo.ID, 10), } orderRecordResp, err := service.BundleProvider.OrderRecordsDetail(context.Background(), &orderRecordReq) if err != nil { service.Error(c, err) return } if orderRecordResp.OrderRecord.ExpirationTime == "" || orderRecordResp.OrderRecord.ExpirationTime < time.Now().Format("2006-01-02") { service.Error(c, errors.New(common.ThePackageHasExpired)) return } // 获取套餐详情(待替换逻辑) bundleDetail, err := service.BundleProvider.BundleDetail(context.Background(), &bundle.BundleDetailRequest{ Uuid: req.BundleUuid, }) if err != nil { service.Error(c, err) return } // todo 需要判断购买的增值服务是否为可用时长 如果为可以用时长 合同截止日期为购买时长时间 否则合同截止日期为主套餐截止日期 // 处理多个增值服务 type ValueAddServiceInfo struct { Service *bundle.ValueAddServiceLang Options *bundle.ValueAddPriceOptions ID int32 } var ( valueAddServices []ValueAddServiceInfo totalAmount float64 mainDeadline = orderRecordResp.OrderRecord.ExpirationTime ) //for _, opt := range req.AddPriceOptionsList { // valueAddInfo, err := service.BundleProvider.ValueAddServiceDetail(context.Background(), &bundle.ValueAddServiceDetailRequest{ // Uuid: opt.ValueUid, // Language: req.Language, // }) // if err != nil { // service.Error(c, err) // return // } // // 找到匹配的选项 // var selectedOption *bundle.ValueAddPriceOptions // for _, option := range valueAddInfo.ValueAddServiceLang.Options { // if int32(option.Id) == opt.Id { // selectedOption = option // break // } // } // if selectedOption == nil { // service.Error(c, errors.New("未找到匹配的价格选项")) // return // } // valueAddServices = append(valueAddServices, ValueAddServiceInfo{ // Service: valueAddInfo.ValueAddServiceLang, // Options: selectedOption, // ID: opt.Id, // }) //} // 计算总金额和确定截止日期 var expirationDate string var addPriceList []*bundle.AddPriceOptionsInfo for _, svc := range valueAddServices { price, err := strconv.ParseFloat(svc.Options.Price, 64) if err != nil { service.Error(c, errors.New("价格格式错误")) return } var nowAmount float64 switch svc.Service.PriceMode { case 1: // 数量×单价模式 nowAmount = float64(svc.Options.Num) * price totalAmount += float64(svc.Options.Num) * price case 2: // 固定价格模式 nowAmount = price totalAmount += price } addPriceList = append(addPriceList, &bundle.AddPriceOptionsInfo{ ValueUid: svc.Service.Uuid, ServiceType: svc.Service.ServiceType, CurrencyType: svc.Service.PriceType, Amount: float32(nowAmount), Num: svc.Options.Num, Unit: svc.Service.Unit, }) // 如果是可用时长服务,计算新的截止日期 if svc.Service.ServiceType == 5 { newDeadline := calculateExpirationDate(svc.Options.Num, svc.Service.Unit) if expirationDate == "" || newDeadline > expirationDate { expirationDate = newDeadline } } } // 如果没有可用时长服务,使用主套餐截止日期 if expirationDate == "" { expirationDate = mainDeadline } req.CustomerNum = userInfo.SubNum req.CustomerName = userInfo.Name req.CustomerID = strconv.FormatUint(userInfo.ID, 10) req.Source = 2 req.SignedTime = common.GetBeijingTime() req.ExpirationDate = expirationDate req.AddPriceOptionsList = addPriceList // 当前 未将 签名 写入合同中 signContract, signContractErr := logic.SignContractV2(req.CustomerNum, bundleDetail.Bundle.Contract, float32(totalAmount), expirationDate) if signContractErr != nil { service.Error(c, signContractErr) return } req.SignContract = signContract // 创建增值服务订单记录 res, err := service.BundleProvider.CreateOrderAddRecord(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } // 计算截止日期辅助函数 func calculateExpirationDate(num int32, unit string) string { now := time.Now() switch unit { case "天": return now.AddDate(0, 0, int(num)).Format("2006-01-02") case "月": return now.AddDate(0, int(num), 0).Format("2006-01-02") case "年": return now.AddDate(int(num), 0, 0).Format("2006-01-02") default: return "" } } func CreateBundleOrderSignature(c *gin.Context) { var req bundle.OrderRecord if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } if req.BundleUuid == "" { service.Error(c, errors.New(common.MissBundleUUID)) return } if req.Language == "" { service.Error(c, errors.New(common.MissLanguageTypes)) return } // 不去校验 签名 /*if req.Signature == "" { service.Error(c, errors.New(common.MissOrderSignature)) return }*/ statusMessages := map[int32]string{ 1: common.Unnamed, 2: common.UnderReview, 3: common.ReviewFailed, } // 获取 用户信息 userInfo := login.GetUserInfoFromC(c) if userInfo.Status != 4 { if msg, exists := statusMessages[userInfo.Status]; exists { service.Error(c, errors.New(msg)) return } else { service.Error(c, errors.New(common.UnknownStatus)) return } } // 校验 当前用户只能买一次套餐 orderRecordsListReq := bundle.OrderRecordsRequest{ CustomerID: strconv.FormatUint(userInfo.ID, 10), } orderRecordsList, orderRecordsListErr := service.BundleProvider.OrderRecordsList(context.Background(), &orderRecordsListReq) if orderRecordsListErr != nil { service.Error(c, orderRecordsListErr) return } //有套餐并且套餐未过期 if orderRecordsList.OrderRecords != nil { for _, orderInfo := range orderRecordsList.OrderRecords { if orderInfo.CustomerID == strconv.FormatUint(userInfo.ID, 10) && orderInfo.ExpirationTime > time.Now().Format("2006-01-02") { service.Error(c, errors.New(common.HadOrder)) return } } } // 获取 最后一次的 合同编号 lastOrderRecord, lastOrderRecordErr := service.BundleProvider.OrderRecordsList(context.Background(), &bundle.OrderRecordsRequest{ PageSize: 1, Page: 1, }) if lastOrderRecordErr != nil { service.Error(c, lastOrderRecordErr) return } lastContractNo := "" if lastOrderRecord.OrderRecords != nil { for _, lastOrder := range lastOrderRecord.OrderRecords { lastContractNo = lastOrder.ContractNo } } req.CustomerNum = userInfo.SubNum req.CustomerName = userInfo.Name req.CustomerID = strconv.FormatUint(userInfo.ID, 10) // 获取 套餐信息 bundleDetailReq := &bundle.BundleDetailRequest{ Uuid: req.BundleUuid, } bundleDetail, detailErr := service.BundleProvider.BundleDetail(context.Background(), bundleDetailReq) if detailErr != nil { service.Error(c, detailErr) return } //获取增值套餐信息 //if req.ValueAddBundleUuid != "" { // valueAddBundleDetail, err := service.BundleProvider.ValueAddBundleDetail(context.Background(), &bundle.ValueAddBundleDetailRequest{ // Uuid: req.ValueAddBundleUuid, // }) // if err != nil { // service.Error(c, err) // return // } // // req.ValueAddBundleUuid = valueAddBundleDetail.Data.Uuid // req.ValueAddOriginalPrice = valueAddBundleDetail.Data.OriginalPrice // req.ValueAddDiscountPrice = valueAddBundleDetail.Data.DiscountPrice // req.AddBundleCommonUid = valueAddBundleDetail.Data.AddBundleCommonUid // // if valueAddBundleDetail.Data.Choose { // 可选条数 // req.ValueAddBundleAmount = valueAddBundleDetail.Data.DiscountPrice * float32(req.Num) // discount, _ := new(big.Float).Sub(big.NewFloat(float64(valueAddBundleDetail.Data.OriginalPrice)), big.NewFloat(float64(valueAddBundleDetail.Data.DiscountPrice))).Float32() // req.ValueAddSavedAmount = discount * float32(req.Num) // } else { // 固定条数 // req.ValueAddBundleAmount = valueAddBundleDetail.Data.TotalPrice // req.ValueAddSavedAmount = valueAddBundleDetail.Data.SavedAmount // } // // req.TotalAmount, _ = new(big.Float).Add(big.NewFloat(float64(req.ValueAddBundleAmount)), big.NewFloat(float64(bundleDetail.Bundle.Price))).Float32() //} req.BundleName = bundleDetail.Bundle.Name req.Amount = bundleDetail.Bundle.Price req.AmountType = bundleDetail.Bundle.PriceType req.BundleCommonUid = bundleDetail.Bundle.BundleCommonUid req.TotalAmount = bundleDetail.Bundle.Price req.PayType = 1 // 默认 人民币 //获取过期时间和增值服务金额 PriceAndTime, err := service.BundleProvider.PackagePriceAndTime(context.Background(), &req) if err != nil { service.Error(c, err) return } //套餐金额+增值服务金额 totalAmount := PriceAndTime.Price + bundleDetail.Bundle.Price req.ContractNo = common.GenerateContractNo(lastContractNo) // 当前 未将 签名 写入合同中 todo 金额和有效时间待修改 signContract, signContractErr := logic.SignContractV2(req.CustomerNum, bundleDetail.Bundle.Contract, totalAmount, PriceAndTime.Time) if signContractErr != nil { service.Error(c, signContractErr) return } req.SignContract = signContract req.SignedTime = common.GetBeijingTime() req.Status = bundleModel.OrderSigned res, err := service.BundleProvider.CreateOrderRecord(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func UpdateBundleOrderStatusPaid(c *gin.Context) { var req bundle.OrderRecord if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } // 获取 用户信息 userInfo := login.GetUserInfoFromC(c) if req.Uuid == "" { service.Error(c, errors.New(common.MissOrderUUID)) return } detail, detailErr := service.BundleProvider.OrderRecordsDetail(context.Background(), &bundle.OrderRecordsDetailRequest{ Uuid: req.Uuid, }) if detailErr != nil { service.Error(c, detailErr) return } // 判断 是否是 本人操作 if strconv.FormatUint(userInfo.ID, 10) != detail.OrderRecord.CustomerID { service.Error(c, errors.New(common.NotMatchOrderInfo)) return } // 如果 当前订单 是 已签未支付 且 存在 checkoutSessionId 需要 查询 支付结果 if detail.OrderRecord.Status == bundleModel.OrderSigned && detail.OrderRecord.CheckoutSessionId != "" && detail.OrderRecord.PayTime == "" { // 查询支付结果 stripeInfosRes, stripeInfosErr := service.OrderProvider.QueryStripeInfoByCheckSessionIds(context.Background(), &order.QueryStripeInfoRequest{ CheckoutSessionIds: []string{detail.OrderRecord.CheckoutSessionId}, }) if stripeInfosErr != nil { service.Error(c, errors.New(common.ErrorQueryStripeInfo)) return } totalStripe := 0 if stripeInfosRes != nil && len(stripeInfosRes.StripeInfos) > 0 { totalStripe = len(stripeInfosRes.StripeInfos) for _, stripeInfo := range stripeInfosRes.StripeInfos { if stripeInfo.OutTradeNo == detail.OrderRecord.OrderNo && stripeInfo.PaymentIntentStatus == "paid" { _, updateOrderRecordErr := service.BundleProvider.UpdateOrderRecord(context.Background(), &bundle.OrderRecord{ Uuid: detail.OrderRecord.Uuid, Status: bundleModel.OrderPaid, PayTime: common.GetBeijingTime(), }) if updateOrderRecordErr != nil { service.Error(c, detailErr) return } totalStripe-- } } } if totalStripe != 0 && totalStripe == len(stripeInfosRes.StripeInfos) { _, updateOrderRecordErr := service.BundleProvider.UpdateOrderRecord(context.Background(), &bundle.OrderRecord{ Uuid: detail.OrderRecord.Uuid, CheckoutSessionId: "", CheckoutSessionUrl: "", }) if updateOrderRecordErr != nil { service.Error(c, detailErr) return } } } service.Success(c, nil) } func OrderRecordsList(c *gin.Context) { var req bundle.OrderRecordsRequest if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } // 获取 用户信息 //userInfo := login.GetUserInfoFromC(c) //req.CustomerID = strconv.FormatUint(userInfo.ID, 10) res, err := service.BundleProvider.OrderRecordsList(context.Background(), &req) if err != nil { service.Error(c, err) return } for _, orderRecord := range res.OrderRecords { if orderRecord.CustomerID != "" { var userID uint64 userID, err = strconv.ParseUint(orderRecord.CustomerID, 10, 64) if err != nil { err = nil continue } userInfo, _ := service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{ Domain: "app", ID: userID, }) if userInfo != nil { orderRecord.Sex = userInfo.Sex orderRecord.Nationality = userInfo.Nationality orderRecord.CertificatePicture = userInfo.CertificatePicture orderRecord.PlaceOfResidence = userInfo.PlaceOfResidence orderRecord.GroupPhoto = userInfo.GroupPhoto orderRecord.TelNum = userInfo.TelNum } } } service.Success(c, res) } func OrderRecordsDetail(c *gin.Context) { var req bundle.OrderRecordsDetailRequest if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } /*// 获取 用户信息 userInfo := login.GetUserInfoFromC(c) req.CustomerID = strconv.FormatUint(userInfo.ID, 10)*/ res, err := service.BundleProvider.OrderRecordsDetail(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } // web func UpdateFinancialConfirmationStatus(c *gin.Context) { var req bundle.FinancialConfirmationRequest if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } // 不限制 支付状态 未支付 也可确认 //detail, err := service.BundleProvider.OrderRecordsDetail(context.Background(), &bundle.OrderRecordsDetailRequest{ // OrderNo: req.OrderNo, //}) //if err != nil { // service.Error(c, err) // return //} //if detail.OrderRecord.Status != bundleModel.OrderPaid { // service.Error(c, errors.New("订单未支付,不可确认")) // return //} res, err := service.BundleProvider.UpdateFinancialConfirmationStatus(context.Background(), &req) if err != nil { service.Error(c, err) return } service.Success(c, res) } func ExportOrderInfo(c *gin.Context) { var req bundle.OrderRecordsRequest if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.OrderRecordsList(context.Background(), &req) if err != nil { service.Error(c, err) return } rows := make([][]interface{}, 0) for _, orderRecord := range res.OrderRecords { if orderRecord.CustomerID != "" { var userID uint64 userID, err = strconv.ParseUint(orderRecord.CustomerID, 10, 64) if err != nil { err = nil continue } userInfo, _ := service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{ Domain: "app", ID: userID, }) if userInfo != nil { orderRecord.Sex = userInfo.Sex orderRecord.Nationality = userInfo.Nationality orderRecord.TelNum = userInfo.TelNum } } status := "" if orderRecord.Status == bundleModel.OrderSigned { status = "未支付" } else if orderRecord.Status == bundleModel.OrderPaid { status = "已支付" } financialConfirmation := "" if orderRecord.FinancialConfirmation == bundleModel.UnConfirm { financialConfirmation = "未确认" } else if orderRecord.FinancialConfirmation == bundleModel.Confirmed { financialConfirmation = "已确认" } rows = append(rows, []interface{}{ orderRecord.OrderNo, orderRecord.CustomerNum, orderRecord.CustomerName, orderRecord.Sex, orderRecord.TelNum, orderRecord.Nationality, orderRecord.BundleName, orderRecord.SignedTime, orderRecord.Amount, orderRecord.Num, orderRecord.ValueAddBundleAmount, orderRecord.TotalAmount, status, orderRecord.PayTime, financialConfirmation, }) } dirPath := "./runtime" filePath, err := logic.WriteToExcel(dirPath, rows) if err != nil { service.Error(c, err) return } var httpType string = "http" // Default to http // Safely check if Origin exists in c.Keys if origin, exists := c.Keys["Origin"]; exists && origin != nil { originStr, ok := origin.(string) if ok && originStr != "" { fmt.Printf("c.Request.Origin %+v\n", originStr) parts := strings.Split(originStr, ":") if len(parts) > 0 { httpType = parts[0] } } } else { // Fallback: Check if the request was made over TLS if c.Request.TLS != nil || c.Request.Header.Get("X-Forwarded-Proto") == "https" { httpType = "https" } } var exportUrl = strings.Replace(strings.Replace(filePath, ".", fmt.Sprintf("%s://%s", httpType, c.Request.Host), 1), "runtime", "api/fiee/static", 1) //var exportUrl = fmt.Sprintf("%s%s/%s", httpType, c.Request.Host, dirPath + path) fmt.Println("exportUrl : ", exportUrl) service.Success(c, &bundleModel.ExportResponse{ExportUrl: exportUrl}) } func ExportOrderInfoOss(c *gin.Context) { var req bundle.OrderRecordsRequest if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } res, err := service.BundleProvider.OrderRecordsList(context.Background(), &req) if err != nil { service.Error(c, err) return } rows := make([][]interface{}, 0) for _, orderRecord := range res.OrderRecords { if orderRecord.CustomerID != "" { var userID uint64 userID, err = strconv.ParseUint(orderRecord.CustomerID, 10, 64) if err != nil { err = nil continue } userInfo, _ := service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{ Domain: "app", ID: userID, }) if userInfo != nil { orderRecord.Sex = userInfo.Sex orderRecord.Nationality = userInfo.Nationality orderRecord.TelNum = userInfo.TelNum } } status := "" if orderRecord.Status == bundleModel.OrderSigned { status = "未支付" } else if orderRecord.Status == bundleModel.OrderPaid { status = "已支付" } financialConfirmation := "" if orderRecord.FinancialConfirmation == bundleModel.UnConfirm { financialConfirmation = "未确认" } else if orderRecord.FinancialConfirmation == bundleModel.Confirmed { financialConfirmation = "已确认" } rows = append(rows, []interface{}{ orderRecord.OrderNo, orderRecord.CustomerNum, orderRecord.CustomerName, orderRecord.Sex, orderRecord.TelNum, orderRecord.Nationality, orderRecord.BundleName, orderRecord.SignedTime, orderRecord.Amount, orderRecord.Num, orderRecord.ValueAddBundleAmount, orderRecord.TotalAmount, status, orderRecord.PayTime, financialConfirmation, }) } dirPath := "./runtime" filePath, err := logic.WriteToExcel(dirPath, rows) if err != nil { service.Error(c, err) return } exportUrl, err := upload.PutBos(filePath, "excel", true) if err != nil { service.Error(c, err) return } service.Success(c, &bundleModel.ExportResponse{ExportUrl: exportUrl}) }