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 +4 -4
- data/.github/workflows/lint.yml +29 -0
- data/.github/workflows/tests.yml +22 -0
- data/.rubocop.yml +61 -0
- data/README.md +55 -0
- data/Rakefile +14 -19
- data/VERSION +1 -1
- data/acts_as_account.gemspec +18 -32
- data/acts_as_account.sqlite +0 -0
- data/features/db/database.yml +5 -6
- data/features/db/schema.rb +0 -4
- data/features/step_definitions/account_steps.rb +19 -5
- data/features/support/env.rb +15 -8
- data/features/transfer/transfer.feature +15 -3
- data/lib/acts_as_account/account.rb +42 -12
- data/lib/acts_as_account/active_record_extensions.rb +0 -1
- data/lib/acts_as_account/configuration.rb +10 -0
- data/lib/acts_as_account/global_account.rb +6 -1
- data/lib/acts_as_account/journal.rb +9 -4
- data/lib/acts_as_account/posting.rb +2 -2
- data/lib/acts_as_account/version.rb +1 -1
- data/lib/acts_as_account.rb +9 -0
- metadata +36 -31
- data/.travis.yml +0 -5
- data/README.rdoc +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c148f57665d7973143472d6c9bf4d68098a136680e5f5f059d9432d5df3b74a0
|
4
|
+
data.tar.gz: f26b227813ab4a345d6d32944970e0b1817f636109bcaed4983e8f5554e788ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 "
|
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.
|
15
|
+
readme 'README.md'
|
16
16
|
title "#{name.camelize} -- More Math in Ruby"
|
17
17
|
licenses << 'Apache-2.0'
|
18
18
|
|
19
|
-
dependency 'activerecord', '>=
|
20
|
-
dependency 'actionpack' , '>= 4.1', '<
|
21
|
-
development_dependency 'cucumber'
|
22
|
-
development_dependency '
|
23
|
-
development_dependency 'rspec'
|
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 '
|
26
|
-
development_dependency '
|
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 '
|
32
|
-
|
33
|
-
|
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
|
-
|
42
|
-
|
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.
|
1
|
+
3.3.0
|
data/acts_as_account.gemspec
CHANGED
@@ -1,47 +1,33 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: acts_as_account 3.
|
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.
|
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 = "
|
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.
|
15
|
-
s.files = [".gitignore".freeze, ".
|
16
|
-
s.homepage = "
|
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.
|
19
|
-
s.rubygems_version = "3.
|
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
|
-
|
23
|
-
s.specification_version = 4
|
24
|
-
end
|
22
|
+
s.specification_version = 4
|
25
23
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
data/features/db/database.yml
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
host: localhost
|
1
|
+
adapter: sqlite3
|
2
|
+
encoding: utf8
|
3
|
+
database: acts_as_account.sqlite
|
4
|
+
username: root
|
5
|
+
host: localhost
|
data/features/db/schema.rb
CHANGED
@@ -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
|
-
|
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
|
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.
|
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
|
data/features/support/env.rb
CHANGED
@@ -6,21 +6,28 @@ if ENV['START_SIMPLECOV'].to_i == 1
|
|
6
6
|
end
|
7
7
|
|
8
8
|
require 'acts_as_account'
|
9
|
-
require '
|
10
|
-
|
11
|
-
ActiveRecord::Base.establish_connection(
|
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[
|
17
|
+
Dir["#{__dir__}/../step_definitions/*.rb"].sort.each { |file| require file }
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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.
|
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
|
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
|
@@ -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.
|
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
|
56
|
+
update_attributes_on(account, posting)
|
57
57
|
|
58
58
|
posting.save(:validate => false)
|
59
|
-
|
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.
|
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.
|
19
|
+
date = Time.parse(date.to_s).utc.to_fs(:db)
|
20
20
|
where(['valuta <= ?', date])
|
21
21
|
}
|
22
22
|
end
|
data/lib/acts_as_account.rb
CHANGED
@@ -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.
|
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:
|
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.
|
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.
|
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: '
|
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: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
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: '
|
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: '
|
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:
|
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:
|
98
|
+
name: rubocop
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
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: '
|
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: '
|
117
|
+
version: '5.1'
|
118
118
|
- - "<"
|
119
119
|
- !ruby/object:Gem::Version
|
120
|
-
version: '
|
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: '
|
127
|
+
version: '5.1'
|
128
128
|
- - "<"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
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: '
|
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: '
|
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.
|
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
|
-
- ".
|
174
|
+
- ".rubocop.yml"
|
172
175
|
- CHANGELOG.md
|
173
176
|
- Gemfile
|
174
177
|
- LICENSE
|
175
|
-
- README.
|
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:
|
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.
|
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.
|
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
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
|