| 1 |
|
defmodule DaProductApp.QRValidation.Parser.ValQrParser do |
| 2 |
|
@moduledoc """ |
| 3 |
|
Parses ReqValQr / RespValQr XML into normalized maps for persistence. |
| 4 |
|
NOTE: Minimal subset implemented; extend as needed per spec. |
| 5 |
|
""" |
| 6 |
|
import SweetXml |
| 7 |
|
|
| 8 |
|
@type parsed :: map() |
| 9 |
|
|
| 10 |
|
@spec parse_req(String.t()) :: {:ok, parsed()} | {:error, term()} |
| 11 |
|
def parse_req(xml) when is_binary(xml) do |
| 12 |
:-( |
try do |
| 13 |
:-( |
doc = SweetXml.parse(xml) |
| 14 |
|
{:ok, |
| 15 |
|
%{ |
| 16 |
|
kind: :req_val_qr, |
| 17 |
|
msg_id: xpath(doc, ~x"//Head/@msgId"s), |
| 18 |
|
org_id: xpath(doc, ~x"//Head/@orgId"s), |
| 19 |
|
txn_id: xpath(doc, ~x"//Txn/@id"s), |
| 20 |
|
payer_addr: xpath(doc, ~x"//Payer/@addr"s), |
| 21 |
|
payer_name: xpath(doc, ~x"//Payer/@name"s), |
| 22 |
|
ver_token: nil, |
| 23 |
|
raw_xml: xml |
| 24 |
|
}} |
| 25 |
|
rescue |
| 26 |
:-( |
e -> {:error, {:parse_error, e}} |
| 27 |
|
end |
| 28 |
|
end |
| 29 |
|
|
| 30 |
|
@spec parse_resp(String.t()) :: {:ok, parsed()} | {:error, term()} |
| 31 |
|
def parse_resp(xml) when is_binary(xml) do |
| 32 |
:-( |
try do |
| 33 |
:-( |
doc = SweetXml.parse(xml) |
| 34 |
:-( |
fx_nodes = xpath(doc, ~x"//FxList/Fx"l) |
| 35 |
|
|
| 36 |
:-( |
fx_quotes = |
| 37 |
|
Enum.map(fx_nodes, fn node -> |
| 38 |
:-( |
%{ |
| 39 |
|
base_currency: xpath(node, ~x"./@baseCurr"s), |
| 40 |
|
base_amount: to_decimal(xpath(node, ~x"./@baseAmount"s)), |
| 41 |
|
fx_rate: to_decimal(xpath(node, ~x"./@Fx"s)), |
| 42 |
|
markup_pct: to_decimal(xpath(node, ~x"./@Mkup"s)), |
| 43 |
|
active: xpath(node, ~x"./@active"s) |> active_flag(), |
| 44 |
|
last_modified_ts: parse_dt(xpath(node, ~x"./@lastModifedTs"s)) |
| 45 |
|
} |
| 46 |
|
end) |
| 47 |
|
|
| 48 |
|
{:ok, |
| 49 |
|
%{ |
| 50 |
|
kind: :resp_val_qr, |
| 51 |
|
msg_id: xpath(doc, ~x"//Head/@msgId"s), |
| 52 |
|
org_id: xpath(doc, ~x"//Head/@orgId"s), |
| 53 |
|
txn_id: xpath(doc, ~x"//Txn/@id"s), |
| 54 |
|
ver_token: xpath(doc, ~x"//Qr/@verToken"s), |
| 55 |
|
payer_addr: xpath(doc, ~x"//Payee/@addr"s), |
| 56 |
|
payer_name: xpath(doc, ~x"//Payee/@name"s), |
| 57 |
|
fx_quotes: fx_quotes, |
| 58 |
|
raw_xml: xml |
| 59 |
|
}} |
| 60 |
|
rescue |
| 61 |
:-( |
e -> {:error, {:parse_error, e}} |
| 62 |
|
end |
| 63 |
|
end |
| 64 |
|
|
| 65 |
:-( |
defp to_decimal(""), do: nil |
| 66 |
:-( |
defp to_decimal(nil), do: nil |
| 67 |
|
defp to_decimal(str) do |
| 68 |
:-( |
case Decimal.parse(str) do |
| 69 |
:-( |
{:ok, dec} -> dec |
| 70 |
:-( |
:error -> nil |
| 71 |
|
end |
| 72 |
|
end |
| 73 |
|
|
| 74 |
:-( |
defp active_flag("TRUE"), do: true |
| 75 |
:-( |
defp active_flag("true"), do: true |
| 76 |
:-( |
defp active_flag(_), do: false |
| 77 |
|
|
| 78 |
:-( |
defp parse_dt(""), do: nil |
| 79 |
:-( |
defp parse_dt(nil), do: nil |
| 80 |
|
defp parse_dt(str) do |
| 81 |
:-( |
case DateTime.from_iso8601(str) do |
| 82 |
:-( |
{:ok, dt, _} -> dt |
| 83 |
:-( |
_ -> nil |
| 84 |
|
end |
| 85 |
|
end |
| 86 |
|
end |