Background & Motivation
In issue FDM-210, the "Gewasresten achterlaten" (m_cropresidue) input was made conditionally visible based on b_lu_eom_residue === 0. This implementation is incorrect for two reasons:
- Wrong visibility condition: The input should only be visible when
b_lu_croprotation === 'cereal'. Whether the EOM residue value is zero does not correctly capture which crops can leave residues — the crop rotation category is the right signal.
- Wrong hidden value: When the input is hidden (non-cereal crops),
m_cropresidue is currently defaulted to false. It should be undefined instead. Setting it to false incorrectly implies "residues are removed", which causes the nitrogen balance to calculate residue removal for non-cereal crops where this concept does not apply.
Requirements
UI
- The "Gewasresten achterlaten" input must only be visible when
b_lu_croprotation === 'cereal'.
- When the input is hidden (not a cereal crop), the value of
m_cropresidue must be undefined — not false.
Balance Calculations
The semantic meaning of m_cropresidue:
true — user explicitly chose to leave residues on the field
false — user explicitly chose to remove residues from the field
undefined — no choice recorded (non-cereal crop); standard practice applies = residues are left on the field
- Organic matter supply by residues: supply must be calculated when
m_cropresidue !== false (i.e., for both true and undefined).
- Nitrogen removal by residues: removal must only be calculated when
m_cropresidue === false. For true or undefined, removal must be zero.
Affected Files
fdm-app
fdm-app/app/components/blocks/cultivation/card-details.tsx
- Change the
invisible class condition from !cultivation.b_lu_eom_residue → cultivation.b_lu_croprotation !== 'cereal'
- Change the
defaultValues / reset for m_cropresidue:
- Before:
!!cultivation.b_lu_eom_residue && (cultivation.m_cropresidue ?? false)
- After:
cultivation.b_lu_croprotation === 'cereal' ? (cultivation.m_cropresidue ?? undefined) : undefined
fdm-app/app/components/blocks/rotation/columns.tsx
- Change the cell render condition for the
m_cropresidue column:
- Before:
(props.row.original.b_lu_eom_residue ?? 0) !== 0
- After:
props.row.original.b_lu_croprotation === 'cereal'
fdm-calculator (verify, no change expected)
fdm-calculator/src/balance/nitrogen/removal/residue.ts
- Already correctly handled. The guard
if (cultivation.m_cropresidue !== false) returns zero for both true and undefined. No functional change needed, but add a test case that explicitly covers m_cropresidue === undefined resulting in zero removal.
fdm-calculator/src/balance/organic-matter/supply/residues.ts
- Bug: Line 39 uses
cult.m_cropresidue as a truthy check, so undefined currently yields zero EOM supply — this is wrong. Standard practice when m_cropresidue is undefined is that residues are left on the field, so supply should be calculated.
- Change the condition:
- Before:
cultivationDetail?.b_lu_eom_residue != null && cult.m_cropresidue
- After:
cultivationDetail?.b_lu_eom_residue != null && cult.m_cropresidue !== false
- Add a test case that verifies
m_cropresidue === undefined results in the same EOM supply as m_cropresidue === true.
Acceptance Criteria
Technical Notes
b_lu_croprotation is a database enum defined in fdm-core/src/db/schema.ts with values: other, clover, nature, potato, grass, rapeseed, starch, maize, cereal, sugarbeet, alfalfa, catchcrop.
- Both
CropRow and FieldRow in columns.tsx already carry b_lu_croprotation: string, so no data-fetching changes are needed.
- The
Cultivation type in fdm-core/src/cultivation.types.d.ts already exposes b_lu_croprotation.
Background & Motivation
In issue FDM-210, the "Gewasresten achterlaten" (
m_cropresidue) input was made conditionally visible based onb_lu_eom_residue === 0. This implementation is incorrect for two reasons:b_lu_croprotation === 'cereal'. Whether the EOM residue value is zero does not correctly capture which crops can leave residues — the crop rotation category is the right signal.m_cropresidueis currently defaulted tofalse. It should beundefinedinstead. Setting it tofalseincorrectly implies "residues are removed", which causes the nitrogen balance to calculate residue removal for non-cereal crops where this concept does not apply.Requirements
UI
b_lu_croprotation === 'cereal'.m_cropresiduemust beundefined— notfalse.Balance Calculations
The semantic meaning of
m_cropresidue:true— user explicitly chose to leave residues on the fieldfalse— user explicitly chose to remove residues from the fieldundefined— no choice recorded (non-cereal crop); standard practice applies = residues are left on the fieldm_cropresidue !== false(i.e., for bothtrueandundefined).m_cropresidue === false. Fortrueorundefined, removal must be zero.Affected Files
fdm-appfdm-app/app/components/blocks/cultivation/card-details.tsxinvisibleclass condition from!cultivation.b_lu_eom_residue→cultivation.b_lu_croprotation !== 'cereal'defaultValues/resetform_cropresidue:!!cultivation.b_lu_eom_residue && (cultivation.m_cropresidue ?? false)cultivation.b_lu_croprotation === 'cereal' ? (cultivation.m_cropresidue ?? undefined) : undefinedfdm-app/app/components/blocks/rotation/columns.tsxm_cropresiduecolumn:(props.row.original.b_lu_eom_residue ?? 0) !== 0props.row.original.b_lu_croprotation === 'cereal'fdm-calculator(verify, no change expected)fdm-calculator/src/balance/nitrogen/removal/residue.tsif (cultivation.m_cropresidue !== false)returns zero for bothtrueandundefined. No functional change needed, but add a test case that explicitly coversm_cropresidue === undefinedresulting in zero removal.fdm-calculator/src/balance/organic-matter/supply/residues.tscult.m_cropresidueas a truthy check, soundefinedcurrently yields zero EOM supply — this is wrong. Standard practice whenm_cropresidueis undefined is that residues are left on the field, so supply should be calculated.cultivationDetail?.b_lu_eom_residue != null && cult.m_cropresiduecultivationDetail?.b_lu_eom_residue != null && cult.m_cropresidue !== falsem_cropresidue === undefinedresults in the same EOM supply asm_cropresidue === true.Acceptance Criteria
b_lu_croprotation === 'cereal', both in the Cultivation Details card and in the Rotation Table.m_cropresidueis stored/submitted asundefined(notfalse).m_cropresidue !== false(covers bothtrueandundefined).0for cultivations wherem_cropresidueisundefinedortrue.residue.test.tsthat explicitly verifiesm_cropresidue === undefinedresults in zero removal.Technical Notes
b_lu_croprotationis a database enum defined infdm-core/src/db/schema.tswith values:other,clover,nature,potato,grass,rapeseed,starch,maize,cereal,sugarbeet,alfalfa,catchcrop.CropRowandFieldRowincolumns.tsxalready carryb_lu_croprotation: string, so no data-fetching changes are needed.Cultivationtype infdm-core/src/cultivation.types.d.tsalready exposesb_lu_croprotation.