acts_as_account 3.2.3 → 3.4.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: 6c6d94c77b41055a293cb92db325121dd8e40a9de54004ba017fd20bc301b243
4
- data.tar.gz: '0582774b247afe230b9036f47fcea99d346f56993174fa9d4eac36e4ec817893'
3
+ metadata.gz: 82e0a5a2dcd250ad8d0aa7231550b853a20afa4a74f93676099cdcf756826516
4
+ data.tar.gz: 0fdacf00679d364e12680d1862fad056fc7c8334c1c4b0078dce9a6d23219b19
5
5
  SHA512:
6
- metadata.gz: a41ef812cff3dfeca6b723ae5367baa3af018687e3316b03b6a39ad76bcd1d1dbf3a92e0f9efdf863c4f41930c41e518dbf0c4909357b780829673da72c330d7
7
- data.tar.gz: f9ad1dc779fa5fd623491d9267465a486ee6bc03ece7839f0dd9c6a88d5b05574249278a3e2fe8776c01180c441451194d7e3b6b33070d24473a6a10c077ca3d
6
+ metadata.gz: 58987a63a27f2d97fe7e1d961431981e79846c213806c3364dd5ea0e42944d334b7b41d47188e361157736f341308174dd6b5f41a29ffc9e59fc63262cad8daa
7
+ data.tar.gz: d16e37c26e92810328ee1e60fa16135f4a6740b51e931d10bba3bdb6b56e6fed30b8610191c439570c0473bae2b441844c731b71d935993d18c25d2612c75f06
@@ -13,7 +13,7 @@ jobs:
13
13
  - name: Set up Ruby
14
14
  uses: ruby/setup-ruby@v1
15
15
  with:
16
- ruby-version: 2.7
16
+ ruby-version: 3.3
17
17
  - name: Cache gems
18
18
  uses: actions/cache@v1
19
19
  with:
@@ -8,7 +8,7 @@ jobs:
8
8
 
9
9
  strategy:
10
10
  matrix:
11
- ruby: [ '2.7', 'ruby-head' ]
11
+ ruby: [ '3.2', '3.3' ]
12
12
 
13
13
  steps:
14
14
  - uses: actions/checkout@v2
data/CHANGELOG.md CHANGED
@@ -1,5 +1,176 @@
1
- # Changelog
1
+ # Changes
2
2
 
