Skip to content

Commit

Permalink
Handle code update on payment provider
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent-pochet committed Dec 20, 2024
1 parent 5a878c2 commit 0047ca5
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 39 deletions.
22 changes: 14 additions & 8 deletions app/services/payment_providers/cashfree_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def create_or_update(**args)
organization_id: args[:organization].id,
code: args[:code],
id: args[:id],
payment_provider_type: 'cashfree'
payment_provider_type: "cashfree"
)

cashfree_provider = if payment_provider_result.success?
Expand All @@ -23,13 +23,19 @@ def create_or_update(**args)
)
end

old_code = cashfree_provider.code

cashfree_provider.client_id = args[:client_id] if args.key?(:client_id)
cashfree_provider.client_secret = args[:client_secret] if args.key?(:client_secret)
cashfree_provider.success_redirect_url = args[:success_redirect_url] if args.key?(:success_redirect_url)
cashfree_provider.code = args[:code] if args.key?(:code)
cashfree_provider.name = args[:name] if args.key?(:name)
cashfree_provider.save!

if payment_provider_code_changed?(cashfree_provider, old_code, args)
cashfree_provider.customers.update_all(payment_provider_code: args[:code]) # rubocop:disable Rails/SkipsModelValidations
end

result.cashfree_provider = cashfree_provider
result
rescue ActiveRecord::RecordInvalid => e
Expand All @@ -40,17 +46,17 @@ def handle_incoming_webhook(organization_id:, body:, timestamp:, signature:, cod
payment_provider_result = PaymentProviders::FindService.call(
organization_id:,
code:,
payment_provider_type: 'cashfree'
payment_provider_type: "cashfree"
)

return payment_provider_result unless payment_provider_result.success?

secret_key = payment_provider_result.payment_provider.client_secret
data = "#{timestamp}#{body}"
gen_signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', secret_key, data))
gen_signature = Base64.strict_encode64(OpenSSL::HMAC.digest("sha256", secret_key, data))

unless gen_signature == signature
return result.service_failure!(code: 'webhook_error', message: 'Invalid signature')
return result.service_failure!(code: "webhook_error", message: "Invalid signature")
end

PaymentProviders::Cashfree::HandleEventJob.perform_later(event_json: body)
Expand All @@ -61,12 +67,12 @@ def handle_incoming_webhook(organization_id:, body:, timestamp:, signature:, cod

def handle_event(event_json:)
event = JSON.parse(event_json)
event_type = event['type']
event_type = event["type"]

case event_type
when 'PAYMENT_LINK_EVENT'
link_status = event.dig('data', 'link_status')
provider_payment_id = event.dig('data', 'link_notes', 'lago_invoice_id')
when "PAYMENT_LINK_EVENT"
link_status = event.dig("data", "link_status")
provider_payment_id = event.dig("data", "link_notes", "lago_invoice_id")

if LINK_STATUS_ACTIONS.include?(link_status) && !provider_payment_id.nil?
update_payment_status_result = Invoices::Payments::CashfreeService
Expand Down
95 changes: 64 additions & 31 deletions spec/services/payment_providers/cashfree_service_spec.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# frozen_string_literal: true

require 'rails_helper'
require "rails_helper"

RSpec.describe PaymentProviders::CashfreeService, type: :service do
subject(:cashfree_service) { described_class.new(membership.user) }

let(:membership) { create(:membership) }
let(:organization) { membership.organization }
let(:code) { 'code_1' }
let(:name) { 'Name 1' }
let(:client_id) { '123456_abc' }
let(:client_secret) { 'cfsk_ma_prod_abc_123456' }
let(:code) { "code_1" }
let(:name) { "Name 1" }
let(:client_id) { "123456_abc" }
let(:client_secret) { "cfsk_ma_prod_abc_123456" }
let(:success_redirect_url) { Faker::Internet.url }

describe '.create_or_update' do
it 'creates a cashfree provider' do
describe ".create_or_update" do
it "creates a cashfree provider" do
expect do
cashfree_service.create_or_update(
organization:,
Expand All @@ -27,14 +27,47 @@
end.to change(PaymentProviders::CashfreeProvider, :count).by(1)
end

context 'when organization already have a cashfree provider' do
context "when code was changed" do
let(:new_code) { "updated_code_1" }
let(:cashfree_customer) { create(:cashfree_customer, payment_provider:, customer:) }
let(:customer) { create(:customer, organization:) }

let(:payment_provider) do
create(
:cashfree_provider,
organization:,
code:,
name:,
client_secret: "secret"
)
end

before { cashfree_customer }

it "updates payment provider codes of all customers" do
result = cashfree_service.create_or_update(
id: payment_provider.id,
organization:,
code: new_code,
name:,
client_secret: "secret"
)

aggregate_failures do
expect(result).to be_success
expect(result.cashfree_provider.customers.first.payment_provider_code).to eq(new_code)
end
end
end

context "when organization already have a cashfree provider" do
let(:cashfree_provider) do
create(:cashfree_provider, organization:, client_id: '123456_abc_old', client_secret: 'cfsk_ma_prod_abc_123456_old', code:)
create(:cashfree_provider, organization:, client_id: "123456_abc_old", client_secret: "cfsk_ma_prod_abc_123456_old", code:)
end

before { cashfree_provider }

it 'updates the existing provider' do
it "updates the existing provider" do
result = cashfree_service.create_or_update(
organization:,
code:,
Expand All @@ -48,76 +81,76 @@

aggregate_failures do
expect(result.cashfree_provider.id).to eq(cashfree_provider.id)
expect(result.cashfree_provider.client_id).to eq('123456_abc')
expect(result.cashfree_provider.client_secret).to eq('cfsk_ma_prod_abc_123456')
expect(result.cashfree_provider.client_id).to eq("123456_abc")
expect(result.cashfree_provider.client_secret).to eq("cfsk_ma_prod_abc_123456")
expect(result.cashfree_provider.code).to eq(code)
expect(result.cashfree_provider.name).to eq(name)
expect(result.cashfree_provider.success_redirect_url).to eq(success_redirect_url)
end
end
end

context 'with validation error' do
context "with validation error" do
let(:token) { nil }

it 'returns an error result' do
it "returns an error result" do
result = cashfree_service.create_or_update(
organization:
)

aggregate_failures do
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ValidationFailure)
expect(result.error.messages[:client_id]).to eq(['value_is_mandatory'])
expect(result.error.messages[:client_secret]).to eq(['value_is_mandatory'])
expect(result.error.messages[:client_id]).to eq(["value_is_mandatory"])
expect(result.error.messages[:client_secret]).to eq(["value_is_mandatory"])
end
end
end
end

describe '.handle_incoming_webhook' do
describe ".handle_incoming_webhook" do
let(:cashfree_provider) { create(:cashfree_provider, organization:, client_id:, client_secret:) }

let(:body) do
path = Rails.root.join('spec/fixtures/cashfree/event.json')
path = Rails.root.join("spec/fixtures/cashfree/event.json")
File.read(path)
end

before { cashfree_provider }

it 'checks the webhook' do
it "checks the webhook" do
result = cashfree_service.handle_incoming_webhook(
organization_id: organization.id,
body:,
timestamp: '1629271506',
signature: 'MFB3Rkubs4jB97ROS/I4iu9llAAP5ykJ3GZYp95o/Mw='
timestamp: "1629271506",
signature: "MFB3Rkubs4jB97ROS/I4iu9llAAP5ykJ3GZYp95o/Mw="
)

expect(result).to be_success

expect(PaymentProviders::Cashfree::HandleEventJob).to have_been_enqueued
end

context 'when failing to validate the signature' do
it 'returns an error' do
context "when failing to validate the signature" do
it "returns an error" do
result = cashfree_service.handle_incoming_webhook(
organization_id: organization.id,
body:,
timestamp: '1629271506',
signature: 'signature'
timestamp: "1629271506",
signature: "signature"
)

aggregate_failures do
expect(result).not_to be_success
expect(result.error).to be_a(BaseService::ServiceFailure)
expect(result.error.code).to eq('webhook_error')
expect(result.error.error_message).to eq('Invalid signature')
expect(result.error.code).to eq("webhook_error")
expect(result.error.error_message).to eq("Invalid signature")
end
end
end
end

describe '.handle_event' do
describe ".handle_event" do
let(:payment_service) { instance_double(Invoices::Payments::CashfreeService) }
let(:service_result) { BaseService::Result.new }

Expand All @@ -128,13 +161,13 @@
.and_return(service_result)
end

context 'when succeeded payment event' do
context "when succeeded payment event" do
let(:event) do
path = Rails.root.join('spec/fixtures/cashfree/event.json')
path = Rails.root.join("spec/fixtures/cashfree/event.json")
File.read(path)
end

it 'routes the event to an other service' do
it "routes the event to an other service" do
cashfree_service.handle_event(event_json: event)

expect(Invoices::Payments::CashfreeService).to have_received(:new)
Expand Down

0 comments on commit 0047ca5

Please sign in to comment.