keepr 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +44 -0
  3. data/.travis.yml +9 -9
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +1 -1
  6. data/README.md +3 -3
  7. data/Rakefile +2 -0
  8. data/ci/Gemfile-rails-4-2 +3 -2
  9. data/ci/Gemfile-rails-5-0 +3 -2
  10. data/ci/Gemfile-rails-5-1 +3 -2
  11. data/ci/Gemfile-rails-5-2 +3 -2
  12. data/ci/{Gemfile-rails-4-1 → Gemfile-rails-6-0} +3 -2
  13. data/keepr.gemspec +14 -12
  14. data/lib/generators/keepr/migration/migration_generator.rb +5 -3
  15. data/lib/generators/keepr/migration/templates/migration.rb +2 -0
  16. data/lib/keepr.rb +6 -4
  17. data/lib/keepr/account.rb +37 -37
  18. data/lib/keepr/account_export.rb +10 -14
  19. data/lib/keepr/active_record_extension.rb +4 -2
  20. data/lib/keepr/contact_export.rb +6 -7
  21. data/lib/keepr/cost_center.rb +2 -0
  22. data/lib/keepr/group.rb +21 -20
  23. data/lib/keepr/groups_creator.rb +7 -7
  24. data/lib/keepr/journal.rb +14 -11
  25. data/lib/keepr/journal_export.rb +9 -6
  26. data/lib/keepr/posting.rb +21 -16
  27. data/lib/keepr/tax.rb +2 -0
  28. data/lib/keepr/version.rb +3 -1
  29. data/spec/factories/account.rb +5 -3
  30. data/spec/factories/cost_center.rb +4 -2
  31. data/spec/factories/group.rb +4 -2
  32. data/spec/factories/tax.rb +5 -3
  33. data/spec/keepr/account_export_spec.rb +22 -19
  34. data/spec/keepr/account_spec.rb +47 -42
  35. data/spec/keepr/active_record_extension_spec.rb +20 -18
  36. data/spec/keepr/contact_export_spec.rb +17 -14
  37. data/spec/keepr/cost_center_spec.rb +2 -0
  38. data/spec/keepr/group_spec.rb +39 -35
  39. data/spec/keepr/groups_creator_spec.rb +7 -4
  40. data/spec/keepr/journal_export_spec.rb +26 -25
  41. data/spec/keepr/journal_spec.rb +33 -31
  42. data/spec/keepr/posting_spec.rb +8 -6
  43. data/spec/keepr/tax_spec.rb +21 -14
  44. data/spec/spec_helper.rb +6 -5
  45. data/spec/support/contact.rb +2 -0
  46. data/spec/support/document.rb +2 -0
  47. data/spec/support/ledger.rb +2 -0
  48. data/spec/support/spec_migration.rb +2 -0
  49. metadata +28 -14
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Keepr::ActiveRecordExtension
2
4
  def self.included(base)
3
5
  base.extend ClassMethods
@@ -17,7 +19,7 @@ module Keepr::ActiveRecordExtension
17
19
  def has_keepr_journals
18
20
  has_many :keepr_journals, class_name: 'Keepr::Journal', as: :accountable, dependent: :restrict_with_error
19
21
 
20
- class_eval <<-EOT
22
+ class_eval <<-CODE, __FILE__, __LINE__ + 1
21
23
  def keepr_booked?
22
24
  keepr_journals.exists?
23
25
  end
@@ -27,7 +29,7 @@ module Keepr::ActiveRecordExtension
27
29
  where('keepr_journals.id' => nil)
28
30
  }
29
31
  scope :keepr_booked, -> { joins(:keepr_journals) }
30
- EOT
32
+ CODE
31
33
  end
32
34
 
33
35
  def has_keepr_postings
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::ContactExport
2
- def initialize(accounts, header_options={}, &block)
4
+ def initialize(accounts, header_options = {}, &block)
3
5
  raise ArgumentError unless block_given?
4
6
 
5
7
  @accounts = accounts
@@ -15,22 +17,19 @@ class Keepr::ContactExport
15
17
  export.to_file(filename)
16
18
  end
17
19
 
18
- private
20
+ private
19
21
 