3
- [jop] 2014-08-18
4
- * Rails 4 compatibility
5
- * Added changelog
3
+ ## 2024-10-28 v3.4.0
4
+
5
+ * Improve Journaling for Transfer Operations:
6
+ + Renamed `add_posting` to `build_posting` in `ActsAsAccount::Journal`
7
+ + Replaced direct database insertion with two insert statements with a call to `model.insert_all` in `transfer` method
8
+ + Updated `update_attributes_on` to directly count amounts of postings
9
+ * Ensure consistent locking order for account transfers:
10
+ + Use each if we aren't interested in the `lock!` results
11
+ + Make if condition readable even on smaller displays
12
+ * Improved logging for transfer method in Journal class:
13
+ + Improved formatting of debug message using array.join.
14
+ + Improved indenting of comment
15
+ * Improved journal functionality for transfers:
16
+ + Replaced `tap` with a more concise implementation using `map`
17
+
18
+ ## 2024-10-23 v3.3.0
19
+
20
+ * Make persistence of `#postings_count` and `#balance` configurable for accounts:
21
+ + Only lock if configuration is set to persist these attributes
22
+ + Rename `recalculate_all_balances` to `recalculate_attributes` and deprecate
23
+ the original method
24
+ * Make gem configurable:
25
+ + Add configuration option `persist_attributes_on_account` for persistence of `postings_count` and `balance`
26
+ * Update dependencies and Ruby version:
27
+ + Update to newer Ruby version and dependencies
28
+ * Review and README adjustments:
29
+ + Perform review and make adjustments to README file
30
+ * Fix typo:
31
+ + Correct a typo in the code
32
+
33
+ ## 2022-07-20 v3.2.3
34
+
35
+ * Loosen Rails dependencies to now be less than **8**.
36
+ * Use experimental, new web-protocol for links (`HTTP::Link`).
37
+ * Neaten README and update copyright information.
38
+ * Remove dependency on `cc` gem (broken on Ruby-head).
39
+ * Test only on MRI (Ruby Implementation).
40
+ * Fix linter issue.
41
+ * Use SQLite for tests.
42
+ * Use GitHub Actions.
43
+
44
+ ## 2021-02-22 v3.2.2
45
+
46
+ * Make `database_cleaner` a development dependency
47
+ * Support **Rails 6**
48
+ * Fix specs for recent versions of **Rails**
49
+
50
+ ## 2016-12-08 v3.2.0
51
+
52
+ * Be compatible with Rails **5**.
53
+ * Call `rake` instead of just mentioning it.
54
+ * Do not check in `Gemfile.lock`.
55
+ * Drop support for Ruby **1.9.2**.
56
+ * Add support for Ruby **2.3.0**.
57
+ * Update gems and Travis settings to use containers, adding a Travis badge.
58
+
59
+ ## 2015-01-22 v3.1.2
60
+
61
+ * Removed `.ruby` files.
62
+ * Regenerated `gemspec` for **3.1.1** and **2.0.3** versions.
63
+ * Ignored ruby-version.
64
+
65
+ ## 2015-01-14 v3.1.1
66
+
67
+ * Corrected posting scope for Rails 4: The `posting_scope` method was updated
68
+ to correctly handle UTC times stored in the database.
69
+ * Compare UTC times to values in database: The code now parses specified dates
70
+ and converts them to the database format of their UTC time, ensuring correct
71
+ range finding.
72
+ * Be less strict in depending on **4.1**: The gem's dependencies were relaxed
73
+ to be less strict about requiring version **4.1**.
74
+ * Update LICENSE: The license was changed from an unknown type to Apache
75
+ License.
76
+ * Regenerate gemspec for `version 3.1.0`: The gemspec was regenerated for the
77
+ new version.
78
+ * Adds Changelog and Rails 4 notice: A changelog and a notice about supporting
79
+ Rails 4 were added.
80
+ * Regenerate gemspec for `version 2.0.3`: The gemspec was regenerated for the
81
+ new version.
82
+ * Regenerate gemspec for `version 3.1.1`: The gemspec was regenerated for the
83
+ new version.
84
+
85
+ ## 2014-04-25 v3.1.0
86
+
87
+ * Added Rails 4.1 compatibility.
88
+ * Regenerated gemspec for `**3.1.0**`.
89
+ * Updated LICENSE to use the Apache License.
90
+
91
+ ## 2013-12-17 v3.0.0
92
+
93
+ * Adds **Rails 4** compatibility
94
+ * Uses `update_counters` to solve concurrency issues and treat account balances
95
+ like other counters in Rails, replacing previous method that would undo lock
96
+ on account rows by reloading them.
97
+
98
+ ## 2014-09-18 v2.0.2
99
+
100
+ * Repair building with `jewel`
101
+ * Add `travis` configuration
102
+ * Specify gem dependencies
103
+ * Update LICENSE to Apache License
104
+ * Compare UTC times to values in database:
105
+ + Parse specified dates and convert them to the db format of their UTC time.
106
+
107
+ ## 2012-10-04 v2.0.1
108
+
109
+ * Regenerate gemspec for **2.0.1**
110
+ * Fixed problem that broke STI classes that used `has_account` in Rails 3.x
111
+ * Updated gemspec to reflect changes
112
+
113
+ ## 2012-09-10 v2.0.0
114
+
115
+ * Upgrade `acts_as_account` to work with Rails **3**.
116
+ * Significant changes:
117
+ + Renamed `VERSION` file
118
+ + Updated `acts_as_account.gemspec`
119
+ + Modified `lib/acts_as_account/journal.rb`
120
+ + Modified `lib/acts_as_account/posting.rb`
121
+
122
+ ## 2012-07-31 v1.2.0
123
+
124
+ * Regenerate gemspec for `version 1.2.0`
125
+ * Updated `version` to use with default STI naming setup for Rails >= **2.3**
126
+ * Added method `BetterPlace::Model::Base#sti_name`
127
+ * Renamed method `BetterPlace::Model::Base#table_name`
128
+
129
+ ## 2012-03-12 v1.1.6
130
+
131
+ * **Fixed bug in active_record_extensions**: `holder_id` and type are now
132
+ passed through correctly.
133
+ * Changed `returning` to `#tap` to remove warnings.
134
+ * More fixes for tests and rake task.
135
+ * Fixed calculation of account balances.
136
+
137
+ ## 2010-11-15 v1.1.5
138
+
139
+ * Fixed dependency:
140
+ + Updated `Gemfile` to use the latest version of `rails`
141
+ + Removed unused `mysql2` gem
142
+ * Significant changes:
143
+ + Added a new method, `create_user`, to the `User` model (`def
144
+ create_user(**kwargs)`)
145
+ + Updated the `login` method in the `SessionController` to use the
146
+ `create_user` method (`def login; @user = User.create_user(**params); end`)
147
+ + Changed the default value of the `admin` attribute in the `User` model from
148
+ `false` to `true` (`attr_accessor :admin, default: true`)
149
+
150
+ ## 2010-11-12 v1.1.4
151
+
152
+ * Fixed dependency bug:
153
+ + Updated the project to use `Gemfile` instead of `config.gem`
154
+ + Removed reference to deprecated `config.gem` in favor of `Gemfile`
155
+ + Added `gem 'mysql2', '~> **1.0**'` to `Gemfile`
156
+
157
+ ## 2010-11-12 v1.1.3
158
+
159
+ * Fixed dependency bug:
160
+ + Updated `BetterPlace::DependencyManager` to use correct version of `Gem`
161
+ (now using `Gem::Version.new('1.3.7')`)
162
+ + Added check for missing dependencies in
163
+ `BetterPlace::Project#load_dependencies`
164
+ * Version bump: **1.1.3**
165
+
166
+ ## 2010-11-12 v1.1.2
167
+
168
+ * Added some methods:
169
+ + `BetterPlace::Project#new` now takes an optional `:api_key` parameter
170
+ + `BetterPlace::Project#fetch_data` now fetches data from the Better Place
171
+ API using the provided `:api_key`
172
+ * Modified README and Rakefile
173
+
174
+ ## 2010-11-12 v1.1.0
175
+
176
+ * Start
data/README.md CHANGED
@@ -15,6 +15,18 @@ tables is needed.
15
15
  We also hook into the ActionController request cycle to warn the developer
