keepr 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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)