package logic import ( "encoding/json" "errors" "fmt" "fusenapi/constants" "fusenapi/model/gmodel" "fusenapi/utils/auth" "fusenapi/utils/basic" "fusenapi/utils/pdf" "gorm.io/gorm" "strings" "time" "context" "fusenapi/server/orders/internal/svc" "fusenapi/server/orders/internal/types" "github.com/zeromicro/go-zero/core/logx" ) type GetOrderInvoiceLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext } func NewGetOrderInvoiceLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderInvoiceLogic { return &GetOrderInvoiceLogic{ Logger: logx.WithContext(ctx), ctx: ctx, svcCtx: svcCtx, } } func (l *GetOrderInvoiceLogic) GetOrderInvoice(req *types.GetOrderInvoiceReq, userinfo *auth.UserInfo) (resp *basic.Response) { if userinfo.GetIdType() != auth.IDTYPE_User { return resp.SetStatusWithMessage(basic.CodeUnAuth, "please login first") } //获取用户信息 userModel := gmodel.NewFsUserModel(l.svcCtx.MysqlConn) user, err := userModel.FindUserById(l.ctx, userinfo.UserId) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "user not found") } logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get user info") } if req.Sn == "" { return resp.SetStatusWithMessage(basic.CodeRequestParamsErr, "param sn is required") } //查询订单信息 orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn) orderInfo, err := orderModel.FindOneBySn(l.ctx, userinfo.UserId, req.Sn) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the order is not exists") } logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order info") } //地址数据 var address gmodel.FsAddress if err = json.Unmarshal([]byte(*orderInfo.AddressInfo), &address); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to parse address info") } userName := "" if user.LastName != nil && user.FirstName != nil && *user.LastName != "" && *user.FirstName != "" { userName = *user.LastName + " " + *user.FirstName } else if address.LastName != nil && address.FirstName != nil && *address.LastName != "" && *address.FirstName != "" { userName = *address.LastName + " " + *address.LastName } pdfFileName := *orderInfo.Sn + "_" + userName + "_FusenPack.pdf" //首款 firstPayment := *orderInfo.TotalAmount / 2 amountDue := int64(0) //未完全支付 if *orderInfo.IsPayCompleted == 0 { amountDue = *orderInfo.TotalAmount - firstPayment } var ( secondPaymentHtml string firstStyle1 = `style="padding-bottom: 20px; border-bottom: 1px solid #212121;"` firstStyle2 = `style="width: 16.66%; padding-bottom: 20px; border-bottom: 1px solid #212121;"` payHtml = strings.Builder{} orderHTML strings.Builder totalAmount float64 rowspan = `rowspan = "12"` ) if *orderInfo.IsPayCompleted == 1 { firstStyle1 = "" firstStyle2 = "" rowspan = `rowspan = "14"` remainAmount := float64(*orderInfo.TotalAmount - firstPayment) secondPaymentHtml = strings.ReplaceAll(constants.SECOND_PAYMENY_HTML, "{{remain_amount}}", fmt.Sprintf("%.2f", remainAmount/100)) } //获取订单详情列表 orderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn) orderDetails, err := orderDetailModel.GetOrderDetailsByOrderId(l.ctx, orderInfo.Id) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order details") } if len(orderDetails) == 0 { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order details is empty") } productIds := make([]int64, 0, len(orderDetails)) for _, v := range orderDetails { productIds = append(productIds, *v.ProductId) } //获取产品列表 productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn) productList, err := productModel.GetProductListByIds(l.ctx, productIds, "") if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product list") } mapProduct := make(map[int64]int) for k, v := range productList { mapProduct[v.Id] = k } payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn) payList, err := payModel.GetListByOrderNumber(l.ctx, *orderInfo.Sn) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get payment list") } for _, v := range payList { tem := strings.ReplaceAll(constants.PAYMENT_HTML, "{{pay_amount}}", fmt.Sprintf("%.2f", float64(*v.PayAmount)/100)) tem = strings.ReplaceAll(tem, "{{brand}}", *v.Brand) tem = strings.ReplaceAll(tem, "{{card_no}}", *v.CardNo) payHtml.WriteString(tem) } detailCount := len(orderDetails) for k, v := range orderDetails { amount := float64(*v.Amount) sumAmount := amount * float64(*v.BuyNum) totalAmount += sumAmount var style1, style2 string if k == (detailCount - 1) { style1 = "vertical-align: top;" style2 = "padding-bottom: 20px; border-bottom: 1px solid #212121;" } tem := strings.ReplaceAll(constants.ORDER_HTML, "{{amount}}", fmt.Sprintf("%.2f", amount/100)) tem = strings.ReplaceAll(tem, "{{style1}}", style1) tem = strings.ReplaceAll(tem, "{{style2}}", style2) tem = strings.ReplaceAll(tem, "{{rowspan}}", rowspan) tem = strings.ReplaceAll(tem, "{{buy_num}}", fmt.Sprintf("%d", *v.BuyNum)) tem = strings.ReplaceAll(tem, "{{sum_amount}}", fmt.Sprintf("%.2f", sumAmount/100)) if productIndex, ok := mapProduct[*v.ProductId]; ok { tem = strings.ReplaceAll(tem, "{{product_title}}", *productList[productIndex].Title) } else { tem = strings.ReplaceAll(tem, "{{product_title}}", "") } orderHTML.WriteString(tem) } mainHtml := strings.ReplaceAll(constants.MAIN_INVOICE_HTML, "{{pay_html}}", payHtml.String()) mainHtml = strings.ReplaceAll(mainHtml, "{{amount_due}}", fmt.Sprintf("%.2f", float64(amountDue)/100)) mainHtml = strings.ReplaceAll(mainHtml, "{{second_payment_html}}", secondPaymentHtml) mainHtml = strings.ReplaceAll(mainHtml, "{{total_amount}}", fmt.Sprintf("%.2f", totalAmount/100)) mainHtml = strings.ReplaceAll(mainHtml, "{{first_payment}}", fmt.Sprintf("%.2f", float64(firstPayment)/100)) mainHtml = strings.ReplaceAll(mainHtml, "{{orderHTML}}", orderHTML.String()) mainHtml = strings.ReplaceAll(mainHtml, "{{city}}", *address.City) mainHtml = strings.ReplaceAll(mainHtml, "{{state}}", *address.State) mainHtml = strings.ReplaceAll(mainHtml, "{{zip_code}}", *address.ZipCode) mainHtml = strings.ReplaceAll(mainHtml, "{{street}}", *address.Street) mainHtml = strings.ReplaceAll(mainHtml, "{{suite}}", *address.Suite) mainHtml = strings.ReplaceAll(mainHtml, "{{name}}", userName) mainHtml = strings.ReplaceAll(mainHtml, "{{first_style1}}", firstStyle1) mainHtml = strings.ReplaceAll(mainHtml, "{{first_style2}}", firstStyle2) mainHtml = strings.ReplaceAll(mainHtml, "{{h5Url}}", constants.H5_URL) mainHtml = strings.ReplaceAll(mainHtml, "{{order_sn}}", *orderInfo.Sn) mainHtml = strings.ReplaceAll(mainHtml, "{{order_expire_time}}", time.Unix(*orderInfo.Ctime, req.TimeZone*60).Format("02 Jan,2006")) //html内容页面转pdf的base64 prfBase64, err := pdf.HtmlToPdfBase64(mainHtml, 2) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to generate pdf file") } return resp.SetStatusWithMessage(basic.CodeOK, "success", types.GetOrderInvoiceRsp{ FileName: pdfFileName, Pdf: prfBase64, }) }