20
22
  def export
21
23
  export = Datev::ContactExport.new(@header_options)
22
24
 
23
25
  @accounts.reorder(:number).each do |account|
24
- if account.debtor? || account.creditor?
25
- export << to_datev(account)
26
- end
26
+ export << to_datev(account) if account.debtor? || account.creditor?
27
27
  end
28
28
 
29
29
  export
30
30
  end
31
31
 
32
32
  def to_datev(account)
33
- { 'Konto' => account.number
34
- }.merge(@block.call(account))
33
+ { 'Konto' => account.number }.merge(@block.call(account))
35
34
  end
36
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::CostCenter < ActiveRecord::Base
2
4
  self.table_name = 'keepr_cost_centers'
3
5
 
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::Group < ActiveRecord::Base
2
4
  self.table_name = 'keepr_groups'
3
5
 
4
6
  has_ancestry orphan_strategy: :restrict
5
7
 
6
- enum target: [ :asset, :liability, :profit_and_loss ]
8
+ enum target: %i[asset liability profit_and_loss]
7
9
 
8
10
  validates_presence_of :name
9
11
 
10
12
  has_many :keepr_accounts, class_name: 'Keepr::Account', foreign_key: 'keepr_group_id', dependent: :restrict_with_error
11
13
 
12
- before_validation :get_from_parent
14
+ before_validation :set_target_from_parent
13
15
 
14
16
  validate :check_result_and_target
15
17
 
@@ -19,30 +21,29 @@ class Keepr::Group < ActiveRecord::Base
19
21
 
20
22
  def keepr_postings
21
23
  if is_result
22
- Keepr::Posting.
23
- joins(:keepr_account).
24
- where(keepr_accounts: { kind: [
25
- Keepr::Account.kinds[:revenue],
26
- Keepr::Account.kinds[:expense]
27
- ]})
24
+ Keepr::Posting
25
+ .joins(:keepr_account)
26
+ .where(keepr_accounts: { kind: [
27
+ Keepr::Account.kinds[:revenue],
28
+ Keepr::Account.kinds[:expense]
29
+ ] })
28
30
  else
29
- Keepr::Posting.
30
- joins(keepr_account: :keepr_group).
31
- merge(self.subtree)
31
+ Keepr::Posting
32
+ .joins(keepr_account: :keepr_group)
33
+ .merge(subtree)
32
34
  end
33
35
  end
34
36
 
35
- private
36
- def get_from_parent
37
- if self.parent
38
- self.target = self.parent.target
39
- end
37
+ private
38
+
39
+ def set_target_from_parent
40
+ self.target = parent.target if parent
40
41
  end
41
42
 
42
43
  def check_result_and_target
43
- if is_result
44
- # Attribute `is_result` allowed for liability target only
45
- errors.add :base, :liability_needed_for_result unless liability?
46
- end
44
+ return unless is_result
45
+
46
+ # Attribute `is_result` allowed for liability target only
47
+ errors.add :base, :liability_needed_for_result unless liability?
47
48
  end
48
49
  end
@@ -1,7 +1,8 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  class Keepr::GroupsCreator
3
4
  def initialize(target)
4
- raise ArgumentError unless [ :balance, :profit_and_loss ].include?(target)
5
+ raise ArgumentError unless %i[balance profit_and_loss].include?(target)
5
6
 
6
7
  @target = target
7
8
  end
@@ -16,7 +17,8 @@ class Keepr::GroupsCreator
16
17
  end
17
18
  end
18
19
 
19
- private
20
+ private
21
+
20
22
  def load(filename, options)
21
23
  full_filename = File.join(File.dirname(__FILE__), "groups_creator/#{filename}".downcase)
22
24
  lines = File.readlines(full_filename)
@@ -31,11 +33,9 @@ private
31
33
  number, name = line.lstrip.match(/^(.*?)\s(.+)$/).to_a[1..-1]
32
34
 
33
35
  attributes = options.merge(name: name, number: number)
34
- if @target == :balance && name == 'Jahresüberschuss/Jahresfehlbetrag'
35
- attributes[:is_result] = true
36
- end
36
+ attributes[:is_result] = true if @target == :balance && name == 'Jahresüberschuss/Jahresfehlbetrag'
37
37
 
