How to
Import "Intelligent Form 8949 Statements"
into Tax Software
This information is intended for developers of tax software.
Exception 2
As you are aware, the IRS allows taxpayers to report their transactions using what they call "Exception 2". Exception 2 reads as follows:
Instead of reporting each of your transactions on a separate row of Part I or II,
you can report them on an attached statement containing all the same information as Parts I and II and in a similar format".
The Statement (PDF)
The statements we generate contain the same information and are in a format that qualifies under Exception 2.
The statement has a cover page.
The cover page is followed by pages showing the detailed transactions.
"Intelligent" Form 8949 Statements
The statements we generate take advantage of Intelligent Tax Document™ technology.
The summary transaction data to be reported on Form 8949 is included in the PDF "Custom Document Properties" as seen below.
Accept PDF
Your tax software accepts upload of the PDF file. You will probably use "MultipartFile" technology to do this.
For example:
@PostMapping( value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE ) private void acceptUploadedFile( @RequestPart( "file" ) MultipartFile file, ) { byte[] bytes = file.getBytes( ); }
You will then save this PDF for attachment to the electronic tax return.
Extract and Import Summary Transaction Data
You extract the JSON from the PDF.
PdfFdxJsonReader reader = new PdfFdxJsonReader( ); reader.read( bytes ); String json = reader.getFdxJson( );
package readers; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDDocumentInformation; import java.io.File; public class PdfFdxJsonReader { private String fdxJson; private String fdxVersion; private String fdxSoftwareId; public String getFdxJson( ) { return fdxJson; } public String getFdxVersion( ) { return fdxVersion; } public String getFdxSoftwareId( ) { return fdxSoftwareId; } public void read( byte[] pdfBytes ) { try ( PDDocument document = PDDocument.load( pdfBytes ); ) { PDDocumentInformation info = document.getDocumentInformation( ); if ( info == null ) { return; } this.fdxJson = info.getCustomMetadataValue( "fdxJson" ); this.fdxVersion = info.getCustomMetadataValue( "fdxVersion" ); this.fdxSoftwareId = info.getCustomMetadataValue( "fdxSoftwareId" ); } catch ( Exception e ) { } } }
The JSON will look like this:
{ "forms" : [ { "tax1099B" : { "securityDetails" : [ { "checkboxOnForm8949" : "A", "saleDescription" : "See Attached Statement A", "salesPrice" : 5285483.32, "adjustmentCodes" : [ { "code" : "B", "amount" : -119.09 }, { "code" : "M" } ], "costBasis" : 5363446.72, "washSaleLossDisallowed" : 67796.95 }, { "checkboxOnForm8949" : "B", "saleDescription" : "See Attached Statement B", "salesPrice" : 628000.29, "adjustmentCodes" : [ { "code" : "M" } ], "costBasis" : 636552.72, "washSaleLossDisallowed" : 18.51 } ] } } ] }
Next, deserialize the JSON to a TaxDataList object.
TaxDataList taxDataList = TaxDataListSerializer.deserialize( json );
package fdx.tax.json; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonGenerationException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.joda.JodaModule; import fdx.tax.models.*; import java.io.IOException; import java.io.StringWriter; public class TaxDataListSerializer { public static TaxDataList deserialize( String json ) { TaxDataList data = null; try { ObjectMapper objectMapper = new ObjectMapper( ); // Special handling for dates objectMapper.registerModule( new JodaModule( ) ); objectMapper.disable( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS ); data = objectMapper.readValue( json, TaxDataList.class ); } catch( Exception e ) { } return data; } }
Then read the summary transactions (SecurityDetail) from the TaxDataList object and import the transaction data into the tax return.
List<YourForm8949Entry> entries = extractForm8949Entries( taxDataList ); importEntries( entries );
public static List<YourForm8949Entry> extractForm8949Entries( TaxDataList taxDataList ) { List<YourForm8949Entry> form8949Entries = new ArrayList<>(); List<TaxData> forms = taxDataList.getForms( ); for ( TaxData taxData : forms ) { Tax1099B tax1099B = taxData.getTax1099B( ); if ( tax1099B == null ) continue; List<SecurityDetail> securityDetails = tax1099B.getSecurityDetails( ); if ( securityDetails == null ) continue; for ( SecurityDetail securityDetail : securityDetails ) { YourForm8949Entry yourForm8949Entry = convertSecurityDetail( securityDetail ); form8949Entries.add( yourForm8949Entry ); } } return form8949Entries; } public static YourForm8949Entry convertSecurityDetail( SecurityDetail securityDetail ) { YourForm8949Entry yourForm8949Entry = new YourForm8949Entry( ); // Map FDX SecurityDetail to YourForm8949Entry // ... return yourForm8949Entry; }
private static void importEntries( List<YourForm8949Entry> entries ) { // Import into tax return as if the user had entered these values }
Feel free to contact us at support@form8949.com for additional source code and resources.