diff --git a/app/controllers/concerns/api_errors.rb b/app/controllers/concerns/api_errors.rb index 102245148bb..b0f9463eff7 100644 --- a/app/controllers/concerns/api_errors.rb +++ b/app/controllers/concerns/api_errors.rb @@ -57,6 +57,20 @@ def method_not_allowed_error(code:) ) end + def thirdpary_error(error:) + render( + json: { + status: 422, + error: 'Unprocessable Entity', + code: 'third_party_error', + error_details: { + third_party: error.third_party, + thirdparty_error: error.error_message + } + } + ) + end + def render_error_response(error_result) case error_result.error when BaseService::NotFoundFailure @@ -69,6 +83,8 @@ def render_error_response(error_result) forbidden_error(code: error_result.error.code) when BaseService::UnauthorizedFailure unauthorized_error(message: error_result.error.message) + when BaseService::ThirdPartyFailure + thirdpary_error(error: error_result.error) else raise(error_result.error) end diff --git a/app/services/base_service.rb b/app/services/base_service.rb index 44a7de04999..33a3756e148 100644 --- a/app/services/base_service.rb +++ b/app/services/base_service.rb @@ -93,6 +93,17 @@ def initialize(result, message:) end end + class ThirdPartyFailure < FailedResult + attr_reader :third_party, :error_message + + def initialize(result, third_party:, error_message:) + @third_party = third_party + @error_message = error_message + + super(result, "#{third_party}: #{error_message}") + end + end + class Result < OpenStruct attr_reader :error @@ -150,6 +161,10 @@ def unauthorized_failure!(message: "unauthorized") fail_with_error!(UnauthorizedFailure.new(self, message:)) end + def third_party_failure!(third_party:, error_message:) + fail_with_error!(ThirdPartyFailure.new(self, third_party:, error_message:)) + end + def raise_if_error! return self if success? diff --git a/app/services/invoices/payments/cashfree_service.rb b/app/services/invoices/payments/cashfree_service.rb index c7d9331a727..09982b65566 100644 --- a/app/services/invoices/payments/cashfree_service.rb +++ b/app/services/invoices/payments/cashfree_service.rb @@ -44,7 +44,8 @@ def generate_payment_url result rescue LagoHttpClient::HttpError => e deliver_error_webhook(e) - result.service_failure!(code: e.error_code, message: e.error_body) + + result.third_party_failure!(third_party: "Cashfree", error_message: e.error_body) end private diff --git a/app/services/invoices/payments/generate_payment_url_service.rb b/app/services/invoices/payments/generate_payment_url_service.rb index 03abd0d08bd..bd4d7254cc2 100644 --- a/app/services/invoices/payments/generate_payment_url_service.rb +++ b/app/services/invoices/payments/generate_payment_url_service.rb @@ -22,6 +22,7 @@ def call payment_url_result = Invoices::Payments::PaymentProviders::Factory.new_instance(invoice:).generate_payment_url return payment_url_result unless payment_url_result.success? + return payment_url_result if payment_url_result.error.is_a?(BaseService::ThirdPartyFailure) if payment_url_result.payment_url.blank? return result.single_validation_failure!(error_code: 'payment_provider_error') diff --git a/spec/services/invoices/payments/cashfree_service_spec.rb b/spec/services/invoices/payments/cashfree_service_spec.rb index 07c45ef7cc4..dd9706e4e39 100644 --- a/spec/services/invoices/payments/cashfree_service_spec.rb +++ b/spec/services/invoices/payments/cashfree_service_spec.rb @@ -168,6 +168,7 @@ describe ".generate_payment_url" do let(:payment_links_response) { Net::HTTPResponse.new("1.0", "200", "OK") } + let(:payment_links_body) { {link_url: "https://payments-test.cashfree.com/links//U1mgll3c0e9g"}.to_json } before do cashfree_payment_provider @@ -178,7 +179,7 @@ allow(cashfree_client).to receive(:post_with_response) .and_return(payment_links_response) allow(payment_links_response).to receive(:body) - .and_return({link_url: "https://payments-test.cashfree.com/links//U1mgll3c0e9g"}.to_json) + .and_return(payment_links_body) end it "generates payment url" do @@ -206,5 +207,35 @@ expect(result.payment_url).to be_nil end end + + context 'when payment url failed to generate' do + let(:payment_links_response) { Net::HTTPResponse.new("1.0", "400", "Bad Request") } + let(:payment_links_body) do + { + message: "Currency USD is not enabled", + code: "link_post_failed", + type: "invalid_request_error" + }.to_json + end + + before do + cashfree_payment_provider + cashfree_customer + + allow(LagoHttpClient::Client).to receive(:new) + .and_return(cashfree_client) + allow(cashfree_client).to receive(:post_with_response) + .and_raise(::LagoHttpClient::HttpError.new(payment_links_response.code, payment_links_body, nil)) + end + + it 'returns a third party error' do + result = cashfree_service.generate_payment_url + + expect(result).not_to be_success + expect(result.error).to be_a(BaseService::ThirdPartyFailure) + expect(result.error.third_party).to eq('Cashfree') + expect(result.error.error_message).to eq(payment_links_body) + end + end end end diff --git a/spec/services/invoices/payments/generate_payment_url_service_spec.rb b/spec/services/invoices/payments/generate_payment_url_service_spec.rb index 7d26d8f26c6..d47a9d726be 100644 --- a/spec/services/invoices/payments/generate_payment_url_service_spec.rb +++ b/spec/services/invoices/payments/generate_payment_url_service_spec.rb @@ -87,5 +87,39 @@ end end end + + context 'when provider service return a third party error' do + let(:payment_provider) { 'cashfree' } + let(:code) { 'cashfree_1' } + + let(:payment_provider_service) { instance_double(PaymentRequests::Payments::CashfreeService) } + + let(:error_result) do + BaseService::Result.new.tap do |result| + result.fail_with_error!( + BaseService::ThirdPartyFailure.new( + result, + third_party: 'Cashfree', + error_message: '{"code: "link_post_failed", "type": "invalid_request_error"}' + ) + ) + end + end + + before do + allow(PaymentRequests::Payments::CashfreeService) + .to receive(:new) + .and_return(payment_provider_service) + + allow(payment_provider_service).to receive(:generate_payment_url) + .and_return(error_result) + end + + it 'returns a third party error' do + result = generate_payment_url_service.call + + expect(result).to eq(error_result) + end + end end end