38
- if depth == 0
38
+ if depth.zero?
39
39
  parents = []
40
40
  group = Keepr::Group.create!(attributes)
41
41
  else
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::Journal < ActiveRecord::Base
2
4
  self.table_name = 'keepr_journals'
3
5
 
@@ -11,7 +13,7 @@ class Keepr::Journal < ActiveRecord::Base
11
13
 
12
14
  accepts_nested_attributes_for :keepr_postings, allow_destroy: true, reject_if: :all_blank
13
15
 
14
- default_scope { order({date: :desc}, {id: :desc}) }
16
+ default_scope { order({ date: :desc }, id: :desc) }
15
17
 
16
18
  validate :validate_postings
17
19
 
@@ -31,7 +33,8 @@ class Keepr::Journal < ActiveRecord::Base
31
33
  before_update :check_permanent
32
34
  before_destroy :check_permanent
33
35
 
34
- private
36
+ private
37
+
35
38
  def existing_postings
36
39
  keepr_postings.to_a.delete_if(&:marked_for_destruction?)
37
40
  end
@@ -51,15 +54,15 @@ private
51
54
  end
52
55
 
53
56
  def check_permanent
54
- if self.permanent_was
55
- # If marked as permanent, no changes are allowed
56
- errors.add :base, :changes_not_allowed
57
-
58
- if ActiveRecord::VERSION::MAJOR < 5
59
- false
60
- else
61
- throw :abort
62
- end
57
+ return unless permanent_was
58
+
59
+ # If marked as permanent, no changes are allowed
60
+ errors.add :base, :changes_not_allowed
61
+
62
+ if ActiveRecord::VERSION::MAJOR < 5
63
+ false
64
+ else
65
+ throw :abort
63
66
  end
64
67
  end
65
68
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::JournalExport
2
- def initialize(journals, header_options={}, &block)
4
+ def initialize(journals, header_options = {}, &block)
3
5
  @journals = journals
4
6
  @header_options = header_options
5
7
  @block = block
@@ -13,7 +15,7 @@ class Keepr::JournalExport
13
15
  export.to_file(filename)
14
16
  end
15
17
 
16
- private
18
+ private
17
19
 
18
20
  def export
19
21
  export = Datev::BookingExport.new(@header_options)
@@ -29,19 +31,20 @@ private
29
31
 
30
32
  def to_datev(journal)
31
33
  main_posting = journal.keepr_postings.find { |p| p.keepr_account.debtor? || p.keepr_account.creditor? }
32
- main_posting ||= journal.keepr_postings.sort_by(&:amount).last
34
+ main_posting ||= journal.keepr_postings.max_by(&:amount)
33
35
 
34
- journal.keepr_postings.sort_by { |p| [ p.side == main_posting.side ? 1 : 0, -p.amount ] }.map do |posting|
36
+ journal.keepr_postings.sort_by { |p| [p.side == main_posting.side ? 1 : 0, -p.amount] }.map do |posting|
35
37
  next if posting == main_posting
36
38
 
