/* DESCRIPTION: Any functions that are used internally by the use-case */ package patient import ( "fmt" "path/filepath" "strconv" "strings" "time" e "simrs-vx/internal/domain/main-entities/patient" ibpjs "simrs-vx/internal/infra/bpjs" pl "simrs-vx/pkg/logger" pmh "simrs-vx/pkg/minio-helper" puh "simrs-vx/pkg/upload-helper" dg "github.com/karincake/apem/db-gorm-pg" ) func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Patient) error { var inputSrc *e.CreateDto if inputT, ok := any(input).(*e.CreateDto); ok { inputSrc = inputT } else { inputTemp := any(input).(*e.UpdateDto) inputSrc = &inputTemp.CreateDto } if data.Id == 0 { medRecNum, err := GenerateNextMedicalRecordNumber() if err != nil { return err } data.Number = &medRecNum } data.Person_Id = inputSrc.Person_Id data.RegisteredAt = inputSrc.RegisteredAt data.Status_Code = inputSrc.Status_Code data.NewBornStatus = inputSrc.NewBornStatus return nil } func GenerateNextMedicalRecordNumber() (string, error) { var last string err := dg.I. Table("\"Patient\""). Select("\"Number\""). Where("\"Number\" IS NOT NULL AND \"Number\" ~ '^[0-9]+$'"). // Only numeric strings Order("\"Number\"::bigint DESC"). Limit(1). Scan(&last).Error if err != nil { return "", err } var nextInt int64 var format string if last == "" { // No existing records, start with 10 digits nextInt = 1 format = "%010d" } else { n, err := strconv.ParseInt(last, 10, 64) if err != nil { return "", err } nextInt = n + 1 // Dynamically determine format based on existing number digitCount := len(last) // If the incremented number needs more digits, expand format nextStr := strconv.FormatInt(nextInt, 10) if len(nextStr) > digitCount { digitCount = len(nextStr) } // Ensure minimum 10 digits as per requirement if digitCount < 10 { digitCount = 10 } format = fmt.Sprintf("%%0%dd", digitCount) } return fmt.Sprintf(format, nextInt), nil } func uploadAndGenerateFileUrl(input e.UploadDto, event *pl.Event) (string, error) { pl.SetLogInfo(event, input, "started", "uploadAndGenerateFileUrl") bucket := string(input.Code) ext := strings.ToLower(filepath.Ext(input.Filename)) if !puh.IsValidFileType(ext, bucket) { return "", fmt.Errorf("invalid file type: %s", input.Filename) } objectName := fmt.Sprintf("%s%d%s", input.MedRecNumber, time.Now().UnixNano(), ext) uploadInput := pmh.UploadReaderInput{ BucketName: bucket, Name: objectName, File: input.File, Size: input.Size, ContentType: input.MimeType, } _, err := pmh.I.PutObject(uploadInput) if err != nil { return "", err } // Build URL for access publicUrl := pmh.I.GenerateUrl(bucket, objectName) pl.SetLogInfo(event, nil, "complete") return publicUrl, nil } func removeUploadedFile(bucket, fileUrl string, event *pl.Event) error { pl.SetLogInfo(event, nil, "started", "removeUploadedFile") filename, err := pmh.GetFilename(fileUrl) if err != nil { return err } err = pmh.I.RemoveObject(bucket, filename) if err != nil { return err } pl.SetLogInfo(event, nil, "complete") return nil } func endpointMapper(noBpjs string) string { today := getTodayDate() return fmt.Sprintf("%speserta/nokartu?noKartu=%s&tglpelayanan=%s", ibpjs.O.BaseUrl, noBpjs, today) } func getTodayDate() string { return time.Now().Format("2006-01-02") }