defmodule DaProductAppWeb.QRController do use DaProductAppWeb, :controller require Logger #@default_provider "aani" @default_provider "alipay" def generate(conn, %{"device_id" => device_id, "amount" => amount_param} = params) do provider_key = Map.get(params, "provider", @default_provider) Logger.info("QR code request for device=#{device_id} amount=#{amount_param} via #{provider_key}") amount = parse_amount(conn, amount_param) amount = amount * 100 with {:ok, mod} <- DaProductApp.QRProviderFactory.fetch(provider_key), {:ok, qrcode} <- mod.generate(device_id, amount), true <- PlatformCore.DeviceRegistry.is_online?(device_id) do topic = "cmd/qr-device/#{device_id}" payload = Jason.encode!(%{amount: amount, qrcode: qrcode, ts: System.system_time(:second)}) Logger.info("Publishing to #{topic}: #{payload}") case DaProductApp.MQTT.publish(topic, payload, qos: 1) do {:ok, _ref} -> conn |> put_status(:ok) |> json(%{status: "sent", device: device_id}) {:error, reason} -> Logger.error("Publish failed: #{inspect(reason)}") conn |> put_status(:service_unavailable) |> json(%{error: "publish_failed"}) end else {:error, :unknown_provider} -> conn |> put_status(:bad_request) |> json(%{error: "unsupported_provider"}) {:error, reason} -> conn |> put_status(:internal_server_error) |> json(%{error: inspect(reason)}) false -> conn |> put_status(:not_found) |> json(%{error: "device_offline"}) end end defp parse_amount(conn, amount) when is_integer(amount) or is_float(amount), do: amount defp parse_amount(conn, amount) when is_binary(amount) do case Integer.parse(amount) do {int, ""} -> int _ -> case Float.parse(amount) do {flt, ""} -> flt _ -> conn |> put_status(:bad_request) |> json(%{error: "invalid_amount"}) |> halt() end end end defp parse_amount(conn, _amount) do conn |> put_status(:bad_request) |> json(%{error: "invalid_amount"}) |> halt() end end