feat(dimentorin): Midtrans payment provider (sandbox VA + QRIS)

- Env: MIDTRANS_MERCHANT_ID / CLIENT_KEY / SERVER_KEY (masked in Debug)
- midtrans_provider: Core API v2/charge for bank_transfer (VA BCA) and qris (gopay)
- PaymentServiceImpl: when MIDTRANS_MERCHANT_ID set -> provider=midtrans, external_ref = real VA number / QR string; falls back to manual refs otherwise
- SMTP: Google app password working (send-otp 200, OTP stored)
- E2E verified (sandbox): VA externalRef=47329093597744219189188, QRIS qr_string EMVCo, confirm->paid
- Credentials stored in BWS (dimentorin_midtrans_*, dimentorin_smtp_*)
This commit is contained in:
asepharyana
2026-08-05 13:34:59 +07:00
parent 2ea6cd3d17
commit 9214b32139
6 changed files with 163 additions and 2 deletions
@@ -75,7 +75,37 @@ impl PaymentService for PaymentServiceImpl {
let rate = mentor.mentoring_rate.unwrap_or(50_000.0).round() as i64;
let total = rate + SERVICE_FEE;
let method = cmd.method.clone();
let provider = "manual".to_string(); // swap to midtrans/xendit later
// Use Midtrans when credentials are configured; fall back to manual refs.
let midtrans = imphnen_libs::environment::ENV.midtrans_merchant_id.clone();
let (provider, external_ref) = if !midtrans.is_empty() {
let server_key = imphnen_libs::environment::ENV.midtrans_server_key.clone();
let order_id = format!("DM-{}", Uuid::new_v4());
match method.as_str() {
"va" => {
let va =
crate::payments::application::midtrans_provider::create_va_charge(
&order_id,
total,
"bca",
&server_key,
)
.await?;
("midtrans".to_string(), Some(va))
}
"qris" => {
let qr = crate::payments::application::midtrans_provider::create_qris_charge(
&order_id,
total,
&server_key,
)
.await?;
("midtrans".to_string(), Some(qr))
}
_ => ("manual".to_string(), Some(generate_external_ref(&method, session_id))),
}
} else {
("manual".to_string(), Some(generate_external_ref(&method, session_id)))
};
let expires_at = Utc::now() + Duration::hours(24);
let payment = PaymentEntity {
@@ -89,7 +119,7 @@ impl PaymentService for PaymentServiceImpl {
method: method.clone(),
provider,
status: "pending".into(),
external_ref: Some(generate_external_ref(&method, session_id)),
external_ref,
expires_at,
created_at: Utc::now(),
paid_at: None,