Skip to content

Add 1099-B tax form#1616

Open
nyomanjyotisa wants to merge 4 commits intomainfrom
1099-B
Open

Add 1099-B tax form#1616
nyomanjyotisa wants to merge 4 commits intomainfrom
1099-B

Conversation

@nyomanjyotisa
Copy link
Member

@nyomanjyotisa nyomanjyotisa commented Feb 13, 2026

Issue: #1614
Ref https://chat.google.com/room/AAQAWojMDVI/DOxHDk3v5ao/VQHyvh5xEQw?cls=10

Description

Add full 1099-B tax form generation support for Return of Capital dividend transactions


After

All data exist

1099-B-sample-full-data.pdf
Screenshot 2026-02-13 at 14 40 15

If number of shares, date accquired, and invesment amount unknown or not exist on database

Screenshot 2026-02-13 at 14 37 51

AI Disclosure

Claude Opus 4.6 for code generation. All code self reviewed

@nyomanjyotisa nyomanjyotisa marked this pull request as draft February 13, 2026 04:59
@nyomanjyotisa nyomanjyotisa self-assigned this Feb 13, 2026
scope :with_required_tax_info_for, -> (tax_year:) do
dividends_subquery = Dividend.select("company_investor_id")
.for_tax_year(tax_year)
.not_return_of_capital
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return of capital dividends are reported on 1099-B, not 1099-DIV. Without this filter, an investor who only received Return of Capital dividends could incorrectly trigger a 1099-DIV

.not_return_of_capital
.group("company_investor_id")
.having("SUM(total_amount_in_cents) >= ?", MIN_DIVIDENDS_AMOUNT_FOR_TAX_FORMS)
.having("SUM(dividends.total_amount_in_cents) >= ?", MIN_DIVIDENDS_AMOUNT_FOR_TAX_FORMS)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the dividends. table qualifier because the .not_return_of_capital scope joins dividend_rounds, and the unqualified total_amount_in_cents column is ambiguous between the two tables

def mark_deleted!
docs = documents.tax_document.unsigned
docs = docs.where.not(document_type: [:form_1099div, :form_1042s]) if dividends.paid.any?
docs = docs.where.not(document_type: :form_1099b) if dividends.paid.return_of_capital.exists?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a user re-submits their tax info (W-9), we delete their unsigned tax forms and regenerate them. But if they already have paid Return of Capital dividends, we must preserve the 1099-B, same logic as the existing 1099-DIV/1042-S preservation above

end

# Box 5: Noncovered security (private company shares are noncovered)
result[noncovered_field(copy, page)] = "1"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Private company shares are always noncovered securities per IRS rules, meaning the broker is not required to report cost basis to the IRS

def long_term?
earliest_acquired = investor.share_holdings.minimum(:originally_acquired_at)
latest_sold = roc_dividends_for_tax_year.filter_map(&:paid_at).max
return true unless earliest_acquired && latest_sold
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't have share holding acquisition dates, we default to long-term

@_dividend_amounts_for_tax_year ||= investor.dividends
.for_tax_year(tax_year)
.pluck("SUM(total_amount_in_cents), SUM(withheld_tax_cents), SUM(qualified_amount_cents)")
.not_return_of_capital
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excluding Return of Capital dividends here prevents double-reporting


def type_of_return = "B ".ljust(2) # Proceeds from broker and barter exchange transactions

def amount_codes = "24".ljust(18) # Amount code 2 = Gross proceeds, Amount code 4 = Federal income tax withheld
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per IRS FIRE format spec: Amount Code 2 = Gross proceeds, Amount Code 4 = Federal income tax withheld. These are the only two payment amount fields used for 1099-B broker transactions

tax_year:,
)

if user_compliance_info.requires_w9?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1099-B is only filed for US tax residents (W-9 filers)

end
end

def collect_roc_tax_form_data(tax_year, user_compliance_info_ids, company_ids, user_compliance_info_company_ids)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return of Capital tax forms can't use the shared collect_tax_form_data_for method because Return of Capital eligibility is based on having Return of Capital dividends (via CompanyInvestor.with_return_of_capital_dividends_for), not on meeting a minimum dividend threshold like 1099-DIV/1099-NEC.

We will submit form 1099-NEC to the IRS on {formatDate(new Date(currentYear, 0, 31))}, form 1042-S on{" "}
{formatDate(new Date(currentYear, 2, 15))}, and form 1099-DIV on {formatDate(filingDueDateFor1099DIV)}.
{formatDate(new Date(currentYear, 2, 15))}, and forms 1099-DIV and 1099-B on{" "}
{formatDate(filingDueDateFor1099DIV)}.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1099-B shares the same IRS filing deadline as 1099-DIV (March 31)

@nyomanjyotisa nyomanjyotisa marked this pull request as ready for review February 13, 2026 07:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants