mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
add migration to migrate cvv_message_response value to redirect_auth_url
- As per the patch, cvv_message_response contains 3D verification URL for those payments which require it. So need to migrate to the new column to maintain data integrity
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class MigrateCvvMessageToRedirectAuthUrl < ActiveRecord::Migration[7.1]
|
||||
def up
|
||||
records = Spree::Payment.where.not(
|
||||
cvv_response_message: nil
|
||||
).where.not(
|
||||
state: :completed
|
||||
)
|
||||
|
||||
records.update_all(
|
||||
"redirect_auth_url = cvv_response_message, cvv_response_message = null"
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
records = Spree::Payment.where.not(
|
||||
redirect_auth_url: nil
|
||||
).where.not(
|
||||
state: :completed
|
||||
)
|
||||
|
||||
records.update_all("cvv_response_message = redirect_auth_url, redirect_auth_url = null")
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_08_20_224718) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_08_27_205335) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "plpgsql"
|
||||
|
||||
235
spec/migrations/migrate_cvv_message_to_redirect_auth_url.rb
Normal file
235
spec/migrations/migrate_cvv_message_to_redirect_auth_url.rb
Normal file
@@ -0,0 +1,235 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_relative '../../db/migrate/20250827205335_migrate_cvv_message_to_redirect_auth_url.rb'
|
||||
|
||||
RSpec.describe MigrateCvvMessageToRedirectAuthUrl, type: :migration do
|
||||
let(:migration) { described_class.new }
|
||||
|
||||
describe '#up' do
|
||||
context 'when payments have cvv_response_message with redirect URLs and are not completed' do
|
||||
let!(:payment_requires_auth) do
|
||||
create(:payment,
|
||||
cvv_response_message: 'https://bank.com/3ds-redirect?token=abc123',
|
||||
redirect_auth_url: nil,
|
||||
state: 'requires_authorization')
|
||||
end
|
||||
|
||||
let!(:payment_processing) do
|
||||
create(:payment,
|
||||
cvv_response_message: 'https://payment-gateway.com/auth/redirect',
|
||||
redirect_auth_url: nil,
|
||||
state: 'processing')
|
||||
end
|
||||
|
||||
let!(:payment_pending) do
|
||||
create(:payment,
|
||||
cvv_response_message: 'https://secure.payment.com/authenticate',
|
||||
redirect_auth_url: nil,
|
||||
state: 'pending')
|
||||
end
|
||||
|
||||
it 'migrates cvv_response_message to redirect_auth_url' do
|
||||
migration.up
|
||||
|
||||
payment_requires_auth.reload
|
||||
payment_processing.reload
|
||||
payment_pending.reload
|
||||
|
||||
expect(payment_requires_auth.redirect_auth_url).to eq('https://bank.com/3ds-redirect?token=abc123')
|
||||
expect(payment_processing.redirect_auth_url).to eq('https://payment-gateway.com/auth/redirect')
|
||||
expect(payment_pending.redirect_auth_url).to eq('https://secure.payment.com/authenticate')
|
||||
|
||||
expect(payment_requires_auth.cvv_response_message).to be_nil
|
||||
expect(payment_processing.cvv_response_message).to be_nil
|
||||
expect(payment_pending.cvv_response_message).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when payments are completed' do
|
||||
let!(:completed_payment) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: nil,
|
||||
state: 'completed')
|
||||
end
|
||||
|
||||
it 'does not affect completed payments (they already have nil cvv_response_message)' do
|
||||
migration.up
|
||||
|
||||
completed_payment.reload
|
||||
|
||||
expect(completed_payment.cvv_response_message).to be_nil
|
||||
expect(completed_payment.redirect_auth_url).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when payments have nil cvv_response_message' do
|
||||
let!(:nil_cvv_payment) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: nil,
|
||||
state: 'pending')
|
||||
end
|
||||
|
||||
it 'does not migrate payments with nil cvv_response_message' do
|
||||
migration.up
|
||||
|
||||
nil_cvv_payment.reload
|
||||
|
||||
expect(nil_cvv_payment.cvv_response_message).to be_nil
|
||||
expect(nil_cvv_payment.redirect_auth_url).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'mixed payment states' do
|
||||
let!(:eligible_payments) do
|
||||
[
|
||||
create(:payment, cvv_response_message: 'https://url1.com', state: 'requires_authorization'),
|
||||
create(:payment, cvv_response_message: 'https://url2.com', state: 'processing'),
|
||||
create(:payment, cvv_response_message: 'https://url3.com', state: 'pending'),
|
||||
create(:payment, cvv_response_message: 'https://url4.com', state: 'checkout'),
|
||||
create(:payment, cvv_response_message: 'https://url5.com', state: 'failed'),
|
||||
create(:payment, cvv_response_message: 'https://url6.com', state: 'void'),
|
||||
create(:payment, cvv_response_message: 'https://url7.com', state: 'invalid')
|
||||
]
|
||||
end
|
||||
|
||||
let!(:ineligible_payments) do
|
||||
[
|
||||
create(:payment, cvv_response_message: nil, state: 'completed'),
|
||||
create(:payment, cvv_response_message: nil, state: 'requires_authorization')
|
||||
]
|
||||
end
|
||||
|
||||
it 'only migrates non-completed payments with cvv_response_message' do
|
||||
migration.up
|
||||
|
||||
# Check eligible payments were migrated
|
||||
eligible_payments.each do |payment|
|
||||
payment.reload
|
||||
expect(payment.redirect_auth_url).to be_present
|
||||
expect(payment.cvv_response_message).to be_nil
|
||||
end
|
||||
|
||||
# Check ineligible payments were not migrated
|
||||
ineligible_payments.each do |payment|
|
||||
payment.reload
|
||||
expect(payment.redirect_auth_url).to be_nil
|
||||
expect(payment.cvv_response_message).to eq(payment.cvv_response_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#down' do
|
||||
context 'when payments have redirect_auth_url and are not completed' do
|
||||
let!(:requires_auth_payment) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: 'https://bank.com/3ds-redirect?token=xyz789',
|
||||
state: 'requires_authorization')
|
||||
end
|
||||
|
||||
let!(:processing_payment_with_redirect) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: 'https://gateway.com/authenticate',
|
||||
state: 'processing')
|
||||
end
|
||||
|
||||
it 'migrates redirect_auth_url back to cvv_response_message' do
|
||||
migration.down
|
||||
|
||||
requires_auth_payment.reload
|
||||
processing_payment_with_redirect.reload
|
||||
|
||||
expect(requires_auth_payment.cvv_response_message).to eq('https://bank.com/3ds-redirect?token=xyz789')
|
||||
expect(processing_payment_with_redirect.cvv_response_message).to eq('https://gateway.com/authenticate')
|
||||
expect(requires_auth_payment.redirect_auth_url).to be_nil
|
||||
expect(processing_payment_with_redirect.redirect_auth_url).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when payments are completed' do
|
||||
let!(:completed_payment_with_redirect) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: nil,
|
||||
state: 'completed')
|
||||
end
|
||||
|
||||
it 'does not affect completed payments (they have nil values)' do
|
||||
migration.down
|
||||
|
||||
completed_payment_with_redirect.reload
|
||||
|
||||
expect(completed_payment_with_redirect.redirect_auth_url).to be_nil
|
||||
expect(completed_payment_with_redirect.cvv_response_message).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when payments have nil redirect_auth_url' do
|
||||
let!(:nil_redirect_payment) do
|
||||
create(:payment,
|
||||
cvv_response_message: nil,
|
||||
redirect_auth_url: nil,
|
||||
state: 'pending')
|
||||
end
|
||||
|
||||
it 'does not affect payments with nil redirect_auth_url' do
|
||||
migration.down
|
||||
|
||||
nil_redirect_payment.reload
|
||||
|
||||
expect(nil_redirect_payment.redirect_auth_url).to be_nil
|
||||
expect(nil_redirect_payment.cvv_response_message).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'full migration cycle (up then down)' do
|
||||
let!(:original_payments) do
|
||||
[
|
||||
create(
|
||||
:payment,
|
||||
cvv_response_message: 'https://original1.com/auth',
|
||||
state: 'requires_authorization'
|
||||
),
|
||||
create(
|
||||
:payment,
|
||||
cvv_response_message: 'https://original2.com/redirect',
|
||||
state: 'processing'
|
||||
),
|
||||
create(
|
||||
:payment,
|
||||
cvv_response_message: 'https://original3.com/3ds',
|
||||
state: 'pending'
|
||||
)
|
||||
]
|
||||
end
|
||||
|
||||
it 'preserves data integrity through up and down migrations' do
|
||||
original_urls = original_payments.map(&:cvv_response_message)
|
||||
|
||||
# Verify initial state
|
||||
expect(original_payments.all? { |p| p.redirect_auth_url.nil? }).to be true
|
||||
|
||||
# Migrate up
|
||||
migration.up
|
||||
original_payments.each(&:reload)
|
||||
|
||||
# Verify up migration
|
||||
expect(original_payments.map(&:redirect_auth_url)).to eq(original_urls)
|
||||
expect(original_payments.all? { |p| p.cvv_response_message.nil? }).to be true
|
||||
|
||||
# Migrate down
|
||||
migration.down
|
||||
original_payments.each(&:reload)
|
||||
|
||||
# Verify down migration restores original state
|
||||
expect(original_payments.map(&:cvv_response_message)).to eq(original_urls)
|
||||
expect(original_payments.all? { |p| p.redirect_auth_url.nil? }).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user