defmodule DaProductApp.Services.YspNotificationServiceTest do use DaProductApp.DataCase import DaProductApp.DataCase alias DaProductApp.Services.YspNotificationService alias DaProductApp.Transactions.Transaction alias DaProductApp.YspNotificationLog alias DaProductApp.YspConfiguration alias DaProductApp.BatchNumber alias DaProductApp.Repo setup do # Create test configuration config_attrs = %{ merchant_id: "test_merchant", notification_url: "http://test.example.com/webhook", merchant_tag: "TEST_TAG", bank_user_id: "TEST_BANK_123", terminal_id: "TEST_TERMINAL_001", shop_id: "TEST_SHOP_001", cash_desk_id: "TEST_DESK_001", max_retry_attempts: 3, retry_interval_seconds: 30, is_active: true } {:ok, config} = %YspConfiguration{} |> YspConfiguration.changeset(config_attrs) |> Repo.insert() # Create test transaction transaction_attrs = %{ transaction_refid: "test_refid_123", amount: 500, m_ref_num: "m_test123", device_id: "DEV001", provider_name: "alipay", status: "pending", payment_reference_id: "ALIPAY_PAY_123456", merchant_id: "test_merchant" } {:ok, transaction} = %Transaction{} |> Transaction.changeset(transaction_attrs) |> Repo.insert() %{transaction: transaction, config: config} end describe "send_notification/3" do test "creates notification log and queues notification for successful payment", %{transaction: transaction, config: config} do payment_params = %{ "paymentResult" => %{ "resultCode" => "SUCCESS", "resultStatus" => "S", "resultMessage" => "Transaction completed successfully" }, "paymentAmount" => %{ "value" => "500", "currency" => "AED" }, "settlementAmount" => %{ "value" => "500", "currency" => "AED" }, "qrCodeTransactionId" => "alipay_qr_123456", "paymentTime" => "2025-06-01T12:35:00+05:30" } # Mock HTTPoison to avoid actual HTTP calls during testing # In a real test environment, you would use a mocking library like Mox result = YspNotificationService.send_notification(transaction.payment_reference_id, payment_params) assert {:ok, "Notification queued successfully"} = result # Verify notification log was created notification_log = Repo.get_by(YspNotificationLog, payment_id: transaction.payment_reference_id) assert notification_log != nil assert notification_log.status == :pending assert notification_log.notification_url == config.notification_url assert notification_log.max_attempts == 3 # Verify batch number was created batch_record = Repo.get_by(BatchNumber, merchant_id: "test_merchant") assert batch_record != nil assert batch_record.batch_number == "000001" end test "does not send notification when resultCode is not SUCCESS", %{transaction: transaction} do payment_params = %{ "paymentResult" => %{ "resultCode" => "FAILED", "resultStatus" => "S", "resultMessage" => "Transaction failed" } } result = YspNotificationService.send_notification(transaction.payment_reference_id, payment_params) assert {:ok, "Conditions not met for notification"} = result # Verify no notification log was created notification_log = Repo.get_by(YspNotificationLog, payment_id: transaction.payment_reference_id) assert notification_log == nil end test "does not send notification when resultStatus is not S", %{transaction: transaction} do payment_params = %{ "paymentResult" => %{ "resultCode" => "SUCCESS", "resultStatus" => "F", "resultMessage" => "Transaction failed" } } result = YspNotificationService.send_notification(transaction.payment_reference_id, payment_params) assert {:ok, "Conditions not met for notification"} = result # Verify no notification log was created notification_log = Repo.get_by(YspNotificationLog, payment_id: transaction.payment_reference_id) assert notification_log == nil end test "returns error when transaction not found" do payment_params = %{ "paymentResult" => %{ "resultCode" => "SUCCESS", "resultStatus" => "S" } } result = YspNotificationService.send_notification("NON_EXISTENT_PAYMENT_ID", payment_params) assert {:error, "Transaction not found"} = result end end describe "send_notification_from_polling/3" do test "creates notification log for successful polling result", %{transaction: transaction} do inquiry_response = %{ "result" => %{ "paymentResult" => %{ "resultCode" => "SUCCESS", "resultStatus" => "S" } } } payment_result = %{ "resultCode" => "SUCCESS", "resultStatus" => "S", "resultMessage" => "Payment completed" } result = YspNotificationService.send_notification_from_polling(transaction.m_ref_num, inquiry_response, payment_result) assert {:ok, "Notification queued successfully"} = result # Verify notification log was created notification_log = Repo.get_by(YspNotificationLog, payment_id: transaction.payment_reference_id) assert notification_log != nil assert notification_log.status == :pending end test "handles string payment result from polling", %{transaction: transaction} do inquiry_response = %{} payment_result = "PAYMENT_SUCCESS" result = YspNotificationService.send_notification_from_polling(transaction.m_ref_num, inquiry_response, payment_result) assert {:ok, "Notification queued successfully"} = result # Verify notification log was created notification_log = Repo.get_by(YspNotificationLog, payment_id: transaction.payment_reference_id) assert notification_log != nil assert notification_log.status == :pending end end describe "BatchNumber functionality" do test "creates and increments batch numbers correctly" do merchant_id = "test_merchant_batch" date = Date.utc_today() # First batch number should be 000001 {:ok, batch1} = BatchNumber.get_or_create_batch_number(merchant_id, date) assert batch1 == "000001" # Second batch number should be 000002 {:ok, batch2} = BatchNumber.get_or_create_batch_number(merchant_id, date) assert batch2 == "000002" # Verify database record batch_record = Repo.get_by(BatchNumber, merchant_id: merchant_id, date: date) assert batch_record.transaction_count == 2 assert batch_record.batch_number == "000002" end test "different merchants have separate batch numbers" do date = Date.utc_today() {:ok, batch1} = BatchNumber.get_or_create_batch_number("merchant_1", date) {:ok, batch2} = BatchNumber.get_or_create_batch_number("merchant_2", date) assert batch1 == "000001" assert batch2 == "000001" end end describe "YspConfiguration" do test "get_config_for_merchant returns specific config when available", %{config: config} do result = YspConfiguration.get_config_for_merchant("test_merchant") assert result.id == config.id assert result.merchant_tag == "TEST_TAG" end test "get_config_for_merchant falls back to default when merchant not found" do # Ensure no duplicate default config exists Repo.delete_all(from c in YspConfiguration, where: c.merchant_id == "default") # Create default configuration default_attrs = %{ merchant_id: "default", notification_url: "http://default.example.com/webhook", merchant_tag: "DEFAULT_TAG", is_active: true } {:ok, _default_config} = %YspConfiguration{} |> YspConfiguration.changeset(default_attrs) |> Repo.insert() result = YspConfiguration.get_config_for_merchant("non_existent_merchant") assert result != nil assert result.merchant_id == "default" assert result.merchant_tag == "DEFAULT_TAG" end end end