Skip to content

Commit

Permalink
FYST-526 Update refund taxes owed UI and add financial information to…
Browse files Browse the repository at this point in the history
… MD pdf/xml (#5007)

* Add joint+account holder name fields & bank_authorization_confirmation, has_joint_account_holder
* Drop account_holder_name, ignore bank_name, df_data_import_failed_at fields
* Update refund/taxes_owed UI, validations, update MD502 XML and PDF
  • Loading branch information
arinchoi03 authored Nov 27, 2024
1 parent d5ca3cf commit a074c6d
Show file tree
Hide file tree
Showing 48 changed files with 578 additions and 120 deletions.
4 changes: 3 additions & 1 deletion app/assets/stylesheets/_state-file.scss
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,9 @@
}

.question-with-follow-up__follow-up {
margin: 0;
:not(.not-centered) {
margin: 0;
}

p.form-question {
font-size: 1.3rem;
Expand Down
1 change: 0 additions & 1 deletion app/controllers/flows_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,6 @@ def self.common_attributes
spouse_esigned: "yes",
spouse_esigned_at: 1.minute.ago,
payment_or_deposit_type: "mail",
bank_name: 'bank name',
account_type: 'unfilled',
routing_number: '111111111',
account_number: '2222222222',
Expand Down
36 changes: 30 additions & 6 deletions app/forms/state_file/md_tax_refund_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,29 @@ class MdTaxRefundForm < QuestionsForm
:routing_number,
:account_number,
:account_type,
:bank_name,
:account_holder_name
:account_holder_first_name,
:account_holder_middle_initial,
:account_holder_last_name,
:account_holder_suffix,
:has_joint_account_holder,
:joint_account_holder_first_name,
:joint_account_holder_middle_initial,
:joint_account_holder_last_name,
:joint_account_holder_suffix,
:bank_authorization_confirmed
set_attributes_for :confirmation, :routing_number_confirmation, :account_number_confirmation

validates :payment_or_deposit_type, presence: true

with_options unless: -> { payment_or_deposit_type == "mail" } do
validates :account_holder_name, presence: true
SUFFIX_OPTIONS = %w[JR SR I II III IV V VI VII VIII IX X]

validates :bank_name, presence: true
with_options unless: -> { payment_or_deposit_type == "mail" } do
validates :account_holder_first_name, presence: true
validates :account_holder_last_name, presence: true
validates :account_holder_first_name, format: { with: /\A[a-zA-Z0-9]([A-Za-z0-9\-\s']{0,15})\z/.freeze, message: ->(_object, _data) { I18n.t('errors.attributes.first_name.invalid_format') }}
validates :account_holder_last_name, format: { with: /\A[a-zA-Z0-9]([A-Za-z0-9\-\s']{0,31})\z/.freeze, message: ->(_object, _data) { I18n.t('errors.attributes.last_name.invalid_format') }}
validates :account_holder_middle_initial, length: { maximum: 1 }, format: { with: /\A[A-Za-z]\z/.freeze, allow_blank: true }
validates :account_holder_suffix, inclusion: { in: SUFFIX_OPTIONS }, allow_blank: true, if: -> { account_holder_suffix.present? }
validates :account_type, presence: true

validates :account_number, presence: true, confirmation: true, length: { in: 5..17 }, numericality: true
Expand All @@ -24,9 +37,20 @@ class MdTaxRefundForm < QuestionsForm
validates :routing_number, presence: true, confirmation: true, routing_number: true
validates :routing_number_confirmation, presence: true

validates :bank_authorization_confirmed, acceptance: { accept: 'yes', message: ->(_object, _data) { I18n.t("state_file.questions.md_tax_refund.md_bank_details.bank_authorization_confirmation_error") }}

with_options if: -> { account_number.present? && routing_number.present? } do
validate :bank_numbers_not_equal
end

with_options if: -> { has_joint_account_holder == 'yes' } do
validates :joint_account_holder_first_name, presence: true
validates :joint_account_holder_last_name, presence: true
validates :joint_account_holder_first_name, format: { with: /\A[a-zA-Z0-9]([A-Za-z0-9\-\s']{0,15})\z/.freeze, message: ->(_object, _data) { I18n.t('errors.attributes.first_name.invalid_format') }}
validates :joint_account_holder_last_name, format: { with: /\A[a-zA-Z0-9]([A-Za-z0-9\-\s']{0,31})\z/.freeze, message: ->(_object, _data) { I18n.t('errors.attributes.last_name.invalid_format') }}
validates :joint_account_holder_middle_initial, length: { maximum: 1 }, format: { with: /\A[A-Za-z]\z/.freeze, allow_blank: true }
validates :joint_account_holder_suffix, inclusion: { in: SUFFIX_OPTIONS }, allow_blank: true, if: -> { joint_account_holder_suffix.present? }
end
end

def save
Expand All @@ -35,7 +59,7 @@ def save

def self.existing_attributes(intake)
attributes = super
attributes.except(:routing_number, :account_number, :routing_number_confirmation, :account_number_confirmation, :bank_name)
attributes.except(:routing_number, :account_number, :routing_number_confirmation, :account_number_confirmation)
end

private
Expand Down
6 changes: 2 additions & 4 deletions app/forms/state_file/tax_refund_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ class TaxRefundForm < QuestionsForm
:payment_or_deposit_type,
:routing_number,
:account_number,
:account_type,
:bank_name
:account_type
set_attributes_for :confirmation, :routing_number_confirmation, :account_number_confirmation

validates :payment_or_deposit_type, presence: true

with_options unless: -> { payment_or_deposit_type == "mail" } do
validates :bank_name, presence: true
validates :account_type, presence: true

validates :account_number, presence: true, confirmation: true, length: { in: 5..17 }, numericality: true
Expand All @@ -32,7 +30,7 @@ def save

def self.existing_attributes(intake)
attributes = super
attributes.except(:routing_number, :account_number, :routing_number_confirmation, :account_number_confirmation, :bank_name)
attributes.except(:routing_number, :account_number, :routing_number_confirmation, :account_number_confirmation)
end

private
Expand Down
1 change: 0 additions & 1 deletion app/forms/state_file/taxes_owed_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ class TaxesOwedForm < TaxRefundForm
:routing_number,
:account_number,
:account_type,
:bank_name,
:withdraw_amount

set_attributes_for :confirmation, :routing_number_confirmation, :account_number_confirmation
Expand Down
4 changes: 4 additions & 0 deletions app/lib/efile/line_data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,10 @@ MD502_LINE_34:
label: '34. Total Maryland and local tax amount (line 27 + line 33 if deduction standard)'
MD502_LINE_40:
label: "40 Total Maryland and local tax withheld"
MD502_AUTHORIZE_DIRECT_DEPOSIT:
label: "Client authorizes the State of Maryland to issue refund by direct deposit (tax refund controller)."
MD502_LINE_51D:
label: "51D Name(s) of Bank Account Holder(s)"
MD502B_LINE_1:
label: '1 Total number of Regular dependents'
MD502B_LINE_2:
Expand Down
1 change: 1 addition & 0 deletions app/lib/efile/md/md502_calculator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def calculate
set_line(:MD502_LINE_34, :calculate_line_34)

set_line(:MD502_LINE_40, :calculate_line_40)
set_line(:MD502_AUTHORIZE_DIRECT_DEPOSIT, @intake, :bank_authorization_confirmed_yes?)

@md502cr.calculate
@lines.transform_values(&:value)
Expand Down
35 changes: 32 additions & 3 deletions app/lib/pdf_filler/md502_pdf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def initialize(submission)
end

def hash_for_pdf
{
answers = {
'Enter 1': @xml_document.at("Form502 Income FederalAdjustedGrossIncome")&.text,
'Enter 1a': @xml_document.at("Form502 Income WagesSalariesAndTips")&.text,
'Enter 1b': @xml_document.at("Form502 Income EarnedIncome")&.text,
Expand Down Expand Up @@ -87,8 +87,8 @@ def hash_for_pdf
'Enter 3': @xml_document.at('Form502 Additions StateRetirementPickup')&.text,
'Enter 6': @xml_document.at('Form502 Additions Total')&.text,
'Enter 7': @xml_document.at('Form502 Additions FedAGIAndStateAdditions')&.text,
"Enter 15": @xml_document.at('Form502 Subtractions Total')&.text,
"Enter 16": @xml_document.at('Form502 Subtractions StateAdjustedGrossIncome')&.text,
'Enter 15': @xml_document.at('Form502 Subtractions Total')&.text,
'Enter 16': @xml_document.at('Form502 Subtractions StateAdjustedGrossIncome')&.text,
'Text Box 30': @xml_document.at('Form502 StateTaxComputation StateIncomeTax')&.text,
'Text Box 36': @xml_document.at('Form502 StateTaxComputation PovertyLevelCredit')&.text,
'Text Box 40': @xml_document.at('Form502 StateTaxComputation TotalCredits')&.text,
Expand All @@ -100,7 +100,18 @@ def hash_for_pdf
'Text Box 52': @xml_document.at('Form502 LocalTaxComputation TotalCredits')&.text,
'Text Box 54': @xml_document.at('Form502 LocalTaxComputation LocalTaxAfterCredits')&.text,
'Text Box 56': @xml_document.at('Form502 TotalStateAndLocalTax')&.text,
'Check Box 39': @xml_document.at('Form502 AuthToDirectDepositInd')&.text == 'X' ? 'Yes' : 'Off',
'Text Box 95': full_names_of_bank_account_holders || ""
}
if @xml_document.at('RefundDirectDeposit').present?
answers.merge!({
'Check Box 41': @xml_document.at('Checking')&.text == "X" ? 'Yes' : 'Off',
'Check Box 42': @xml_document.at('Savings')&.text == "X" ? 'Yes' : 'Off',
'Text Box 93': @xml_document.at('RoutingTransitNumber')&.text,
'Text Box 94': @xml_document.at('BankAccountNumber')&.text,
})
end
answers
end

def spouse_ssn_if_mfs
Expand Down Expand Up @@ -139,6 +150,24 @@ def generate_codes_for_502_su
applicable_codes
end

def full_names_of_bank_account_holders
intake = @submission.data_source
return nil unless intake.payment_or_deposit_type.to_sym == :direct_deposit

if intake.has_joint_account_holder_yes?
account_holder_full_name + " and " + account_holder_full_name(for_joint: true)
else
account_holder_full_name
end
end

def account_holder_full_name(for_joint: false)
attributes = %w[FirstName MiddleInitial LastName NameSuffix]
account_holder_xmls = @xml_document.css('Form502 NameOnBankAccount')
account_holder_xml = for_joint ? account_holder_xmls[1] : account_holder_xmls[0]
attributes.map { |attr| account_holder_xml.at(attr)&.text }.filter_map(&:presence).join(" ")
end

def calculated_fields
@calculated_fields ||= @submission.data_source.tax_calculator.calculate
end
Expand Down
17 changes: 17 additions & 0 deletions app/lib/submission_builder/ty2024/states/md/documents/md502.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,23 @@ def document
end
add_element_if_present(xml, "TotalStateAndLocalTax", :MD502_LINE_34)
xml.TaxWithheld calculated_fields.fetch(:MD502_LINE_40)
xml.AuthToDirectDepositInd "X" if calculated_fields.fetch(:MD502_AUTHORIZE_DIRECT_DEPOSIT)
if @intake.payment_or_deposit_type.to_sym == :direct_deposit
xml.NameOnBankAccount do
xml.FirstName sanitize_for_xml(@intake.account_holder_first_name) if @intake.account_holder_first_name
xml.MiddleInitial sanitize_for_xml(@intake.account_holder_middle_initial) if @intake.account_holder_middle_initial
xml.LastName sanitize_for_xml(@intake.account_holder_last_name) if @intake.account_holder_last_name
xml.NameSuffix @intake.account_holder_suffix if @intake.account_holder_suffix
end
if @intake.has_joint_account_holder_yes?
xml.NameOnBankAccount do
xml.FirstName sanitize_for_xml(@intake.joint_account_holder_first_name) if @intake.joint_account_holder_first_name
xml.MiddleInitial sanitize_for_xml(@intake.joint_account_holder_middle_initial) if @intake.joint_account_holder_middle_initial
xml.LastName sanitize_for_xml(@intake.joint_account_holder_last_name) if @intake.joint_account_holder_last_name
xml.NameSuffix @intake.joint_account_holder_suffix if @intake.joint_account_holder_suffix
end
end
end
xml.DaytimePhoneNumber @direct_file_data.phone_number if @direct_file_data.phone_number.present?
end
end
Expand Down
4 changes: 1 addition & 3 deletions app/models/state_file_az_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
# account_type :integer
# armed_forces_member :integer default("unfilled"), not null
# armed_forces_wages_amount :decimal(12, 2)
# bank_name :string
# charitable_cash_amount :decimal(12, 2)
# charitable_contributions :integer default("unfilled"), not null
# charitable_noncash_amount :decimal(12, 2)
Expand All @@ -17,7 +16,6 @@
# current_sign_in_ip :inet
# current_step :string
# date_electronic_withdrawal :date
# df_data_import_failed_at :datetime
# df_data_import_succeeded_at :datetime
# df_data_imported_at :datetime
# eligibility_529_for_non_qual_expense :integer default("unfilled"), not null
Expand Down Expand Up @@ -86,7 +84,7 @@
# index_state_file_az_intakes_on_spouse_state_id_id (spouse_state_id_id)
#
class StateFileAzIntake < StateFileBaseIntake
self.ignored_columns = %w[charitable_cash charitable_noncash household_excise_credit_claimed_amt tribal_wages armed_forces_wages]
self.ignored_columns += %w[charitable_cash charitable_noncash household_excise_credit_claimed_amt tribal_wages armed_forces_wages]
encrypts :account_number, :routing_number, :raw_direct_file_data, :raw_direct_file_intake_data

has_many :az322_contributions, dependent: :destroy
Expand Down
3 changes: 1 addition & 2 deletions app/models/state_file_base_intake.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class StateFileBaseIntake < ApplicationRecord
self.ignored_columns = [:df_data_import_failed]
self.ignored_columns = [:df_data_import_failed_at, :bank_name]

devise :lockable, :timeoutable, :trackable

Expand Down Expand Up @@ -371,7 +371,6 @@ def self.opted_out_state_file_intakes(email)
def sanitize_bank_details
if (payment_or_deposit_type || "").to_sym != :direct_deposit
self.account_type = "unfilled"
self.bank_name = nil
self.routing_number = nil
self.account_number = nil
self.withdraw_amount = nil
Expand Down
2 changes: 0 additions & 2 deletions app/models/state_file_id_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
# id :bigint not null, primary key
# account_number :string
# account_type :integer default("unfilled"), not null
# bank_name :string
# consented_to_terms_and_conditions :integer default("unfilled"), not null
# contact_preference :integer default("unfilled"), not null
# current_sign_in_at :datetime
# current_sign_in_ip :inet
# current_step :string
# date_electronic_withdrawal :date
# df_data_import_failed_at :datetime
# df_data_import_succeeded_at :datetime
# df_data_imported_at :datetime
# donate_grocery_credit :integer default("unfilled"), not null
Expand Down
27 changes: 22 additions & 5 deletions app/models/state_file_md_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
# Table name: state_file_md_intakes
#
# id :bigint not null, primary key
# account_holder_name :string
# account_holder_first_name :string
# account_holder_last_name :string
# account_holder_middle_initial :string
# account_holder_suffix :string
# account_number :string
# account_type :integer default("unfilled"), not null
# authorize_sharing_of_health_insurance_info :integer default("unfilled"), not null
# bank_name :string
# bank_authorization_confirmed :integer default("unfilled"), not null
# city :string
# confirmed_permanent_address :integer default("unfilled"), not null
# consented_to_terms_and_conditions :integer default("unfilled"), not null
Expand All @@ -16,7 +19,6 @@
# current_sign_in_ip :inet
# current_step :string
# date_electronic_withdrawal :date
# df_data_import_failed_at :datetime
# df_data_import_succeeded_at :datetime
# df_data_imported_at :datetime
# eligibility_filing_status_mfj :integer default("unfilled"), not null
Expand All @@ -30,7 +32,12 @@
# failed_attempts :integer default(0), not null
# federal_return_status :string
# had_hh_member_without_health_insurance :integer default("unfilled"), not null
# has_joint_account_holder :integer default("unfilled"), not null
# hashed_ssn :string
# joint_account_holder_first_name :string
# joint_account_holder_last_name :string
# joint_account_holder_middle_initial :string
# joint_account_holder_suffix :string
# last_sign_in_at :datetime
# last_sign_in_ip :inet
# locale :string default("en")
Expand Down Expand Up @@ -111,6 +118,8 @@ class StateFileMdIntake < StateFileBaseIntake
enum authorize_sharing_of_health_insurance_info: { unfilled: 0, yes: 1, no: 2}, _prefix: :authorize_sharing_of_health_insurance_info
enum primary_did_not_have_health_insurance: { unfilled: 0, yes: 1, no: 2}, _prefix: :primary_did_not_have_health_insurance
enum spouse_did_not_have_health_insurance: { unfilled: 0, yes: 1, no: 2}, _prefix: :spouse_did_not_have_health_insurance
enum bank_authorization_confirmed: { unfilled: 0, yes: 1, no: 2 }, _prefix: :bank_authorization_confirmed
enum has_joint_account_holder: { unfilled: 0, yes: 1, no: 2 }, _prefix: :has_joint_account_holder

def disqualifying_df_data_reason
w2_states = direct_file_data.parsed_xml.css('W2StateLocalTaxGrp W2StateTaxGrp StateAbbreviationCd')
Expand Down Expand Up @@ -140,12 +149,20 @@ def calculate_age(dob, inclusive_of_jan_1)
def sanitize_bank_details
if (payment_or_deposit_type || "").to_sym != :direct_deposit
self.account_type = "unfilled"
self.bank_name = nil
self.routing_number = nil
self.account_number = nil
self.withdraw_amount = nil
self.date_electronic_withdrawal = nil
self.account_holder_name = nil
self.account_holder_first_name = nil
self.account_holder_middle_initial = nil
self.account_holder_last_name = nil
self.account_holder_suffix = nil
self.joint_account_holder_first_name = nil
self.joint_account_holder_middle_initial = nil
self.joint_account_holder_last_name = nil
self.joint_account_holder_suffix = nil
self.has_joint_account_holder = "unfilled"
self.bank_authorization_confirmed = "unfilled"
end
end

Expand Down
2 changes: 0 additions & 2 deletions app/models/state_file_nc_intake.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,13 @@
# id :bigint not null, primary key
# account_number :string
# account_type :integer default("unfilled"), not null
# bank_name :string
# city :string
# consented_to_terms_and_conditions :integer default("unfilled"), not null
# contact_preference :integer default("unfilled"), not null
# current_sign_in_at :datetime
# current_sign_in_ip :inet
# current_step :string
# date_electronic_withdrawal :date
# df_data_import_failed_at :datetime
# df_data_import_succeeded_at :datetime
# df_data_imported_at :datetime
# eligibility_lived_in_state :integer default("unfilled"), not null
Expand Down
Loading

0 comments on commit a074c6d

Please sign in to comment.