Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.0.2
3.4.3
24 changes: 12 additions & 12 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ PATH
remote: .
specs:
girocode (0.2.0)
bank-contact
iban-tools
rqrcode

GEM
remote: https://rubygems.org/
specs:
bank-contact (0.0.6)
chunky_png (1.4.0)
docile (1.4.0)
minitest (5.14.4)
rake (13.0.6)
rqrcode (2.1.0)
docile (1.4.1)
iban-tools (1.2.1)
minitest (5.25.5)
rake (13.3.0)
rqrcode (3.1.0)
chunky_png (~> 1.0)
rqrcode_core (~> 1.0)
rqrcode_core (1.2.0)
simplecov (0.21.2)
rqrcode_core (~> 2.0)
rqrcode_core (2.0.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.3)
simplecov-html (0.13.1)
simplecov_json_formatter (0.1.4)

PLATFORMS
ruby
Expand All @@ -34,4 +34,4 @@ DEPENDENCIES
simplecov

BUNDLED WITH
2.2.22
2.6.8
2 changes: 1 addition & 1 deletion girocode.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ Gem::Specification.new do |s|
s.require_paths = ['lib']

s.add_dependency 'rqrcode'
s.add_dependency 'bank-contact'
s.add_dependency 'iban-tools'
end
2 changes: 1 addition & 1 deletion lib/girocode.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require 'bigdecimal'
require 'bank/contact'
require 'iban-tools'
require 'rqrcode'

require_relative 'girocode/version'
Expand Down
50 changes: 25 additions & 25 deletions lib/girocode/code.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
module Girocode
class Error < StandardError; end

class Code
ATTRIBUTES = %i[bic name iban currency amount purpose creditor_reference reference bto_info]
attr_reader *ATTRIBUTES

MAX_PAYLOAD_BYTES = 331
AMOUNT_RANGE = BigDecimal('0.01')..BigDecimal('999999999.99')

def initialize(**attrs)
if keys = attrs.keys - ATTRIBUTES and not keys.empty?
raise ArgumentError, "Illegal attributes #{keys.inspect}"
Expand All @@ -19,99 +19,99 @@ def initialize(**attrs)
raise ArgumentError, "either creditor reference or reference may be set" if creditor_reference? && reference?
raise ArgumentError, "payload too long" if payload.bytesize > MAX_PAYLOAD_BYTES
end

def bic=(value)
if value.nil?
@bic = nil
elsif value.match? /\A[A-Z0-9]{4}([A-Z]{2})([A-Z0-9]{2})([A-Z0-9]{3})?\z/
@bic = value
else
bic = Bank::BIC.new(value)
raise ArgumentError, "Invalid BIC #{value.inspect}" unless bic.valid?
@bic = bic.to_s
raise ArgumentError, "Invalid BIC #{value.inspect}"
end
end

def name=(value)
value = value.strip
raise ArgumentError, 'name is required' unless value
raise ArgumentError, 'name too long' if value.size > 70
raise ArgumentError, 'Illegal name' if value.include?("\n") || value.include?("\r")
@name = value
end

def iban=(value)
iban = Bank::IBAN.new(value)
raise ArgumentError, "Invalid IBAN #{value.inspect}" unless iban.valid?
@iban = iban.to_s
raise ArgumentError, "Invalid IBAN #{value.inspect}" unless IBANTools::IBAN.valid?(value)

@iban = value
end

def currency=(value)
value = value.to_s.upcase
raise ArgumentError, "Invalid currency" unless value.match?(/\A[A-Z]{3}\z/)
@currency = value
end

def amount=(value)
raise ArgumentError, 'amount is required' unless value
value = BigDecimal(value, Float::DIG + 1)
raise ArgumentError, "invalid amount #{value.inspect}" unless AMOUNT_RANGE.cover?(value)
@amount = value
end

def purpose=(value)
unless value.nil?
raise ArgumentError, "invalid purpose #{value.inspect}" unless value.match?(/\A[A-z0-9]{0,4}\z/)
end
@purpose = value
end

def creditor_reference=(value)
unless value.nil?
raise ArgumentError, "invalid creditor reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 35
end
@creditor_reference = value
end

def reference=(value)
unless value.nil?
raise ArgumentError, "invalid reference #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 140
end
@reference = value
end

def bto_info=(value)
unless value.nil?
raise ArgumentError, "invalid bto_info #{value.inspect}" if value.include?("\n") || value.include?("\r") || value.size > 70
end
@bto_info = value
end

ATTRIBUTES.each do |attr|
define_method("#{attr}?") do
value = instance_variable_get("@#{attr}")
value.respond_to?(:empty?) ? !value.empty? : !!value
end
end

def payload
['BCD', '002', '1', 'SCT',
bic, name, iban,formatted_amount, purpose,
creditor_reference || reference, bto_info].map(&:to_s).join("\n")
end

def to_qrcode
RQRCode::QRCode.new(payload, level: :m, mode: :byte_8bit)
end

def to_ascii
to_qrcode.to_s
end

%i[png svg html ansi].each do |format|
define_method("to_#{format}") { |*args| to_qrcode.public_send("as_#{format}", *args) }
end

private

def formatted_amount
"#{currency}#{amount.round(2).to_s('F')}" if currency? && amount
end
Expand Down
Loading