-
Notifications
You must be signed in to change notification settings - Fork 381
Add TIN reverification workflow for 1099-DIV #1591
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,7 +86,10 @@ def update_tax_id_status | |
| tax_status_related_attributes = %w[legal_name business_name business_entity tax_id] | ||
|
|
||
| if persisted? | ||
| self.tax_id_status = nil if tax_status_related_attributes.any? { send("#{_1}_changed?") } | ||
| if tax_status_related_attributes.any? { send("#{_1}_changed?") } | ||
| self.tax_id_status = nil | ||
| self.requires_tin_reverification = false if requires_tin_reverification? | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clear re-verification flag if user updates their tax information |
||
| end | ||
| elsif prior_compliance_info.present? && prior_compliance_info.attributes.values_at(*tax_status_related_attributes) == attributes.values_at(*tax_status_related_attributes) | ||
| self.tax_id_status = prior_compliance_info.tax_id_status | ||
| end | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| # Onetime script to flag users from IRS CP 2100A notice for TIN re-verification | ||
| # Usage: | ||
| # tins = %w[111111111 222222222] | ||
| # Onetime::FlagCp2100aTinReverification.perform(tins:, dry_run: true) # Preview only | ||
| # Onetime::FlagCp2100aTinReverification.perform(tins:, dry_run: false) # Actually flag users | ||
| class Onetime::FlagCp2100aTinReverification | ||
| def self.perform(tins:, dry_run: true) | ||
| if dry_run | ||
| puts "DRY RUN MODE - No changes will be made" | ||
| puts "" | ||
| else | ||
| puts "LIVE MODE - Users will be flagged for TIN re-verification" | ||
| puts "" | ||
| end | ||
|
|
||
| puts "Processing #{tins.count} TINs from IRS CP 2100A notice..." | ||
| puts "================================================================================" | ||
|
|
||
| found_users = [] | ||
| not_found_tins = [] | ||
|
|
||
| all_compliance_infos = UserComplianceInfo.alive.where.not(tax_id: nil).includes(:user) | ||
|
|
||
| tins.each do |tin| | ||
| compliance_info = all_compliance_infos.find { |ci| ci.tax_id == tin } | ||
|
|
||
| if compliance_info.nil? | ||
| not_found_tins << tin | ||
| next | ||
| end | ||
|
|
||
| user = compliance_info.user | ||
| found_users << { | ||
| user:, | ||
| compliance_info:, | ||
| tin:, | ||
| } | ||
| end | ||
|
|
||
| puts "\n=== FOUND USERS (#{found_users.count}) ===" | ||
| puts "================================================================================" | ||
|
|
||
| if found_users.any? | ||
| found_users.each_with_index do |data, index| | ||
| user = data[:user] | ||
| tin = data[:tin] | ||
|
|
||
| puts "\n#{index + 1}. User ID: #{user.id}" | ||
| puts " Email: #{user.email}" | ||
| puts " Name: #{user.name}" | ||
| puts " Legal Name: #{user.legal_name}" | ||
| puts " TIN: ***#{tin[-4..]}" | ||
| puts " Current Status: #{data[:compliance_info].requires_tin_reverification ? 'Already flagged' : 'Not flagged'}" | ||
|
|
||
| if dry_run | ||
| puts " [DRY RUN] Would flag this user for TIN re-verification and send email" | ||
| else | ||
| begin | ||
| data[:compliance_info].update!( | ||
| requires_tin_reverification: true, | ||
| tax_id_status: nil | ||
| ) | ||
| UserMailer.tin_reverification_required(user.id).deliver_later | ||
| puts " ✓ Flagged for TIN re-verification and email sent" | ||
| rescue => e | ||
| puts " ✗ Error: #{e.message}" | ||
| end | ||
| end | ||
| end | ||
| else | ||
| puts "No users found with the provided TINs" | ||
| end | ||
|
|
||
| if not_found_tins.any? | ||
| puts "\n=== NOT FOUND TINS (#{not_found_tins.count}) ===" | ||
| puts "================================================================================" | ||
| not_found_tins.each do |tin| | ||
| puts " ***#{tin[-4..]}" | ||
| end | ||
| end | ||
|
|
||
| puts "\n================================================================================" | ||
| puts "SUMMARY:" | ||
| puts "================================================================================" | ||
| puts " Total TINs processed: #{tins.count}" | ||
| puts " Users found: #{found_users.count}" | ||
| puts " TINs not found: #{not_found_tins.count}" | ||
|
|
||
| if dry_run | ||
| puts "\n✓ Dry run complete! No changes were made." | ||
| puts " To actually flag users and send emails, run with dry_run: false" | ||
| else | ||
| puts "\n✓ Flagging complete!" | ||
| puts " Users have been flagged for TIN re-verification and emails have been sent." | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| <h1>IRS Notice: Action Required</h1> | ||
| <p>We received a <strong>CP 2100A notice from the IRS</strong> regarding a mismatch between your <%= @user.business_entity? ? "business name" : "legal name" %> and <%= @user.tax_id_name %> on file.</p> | ||
|
|
||
| <p>To continue receiving payments without tax withholding, please log in to Flexile and re-enter your tax information. <strong>Your legal name must match your IRS records exactly.</strong></p> | ||
|
|
||
| <p><strong>Important:</strong> Until you update your information, you will not be able to receive payments.</p> | ||
|
|
||
| <%= link_to "Update your tax info", @settings_url, class: "button" %> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| class AddTinReverificationFieldsToUserComplianceInfos < ActiveRecord::Migration[8.0] | ||
| def change | ||
| add_column :user_compliance_infos, :requires_tin_reverification, :boolean, default: false, null: false | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,20 @@ function DashboardLayout({ children }: { children: React.ReactNode }) { | |
| logout(); | ||
| }; | ||
|
|
||
| React.useEffect(() => { | ||
| if (user.requiresTinReverification && pathname !== "/settings/tax") { | ||
| router.replace("/settings/tax"); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redirect users flagged for TIN re-verification to the tax settings page to forced them to re-enter their TIN and name |
||
| } | ||
| }, [user.requiresTinReverification, pathname, router]); | ||
|
|
||
| if (user.requiresTinReverification && pathname !== "/settings/tax") { | ||
| return ( | ||
| <div className="flex h-screen items-center justify-center"> | ||
| <p className="text-muted-foreground">Redirecting...</p> | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Block rendering while redirecting |
||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <SidebarProvider> | ||
| <Sidebar collapsible="offcanvas" mobileSidebar={<MobileBottomNav />}> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Set
has_verified_tax_idtofalseifrequires_tin_reverificationistrueto prevent flagged users to receive any payments