ach_client 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +18 -0
  3. data/.gitignore +9 -0
  4. data/.rubocop.yml +1156 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +10 -0
  7. data/Gemfile +4 -0
  8. data/README.md +388 -0
  9. data/Rakefile +10 -0
  10. data/ach_client.gemspec +58 -0
  11. data/bin/console +93 -0
  12. data/bin/setup +8 -0
  13. data/config/return_codes.yml +761 -0
  14. data/lib/ach_client/abstract/abstract_method_error.rb +3 -0
  15. data/lib/ach_client/helpers/dollars_to_cents.rb +15 -0
  16. data/lib/ach_client/logging/log_provider_job.rb +36 -0
  17. data/lib/ach_client/logging/log_providers/log_provider.rb +22 -0
  18. data/lib/ach_client/logging/log_providers/null_log_provider.rb +14 -0
  19. data/lib/ach_client/logging/log_providers/stdout_log_provider.rb +14 -0
  20. data/lib/ach_client/logging/logging.rb +76 -0
  21. data/lib/ach_client/logging/savon_observer.rb +26 -0
  22. data/lib/ach_client/objects/account_types.rb +32 -0
  23. data/lib/ach_client/objects/responses/ach_response.rb +15 -0
  24. data/lib/ach_client/objects/responses/corrected_ach_response.rb +18 -0
  25. data/lib/ach_client/objects/responses/processing_ach_response.rb +6 -0
  26. data/lib/ach_client/objects/responses/returned_ach_response.rb +16 -0
  27. data/lib/ach_client/objects/responses/settled_ach_response.rb +5 -0
  28. data/lib/ach_client/objects/return_code.rb +20 -0
  29. data/lib/ach_client/objects/return_codes.rb +33 -0
  30. data/lib/ach_client/objects/transaction_types.rb +16 -0
  31. data/lib/ach_client/providers/abstract/ach_batch.rb +23 -0
  32. data/lib/ach_client/providers/abstract/ach_status_checker.rb +21 -0
  33. data/lib/ach_client/providers/abstract/ach_transaction.rb +70 -0
  34. data/lib/ach_client/providers/abstract/company_info.rb +28 -0
  35. data/lib/ach_client/providers/abstract/response_record_processor.rb +15 -0
  36. data/lib/ach_client/providers/abstract/transformer.rb +38 -0
  37. data/lib/ach_client/providers/sftp/account_type_transformer.rb +20 -0
  38. data/lib/ach_client/providers/sftp/ach_batch.rb +97 -0
  39. data/lib/ach_client/providers/sftp/ach_status_checker.rb +146 -0
  40. data/lib/ach_client/providers/sftp/ach_transaction.rb +62 -0
  41. data/lib/ach_client/providers/sftp/nacha_provider.rb +30 -0
  42. data/lib/ach_client/providers/sftp/sftp_provider.rb +124 -0
  43. data/lib/ach_client/providers/sftp/transaction_type_transformer.rb +19 -0
  44. data/lib/ach_client/providers/soap/ach_works/account_type_transformer.rb +17 -0
  45. data/lib/ach_client/providers/soap/ach_works/ach_batch.rb +89 -0
  46. data/lib/ach_client/providers/soap/ach_works/ach_status_checker.rb +86 -0
  47. data/lib/ach_client/providers/soap/ach_works/ach_transaction.rb +80 -0
  48. data/lib/ach_client/providers/soap/ach_works/ach_works.rb +57 -0
  49. data/lib/ach_client/providers/soap/ach_works/company_info.rb +87 -0
  50. data/lib/ach_client/providers/soap/ach_works/correction_details_processor.rb +92 -0
  51. data/lib/ach_client/providers/soap/ach_works/date_formatter.rb +33 -0
  52. data/lib/ach_client/providers/soap/ach_works/response_record_processor.rb +91 -0
  53. data/lib/ach_client/providers/soap/ach_works/transaction_type_transformer.rb +18 -0
  54. data/lib/ach_client/providers/soap/i_check_gateway/account_type_transformer.rb +20 -0
  55. data/lib/ach_client/providers/soap/i_check_gateway/ach_batch.rb +12 -0
  56. data/lib/ach_client/providers/soap/i_check_gateway/ach_status_checker.rb +35 -0
  57. data/lib/ach_client/providers/soap/i_check_gateway/ach_transaction.rb +53 -0
  58. data/lib/ach_client/providers/soap/i_check_gateway/company_info.rb +51 -0
  59. data/lib/ach_client/providers/soap/i_check_gateway/i_check_gateway.rb +39 -0
  60. data/lib/ach_client/providers/soap/i_check_gateway/response_record_processor.rb +59 -0
  61. data/lib/ach_client/providers/soap/i_check_gateway/transaction_type_transformer.rb +8 -0
  62. data/lib/ach_client/providers/soap/soap_provider.rb +47 -0
  63. data/lib/ach_client/version.rb +4 -0
  64. data/lib/ach_client.rb +38 -0
  65. metadata +346 -0
