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.
- checksums.yaml +4 -4
- data/.rubocop.yml +44 -0
- data/.travis.yml +9 -9
- data/Gemfile +2 -0
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/Rakefile +2 -0
- data/ci/Gemfile-rails-4-2 +3 -2
- data/ci/Gemfile-rails-5-0 +3 -2
- data/ci/Gemfile-rails-5-1 +3 -2
- data/ci/Gemfile-rails-5-2 +3 -2
- data/ci/{Gemfile-rails-4-1 → Gemfile-rails-6-0} +3 -2
- data/keepr.gemspec +14 -12
- data/lib/generators/keepr/migration/migration_generator.rb +5 -3
- data/lib/generators/keepr/migration/templates/migration.rb +2 -0
- data/lib/keepr.rb +6 -4
- data/lib/keepr/account.rb +37 -37
- data/lib/keepr/account_export.rb +10 -14
- data/lib/keepr/active_record_extension.rb +4 -2
- data/lib/keepr/contact_export.rb +6 -7
- data/lib/keepr/cost_center.rb +2 -0
- data/lib/keepr/group.rb +21 -20
- data/lib/keepr/groups_creator.rb +7 -7
- data/lib/keepr/journal.rb +14 -11
- data/lib/keepr/journal_export.rb +9 -6
- data/lib/keepr/posting.rb +21 -16
- data/lib/keepr/tax.rb +2 -0
- data/lib/keepr/version.rb +3 -1
- data/spec/factories/account.rb +5 -3
- data/spec/factories/cost_center.rb +4 -2
- data/spec/factories/group.rb +4 -2
- data/spec/factories/tax.rb +5 -3
- data/spec/keepr/account_export_spec.rb +22 -19
- data/spec/keepr/account_spec.rb +47 -42
- data/spec/keepr/active_record_extension_spec.rb +20 -18
- data/spec/keepr/contact_export_spec.rb +17 -14
- data/spec/keepr/cost_center_spec.rb +2 -0
- data/spec/keepr/group_spec.rb +39 -35
- data/spec/keepr/groups_creator_spec.rb +7 -4
- data/spec/keepr/journal_export_spec.rb +26 -25
- data/spec/keepr/journal_spec.rb +33 -31
- data/spec/keepr/posting_spec.rb +8 -6
- data/spec/keepr/tax_spec.rb +21 -14
- data/spec/spec_helper.rb +6 -5
- data/spec/support/contact.rb +2 -0
- data/spec/support/document.rb +2 -0
- data/spec/support/ledger.rb +2 -0
- data/spec/support/spec_migration.rb +2 -0
- 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 <<-
|
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
|
-
|
32
|
+
CODE
|
31
33
|
end
|
32
34
|
|
33
35
|
def has_keepr_postings
|
data/lib/keepr/contact_export.rb
CHANGED
@@ -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
|
data/lib/keepr/cost_center.rb
CHANGED
data/lib/keepr/group.rb
CHANGED
@@ -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: [
|
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 :
|
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
|
-
|
26
|
-
|
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(
|
31
|
+
Keepr::Posting
|
32
|
+
.joins(keepr_account: :keepr_group)
|
33
|
+
.merge(subtree)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
35
|
-
private
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
data/lib/keepr/groups_creator.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
class Keepr::GroupsCreator
|
3
4
|
def initialize(target)
|
4
|
-
raise ArgumentError unless [
|
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
|
38
|
+
if depth.zero?
|
39
39
|
parents = []
|
40
40
|
group = Keepr::Group.create!(attributes)
|
41
41
|
else
|
data/lib/keepr/journal.rb
CHANGED
@@ -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},
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
data/lib/keepr/journal_export.rb
CHANGED
@@ -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.
|
34
|
+
main_posting ||= journal.keepr_postings.max_by(&:amount)
|
33
35
|
|
34
|
-
journal.keepr_postings.sort_by { |p| [
|
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
|
-
{
|
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
|
data/lib/keepr/posting.rb
CHANGED
@@ -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
|
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 [
|
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
|
-
|
61
|
-
self.raw_amount =
|
62
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
data/lib/keepr/tax.rb
CHANGED
data/lib/keepr/version.rb
CHANGED
data/spec/factories/account.rb
CHANGED
data/spec/factories/group.rb
CHANGED
data/spec/factories/tax.rb
CHANGED
@@ -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:
|
5
|
-
let!(:account_1776) { FactoryBot.create :account, kind: :liability, number:
|
6
|
-
let!(:account_4920) { FactoryBot.create :account, kind: :expense, number:
|
7
|
-
let!(:account_8400) { FactoryBot.create :account, kind: :revenue, number:
|
8
|
-
let!(:account_9000) { FactoryBot.create :account, kind: :forward, number:
|
9
|
-
let!(:account_10000) { FactoryBot.create :account, kind: :creditor, number:
|
10
|
-
let!(:account_70000) { FactoryBot.create :account, kind: :debtor, number:
|
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(
|
16
|
-
|
17
|
-
'
|
18
|
-
'
|
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
|
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
|
35
|
+
it 'should return CSV lines' do
|
33
36
|
subject.lines.each { |line| expect(line).to include(';') }
|
34
37
|
end
|
35
38
|
|
36
|
-
it
|
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
|
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
|
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
|
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)
|