dhi_xml/
lib.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3use serde_xml_rs::to_string;
4
5use std::collections::BTreeMap;
6
7mod util;
8
9#[derive(Serialize, Debug)]
10pub struct Header {
11    #[serde(rename(serialize = "MessageID"))]
12    message_id: i64,
13    #[serde(rename(serialize = "SystemID"))]
14    system_id: String,
15}
16
17#[derive(Serialize, Debug)]
18#[serde(rename(serialize = "RequestInput"))]
19pub struct DHIRequest {
20    #[serde(rename(serialize = "ISO8583-87"))]
21    iso_fields: Value,
22}
23
24impl DHIRequest {
25    pub fn new(iso_obj: Value) -> Self {
26        let mut req = DHIRequest {
27            iso_fields: iso_obj,
28        };
29        if req.iso_fields.get("i007") == None {
30            req.iso_fields["i007"] = serde_json::value::Value::String(util::get_mmddhhmmss());
31        }
32        if req.iso_fields.get("i011") == None {
33            req.iso_fields["i011"] = serde_json::value::Value::String(util::gen_stan());
34        }
35        if req.iso_fields.get("i012") == None {
36            req.iso_fields["i012"] = serde_json::value::Value::String(util::get_hhmmss());
37        }
38        if req.iso_fields.get("i013") == None {
39            req.iso_fields["i013"] = serde_json::value::Value::String(util::get_mmdd());
40        }
41        if req.iso_fields.get("i037") == None {
42            req.iso_fields["i037"] = serde_json::value::Value::String(util::gen_rrn());
43        }
44        req
45    }
46
47    pub fn serialize(&self) -> Result<String, serde_xml_rs::Error> {
48        let serialized = to_string(&self)?;
49        let serialized = format!("{:05}{}", serialized.len(), serialized);
50        Ok(serialized)
51    }
52}
53
54#[derive(Deserialize, Debug)]
55#[serde(rename(deserialize = "Result"))]
56#[serde(rename_all = "PascalCase")]
57pub struct DHIResult {
58    code: i32,
59    description: String,
60}
61
62#[derive(Deserialize, Debug)]
63#[serde(rename(deserialize = "RequestResponse"))]
64pub struct DHIResponse {
65    #[serde(rename(deserialize = "Result"))]
66    res: DHIResult,
67
68    #[serde(rename(deserialize = "ISO8583-87"))]
69    iso_fields: BTreeMap<String, String>,
70}
71
72impl DHIResponse {
73    pub fn serialize(&self) -> Result<String, serde_json::error::Error> {
74        let serialized = serde_json::to_string(&self.iso_fields)?;
75        Ok(serialized)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use serde_xml_rs::from_reader;
83
84    #[test]
85    fn dhi_request_new_existing_fields() {
86        let iso_data = r#"{
87            "i000": "0100",
88            "i002": "555544******0895",
89            "i007": "Transmission date & time ",
90            "i011": "STAN",
91            "i012": "hhmmss",
92            "i013": "MMDD",
93            "i037": "Retrieval Reference Number"
94        }"#;
95
96        let r: DHIRequest = DHIRequest::new(serde_json::from_str(&iso_data).unwrap());
97        assert_eq!(
98            r.iso_fields["i007"], "Transmission date & time ",
99            "i007 original value should be left untouched"
100        );
101        assert_eq!(
102            r.iso_fields["i011"], "STAN",
103            "i011 original value should be left untouched"
104        );
105        assert_eq!(
106            r.iso_fields["i012"], "hhmmss",
107            "i012 original value should be left untouched"
108        );
109        assert_eq!(
110            r.iso_fields["i013"], "MMDD",
111            "i013 original value should be left untouched"
112        );
113        assert_eq!(
114            r.iso_fields["i037"], "Retrieval Reference Number",
115            "Provided RRN should be left untouched"
116        );
117    }
118
119    #[test]
120    fn dhi_response_deserialization() {
121        let s = r##"
122        <?xml version="1.0"?>
123        <RequestResponse>
124            <Header/>
125            <Result><Code>0</Code><Description>OK</Description></Result>
126            <ISO8583-87><i000>0110</i000><i002>555544******0961</i002><i003>300000</i003><i004>000000000000</i004><i007>2804114717</i007><i043><![CDATA[IDDQD AM. 341215574     341215574 MSKRU]]></i043><i120>UD038IR0044444CR009ES0048100IA0103510198686</i120></ISO8583-87>"
127        </RequestResponse>
128        "##;
129
130        let resp: DHIResponse = from_reader(s.as_bytes()).unwrap();
131
132        assert_eq!(resp.res.code, 0);
133        assert_eq!(resp.res.description, "OK");
134
135        assert_eq!(resp.iso_fields["i000"], "0110");
136        assert_eq!(resp.iso_fields["i002"], "555544******0961");
137        assert_eq!(resp.iso_fields["i003"], "300000");
138        assert_eq!(resp.iso_fields["i004"], "000000000000");
139        assert_eq!(resp.iso_fields["i007"], "2804114717");
140        assert_eq!(
141            resp.iso_fields["i043"],
142            "IDDQD AM. 341215574     341215574 MSKRU"
143        );
144        assert_eq!(
145            resp.iso_fields["i120"],
146            "UD038IR0044444CR009ES0048100IA0103510198686"
147        );
148
149        assert_eq!(resp.serialize().unwrap(), "{\"i000\":\"0110\",\"i002\":\"555544******0961\",\"i003\":\"300000\",\"i004\":\"000000000000\",\"i007\":\"2804114717\",\"i043\":\"IDDQD AM. 341215574     341215574 MSKRU\",\"i120\":\"UD038IR0044444CR009ES0048100IA0103510198686\"}");
150    }
151}