package services import ( "errors" "fmt" "net/smtp" "os" "strings" "backendcareit/database" "backendcareit/models" "gorm.io/gorm" ) // SendEmail - Ngirim email pake SMTP bro func SendEmail(to, subject, body string) error { // Ambil konfigurasi dari env variable dulu, lebih aman from := os.Getenv("EMAIL_FROM") password := os.Getenv("EMAIL_PASSWORD") smtpHost := os.Getenv("SMTP_HOST") smtpPort := os.Getenv("SMTP_PORT") // Kalau env variable gak ada, pake default value (biar kompatibel sama versi lama) if from == "" { from = "careit565@gmail.com" } if password == "" { password = "gkhz bjax uamw xydf" } if smtpHost == "" { smtpHost = "smtp.gmail.com" } if smtpPort == "" { smtpPort = "587" } if from == "" || password == "" || smtpHost == "" || smtpPort == "" { return fmt.Errorf("konfigurasi email tidak lengkap. Pastikan EMAIL_FROM, EMAIL_PASSWORD, SMTP_HOST, dan SMTP_PORT sudah di-set") } // Setup authentication auth := smtp.PlainAuth("", from, password, smtpHost) // Format email message msg := []byte(fmt.Sprintf("To: %s\r\n", to) + fmt.Sprintf("Subject: %s\r\n", subject) + "MIME-Version: 1.0\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "\r\n" + body + "\r\n") // Send email addr := fmt.Sprintf("%s:%s", smtpHost, smtpPort) err := smtp.SendMail(addr, auth, from, []string{to}, msg) if err != nil { return fmt.Errorf("gagal mengirim email: %w", err) } return nil } // SendEmailToMultiple - Ngirim email ke banyak orang sekaligus func SendEmailToMultiple(to []string, subject, body string) error { from := os.Getenv("EMAIL_FROM") password := os.Getenv("EMAIL_PASSWORD") smtpHost := os.Getenv("SMTP_HOST") smtpPort := os.Getenv("SMTP_PORT") if from == "" { from = "asikmahdi@gmail.com" } if password == "" { password = "njom rhxb prrj tuoj" } if smtpHost == "" { smtpHost = "smtp.gmail.com" } if smtpPort == "" { smtpPort = "587" } if from == "" || password == "" || smtpHost == "" || smtpPort == "" { return fmt.Errorf("konfigurasi email tidak lengkap") } if len(to) == 0 { return fmt.Errorf("daftar penerima email tidak boleh kosong") } // Setup authentication auth := smtp.PlainAuth("", from, password, smtpHost) // Rapihin header To buat semua penerima toHeader := strings.Join(to, ", ") // Format email message msg := []byte(fmt.Sprintf("To: %s\r\n", toHeader) + fmt.Sprintf("Subject: %s\r\n", subject) + "MIME-Version: 1.0\r\n" + "Content-Type: text/html; charset=UTF-8\r\n" + "\r\n" + body + "\r\n") // Kirim email ke semua orang sekaligus addr := fmt.Sprintf("%s:%s", smtpHost, smtpPort) err := smtp.SendMail(addr, auth, from, to, msg) if err != nil { return fmt.Errorf("gagal mengirim email: %w", err) } return nil } // SendEmailTest - Cuma buat test kirim email ke teman-teman func SendEmailTest() error { to := []string{"stylohype685@gmail.com", "pasaribumonica2@gmail.com", "yestondehaan607@gmail.com"} subject := "Test Email - Sistem Billing Care IT" body := `

Test Email - Sistem Billing Care IT

Halo!

Ini adalah email test dari sistem billing Care IT.

Jika Anda menerima email ini, berarti sistem email berfungsi dengan baik.

Terima kasih!

