sepa_king 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d39443f2a8e1403804bfc6dd0eeb03f9e5e9d845
4
- data.tar.gz: 7fa5f5072912dee37819412cc0e05229c371b33a
3
+ metadata.gz: 5cc20b05ec4228c5ed453503dd90329e3b6366b3
4
+ data.tar.gz: 884d0f00387ef8d8a50b06a529a92d4220897773
5
5
  SHA512:
6
- metadata.gz: a6aa54767870360c955f350ae74bd3777fc6f7928b9cf9b75806689e76f4b70db70f5f722e426c7b4df075b6dcba939e560e84af479d56417c2b8caac9b173a1
7
- data.tar.gz: 9a06003c4a9d9c9fdbf58d1d6430651888339317c1f1a8f98d2f5c1a5f320b7b60457e3fae7e7ce8d8c74e6fdc9e3d4b2052aeae96e742079c3dbc4650a5cf1b
6
+ metadata.gz: 21b8f10e50d79e84d5a9ef67a54b15999e48efa0d13e8bc9df75387638395cc852e37c2e7f8541763aaee9fd74eee3e969d95a08a04a744e3ad16869ac326eaf
7
+ data.tar.gz: ae7a218d84ba1ee072079a1720d9da747d8c6d6c24179db3ec4b7cc7d1b7e3ac61556a9260836d36eeabf33111efd97910a210709f7d75ca6a17b12a45e28dc9
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,38 @@
1
+ We love pull requests. Here's a quick guide:
2
+
3
+ 1. Fork the repo.
4
+
5
+ 2. Run the tests. We only take pull requests with passing tests, and it's great
6
+ to know that you have a clean slate: `bundle && rake`
7
+
8
+ 3. Add a test for your change. Only refactoring and documentation changes
9
+ require no new tests. If you are adding functionality or fixing a bug, we need
10
+ a test!
11
+
12
+ 4. Make the test pass.
13
+
14
+ 5. Push to your fork and submit a pull request.
15
+
16
+
17
+ At this point you're waiting on us. We like to at least comment on, if not
18
+ accept, pull requests within three business days (and, typically, one business
19
+ day). We may suggest some changes or improvements or alternatives.
20
+
21
+ Some things that will increase the chance that your pull request is accepted,
22
+ taken straight from the Ruby on Rails guide:
23
+
24
+ * Use Rails idioms and helpers
25
+ * Include tests that fail without your code, and pass with it
26
+ * Update the documentation, the surrounding one, examples elsewhere, guides,
27
+ whatever is affected by your contribution
28
+
29
+ Syntax:
30
+
31
+ * Two spaces, no tabs.
32
+ * No trailing whitespace. Blank lines should not have any space.
33
+ * Prefer &&/|| over and/or.
34
+ * MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
35
+ * a = b and not a=b.
36
+ * Follow the conventions you see used in the source already.
37
+
38
+ And in case we didn't emphasize it enough: we love tests!
@@ -1,7 +1,7 @@
1
- The MIT License (MIT)
2
-
3
1
  Copyright (c) 2013 Georg Leciejewski (Sales King GmbH) & Georg Ledermann
4
2
 
3
+ MIT License
4
+
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
7
7
  "Software"), to deal in the Software without restriction, including
