diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8494bc2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,161 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+build/
+[Bb]in/
+[Oo]bj/
+
+# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
+!packages/*/build/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+*.exe
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+#sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+
+#LightSwitch generated files
+GeneratedArtifacts/
+_Pvt_Extensions/
+ModelManifest.xml
+
+# =========================
+# Windows detritus
+# =========================
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac desktop service store files
+.DS_Store
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..081f197
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/pack.cmd b/pack.cmd
new file mode 100644
index 0000000..1defcf6
--- /dev/null
+++ b/pack.cmd
@@ -0,0 +1,4 @@
+source\.nuget\nuget.exe pack source\OFXSharper\OFXSharper.csproj -Prop Configuration=Release
+echo # update Project Url: https://github.com/Habanerio/OFXSharper
+echo # update License Url: http://opensource.org/licenses/MIT
+pause
\ No newline at end of file
diff --git a/source/.editorconfig b/source/.editorconfig
new file mode 100644
index 0000000..2c73003
--- /dev/null
+++ b/source/.editorconfig
@@ -0,0 +1,273 @@
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
+root = true
+
+# All files
+[*]
+charset = utf-8
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_readonly_field = true:suggestion
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_code_quality_unused_parameters = all:suggestion
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+
+# C# files
+[*.cs]
+
+#### Core EditorConfig Options ####
+
+# Indentation and spacing
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET Coding Conventions ####
+
+# Organize usings
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false:silent
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_property = false:silent
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+
+# Expression-level preferences
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+
+# Field preferences
+dotnet_style_readonly_field = true:suggestion
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all:suggestion
+
+#### C# Coding Conventions ####
+
+# var preferences
+csharp_style_var_elsewhere = false:silent
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_prefer_switch_expression = true:suggestion
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:suggestion
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
+
+# Code-block preferences
+csharp_prefer_braces = true:silent
+csharp_prefer_simple_using_statement = true:suggestion
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:warning
+
+#### C# Formatting Rules ####
+
+# New line preferences
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = no_change
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = false
+
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+csharp_style_namespace_declarations = file_scoped:suggestion
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_prefer_readonly_struct = true:suggestion
+csharp_style_prefer_readonly_struct_member = true:suggestion
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent
+csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_extended_property_pattern = true:suggestion
+
+# Constants are UPPERCASE
+dotnet_naming_rule.constants_should_be_upper_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_upper_case.symbols = constants
+dotnet_naming_rule.constants_should_be_upper_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = all_upper
+
+[*.cs]
+dotnet_diagnostic.MA0053.severity = suggestion
+
+# Report public classes without inheritors (default: false)
+MA0053.public_class_should_be_sealed = true
+
+# Report class without inheritors even if there is virtual members (default: false)
+MA0053.class_with_virtual_member_shoud_be_sealed = true
diff --git a/source/.nuget/NuGet.Config b/source/.nuget/NuGet.Config
new file mode 100644
index 0000000..67f8ea0
--- /dev/null
+++ b/source/.nuget/NuGet.Config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/.nuget/NuGet.targets b/source/.nuget/NuGet.targets
new file mode 100644
index 0000000..593e44a
--- /dev/null
+++ b/source/.nuget/NuGet.targets
@@ -0,0 +1,151 @@
+
+
+
+ $(MSBuildProjectDirectory)\..\
+
+
+ false
+
+
+ false
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+ $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
+
+
+
+
+ $(SolutionDir).nuget
+
+
+
+ packages.$(MSBuildProjectName.Replace(' ', '_')).config
+
+
+
+
+
+ $(PackagesProjectConfig)
+
+
+
+
+ packages.config
+
+
+
+
+
+
+ $(NuGetToolsPath)\NuGet.exe
+ @(PackageSource)
+
+ "$(NuGetExePath)"
+ mono --runtime=v4.0.30319 $(NuGetExePath)
+
+ $(TargetDir.Trim('\\'))
+
+ -RequireConsent
+ -NonInteractive
+
+ "$(SolutionDir) "
+ "$(SolutionDir)"
+
+
+ $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
+ $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
+
+
+
+ RestorePackages;
+ $(BuildDependsOn);
+
+
+
+
+ $(BuildDependsOn);
+ BuildPackage;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/.unitTestGeneratorConfig b/source/.unitTestGeneratorConfig
new file mode 100644
index 0000000..084b10c
--- /dev/null
+++ b/source/.unitTestGeneratorConfig
@@ -0,0 +1,76 @@
+[GenerationOptions]
+AutoDetectFrameworkTypes=False
+FrameworkType=XUnit
+MockingFrameworkType=MoqAutoMock
+AllowGenerationWithoutTargetProject=True
+TestProjectNaming={0}.Tests
+TestFileNaming={0}Tests
+TestTypeNaming={0}Tests
+UseFluentAssertions=False
+UseShouldly=False
+UseAutoFixture=True
+UseAutoFixtureForMocking=True
+UseFieldForAutoFixture=True
+EmitUsingsOutsideNamespace=True
+PartialGenerationAllowed=True
+EmitTestsForInternals=False
+AutomaticallyConfigureMocks=True
+EmitSubclassForProtectedMethods=True
+ArrangeComment=Arrange
+ActComment=Act
+AssertComment=Assert
+UserInterfaceMode=WhenTargetNotFound
+FallbackTargetFinding=TypeInCorrectNamespace
+PrefixFieldReferencesWithThis=False
+EmitXmlDocumentation=False
+UseMockBehaviorStrict=False
+CreateTargetAssets=True
+TestTypeBaseClass=
+TestTypeBaseClassNamespace=
+GenerateFileScopedNamespaces=True
+PlaceSystemUsingDirectivesFirst=True
+SkipInternalTypesOnMultipleGeneration=False
+DefaultFailureMessage=Create or modify test
+EmitMultilinePocoInitializers=True
+UseFieldsForConstructorParameterTests=True
+
+[NamingOptions]
+CanConstructNamingPattern=Can_Construct
+CannotConstructWithNullNamingPattern=Cannot_Construct_WithNull_{parameterName}
+CannotConstructWithInvalidNamingPattern=Cannot_Construct_WithInvalid_{parameterName}
+CanInitializeNamingPattern=Can_Initialize
+CannotInitializeWithNullNamingPattern=Cannot_Initialize_WithNull_{memberName}
+CannotInitializeWithInvalidNamingPattern=Cannot_Initialize_WithInvalid_{memberName}
+CanGetNamingPattern=CanGet_{memberName}
+CanSetAndGetNamingPattern=CanSet_And_Get_{memberName}
+CanSetNamingPattern=CanSet_{memberName}
+IsInitializedCorrectlyNamingPattern={memberName}_IsInitialized_Correctly
+ImplementsIEnumerableNamingPattern=ImplementsI_Enumerable_{typeParameters}
+ImplementsIComparableNamingPattern=ImplementsI_Comparable_{typeParameters}
+ImplementsIEquatableNamingPattern=ImplementsI_Equatable_{typeParameters}
+CanCallNamingPattern=CanCall_{memberName}
+PerformsMappingNamingPattern={memberName}_PerformsMapping
+CannotCallWithNullNamingPattern=CannotCall_{memberName}_WithNull_{parameterName}
+CannotCallWithInvalidNamingPattern=CannotCall_{memberName}_WithInvalid_{parameterName}
+CanCallOperatorNamingPattern=CanCall_{memberName}_Operator
+CannotCallOperatorWithNullNamingPattern=CannotCall_{memberName}_Operator_WithNull_{parameterName}
+TargetFieldName=_testClass
+DependencyFieldName=_{parameterName:camel}
+MockDependencyFieldName=
+AutoFixtureFieldName=_fixture
+ForceAsyncSuffix=False
+
+[StrategyOptions]
+ConstructorChecksAreEnabled=True
+ConstructorParameterChecksAreEnabled=True
+InitializerChecksAreEnabled=True
+InitializerPropertyChecksAreEnabled=True
+MethodCallChecksAreEnabled=True
+MappingMethodChecksAreEnabled=True
+MethodParameterChecksAreEnabled=True
+IndexerChecksAreEnabled=True
+PropertyChecksAreEnabled=True
+InitializedPropertyChecksAreEnabled=True
+OperatorChecksAreEnabled=True
+OperatorParameterChecksAreEnabled=True
+InterfaceImplementationChecksAreEnabled=True
diff --git a/source/OFXSharper.Tests/CanParser.cs b/source/OFXSharper.Tests/CanParser.cs
new file mode 100644
index 0000000..7e133c3
--- /dev/null
+++ b/source/OFXSharper.Tests/CanParser.cs
@@ -0,0 +1,117 @@
+using System;
+using System.IO;
+using Habanerio.OFXSharper.Types;
+using Xunit;
+
+namespace Habanerio.OFXSharper.Tests
+{
+ public class CanParser
+ {
+ [Fact]
+ public void CanParserBankTransactions()
+ {
+ var parser = new OFXDocumentParser();
+ var ofxDocument = parser.Import(new FileStream(@"bankTransactions.sgml", FileMode.Open));
+
+ Assert.NotNull(ofxDocument);
+ Assert.NotNull(ofxDocument.Account);
+
+ Assert.Equal(AccountType.BANK, ofxDocument.AccType);
+
+ Assert.Equal("0000000000003158", ofxDocument.Account.AccountID);
+ Assert.Equal("3158", ofxDocument.Account.AccountKey);
+ Assert.Equal(AccountType.BANK, ofxDocument.Account.AccountType);
+ Assert.Equal(BankAccountType.CHECKING, ofxDocument.Account.BankAccountType);
+ Assert.Equal("011000138", ofxDocument.Account.BankID);
+ Assert.Equal("003", ofxDocument.Account.BranchID);
+
+ Assert.NotNull(ofxDocument.Balance);
+ Assert.Equal(1327.42M, ofxDocument.Balance.AvailableBalance);
+ Assert.Equal(new DateTime(2024, 02, 08, 0, 0, 0
+ , DateTimeKind.Unspecified), ofxDocument.Balance.AvailableBalanceDate);
+
+ Assert.Equal(1327.42M, ofxDocument.Balance.LedgerBalance);
+ Assert.Equal(new DateTime(2024, 02, 08, 0, 0, 0
+ , DateTimeKind.Unspecified), ofxDocument.Balance.LedgerBalanceDate);
+
+ Assert.Equal("USD", ofxDocument.Currency);
+
+ Assert.NotNull(ofxDocument.SignOn);
+ Assert.Equal(new DateTime(2024, 02, 09, 0, 0, 0
+ , DateTimeKind.Unspecified), ofxDocument.SignOn.DTServer);
+ Assert.Equal("", ofxDocument.SignOn.IntuBid);
+ Assert.Equal("ENG", ofxDocument.SignOn.Language);
+ Assert.Equal(0, ofxDocument.SignOn.StatusCode);
+ Assert.Equal("INFO", ofxDocument.SignOn.StatusSeverity);
+
+ Assert.Equal(new DateTime(2024, 01, 11, 0, 0, 0
+ , DateTimeKind.Unspecified), ofxDocument.StatementStart);
+ Assert.Equal(new DateTime(2024, 02, 06, 0, 0, 0
+ , DateTimeKind.Unspecified), ofxDocument.StatementEnd);
+ }
+
+ [Fact]
+ public void CanParserCreditCardTransactions()
+ {
+ var parser = new OFXDocumentParser();
+ var ofxDocument = parser.Import(new FileStream(@"creditCardTransactions.sgml", FileMode.Open));
+
+ Assert.NotNull(ofxDocument);
+ Assert.NotNull(ofxDocument.Account);
+
+ Assert.Equal(AccountType.CC, ofxDocument.AccType);
+
+ Assert.Equal("XXXXXXXXXXXX3158", ofxDocument.Account.AccountID);
+ Assert.Equal(string.Empty, ofxDocument.Account.AccountKey);
+ Assert.Equal(AccountType.CC, ofxDocument.Account.AccountType);
+ Assert.Equal(BankAccountType.NA, ofxDocument.Account.BankAccountType);
+ Assert.Null(ofxDocument.Account.BankID);
+ Assert.Null(ofxDocument.Account.BranchID);
+
+ Assert.NotNull(ofxDocument.Balance);
+ Assert.Equal(12000.00M, ofxDocument.Balance.AvailableBalance);
+ Assert.Equal(new DateTime(2024, 01, 04, 0, 0, 0,
+ DateTimeKind.Unspecified), ofxDocument.Balance.AvailableBalanceDate);
+
+ Assert.Equal(345m, ofxDocument.Balance.LedgerBalance);
+ Assert.Equal(new DateTime(2024, 01, 04, 0, 0, 0,
+ DateTimeKind.Unspecified), ofxDocument.Balance.LedgerBalanceDate);
+
+ Assert.Equal("USD", ofxDocument.Currency);
+
+ Assert.NotNull(ofxDocument.SignOn);
+ Assert.Equal(new DateTime(2024, 01, 05, 0, 0, 0,
+ DateTimeKind.Unspecified), ofxDocument.SignOn.DTServer);
+ Assert.Equal("", ofxDocument.SignOn.IntuBid);
+ Assert.Equal("ENG", ofxDocument.SignOn.Language);
+ Assert.Equal(0, ofxDocument.SignOn.StatusCode);
+ Assert.Equal("INFO", ofxDocument.SignOn.StatusSeverity);
+
+ // TODO: Fix this
+ //Assert.Equal(new DateTime(2024, 01, 04, 0, 0, 0,
+ // DateTimeKind.Unspecified), ofxDocument.StatementStart);
+ //Assert.Equal(new DateTime(2024, 02, 06, 0, 0, 0,
+ // DateTimeKind.Unspecified), ofxDocument.StatementEnd);
+ }
+
+ [Fact]
+ public void CanParserItau()
+ {
+ var parser = new OFXDocumentParser();
+ var ofxDocument = parser.Import(new FileStream(@"itau.ofx", FileMode.Open));
+
+ Assert.NotNull(ofxDocument);
+ Assert.NotNull(ofxDocument.Account);
+ }
+
+ [Fact]
+ public void CanParserSantander()
+ {
+ var parser = new OFXDocumentParser();
+ var ofxDocument = parser.Import(new FileStream(@"santander.ofx", FileMode.Open));
+
+ Assert.NotNull(ofxDocument);
+ Assert.NotNull(ofxDocument.Account);
+ }
+ }
+}
diff --git a/source/OFXSharper.Tests/OFXSharper.Tests.csproj b/source/OFXSharper.Tests/OFXSharper.Tests.csproj
new file mode 100644
index 0000000..4ec9bb0
--- /dev/null
+++ b/source/OFXSharper.Tests/OFXSharper.Tests.csproj
@@ -0,0 +1,70 @@
+
+
+
+ net6.0
+ OFXSharper
+ Habanerio.OFXSharper.Tests
+ Habanerio.OFXSharper.Tests
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+
+
diff --git a/source/OFXSharper.Tests/accountList.sgml b/source/OFXSharper.Tests/accountList.sgml
new file mode 100644
index 0000000..396289e
--- /dev/null
+++ b/source/OFXSharper.Tests/accountList.sgml
@@ -0,0 +1,75 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:103
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+
+
+
+
+
+ 0
+ INFO
+ SUCCESS
+
+ 20150103023446
+ ENG
+ 20131012020000
+
+ HAN<
+ FID>5959
+
+ 010101010101010101010101
+
+
+
+
+ 409927339
+
+ 0
+ INFO
+
+
+ 20150103023447
+
+ BankAmericard
+
+
+ 0000000000003158
+
+ Y
+ Y
+ N
+ ACTIVE
+
+
+
+ BOFA CORE CHECKING
+
+
+ 011000138
+ 0000000000003158
+ CHECKING
+
+ Y
+ Y
+ Y
+ ACTIVE
+
+
+
+ 010101010
+ 000000003158
+ CHECKING
+
+ ACTIVE
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper.Tests/accountList.xml b/source/OFXSharper.Tests/accountList.xml
new file mode 100644
index 0000000..cf54c62
--- /dev/null
+++ b/source/OFXSharper.Tests/accountList.xml
@@ -0,0 +1,3 @@
+
+
+0
INFOSUCCESS20150103023446ENG20131012020000HAN59590101010101010101010101014099273390
INFO20150103023447BankAmericard0000000000003158YYNACTIVEBOFA CORE CHECKING0110001380000000000003158CHECKINGYYYACTIVE010101010000000003158CHECKINGACTIVE
\ No newline at end of file
diff --git a/source/OFXSharper.Tests/bankTransactions.sgml b/source/OFXSharper.Tests/bankTransactions.sgml
new file mode 100644
index 0000000..8dfe75f
--- /dev/null
+++ b/source/OFXSharper.Tests/bankTransactions.sgml
@@ -0,0 +1,74 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:103
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+
+
+
+
+
+ 0
+ INFO
+ SUCCESS
+
+ 20240209014309
+ ENG
+ 20231012020000
+
+ HAN
+ 5959
+
+ 010101010101010101010101
+
+
+
+
+ 829631324
+
+ 0
+ INFO
+
+
+ USD
+
+ 011000138
+ 003
+ 0000000000003158
+ 3158
+ CHECKING
+
+
+ 20240111190000
+ 20240206190000
+
+ DEBIT
+ 20240206190000
+ -9.95
+ 00094320206-9.95015020613276.42
+ ONLINE BANKING VIA QUICKEN
+
+
+ CREDIT
+ 20240205190000
+ 2598.75
+ 000902335012598.75015020515221.67
+ DIRECTPAY
+
+
+
+ +1327.42
+ 20240208204311
+
+
+ +1327.42
+ 20240208204311
+
+
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper.Tests/creditCardTransactions.sgml b/source/OFXSharper.Tests/creditCardTransactions.sgml
new file mode 100644
index 0000000..e9e5588
--- /dev/null
+++ b/source/OFXSharper.Tests/creditCardTransactions.sgml
@@ -0,0 +1,71 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:103
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+
+
+
+
+
+ 0
+ INFO
+ SUCCESS
+
+ 20240105043851
+ ENG
+ 20131012020000
+
+ HAN
+ 5959
+
+ 010101010101010101010101
+
+
+
+
+ 257568705
+
+ 0
+ INFO
+
+
+ USD
+
+ XXXXXXXXXXXX3158
+
+
+ 20230104190000
+ 20240103190000
+
+ DEBIT
+ 20240103190000
+ -9.62
+ B27K7JG8PBN5VNGD
+ REBECCAS CAFE INC
+ CAMBRIDGE MA
+
+
+ CREDIT
+ 20231230190000
+ 835.58
+ B27JSWPVPWSSVPD8
+ PAYMENT - THANK YOU
+
+
+
+ 345.00
+ 20240104233852
+
+
+ 12000.00
+ 20240104233852
+
+
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper.Tests/itau.ofx b/source/OFXSharper.Tests/itau.ofx
new file mode 100644
index 0000000..61b285b
--- /dev/null
+++ b/source/OFXSharper.Tests/itau.ofx
@@ -0,0 +1,71 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:102
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+
+
+
+
+
+0
+INFO
+
+20140304100000[-03:EST]
+POR
+
+
+
+
+1001
+
+0
+INFO
+
+
+BRL
+
+0341
+9999999999
+CHECKING
+
+
+20131205100000[-03:EST]
+20140228100000[-03:EST]
+
+DEBIT
+20131209100000[-03:EST]
+-666.66
+20131209001
+20131209001
+RSHOP
+
+
+CREDIT
+20131209100000[-03:EST]
+99.99
+20131209002
+20131209002
+REND PAGO APLIC AUT MAIS
+
+
+DEBIT
+20131210100000[-03:EST]
+-77.77
+20131210001
+20131210001
+SISDEB
+
+
+
+-9999.99
+20140304100000[-03:EST]
+
+
+
+
+
diff --git a/source/OFXSharper.Tests/santander.ofx b/source/OFXSharper.Tests/santander.ofx
new file mode 100644
index 0000000..071eab8
--- /dev/null
+++ b/source/OFXSharper.Tests/santander.ofx
@@ -0,0 +1,78 @@
+OFXHEADER:100
+DATA:OFXSGML
+VERSION:102
+SECURITY:NONE
+ENCODING:USASCII
+CHARSET:1252
+COMPRESSION:NONE
+OLDFILEUID:NONE
+NEWFILEUID:NONE
+
+
+
+
+
+ 0
+ INFO
+
+ 20140203182251[-3:GMT]
+ ENG
+
+ SANTANDER
+ SANTANDER
+
+
+
+
+
+ 1
+
+ 0
+ INFO
+
+
+ BRL
+
+ 033
+ 9999999999999
+ CHECKING
+
+
+ 20140203182251[-3:GMT]
+ 20140203182251[-3:GMT]
+
+ OTHER
+ 20131107000000[-3:GMT]
+ -11.11
+ 00510367
+ 00510367
+ 0
+ DEBITO VISA ELECTRON BRASIL
+
+
+ OTHER
+ 20131107000000[-3:GMT]
+ -222,22
+ 00000105
+ 00000105
+ 0
+ COMPENSACAO INTERNA DE CHEQUE
+
+
+ OTHER
+ 20131108000000[-3:GMT]
+ -333.33
+ 00330867
+ 00330867
+ 0
+ DEBITO VISA ELECTRON BRASIL
+
+
+
+ 9999.99
+ 20140203182251[-3:GMT]
+
+
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper.sln b/source/OFXSharper.sln
new file mode 100644
index 0000000..3bf270d
--- /dev/null
+++ b/source/OFXSharper.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.10.34825.169
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OFXSharper", "OFXSharper\OFXSharper.csproj", "{C89D7C48-DE17-4EB3-BC65-CCA3D8A375F9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OFXSharper.Tests", "OFXSharper.Tests\OFXSharper.Tests.csproj", "{72CCB407-4984-45B3-8326-5263B8CB4AAD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C89D7C48-DE17-4EB3-BC65-CCA3D8A375F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C89D7C48-DE17-4EB3-BC65-CCA3D8A375F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C89D7C48-DE17-4EB3-BC65-CCA3D8A375F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C89D7C48-DE17-4EB3-BC65-CCA3D8A375F9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72CCB407-4984-45B3-8326-5263B8CB4AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72CCB407-4984-45B3-8326-5263B8CB4AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72CCB407-4984-45B3-8326-5263B8CB4AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72CCB407-4984-45B3-8326-5263B8CB4AAD}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {64987655-AB4A-4038-A051-47C71E6C4113}
+ EndGlobalSection
+EndGlobal
diff --git a/source/OFXSharper/Exceptions/OFXException.cs b/source/OFXSharper/Exceptions/OFXException.cs
new file mode 100644
index 0000000..cb9deb3
--- /dev/null
+++ b/source/OFXSharper/Exceptions/OFXException.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Habanerio.OFXSharper.Exceptions
+{
+ [Serializable]
+ public class OFXException : Exception
+ {
+ public OFXException()
+ {
+ }
+
+ public OFXException(string message) : base(message)
+ {
+ }
+
+ public OFXException(string message, Exception inner) : base(message, inner)
+ {
+ }
+
+ protected OFXException(
+ SerializationInfo info,
+ StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Exceptions/OFXParseException.cs b/source/OFXSharper/Exceptions/OFXParseException.cs
new file mode 100644
index 0000000..3165543
--- /dev/null
+++ b/source/OFXSharper/Exceptions/OFXParseException.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Habanerio.OFXSharper.Exceptions
+{
+ [Serializable]
+ public class OFXParseException : OFXException
+ {
+ public OFXParseException()
+ {
+ }
+
+ public OFXParseException(string message) : base(message)
+ {
+ }
+
+ public OFXParseException(string message, Exception inner) : base(message, inner)
+ {
+ }
+
+ protected OFXParseException(
+ SerializationInfo info,
+ StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/ModelDiagram.cd b/source/OFXSharper/ModelDiagram.cd
new file mode 100644
index 0000000..c8217a6
--- /dev/null
+++ b/source/OFXSharper/ModelDiagram.cd
@@ -0,0 +1,55 @@
+
+
+
+
+
+ AACBAAAAAAAAAAAEAAgAAAABCAAAAAAAAAAAAAAAAEI=
+ OFXDocument.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AAAAAAAAAAAAAAAAAAIIAAAAAAAAAAEAAAAAAAAAAAQ=
+ Balance.cs
+
+
+
+
+
+ BACAAIAAIQAAAAAAAgAAIAAAAAAAAAAAACAAQAAAAAA=
+ Account.cs
+
+
+
+
+
+ AAAAAAAACAAAAAAAAAAAAABAAAAABAAAIAQAAAAAAAA=
+ SignOn.cs
+
+
+
+
+
+ AAAAAgAAAACAAQAAAAAEAgSgCBABFAUDgAAAAAAAIAA=
+ Transaction.cs
+
+
+
+
+
+ AAAAAAIAAAAAAAAQAAAAAAEgAAAAAgAAAAAAAAAAAAA=
+ AccountType.cs
+
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper/Models/Account.cs b/source/OFXSharper/Models/Account.cs
new file mode 100644
index 0000000..69d128f
--- /dev/null
+++ b/source/OFXSharper/Models/Account.cs
@@ -0,0 +1,95 @@
+using System.Xml;
+using Habanerio.OFXSharper.Exceptions;
+using Habanerio.OFXSharper.Types;
+
+namespace Habanerio.OFXSharper.Models
+{
+ public class Account
+ {
+ public string AccountID { get; set; }
+ public string AccountKey { get; set; }
+ public AccountType AccountType { get; set; }
+
+ #region Bank Only
+
+ private BankAccountType _BankAccountType = BankAccountType.NA;
+
+ public string BankID { get; set; }
+
+ public string BranchID { get; set; }
+
+
+ public BankAccountType BankAccountType
+ {
+ get
+ {
+ if (AccountType == AccountType.BANK)
+ return _BankAccountType;
+
+ return BankAccountType.NA;
+ }
+ set
+ {
+ _BankAccountType = AccountType == AccountType.BANK ? value : BankAccountType.NA;
+ }
+ }
+
+ #endregion
+
+ public Account(XmlNode node, AccountType type)
+ {
+ AccountType = type;
+
+ AccountID = node.GetValue("//ACCTID");
+ AccountKey = node.GetValue("//ACCTKEY");
+
+ switch (AccountType)
+ {
+ case AccountType.BANK:
+ InitializeBank(node);
+ break;
+ case AccountType.AP:
+ InitializeAP(node);
+ break;
+ case AccountType.AR:
+ InitializeAR(node);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ///
+ /// Initializes information specific to bank
+ ///
+ private void InitializeBank(XmlNode node)
+ {
+ BankID = node.GetValue("//BANKID");
+ BranchID = node.GetValue("//BRANCHID");
+
+ //Get Bank Account Type from XML
+ string bankAccountType = node.GetValue("//ACCTTYPE");
+
+ //Check that it has been set
+ if (string.IsNullOrEmpty(bankAccountType))
+ throw new OFXParseException("Bank Account type unknown");
+
+ //Set bank account enum
+ _BankAccountType = bankAccountType.GetBankAccountType();
+ }
+
+ #region Account types not supported
+
+ private static void InitializeAP(XmlNode node)
+ {
+ throw new OFXParseException("AP Account type not supported");
+ }
+
+ private static void InitializeAR(XmlNode node)
+ {
+ throw new OFXParseException("AR Account type not supported");
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Models/Balance.cs b/source/OFXSharper/Models/Balance.cs
new file mode 100644
index 0000000..b433377
--- /dev/null
+++ b/source/OFXSharper/Models/Balance.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Globalization;
+using System.Xml;
+using Habanerio.OFXSharper.Exceptions;
+
+namespace Habanerio.OFXSharper.Models
+{
+ public class Balance
+ {
+ public decimal LedgerBalance { get; set; }
+
+ public DateTime? LedgerBalanceDate { get; set; }
+
+ public decimal AvailableBalance { get; set; }
+
+ public DateTime? AvailableBalanceDate { get; set; } = null;
+
+ public Balance(XmlNode ledgerNode, XmlNode availableNode)
+ {
+ var tempLedgerBalance = ledgerNode.GetValue("//LEDGERBAL//BALAMT");
+
+ if (!string.IsNullOrEmpty(tempLedgerBalance))
+ {
+ // ***** Forced Invariant Culture.
+ // If you don't force it, it will use the computer's default (defined in windows control panel, regional settings)
+ // So, if the number format of the computer in use it's different from OFX standard (i suppose the english/invariant),
+ // the next line of could crash or (worse) the number would be wrongly interpreted.
+ // For example, my computer has a brazilian regional setting, with "." as thousand separator and "," as
+ // decimal separator, so the value "10.99" (ten 'dollars' (or whatever currency) and ninety-nine cents) would be interpreted as "1099"
+ // (one thousand and ninety-nine dollars - the "." would be ignored)
+ LedgerBalance = Convert.ToDecimal(tempLedgerBalance, CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ throw new OFXParseException("Ledger balance has not been set");
+ }
+
+ // ***** OFX files from my bank don't have the 'availableNode' node, so i manage a null situation
+ if (availableNode == null)
+ {
+ AvailableBalance = 0;
+ }
+ else
+ {
+ // *** Need to prepend `//AVAILBAL` to the xpath to get the correct value. Or else it returns the value in `//LEDGERBAL//BALAMT`
+ var tempAvailableBalance = availableNode.GetValue("//AVAILBAL//BALAMT");
+
+ if (!string.IsNullOrEmpty(tempAvailableBalance))
+ {
+ // ***** Forced Invariant Culture. (same comment as above)
+ AvailableBalance = Convert.ToDecimal(tempAvailableBalance, CultureInfo.InvariantCulture);
+ }
+ else
+ {
+ throw new OFXParseException("Available balance has not been set");
+ }
+
+ AvailableBalanceDate = availableNode.GetValue("//DTASOF").ToDate();
+ }
+
+ LedgerBalanceDate = ledgerNode.GetValue("//DTASOF")?.ToDate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Models/SignOn.cs b/source/OFXSharper/Models/SignOn.cs
new file mode 100644
index 0000000..396c451
--- /dev/null
+++ b/source/OFXSharper/Models/SignOn.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Xml;
+
+namespace Habanerio.OFXSharper.Models
+{
+ public class SignOn
+ {
+ public string StatusSeverity { get; set; }
+
+ public DateTime? DTServer { get; set; }
+
+ public int StatusCode { get; set; }
+
+ public string Language { get; set; }
+
+ public string IntuBid { get; set; }
+
+ public SignOn(XmlNode node)
+ {
+ StatusCode = Convert.ToInt32(node.GetValue("//CODE"));
+ StatusSeverity = node.GetValue("//SEVERITY");
+ DTServer = node.GetValue("//DTSERVER")?.ToDate();
+ Language = node.GetValue("//LANGUAGE");
+ IntuBid = node.GetValue("//INTU.BID");
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Models/Transaction.cs b/source/OFXSharper/Models/Transaction.cs
new file mode 100644
index 0000000..7a97083
--- /dev/null
+++ b/source/OFXSharper/Models/Transaction.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Globalization;
+using System.Xml;
+using Habanerio.OFXSharper.Exceptions;
+using Habanerio.OFXSharper.Types;
+
+namespace Habanerio.OFXSharper.Models
+{
+ public class Transaction
+ {
+ public TransactionType TransType { get; set; }
+
+ public DateTime? Date { get; set; }
+
+ public decimal Amount { get; set; }
+
+ public string TransactionID { get; set; }
+
+ public string Name { get; set; }
+
+ public DateTime? TransactionInitializationDate { get; set; }
+
+ public DateTime? FundAvaliabilityDate { get; set; }
+
+ public string Memo { get; set; }
+
+ public string IncorrectTransactionID { get; set; }
+
+ public TransactionCorrectionType TransactionCorrectionAction { get; set; }
+
+ public string ServerTransactionID { get; set; }
+
+ public string CheckNum { get; set; }
+
+ public string ReferenceNumber { get; set; }
+
+ public string Sic { get; set; }
+
+ public string PayeeID { get; set; }
+
+ public Account TransactionSenderAccount { get; set; }
+
+ public string Currency { get; set; }
+
+ public Transaction()
+ {
+ }
+
+ public Transaction(XmlNode node, string currency)
+ {
+ TransType = GetTransactionType(node.GetValue(".//TRNTYPE"));
+ Date = node.GetValue(".//DTPOSTED").ToDate();
+ TransactionInitializationDate = node.GetValue(".//DTUSER").ToDate();
+ FundAvaliabilityDate = node.GetValue(".//DTAVAIL").ToDate();
+
+ try
+ {
+ Amount = Convert.ToDecimal(node.GetValue(".//TRNAMT"), CultureInfo.InvariantCulture);
+ }
+ catch (Exception ex)
+ {
+ throw new OFXParseException("Transaction Amount unknown", ex);
+ }
+
+ try
+ {
+ TransactionID = node.GetValue(".//FITID");
+ }
+ catch (Exception ex)
+ {
+ throw new OFXParseException("Transaction ID unknown", ex);
+ }
+
+ IncorrectTransactionID = node.GetValue(".//CORRECTFITID");
+
+
+ //If Transaction Correction Action exists, populate
+ var tempCorrectionAction = node.GetValue(".//CORRECTACTION");
+
+ TransactionCorrectionAction = !string.IsNullOrEmpty(tempCorrectionAction)
+ ? GetTransactionCorrectionType(tempCorrectionAction)
+ : TransactionCorrectionType.NA;
+
+ ServerTransactionID = node.GetValue(".//SRVRTID");
+ CheckNum = node.GetValue(".//CHECKNUM");
+ ReferenceNumber = node.GetValue(".//REFNUM");
+ Sic = node.GetValue(".//SIC");
+ PayeeID = node.GetValue(".//PAYEEID");
+ Name = node.GetValue(".//NAME");
+ Memo = node.GetValue(".//MEMO");
+
+ //If different currency to CURDEF, populate currency
+ if (NodeExists(node, ".//CURRENCY"))
+ Currency = node.GetValue(".//CURRENCY");
+ else if (NodeExists(node, ".//ORIGCURRENCY"))
+ Currency = node.GetValue(".//ORIGCURRENCY");
+ //If currency not different, set to CURDEF
+ else
+ Currency = currency;
+
+ //If senders bank/credit card details available, add
+ if (NodeExists(node, ".//BANKACCTTO"))
+ TransactionSenderAccount = new Account(node.SelectSingleNode(".//BANKACCTTO"), AccountType.BANK);
+ else if (NodeExists(node, ".//CCACCTTO"))
+ TransactionSenderAccount = new Account(node.SelectSingleNode(".//CCACCTTO"), AccountType.CC);
+ }
+
+ ///
+ /// Returns TransactionType from string version
+ ///
+ /// string version of transaction type
+ /// Enum version of given transaction type string
+ private static TransactionType GetTransactionType(string transactionType)
+ {
+ return (TransactionType)Enum.Parse(typeof(TransactionType), transactionType);
+ }
+
+ ///
+ /// Returns TransactionCorrectionType from string version
+ ///
+ /// string version of Transaction Correction Type
+ /// Enum version of given TransactionCorrectionType string
+ private static TransactionCorrectionType GetTransactionCorrectionType(string transactionCorrectionType)
+ {
+ return (TransactionCorrectionType)Enum.Parse(typeof(TransactionCorrectionType), transactionCorrectionType);
+ }
+
+ ///
+ /// Checks if a node exists
+ ///
+ /// Node to search in
+ /// XPath to node you want to see if exists
+ ///
+ private static bool NodeExists(XmlNode node, string xpath)
+ {
+ return node.SelectSingleNode(xpath) != null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/OFXDocument.cs b/source/OFXSharper/OFXDocument.cs
new file mode 100644
index 0000000..091826d
--- /dev/null
+++ b/source/OFXSharper/OFXDocument.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using Habanerio.OFXSharper.Models;
+using Habanerio.OFXSharper.Types;
+
+namespace Habanerio.OFXSharper
+{
+ public class OFXDocument
+ {
+ public DateTime? StatementStart { get; set; }
+
+ public DateTime? StatementEnd { get; set; }
+
+ public AccountType AccType { get; set; }
+
+ public string Currency { get; set; }
+
+ public SignOn SignOn { get; set; }
+
+ public Account Account { get; set; }
+
+ public Balance Balance { get; set; }
+
+ public List Transactions { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/OFXDocumentParser.cs b/source/OFXSharper/OFXDocumentParser.cs
new file mode 100644
index 0000000..9e0bcf8
--- /dev/null
+++ b/source/OFXSharper/OFXDocumentParser.cs
@@ -0,0 +1,316 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+using Habanerio.OFXSharper.Exceptions;
+using Habanerio.OFXSharper.Models;
+using Habanerio.OFXSharper.Types;
+using Sgml;
+
+
+namespace Habanerio.OFXSharper
+{
+ public class OFXDocumentParser
+ {
+ public string Version { get; private set; } = "102";
+
+ public OFXDocument Import(FileStream stream)
+ {
+ using (var reader = new StreamReader(stream, Encoding.Default))
+ {
+ return Import(reader.ReadToEnd());
+ }
+ }
+
+ public OFXDocument Import(string ofx)
+ {
+ return ParseOfxDocument(ofx);
+ }
+
+ private OFXDocument ParseOfxDocument(string ofxString)
+ {
+ //If OFX file in SGML format, convert to XML
+ if (!IsXmlVersion(ofxString))
+ {
+ ofxString = SGMLToXML(ofxString);
+ }
+
+ return Parse(ofxString);
+ }
+
+ private OFXDocument Parse(string ofxString)
+ {
+ var ofx = new OFXDocument { AccType = GetAccountType(ofxString) };
+
+ //Load into xml document
+ var doc = new XmlDocument();
+ doc.Load(new StringReader(ofxString));
+
+ var currencyNode = doc.SelectSingleNode(GetXPath(ofx.AccType, OFXSection.CURRENCY));
+
+ if (currencyNode != null)
+ {
+ ofx.Currency = currencyNode.FirstChild.Value.Trim();
+ }
+ else
+ {
+ throw new OFXParseException("Currency not found");
+ }
+
+ //Get sign on node from OFX file
+ var signOnNode = doc.SelectSingleNode(Resources.SignOn);
+
+ //If exists, populate signon obj, else throw parse error
+ if (signOnNode != null)
+ {
+ ofx.SignOn = new SignOn(signOnNode);
+ }
+ else
+ {
+ throw new OFXParseException("Sign On information not found");
+ }
+
+ //Get Account information for ofx doc
+ var accountNode = doc.SelectSingleNode(GetXPath(ofx.AccType, OFXSection.ACCOUNTINFO));
+
+ //If account info present, populate account object
+ if (accountNode != null)
+ {
+ ofx.Account = new Account(accountNode, ofx.AccType);
+ }
+ else
+ {
+ throw new OFXParseException("Account information not found");
+ }
+
+ //Get list of transactions
+ ImportTransactions(ofx, doc);
+
+ //Get balance info from ofx doc
+ var ledgerNode = doc.SelectSingleNode(GetXPath(ofx.AccType, OFXSection.BALANCE) + "/LEDGERBAL");
+ var availableNode = doc.SelectSingleNode(GetXPath(ofx.AccType, OFXSection.BALANCE) + "/AVAILBAL");
+
+ //If balance info present, populate balance object
+ // ***** OFX files from my bank don't have the 'availableNode' node, so i manage a 'null' situation
+ if (ledgerNode != null) // && availableNode != null
+ {
+ ofx.Balance = new Balance(ledgerNode, availableNode);
+ }
+ else
+ {
+ throw new OFXParseException("Balance information not found");
+ }
+
+ return ofx;
+ }
+
+
+ ///
+ /// Returns the correct xpath to specified section for given account type
+ ///
+ /// Account type
+ /// Section of OFX document, e.g. Transaction Section
+ /// Thrown in account type not supported
+ private static string GetXPath(AccountType type, OFXSection section)
+ {
+ string xpath, accountInfo;
+
+ switch (type)
+ {
+ case AccountType.BANK:
+ xpath = Resources.BankAccount;
+ accountInfo = "/BANKACCTFROM";
+ break;
+ case AccountType.CC:
+ xpath = Resources.CCAccount;
+ accountInfo = "/CCACCTFROM";
+ break;
+ default:
+ throw new OFXException("Account Type not supported. Account type " + type);
+ }
+
+ switch (section)
+ {
+ case OFXSection.ACCOUNTINFO:
+ return xpath + accountInfo;
+ case OFXSection.BALANCE:
+ return xpath;
+ case OFXSection.TRANSACTIONS:
+ return xpath + "/BANKTRANLIST";
+ case OFXSection.SIGNON:
+ return Resources.SignOn;
+ case OFXSection.CURRENCY:
+ return xpath + "/CURDEF";
+ default:
+ throw new OFXException("Unknown section found when retrieving XPath. Section " + section);
+ }
+ }
+
+ ///
+ /// Returns list of all transactions in OFX document
+ ///
+ /// OFX Document
+ /// XML document
+ /// List of transactions found in OFX document
+ private static void ImportTransactions(OFXDocument ofxDocument, XmlDocument doc)
+ {
+ var xpath = GetXPath(ofxDocument.AccType, OFXSection.TRANSACTIONS);
+
+ ofxDocument.StatementStart = doc.GetValue(xpath + "//DTSTART")?.ToDate();
+ ofxDocument.StatementEnd = doc.GetValue(xpath + "//DTEND")?.ToDate();
+
+ var transactionNodes = doc.SelectNodes(xpath + "//STMTTRN");
+
+ if (transactionNodes == null)
+ return;
+
+ ofxDocument.Transactions = new List();
+
+ foreach (XmlNode node in transactionNodes)
+ ofxDocument.Transactions.Add(new Transaction(node, ofxDocument.Currency));
+ }
+
+ ///
+ /// Checks account type of supplied file
+ ///
+ /// OFX file want to check
+ /// Account type for account supplied in ofx file
+ private static AccountType GetAccountType(string file)
+ {
+ if (file.IndexOf("", StringComparison.InvariantCulture) != -1)
+ return AccountType.CC;
+
+ if (file.IndexOf("", StringComparison.InvariantCulture) != -1)
+ return AccountType.BANK;
+
+ throw new OFXException("Unsupported Account Type");
+ }
+
+ ///
+ /// Check if OFX file is in SGML or XML format
+ ///
+ ///
+ ///
+ private static bool IsXmlVersion(string file)
+ {
+ return file.IndexOf("OFXHEADER:100", StringComparison.InvariantCulture) == -1;
+ }
+
+ ///
+ /// Converts SGML to XML
+ ///
+ /// OFX File (SGML Format)
+ /// OFX File in XML format
+ private string SGMLToXML(string file)
+ {
+ var sgmlReader = new SgmlReader();
+
+ //Initialize SGML reader
+ var fileReader = new StringReader(ParseHeader(file));
+
+ sgmlReader.DocType = "OFX";
+ sgmlReader.InputStream = fileReader;
+
+ // Newer implementation
+ var ofxDoc = new XmlDocument();
+ ofxDoc.PreserveWhitespace = false;
+ ofxDoc.XmlResolver = null;
+ ofxDoc.Load(sgmlReader);
+
+ return ofxDoc.OuterXml;
+
+ // Original implementation
+ //var sw = new StringWriter();
+ //var xml = new XmlTextWriter(sw);
+
+ ////write output of sgml reader to xml text writer
+ //while (!sgmlReader.EOF)
+ // xml.WriteNode(sgmlReader, true);
+
+ ////close xml text writer
+ //xml.Flush();
+ //xml.Close();
+
+ //var temp = sw.ToString().Replace("\t", "").TrimStart().Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+
+ //return string.Join("", temp);
+ }
+
+ ///
+ /// Checks that the file is supported by checking the header. Removes the header.
+ ///
+ /// OFX file
+ /// File, without the header
+ private string ParseHeader(string file)
+ {
+ //Select header of file and split into array
+ //End of header worked out by finding first instance of '<'
+ //Array split based of new line & carrige return
+ var header = file.Substring(0, file.IndexOf('<'))
+ .Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
+
+ //Check that no errors in header
+ CheckHeader(header);
+
+ //Remove header
+ return file.Substring(file.IndexOf('<')).Trim();
+ }
+
+ ///
+ /// Checks that all the elements in the header are supported
+ ///
+ /// Header of OFX file in array
+ private void CheckHeader(string[] header)
+ {
+ if (header[0] == "OFXHEADER:100DATA:OFXSGMLVERSION:102SECURITY:NONEENCODING:USASCIICHARSET:1252COMPRESSION:NONEOLDFILEUID:NONENEWFILEUID:NONE")//non delimited header
+ return;
+
+ if (header[0] != "OFXHEADER:100")
+ throw new OFXParseException("Incorrect header format");
+
+ if (header[1] != "DATA:OFXSGML")
+ throw new OFXParseException("Data type unsupported: " + header[1] + ". OFXSGML required");
+
+ if (header[2].Contains("VERSION"))
+ {
+ Version = header[2].Split(':')[1];
+ }
+
+ //if (header[2] != "VERSION:102")
+ // throw new OFXParseException("OFX version unsupported. " + header[2]);
+
+ // Do we care if the SECURITY is not NONE?
+ //if (header[3] != "SECURITY:NONE")
+ // throw new OFXParseException("OFX security unsupported");
+
+ if (header[4] != "ENCODING:USASCII")
+ throw new OFXParseException("ASCII Format unsupported:" + header[4]);
+
+ if (header[5] != "CHARSET:1252")
+ throw new OFXParseException("Charecter set unsupported:" + header[5]);
+
+ if (header[6] != "COMPRESSION:NONE")
+ throw new OFXParseException("Compression unsupported");
+
+ if (header[7] != "OLDFILEUID:NONE")
+ throw new OFXParseException("OLDFILEUID incorrect");
+ }
+
+ #region Nested type: OFXSection
+
+ ///
+ /// Section of OFX Document
+ ///
+ private enum OFXSection
+ {
+ SIGNON,
+ ACCOUNTINFO,
+ TRANSACTIONS,
+ BALANCE,
+ CURRENCY
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/OFXHelperMethods.cs b/source/OFXSharper/OFXHelperMethods.cs
new file mode 100644
index 0000000..82166d0
--- /dev/null
+++ b/source/OFXSharper/OFXHelperMethods.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Xml;
+using Habanerio.OFXSharper.Exceptions;
+using Habanerio.OFXSharper.Types;
+
+namespace Habanerio.OFXSharper
+{
+ public static class OFXHelperMethods
+ {
+ ///
+ /// Converts string representation of AccountInfo to enum AccountInfo
+ ///
+ /// representation of AccountInfo
+ /// AccountInfo
+ public static BankAccountType GetBankAccountType(this string bankAccountType)
+ {
+ try
+ {
+ return (BankAccountType)Enum.Parse(typeof(BankAccountType), bankAccountType, true);
+ }
+ catch (Exception)
+ {
+
+ return BankAccountType.NA;
+ }
+ }
+
+ ///
+ /// Flips date from YYYYMMDD to DDMMYYYY
+ ///
+ /// Date in YYYYMMDD format
+ /// Date in format DDMMYYYY
+ public static DateTime? ToDate(this string date)
+ {
+ try
+ {
+ if (date.Length < 8)
+ {
+ return null;
+ }
+
+ var dd = int.Parse(date.Substring(6, 2));
+ var mm = int.Parse(date.Substring(4, 2));
+ var yyyy = int.Parse(date.Substring(0, 4));
+
+ return new DateTime(yyyy, mm, dd, 0, 0, 0, DateTimeKind.Unspecified);
+ }
+ catch
+ {
+ throw new OFXParseException("Unable to parse date");
+ }
+ }
+
+ ///
+ /// Returns value of specified node
+ ///
+ /// Node to look for specified node
+ /// XPath for node you want
+ ///
+ public static string GetValue(this XmlNode node, string xpath)
+ {
+ var tempNode = node.SelectSingleNode(xpath);
+
+ if (tempNode?.FirstChild != null)
+ {
+ return tempNode.FirstChild.Value.Trim();
+ }
+
+ return string.Empty;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/OFXSharper.csproj b/source/OFXSharper/OFXSharper.csproj
new file mode 100644
index 0000000..9e3eca5
--- /dev/null
+++ b/source/OFXSharper/OFXSharper.csproj
@@ -0,0 +1,48 @@
+
+
+ netstandard2.0
+ OFXSharper
+ Habanerio.OFXSharper
+ Habanerio.OFXSharper
+
+ Habaner.io, jhollingworth
+ Habaner.io
+ .Net Standard version of James Hollingworth's popular OFXSharp Library (https://github.com/jhollingworth/OFXSharp)
+
+ Habanerio.OFXSharper
+
+ 1.0.0
+ 1.0.0
+ 1.0.0
+
+
+ http://opensource.org/licenses/MIT
+ https://github.com/Habanerio/OFXSharper
+
+ OFX, OFX Parser, OFXSharp
+
+ true
+
+
+
+ True
+ True
+ Resources.resx
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
\ No newline at end of file
diff --git a/source/OFXSharper/Properties/AssemblyInfo.cs b/source/OFXSharper/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..09a9486
--- /dev/null
+++ b/source/OFXSharper/Properties/AssemblyInfo.cs
@@ -0,0 +1,13 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("4dc4da7c-0cb3-455d-98d7-7a2ad77069ff")]
diff --git a/source/OFXSharper/Resources.Designer.cs b/source/OFXSharper/Resources.Designer.cs
new file mode 100644
index 0000000..16991d1
--- /dev/null
+++ b/source/OFXSharper/Resources.Designer.cs
@@ -0,0 +1,117 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Habanerio.OFXSharper {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Habanerio.OFXSharper.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OFX/BANKMSGSRSV1/STMTTRNRS/.
+ ///
+ internal static string BankAccount {
+ get {
+ return ResourceManager.GetString("BankAccount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OFX/CREDITCARDMSGSRSV1/CCSTMTTRNRS/.
+ ///
+ internal static string CCAccount {
+ get {
+ return ResourceManager.GetString("CCAccount", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to There are insufficient funds to pay your {item}. We have allocated what you have evenly between the {item} but there is no room in the budget for anything else, sorry....
+ ///
+ internal static string InsufficentFunds {
+ get {
+ return ResourceManager.GetString("InsufficentFunds", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to There are no funds for your {item} sorry....
+ ///
+ internal static string NoFunds {
+ get {
+ return ResourceManager.GetString("NoFunds", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to You are spending beyond your means so we have had to use your savings to create this budget. Perhaps you need to review your spending....
+ ///
+ internal static string NoMoney {
+ get {
+ return ResourceManager.GetString("NoMoney", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to OFX/SIGNONMSGSRSV1/SONRS.
+ ///
+ internal static string SignOn {
+ get {
+ return ResourceManager.GetString("SignOn", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/source/OFXSharper/Resources.resx b/source/OFXSharper/Resources.resx
new file mode 100644
index 0000000..1f57462
--- /dev/null
+++ b/source/OFXSharper/Resources.resx
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ OFX/BANKMSGSRSV1/STMTTRNRS/
+
+
+ OFX/CREDITCARDMSGSRSV1/CCSTMTTRNRS/
+
+
+ There are insufficient funds to pay your {item}. We have allocated what you have evenly between the {item} but there is no room in the budget for anything else, sorry...
+
+
+ There are no funds for your {item} sorry...
+
+
+ You are spending beyond your means so we have had to use your savings to create this budget. Perhaps you need to review your spending...
+
+
+ OFX/SIGNONMSGSRSV1/SONRS
+
+
diff --git a/source/OFXSharper/Types/AccountType.cs b/source/OFXSharper/Types/AccountType.cs
new file mode 100644
index 0000000..cbe8bbe
--- /dev/null
+++ b/source/OFXSharper/Types/AccountType.cs
@@ -0,0 +1,17 @@
+using System.ComponentModel;
+
+namespace Habanerio.OFXSharper.Types
+{
+ public enum AccountType
+ {
+ [Description("Bank Account")]
+ BANK,
+ [Description("Credit Card")]
+ CC,
+ [Description("Accounts Payable")]
+ AP,
+ [Description("Accounts Recievable")]
+ AR,
+ NA,
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Types/BankAccountType.cs b/source/OFXSharper/Types/BankAccountType.cs
new file mode 100644
index 0000000..d94a633
--- /dev/null
+++ b/source/OFXSharper/Types/BankAccountType.cs
@@ -0,0 +1,19 @@
+using System.ComponentModel;
+
+namespace Habanerio.OFXSharper.Types
+{
+ public enum BankAccountType
+ {
+ [Description("Checking Account")]
+ CHECKING,
+ [Description("Savings Account")]
+ SAVINGS,
+ [Description("Money Market Account")]
+ MONEYMRKT,
+ [Description("Line of Credit")]
+ CREDITLINE,
+ NA,
+ [Description("Home Loan")]
+ HOMELOAN,
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Types/TransactionCorrectionType.cs b/source/OFXSharper/Types/TransactionCorrectionType.cs
new file mode 100644
index 0000000..db9032a
--- /dev/null
+++ b/source/OFXSharper/Types/TransactionCorrectionType.cs
@@ -0,0 +1,14 @@
+using System.ComponentModel;
+
+namespace Habanerio.OFXSharper.Types
+{
+ public enum TransactionCorrectionType
+ {
+ [Description("No correction needed")]
+ NA,
+ [Description("Replace this transaction with one referenced by CORRECTFITID")]
+ REPLACE,
+ [Description("Delete transaction")]
+ DELETE,
+ }
+}
\ No newline at end of file
diff --git a/source/OFXSharper/Types/TransactionType.cs b/source/OFXSharper/Types/TransactionType.cs
new file mode 100644
index 0000000..572af37
--- /dev/null
+++ b/source/OFXSharper/Types/TransactionType.cs
@@ -0,0 +1,41 @@
+using System.ComponentModel;
+
+namespace Habanerio.OFXSharper.Types
+{
+ public enum TransactionType
+ {
+ [Description("Basic Credit")]
+ CREDIT,
+ [Description("Basic Debit")]
+ DEBIT,
+ [Description("Interest")]
+ INT,
+ [Description("Dividend")]
+ DIV,
+ [Description("Fee")]
+ FEE,
+ [Description("Service Charge")]
+ SRVCHG,
+ [Description("Deposit")]
+ DEP,
+ [Description("ATM transfer")]
+ ATM,
+ [Description("Point of Sale transfer")]
+ POS,
+ [Description("Transfer")]
+ XFER,
+ [Description("Check")]
+ CHECK,
+ [Description("Payment")]
+ PAYMENT,
+ [Description("Cash Withdrawl")]
+ CASH,
+ [Description("Direct Deposit")]
+ DIRECTDEP,
+ [Description("Merchant Initiated Debit")]
+ DIRECTDEBIT,
+ [Description("Repeating Payment")]
+ REPEATPMT,
+ OTHER,
+ }
+}