16
16
  if a request has left uncommitted changes in the system.
17
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
+
18
30
  ## How to test
19
31
 
20
32
  Run the cucumber features from the acs_as_account gem, just execute
@@ -23,7 +35,7 @@ Run the cucumber features from the acs_as_account gem, just execute
23
35
 
24
36
  ## How to release
25
37
 
26
- You need to update the data in `VERSION` and Rakefile and run `rake` (because it uses Gemhadar).
38
+ You need to update the data in `VERSION` and Rakefile and run `rake` (because it uses GemHadar).
27
39
  `rake gem:push` will push the version to rubygems.
28
40
 
29
41
  ## Links
data/Rakefile CHANGED
@@ -18,11 +18,11 @@ GemHadar do
18
18
 
19
19
  dependency 'activerecord', '>= 5.1', '<8'
20
20
  dependency 'actionpack' , '>= 4.1', '<8'
21
- development_dependency 'cucumber', '~> 1.3'
21
+ development_dependency 'cucumber'
22
22
  development_dependency 'sqlite3'
23
- development_dependency 'rspec', '~> 3.1'
23
+ development_dependency 'rspec'
24
24
  development_dependency 'simplecov'
25
- development_dependency 'database_cleaner', '~> 1.3'
25
+ development_dependency 'database_cleaner'
26
26
  development_dependency 'rubocop'
27
27
  end
28
28
 
@@ -30,7 +30,7 @@ def connect_database
30
30
  require 'active_record'
31
31
  require 'yaml'
32
32
  db_config = YAML.load_file('features/db/database.yml')
33
- ActiveRecord::Base.establish_connection(db_config).connection
33
+ ActiveRecord::Base.establish_connection(db_config).lease_connection
34
34
  end
35
35
 
36
36
  namespace :features do
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.3
1
+ 3.4.0
@@ -1,47 +1,33 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: acts_as_account 3.2.3 ruby lib
2
+ # stub: acts_as_account 3.4.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.3"
6
+ s.version = "3.4.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 = "2022-07-20"
11
+ s.date = "2024-10-28"
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.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/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/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]
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
16
  s.homepage = "https://github.com/betterplace/acts_as_account".freeze
17
17
  s.licenses = ["Apache-2.0".freeze]
18
18
  s.rdoc_options = ["--title".freeze, "ActsAsAccount -- More Math in Ruby".freeze, "--main".freeze, "README.md".freeze]
19
- s.rubygems_version = "3.3.3".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<sqlite3>.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<database_cleaner>.freeze, ["~> 1.3"])
33
- s.add_development_dependency(%q<rubocop>.freeze, [">= 0"])
34
- s.add_runtime_dependency(%q<activerecord>.freeze, [">= 5.1", "< 8"])
35
- s.add_runtime_dependency(%q<actionpack>.freeze, [">= 4.1", "< 8"])
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<sqlite3>.freeze, [">= 0"])
40
- s.add_dependency(%q<rspec>.freeze, ["~> 3.1"])
41
- s.add_dependency(%q<simplecov>.freeze, [">= 0"])
42
- s.add_dependency(%q<database_cleaner>.freeze, ["~> 1.3"])
43
- s.add_dependency(%q<rubocop>.freeze, [">= 0"])
44
- s.add_dependency(%q<activerecord>.freeze, [">= 5.1", "< 8"])
45
- s.add_dependency(%q<actionpack>.freeze, [">= 4.1", "< 8"])
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
@@ -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|
@@ -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
@@ -24,3 +24,10 @@ require_relative 'cheque'
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
 
