-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtransform_csv.rb
More file actions
145 lines (116 loc) · 4.34 KB
/
Copy pathtransform_csv.rb
File metadata and controls
145 lines (116 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
require 'csv'
require 'time'
# Load configuration from options CSV
def load_options_config
options = []
CSV.foreach('./data/config/options.csv', headers: true) do |row|
options << {
origin: row['Origin'],
target: row['Target']
}
end
options
end
# Find the correct category based on the rules
def find_category(labels, category_name, options)
category = nil
labels.each do |label|
match = options.find { |opt| opt[:origin] == label }
if match
category = match[:target]
end
end
# Fallback to the original Category name if no match is found
category ||= category_name
category
end
# Convert transaction date to CST and format as YYYY-MM-DD
def convert_to_cst(date_str)
# Parse the string into a Time object
date = Time.parse(date_str)
# Convert the time to Central Standard Time (CST) without daylight saving
cst_time = date.getlocal('-06:00')
# Format the time as YYYY-MM-DD
cst_time.strftime('%Y-%m-%d')
end
# Process the source transactions CSV and apply the transformations
def transform_transactions(file_path, options)
transformed_data = []
CSV.foreach(file_path, headers: true) do |row|
tags_in_note = row['Note']&.scan(/#\w+/)&.map { |tag| tag[1..] } || []
# Parse and transform the columns according to the rules
date = convert_to_cst(row['Date'])
wallet = row['Wallet']
type = row['Type'].downcase == 'incoming transfer' || row['Type'].downcase == 'outgoing transfer' ? 'transfer' : row['Type'].downcase
category_name = row['Category name']
amount = row['Amount']
currency = row['Currency']
description = row['Note']
tags = (tags_in_note + (row['Labels']&.split(',')&.map(&:strip) || [])).uniq.map { |tag| tag.gsub(/(?<!^)(?=[A-Z])/, ' ').downcase }.join(',')
labels = row['Labels']&.split(',')&.map(&:strip) || []
# Find the correct category based on labels and configuration
category = find_category(labels, category_name, options)
# Construct the transformed row
transformed_data << {
date: date,
wallet: wallet,
type: type,
category: category,
amount: amount,
currency: currency,
description: description,
label: category_name,
tags: tags
}
end
transformed_data
end
# Export the transformed data to CSV, splitting into multiple files if needed
def export_to_csv(transformed_data, output_file_path)
# Split data into chunks of 1000 rows
chunks = transformed_data.each_slice(250).to_a
chunks.each_with_index do |chunk, index|
# Generate the output filename with index if there are multiple chunks
current_output_path = chunks.length > 1 ?
output_file_path.gsub('.csv', "_#{index + 1}.csv") :
output_file_path
CSV.open(current_output_path, 'wb') do |csv|
csv << %w[date wallet type category amount currency description label tags] # Header row
chunk.each do |row|
csv << [row[:date], row[:wallet], row[:type], row[:category], row[:amount], row[:currency], row[:description],
row[:label], row[:tags]]
end
end
puts "Exported chunk #{index + 1} of #{chunks.length} to: #{current_output_path}"
end
end
# Process all files in the given directory and export transformed files to output directory
def process_directory(input_dir, output_dir, options)
Dir.foreach(input_dir) do |filename|
next if ['.', '..'].include?(filename) # Skip special directories
file_path = File.join(input_dir, filename)
# Process only CSV files
if File.file?(file_path) && File.extname(filename) == '.csv'
puts "Processing file: #{filename}"
# Transform the data
transformed_data = transform_transactions(file_path, options)
# Prepare the output path
output_file_path = File.join(output_dir, filename)
# Export the transformed data (will be split if needed)
export_to_csv(transformed_data, output_file_path)
end
end
end
# Main process
def main
# Define the input and output directories
input_dir = './data/input' # Change this path as needed
output_dir = './data/output' # Change this path as needed
# Create the output directory if it doesn't exist
Dir.mkdir(output_dir) unless Dir.exist?(output_dir)
# Load the configuration options
options = load_options_config
# Process all files in the input directory
process_directory(input_dir, output_dir, options)
end
main