package iot import ( "context" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/batchmetadata" "strings" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/batchimport" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/logic/iot/simcardbatch/renew" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/iot_excelize" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/xuri/excelize/v2" ) func (s *sIotTSimCardRenew) DownloadExcelTemplate(ctx context.Context) error { f := excelize.NewFile() defer func() { _ = f.Close() }() headers := renew.ExcelTemplateHeaders() if err := f.SetSheetRow("Sheet1", "A1", &headers); err != nil { return err } widths := map[string]float64{ "A": 22, "B": 20, "C": 20, "D": 18, "E": 18, } for column, width := range widths { if err := f.SetColWidth("Sheet1", column, column, width); err != nil { return err } } if err := iot_excelize.ApplyHeaderColumnsTextStyle(f); err != nil { return err } return iot_excelize.WriteHTTP(ctx, f, "sim_card_renew_template") } // SubmitExcel creates an asynchronous renew prepare batch. The worker performs // database validation, including the six-month expiry window and latest pending // subscription selection. The formal renew batch is created after confirmation. func (s *sIotTSimCardRenew) SubmitExcel(ctx context.Context, in *model.TSimCardRenewExcelSubmitParam) (*model.TSimCardRenewExcelSubmitRes, error) { if in == nil { in = &model.TSimCardRenewExcelSubmitParam{} } file, err := s.getRenewUploadFile(ctx) if err != nil { return nil, err } excelProcessor := renew.NewPrepareExcelProcessor() req := batchimport.SubmitRequest{ SourceChannel: batchmetadata.Console, ExecutionMode: batchmetadata.Bulk, File: file, SourceType: consts.BatchSourceTypeFile, Operator: currentOperator(ctx), BeforeSave: func(ctx context.Context, tx gdb.TX, request *batchimport.SubmitRequest, rows []batchimport.Row) error { opts := excelProcessor.ExcelSubmitOptions() if opts == nil { if reason := firstRenewExcelRowReason(rows); reason != "" { return gerror.New(reason) } return gerror.New("续费年限不能为空") } isTop, _, err := service.AgentDept().IsTopDept(ctx) if err != nil { return gerror.Wrap(err, "校验续费付款方式失败") } paymentMode, err := normalizeRenewPaymentMode(opts.PaymentMode, isTop) if err != nil { return err } opts.PaymentMode = paymentMode request.BizParams = opts.ToBatchSubmitParam() return nil }, } result, err := batchimport.CreatePendingUpload(ctx, req, excelProcessor, batchimport.PendingOptions{ PrepareRows: func(ctx context.Context, rows []batchimport.Row) error { if len(rows) == 0 { return nil } return excelProcessor.ValidateRows(ctx, rows) }, }) if err != nil { return nil, err } res := renewExcelSubmitResult(result) if result.ImportStatus == consts.ImportStatusSuccess { publishPendingExecute(ctx, result.BatchNo, consts.BatchTypePrepare, contexts.GetTenantId(ctx)) } return res, nil } func (s *sIotTSimCardRenew) getRenewUploadFile(ctx context.Context) (*ghttp.UploadFile, error) { r := g.RequestFromCtx(ctx) if r == nil { return nil, gerror.New("current context is not an HTTP request") } file := r.GetUploadFile("file") if file == nil { return nil, gerror.New("please select upload file") } return file, nil } func renewExcelSubmitResult(result *batchimport.Result) *model.TSimCardRenewExcelSubmitRes { if result == nil { return &model.TSimCardRenewExcelSubmitRes{} } res := &model.TSimCardRenewExcelSubmitRes{ BatchNo: result.BatchNo, BatchType: result.BatchType, TargetBatchType: consts.BatchTypeRenew, Status: result.ImportStatus, BatchAsyncStatus: consts.BatchAsyncStatusPending, RunResult: consts.BatchRunResultPending, Total: result.TotalRows, ResultDownloadId: result.ResultDownloadId, ResultFileOssId: result.ResultFileOssId, FailReason: result.FailReason, } if result.ImportStatus != consts.ImportStatusSuccess { res.BatchAsyncStatus = consts.BatchAsyncStatusFailed res.RunResult = consts.BatchRunResultFailed } return res } func firstRenewExcelRowReason(rows []batchimport.Row) string { for _, item := range rows { row, ok := item.(*renew.Row) if !ok || row == nil { continue } if reason := strings.TrimSpace(row.Reason); reason != "" { return reason } } return "" }