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" "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 == "" { req.Language = c.GetHeader("Accept-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 expirationDate string var addPriceList []*bundle.AddPriceOptionsInfo var totalAmount float32 for _, svc := range req.AddPriceOptionsList { valueAddInfo, err := service.BundleProvider.ValueAddServiceLangByUuidAndLanguage(context.Background(), &bundle.ValueAddServiceDetailRequest{ Uuid: svc.ValueUid, Language: req.Language, }) if err != nil { service.Error(c, err) return } valuePrice, err := service.BundleProvider.CalculatePrice(context.Background(), &bundle.CalculatePriceRequest{ Uuid: svc.ValueUid, Num: svc.Num, Language: req.Language, }) if err != nil { service.Error(c, err) return } totalAmount += valuePrice.Price addPriceList = append(addPriceList, &bundle.AddPriceOptionsInfo{ ValueUid: valueAddInfo.Uuid, ServiceType: valueAddInfo.ServiceType, CurrencyType: valueAddInfo.PriceType, Amount: valuePrice.Price, Num: svc.Num, Unit: valueAddInfo.Unit, }) // 如果是可用时长服务,计算新的截止日期 todo 不需要计算到期时间 在完成支付时添加 /*if valueAddInfo.ServiceType == 5 { endDate := orderRecordResp.OrderRecord.ExpirationTime if endDate == "9999-12-31" { service.Error(c, errors.New(common.ErrorPermanentPackage)) return } t, err := time.Parse("2006-01-02", endDate) if err != nil { fmt.Println("解析时间出错:", err) return } newDeadline := calculateExpirationDate(t, svc.Num, valueAddInfo.Unit) expirationDate = newDeadline //} }*/ } // 如果没有可用时长服务,使用主套餐截止日期 //if expirationDate == "" { // expirationDate = orderRecordResp.OrderRecord.ExpirationTime //} 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 req.OrderUUID = orderRecordResp.OrderRecord.Uuid // 当前 未将 签名 写入合同中 todo 购买增值服务取消签约合同 //signContract, signContractErr := logic.SignContractV2(req.CustomerNum, bundleDetail.Bundle.Contract, 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(startDate time.Time, num int32, unit string) string { //now := time.Now() switch unit { case "天": return startDate.AddDate(0, 0, int(num)).Format("2006-01-02") case "月": return startDate.AddDate(0, int(num), 0).Format("2006-01-02") case "年": return startDate.AddDate(int(num), 0, 0).Format("2006-01-02") default: return "" } } func CreateBundleOrderSignature(c *gin.Context) { var req bundle.OrderCreateRecord 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 == "" { req.Language = c.GetHeader("Accept-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 } } // 获取 套餐信息 bundleDetailReq := &bundle.BundleDetailRequest{ Uuid: req.BundleUuid, } bundleDetail, detailErr := service.BundleProvider.BundleDetail(context.Background(), bundleDetailReq) if detailErr != nil { service.Error(c, detailErr) return } //获取过期时间和增值服务金额 var addRecords []*bundle.OrderCreateAddRecord var addTotalPrice float32 var expirationDay string for _, i := range req.AddRecords { price, err := service.BundleProvider.CalculatePrice(context.Background(), &bundle.CalculatePriceRequest{ Uuid: i.ValueUid, Num: i.Num, Language: req.Language, }) if err != nil { service.Error(c, err) return } addTotalPrice += price.Price addService, err := service.BundleProvider.ValueAddServiceLangByUuidAndLanguage(context.Background(), &bundle.ValueAddServiceDetailRequest{ Uuid: i.ValueUid, Language: req.Language, }) if err != nil { service.Error(c, err) return } addRecords = append(addRecords, &bundle.OrderCreateAddRecord{ ServiceType: addService.ServiceType, ValueUid: i.ValueUid, CurrencyType: addService.PriceType, Amount: price.Price, Num: i.Num, Unit: addService.Unit, Source: 1, PaymentStatus: 1, }) //服务类型为时长 计算 if addService.ServiceType == 5 { expirationDay = calculateExpirationDate(time.Now(), i.Num, addService.Unit) } else { expirationDay = time.Now().AddDate(0, 0, 7).Format("2006-01-02") } } // 当前 未将 签名 写入合同中 todo 金额和有效时间待修改 signContract, signContractErr := logic.SignContractV2(req.CustomerNum, bundleDetail.Bundle.Contract, addTotalPrice, expirationDay) if signContractErr != nil { service.Error(c, signContractErr) return } req.CustomerNum = userInfo.SubNum req.CustomerName = userInfo.Name req.CustomerID = strconv.FormatUint(userInfo.ID, 10) 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 + addTotalPrice req.ContractNo = common.GenerateContractNo(lastContractNo) req.SignContract = signContract req.SignedTime = common.GetBeijingTime() req.Status = bundleModel.OrderSigned req.AddRecords = addRecords //req.ExpirationTime = expirationDay //过期日期取消 在完成支付是更新 req.PayType = 1 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 OrderRecordsListV2(c *gin.Context) { var req bundle.OrderRecordsRequestV2 if err := c.ShouldBindBodyWith(&req, binding.JSON); err != nil { service.Error(c, err) return } res := &bundle.OrderRecordsResponseV2{} // Step 1: 如果有姓名/电话筛选,先查用户列表 if req.CustomerName != "" { userListResp, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{ BlurNameTel: req.CustomerName, Domain: "app", }) if err != nil { service.Error(c, err) return } if len(userListResp.UserList) == 0 { // 没查到用户,直接返回空结果 res.Page = req.Page res.PageSize = req.PageSize res.Total = 0 service.Success(c, res) return } // 提取用户ID列表 for _, u := range userListResp.UserList { req.UserIds = append(req.UserIds, int64(u.Id)) } } // Step 2: 查询订单列表 orderList, err := service.BundleProvider.OrderRecordsListV2(context.Background(), &req) if err != nil { service.Error(c, err) return } // Step 3: 如果订单不为空,查一次用户信息填充(只查一次) if len(orderList.BundleInfo) > 0 { // 收集订单里的所有用户ID userIdSet := make(map[int64]struct{}) for _, i := range orderList.BundleInfo { userIdSet[i.CustomerId] = struct{}{} } var userIds []int64 for id := range userIdSet { userIds = append(userIds, id) } userListResp, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{ Ids: userIds, Domain: "app", }) if err != nil { service.Error(c, err) return } // 建立用户ID -> 用户信息映射 userMap := make(map[int64]*accountFiee.UserListInfo, len(userListResp.UserList)) for _, u := range userListResp.UserList { userMap[int64(u.Id)] = u } // 填充订单中的用户信息 for _, item := range orderList.BundleInfo { if u, ok := userMap[item.CustomerId]; ok { item.CustomerName = u.Name item.TelNum = u.TelNum } } } service.Success(c, orderList) } 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/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}) }