pakasir_sdk/
simulation.rs1use reqwest::Method;
26use serde::Serialize;
27
28use crate::client::Client;
29use crate::constants::PATH_PAYMENT_SIMULATION;
30use crate::error::{Error, Result};
31
32#[derive(Debug, Clone)]
36pub struct SimulationService {
37 client: Client,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
42pub struct PayRequest {
43 pub order_id: String,
45 pub amount: i64,
47}
48
49#[derive(Debug, Serialize)]
52struct RequestBody<'a> {
53 project: &'a str,
54 order_id: &'a str,
55 amount: i64,
56 api_key: &'a str,
57}
58
59impl SimulationService {
60 pub fn new(client: Client) -> Self {
62 Self { client }
63 }
64
65 pub async fn pay(&self, request: &PayRequest) -> Result<()> {
71 if request.order_id.is_empty() {
72 return Err(Error::invalid_order_id(self.client.language()));
73 }
74 if request.amount <= 0 {
75 return Err(Error::invalid_amount(self.client.language()));
76 }
77
78 let body = serde_json::to_vec(&RequestBody {
79 project: self.client.project(),
80 order_id: &request.order_id,
81 amount: request.amount,
82 api_key: self.client.api_key(),
83 })
84 .map_err(|err| Error::encode_json(self.client.language(), err))?;
85
86 self.client
87 .do_request(Method::POST, PATH_PAYMENT_SIMULATION, Some(body))
88 .await
89 .map(|_| ())
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::Language;
97
98 fn dummy_client(language: Language) -> Client {
101 Client::builder("project", "key")
102 .base_url("http://127.0.0.1:1")
103 .retries(0)
104 .language(language)
105 .build()
106 }
107
108 #[tokio::test]
109 async fn pay_rejects_empty_order_id_with_localized_message() {
110 let service = SimulationService::new(dummy_client(Language::English));
111 let err = service
112 .pay(&PayRequest {
113 order_id: String::new(),
114 amount: 1,
115 })
116 .await
117 .unwrap_err();
118 assert!(matches!(err, Error::InvalidOrderId { .. }));
119 assert_eq!(err.to_string(), "order ID is required");
120
121 let service = SimulationService::new(dummy_client(Language::Indonesian));
122 let err = service
123 .pay(&PayRequest {
124 order_id: String::new(),
125 amount: 1,
126 })
127 .await
128 .unwrap_err();
129 assert_eq!(err.to_string(), "ID pesanan wajib diisi");
130 }
131
132 #[tokio::test]
133 async fn pay_rejects_non_positive_amount() {
134 let service = SimulationService::new(dummy_client(Language::English));
135 for amount in [0_i64, -1, i64::MIN] {
136 let err = service
137 .pay(&PayRequest {
138 order_id: "x".into(),
139 amount,
140 })
141 .await
142 .unwrap_err();
143 assert!(
144 matches!(err, Error::InvalidAmount { .. }),
145 "amount={amount}"
146 );
147 }
148 }
149
150 #[test]
151 fn simulation_service_is_clone() {
152 let service = SimulationService::new(dummy_client(Language::English));
154 let _ = service.clone();
155 }
156}