Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor callback service and controller #1201

Merged
merged 31 commits into from
Jun 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
5e109ce
Rename non-worldpay-specific model methods to `online_payment` in pre…
PaulDoyle-DEFRA May 16, 2022
b51477c
Move worldpay fixtures to sub-folder and add govpay fixture folder
PaulDoyle-DEFRA May 16, 2022
30a56c9
Move worldpay fixtures to sub-folder
PaulDoyle-DEFRA May 16, 2022
c3f43d8
Add govpay attributes and payment_uuid to order model
PaulDoyle-DEFRA Jun 15, 2022
f77b9ec
Add govpay attributes to payment model and extend online payment logic
PaulDoyle-DEFRA Jun 15, 2022
6972dc4
Use payments scope for finance_details update_balance
PaulDoyle-DEFRA Jun 15, 2022
79b23bb
Add unit tests for order payment_uuid
PaulDoyle-DEFRA Jun 15, 2022
dfed79a
Add Govpay response fixtures
PaulDoyle-DEFRA Jun 15, 2022
5410b86
Add govpay traits to rspec factories
PaulDoyle-DEFRA Jun 15, 2022
6c658f3
Add govpay support to pending_online_payment?
PaulDoyle-DEFRA Jun 15, 2022
b820cd8
Add govpay routes, controllers and forms
PaulDoyle-DEFRA Jun 15, 2022
65b2487
Add new govpay services
PaulDoyle-DEFRA Jun 15, 2022
8600755
Move _pending_worldpay_ services to _pending_online_payment_ services…
PaulDoyle-DEFRA Jun 15, 2022
1ae8a29
Add unit tests for except_online_not_authorised payment scope
PaulDoyle-DEFRA Jun 15, 2022
65aa1c4
Update new registration and renewal workflows to support govpay form …
PaulDoyle-DEFRA Jun 15, 2022
1bd6e17
Rename _pending_worldpay_payment VCR cassette to _pending_online_payment
PaulDoyle-DEFRA Jun 15, 2022
736c1f4
Unit tests for govpay forms workflow
PaulDoyle-DEFRA Jun 15, 2022
e5e2d89
Add govpay views and locale definitions
PaulDoyle-DEFRA Jun 15, 2022
b6c9e6d
Add govpay env vars to spec/dummy application config
PaulDoyle-DEFRA Jun 15, 2022
c7c8b1b
Add unit tests
PaulDoyle-DEFRA Jun 16, 2022
f3178d3
Add unit tests
PaulDoyle-DEFRA Jun 16, 2022
958e0ea
Rubocop fix
PaulDoyle-DEFRA Jun 16, 2022
d5b7085
Address SonarCloud warning
PaulDoyle-DEFRA Jun 16, 2022
f6db73f
Additional temporary debugging
PaulDoyle-DEFRA Jun 16, 2022
97386fc
Additional debugging
PaulDoyle-DEFRA Jun 17, 2022
05d3f69
rubocop fix
PaulDoyle-DEFRA Jun 17, 2022
8ae3e72
Refactor callback service, controller and handling of govpay_id and s…
PaulDoyle-DEFRA Jun 20, 2022
18b421a
Remove redundant quotes in locale definition files
PaulDoyle-DEFRA Jun 21, 2022
fbf6caa
Add unit tests for card payment navigation with feature toggle
PaulDoyle-DEFRA Jun 21, 2022
2431c2e
Fix renewal govpay navigation
PaulDoyle-DEFRA Jun 21, 2022
8638e2a
Remove redundant debugging
PaulDoyle-DEFRA Jun 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
95 changes: 95 additions & 0 deletions app/controllers/waste_carriers_engine/govpay_forms_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# frozen_string_literal: true

module WasteCarriersEngine
class GovpayFormsController < ::WasteCarriersEngine::FormsController
include UnsubmittableForm

def new
super(GovpayForm, "govpay_form")

payment_info = prepare_for_payment

if payment_info == :error
flash[:error] = I18n.t(".waste_carriers_engine.govpay_forms.new.setup_error")
go_back
else
redirect_to payment_info[:url]
end
end

def payment_callback
find_or_initialize_transient_registration(params[:token])