data/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Ruby gem for creating SEPA XML files
2
+
3
+ [![Build Status](https://secure.travis-ci.org/salesking/sepa_king.png)](http://travis-ci.org/salesking/sepa_king)
4
+ [![Code Climate](https://codeclimate.com/github/salesking/sepa_king.png)](https://codeclimate.com/github/salesking/sepa_king)
5
+ [![Coverage Status](https://coveralls.io/repos/salesking/sepa_king/badge.png)](https://coveralls.io/r/salesking/sepa_king)
6
+
7
+ We love building payment applications! So after developing the [DTAUS library for Ruby](https://github.com/salesking/king_dtaus) we move on with SEPA.
8
+
9
+
10
+ ## Features
11
+
12
+ * Credit transfer initiation (pain.001.002.03)
13
+ * Debit transfer initiation (pain.008.002.02)
14
+ * Tested with Ruby 1.9.3 and 2.0.0
15
+
16
+
17
+ ## Installation
18
+
19
+ gem install sepa_king
20
+
21
+
22
+ ## Usage
23
+
24
+ How to create the XML for **Direct Debit Initiation** (in German: "Lastschriften")
25
+
26
+ ```ruby
27
+ # First: Create the main object
28
+ sdd = SEPA::DirectDebit.new(
29
+ # Name of the initiating party and creditor, in German: "Auftraggeber"
30
+ # String, max. 70 char
31
+ name: 'Gläubiger GmbH',
32
+
33
+ # Business Identifier Code (SWIFT-Code) of the creditor
34
+ # String, 8 or 11 char
35
+ bic: 'BANKDEFFXXX',
36
+
37
+ # International Bank Account Number of the creditor
38
+ # String, max. 34 chars
39
+ iban: 'DE87200500001234567890',
40
+
41
+ # Creditor Identifier, in German: Gläubiger-Identifikationsnummer
42
+ # String, max. 35 chars
43
+ creditor_identifier: 'DE98ZZZ09999999999'
44
+ )
45
+
46
+ # Second: Add transactions
47
+ sdd.add_transaction(
48
+ # Name of the debitor, in German: "Zahlungspflichtiger"
49
+ # String, max. 70 char
50
+ name: 'Zahlemann & Söhne GbR',
51
+
52
+ # Business Identifier Code (SWIFT-Code) of the debitor's account
53
+ # String, 8 or 11 char
54
+ bic: 'SPUEDE2UXXX',
55
+
56
+ # International Bank Account Number of the debitor's account
57
+ # String, max. 34 chars
58
+ iban: 'DE21500500009876543210',
59
+
60
+ # Amount in EUR
61
+ # Number with two decimal digit
62
+ amount: 39.99,
63
+
64
+ # OPTIONAL: End-To-End-Identification, will be submitted to the debitor
65
+ # String, max. 35 char
66
+ reference: 'XYZ/2013-08-ABO/6789',
67
+
68
+ # OPTIONAL: Unstructured remittance Information, in German "Verwendungszweck"
69
+ # String, max. 140 char
70
+ remittance_information: 'Vielen Dank für Ihren Einkauf!',
71
+
72
+ # Mandate identifikation, in German "Mandatsreferenz"
73
+ # String, max. 35 char
74
+ mandate_id: 'K-02-2011-12345',
75
+
76
+ # Mandate Date of signature, in German "Datum, zu dem das Mandat unterschrieben wurde"
77
+ # Date
78
+ mandate_date_of_signature: Date.new(2011,1,25),
79
+
80
+ # Local instrument, in German "Lastschriftart"
81
+ # One of this strings:
82
+ # 'CORE' ("Basis-Lastschrift")
83
+ # 'B2B' ("Firmen-Lastschrift")
84
+ local_instrument: 'CORE',
85
+
86
+ # Sequence type
87
+ # One of this strings:
88
+ # 'FRST' ("Erst-Lastschrift")
89
+ # 'RCUR' ("Folge-Lastschrift")
90
+ # 'OOFF' ("Einmalige Lastschrift")
91
+ # 'FNAL' ("Letztmalige Lastschrift")
92
+ sequence_type: 'OOFF',
93
+
94
+ # OPTIONAL: Requested collection date, in German "Fälligkeitsdatum der Lastschrift"
95
+ # Date
96
+ requested_date: Date.new(2013,9,5),
97
+
98
+ # OPTIONAL: Enables or disables batch booking, in German "Sammelbuchung / Einzelbuchung"
99
+ batch_booking: true
100
+ )
101
+ sdd.add_transaction ...
102
+
103
+ # Last: create XML string
104
+ xml_string = sdd.to_xml
105
+ ```
106
+
107
+
108
+ How to create the XML for **Credit Transfer Initiation** (in german: "Überweisungen")
109
+
110
+ ```ruby
111
+ # First: Create the main object
112
+ sct = SEPA::CreditTransfer.new(
113
+ # Name of the initiating party and debitor, in German: "Auftraggeber"
114
+ # String, max. 70 char
115
+ name: 'Schuldner GmbH',
116
+
117
+ # Business Identifier Code (SWIFT-Code) of the debitor
118
+ # String, 8 or 11 char
119
+ bic: 'BANKDEFFXXX',
120
+
121
+ # International Bank Account Number of the debitor
122
+ # String, max. 34 chars
123
+ iban: 'DE87200500001234567890'
124
+ )
125
+
126
+ # Second: Add transactions
127
+ sct.add_transaction(
128
+ # Name of the creditor, in German: "Zahlungsempfänger"
129
+ # String, max. 70 char
130
+ name: 'Telekomiker AG',
131
+
132
+ # Business Identifier Code (SWIFT-Code) of the creditor's account
133
+ # String, 8 or 11 char
134
+ bic: 'PBNKDEFF370',
135
+
136
+ # International Bank Account Number of the creditor's account
137
+ # String, max. 34 chars
138
+ iban: 'DE37112589611964645802',
139
+
140
+ # Amount in EUR
141
+ # Number with two decimal digit
142
+ amount: 102.50,
143
+
144
+ # OPTIONAL: End-To-End-Identification, will be submitted to the creditor
145
+ # String, max. 35 char
146
+ reference: 'XYZ-1234/123',
147
+
148
+ # OPTIONAL: Unstructured remittance Information, in German "Verwendungszweck"
149
+ # String, max. 140 char
150
+ remittance_information: 'Rechnung vom 22.08.2013'
151
+ )
152
+ sct.add_transaction ...
153
+
154
+ # Last: create XML string
155
+ xml_string = sct.to_xml
156
+ ```
157
+
158
+
159
+ ## Changelog
160
+
161
+ https://github.com/salesking/sepa_king/releases
162
+
163
+
164
+ ## Resources
165
+
166
+ * http://www.ebics.de/index.php?id=77
167
+ * SalesKing: http://salesking.eu
168
+
169
+
170
+ ## License
171
+
172
+ Released under the MIT license
173
+
174
+ Copyright (c) 2013 Georg Leciejewski (SalesKing), Georg Ledermann (https://github.com/ledermann)
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
- task :default => :spec
6
+ task default: :spec
data/lib/sepa_king.rb CHANGED
@@ -5,6 +5,7 @@ require 'builder'
5
5
  require 'iban-tools'
6
6
 
7
7
  require 'sepa_king/converter'
8
+ require 'sepa_king/validator'
8
9
  require 'sepa_king/account'
9
10
  require 'sepa_king/account/debtor_account'
10
11
  require 'sepa_king/account/creditor_account'
@@ -1,18 +1,19 @@
1
1
  # encoding: utf-8
2
2
  module SEPA
3
3
  class Account
4
- include ActiveModel::Model
4
+ include ActiveModel::Validations
5
5
  extend Converter
6
6
 
7
7
  attr_accessor :name, :iban, :bic
8
- convert :name, :to => :text
8
+ convert :name, to: :text
9
9
 
10
- validates_presence_of :name, :iban, :bic
11
- validates_length_of :name, :maximum => 70
12
- validates_length_of :bic, :within => 8..11
10
+ validates_length_of :name, within: 1..70
11
+ validates_with BICValidator, IBANValidator
13
12
 
14
- validate do |t|
15
- errors.add(:iban, 'is invalid') unless IBANTools::IBAN.valid?(t.iban.to_s)
13
+ def initialize(attributes = {})
14
+ attributes.each do |name, value|
15
+ send("#{name}=", value)
16
+ end
16
17
  end
17
18
  end
18
19
  end
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
  module SEPA
3
3
  class CreditorAccount < Account
4
- attr_accessor :identifier
4
+ attr_accessor :creditor_identifier
5
5
 
6
- validates_length_of :identifier, :is => 18
6
+ validates_with CreditorIdentifierValidator
7
7
  end
8
8
  end
@@ -3,11 +3,11 @@
3
3
  module SEPA
4
4
  class Message
5
5
  attr_reader :account, :transactions
6
- class_attribute :account_class, :transaction_class
6
+ class_attribute :account_class, :transaction_class, :xml_main_tag
7
7
 
8
8
  def initialize(account_options={})
9
9
  @transactions = []
10
- @account = self.account_class.new(account_options)
10
+ @account = account_class.new(account_options)
11
11
  end
12
12
 
13
13
  def add_transaction(options)
@@ -16,12 +16,22 @@ module SEPA
16
16
  @transactions << transaction
17
17
  end
18
18
 
19
+ # @return [String] xml
19
20
  def to_xml
20
21
  raise RuntimeError.new(account.errors.full_messages.join("\n")) unless account.valid?
22
+
23
+ builder = Builder::XmlMarkup.new indent: 2
24
+ builder.instruct!
25
+ builder.Document(xml_schema) do
26
+ builder.__send__(xml_main_tag) do
27
+ build_group_header(builder)
28
+ build_payment_informations(builder)
29
+ end
30
+ end
21
31
  end
22
32
 
23
- def amount_total
24
- transactions.inject(0) { |sum, t| sum + t.amount }
33
+ def amount_total(selected_transactions=transactions)
34
+ selected_transactions.inject(0) { |sum, t| sum + t.amount }
25
35
  end
26
36
 
27
37
  private
@@ -4,80 +4,87 @@ module SEPA
4
4
  class CreditTransfer < Message
5
5
  self.account_class = DebtorAccount
6
6
  self.transaction_class = CreditTransferTransaction
7
+ self.xml_main_tag = 'CstmrCdtTrfInitn'
7
8
 
8
- def to_xml
9
- super
9
+ private
10
+ # @return {Hash<Symbol=>String>} xml schema information used in output xml
11
+ def xml_schema
12
+ { :xmlns => 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03',
13
+ :'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
14
+ :'xsi:schemaLocation' => 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03 pain.001.002.03.xsd' }
15
+ end
10
16
 
11
- builder = Builder::XmlMarkup.new :indent => 2
12
- builder.instruct!
13
- builder.Document :xmlns => 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03',
14
- :'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
15
- :'xsi:schemaLocation' => 'urn:iso:std:iso:20022:tech:xsd:pain.001.002.03 pain.001.002.03.xsd' do
16
- builder.CstmrCdtTrfInitn do
17
- build_group_header(builder)
18
- build_payment_information(builder)
19
- end
17
+ # Find groups of transactions which share the same values of some attributes
18
+ def grouped_transactions
19
+ transactions.group_by do |transaction|
20
+ { requested_date: transaction.requested_date,
21
+ batch_booking: transaction.batch_booking
22
+ }
20
23
  end
21
24
  end
22
25
 
23
- private
24
- def build_payment_information(builder)
25
- builder.PmtInf do
26
- builder.PmtInfId(payment_information_identification)
27
- builder.PmtMtd('TRF')
28
- builder.BtchBookg(true)
29
- builder.NbOfTxs(transactions.length)
30
- builder.CtrlSum('%.2f' % amount_total)
31
- builder.PmtTpInf do
32
- builder.SvcLvl do
33
- builder.Cd('SEPA')
26
+ def build_payment_informations(builder)
27
+ # Build a PmtInf block for every group of transactions
28
+ grouped_transactions.each do |group, transactions|
29
+ # All transactions with the same requested_date are placed into the same PmtInf block
30
+ builder.PmtInf do
31
+ builder.PmtInfId(payment_information_identification)
32
+ builder.PmtMtd('TRF')
33
+ builder.BtchBookg(group[:batch_booking])
34
+ builder.NbOfTxs(transactions.length)
35
+ builder.CtrlSum('%.2f' % amount_total(transactions))
36
+ builder.PmtTpInf do
37
+ builder.SvcLvl do
38
+ builder.Cd('SEPA')
39
+ end
34
40
  end
35
- end
36
- builder.ReqdExctnDt(Date.today.next.iso8601)
37
- builder.Dbtr do
38
- builder.Nm(account.name)
39
- end
40
- builder.DbtrAcct do
41
- builder.Id do
42
- builder.IBAN(account.iban)
41
+ builder.ReqdExctnDt(group[:requested_date].iso8601)
42
+ builder.Dbtr do
43
+ builder.Nm(account.name)
43
44
  end
44
- end
45
- builder.DbtrAgt do
46
- builder.FinInstnId do
47
- builder.BIC(account.bic)
45
+ builder.DbtrAcct do
46
+ builder.Id do
47
+ builder.IBAN(account.iban)
48
+ end
49
+ end
50
+ builder.DbtrAgt do
51
+ builder.FinInstnId do
52
+ builder.BIC(account.bic)
53
+ end
54
+ end
55
+ builder.ChrgBr('SLEV')
56
+
57
+ transactions.each do |transaction|
58
+ build_transaction(builder, transaction)
48
59
  end
49
60
  end
50
- builder.ChrgBr('SLEV')
51
- build_transactions(builder)
52
61
  end
53
62
  end
54
63
 
55
- def build_transactions(builder)
56
- transactions.each do |transaction|
57
- builder.CdtTrfTxInf do
58
- builder.PmtId do
59
- builder.EndToEndId(transaction.reference || 'NOTPROVIDED')
60
- end
61
- builder.Amt do
62
- builder.InstdAmt('%.2f' % transaction.amount, :Ccy => 'EUR')
63
- end
64
- builder.CdtrAgt do
65
- builder.FinInstnId do
66
- builder.BIC(transaction.bic)
67
- end
68
- end
69
- builder.Cdtr do
70
- builder.Nm(transaction.name)
64
+ def build_transaction(builder, transaction)
65
+ builder.CdtTrfTxInf do
66
+ builder.PmtId do
67
+ builder.EndToEndId(transaction.reference)
68
+ end
69
+ builder.Amt do
70
+ builder.InstdAmt('%.2f' % transaction.amount, Ccy: 'EUR')
71
+ end
72
+ builder.CdtrAgt do
73
+ builder.FinInstnId do
74
+ builder.BIC(transaction.bic)
71
75
  end
72
- builder.CdtrAcct do
73
- builder.Id do
74
- builder.IBAN(transaction.iban)
75
- end
76
+ end
77
+ builder.Cdtr do
78
+ builder.Nm(transaction.name)
79
+ end
80
+ builder.CdtrAcct do
81
+ builder.Id do
82
+ builder.IBAN(transaction.iban)
76
83
  end
77
- if transaction.remittance_information
78
- builder.RmtInf do
79
- builder.Ustrd(transaction.remittance_information)
80
- end
84
+ end
85
+ if transaction.remittance_information
86
+ builder.RmtInf do
87
+ builder.Ustrd(transaction.remittance_information)
81
88
  end
82
89
  end
83
90
  end