P3 review: asset bases and the tax-basis K-1

Schema 13 is as shipped and the asset columns are schema 14 (shipped
migrations pinned by hash); the tax-basis K-1 leaves net income open (only
the return has it) and takes a contributed prepaid plan at its book amount
as its section 723 basis; a disposal of contributed property names its
704(c) gain or loss; aliases compare by meaning; fixture amounts made up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-21 17:43:44 -06:00
1 parent 2ae93fb2d6
commit 6288ead747
24 files changed
+860 -127

No files matched your search

+6 -3
View File
@@ -203,8 +203,11 @@ pub fn book_vs_tax(rule: Option<BasisRule>) -> &'static str {
Some(BasisRule::Purchase) => {
"Book cost and tax basis are both what the company paid; tax depreciation starts from the tax basis — the CPA's."
}
_ => {
"Book value is the fair market value at contribution; the tax figures are at contribution, and tax depreciation starts from the depreciable basis — the CPA's."
Some(BasisRule::Carryover723 | BasisRule::PersonalUseConversion) => {
"Book cost is the fair market value at contribution, and book value that cost less the depreciation posted; the tax figures are at contribution, and tax depreciation starts from the depreciable basis — the CPA's."
}
None => {
"No tax basis is recorded: book value is cost less the depreciation posted; the tax figures follow once the basis is recorded."
}
}
}
@@ -1433,7 +1436,7 @@ fn tax_card(ui: &mut Ui, a: &Asset) {
ui.add(
egui::Label::new(
RichText::new(
"Ask the bookkeeper to record it (books.set_asset_tax_basis): was it bought by the company, contributed by a member from business use, or converted from personal use? Book value is the fair market value at contribution; tax depreciation starts from the tax basis — the CPA's.",
"Ask the bookkeeper to record it (books.set_asset_tax_basis): was it bought by the company, contributed by a member from business use, or converted from personal use? For a contribution, book cost is the fair market value at contribution; tax depreciation starts from the depreciable basis — the CPA's.",
)
.font(theme::regular(12.5))
.color(p.muted),
+7
View File
@@ -363,6 +363,9 @@ fn assets(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
AssetStatus::Disposed { date, .. } if *date <= b.today => Some(*date),
_ => None,
};
// Not on the books until its acquired date: no book value
// yet (the register leaves it out the same way).
let later = b.ledger.asset_acquired_date(a.id).filter(|d| *d > b.today);
let acc = b.ledger.accumulated_posted(a.id, b.today);
let scheduled = accumulated_scheduled_through(a, b.today);
let dep = a.cost.amount - a.salvage_value.amount;
@@ -391,6 +394,10 @@ fn assets(ui: &mut Ui, b: &Books, shell: &mut Shell<'_>) {
);
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
let text = match (&acc, disposed) {
_ if later.is_some() => format!(
"not on the books until {}",
fmt::date(later.expect("checked"))
),
(_, Some(_)) => format!("book value {}", fmt::dollars(Decimal::ZERO)),
(Ok(acc), None) => {
format!("book value {}", fmt::dollars(a.cost.amount - *acc))
+4 -1
View File
@@ -65,7 +65,10 @@ fn attachment_name(b: &Books, id: u64) -> String {
/// depreciable basis $1,440.00, built-in loss $248.40". The figures are
/// ledger-core's (`Asset::basis_figures`) for the event's facts on the
/// asset; a pre-P3 `asset.tax_basis_set` (`legacy`: its rule by its old
/// name, no value) reads the value as the book cost, as it was recorded.
/// name, no value) reads the value as the asset's book cost today, which
/// is the cost it was recorded against unless the cost was corrected since
/// (a correction moves a pre-P3 record's built-in gain, and the line shows
/// today's figure).
fn tax_basis_text(b: &Books, asset_id: Option<u64>, p: &Value, legacy: bool) -> String {
let asset = asset_id.and_then(|id| b.ledger.get_asset(id));
let name = match (asset, asset_id) {
+23 -12
View File
@@ -1148,17 +1148,20 @@ fn aging(
/// The fixed asset register on `as_of`: ledger-core's
/// `fixed_asset_register`, laid out, with its reconciliation to the
/// general ledger and what that says (the Assets page's notices). Each
/// asset's federal tax basis sits beside its book figures: contributor's
/// basis, tax basis, and built-in gain (loss), the register row's own,
/// with its rule (and citation) in the detail; the tax basis total is the
/// general ledger and what that says (the Assets page's notices). The
/// book figures in the Assets page's order (cost, posted, book value =
/// cost less posted, then the schedule's figure); beside them each
/// asset's tax figures at contribution, the register row's own: §723
/// basis, depreciable basis and §704(c) built-in gain (loss), with its
/// rule (and citation), value at contribution, method and, for a built-in
/// loss, the IRC §704(c)(1)(C) note in the detail; the totals are the
/// register's.
fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
let mut t = Table::new(vec![
"Cost".into(),
"Scheduled".into(),
"Posted".into(),
"Book value".into(),
"Scheduled".into(),
// Short enough for the columns: the note says what each is.
"§723 basis".into(),
"Depr. basis".into(),
@@ -1217,6 +1220,12 @@ fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
ledger_import::asset_register::method_cited(m)
));
}
if tax.built_in_gain_704c.is_some_and(|g| g < Decimal::ZERO) {
detail.push(
"a built-in loss counts only for the contributing member (IRC §704(c)(1)(C))"
.into(),
);
}
let opt = |v: Option<Decimal>| Cell {
value: v,
drill: None,
@@ -1232,9 +1241,9 @@ fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
}
None => vec![
Cell::of(x.cost),
Cell::of(x.accumulated_scheduled),
Cell::of(x.accumulated_posted),
Cell::of(x.book_value),
Cell::of(x.accumulated_scheduled),
opt(tax.tax_basis_723),
opt(tax.depreciable_basis),
opt(tax.built_in_gain_704c),
@@ -1252,9 +1261,9 @@ fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
"Total held",
vec![
Cell::of(r.total_cost),
Cell::of(r.total_accumulated_scheduled),
Cell::of(r.total_accumulated_posted),
Cell::of(r.total_book_value),
Cell::of(r.total_accumulated_scheduled),
Cell::of(r.total_tax_basis_723),
Cell::of(r.total_depreciable_basis),
Cell::none(),
@@ -1292,11 +1301,11 @@ fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
value: Some(r.ledger_accumulated),
drill: accum_drill,
},
Cell::of(r.ledger_cost - r.ledger_accumulated),
Cell {
value: Some(r.ledger_accumulated),
drill: accum_drill,
},
Cell::of(r.ledger_cost - r.ledger_accumulated),
Cell::none(),
Cell::none(),
Cell::none(),
@@ -1307,9 +1316,9 @@ fn asset_register(b: &Books, as_of: NaiveDate) -> Table {
"Register less books",
vec![
Cell::of(-r.unregistered_cost()),
Cell::of(r.unposted_depreciation()),
Cell::of(-r.unattributed_accumulated()),
Cell::of(r.total_book_value - (r.ledger_cost - r.ledger_accumulated)),
Cell::of(r.unposted_depreciation()),
Cell::none(),
Cell::none(),
Cell::none(),
@@ -2441,9 +2450,9 @@ mod tests {
t.columns,
[
"Cost",
"Scheduled",
"Posted",
"Book value",
"Scheduled",
"§723 basis",
"Depr. basis",
"Built-in gain"
@@ -2462,9 +2471,9 @@ mod tests {
v,
[
Some(x.cost),
Some(x.accumulated_scheduled),
Some(x.accumulated_posted),
Some(x.book_value),
Some(x.accumulated_scheduled),
f.tax_basis_723,
Some(f.depreciable_basis),
f.built_in_gain_704c,
@@ -2476,7 +2485,9 @@ mod tests {
let total = t.rows.iter().find(|row| row.label == "Total held").unwrap();
assert_eq!(total.cells[5].value, Some(r.total_depreciable_basis));
assert_eq!(total.cells[5].value, r.rows[0].depreciable_basis);
assert_eq!(total.cells[2].value, Some(r.total_accumulated_posted));
assert_eq!(total.cells[1].value, Some(r.total_accumulated_posted));
assert_eq!(total.cells[2].value, Some(r.total_book_value));
assert_eq!(total.cells[3].value, Some(r.total_accumulated_scheduled));
assert!(
t.rows
.iter()