if @transient_registration.finance_details.orders.first.govpay_status == "success"
Rails.logger.warn "Attempt to pay for an order with govpay_status already set to success"
respond_to_acceptable_payment(:success)

else
@transient_registration.with_lock do
payment_status = GovpayCallbackService.new(params[:uuid]).run

case payment_status
when :success, :pending
respond_to_acceptable_payment(payment_status)
else
respond_to_unsuccessful_payment(payment_status)
end
end
end
rescue ArgumentError
Rails.logger.warn "Govpay payment callback error: invalid payment uuid \"#{params[:uuid]}\""
Airbrake.notify("Govpay callback error", "Invalid payment uuid \"#{params[:uuid]}\"")
flash[:error] = I18n.t(".waste_carriers_engine.govpay_forms.new.internal_error")
go_back
end

private

def prepare_for_payment
@transient_registration.prepare_for_payment(:govpay, current_user)
order = @transient_registration.finance_details.orders.first
govpay_service = GovpayPaymentService.new(@transient_registration, order, current_user)
govpay_service.prepare_for_payment
end

def respond_to_acceptable_payment(action)
return unless valid_transient_registration?

if action != :error
log_and_send_govpay_response(true, action)
@transient_registration.next!
redirect_to_correct_form
else
log_and_send_govpay_response(false, action)
flash[:error] = I18n.t(".waste_carriers_engine.govpay_forms.#{action}.invalid_response")
go_back
end
end

def respond_to_unsuccessful_payment(action)
return unless valid_transient_registration?

if action != :error
log_and_send_govpay_response(true, action)
flash[:error] = I18n.t(".waste_carriers_engine.govpay_forms.#{action}.message")
else
log_and_send_govpay_response(false, action)
flash[:error] = I18n.t(".waste_carriers_engine.govpay_forms.#{action}.invalid_response")
end

go_back
end

def valid_transient_registration?
setup_checks_pass?
end

def log_and_send_govpay_response(is_valid, action)
valid_text = is_valid ? "Valid" : "Invalid"
title = "#{valid_text} Govpay response: #{action}"

Rails.logger.debug [title, "Params:", params.to_json].join("\n")
Airbrake.notify(title, error_message: params) unless is_valid && action == :success
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module WasteCarriersEngine
class RegistrationReceivedPendingGovpayPaymentFormsController < ::WasteCarriersEngine::FormsController
include UnsubmittableForm
include CannotGoBackForm

def new
return unless super(
RegistrationReceivedPendingGovpayPaymentForm,
"registration_received_pending_govpay_payment_form"
)

begin
@registration = RegistrationCompletionService.run(@transient_registration)
rescue StandardError => e
Airbrake.notify(e, reg_identifier: @transient_registration.reg_identifier)
Rails.logger.error e
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

module WasteCarriersEngine
class RenewalReceivedPendingGovpayPaymentFormsController < ::WasteCarriersEngine::FormsController
include CannotGoBackForm
include UnsubmittableForm

def new
super(RenewalReceivedPendingGovpayPaymentForm, "renewal_received_pending_govpay_payment_form")
end
end
end
9 changes: 9 additions & 0 deletions app/forms/waste_carriers_engine/govpay_form.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

module WasteCarriersEngine
class GovpayForm < ::WasteCarriersEngine::BaseForm
def self.can_navigate_flexibly?
false
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module WasteCarriersEngine
class RegistrationReceivedPendingGovpayPaymentForm < ::WasteCarriersEngine::BaseForm
include CannotSubmit

def self.can_navigate_flexibly?
false
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

module WasteCarriersEngine
class RenewalReceivedPendingGovpayPaymentForm < ::WasteCarriersEngine::BaseForm
include CannotSubmit

def self.can_navigate_flexibly?
false
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,16 @@ def ad_contact_email?
contact_email.blank? || contact_email == WasteCarriersEngine.configuration.assisted_digital_email
end

def pending_worldpay_payment?
def pending_online_payment?
return false unless finance_details.present? &&
finance_details.orders.present? &&
finance_details.orders.first.present?

WorldpayValidatorService.valid_world_pay_status?(:pending, finance_details.orders.first.world_pay_status)
if WasteCarriersEngine::FeatureToggle.active?(:govpay_payments)
GovpayValidatorService.valid_govpay_status?(:pending, finance_details.orders.first.govpay_status)
else
WorldpayValidatorService.valid_world_pay_status?(:pending, finance_details.orders.first.world_pay_status)
end
end

# Some business types should not have a company_no
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,14 @@ module CanUseNewRegistrationWorkflow
state :cards_form
state :payment_summary_form
state :worldpay_form
state :govpay_form
state :confirm_bank_transfer_form

state :registration_completed_form
state :registration_received_pending_payment_form
state :registration_received_pending_conviction_form
state :registration_received_pending_worldpay_payment_form
state :registration_received_pending_govpay_payment_form

# Transitions
event :next do
Expand Down Expand Up @@ -264,6 +266,9 @@ module CanUseNewRegistrationWorkflow
# Payment & Completion
transitions from: :cards_form, to: :payment_summary_form

transitions from: :payment_summary_form, to: :govpay_form,
if: :paying_by_card_govpay?

transitions from: :payment_summary_form, to: :worldpay_form,
if: :paying_by_card?

Expand All @@ -274,13 +279,15 @@ module CanUseNewRegistrationWorkflow
# callback block, hence we went for `after`
after: :set_metadata_route

transitions from: :worldpay_form, to: :registration_received_pending_worldpay_payment_form,
if: :pending_worldpay_payment?,
transitions from: :worldpay_form,
to: :registration_received_pending_worldpay_payment_form,
if: :pending_online_payment?,
# TODO: This don't get triggered if in the `success`
# callback block, hence we went for `after`
after: :set_metadata_route

transitions from: :worldpay_form, to: :registration_received_pending_conviction_form,
transitions from: :worldpay_form,
to: :registration_received_pending_conviction_form,
if: :conviction_check_required?,
# TODO: This don't get triggered if in the `success`
# callback block, hence we went for `after`
Expand All @@ -290,6 +297,19 @@ module CanUseNewRegistrationWorkflow
# TODO: This don't get triggered if in the `success`
# callback block, hence we went for `after`
after: :set_metadata_route

transitions from: :govpay_form,
to: :registration_received_pending_govpay_payment_form,
if: :pending_online_payment?,
after: :set_metadata_route

transitions from: :govpay_form,
to: :registration_received_pending_conviction_form,
if: :conviction_check_required?,
after: :set_metadata_route

transitions from: :govpay_form, to: :registration_completed_form,
after: :set_metadata_route
end

# Transitions
Expand Down Expand Up @@ -366,6 +386,10 @@ def paying_by_card?
temp_payment_method == "card"
end

def paying_by_card_govpay?
WasteCarriersEngine::FeatureToggle.active?(:govpay_payments) && temp_payment_method == "card"
end

def switch_to_lower_tier
update_attributes(tier: WasteCarriersEngine::NewRegistration::LOWER_TIER)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,14 @@ module CanUseRenewingRegistrationWorkflow
state :cards_form
state :payment_summary_form
state :worldpay_form
state :govpay_form
state :confirm_bank_transfer_form

state :renewal_complete_form
state :renewal_received_pending_conviction_form
state :renewal_received_pending_payment_form
state :renewal_received_pending_worldpay_payment_form
state :renewal_received_pending_govpay_payment_form

state :cannot_renew_type_change_form

Expand Down Expand Up @@ -193,14 +195,17 @@ module CanUseRenewingRegistrationWorkflow
# Payment & completion
transitions from: :cards_form, to: :payment_summary_form

transitions from: :payment_summary_form, to: :govpay_form,
if: :paying_by_card_govpay?

transitions from: :payment_summary_form, to: :worldpay_form,
if: :paying_by_card?

transitions from: :payment_summary_form, to: :confirm_bank_transfer_form

transitions from: :worldpay_form, to: :renewal_received_pending_worldpay_payment_form,
if: :pending_worldpay_payment?,
success: :send_renewal_pending_worldpay_payment_email,
if: :pending_online_payment?,
success: :send_renewal_pending_online_payment_email,
# TODO: This don't get triggered if in the `success`
# callback block, hence we went for `after`
after: :set_metadata_route
Expand All @@ -217,6 +222,19 @@ module CanUseRenewingRegistrationWorkflow
# callback block, hence we went for `after`
after: :set_metadata_route