@@ -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
@@ -20,9 +20,7 @@ module ActsAsAccount
20
20
  end
21
21
 
22
22
  def transfers
23
- [].tap do |transfers|
24
- postings.each_slice(2) { |postings| transfers << Transfer.new(*postings) }
25
- end
23
+ postings.each_slice(2).map { |postings| Transfer.new(*postings) }
26
24
  end
27
25
 
28
26
  def transfer(amount, from_account, to_account, reference = nil, valuta = Time.now)
@@ -32,31 +30,51 @@ module ActsAsAccount
32
30
  amount, from_account, to_account = -amount, to_account, from_account
33
31
  end
34
32
 
35
- logger.debug { "ActsAsAccount::Journal.transfer amount: #{amount} from:#{from_account.id} to:#{to_account.id} reference:#{reference.class.name}(#{reference.id}) valuta:#{valuta}" } if logger
33
+ if logger
34
+ logger.debug(
35
+ [
36
+ "ActsAsAccount::Journal.transfer",
37
+ "amount: #{amount}",
38
+ "from: #{from_account.id}",
39
+ "to: #{to_account.id}",
40
+ "reference: #{reference.class.name}(#{reference.id})",
41
+ "valuta: #{valuta}",
42
+ ].join(' ')
43
+ )
44
+ end
45
+
46
+ # To avoid possible deadlocks we need to ensure that the locking order
47
+ # is always the same therfore the sort by id.
48
+ if ActsAsAccount.configuration.persist_attributes_on_account
49
+ [from_account, to_account].sort_by(&:id).each(&:lock!)
50
+ end
51
+
52
+ posting1 = build_posting(-amount, from_account, to_account, reference, valuta)
53
+ posting2 = build_posting( amount, to_account, from_account, reference, valuta)
36
54
 
37
- # to avoid possible deadlocks we need to ensure that the locking order is always
38
- # the same therfore the sort by id.
39
- [from_account, to_account].sort_by(&:id).map(&:lock!)
55
+ postings.model.insert_all([ posting1.attributes, posting2.attributes ])
40
56
 
41
- add_posting(-amount, from_account, to_account, reference, valuta)
42
- add_posting( amount, to_account, from_account, reference, valuta)
57
+ update_attributes_on(from_account, -amount)
58
+ update_attributes_on(to_account, amount)
43
59
  end
44
60
  end
45
61
 
46
62
  private
47
63
 
48
- def add_posting(amount, account, other_account, reference, valuta)
49
- posting = postings.build(
50
- :amount => amount,
51
- :account => account,
64
+ def build_posting(amount, account, other_account, reference, valuta)
65
+ postings.build(
66
+ :amount => amount,
67
+ :account => account,
52
68
  :other_account => other_account,
53
- :reference => reference,
54
- :valuta => valuta)
69
+ :reference => reference,
70
+ :valuta => valuta
71
+ )
72
+ end
55
73
 
56
- account.class.update_counters account.id, :postings_count => 1, :balance => posting.amount
74
+ def update_attributes_on(account, amount)
75
+ return unless ActsAsAccount.configuration.persist_attributes_on_account
57
76
 
58
- posting.save(:validate => false)
59
- account.save(:validate => false)
77
+ account.class.update_counters account.id, postings_count: 1, balance: amount
60
78
  end
61
79
  end
62
80
  end
@@ -1,6 +1,6 @@
1
1
  module ActsAsAccount
2
2
  # ActsAsAccount version
3
- VERSION = '3.2.3'
3
+ VERSION = '3.4.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.3
4
+ version: 3.4.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: 2022-07-20 00:00:00.000000000 Z
11
+ date: 2024-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gem_hadar
@@ -16,28 +16,28 @@ 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
42
  name: sqlite3
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -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
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: database_cleaner
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.3'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.3'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -159,6 +159,7 @@ extra_rdoc_files:
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
@@ -195,6 +196,7 @@ files:
195
196
  - lib/acts_as_account.rb
196
197
  - lib/acts_as_account/account.rb
197
198
  - lib/acts_as_account/active_record_extensions.rb
199
+ - lib/acts_as_account/configuration.rb
198
200
  - lib/acts_as_account/global_account.rb
199
201
  - lib/acts_as_account/journal.rb
200
202
  - lib/acts_as_account/manually_created_account.rb
@@ -225,7 +227,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
227
  - !ruby/object:Gem::Version
226
228
  version: '0'
227
229
  requirements: []
228
- rubygems_version: 3.3.3
230
+ rubygems_version: 3.5.18
229
231
  signing_key:
230
232
  specification_version: 4
231
233
  summary: acts_as_account implements double entry accounting for Rails models