defmodule DaProductAppWeb.SettlementControllerTest do use DaProductAppWeb.ConnCase import DaProductApp.SettlementsFixtures setup %{conn: conn} do {:ok, conn: put_req_header(conn, "accept", "application/json")} end describe "index" do test "lists all settlements", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlements") assert json_response(conn, 200)["settlements"] |> length() == 1 response = json_response(conn, 200) assert response["total"] == 1 assert response["page"] == 1 assert response["page_size"] == 10 settlement_data = List.first(response["settlements"]) assert settlement_data["id"] == settlement.settlement_id assert settlement_data["amount"] == to_string(settlement.amount) assert settlement_data["status"] == settlement.status end test "filters settlements by status", %{conn: conn} do _settlement1 = settlement_fixture(%{status: "settled"}) _settlement2 = settlement_fixture(%{status: "pending"}) conn = get(conn, ~p"/api/v1/merchant/settlements?status=settled") response = json_response(conn, 200) assert response["total"] == 1 assert List.first(response["settlements"])["status"] == "settled" end end describe "show" do test "shows settlement when exists", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlement/#{settlement.settlement_id}") response = json_response(conn, 200) assert response["id"] == settlement.settlement_id assert response["amount"] == to_string(settlement.amount) assert response["status"] == settlement.status assert response["transaction_count"] == settlement.total_transaction_count end test "returns 404 when settlement does not exist", %{conn: conn} do conn = get(conn, ~p"/api/v1/merchant/settlement/nonexistent") assert json_response(conn, 404)["error"] == "Settlement not found" end end describe "transactions" do test "returns transactions for settlement", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlement/#{settlement.settlement_id}/transactions") response = json_response(conn, 200) assert Map.has_key?(response, "transactions") assert is_list(response["transactions"]) end test "returns 404 for non-existent settlement", %{conn: conn} do conn = get(conn, ~p"/api/v1/merchant/settlement/nonexistent/transactions") assert json_response(conn, 404)["error"] == "Settlement not found" end end describe "summary" do test "returns settlement summary", %{conn: conn} do _settlement1 = settlement_fixture(%{status: "settled", amount: Decimal.new("1000.00")}) _settlement2 = settlement_fixture(%{status: "pending", amount: Decimal.new("500.00")}) conn = get(conn, ~p"/api/v1/merchant/settlement/summary") response = json_response(conn, 200) assert Map.has_key?(response, "total_settled") assert Map.has_key?(response, "pending") assert Map.has_key?(response, "exception_count") assert Map.has_key?(response, "last_settlement_date") end end describe "download" do test "downloads CSV format", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlement/#{settlement.settlement_id}/download?format=csv") assert response(conn, 200) assert get_resp_header(conn, "content-type") == ["text/csv; charset=utf-8"] assert get_resp_header(conn, "content-disposition") == ["attachment; filename=\"settlement_#{settlement.settlement_id}.csv\""] end test "downloads PDF format", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlement/#{settlement.settlement_id}/download?format=pdf") assert response(conn, 200) assert get_resp_header(conn, "content-type") == ["application/pdf; charset=utf-8"] end test "returns error for invalid format", %{conn: conn} do settlement = settlement_fixture() conn = get(conn, ~p"/api/v1/merchant/settlement/#{settlement.settlement_id}/download?format=invalid") assert json_response(conn, 400)["error"] == "Invalid format. Use 'csv' or 'pdf'" end end describe "generate_merchant_settlement_files" do test "generates and returns both CSV and JSON files for valid merchant and date", %{conn: conn} do # Create test data settlement = create_test_settlement_with_transactions() conn = get(conn, "/api/v1/settlements/settlement/#{settlement.merchant_id}/#{Date.to_iso8601(settlement.date)}") assert json_response(conn, 201) response = json_response(conn, 201) assert response["message"] == "Settlement files generated successfully" assert Map.has_key?(response["files"], "csv") assert Map.has_key?(response["files"], "json") assert response["merchant_id"] == settlement.merchant_id assert response["date"] == Date.to_iso8601(settlement.date) # Verify files exist csv_path = response["files"]["csv"]["path"] json_path = response["files"]["json"]["path"] assert File.exists?(csv_path) assert File.exists?(json_path) # Cleanup File.rm!(csv_path) File.rm!(json_path) end test "returns CSV file when Accept header is text/csv", %{conn: conn} do settlement = create_test_settlement_with_transactions() conn = conn |> put_req_header("accept", "text/csv") |> get("/api/v1/settlements/settlement/#{settlement.merchant_id}/#{Date.to_iso8601(settlement.date)}") assert response(conn, 200) assert get_resp_header(conn, "content-type") == ["text/csv; charset=utf-8"] assert get_resp_header(conn, "content-disposition") |> List.first() |> String.contains?("mercury_pay_") end test "returns 400 for invalid date format", %{conn: conn} do conn = get(conn, "/api/v1/settlements/settlement/MERCHANT123/invalid-date") assert json_response(conn, 400) response = json_response(conn, 400) assert response["error"] == "Invalid date format. Use YYYY-MM-DD" end test "returns 400 when no settlement found for merchant and date", %{conn: conn} do conn = get(conn, "/api/v1/settlements/settlement/NONEXISTENT/2025-07-05") assert json_response(conn, 400) response = json_response(conn, 400) assert String.contains?(response["error"], "No settlement found") end end describe "generate_merchant_settlement_csv" do test "generates and serves CSV file directly", %{conn: conn} do settlement = create_test_settlement_with_transactions() conn = get(conn, "/api/v1/settlements/settlement/#{settlement.merchant_id}/#{Date.to_iso8601(settlement.date)}/csv") assert response(conn, 200) assert get_resp_header(conn, "content-type") == ["text/csv; charset=utf-8"] csv_content = response(conn, 200) assert String.contains?(csv_content, "#FileType,QR_Payment_Settlement") assert String.contains?(csv_content, "#Version,1.1") assert String.contains?(csv_content, "QRTransactionID,QRID,TID") end end describe "generate_merchant_settlement_json" do test "generates and serves JSON file directly", %{conn: conn} do settlement = create_test_settlement_with_transactions() conn = get(conn, "/api/v1/settlements/settlement/#{settlement.merchant_id}/#{Date.to_iso8601(settlement.date)}/json") assert response(conn, 200) assert get_resp_header(conn, "content-type") == ["application/json; charset=utf-8"] json_content = response(conn, 200) {:ok, json_data} = Jason.decode(json_content) assert json_data["fileType"] == "QR_Payment_Settlement" assert json_data["version"] == "1.1" assert Map.has_key?(json_data, "transactions") assert Map.has_key?(json_data, "footer") end end # Helper function for controller tests defp create_test_settlement_with_transactions do # Create a settlement with some transactions for testing {:ok, settlement} = DaProductApp.Settlements.create_settlement(%{ settlement_id: "SETT20250705-TEST", merchant_id: "MERCHANT123", date: ~D[2025-07-05], status: "settled", amount: Decimal.new("150.00"), merchant_tag: "TAG123", bank_user_id: "BANK_USER_123", total_transaction_count: 2, gross_settlement_amount: Decimal.new("150.00"), gross_settlement_currency: "AED", mdr_charges: Decimal.new("3.00"), mdr_charges_currency: "AED", tax_on_mdr: Decimal.new("0.15"), tax_on_mdr_currency: "AED", net_settlement_amount: Decimal.new("146.85"), net_settlement_currency: "AED", mismatch_count: 0, provider_id: 1, batch_number: "000001" }) # Create some test transactions for i <- 1..2 do {:ok, _transaction} = DaProductApp.Repo.insert( DaProductApp.Settlements.SettlementTransaction.changeset(%DaProductApp.Settlements.SettlementTransaction{}, %{ settlement_id: settlement.id, transaction_id: "test_txn_#{i}", qr_id: "QR123", terminal_id: "TID123", transaction_amount: Decimal.new("75.00"), transaction_currency: "AED", transaction_status: "SUCCESS", transaction_time: ~U[2025-07-05 12:30:00Z], mdr_charge: Decimal.new("1.50"), mdr_charge_currency: "AED", tax_on_mdr: Decimal.new("0.075"), tax_on_mdr_currency: "AED", net_received_amount: Decimal.new("73.425"), net_received_currency: "AED" }) ) end settlement end describe "create_ycs_settlement" do test "creates YCS settlement when provider-wise batch number is disabled", %{conn: conn} do # Temporarily disable provider-wise batch number for this test Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: false) settlement_params = %{ "merchant_id" => "TEST_MERCHANT_YCS", "amount" => "1000.00", "status" => "pending", "date" => Date.to_iso8601(Date.utc_today()), "provider_id" => 2 } conn = post(conn, ~p"/api/v1/settlements/ycs/create", settlement_params) response = json_response(conn, 201) assert response["status"] == "created" assert response["batch_number"] == 1 assert response["message"] == "YCS settlement created successfully with batch number assignment" assert Map.has_key?(response, "settlement_id") # Reset configuration Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: true) end test "increments batch number for subsequent YCS settlements", %{conn: conn} do # Temporarily disable provider-wise batch number for this test Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: false) merchant_id = "TEST_MERCHANT_YCS_INCREMENT" # Create first settlement settlement_params1 = %{ "merchant_id" => merchant_id, "amount" => "1000.00", "status" => "pending", "date" => Date.to_iso8601(Date.utc_today()), "provider_id" => 2 } conn1 = post(conn, ~p"/api/v1/settlements/ycs/create", settlement_params1) response1 = json_response(conn1, 201) assert response1["batch_number"] == 1 # Create second settlement settlement_params2 = %{ "merchant_id" => merchant_id, "amount" => "2000.00", "status" => "pending", "date" => Date.to_iso8601(Date.utc_today()), "provider_id" => 2 } conn2 = post(conn, ~p"/api/v1/settlements/ycs/create", settlement_params2) response2 = json_response(conn2, 201) assert response2["batch_number"] == 2 # Reset configuration Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: true) end test "returns error when provider-wise batch number is enabled", %{conn: conn} do # Ensure provider-wise batch number is enabled Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: true) settlement_params = %{ "merchant_id" => "TEST_MERCHANT", "amount" => "1000.00", "status" => "pending" } conn = post(conn, ~p"/api/v1/settlements/ycs/create", settlement_params) response = json_response(conn, 400) assert response["error"] == "YCS settlement creation not available when provider-wise batch number is enabled" end test "returns error when merchant_id is missing", %{conn: conn} do # Temporarily disable provider-wise batch number for this test Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: false) settlement_params = %{ "amount" => "1000.00", "status" => "pending" } conn = post(conn, ~p"/api/v1/settlements/ycs/create", settlement_params) response = json_response(conn, 400) assert response["error"] == "merchant_id is required" # Reset configuration Application.put_env(:da_product_app, :batch_settings, provider_wise_batch_number_enabled: true) end end end