@@ -0,0 +1,3 @@
1
+ # To be raised when someone tries to call an abstract method
2
+ class AbstractMethodError < RuntimeError
3
+ end
@@ -0,0 +1,15 @@
1
+ module AchClient
2
+ # Utility classes shared by all providers
3
+ class Helpers
4
+
5
+ # Turns dollars into cents
6
+ class DollarsToCents
7
+
8
+ # @param dollars [Float | BigDecimal | Fixnum | Integer]
9
+ # @return [Fixnum] cents
10
+ def self.dollars_to_cents(dollars)
11
+ (dollars.to_f.round(2) * 100).to_i
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,36 @@
1
+ module AchClient
2
+ class Logging
3
+ # Worker to asynchronously invoke the log provider
4
+ class LogProviderJob
5
+ include SuckerPunch::Job
6
+
7
+ ## Prettifies the xml and sends it asynchronously to the log provider
8
+ # @param xml [String] xml body to log
9
+ # @param name [String] title for the log
10
+ def perform(body:, name:)
11
+ # Savon logger does a nice job of XML pretty print
12
+ # Takes: message, list of filters, pretty print boolean
13
+ AchClient::Logging.log_provider.send_logs(
14
+ body: maybe_encrypt_message(
15
+ message: Savon::LogMessage.new(
16
+ body,
17
+ AchClient::Logging.log_filters,
18
+ true
19
+ ).to_s
20
+ ),
21
+ name: name
22
+ )
23
+ end
24
+
25
+ private
26
+ def maybe_encrypt_message(message:)
27
+ # Only encrypt if the client provided a password and a salt
28
+ if AchClient::Logging.should_use_encryption?
29
+ AchClient::Logging.codec.encrypt_and_sign(message)
30
+ else
31
+ message
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,22 @@
1
+ module AchClient
2
+ class Logging
3
+ # Base class for log providers
4
+ # Extending classes must implement send_logs
5
+ # The consumer may implement their own log provider and assign it to
6
+ # AchClient:
7
+ # ```ruby
8
+ # class MyCustomLogger < AchClient::Logging::LogProvider
9
+ # def self.send_logs(body:, name:)
10
+ # # Do whatever you want, like send the log data to S3, or whatever
11
+ # # logging service you choose
12
+ # end
13
+ # end
14
+ # AchClient::Logging.log_provider = MyCustomLogger
15
+ # ```
16
+ class LogProvider
17
+ def self.send_logs(body:, name:)
18
+ raise AbstractMethodError, "#{body}#{name}"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module AchClient
2
+ class Logging
3
+
4
+ # A log provider that does nothing.
5
+ class NullLogProvider < LogProvider
6
+
7
+ # Does absolutely nothing with the log info
8
+ def self.send_logs(*)
9
+ # Do nothing
10
+ nil
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module AchClient
2
+ class Logging
3
+ # Logs to stdout (using puts)
4
+ class StdoutLogProvider < LogProvider
5
+ # Prints the name and then the body
6
+ # @param body [String] the log body
7
+ # @param name [String] the log name
8
+ def self.send_logs(body:, name:)
9
+ puts name
10
+ puts body
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ require_relative './savon_observer.rb'
2
+ require_relative './log_providers/log_provider.rb'
3
+
4
+ module AchClient
5
+ # Base class for all things logging
6
+ class Logging
7
+
8
+ # Register our observer with Savon
9
+ Savon.observers << AchClient::Logging::SavonObserver.new
10
+
11
+ # @return [Class] type of the log provider
12
+ class_attribute :_log_provider_type
13
+
14
+ # @return [String] password to use for encrypting logs
15
+ class_attribute :encryption_password
16
+
17
+ # @return [String] salt to use for encrypting logs
18
+ class_attribute :encryption_salt
19
+
20
+ # Defaults to AchClient::Logging::NullLogProvider
21
+ # @return [Class] The Log provider to use.
22
+ def self.log_provider
23
+ self._log_provider_type || AchClient::Logging::NullLogProvider
24
+ end
25
+
26
+ # Set the log provider
27
+ # Must extend AchClient::Logging::LogProvider
28
+ # @param [Class] the new log provider
29
+ def self.log_provider=(log_provider)
30
+ if log_provider.is_a?(Class) &&
31
+ log_provider < AchClient::Logging::LogProvider
32
+ self._log_provider_type = log_provider
33
+ else
34
+ raise 'Must be subclass of AchClient::Logging::LogProvider'
35
+ end
36
+ end
37
+
38
+ # @return [Array<String>] List of XML nodes to scrub
39
+ class_attribute :_log_filters
40
+
41
+ # @return [Array<String>] List of XML nodes to scrub
42
+ def self.log_filters
43
+ self._log_filters || []
44
+ end
45
+
46
+ # Updates the log filters
47
+ # @param filters [Array<String>] List of XML nodes to scrub from the logs
48
+ def self.log_filters=(filters)
49
+ self._log_filters = filters
50
+ end
51
+
52
+ # Creates a codec (does encryption and decryption) using the provided
53
+ # password and salt
54
+ # @return [ActiveSupport::MessageEncryptor] the encryptor
55
+ def self.codec
56
+ ActiveSupport::MessageEncryptor.new(
57
+ ActiveSupport::KeyGenerator.new(
58
+ AchClient::Logging.encryption_password
59
+ ).generate_key(AchClient::Logging.encryption_salt)
60
+ )
61
+ end
62
+
63
+ # Returns whether the client has enabled encryption - if both a username and
64
+ # salt have been provided
65
+ # @return [Boolean] is encryption enabled?
66
+ def self.should_use_encryption?
67
+ encryption_password && encryption_salt
68
+ end
69
+
70
+ # Decrypt encrypted log file
71
+ # @param gibberish [String] the log body to decrypt
72
+ def self.decrypt_log(gibberish)
73
+ codec.decrypt_and_verify(gibberish)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ module AchClient
2
+ class Logging
3
+ # Hooks into every savon request.
4
+ # #notify is called before the request is made
5
+ class SavonObserver
6
+
7
+ ##
8
+ # Hooks into every SOAP request and sends the XML body to be logged.
9
+ # @param operation_name [Symbol] name of SOAP operation being exectuted
10
+ # @param builder [Savon::Builder] Savon wrapper for the request
11
+ # @param globals [Savon::GlobalOptions] Savon's global options
12
+ # @param locals [Savon::LocalOptions] Savon's global options
13
+ # @return [NilClass] returns nothing so the request is not mutated
14
+ def notify(operation_name, builder, _globals, _locals)
15
+ # Send the xml body to the logger job
16
+ AchClient::Logging::LogProviderJob.perform_async(
17
+ body: builder.to_s,
18
+ name: "request-#{operation_name}-#{DateTime.now}.xml"
19
+ )
20
+
21
+ # Must return nil so the request is unaltered
22
+ nil
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ module AchClient
2
+ ## Representations of merchant account types (checking or savings)
3
+ module AccountTypes
4
+ ## Base class for all account types
5
+ class AccountType
6
+ end
7
+
8
+ ## Represents a checking account
9
+ class Checking < AchClient::AccountTypes::AccountType
10
+ end
11
+
12
+ ## Represents a savings account
13
+ class Savings < AchClient::AccountTypes::AccountType
14
+ end
15
+
16
+ ## Represents a business checking account
17
+ class BusinessChecking < AchClient::AccountTypes::Checking
18
+ end
19
+
20
+ ## Represents a business savings account
21
+ class BusinessSavings < AchClient::AccountTypes::Savings
22
+ end
23
+
24
+ ## Represents a personal checking account
25
+ class PersonalChecking < AchClient::AccountTypes::Checking
26
+ end
27
+
28
+ ## Represents a personal savings account
29
+ class PersonalSavings < AchClient::AccountTypes::Savings
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,15 @@
1
+ module AchClient
2
+ # Abstract Response wrapper for the various ACH response statuses
3
+ class AchResponse
4
+
5
+
6
+ attr_reader :amount, # Amount of the processed ACH
7
+ :date # Date the Ach was in this status
8
+
9
+ def initialize(amount:, date:)
10
+ raise AbstractMethodError if self.class == AchClient::AchResponse
11
+ @amount = amount
12
+ @date = date
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require_relative './returned_ach_response.rb'
2
+
3
+ module AchClient
4
+ # Representation of an Ach return that contains a correction
5
+ class CorrectedAchResponse < ReturnedAchResponse
6
+ attr_reader :corrections
7
+
8
+ ##
9
+ # @param date [DateTime] date of correction return
10
+ # @param return_code [AchClient::ReturnCode] Ach Return code for the
11
+ # correction (ie AchClient::ReturnCodes.find_by(code: 'C01'))
12
+ # @param corrections [Hash] A hash of corrected attributes and their values
13
+ def initialize(amount:, date:, return_code:, corrections:)
14
+ @corrections = corrections
15
+ super(amount: amount, date: date, return_code: return_code)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ module AchClient
2
+ # The transaction is processing.
3
+ # Not much else to see here.
4
+ class ProcessingAchResponse < AchResponse
5
+ end
6
+ end
@@ -0,0 +1,16 @@
1
+ module AchClient
2
+ # Representation of an Ach return that failed
3
+ class ReturnedAchResponse < AchResponse
4
+
5
+ attr_reader :return_code
6
+
7
+ ##
8
+ # @param date [DateTime] date of correction return
9
+ # @param return_code [AchClient::ReturnCode] Ach Return code for the
10
+ # correction (ie AchClient::ReturnCodes.find_by(code: 'C01'))
11
+ def initialize(amount:, date:, return_code:)
12
+ @return_code = return_code
13
+ super(amount: amount, date: date)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module AchClient
2
+ # The transaction is settled. Huzzah!
3
+ class SettledAchResponse < AchResponse
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module AchClient
2
+ # Represents an Ach Return code. Consult NACHA documentation for a full list
3
+ # See config/return_codes.yml for our list.
4
+ class ReturnCode
5
+
6
+ attr_accessor :code,
7
+ :description,
8
+ :reason
9
+
10
+ # Constructs a Ach return code
11
+ # @param code [String] the 3 char code identifier (ie 'R01')
12
+ # @param description [String] full explanation of the return
13
+ # @param reason [String] shorter explanation of the return
14
+ def initialize(code:, description:, reason: nil)
15
+ @code = code
16
+ @description = description
17
+ @reason = reason
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module AchClient
2
+ # Finding and listing all Ach return codes
3
+ class ReturnCodes
4
+
5
+ # The path to the file where the return codes are enumerated
6
+ RETURN_CODES_YAML = '../../../config/return_codes.yml'
7
+
8
+ class_attribute :_return_codes
9
+
10
+ # @return [Array<AchClient::ReturnCode>] A list of all return codes.
11
+ def self.all
12
+ self._return_codes ||= YAML.load_file(
13
+ File.expand_path(File.join(File.dirname(__FILE__), RETURN_CODES_YAML))
14
+ ).map do |code|
15
+ ReturnCode.new(
16
+ code: code['code'],
17
+ description: code['description'],
18
+ reason: code['reason']
19
+ )
20
+ end
21
+ end
22
+
23
+ # Finds the first ReturnCode with the given code, or raises an exception.
24
+ # @param [String] 3 char code identifier for a return code
25
+ # @param [AchClient::ReturnCode] The ReturnCode object with that code
26
+ def self.find_by(code:)
27
+ self.all.find do |return_code|
28
+ return_code.code == code
29
+ # For some reason || is bad syntax in this context
30
+ end or raise "Could not find return code #{code}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ module AchClient
2
+ ## Representations of Ach transaction types (debit or credit)
3
+ module TransactionTypes
4
+ ## Base class for all transaction types
5
+ class TransactionType
6
+ end
7
+
8
+ ## Representation of a credit transaction type
9
+ class Credit < AchClient::TransactionTypes::TransactionType
10
+ end
11
+
12
+ ## Representation of a debit transaction type
13
+ class Debit < AchClient::TransactionTypes::TransactionType
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module AchClient
2
+ # Abstract Ach provider, which all other provider's inherit from
3
+ class Abstract
4
+
5
+ # Base class for sending batched ACH transactions to various providers
6
+ class AchBatch
7
+
8
+ ##
9
+ # @param ach_transactions [Array] List of AchTransaction objects to batch
10
+ def initialize(ach_transactions: [])
11
+ @ach_transactions = ach_transactions
12
+ end
13
+
14
+ ##
15
+ # Sends the batch to the provider, and returns a tracking identifier
16
+ # @return [Array<String>] Identifiers to use to poll for result of batch
17
+ # processing later on.
18
+ def send_batch
19
+ raise AbstractMethodError
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module AchClient
2
+ class Abstract
3
+
4
+ # Interface for polling provider for ACH status responses
5
+ class AchStatusChecker
6
+ # Wrapper for a provider's "most recent bucket"
7
+ # @return [Hash{String => AchClient::AchResponse}] Hash with provider's
8
+ # external ACH id as the key, AchResponse objects as values
9
+ def self.most_recent
10
+ raise AbstractMethodError
11
+ end
12
+
13
+ # Wrapper for a providers range response endpoint
14
+ # @return [Hash{String => AchClient::AchResponse}] Hash with provider's
15
+ # external ACH id as the key, AchResponse objects as values
16
+ def self.in_range(*)
17
+ raise AbstractMethodError
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,70 @@
1
+ module AchClient
2
+ class Abstract
3
+
4
+ # Generic representation of a single Ach transaction
5
+ class AchTransaction
6
+
7
+ ##
8
+ # @return [Array] A list of arguments to use in the initializer, and as
9
+ # instance attributes
10
+ def self.arguments
11
+ [
12
+ :account_number,
13
+ :account_type,
14
+ :amount,
15
+ :effective_entry_date,
16
+ :external_ach_id,
17
+ :memo,
18
+ :merchant_name,
19
+ :originator_name,
20
+ :routing_number,
21
+ :sec_code,
22
+ :transaction_type
23
+ ]
24
+ end
25
+
26
+ attr_reader(*arguments)
27
+
28
+ ##
29
+ # @param account_number [String] Merchant's account number
30
+ # @param account_type [AchClient::AccountTypes::AccountType] Merchant's account type
31
+ # (debit or credit), must be an instance of AchClient::AccountTypes::AccountType
32
+ # @param amount [BigDecimal] Amount of the ACH transaction
33
+ # @param effective_entry_date [Date] The date the transaction should be enacted
34
+ # @param external_ach_id [String] Tracking string you would like the
35
+ # provider to use with your transaction
36
+ # @param memo [String] Ach memo thing
37
+ # @param merchant_name [String] Name associated with merchantaccount we
38
+ # are ACHing with
39
+ # @param originator_name [String] String identifying you, will appear on
40
+ # merchants bank statement
41
+ # @param routing_number [String] Routing number of the merchant's account
42
+ # @param sec_code [String] CCD, PPD, WEB, etc.
43
+ # See: https://en.wikipedia.org/wiki/Automated_Clearing_House#SEC_codes
44
+ # @param transaction_type [AchClient::TransactionTypes::TransactionType] debit or
45
+ def initialize(*arguments)
46
+ args = arguments.extract_options!
47
+ self.class.arguments.each do |param|
48
+ self.instance_variable_set(
49
+ "@#{param}".to_sym,
50
+ args[param]
51
+ )
52
+ end
53
+ end
54
+
55
+ # @return [Boolean] true if transaction is a debit
56
+ def debit?
57
+ transaction_type == AchClient::TransactionTypes::Debit
58
+ end
59
+
60
+ # @return [Boolean] true if transaction is a credit
61
+ def credit?
62
+ transaction_type == AchClient::TransactionTypes::Credit
63
+ end
64
+
65
+ def send
66
+ raise AbstractMethodError
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,28 @@
1
+ module AchClient
2
+ class Abstract
3
+ # Interface for storing company credentials used with a provider
4
+ class CompanyInfo
5
+
6
+ ##
7
+ # @return [CompanyInfo] instance built from configuration values
8
+ def self.build
9
+ raise AbstractMethodError
10
+ end
11
+
12
+ ##
13
+ # Build a hash to send to provider
14
+ # @return [Hash] hash to send to provider
15
+ def to_hash
16
+ raise AbstractMethodError
17
+ end
18
+
19
+ private_class_method def self.build_from_config(args)
20
+ self.new(
21
+ args.map do |arg|
22
+ {arg => self.to_s.deconstantize.constantize.send(arg)}
23
+ end.reduce(&:merge)
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ module AchClient
2
+ class Abstract
3
+ ## Interface for turning a Provider's response representation of an ACH
4
+ # status into an instance of AchClient::Response
5
+ class ResponseRecordProcessor
6
+ ## Interface for turning a Provider's response representation of an ACH
7
+ # status into an instance of AchClient::Response
8
+ # @param record [Object] the record from the provider
9
+ # @return [AchClient::AchResponse] our representation of the response
10
+ def self.process_response_record(_record)
11
+ raise AbstractMethodError
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,38 @@
1
+ module AchClient
2
+ ##
3
+ # Transforms between client class and the strings that the provider expects
4
+ # For example, the TransactionType classes are serialized as 'C' or 'D' for
5
+ # AchWorks
6
+ class Transformer
7
+
8
+ ##
9
+ # Convert provider's string representation to AchClient class
10
+ # representation
11
+ # @param string [String] string to turn into class
12
+ # @return [Class] for example AchClient::AccountTypes::Checking or
13
+ # AchClient::AccountTypes::Savings
14
+ def self.deserialize_provider_value(string)
15
+ self.transformer[string] or raise(
16
+ "Unknown #{self} string #{string}"
17
+ )
18
+ end
19
+
20
+ ##
21
+ # Convert client class to string representation used by provider
22
+ # @param type [Class] the type to convert to a string
23
+ # @return [String] string serialization of the input class
24
+ def self.serialize_to_provider_value(type)
25
+ self.transformer.find do |_, v|
26
+ type <= v
27
+ end.try(:first) or raise(
28
+ "type must be one of #{self.transformer.values.join(', ')}"
29
+ )
30
+ end
31
+
32
+ # Mapping of classes to strings, to be overridden
33
+ # @return [Hash {String => Class}] the mapping
34
+ def self.transformer
35
+ raise AbstractMethodError
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ module AchClient
2
+ class Sftp
3
+ ##
4
+ # Transforms AccountTypes between AchClient class and the string
5
+ # that NACHA expects
6
+ class AccountTypeTransformer < AchClient::Transformer
7
+
8
+ # '2' means Checking, '3' means Savings
9
+ # The account type string is the first character in the transaction_code
10
+ # field.
11
+ # @return [Hash {String => Class}] the mapping
12
+ def self.transformer
13
+ {
14
+ '3' => AchClient::AccountTypes::Savings,
15
+ '2' => AchClient::AccountTypes::Checking
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end