` if err := SendEmailToMultiple(to, subject, body); err != nil { return fmt.Errorf("gagal mengirim email test: %w", err) } return nil } // SendEmailBillingSignToDokter mengirim email ke semua dokter yang menangani pasien tentang billing sign func SendEmailBillingSignToDokter(idBilling int) error { // 1. Ambil billing berdasarkan ID_Billing var billing models.BillingPasien if err := database.DB.First(&billing, idBilling).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("billing dengan ID_Billing=%d tidak ditemukan", idBilling) } return fmt.Errorf("gagal mengambil billing: %w", err) } // 2. Ambil semua dokter dari billing_dokter var dokterList []models.Dokter if err := database.DB. Table("\"billing_dokter\" bd"). Select("d.*"). Joins("JOIN \"dokter\" d ON bd.\"ID_Dokter\" = d.\"ID_Dokter\""). Where("bd.\"ID_Billing\" = ?", idBilling). Find(&dokterList).Error; err != nil { return fmt.Errorf("gagal mengambil dokter: %w", err) } if len(dokterList) == 0 { return fmt.Errorf("tidak ada dokter yang terkait dengan billing ID_Billing=%d", idBilling) } // 3. Ambil data pasien untuk informasi lengkap var pasien models.Pasien if err := database.DB.Where("\"ID_Pasien\" = ?", billing.ID_Pasien).First(&pasien).Error; err != nil { return fmt.Errorf("gagal mengambil data pasien: %w", err) } // 4. Format billing sign untuk ditampilkan billingSignDisplay := strings.ToUpper(billing.Billing_sign) if billingSignDisplay == "" { billingSignDisplay = "Belum ditentukan" } // Untuk pengiriman ke dokter: kirim personalisasi per dokter (salam pakai nama dokter) // Kumpulkan alamat per dokter dan jalankan pengiriman secara async (goroutine) anyEmail := false subject := fmt.Sprintf("Notifikasi Billing Sign - Pasien: %s", pasien.Nama_Pasien) for _, dokter := range dokterList { // kumpulkan alamat untuk dokter ini addrs := make([]string, 0, 2) if e := strings.TrimSpace(dokter.Email_UB); e != "" { addrs = append(addrs, e) } if e := strings.TrimSpace(dokter.Email_Pribadi); e != "" { // hindari duplikat antara UB dan pribadi if len(addrs) == 0 || addrs[0] != e { addrs = append(addrs, e) } } if len(addrs) == 0 { continue } anyEmail = true // buat body yang dipersonalisasi untuk dokter ini doctorName := dokter.Nama_Dokter if doctorName == "" { doctorName = "Dokter" } bodyForDokter := fmt.Sprintf(`

Notifikasi Billing Sign

Yth. Dr. %s,

Berikut adalah informasi billing sign untuk pasien yang Anda tangani:

Nama Pasien: %s
ID Billing: %d
Ruangan: %s
Kelas: %s
Cara Bayar: %s
Total Tarif RS: Rp %.2f
Total Klaim BPJS: Rp %.2f
Billing Sign: %s

Terima kasih atas perhatiannya.

`, doctorName, pasien.Nama_Pasien, billing.ID_Billing, pasien.Ruangan, pasien.Kelas, billing.Cara_Bayar, billing.Total_Tarif_RS, billing.Total_Klaim, strings.ToLower(billing.Billing_sign), billingSignDisplay) // kirim async ke alamat dokter ini go func(addrs []string, subj, body string, id int) { if err := SendEmailToMultiple(addrs, subj, body); err != nil { fmt.Printf("Warning: Gagal mengirim email ke %v untuk billing %d: %v\n", addrs, id, err) } else { fmt.Printf("Info: Email notifikasi terkirim ke %v untuk billing %d\n", addrs, id) } }(addrs, subject, bodyForDokter, billing.ID_Billing) } if !anyEmail { return fmt.Errorf("tidak ada dokter dengan email yang terdaftar untuk billing ID_Billing=%d", idBilling) } // Return immediately; actual sending berjalan di goroutine return nil }