37
- { 'Umsatz (ohne Soll/Haben-Kz)' => posting.amount,
39
+ {
40
+ 'Umsatz (ohne Soll/Haben-Kz)' => posting.amount,
38
41
  'Soll/Haben-Kennzeichen' => 'S',
39
42
  'Konto' => posting.debit? ? posting.keepr_account.number : main_posting.keepr_account.number,
40
43
  'Gegenkonto (ohne BU-Schlüssel)' => posting.credit? ? posting.keepr_account.number : main_posting.keepr_account.number,
41
44
  'BU-Schlüssel' => '40', # Steuerautomatik deaktivieren
42
45
  'Belegdatum' => journal.date,
43
46
  'Belegfeld 1' => journal.number,
44
- 'Buchungstext' => journal.subject.slice(0,60),
47
+ 'Buchungstext' => journal.subject.slice(0, 60),
45
48
  'Festschreibung' => journal.permanent
46
49
  }.merge(@block ? @block.call(posting) : {})
47
50
  end.compact
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::Posting < ActiveRecord::Base
2
4
  self.table_name = 'keepr_postings'
3
5
 
@@ -17,19 +19,20 @@ class Keepr::Posting < ActiveRecord::Base
17
19
 
18
20
  def side
19
21
  @side || begin
20
- (raw_amount < 0 ? SIDE_CREDIT : SIDE_DEBIT) if raw_amount
22
+ (raw_amount.negative? ? SIDE_CREDIT : SIDE_DEBIT) if raw_amount
21
23
  end
22
24
  end
23
25
 
24
26
  def side=(value)
25
- raise ArgumentError unless [ SIDE_DEBIT, SIDE_CREDIT ].include?(value)
27
+ raise ArgumentError unless [SIDE_DEBIT, SIDE_CREDIT].include?(value)
28
+
26
29
  @side = value
27
30
  return unless amount
28
31
 
29
32
  if credit?
30
- self.raw_amount = -amount
33
+ self.raw_amount = -amount.to_d
31
34
  elsif debit?
32
- self.raw_amount = amount
35
+ self.raw_amount = amount.to_d
33
36
  end
34
37
  end
35
38
 
@@ -54,23 +57,25 @@ class Keepr::Posting < ActiveRecord::Base
54
57
  end
55
58
 
56
59
  def amount=(value)
57
- raise ArgumentError.new('Negative amount not allowed!') if value.to_f < 0
58
60
  @side ||= SIDE_DEBIT
59
61
 
60
- if credit?
61
- self.raw_amount = -value
62
- else
63
- self.raw_amount = value
62
+ unless value
63
+ self.raw_amount = nil
64
+ return
64
65
  end
66
+
67
+ raise ArgumentError, 'Negative amount not allowed!' if value.to_d.negative?
68
+
69
+ self.raw_amount = credit? ? -value.to_d : value.to_d
65
70
  end
66
71
 
67
- private
72
+ private
73
+
68
74
  def cost_center_validation
69
- if keepr_cost_center
70
- unless keepr_account.profit_and_loss?
71
- # allowed for expense or revenue accounts only
72
- errors.add :keepr_cost_center_id, :allowed_for_expense_or_revenue_only
73
- end
74
- end
75
+ return unless keepr_cost_center
76
+ return if keepr_account.profit_and_loss?
77
+
78
+ # allowed for expense or revenue accounts only
79
+ errors.add :keepr_cost_center_id, :allowed_for_expense_or_revenue_only
75
80
  end
76
81
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Keepr::Tax < ActiveRecord::Base
2
4
  self.table_name = 'keepr_taxes'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Keepr
2
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
3
5
  end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryBot.define do
2
4
  factory :account, class: Keepr::Account do
3
- number 12345
4
- kind :asset
5
- name 'Foo'
5
+ number { 12_345 }
6
+ kind { :asset }
7
+ name { 'Foo' }
6
8
  end
7
9
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryBot.define do
2
4
  factory :cost_center, class: Keepr::CostCenter do
3
- number 'FZ1'
4
- name 'Kleintransporter'
5
+ number { 'FZ1' }
6
+ name { 'Kleintransporter' }
5
7
  end
6
8
  end
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryBot.define do
2
4
  factory :group, class: Keepr::Group do
3
- target :asset
4
- name 'Foo'
5
+ target { :asset }
6
+ name { 'Foo' }
5
7
  end
6
8
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  FactoryBot.define do
2
4
  factory :tax, class: Keepr::Tax do
3
- name 'USt19'
4
- description 'Umsatzsteuer 19%'
5
- value 19.0
5
+ name { 'USt19' }
6
+ description { 'Umsatzsteuer 19%' }
7
+ value { 19.0 }
6
8
  keepr_account { FactoryBot.create :account, number: 1776 }
7
9
  end
8
10
  end
@@ -1,26 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Keepr::AccountExport do
4
- let!(:account_1000) { FactoryBot.create :account, kind: :asset, number: 1000, name: 'Kasse' }
5
- let!(:account_1776) { FactoryBot.create :account, kind: :liability, number: 1776, name: 'Umsatzsteuer 19 %' }
6
- let!(:account_4920) { FactoryBot.create :account, kind: :expense, number: 4920, name: 'Telefon' }
7
- let!(:account_8400) { FactoryBot.create :account, kind: :revenue, number: 8400, name: 'Erlöse 19 %' }
8
- let!(:account_9000) { FactoryBot.create :account, kind: :forward, number: 9000, name: 'Saldenvorträge Sachkonten' }
9
- let!(:account_10000) { FactoryBot.create :account, kind: :creditor, number: 10000, name: 'Diverse Kreditoren' }
10
- let!(:account_70000) { FactoryBot.create :account, kind: :debtor, number: 70000, name: 'Diverse Debitoren' }
6
+ let!(:account_1000) { FactoryBot.create :account, kind: :asset, number: 1000, name: 'Kasse' }
7
+ let!(:account_1776) { FactoryBot.create :account, kind: :liability, number: 1776, name: 'Umsatzsteuer 19 %' }
8
+ let!(:account_4920) { FactoryBot.create :account, kind: :expense, number: 4920, name: 'Telefon' }
9
+ let!(:account_8400) { FactoryBot.create :account, kind: :revenue, number: 8400, name: 'Erlöse 19 %' }
10
+ let!(:account_9000) { FactoryBot.create :account, kind: :forward, number: 9000, name: 'Saldenvorträge Sachkonten' }
11
+ let!(:account_10000) { FactoryBot.create :account, kind: :creditor, number: 10_000, name: 'Diverse Kreditoren' }
12
+ let!(:account_70000) { FactoryBot.create :account, kind: :debtor, number: 70_000, name: 'Diverse Debitoren' }
11
13
 
12
14
  let(:scope) { Keepr::Account.all }
13
15
 
14
- let(:export) {
15
- Keepr::AccountExport.new(scope,
16
- 'Berater' => 1234567,
17
- 'Mandant' => 78901,
18
- 'WJ-Beginn' => Date.new(2016,1,1),
16
+ let(:export) do
17
+ Keepr::AccountExport.new(
18
+ scope,
19
+ 'Berater' => 1_234_567,
20
+ 'Mandant' => 78_901,
21
+ 'WJ-Beginn' => Date.new(2016, 1, 1),
19
22
  'Bezeichnung' => 'Keepr-Konten'
20
- ) do |account|
23
+ ) do
21
24
  { 'Sprach-ID' => 'de-DE' }
22
25
  end
23
- }
26
+ end
24
27
 
25
28
  describe :to_s do
26
29
  subject { export.to_s }
@@ -29,17 +32,17 @@ describe Keepr::AccountExport do
29
32
  subject.lines[2..-1].map { |line| line.encode(Encoding::UTF_8) }
30
33
  end
31
34
 
32
- it "should return CSV lines" do
35
+ it 'should return CSV lines' do
33
36
  subject.lines.each { |line| expect(line).to include(';') }
34
37
  end
35
38
 
36
- it "should include header data" do
39
+ it 'should include header data' do
37
40
  expect(subject.lines[0]).to include('1234567;')
38
41
  expect(subject.lines[0]).to include('78901;')
39
42
  expect(subject.lines[0]).to include('"Keepr-Konten";')
40
43
  end
41
44
 
42
- it "should include all accounts except debtor/creditor" do
45
+ it 'should include all accounts except debtor/creditor' do
43
46
  expect(account_lines.count).to eq(5)
44
47
 
45
48
  expect(account_lines[0]).to include('1000;')
@@ -58,14 +61,14 @@ describe Keepr::AccountExport do
58
61
  expect(account_lines[4]).to include('"Saldenvorträge Sachkonten";')
59
62
  end
60
63
 
61
- it "should include data from block" do
64
+ it 'should include data from block' do
62
65
  expect(account_lines[0]).to include(';"de-DE"')
63
66
  expect(account_lines[1]).to include(';"de-DE"')
64
67
  end
65
68
  end
66
69
 
67
70
  describe :to_file do
68
- it "should create CSV file" do
71
+ it 'should create CSV file' do
69
72
  Dir.mktmpdir do |dir|
70
73
  filename = "#{dir}/EXTF_Kontenbeschriftungen.csv"
71
74
  export.to_file(filename)