appydave-tools 0.10.2 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +14 -0
- data/bin/bank_reconciliation.rb +31 -4
- data/lib/appydave/tools/configuration/models/config_base.rb +1 -1
- data/lib/appydave/tools/debuggable.rb +22 -0
- data/lib/appydave/tools/{prompt_tools → llm}/models/llm_info.rb +1 -1
- data/lib/appydave/tools/llm/openai_completion.rb +11 -0
- data/lib/appydave/tools/prompt_tools/_doc.md +5 -0
- data/lib/appydave/tools/prompt_tools/prompt_completion.rb +2 -2
- data/lib/appydave/tools/version.rb +1 -1
- data/lib/appydave/tools/youtube_manager/_doc.md +1 -1
- data/lib/appydave/tools.rb +9 -6
- data/package-lock.json +2 -2
- data/package.json +1 -1
- metadata +6 -9
- data/lib/appydave/tools/bank_reconciliation/_doc.md +0 -36
- data/lib/appydave/tools/bank_reconciliation/clean/clean_transactions.rb +0 -106
- data/lib/appydave/tools/bank_reconciliation/clean/mapper.rb +0 -136
- data/lib/appydave/tools/bank_reconciliation/clean/read_transactions.rb +0 -88
- data/lib/appydave/tools/bank_reconciliation/models/transaction.rb +0 -91
- data/lib/appydave/tools/configuration/models/bank_reconciliation_config.rb +0 -97
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40337ac9a46d2a5d2b7a645b14e572f011c84b52e958ba880be666d6dfe3413b
|
4
|
+
data.tar.gz: 4e4e4bd076cae97a6cdec63dd70313f49efcbb19fb6295ffd1ef297dbbf08e42
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86448501dd1959eb0173ed98af2dead6965b56bf9cfcdc5007d335b73ecd94f8bb7e5cda9f099997285509e93f7ecff1368740fbe38c16c5e4240b1578462116
|
7
|
+
data.tar.gz: 9e32acedc6fbc3b7e21123a56f068e7c91a6b6b4cc58a7315102a08b9455950f531755c5d1405b66dd52a9df60132aab08395877f771d8b096bb364aa6e83e7e
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.10.3](https://github.com/klueless-io/appydave-tools/compare/v0.10.2...v0.10.3) (2024-06-17)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* extending bank reconciliation with platform and banking mapping ([848b044](https://github.com/klueless-io/appydave-tools/commit/848b044bf4bb7c27bae6cf33aba400ab68eb105c))
|
7
|
+
|
8
|
+
## [0.10.2](https://github.com/klueless-io/appydave-tools/compare/v0.10.1...v0.10.2) (2024-06-17)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* make progress on prompt completion tool ([fbc60b7](https://github.com/klueless-io/appydave-tools/commit/fbc60b712e3e18d7f73c47f4568bae65295557df))
|
14
|
+
|
1
15
|
## [0.10.1](https://github.com/klueless-io/appydave-tools/compare/v0.10.0...v0.10.1) (2024-06-13)
|
2
16
|
|
3
17
|
|
data/bin/bank_reconciliation.rb
CHANGED
@@ -14,6 +14,7 @@ class BankReconciliationCLI
|
|
14
14
|
def initialize
|
15
15
|
@commands = {
|
16
16
|
'clean' => method(:clean_transactions),
|
17
|
+
'transform' => method(:transform),
|
17
18
|
'process' => method(:process_transactions),
|
18
19
|
'filter' => method(:filter_transactions)
|
19
20
|
}
|
@@ -48,6 +49,10 @@ class BankReconciliationCLI
|
|
48
49
|
options[:output] = v
|
49
50
|
end
|
50
51
|
|
52
|
+
opts.on('-d', '--debug', 'Enable debug mode') do
|
53
|
+
options[:debug] = true
|
54
|
+
end
|
55
|
+
|
51
56
|
opts.on_tail('-h', '--help', 'Show this message') do
|
52
57
|
puts opts
|
53
58
|
exit
|
@@ -58,17 +63,37 @@ class BankReconciliationCLI
|
|
58
63
|
output_file = options[:output] || 'clean_transactions.csv'
|
59
64
|
include_patterns = options[:include].empty? ? ['*'] : options[:include]
|
60
65
|
|
61
|
-
puts "Cleaning transactions with options: #{options}"
|
66
|
+
# puts "Cleaning transactions with options: #{options}"
|
62
67
|
|
63
68
|
# Ensure the clean directory exists
|
64
69
|
clean_dir = File.dirname(output_file)
|
65
70
|
FileUtils.mkdir_p(clean_dir)
|
66
71
|
|
67
72
|
# Initialize the CleanTransactions class and process the files
|
68
|
-
cleaner = Appydave::Tools::BankReconciliation::Clean::CleanTransactions.new(transaction_folder: transaction_folder)
|
73
|
+
cleaner = Appydave::Tools::BankReconciliation::Clean::CleanTransactions.new(transaction_folder: transaction_folder, debug: options[:debug])
|
69
74
|
cleaner.clean_transactions(include_patterns, output_file)
|
75
|
+
end
|
76
|
+
|
77
|
+
def transform(args)
|
78
|
+
options = {}
|
79
|
+
OptionParser.new do |opts|
|
80
|
+
opts.banner = 'Usage: bank_reconciliation.rb clean [options]'
|
81
|
+
|
82
|
+
opts.on('-c', '--to-csv', 'Write chart of accounts JSON to CSV') { options[:to_csv] = true }
|
83
|
+
opts.on('-j', '--to-json', 'Write chart of accounts CSV to JSON') { options[:to_json] = true }
|
84
|
+
|
85
|
+
opts.on('-d', '--debug', 'Enable debug mode') do
|
86
|
+
options[:debug] = true
|
87
|
+
end
|
88
|
+
|
89
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
90
|
+
puts opts
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
end.parse!(args)
|
70
94
|
|
71
|
-
|
95
|
+
Appydave::Tools::Configuration::Models::BankReconciliationConfig.new.coa_to_csv if options[:to_csv]
|
96
|
+
Appydave::Tools::Configuration::Models::BankReconciliationConfig.new.coa_csv_to_json if options[:to_json]
|
72
97
|
end
|
73
98
|
|
74
99
|
def process_transactions(args)
|
@@ -76,6 +101,7 @@ class BankReconciliationCLI
|
|
76
101
|
OptionParser.new do |opts|
|
77
102
|
opts.banner = 'Usage: bank_reconciliation.rb process [options]'
|
78
103
|
opts.on('-i', '--input FILE', 'Input CSV file with transactions') { |v| options[:input] = v }
|
104
|
+
opts.on('-d', '--debug', 'Enable debug mode') { |v| options[:debug] = v }
|
79
105
|
opts.on_tail('-h', '--help', 'Show this message') do
|
80
106
|
puts opts
|
81
107
|
exit
|
@@ -96,8 +122,9 @@ class BankReconciliationCLI
|
|
96
122
|
opts.on('-e', '--end DATE', 'Filter by dates less than or eqaul to DDMMYY') { |v| options[:year] = v }
|
97
123
|
opts.on('-c', '--codes CODES', 'Filter by chart of account codes (comma-separated)') { |v| options[:codes] = v }
|
98
124
|
opts.on('-w', '--wild TEXT', 'Wildcard text match') { |v| options[:text] = v }
|
99
|
-
opts.on('-
|
125
|
+
opts.on('-v', '--view', 'Display filtered transactions in table format') { |v| options[:display] = v }
|
100
126
|
opts.on('-o', '--output FILE', 'Output CSV file name') { |v| options[:output] = v }
|
127
|
+
opts.on('-d', '--debug', 'Enable debug mode') { |v| options[:debug] = v }
|
101
128
|
opts.on_tail('-h', '--help', 'Show this message') do
|
102
129
|
puts opts
|
103
130
|
exit
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appydave
|
4
|
+
module Tools
|
5
|
+
# Debuggable is a module for adding debug logging to classes
|
6
|
+
module Debuggable
|
7
|
+
attr_accessor :debug
|
8
|
+
|
9
|
+
def log_info(message)
|
10
|
+
log.info(message) if debug
|
11
|
+
end
|
12
|
+
|
13
|
+
def log_kv(key, value)
|
14
|
+
log.kv(key, value) if debug
|
15
|
+
end
|
16
|
+
|
17
|
+
def log_subheading(message)
|
18
|
+
log.subheading(message) if debug
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -16,7 +16,7 @@ module Appydave
|
|
16
16
|
attr_reader :clipboard
|
17
17
|
|
18
18
|
def initialize(options = {})
|
19
|
-
|
19
|
+
setup_options(options)
|
20
20
|
|
21
21
|
validate_options
|
22
22
|
end
|
@@ -44,7 +44,7 @@ module Appydave
|
|
44
44
|
|
45
45
|
private
|
46
46
|
|
47
|
-
def
|
47
|
+
def setup_options(options)
|
48
48
|
@prompt = options.delete(:prompt)
|
49
49
|
@prompt_file = options.delete(:prompt_file)
|
50
50
|
@llm = Appydave::Tools::PromptTools::Models::LlmInfo.new(
|
data/lib/appydave/tools.rb
CHANGED
@@ -18,11 +18,15 @@ require 'webrick'
|
|
18
18
|
require 'pry'
|
19
19
|
|
20
20
|
require 'appydave/tools/version'
|
21
|
+
require 'appydave/tools/debuggable'
|
21
22
|
require 'appydave/tools/types/indifferent_access_hash'
|
22
23
|
require 'appydave/tools/types/hash_type'
|
23
24
|
require 'appydave/tools/types/array_type'
|
24
25
|
require 'appydave/tools/types/base_model'
|
25
26
|
|
27
|
+
require 'appydave/tools/llm/models/llm_info'
|
28
|
+
require 'appydave/tools/llm/openai_completion'
|
29
|
+
|
26
30
|
require 'appydave/tools/cli_actions/base_action'
|
27
31
|
|
28
32
|
# May want to move this into the tools location
|
@@ -37,16 +41,15 @@ require 'appydave/tools/configuration/configurable'
|
|
37
41
|
require 'appydave/tools/configuration/config'
|
38
42
|
require 'appydave/tools/configuration/models/config_base'
|
39
43
|
require 'appydave/tools/configuration/models/settings_config'
|
40
|
-
require 'appydave/tools/configuration/models/bank_reconciliation_config'
|
44
|
+
# require 'appydave/tools/configuration/models/bank_reconciliation_config'
|
41
45
|
require 'appydave/tools/configuration/models/channels_config'
|
42
46
|
require 'appydave/tools/configuration/models/youtube_automation_config'
|
43
47
|
require 'appydave/tools/name_manager/project_name'
|
44
|
-
require 'appydave/tools/bank_reconciliation/clean/clean_transactions'
|
45
|
-
require 'appydave/tools/bank_reconciliation/clean/read_transactions'
|
46
|
-
require 'appydave/tools/bank_reconciliation/clean/mapper'
|
47
|
-
require 'appydave/tools/bank_reconciliation/models/transaction'
|
48
|
+
# require 'appydave/tools/bank_reconciliation/clean/clean_transactions'
|
49
|
+
# require 'appydave/tools/bank_reconciliation/clean/read_transactions'
|
50
|
+
# require 'appydave/tools/bank_reconciliation/clean/mapper'
|
51
|
+
# require 'appydave/tools/bank_reconciliation/models/transaction'
|
48
52
|
|
49
|
-
require 'appydave/tools/prompt_tools/models/llm_info'
|
50
53
|
require 'appydave/tools/prompt_tools/prompt_completion'
|
51
54
|
|
52
55
|
require 'appydave/tools/subtitle_master/clean'
|
data/package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "appydave-tools",
|
3
|
-
"version": "0.10.
|
3
|
+
"version": "0.10.4",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "appydave-tools",
|
9
|
-
"version": "0.10.
|
9
|
+
"version": "0.10.4",
|
10
10
|
"devDependencies": {
|
11
11
|
"@klueless-js/semantic-release-rubygem": "github:klueless-js/semantic-release-rubygem",
|
12
12
|
"@semantic-release/changelog": "^6.0.3",
|
data/package.json
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: appydave-tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Cruwys
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -167,11 +167,6 @@ files:
|
|
167
167
|
- bin/youtube_manager.rb
|
168
168
|
- images.log
|
169
169
|
- lib/appydave/tools.rb
|
170
|
-
- lib/appydave/tools/bank_reconciliation/_doc.md
|
171
|
-
- lib/appydave/tools/bank_reconciliation/clean/clean_transactions.rb
|
172
|
-
- lib/appydave/tools/bank_reconciliation/clean/mapper.rb
|
173
|
-
- lib/appydave/tools/bank_reconciliation/clean/read_transactions.rb
|
174
|
-
- lib/appydave/tools/bank_reconciliation/models/transaction.rb
|
175
170
|
- lib/appydave/tools/cli_actions/_doc.md
|
176
171
|
- lib/appydave/tools/cli_actions/base_action.rb
|
177
172
|
- lib/appydave/tools/cli_actions/get_video_action.rb
|
@@ -180,18 +175,20 @@ files:
|
|
180
175
|
- lib/appydave/tools/configuration/_doc.md
|
181
176
|
- lib/appydave/tools/configuration/config.rb
|
182
177
|
- lib/appydave/tools/configuration/configurable.rb
|
183
|
-
- lib/appydave/tools/configuration/models/bank_reconciliation_config.rb
|
184
178
|
- lib/appydave/tools/configuration/models/channels_config.rb
|
185
179
|
- lib/appydave/tools/configuration/models/config_base.rb
|
186
180
|
- lib/appydave/tools/configuration/models/settings_config copy.xrb
|
187
181
|
- lib/appydave/tools/configuration/models/settings_config.rb
|
188
182
|
- lib/appydave/tools/configuration/models/youtube_automation_config.rb
|
189
183
|
- lib/appydave/tools/configuration/openai.rb
|
184
|
+
- lib/appydave/tools/debuggable.rb
|
190
185
|
- lib/appydave/tools/gpt_context/_doc.md
|
191
186
|
- lib/appydave/tools/gpt_context/file_collector.rb
|
187
|
+
- lib/appydave/tools/llm/models/llm_info.rb
|
188
|
+
- lib/appydave/tools/llm/openai_completion.rb
|
192
189
|
- lib/appydave/tools/name_manager/_doc.md
|
193
190
|
- lib/appydave/tools/name_manager/project_name.rb
|
194
|
-
- lib/appydave/tools/prompt_tools/
|
191
|
+
- lib/appydave/tools/prompt_tools/_doc.md
|
195
192
|
- lib/appydave/tools/prompt_tools/prompt_completion.rb
|
196
193
|
- lib/appydave/tools/subtitle_master/_doc.md
|
197
194
|
- lib/appydave/tools/subtitle_master/clean.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# Bank reconciliation
|
2
|
-
|
3
|
-
[ChatGPT conversation](https://chatgpt.com/c/5d382562-95e5-4243-9b74-c3807d363486)
|
4
|
-
|
5
|
-
|
6
|
-
## Code structure
|
7
|
-
|
8
|
-
```bash
|
9
|
-
├─ lib
|
10
|
-
│ ├─ appydave
|
11
|
-
│ │ └─ tools
|
12
|
-
│ │ ├─ bank_reconciliation
|
13
|
-
│ │ │ ├─ clean
|
14
|
-
│ │ │ │ ├─ read_transactions.rb
|
15
|
-
│ │ │ │ ├─ transaction_cleaner.rb
|
16
|
-
│ │ │ ├─ models
|
17
|
-
│ │ │ │ ├─ raw_transaction.rb
|
18
|
-
│ │ │ │ └─ reconciled_transaction.rb
|
19
|
-
│ │ └─ configuration
|
20
|
-
│ │ └─ models
|
21
|
-
│ │ └─ bank_reconciliation_config.rb
|
22
|
-
└─ spec
|
23
|
-
├─ appydave
|
24
|
-
│ ├─ tools
|
25
|
-
│ │ ├─ bank_reconciliation
|
26
|
-
│ │ │ ├─ clean
|
27
|
-
│ │ │ │ ├─ read_transactions_spec.rb
|
28
|
-
│ │ │ ├─ models
|
29
|
-
│ │ │ │ └─ raw_transaction_spec.rb
|
30
|
-
│ │ └─ configuration
|
31
|
-
│ │ └─ models
|
32
|
-
│ │ └─ bank_reconciliation_config_spec.rb
|
33
|
-
└─ fixtures
|
34
|
-
└─ bank-reconciliation
|
35
|
-
└─ bank-west.csv
|
36
|
-
```
|
@@ -1,106 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appydave
|
4
|
-
module Tools
|
5
|
-
module BankReconciliation
|
6
|
-
module Clean
|
7
|
-
# Clean transactions
|
8
|
-
class CleanTransactions
|
9
|
-
include Appydave::Tools::Configuration::Configurable
|
10
|
-
include KLog::Logging
|
11
|
-
|
12
|
-
attr_reader :transaction_folder
|
13
|
-
attr_reader :output_folder
|
14
|
-
attr_reader :transactions
|
15
|
-
|
16
|
-
# (config_file)
|
17
|
-
def initialize(transaction_folder: nil, output_folder: nil)
|
18
|
-
# needs to use config.bank_reconciliation.transaction_folder
|
19
|
-
transaction_folder ||= '/Volumes/Expansion/Sync/bank-reconciliation/original-transactions'
|
20
|
-
output_folder ||= File.join(transaction_folder, 'clean')
|
21
|
-
|
22
|
-
@transaction_folder = transaction_folder
|
23
|
-
@output_folder = output_folder
|
24
|
-
end
|
25
|
-
|
26
|
-
def clean_transactions(input_globs, output_file)
|
27
|
-
raw_transactions = grab_raw_transactions(input_globs)
|
28
|
-
transactions, duplicates_count = deduplicate(raw_transactions)
|
29
|
-
|
30
|
-
transactions = Mapper.new.map(transactions)
|
31
|
-
|
32
|
-
# tp transactions, Appydave::Tools::BankReconciliation::Models::Transaction.csv_headers
|
33
|
-
|
34
|
-
log.kv 'Deduped consolidated transactions', duplicates_count if duplicates_count.positive?
|
35
|
-
|
36
|
-
save_to_csv(transactions, output_file)
|
37
|
-
|
38
|
-
@transactions = transactions
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def grab_raw_transactions(input_globs)
|
44
|
-
original_dir = Dir.pwd
|
45
|
-
transactions = []
|
46
|
-
|
47
|
-
begin
|
48
|
-
Dir.chdir(transaction_folder)
|
49
|
-
|
50
|
-
input_globs.each do |glob|
|
51
|
-
Dir.glob(glob).each do |file|
|
52
|
-
log.kv 'Reading transactions from', file
|
53
|
-
raw_transactions = ReadTransactions.new(file).read
|
54
|
-
deduped_transactions, duplicates_count = deduplicate(raw_transactions)
|
55
|
-
|
56
|
-
if duplicates_count.positive?
|
57
|
-
log.kv 'Duplicates count', duplicates_count
|
58
|
-
log.kv 'File', file
|
59
|
-
end
|
60
|
-
|
61
|
-
transactions += deduped_transactions
|
62
|
-
end
|
63
|
-
end
|
64
|
-
ensure
|
65
|
-
Dir.chdir(original_dir)
|
66
|
-
end
|
67
|
-
|
68
|
-
transactions
|
69
|
-
end
|
70
|
-
|
71
|
-
def deduplicate(transactions)
|
72
|
-
unique_transactions = transactions.uniq do |transaction|
|
73
|
-
[
|
74
|
-
transaction.bsb_number,
|
75
|
-
transaction.account_number,
|
76
|
-
transaction.transaction_date,
|
77
|
-
transaction.narration,
|
78
|
-
transaction.cheque_number,
|
79
|
-
transaction.debit,
|
80
|
-
transaction.credit,
|
81
|
-
transaction.balance,
|
82
|
-
transaction.transaction_type
|
83
|
-
]
|
84
|
-
end
|
85
|
-
|
86
|
-
duplicates = transactions.size - unique_transactions.size
|
87
|
-
|
88
|
-
[unique_transactions, duplicates]
|
89
|
-
end
|
90
|
-
|
91
|
-
def save_to_csv(transactions, output_file)
|
92
|
-
FileUtils.mkdir_p(output_folder)
|
93
|
-
output_file = File.join(output_folder, output_file)
|
94
|
-
|
95
|
-
CSV.open(output_file, 'w') do |csv|
|
96
|
-
csv << Appydave::Tools::BankReconciliation::Models::Transaction.csv_headers
|
97
|
-
transactions.each do |transaction|
|
98
|
-
csv << transaction.to_csv_row
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
@@ -1,136 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appydave
|
4
|
-
module Tools
|
5
|
-
module BankReconciliation
|
6
|
-
module Clean
|
7
|
-
# Map transactions to chart of accounts and bank accounts
|
8
|
-
class Mapper
|
9
|
-
include Appydave::Tools::Configuration::Configurable
|
10
|
-
|
11
|
-
# "bank_accounts": [
|
12
|
-
# {
|
13
|
-
# "account_number": "5435 6859 0116 7736",
|
14
|
-
# "bsb": "",
|
15
|
-
# "name": "Mastercard",
|
16
|
-
# "platform": "Bankwest"
|
17
|
-
# },
|
18
|
-
# {
|
19
|
-
# "account_number": "303-092",
|
20
|
-
# "bsb": "1361644",
|
21
|
-
# "name": "atcall",
|
22
|
-
# "platform": "Bankwest"
|
23
|
-
# },
|
24
|
-
|
25
|
-
def map(transactions)
|
26
|
-
transactions.map do |original_transaction|
|
27
|
-
transaction = original_transaction.dup
|
28
|
-
|
29
|
-
transaction = map_chart_of_account(transaction)
|
30
|
-
map_bank_account(transaction)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def map_chart_of_account(transaction)
|
37
|
-
equality_match(transaction) ||
|
38
|
-
trigram_match(transaction, 0.9, '90%') ||
|
39
|
-
trigram_match(transaction, 0.8, '80%') ||
|
40
|
-
trigram_match(transaction, 0.7, '70%') ||
|
41
|
-
trigram_match(transaction, 0.6, '60%') ||
|
42
|
-
trigram_match(transaction, 0.5, '50%') ||
|
43
|
-
start_with_match(transaction) ||
|
44
|
-
includes(transaction)
|
45
|
-
transaction
|
46
|
-
end
|
47
|
-
|
48
|
-
def map_bank_account(transaction)
|
49
|
-
bank_account = config.bank_reconciliation.get_bank_account(transaction.account_number, transaction.bsb_number)
|
50
|
-
|
51
|
-
if bank_account
|
52
|
-
transaction.account_name = bank_account.name
|
53
|
-
transaction.platform = bank_account.platform
|
54
|
-
end
|
55
|
-
|
56
|
-
transaction
|
57
|
-
end
|
58
|
-
|
59
|
-
def equality_match(transaction)
|
60
|
-
coa = config.bank_reconciliation.chart_of_accounts.find do |chart_of_account|
|
61
|
-
chart_of_account.narration.to_s.delete(' ').downcase == transaction.narration.delete(' ').downcase
|
62
|
-
end
|
63
|
-
|
64
|
-
return nil unless coa
|
65
|
-
|
66
|
-
transaction.coa_match_type = 'equality'
|
67
|
-
transaction.coa_code = coa.code
|
68
|
-
transaction
|
69
|
-
end
|
70
|
-
|
71
|
-
def start_with_match(transaction)
|
72
|
-
coa = config.bank_reconciliation.chart_of_accounts.find do |chart_of_account|
|
73
|
-
transaction.narration.to_s.delete(' ').downcase.start_with?(chart_of_account.narration.to_s.downcase)
|
74
|
-
end
|
75
|
-
|
76
|
-
return nil unless coa
|
77
|
-
|
78
|
-
transaction.coa_match_type = 'starts_with'
|
79
|
-
transaction.coa_code = coa.code
|
80
|
-
transaction
|
81
|
-
end
|
82
|
-
|
83
|
-
def includes(transaction)
|
84
|
-
coa = config.bank_reconciliation.chart_of_accounts.find do |chart_of_account|
|
85
|
-
transaction.narration.to_s.delete(' ').downcase.include?(chart_of_account.narration.delete(' ').to_s.downcase)
|
86
|
-
end
|
87
|
-
|
88
|
-
return nil unless coa
|
89
|
-
|
90
|
-
transaction.coa_match_type = 'includes'
|
91
|
-
transaction.coa_code = coa.code
|
92
|
-
transaction
|
93
|
-
end
|
94
|
-
|
95
|
-
def trigram_match(transaction, score_threshold, match_type)
|
96
|
-
scored_transactions = config.bank_reconciliation.chart_of_accounts.map do |coa|
|
97
|
-
{
|
98
|
-
coa: coa,
|
99
|
-
score: compare(coa.narration, transaction.narration)
|
100
|
-
}
|
101
|
-
end
|
102
|
-
|
103
|
-
scored_transactions.sort_by! { |t| t[:score] }.reverse!
|
104
|
-
|
105
|
-
best = scored_transactions.first
|
106
|
-
|
107
|
-
return nil unless best
|
108
|
-
return nil if best[:score] < score_threshold
|
109
|
-
|
110
|
-
coa = best[:coa]
|
111
|
-
|
112
|
-
transaction.coa_match_type = match_type
|
113
|
-
transaction.coa_code = coa.code
|
114
|
-
transaction
|
115
|
-
end
|
116
|
-
|
117
|
-
def compare(text1, text2)
|
118
|
-
text1_trigs = trigramify(text1)
|
119
|
-
text2_trigs = trigramify(text2)
|
120
|
-
|
121
|
-
all_cnt = (text1_trigs | text2_trigs).size
|
122
|
-
same_cnt = (text1_trigs & text2_trigs).size
|
123
|
-
|
124
|
-
same_cnt.to_f / all_cnt
|
125
|
-
end
|
126
|
-
|
127
|
-
def trigramify(text)
|
128
|
-
trigs = []
|
129
|
-
text.chars.each_cons(3) { |v| trigs << v.join }
|
130
|
-
trigs
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appydave
|
4
|
-
module Tools
|
5
|
-
module BankReconciliation
|
6
|
-
module Clean
|
7
|
-
# Read transactions from a CSV file
|
8
|
-
class ReadTransactions
|
9
|
-
attr_reader :platform
|
10
|
-
attr_reader :transactions
|
11
|
-
|
12
|
-
def initialize(file)
|
13
|
-
@file = file
|
14
|
-
end
|
15
|
-
|
16
|
-
def read
|
17
|
-
csv_lines = File.read(@file).lines
|
18
|
-
|
19
|
-
@platform = detect_platform(csv_lines)
|
20
|
-
|
21
|
-
case platform
|
22
|
-
when :bankwest
|
23
|
-
read_bankwest(csv_lines)
|
24
|
-
when :bankwest2
|
25
|
-
read_bankwest2(csv_lines)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def read_bankwest(csv_lines)
|
32
|
-
@transactions = []
|
33
|
-
|
34
|
-
# Skip the header line and parse each subsequent line
|
35
|
-
CSV.parse(csv_lines.join, headers: true).each do |row|
|
36
|
-
transaction = Models::Transaction.new(
|
37
|
-
bsb_number: row['BSB Number'],
|
38
|
-
account_number: row['Account Number'],
|
39
|
-
transaction_date: row['Transaction Date'],
|
40
|
-
narration: row['Narration'],
|
41
|
-
cheque_number: row['Cheque Number'],
|
42
|
-
debit: row['Debit'],
|
43
|
-
credit: row['Credit'],
|
44
|
-
balance: row['Balance'],
|
45
|
-
transaction_type: row['Transaction Type']
|
46
|
-
)
|
47
|
-
@transactions << transaction
|
48
|
-
end
|
49
|
-
|
50
|
-
@transactions
|
51
|
-
end
|
52
|
-
|
53
|
-
def read_bankwest2(csv_lines)
|
54
|
-
@transactions = []
|
55
|
-
|
56
|
-
# Skip the header line and parse each subsequent line
|
57
|
-
CSV.parse(csv_lines.join, headers: true).each do |row|
|
58
|
-
transaction = Models::Transaction.new(
|
59
|
-
bsb_number: row['BSB / Account Number'].split(' - ').first,
|
60
|
-
account_number: row['BSB / Account Number'].split(' - ').last,
|
61
|
-
transaction_date: row['Transaction Date'],
|
62
|
-
narration: row['Narration'],
|
63
|
-
cheque_number: row['Cheque Number'],
|
64
|
-
debit: row['Debit'],
|
65
|
-
credit: row['Credit'],
|
66
|
-
balance: row['Balance'],
|
67
|
-
transaction_type: row['Transaction Type']
|
68
|
-
)
|
69
|
-
@transactions << transaction
|
70
|
-
end
|
71
|
-
|
72
|
-
@transactions
|
73
|
-
end
|
74
|
-
|
75
|
-
# For bankwest the first row is the CSV will look like:
|
76
|
-
# BSB Number,Account Number,Transaction Date,Narration,Cheque Number,Debit,Credit,Balance,Transaction Type
|
77
|
-
def detect_platform(csv_lines)
|
78
|
-
return :bankwest if csv_lines.first.start_with?('BSB Number,Account Number,Transaction Date,Narration,Cheque Number,Debit,Credit,Balance,Transaction Type')
|
79
|
-
return :bankwest2 if csv_lines.first.start_with?('Account Name,BSB / Account Number,Transaction Date,Narration,Cheque Number,Debit,Credit,Balance,Transaction Type')
|
80
|
-
|
81
|
-
puts "Unknown platform detected. CSV columns are: #{csv_lines.first.strip}"
|
82
|
-
raise Appydave::Tools::Error, 'Unknown platform'
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appydave
|
4
|
-
module Tools
|
5
|
-
module BankReconciliation
|
6
|
-
module Models
|
7
|
-
# Unified transaction model for raw and reconciled data
|
8
|
-
class Transaction
|
9
|
-
attr_accessor :bsb_number,
|
10
|
-
:account_number,
|
11
|
-
:transaction_date,
|
12
|
-
:narration,
|
13
|
-
:cheque_number,
|
14
|
-
:debit,
|
15
|
-
:credit,
|
16
|
-
:balance,
|
17
|
-
:transaction_type,
|
18
|
-
:platform,
|
19
|
-
:coa_code,
|
20
|
-
:coa_match_type,
|
21
|
-
:account_name
|
22
|
-
|
23
|
-
def initialize(bsb_number: nil,
|
24
|
-
account_number: nil,
|
25
|
-
transaction_date: nil,
|
26
|
-
narration: nil,
|
27
|
-
cheque_number: nil,
|
28
|
-
debit: nil,
|
29
|
-
credit: nil,
|
30
|
-
balance: nil,
|
31
|
-
transaction_type: nil,
|
32
|
-
platform: nil,
|
33
|
-
coa_code: nil,
|
34
|
-
coa_match_type: nil,
|
35
|
-
account_name: nil)
|
36
|
-
@bsb_number = bsb_number&.strip
|
37
|
-
@account_number = account_number&.strip
|
38
|
-
@transaction_date = transaction_date&.strip
|
39
|
-
@transaction_date = Date.strptime(@transaction_date, '%d/%m/%Y')
|
40
|
-
@narration = narration&.gsub(/\s{2,}/, ' ')&.strip
|
41
|
-
@cheque_number = cheque_number&.strip
|
42
|
-
@debit = debit&.strip
|
43
|
-
@credit = credit&.strip
|
44
|
-
@balance = balance&.strip
|
45
|
-
@transaction_type = transaction_type&.strip
|
46
|
-
@platform = platform
|
47
|
-
@coa_code = coa_code
|
48
|
-
@coa_match_type = coa_match_type
|
49
|
-
@account_name = account_name
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.csv_headers
|
53
|
-
%i[
|
54
|
-
bsb_number
|
55
|
-
account_number
|
56
|
-
transaction_date
|
57
|
-
narration
|
58
|
-
cheque_number
|
59
|
-
debit
|
60
|
-
credit
|
61
|
-
balance
|
62
|
-
transaction_type
|
63
|
-
platform
|
64
|
-
coa_code
|
65
|
-
coa_match_type
|
66
|
-
account_name
|
67
|
-
]
|
68
|
-
end
|
69
|
-
|
70
|
-
def to_csv_row
|
71
|
-
[
|
72
|
-
@bsb_number,
|
73
|
-
@account_number,
|
74
|
-
@transaction_date,
|
75
|
-
@narration,
|
76
|
-
@cheque_number,
|
77
|
-
@debit,
|
78
|
-
@credit,
|
79
|
-
@balance,
|
80
|
-
@transaction_type,
|
81
|
-
@platform,
|
82
|
-
@coa_code,
|
83
|
-
@coa_match_type,
|
84
|
-
@account_name
|
85
|
-
]
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Appydave
|
4
|
-
module Tools
|
5
|
-
module Configuration
|
6
|
-
module Models
|
7
|
-
# Bank reconciliation configuration
|
8
|
-
class BankReconciliationConfig < ConfigBase
|
9
|
-
# def
|
10
|
-
# Retrieve all bank accounts
|
11
|
-
def bank_accounts
|
12
|
-
data['bank_accounts'].map do |account|
|
13
|
-
BankAccount.new(account)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def chart_of_accounts
|
18
|
-
data['chart_of_accounts'].map do |entry|
|
19
|
-
ChartOfAccount.new(entry)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def get_bank_account(account_number, bsb = nil)
|
24
|
-
account_data = data['bank_accounts'].find do |account|
|
25
|
-
account['account_number'] == account_number && (account['bsb'].nil? || account['bsb'] == bsb)
|
26
|
-
end
|
27
|
-
|
28
|
-
BankAccount.new(account_data) if account_data
|
29
|
-
end
|
30
|
-
|
31
|
-
# Retrieve a chart of account entry by code
|
32
|
-
def get_chart_of_account(code)
|
33
|
-
entry_data = data['chart_of_accounts'].find { |entry| entry['code'] == code }
|
34
|
-
ChartOfAccount.new(entry_data) if entry_data
|
35
|
-
end
|
36
|
-
|
37
|
-
def print
|
38
|
-
log.subheading 'Bank Reconciliation - Accounts'
|
39
|
-
|
40
|
-
tp bank_accounts, :account_number, :bsb, :name, :bank
|
41
|
-
|
42
|
-
log.subheading 'Bank Reconciliation - Chart of Accounts'
|
43
|
-
|
44
|
-
tp chart_of_accounts, :code, :narration
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def default_data
|
50
|
-
{
|
51
|
-
'bank_accounts' => [],
|
52
|
-
'chart_of_accounts' => []
|
53
|
-
}
|
54
|
-
end
|
55
|
-
|
56
|
-
# Inner class to represent a bank account
|
57
|
-
class BankAccount
|
58
|
-
attr_accessor :account_number, :bsb, :name, :platform
|
59
|
-
|
60
|
-
def initialize(data)
|
61
|
-
@account_number = data['account_number']
|
62
|
-
@bsb = data['bsb']
|
63
|
-
@name = data['name']
|
64
|
-
@platform = data['platform']
|
65
|
-
end
|
66
|
-
|
67
|
-
def to_h
|
68
|
-
{
|
69
|
-
'account_number' => @account_number,
|
70
|
-
'bsb' => @bsb,
|
71
|
-
'name' => @name,
|
72
|
-
'platform' => @platform
|
73
|
-
}
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Inner class to represent a chart of account entry
|
78
|
-
class ChartOfAccount
|
79
|
-
attr_accessor :code, :narration
|
80
|
-
|
81
|
-
def initialize(data)
|
82
|
-
@code = data['code']
|
83
|
-
@narration = data['narration']
|
84
|
-
end
|
85
|
-
|
86
|
-
def to_h
|
87
|
-
{
|
88
|
-
'code' => @code,
|
89
|
-
'narration' => @narration
|
90
|
-
}
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|