transitions from: :govpay_form, to: :renewal_received_pending_govpay_payment_form,
if: :pending_online_payment?,
success: :send_renewal_pending_online_payment_email,
after: :set_metadata_route

transitions from: :govpay_form, to: :renewal_received_pending_conviction_form,
if: :conviction_check_required?,
success: :send_renewal_pending_checks_email,
after: :set_metadata_route

transitions from: :govpay_form, to: :renewal_complete_form,
after: :set_metadata_route

transitions from: :confirm_bank_transfer_form, to: :renewal_received_pending_payment_form,
success: :send_renewal_received_pending_payment_email,
# TODO: This don't get triggered if in the `success`
Expand Down Expand Up @@ -279,6 +297,10 @@ def paying_by_card?
temp_payment_method == "card"
end

def paying_by_card_govpay?
WasteCarriersEngine::FeatureToggle.active?(:govpay_payments) && temp_payment_method == "card"
end

def use_trading_name?
temp_use_trading_name == "yes"
end
Expand All @@ -287,8 +309,8 @@ def incorrect_company_data?
temp_use_registered_company_details == "no"
end

def send_renewal_pending_worldpay_payment_email
WasteCarriersEngine::Notify::RenewalPendingWorldpayPaymentEmailService.run(registration: self)
def send_renewal_pending_online_payment_email
WasteCarriersEngine::Notify::RenewalPendingOnlinePaymentEmailService.run(registration: self)
rescue StandardError => e
Airbrake.notify(e, registration_no: reg_identifier) if defined?(Airbrake)
end
Expand Down
7 changes: 2 additions & 5 deletions app/models/waste_carriers_engine/finance_details.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ class FinanceDetails

field :balance, type: Integer

validates :balance,
presence: true
validates :balance, presence: true

def self.new_renewal_finance_details(transient_registration, method, current_user)
user_email = current_user&.email || transient_registration.contact_email
Expand Down Expand Up @@ -43,9 +42,7 @@ def zero_difference_balance

def update_balance
order_balance = orders.sum { |item| item[:total_amount] }
# Select payments where the type is not WORLDPAY, or if it is, the status is AUTHORISED
payment_balance = payments.any_of({ :payment_type.ne => "WORLDPAY" },
world_pay_payment_status: "AUTHORISED").sum { |item| item[:amount] }
payment_balance = payments.except_online_not_authorised.sum { |item| item[:amount] }
self.balance = order_balance - payment_balance
end
end
Expand Down
19 changes: 17 additions & 2 deletions app/models/waste_carriers_engine/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ class Order
field :orderCode, as: :order_code, type: String
field :paymentMethod, as: :payment_method, type: String
field :merchantId, as: :merchant_id, type: String
field :payment_uuid, type: String
field :totalAmount, as: :total_amount, type: Integer
field :currency, type: String
field :dateCreated, as: :date_created, type: DateTime
field :worldPayStatus, as: :world_pay_status, type: String
field :govpayId, as: :govpay_id, type: String
field :govpayStatus, as: :govpay_status, type: String
field :dateLastUpdated, as: :date_last_updated, type: DateTime
field :updatedByUser, as: :updated_by_user, type: String
field :description, type: String
Expand Down Expand Up @@ -78,12 +81,24 @@ def set_description
self.description = generate_description
end

def update_after_worldpay(status)
self.world_pay_status = status
def update_after_online_payment(status)
if WasteCarriersEngine::FeatureToggle.active?(:govpay_payments)
Rails.logger.debug "Updating order after online payment, status: #{status}"
self.govpay_status = status
else
self.world_pay_status = status
end
self.date_last_updated = Time.current
save!
end

# Generate a uuid for the payment associated with this order, on demand
def payment_uuid
update_attributes!(payment_uuid: SecureRandom.uuid) unless self[:payment_uuid]

self[:payment_uuid]
end

private

def generate_description
Expand Down