acts_as_account 3.2.2 → 3.3.0

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
  SHA256:
3
- metadata.gz: de4d90bc7ede8a221ad6b6c75a2e2f011b3e5d386928a691b474062e176d8e4d
4
- data.tar.gz: a398469051b8d3f8999736de15df861c523960d00bf0173596d26660259d7cda
3
+ metadata.gz: c148f57665d7973143472d6c9bf4d68098a136680e5f5f059d9432d5df3b74a0
4
+ data.tar.gz: f26b227813ab4a345d6d32944970e0b1817f636109bcaed4983e8f5554e788ab
5
5
  SHA512:
6
- metadata.gz: 15501c287164b0968fe841e9bb06c1534366a295287428c039ac9539d8e8a9b1a5a7321654d801a53f6b1d2420bf9a6d56d2dc559cebbcc64387fad6442a7183
7
- data.tar.gz: 89c0ad8c2ba52c551fa6069bff11e2192e00f572a7d477f20b4b02028f4eb64146fc2dd08fc51e52150f6e6e305e2615446506ae0e9bd385e33d30a1d5ec6166
6
+ metadata.gz: c579701e9a1bc66524633e003a19b091fa80ca329906c70dc9c38f6e05d4f0e11bb148c7189135de0c9fe3336affdc99d68fc9b5847869939ffb58d5e2a2344b
7
+ data.tar.gz: ca9b0f706088c6bebb3cccfb6703645aa25edb0ec47b48be8196fbd2763dc231e7db3ae5dfc5ebb0dd03ff56db22a1dbabd8be92c6dfab49944577035ac6a47e
@@ -0,0 +1,29 @@
1
+ # based on https://github.com/rails/rails/blob/4a78dcb/.github/workflows/rubocop.yml
2
+
3
+ name: rubocop linting
4
+
5
+ on: [push, pull_request]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - name: Set up Ruby
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: 3.3
17
+ - name: Cache gems
18
+ uses: actions/cache@v1
19
+ with:
20
+ path: vendor/bundle
21
+ key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }}
22
+ restore-keys: |
23
+ ${{ runner.os }}-rubocop-
24
+ - name: Install gems
25
+ run: |
26
+ bundle config path vendor/bundle
27
+ bundle install --jobs 4 --retry 3
28
+ - name: Run rubocop
29
+ run: bundle exec rubocop --lint
@@ -0,0 +1,22 @@
1
+ name: tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+
9
+ strategy:
10
+ matrix:
11
+ ruby: [ '3.3', 'ruby-head' ]
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Set up Ruby ${{ matrix.ruby }}
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby }}
19
+ - name: Install dependencies
20
+ run: bundle install --jobs 4
21
+ - name: Test with Rake
22
+ run: bundle exec rake
data/.rubocop.yml ADDED
@@ -0,0 +1,61 @@
1
+ # usage: `rubocop --lint`
2
+
3
+ AllCops:
4
+ NewCops: enable
5
+
6
+ # disable some linters that are not so likely to indicate bugs
7
+
8
+ Lint/AmbiguousAssignment:
9
+ Enabled: false
10
+ Lint/AmbiguousBlockAssociation:
11
+ Enabled: false
12
+ Lint/AmbiguousOperator:
13
+ Enabled: false
14
+ Lint/AmbiguousRegexpLiteral:
15
+ Enabled: false
16
+ Lint/AssignmentInCondition:
17
+ Enabled: false
18
+ Lint/ConstantDefinitionInBlock:
19
+ Enabled: false
20
+ Lint/ConstantResolution:
21
+ Enabled: false
22
+ Lint/DuplicateBranch:
23
+ Enabled: false
24
+ Lint/EmptyBlock:
25
+ Enabled: false
26
+ Lint/EmptyClass:
27
+ Enabled: false
28
+ Lint/EmptyConditionalBody:
29
+ Enabled: false
30
+ Lint/EmptyExpression:
31
+ Enabled: false
32
+ Lint/EmptyFile:
33
+ Enabled: false
34
+ Lint/EmptyWhen:
35
+ Enabled: false
36
+ Lint/EnsureReturn:
37
+ Enabled: false
38
+ Lint/Loop:
39
+ Enabled: false
40
+ Lint/MissingSuper:
41
+ Enabled: false
42
+ Lint/MixedRegexpCaptureTypes:
43
+ Enabled: false
44
+ Lint/NumberConversion:
45
+ Enabled: false
46
+ Lint/ParenthesesAsGroupedExpression:
47
+ Enabled: false
48
+ Lint/RedundantStringCoercion:
49
+ Enabled: false
50
+ Lint/ShadowedArgument:
51
+ Enabled: false
52
+ Lint/ShadowedException:
53
+ Enabled: false
54
+ Lint/ShadowingOuterLocalVariable:
55
+ Enabled: false
56
+ Lint/SuppressedException:
57
+ Enabled: false
58
+ Lint/UnusedBlockArgument:
59
+ Enabled: false
60
+ Lint/UnusedMethodArgument:
61
+ Enabled: false
data/README.md ADDED
@@ -0,0 +1,55 @@
1
+ # acts_as_account
2
+
3
+ [![Build Status](https://github.com/betterplace/acts_as_account/workflows/tests/badge.svg)](https://github.com/jaynetics/js_regex/actions)
4
+
5
+ ## Theory
6
+
7
+ *ActsAsAccount* implements a "Double Entry Accounting" system for your
8
+ Rails-models.
9
+
10
+ It hooks into ActiveRecord and allows to add accounts to any model by
11
+ simply means of adding `has_account` to your model. Because the accounts
12
+ are connected via a `has_many` relation no migration to the account-holder
13
+ tables is needed.
14
+
15
+ We also hook into the ActionController request cycle to warn the developer
16
+ if a request has left uncommitted changes in the system.
17
+
18
+ ## Configuration
19
+
20
+ It is possible to configure if attributes (postings_count, balance, last_valuta) are persisted on the Account or if it is calculated on demand.
21
+ ```
22
+ ActsAsAccount.configure do |config|
23
+ # Default values:
24
+ # config.persist_attributes_on_account = true
25
+ end
26
+ ```
27
+ Enabling persistence means that the sending and receiving account will aquire a lock when making a transfer to ensure correct data. This can be problematic in a high load scenario where many transfers to the same accounts are processed in parallel.
28
+
29
+
30
+ ## How to test
31
+
32
+ Run the cucumber features from the acs_as_account gem, just execute
33
+ * `rake features:create_database`
34
+ * `cucumber`
35
+
36
+ ## How to release
37
+
38
+ You need to update the data in `VERSION` and Rakefile and run `rake` (because it uses GemHadar).
39
+ `rake gem:push` will push the version to rubygems.
40
+
41
+ ## Links
42
+
43
+ * Double Entry Accounting in a Relational Database: [http://homepages.tcp.co.uk/~m-wigley/gc_wp_ded.html (archived)](https://web.archive.org/web/20080310200243/http://homepages.tcp.co.uk/~m-wigley/gc_wp_ded.html)
44
+
45
+ ## Compatibility
46
+
47
+ Rails 4 is supported since version 3.1.0, Rails 7 since 3.2.2 .
48
+
49
+ ## Credits
50
+
51
+ This gem was written for the payment backend of betterplace.org by [Thies C. Arntzen, "thieso2"](https://github.com/thieso2), [Norman Timmler, "unnu"](https://github.com/unnu) and others.
52
+
53
+ ## Copyright
54
+
55
+ Copyright (c) 2010, 2022 [gut.org gAG](https://gut.org), released under the [Apache License v2.0](LICENSE).
data/Rakefile CHANGED
@@ -6,43 +6,38 @@ GemHadar do
6
6
  name 'acts_as_account'
7
7
  author [ "Thies C. Arntzen, Norman Timmler, Matthias Frick, Phillip Oertel" ]
8
8
  email 'developers@betterplace.org'
9
- homepage "http://github.com/betterplace/acts_as_account"
9
+ homepage "https://github.com/betterplace/acts_as_account"
10
10
  summary 'acts_as_account implements double entry accounting for Rails models'
11
11
  description 'acts_as_account implements double entry accounting for Rails models. Your models get accounts and you can do consistent transactions between them. Since the documentation is sparse, see the transfer.feature for usage examples.'
12
12
  test_dir 'tests'
13
13
  ignore '.*.sw[pon]', 'pkg', 'Gemfile.lock', 'coverage', '.rvmrc',
14
14
  '.AppleDouble', 'tags', '.byebug_history', '.DS_Store'
15
- readme 'README.rdoc'
15
+ readme 'README.md'
16
16
  title "#{name.camelize} -- More Math in Ruby"
17
17
  licenses << 'Apache-2.0'
18
18
 
19
- dependency 'activerecord', '>= 4.1', '<7'
20
- dependency 'actionpack' , '>= 4.1', '<7'
21
- development_dependency 'cucumber', '~> 1.3'
22
- development_dependency 'mysql2'
23
- development_dependency 'rspec', '~> 3.1'
19
+ dependency 'activerecord', '>= 5.1', '<8'
20
+ dependency 'actionpack' , '>= 4.1', '<8'
21
+ development_dependency 'cucumber'
22
+ development_dependency 'sqlite3'
23
+ development_dependency 'rspec'
24
24
  development_dependency 'simplecov'
25
- development_dependency 'complex_config'
26
- development_dependency 'database_cleaner', '~> 1.3'
25
+ development_dependency 'database_cleaner'
26
+ development_dependency 'rubocop'
27
27
  end
28
28
 
29
29
  def connect_database
30
30
  require 'active_record'
31
- require 'complex_config'
32
- config = ComplexConfig::Provider.config 'features/db/database.yml'
33
- connection_config = config.acts_as_account.to_h
34
- connection_config.delete(:database)
35
- ActiveRecord::Base.establish_connection(connection_config).connection
31
+ require 'yaml'
32
+ db_config = YAML.load_file('features/db/database.yml')
33
+ ActiveRecord::Base.establish_connection(db_config).lease_connection
36
34
  end
37
35
 
38
36
  namespace :features do
39
37
  desc "create test database out of db/schema.rb"
40
38
  task :create_database do
41
- conn = connect_database
42
- conn.execute('DROP DATABASE IF EXISTS acts_as_account')
43
- conn.execute('CREATE DATABASE acts_as_account')
44
- conn.execute('USE acts_as_account')
45
- load(File.dirname(__FILE__) + '/features/db/schema.rb')
39
+ connect_database
40
+ load("#{__dir__}/features/db/schema.rb")
46
41
  end
47
42
  end
48
43
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.2
1
+ 3.3.0
@@ -1,47 +1,33 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: acts_as_account 3.2.2 ruby lib
2
+ # stub: acts_as_account 3.3.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "acts_as_account".freeze
6
- s.version = "3.2.2"
6
+ s.version = "3.3.0".freeze
7
7
 
8
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
9
9
  s.require_paths = ["lib".freeze]
10
10
  s.authors = ["Thies C. Arntzen, Norman Timmler, Matthias Frick, Phillip Oertel".freeze]
11
- s.date = "2021-02-22"
11
+ s.date = "2024-10-23"
12
12
  s.description = "acts_as_account implements double entry accounting for Rails models. Your models get accounts and you can do consistent transactions between them. Since the documentation is sparse, see the transfer.feature for usage examples.".freeze
13
13
  s.email = "developers@betterplace.org".freeze
14
- s.extra_rdoc_files = ["README.rdoc".freeze, "lib/acts_as_account.rb".freeze, "lib/acts_as_account/account.rb".freeze, "lib/acts_as_account/active_record_extensions.rb".freeze, "lib/acts_as_account/global_account.rb".freeze, "lib/acts_as_account/journal.rb".freeze, "lib/acts_as_account/manually_created_account.rb".freeze, "lib/acts_as_account/posting.rb".freeze, "lib/acts_as_account/rails.rb".freeze, "lib/acts_as_account/transfer.rb".freeze, "lib/acts_as_account/version.rb".freeze]
15
- s.files = [".gitignore".freeze, ".travis.yml".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.rdoc".freeze, "Rakefile".freeze, "VERSION".freeze, "acts_as_account.gemspec".freeze, "cucumber.yml".freeze, "features/account/account_creation.feature".freeze, "features/db/database.yml".freeze, "features/db/schema.rb".freeze, "features/step_definitions/account_steps.rb".freeze, "features/support/abstract_user.rb".freeze, "features/support/cheque.rb".freeze, "features/support/env.rb".freeze, "features/support/inheriting_user.rb".freeze, "features/support/user.rb".freeze, "features/transfer/journal_creation.feature".freeze, "features/transfer/transfer.feature".freeze, "init.rb".freeze, "lib/acts_as_account.rb".freeze, "lib/acts_as_account/account.rb".freeze, "lib/acts_as_account/active_record_extensions.rb".freeze, "lib/acts_as_account/global_account.rb".freeze, "lib/acts_as_account/journal.rb".freeze, "lib/acts_as_account/manually_created_account.rb".freeze, "lib/acts_as_account/posting.rb".freeze, "lib/acts_as_account/rails.rb".freeze, "lib/acts_as_account/transfer.rb".freeze, "lib/acts_as_account/version.rb".freeze]
16
- s.homepage = "http://github.com/betterplace/acts_as_account".freeze
14
+ s.extra_rdoc_files = ["README.md".freeze, "lib/acts_as_account.rb".freeze, "lib/acts_as_account/account.rb".freeze, "lib/acts_as_account/active_record_extensions.rb".freeze, "lib/acts_as_account/configuration.rb".freeze, "lib/acts_as_account/global_account.rb".freeze, "lib/acts_as_account/journal.rb".freeze, "lib/acts_as_account/manually_created_account.rb".freeze, "lib/acts_as_account/posting.rb".freeze, "lib/acts_as_account/rails.rb".freeze, "lib/acts_as_account/transfer.rb".freeze, "lib/acts_as_account/version.rb".freeze]
15
+ s.files = [".github/workflows/lint.yml".freeze, ".github/workflows/tests.yml".freeze, ".gitignore".freeze, ".rubocop.yml".freeze, "CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE".freeze, "README.md".freeze, "Rakefile".freeze, "VERSION".freeze, "acts_as_account.gemspec".freeze, "acts_as_account.sqlite".freeze, "cucumber.yml".freeze, "features/account/account_creation.feature".freeze, "features/db/database.yml".freeze, "features/db/schema.rb".freeze, "features/step_definitions/account_steps.rb".freeze, "features/support/abstract_user.rb".freeze, "features/support/cheque.rb".freeze, "features/support/env.rb".freeze, "features/support/inheriting_user.rb".freeze, "features/support/user.rb".freeze, "features/transfer/journal_creation.feature".freeze, "features/transfer/transfer.feature".freeze, "init.rb".freeze, "lib/acts_as_account.rb".freeze, "lib/acts_as_account/account.rb".freeze, "lib/acts_as_account/active_record_extensions.rb".freeze, "lib/acts_as_account/configuration.rb".freeze, "lib/acts_as_account/global_account.rb".freeze, "lib/acts_as_account/journal.rb".freeze, "lib/acts_as_account/manually_created_account.rb".freeze, "lib/acts_as_account/posting.rb".freeze, "lib/acts_as_account/rails.rb".freeze, "lib/acts_as_account/transfer.rb".freeze, "lib/acts_as_account/version.rb".freeze]
16
+ s.homepage = "https://github.com/betterplace/acts_as_account".freeze
17
17
  s.licenses = ["Apache-2.0".freeze]
18
- s.rdoc_options = ["--title".freeze, "ActsAsAccount -- More Math in Ruby".freeze, "--main".freeze, "README.rdoc".freeze]
19
- s.rubygems_version = "3.2.8".freeze
18
+ s.rdoc_options = ["--title".freeze, "ActsAsAccount -- More Math in Ruby".freeze, "--main".freeze, "README.md".freeze]
19
+ s.rubygems_version = "3.5.18".freeze
20
20
  s.summary = "acts_as_account implements double entry accounting for Rails models".freeze
21
21
 
22
- if s.respond_to? :specification_version then
23
- s.specification_version = 4
24
- end
22
+ s.specification_version = 4
25
23
 
26
- if s.respond_to? :add_runtime_dependency then
27
- s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
28
- s.add_development_dependency(%q<cucumber>.freeze, ["~> 1.3"])
29
- s.add_development_dependency(%q<mysql2>.freeze, [">= 0"])
30
- s.add_development_dependency(%q<rspec>.freeze, ["~> 3.1"])
31
- s.add_development_dependency(%q<simplecov>.freeze, [">= 0"])
32
- s.add_development_dependency(%q<complex_config>.freeze, [">= 0"])
33
- s.add_development_dependency(%q<database_cleaner>.freeze, ["~> 1.3"])
34
- s.add_runtime_dependency(%q<activerecord>.freeze, [">= 4.1", "< 7"])
35
- s.add_runtime_dependency(%q<actionpack>.freeze, [">= 4.1", "< 7"])
36
- else
37
- s.add_dependency(%q<gem_hadar>.freeze, ["~> 1.11.0"])
38
- s.add_dependency(%q<cucumber>.freeze, ["~> 1.3"])
39
- s.add_dependency(%q<mysql2>.freeze, [">= 0"])
40
- s.add_dependency(%q<rspec>.freeze, ["~> 3.1"])
41
- s.add_dependency(%q<simplecov>.freeze, [">= 0"])
42
- s.add_dependency(%q<complex_config>.freeze, [">= 0"])
43
- s.add_dependency(%q<database_cleaner>.freeze, ["~> 1.3"])
44
- s.add_dependency(%q<activerecord>.freeze, [">= 4.1", "< 7"])
45
- s.add_dependency(%q<actionpack>.freeze, [">= 4.1", "< 7"])
46
- end
24
+ s.add_development_dependency(%q<gem_hadar>.freeze, ["~> 1.19".freeze])
25
+ s.add_development_dependency(%q<cucumber>.freeze, [">= 0".freeze])
26
+ s.add_development_dependency(%q<sqlite3>.freeze, [">= 0".freeze])
27
+ s.add_development_dependency(%q<rspec>.freeze, [">= 0".freeze])
28
+ s.add_development_dependency(%q<simplecov>.freeze, [">= 0".freeze])
29
+ s.add_development_dependency(%q<database_cleaner>.freeze, [">= 0".freeze])
30
+ s.add_development_dependency(%q<rubocop>.freeze, [">= 0".freeze])
31
+ s.add_runtime_dependency(%q<activerecord>.freeze, [">= 5.1".freeze, "< 8".freeze])
32
+ s.add_runtime_dependency(%q<actionpack>.freeze, [">= 4.1".freeze, "< 8".freeze])
47
33
  end
Binary file
@@ -1,6 +1,5 @@
1
- acts_as_account:
2
- adapter: mysql2
3
- encoding: utf8
4
- database: acts_as_account
5
- username: root
6
- host: localhost
1
+ adapter: sqlite3
2
+ encoding: utf8
3
+ database: acts_as_account.sqlite
4
+ username: root
5
+ host: localhost
@@ -41,10 +41,6 @@ ActiveRecord::Schema.define(version: 1) do
41
41
  add_index "acts_as_account_postings", ["reference_type", "reference_id"], name: "reference"
42
42
  add_index "acts_as_account_postings", ["valuta", "id"], name: "sort_key"
43
43
 
44
- execute "ALTER TABLE acts_as_account_postings ADD CONSTRAINT account_id FOREIGN KEY (account_id) REFERENCES acts_as_account_accounts (id)"
45
- execute "ALTER TABLE acts_as_account_postings ADD CONSTRAINT other_account_id FOREIGN KEY (other_account_id) REFERENCES acts_as_account_accounts (id)"
46
- execute "ALTER TABLE acts_as_account_postings ADD CONSTRAINT journal_id FOREIGN KEY (journal_id) REFERENCES acts_as_account_journals (id)"
47
-
48
44
  create_table "acts_as_account_global_accounts", force: true do |t|
49
45
  t.string "name", null: false
50
46
  end
@@ -15,6 +15,10 @@ Given /^I create a user (\w+)$/ do |name|
15
15
  User.create!(:name => name)
16
16
  end
17
17
 
18
+ Given /^I configure attribute persistence to be (\w+)$/ do |flag|
19
+ ActsAsAccount.configuration.persist_attributes_on_account = flag == 'true'
20
+ end
21
+
18
22
  Given /^I have a user (\w+) that inherits from an abstract class$/ do |name|
19
23
  InheritingUser.create!(:name => name)
20
24
  end
@@ -67,9 +71,10 @@ Then /^the global (\w+) account balance is (-?\d+) €$/ do |name, balance|
67
71
  end
68
72
 
69
73
  When /^I transfer (-?\d+) € from (\w+)'s account to (\w+)'s account$/ do |amount, from, to|
70
- from_account = User.find_by_name(from).account
71
- to_account = User.find_by_name(to).account
72
- Journal.current.transfer(amount.to_i, from_account, to_account, @reference, @valuta)
74
+ @from_account = User.find_by_name(from).account
75
+ @to_account = User.find_by_name(to).account
76
+ @previous_account_attributes = [@from_account.attributes, @to_account.attributes]
77
+ Journal.current.transfer(amount.to_i, @from_account, @to_account, @reference, @valuta)
73
78
  end
74
79
 
75
80
  When /^I transfer (\d+) € from global (\w+) account to global (\w+) account$/ do |amount, from, to|
@@ -94,7 +99,7 @@ When /^I create a Journal via (.+)$/ do |method|
94
99
  eval <<-EOT
95
100
  @journal = Journal.#{method}
96
101
  EOT
97
- rescue Exception => @last_exception
102
+ rescue => @last_exception
98
103
  end
99
104
  end
100
105
 
@@ -152,7 +157,7 @@ end
152
157
 
153
158
  Then /^the order of the postings is correct$/ do
154
159
  # make sure we always book "Soll an Haben"
155
- Posting.all.in_groups_of(2) do |from, to|
160
+ Posting.all.each_slice(2) do |from, to|
156
161
  from.amount.should be < 0
157
162
  to.amount.should be > 0
158
163
  end
@@ -172,3 +177,12 @@ end
172
177
  When /^I call 'account' on both it should be possible$/ do
173
178
  [@user1, @user2].each { |user| user.account }
174
179
  end
180
+
181
+ Then('there are no changes to the accounts') do
182
+ @previous_account_attributes.should eq [@from_account.reload.attributes, @to_account.reload.attributes]
183
+ end
184
+
185
+ Then('the balance field changed on the accounts') do
186
+ @from_account.reload.read_attribute(:balance).should_not eq @previous_account_attributes.first['balance']
187
+ @to_account.reload.read_attribute(:balance).should_not eq @previous_account_attributes.last['balance']
188
+ end
@@ -6,21 +6,28 @@ if ENV['START_SIMPLECOV'].to_i == 1
6
6
  end
7
7
 
8
8
  require 'acts_as_account'
9
- require 'complex_config'
10
- config =ComplexConfig::Provider.config File.dirname(__FILE__) + '/../db/database.yml'
11
- ActiveRecord::Base.establish_connection(config.acts_as_account.to_h)
9
+ require 'yaml'
10
+ db_config = YAML.load_file(__dir__ + '/../db/database.yml')
11
+ ActiveRecord::Base.establish_connection(db_config)
12
12
 
13
13
  require 'database_cleaner'
14
14
  require 'database_cleaner/cucumber'
15
15
  DatabaseCleaner.strategy = :transaction
16
16
 
17
- Dir[File.dirname(__FILE__) + '/../step_definitions/*.rb'].each { |file| require file }
17
+ Dir["#{__dir__}/../step_definitions/*.rb"].sort.each { |file| require file }
18
18
 
19
- require File.dirname(__FILE__) + '/user'
20
- require File.dirname(__FILE__) + '/abstract_user'
21
- require File.dirname(__FILE__) + '/inheriting_user'
22
- require File.dirname(__FILE__) + '/cheque'
19
+ require_relative 'user'
20
+ require_relative 'abstract_user'
21
+ require_relative 'inheriting_user'
22
+ require_relative 'cheque'
23
23
 
24
24
  After do
25
25
  ActsAsAccount::Journal.clear_current
26
26
  end
27
+
28
+ Before do
29
+ ActsAsAccount.configure do |config|
30
+ # Default values:
31
+ # config.persist_attributes_on_account = true
32
+ end
33
+ end
@@ -3,14 +3,26 @@ Feature: Transfer
3
3
  As a Bank
4
4
  I want not to loose money
5
5
 
6
- Scenario: I transfer money between accounts having holders
6
+ Scenario: I transfer money between accounts having holders with attribute persistence set to true
7
7
  Given I create a user Thies
8
8
  Given I create a user Norman
9
+ Given I configure attribute persistence to be true
9
10
  When I transfer 30 € from Thies's account to Norman's account
10
11
  Then Thies's account balance is -30 €
11
12
  And Norman's account balance is 30 €
12
13
  And the order of the postings is correct
13
-
14
+ And the balance field changed on the accounts
15
+
16
+ Scenario: I transfer money between accounts having holders with attribute persistence set to false
17
+ Given I create a user Thies
18
+ Given I create a user Norman
19
+ Given I configure attribute persistence to be false
20
+ When I transfer 30 € from Thies's account to Norman's account
21
+ Then Thies's account balance is -30 €
22
+ And Norman's account balance is 30 €
23
+ And the order of the postings is correct
24
+ And there are no changes to the accounts
25
+
14
26
  Scenario: I transfer a negative amount between accounts having holders
15
27
  Given I create a user Thies
16
28
  Given I create a user Norman
@@ -41,4 +53,4 @@ Feature: Transfer
41
53
  When I transfer 50 € from Thies's account to Norman's account and specify 22.05.1968 07:45 as the booking time
42
54
  Then Thies's account balance is -50 €
43
55
  And Norman's account balance is 50 €
44
- And all postings have 22.05.1968 07:45 as the booking time
56
+ And all postings have 22.05.1968 07:45 as the booking time
@@ -6,20 +6,16 @@ module ActsAsAccount
6
6
  has_many :postings, :class_name => 'ActsAsAccount::Posting'
7
7
  has_many :journals, :through => :postings
8
8
 
9
- # TODO: discuss with norman:
10
- # validates_presence_of will force an ActiveRecord::find on the object
11
- # but we have to create accounts for deleted holder!
12
- #
13
- # validates_presence_of :holder
14
-
15
9
  class << self
16
10
  def recalculate_all_balances
11
+ warn "[DEPRECATION] `recalculate_all_balances` is deprecated and will be removed in a future version. Please use `recalculate_attributes` instead."
12
+
13
+ recalculate_attributes
14
+ end
15
+
16
+ def recalculate_attributes
17
17
  find_each do |account|
18
- account.update_columns(
19
- balance: account.postings.sum(:amount),
20
- postings_count: account.postings.count,
21
- last_valuta: account.postings.maximum(:valuta)
22
- )
18
+ account.recalculate_attributes
23
19
  end
24
20
  end
25
21
 
@@ -53,7 +49,7 @@ module ActsAsAccount
53
49
  yield
54
50
 
55
51
  # Trying to create a duplicate key on a unique index raises StatementInvalid
56
- rescue ActiveRecord::StatementInvalid => e
52
+ rescue ActiveRecord::StatementInvalid
57
53
  record = if attributes[:holder]
58
54
  attributes[:holder].account(attributes[:name])
59
55
  else
@@ -67,6 +63,40 @@ module ActsAsAccount
67
63
  end
68
64
  end
69
65
 
66
+ def balance
67
+ if ActsAsAccount.configuration.persist_attributes_on_account
68
+ super
69
+ else
70
+ postings.sum(:amount)
71
+ end
72
+ end
73
+
74
+ def postings_count
75
+ if ActsAsAccount.configuration.persist_attributes_on_account
76
+ super
77
+ else
78
+ postings.count
79
+ end
80
+ end
81
+
82
+ def last_valuta
83
+ if ActsAsAccount.configuration.persist_attributes_on_account
84
+ super
85
+ else
86
+ postings.maximum(:valuta)
87
+ end
88
+ end
89
+
90
+ def recalculate_attributes
91
+ return unless ActsAsAccount.configuration.persist_attributes_on_account
92
+
93
+ update_columns(
94
+ last_valuta: postings.maximum(:valuta),
95
+ balance: postings.sum(:amount),
96
+ postings_count: postings.count
97
+ )
98
+ end
99
+
70
100
  def deleteable?
71
101
  postings.empty? && journals.empty?
72
102
  end
@@ -10,7 +10,6 @@ module ActsAsAccount
10
10
  end
11
11
 
12
12
  module ClassMethods
13
-
14
13
  def has_account(name = :default)
15
14
  has_one :"#{name}_account", -> { where name: name }, class_name: "ActsAsAccount::Account", as: :holder
16
15
 
@@ -0,0 +1,10 @@
1
+ module ActsAsAccount
2
+ class Configuration
3
+ attr_accessor :persist_attributes_on_account
4
+
5
+ def initialize
6
+ # default values
7
+ @persist_attributes_on_account = true
8
+ end
9
+ end
10
+ end
@@ -1,7 +1,12 @@
1
1
  module ActsAsAccount
2
+ # A named account that is "global" (not tied to any specific entity
3
+ # in your database otherwise).
4
+ #
5
+ # This is useful for accounts that you don't want to model anything
6
+ # for via an ActiveRecord model (like "Cash").
2
7
  class GlobalAccount < ActiveRecord::Base
3
8
  self.table_name = :acts_as_account_global_accounts
4
9
 
5
10
  has_account
6
11
  end
7
- end
12
+ end
@@ -21,7 +21,7 @@ module ActsAsAccount
21
21
 
22
22
  def transfers
23
23
  [].tap do |transfers|
24
- postings.in_groups_of(2) { |postings| transfers << Transfer.new(*postings) }
24
+ postings.each_slice(2) { |postings| transfers << Transfer.new(*postings) }
25
25
  end
26
26
  end
27
27
 
@@ -36,7 +36,7 @@ module ActsAsAccount
36
36
 
37
37
  # to avoid possible deadlocks we need to ensure that the locking order is always
38
38
  # the same therfore the sort by id.
39
- [from_account, to_account].sort_by(&:id).map(&:lock!)
39
+ [from_account, to_account].sort_by(&:id).map(&:lock!) if ActsAsAccount.configuration.persist_attributes_on_account
40
40
 
41
41
  add_posting(-amount, from_account, to_account, reference, valuta)
42
42
  add_posting( amount, to_account, from_account, reference, valuta)
@@ -53,10 +53,15 @@ module ActsAsAccount
53
53
  :reference => reference,
54
54
  :valuta => valuta)
55
55
 
56
- account.class.update_counters account.id, :postings_count => 1, :balance => posting.amount
56
+ update_attributes_on(account, posting)
57
57
 
58
58
  posting.save(:validate => false)
59
- account.save(:validate => false)
59
+ end
60
+
61
+ def update_attributes_on(account, posting)
62
+ return unless ActsAsAccount.configuration.persist_attributes_on_account
63
+
64
+ account.class.update_counters account.id, postings_count: 1, balance: posting.amount
60
65
  end
61
66
  end
62
67
  end
@@ -12,11 +12,11 @@ module ActsAsAccount
12
12
  scope :soll, -> { where('amount >= 0') }
13
13
  scope :haben, -> { where('amount < 0') }
14
14
  scope :start_date, -> date {
15
- date = Time.parse(date.to_s).utc.to_s(:db)
15
+ date = Time.parse(date.to_s).utc.to_fs(:db)
16
16
  where(['valuta >= ?', date])
17
17
  }
18
18
  scope :end_date, -> date {
19
- date = Time.parse(date.to_s).utc.to_s(:db)
19
+ date = Time.parse(date.to_s).utc.to_fs(:db)
20
20
  where(['valuta <= ?', date])
21
21
  }
22
22
  end
@@ -1,6 +1,6 @@
1
1
  module ActsAsAccount
2
2
  # ActsAsAccount version
3
- VERSION = '3.2.2'
3
+ VERSION = '3.3.0'
4
4
  VERSION_ARRAY = VERSION.split('.').map(&:to_i) # :nodoc:
5
5
  VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
6
6
  VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
@@ -1,7 +1,16 @@
1
1
  require 'active_record'
2
2
  require 'action_controller'
3
+ require 'acts_as_account/configuration'
3
4
 
4
5
  module ActsAsAccount
6
+ class << self
7
+ attr_accessor :configuration
8
+ end
9
+
10
+ def self.configure
11
+ self.configuration ||= Configuration.new
12
+ yield(configuration)
13
+ end
5
14
  end
6
15
 
7
16
  require 'acts_as_account/version'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_account
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.2
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thies C. Arntzen, Norman Timmler, Matthias Frick, Phillip Oertel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-22 00:00:00.000000000 Z
11
+ date: 2024-10-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -16,30 +16,30 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.11.0
19
+ version: '1.19'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.11.0
26
+ version: '1.19'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: cucumber
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.3'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.3'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: mysql2
42
+ name: sqlite3
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '3.1'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '3.1'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: simplecov
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: complex_config
84
+ name: database_cleaner
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -95,39 +95,39 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: database_cleaner
98
+ name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '1.3'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '1.3'
110
+ version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: activerecord
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - ">="
116
116
  - !ruby/object:Gem::Version
117
- version: '4.1'
117
+ version: '5.1'
118
118
  - - "<"
119
119
  - !ruby/object:Gem::Version
120
- version: '7'
120
+ version: '8'
121
121
  type: :runtime
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - ">="
126
126
  - !ruby/object:Gem::Version
127
- version: '4.1'
127
+ version: '5.1'
128
128
  - - "<"
129
129
  - !ruby/object:Gem::Version
130
- version: '7'
130
+ version: '8'
131
131
  - !ruby/object:Gem::Dependency
132
132
  name: actionpack
133
133
  requirement: !ruby/object:Gem::Requirement
@@ -137,7 +137,7 @@ dependencies:
137
137
  version: '4.1'
138
138
  - - "<"
139
139
  - !ruby/object:Gem::Version
140
- version: '7'
140
+ version: '8'
141
141
  type: :runtime
142
142
  prerelease: false
143
143
  version_requirements: !ruby/object:Gem::Requirement
@@ -147,7 +147,7 @@ dependencies:
147
147
  version: '4.1'
148
148
  - - "<"
149
149
  - !ruby/object:Gem::Version
150
- version: '7'
150
+ version: '8'
151
151
  description: acts_as_account implements double entry accounting for Rails models.
152
152
  Your models get accounts and you can do consistent transactions between them. Since
153
153
  the documentation is sparse, see the transfer.feature for usage examples.
@@ -155,10 +155,11 @@ email: developers@betterplace.org
155
155
  executables: []
156
156
  extensions: []
157
157
  extra_rdoc_files:
158
- - README.rdoc
158
+ - README.md
159
159
  - lib/acts_as_account.rb
160
160
  - lib/acts_as_account/account.rb
161
161
  - lib/acts_as_account/active_record_extensions.rb
162
+ - lib/acts_as_account/configuration.rb
162
163
  - lib/acts_as_account/global_account.rb
163
164
  - lib/acts_as_account/journal.rb
164
165
  - lib/acts_as_account/manually_created_account.rb
@@ -167,15 +168,18 @@ extra_rdoc_files:
167
168
  - lib/acts_as_account/transfer.rb
168
169
  - lib/acts_as_account/version.rb
169
170
  files:
171
+ - ".github/workflows/lint.yml"
172
+ - ".github/workflows/tests.yml"
170
173
  - ".gitignore"
171
- - ".travis.yml"
174
+ - ".rubocop.yml"
172
175
  - CHANGELOG.md
173
176
  - Gemfile
174
177
  - LICENSE
175
- - README.rdoc
178
+ - README.md
176
179
  - Rakefile
177
180
  - VERSION
178
181
  - acts_as_account.gemspec
182
+ - acts_as_account.sqlite
179
183
  - cucumber.yml
180
184
  - features/account/account_creation.feature
181
185
  - features/db/database.yml
@@ -192,6 +196,7 @@ files:
192
196
  - lib/acts_as_account.rb
193
197
  - lib/acts_as_account/account.rb
194
198
  - lib/acts_as_account/active_record_extensions.rb
199
+ - lib/acts_as_account/configuration.rb
195
200
  - lib/acts_as_account/global_account.rb
196
201
  - lib/acts_as_account/journal.rb
197
202
  - lib/acts_as_account/manually_created_account.rb
@@ -199,7 +204,7 @@ files:
199
204
  - lib/acts_as_account/rails.rb
200
205
  - lib/acts_as_account/transfer.rb
201
206
  - lib/acts_as_account/version.rb
202
- homepage: http://github.com/betterplace/acts_as_account
207
+ homepage: https://github.com/betterplace/acts_as_account
203
208
  licenses:
204
209
  - Apache-2.0
205
210
  metadata: {}
@@ -208,7 +213,7 @@ rdoc_options:
208
213
  - "--title"
209
214
  - ActsAsAccount -- More Math in Ruby
210
215
  - "--main"
211
- - README.rdoc
216
+ - README.md
212
217
  require_paths:
213
218
  - lib
214
219
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -222,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
227
  - !ruby/object:Gem::Version
223
228
  version: '0'
224
229
  requirements: []
225
- rubygems_version: 3.2.8
230
+ rubygems_version: 3.5.18
226
231
  signing_key:
227
232
  specification_version: 4
228
233
  summary: acts_as_account implements double entry accounting for Rails models
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- rvm:
2
- - 2.3.3
3
- - 2.6.3
4
- sudo: false
5
- script: rake
data/README.rdoc DELETED
@@ -1,42 +0,0 @@
1
- = acts_as_account
2
-
3
- {<img src="https://travis-ci.org/betterplace/acts_as_account.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/betterplace/acts_as_account]
4
-
5
- == Theory
6
-
7
- ActsAsAccount implements a "Double Entry Accounting" system for your
8
- Rails-models.
9
-
10
- It hooks into ActiveRecord and allows to add accounts to any model by
11
- simply means of adding "has_account" to your model. Because the accounts
12
- are connected via a has_many relation no migration to the account-holder
13
- tables is needed.
14
-
15
- We also hook into the ActionController request cycle to warn the developer
16
- if a request has left the uncommitted changes in the system.
17
-
18
- == Support
19
-
20
- Rails 4 is supported since version 3.1.0
21
-
22
- == How to test
23
-
24
- Run the cucumber features from the acs_as_account gem, just execute
25
- * rake features:create_database
26
- * cucumber
27
-
28
- == Links
29
-
30
- * Double Entry Accounting in a Relational Database: http://homepages.tcp.co.uk/~m-wigley/gc_wp_ded.html
31
-
32
- == Compatibility
33
-
34
- With the release of version 2.0.0 acts_as_account is supposed to work for Rails 3. If you still use Rails 2 please use version 1.2.0.
35
-
36
- == Credits
37
-
38
- This gem was written for the payment backend of betterplace.org by Thies C. Arntzen (http://github.com/thieso2) and Norman Timmler (github.com/unnu).
39
-
40
- == Copyright
41
-
42
- Copyright (c) 2010 gut.org gAG