simple_drilldown 0.7.2 → 0.8.2

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: cee0cdbb64ae05c37521d974dba3f99c1ca6e3d459ff43d898f7bf5554227124
4
- data.tar.gz: 91532c9f27039c5f117a1c1a1fa43fb7bbcf3484dd4248b4207bd7d921f65d55
3
+ metadata.gz: 02a013f2b885c10991f53c854f8d127147b9ad141e1e80d80b2edef5ee7a2e8a
4
+ data.tar.gz: 949351a24e5171784d0c608126e835a19d736e8bd0248b8816728c37528632be
5
5
  SHA512:
6
- metadata.gz: b04ed3837f8f104088992a942557d50ab3889f1e5264662f27705b568f4828b29e9b9fd0c485babdf66ebf774613fea3d1a4a6d0ff13b6adb73bcc1f3a7eb796
7
- data.tar.gz: 2e685226b70f9472f530669f88f35517044499acce6a88b005bf2e0181a8643d8558190eeb038996c68e3e457de52573d68bc2ab59c669d8ca85a6ab572dc6db
6
+ metadata.gz: 3f0f84cedda3f43e60380c4ac010f7c0f5643c9e1e384efcafb86e2583d1a44e4920368c81a26542018b448960d3b3f89dcebd5f0682fd28064a00ce73f0fb4c
7
+ data.tar.gz: 749dab308a7a85d6cb5d8ae55f5ec4449d90e2c81b81ca1642fd6e048bf2a5730a7e6992f8eb0204762b067c1c371b6b743c38f071cb3de9bddfe16ec0f53a4a
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ def excel_header_row(sheet)
4
+ padding_cells = @dimensions.empty? ? 1 : @dimensions.size
5
+ row = (1...(padding_cells - 1)).map { |_n| nil }
6
+ @search.fields.each_with_index { |field, _i| row << t(field) }
7
+ sheet.add_row row
8
+ end
9
+
10
+ def excel_row(sheet, wrap, transaction:)
11
+ padding_cells = @dimensions.empty? ? 1 : @dimensions.size
12
+ row = (1..(padding_cells - 1)).map { |_n| nil }
13
+
14
+ @search.fields.each_with_index do |field, _i|
15
+ value = if field == 'time'
16
+ (transaction.respond_to?(:completed_at) ? transaction.completed_at : transaction.created_at)
17
+ .localtime.strftime('%Y-%m-%d %H:%M')
18
+ elsif controller.c_fields[field.to_sym][:attr_method]
19
+ controller.c_fields[field.to_sym][:attr_method].call(transaction)
20
+ else
21
+ transaction.send(field)
22
+ end
23
+
24
+ field_def = controller.c_fields[field.to_sym]
25
+ if @search.list_change_times && field_def[:list_change_times] && transaction.assignment.try(:order)
26
+ changes = transaction.assignment.order.send("#{field}_changes")
27
+ .map do |al|
28
+ [al.created_at.localtime.strftime('%H:%M'),
29
+ PacMan.yaml_load(al.new_values).symbolize_keys[field.to_sym]]
30
+ end
31
+ last_change = changes.last.try(:[], 1)
32
+ value =
33
+ "#{changes.map { |al| al.join(' ') }.join("\n")}#{"\nActual: #{value}" if value != last_change}"
34
+ end
35
+
36
+ row << value
37
+ end
38
+ sheet.add_row row, style: wrap
39
+ end
40
+
41
+ sheet.add_row []
42
+ excel_header_row(sheet)
43
+ wrap = sheet.styles.add_style alignment: { wrap_text: true }
44
+ result[:records].each { |t| excel_row(sheet, wrap, transaction: t) }
45
+ sheet.add_row []
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ row = [
4
+ *(1..(dimension - headers.size - 1)).map { |_n| '' },
5
+ *headers.map.with_index { |h, i| value_label(@dimensions.size - headers.size + i - 1, h[:value]) },
6
+ *(value_label(dimension - 1, result[:value]) if dimension.positive?),
7
+ *((result[:count].to_f / parent_result[:count]).inspect if parent_result && @search.percent),
8
+ result[:count].inspect,
9
+ *(if parent_result && @search.percent
10
+ (
11
+ if parent_result[controller.c_summary_fields[0]].positive?
12
+ result[controller.c_summary_fields[0]].to_f / parent_result[controller.c_summary_fields[0]]
13
+ else
14
+ 0
15
+ end).inspect
16
+ end),
17
+ result[controller.c_summary_fields[0]].inspect
18
+ ]
19
+ if controller.c_summary_fields.size > 1
20
+ if parent_result && @search.percent
21
+ percent =
22
+ if parent_result[controller.c_summary_fields[1]].positive?
23
+ result[controller.c_summary_fields[1]].to_f / parent_result[controller.c_summary_fields[1]]
24
+ else
25
+ 0
26
+ end
27
+ row << percent.inspect
28
+ end
29
+ row << result[controller.c_summary_fields[1]].inspect
30
+ end
31
+ sheet.add_row row
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ row = (1..dimension).map { |_n| nil }
4
+
5
+ (@dimensions.size - dimension).times { |_i| row << nil }
6
+ row << result[:count]
7
+ sheet.add_row row
@@ -1,2 +1,3 @@
1
1
  <%= link_to 'Excel', @search.url_options.merge(action: :excel_export) %>&nbsp;|
2
+ <%= link_to 'Excel (XML)', @search.url_options.merge(action: :excel_export, format: :xml) %>&nbsp;|
2
3
  <%= link_to 'HTML', @search.url_options.merge(action: :html_export), data_popup: ['Elections', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes, width=1024px'] %>
@@ -1,11 +1,13 @@
1
1
  <% unless result[:records].empty? %>
2
2
  <tr>
3
3
  <td colspan="<%= controller.c_summary_fields.size + 1 %>">
4
- <table class="table table-condensed table-bordered" style="padding-bottom: 10px;">
4
+ <table id="drilldown-records-<%= result[:value] %>" class="table table-condensed table-bordered" style="padding-bottom: 10px;">
5
5
  <%= render :partial => '/drilldown/row_header' %>
6
- <% result[:records].each do |t| %>
7
- <%= render :partial => '/drilldown/row', :locals => { :transaction => t, :previous_transaction => nil, :errors => [], :error_row => false, :meter1_errors => false } %>
8
- <% end %>
6
+ <tbody>
7
+ <% result[:records].each do |t| %>
8
+ <%= render :partial => '/drilldown/row', :locals => { :transaction => t, :previous_transaction => nil, :errors => [], :error_row => false, :meter1_errors => false } %>
9
+ <% end %>
10
+ </tbody>
9
11
  </table>
10
12
  </td>
11
13
  </tr>
@@ -1,12 +1,14 @@
1
- <table class="table table-condensed table-bordered">
2
- <tr>
3
- <% @dimensions.each do |d| %>
4
- <th><%=h d[:pretty_name]%></th>
5
- <% end %>
6
- <th><%= t controller.c_target_class.table_name.capitalize %></th>
7
- <%= controller.c_summary_fields.map{|l| "<th>#{t(l)}</th>"}.join("\n").html_safe %>
8
- </tr>
9
-
10
- <%=summary_row(@result) %>
11
-
1
+ <table id="drilldown-summary-table" class="table table-condensed table-bordered">
2
+ <thead>
3
+ <tr>
4
+ <% @dimensions.each do |d| %>
5
+ <th><%= h d[:pretty_name] %></th>
6
+ <% end %>
7
+ <th><%= t controller.c_target_class.table_name.capitalize %></th>
8
+ <%= controller.c_summary_fields.map { |l| "<th>#{t(l)}</th>" }.join("\n").html_safe %>
9
+ </tr>
10
+ </thead>
11
+ <tbody>
12
+ <%= summary_row(@result) %>
13
+ </tbody>
12
14
  </table>
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ def excel_summary_row_xlsx(sheet, result, parent_result = nil, dimension = 0, headers = [])
4
+ if result[:rows]
5
+ significant_rows = result[:rows].reject { |r| r[:row_count].zero? }
6
+ significant_rows.each_with_index do |r, i|
7
+ sub_headers =
8
+ if i.zero?
9
+ if dimension.zero?
10
+ headers
11
+ else
12
+ headers + [{
13
+ value: result[:value],
14
+ display_row_count: result[:nodes] + result[:row_count] * (@search.list ? 1 : 0)
15
+ }]
16
+ end
17
+ else
18
+ [] # [{:value => result[:value], :row_count => result[:row_count]}]
19
+ end
20
+ excel_summary_row_xlsx(sheet, r, result, dimension + 1, sub_headers)
21
+ end
22
+ else
23
+ render(partial: '/drilldown/excel_summary_row_xlsx',
24
+ locals: { sheet: sheet, result: result, parent_result: parent_result, headers: headers.dup,
25
+ dimension: dimension })
26
+
27
+ if @search.list
28
+ render(partial: '/drilldown/excel_record_list_xlsx',
29
+ locals: { sheet: sheet, result: result })
30
+ end
31
+ end
32
+
33
+ return if dimension >= @dimensions.size
34
+
35
+ render(partial: '/drilldown/excel_summary_total_row_xlsx', locals: {
36
+ sheet: sheet, result: result, headers: headers.dup, dimension: dimension
37
+ })
38
+ end
39
+
40
+ xlsx_package.use_shared_strings = true
41
+ wb = xlsx_package.workbook
42
+ wb.add_worksheet(name: 'Transaction Summary') do |sheet|
43
+ # header_colspan =
44
+ # if @search.list
45
+ # [@dimensions.size - 1, 0].max + @search.fields.size - 1
46
+ # else
47
+ # @dimensions.size - 1 + (controller.c_summary_fields.size + 1) * (@search.percent ? 2 : 1)
48
+ # end
49
+
50
+ # xml.Row 'ss:Height' => '18.75' do
51
+ # xml.Cell 'ss:MergeAcross' => header_colspan, 'ss:StyleID' => 'MainTitle' do
52
+ # xml.Data caption, 'ss:Type' => 'String'
53
+ # end
54
+ # end
55
+ sheet.add_row [caption]
56
+
57
+ # xml.Row 'ss:Height' => '15.75' do
58
+ # xml.Cell 'ss:MergeAcross' => header_colspan, 'ss:StyleID' => 'SubTitle' do
59
+ # xml.Data subcaption, 'ss:Type' => 'String'
60
+ # end
61
+ # end
62
+ sheet.add_row [subcaption]
63
+
64
+ # xml.Row do
65
+ # @dimensions.each do |d|
66
+ # xml.Cell 'ss:StyleID' => 'DimensionHeading' do
67
+ # xml.Data (h d[:pretty_name]).to_s, 'ss:Type' => 'String'
68
+ # end
69
+ # end
70
+ # xml.Cell 'ss:StyleID' => 'Heading', 'ss:MergeAcross' => @search.percent ? 1 : 0 do
71
+ # xml.Data t(controller.c_target_class.table_name), 'ss:Type' => 'String'
72
+ # end
73
+ # controller.c_summary_fields.each do |f|
74
+ # xml.Cell 'ss:StyleID' => 'Heading', 'ss:MergeAcross' => @search.percent ? 1 : 0 do
75
+ # xml.Data f, 'ss:Type' => 'String'
76
+ # end
77
+ # end
78
+ # end
79
+ sheet.add_row [
80
+ *@dimensions.map { |d| (h d[:pretty_name]).to_s },
81
+ t(controller.c_target_class.table_name),
82
+ *controller.c_summary_fields.map { |f| f }
83
+ ]
84
+
85
+ excel_summary_row_xlsx(sheet, @result)
86
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'caxlsx_rails'
3
4
  require 'simple_drilldown/engine'
4
5
 
5
6
  module SimpleDrilldown
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SimpleDrilldown
4
+ # Allow tracking changes for a field
5
+ module Changes
6
+ def self.included(clazz)
7
+ clazz.extend ClassMethods
8
+ end
9
+
10
+ # Class methods for Changes
11
+ module ClassMethods
12
+ def changes_for(*fields)
13
+ fields.each do |field|
14
+ condition_proc = lambda do
15
+ in_join = is_a?(ActiveRecord::Associations::JoinDependency::JoinAssociation)
16
+ table_alias = in_join ? aliased_table_name : AuditLog.table_name
17
+ "#{table_alias}.new_values LIKE '%#{field}%'"
18
+ end
19
+ has_many :"#{field}_changes", -> { where(condition_proc.call).order(:created_at) },
20
+ class_name: :AuditLog, foreign_key: :record_id
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -15,7 +15,7 @@ module SimpleDrilldown
15
15
  class_attribute :c_default_fields, default: []
16
16
  class_attribute :c_default_select_value, default: SimpleDrilldown::Search::SelectValue::COUNT
17
17
  class_attribute :c_dimension_defs
18
- class_attribute :c_fields
18
+ class_attribute :c_fields, default: []
19
19
  class_attribute :c_list_includes, default: []
20
20
  class_attribute :c_list_order
21
21
  class_attribute :c_select, default: 'count(*) as count'
@@ -36,6 +36,9 @@ module SimpleDrilldown
36
36
  # No default target class found
37
37
  end
38
38
  end
39
+ return unless base.c_target_class.try :paranoid?
40
+
41
+ base.c_base_condition = "#{base.c_target_class.table_name}.deleted_at IS NULL"
39
42
  end
40
43
 
41
44
  def base_condition(base_condition)
@@ -150,14 +153,15 @@ module SimpleDrilldown
150
153
  end
151
154
  includes.uniq!
152
155
  end
153
- rows = c_target_class.unscoped.where(c_base_condition)
154
- .select("#{query[:select]} AS value")
155
- .where(filter_conditions || '1=1')
156
- .where(query[:where] || '1=1')
157
- .joins(make_join([], c_target_class.name.underscore.to_sym, includes))
158
- .order('value')
159
- .group(:value)
160
- .to_a
156
+ rows_query = c_target_class.unscoped.where(c_base_condition)
157
+ .select("#{query[:select]} AS value")
158
+ .joins(make_join([], c_target_class.name.underscore.to_sym, includes))
159
+ .order('value')
160
+ .group(:value)
161
+ # rows_query = rows_query.without_deleted if c_target_class.try :paranoid?
162
+ rows_query = rows_query.where(filter_conditions) if filter_conditions
163
+ rows_query = rows_query.where(query[:where]) if query[:where]
164
+ rows = rows_query.to_a
161
165
  filter_fields = search.filter[field.to_s]
162
166
  filter_fields&.each do |selected_value|
163
167
  next if rows.find { |r| r[:value].to_s == selected_value }
@@ -271,7 +275,8 @@ module SimpleDrilldown
271
275
  ass_order_prefixed.gsub!(/\b#{cname}\b/, "#{include_alias}.#{cname}")
272
276
  end
273
277
  paranoid_clause = 'AND t2.deleted_at IS NULL' if ass.klass.paranoid?
274
- # FIXME(uwe): Should we add "where" from the ScopeHolder here as well? Ref: DrilldownChanges#changes_for
278
+ # FIXME(uwe): Should we add "where" from the ScopeHolder here as well?
279
+ # Ref: SimpleDrilldown::Changes#changes_for
275
280
  min_query = <<~SQL
276
281
  SELECT MIN(#{ass_order}) FROM #{include_table} t2 WHERE t2.#{fk_col} = #{model_table}.id #{paranoid_clause}
277
282
  SQL
@@ -320,6 +325,7 @@ module SimpleDrilldown
320
325
 
321
326
  conditions, @filter_text, filter_includes = self.class.make_conditions(@search.filter)
322
327
  includes += filter_includes
328
+ includes.flatten!
323
329
  includes.keep_if(&:present?).uniq!
324
330
  if @search.order_by_value && @dimensions.size <= 1
325
331
  order = case @search.select_value
@@ -343,8 +349,8 @@ module SimpleDrilldown
343
349
  rows = c_target_class.unscoped.where(c_base_condition).select(select).where(conditions)
344
350
  .joins(joins)
345
351
  .group(group)
346
- .order(order).to_a
347
-
352
+ .order(order)
353
+ .to_a
348
354
  if rows.empty?
349
355
  @result = { value: 'All', count: 0, row_count: 0, nodes: 0, rows: [] }
350
356
  c_summary_fields.each { |f| @result[f] = 0 }
@@ -391,12 +397,19 @@ module SimpleDrilldown
391
397
 
392
398
  def excel_export
393
399
  index(false)
394
- set_excel_headers
395
- if params.dig(:search, :list) == '1'
396
- @records = get_records(@result)
397
- render template: '/drilldown/excel_export_records', layout: false
398
- else
399
- render template: '/drilldown/excel_export', layout: false
400
+ respond_to do |format|
401
+ format.xlsx do
402
+ render xlsx: c_target_class.table_name, template: 'drilldown/excel_export_xlsx'
403
+ end
404
+ format.xml do
405
+ set_excel_headers
406
+ if params.dig(:search, :list) == '1'
407
+ @records = get_records(@result)
408
+ render template: 'drilldown/excel_export_records', layout: false
409
+ else
410
+ render template: 'drilldown/excel_export', layout: false
411
+ end
412
+ end
400
413
  end
401
414
  end
402
415
 
@@ -38,7 +38,7 @@ module SimpleDrilldown
38
38
  html << summary_row(r, result, dimension + 1, sub_headers, i.positive?)
39
39
  end
40
40
  elsif @search.list
41
- html << render(partial: '/drilldown/record_list', locals: { result: result })
41
+ html << render(partial: '/drilldown/record_list', locals: { result: result, dimension: dimension })
42
42
  end
43
43
  if dimension < @dimensions.size
44
44
  html << render(partial: '/drilldown/summary_total_row',
@@ -89,7 +89,7 @@ module SimpleDrilldown
89
89
  private
90
90
 
91
91
  def caption_txt
92
- "#{controller.c_target_class} #{t(@search.select_value.downcase)}" +
92
+ "#{controller.c_target_class} #{I18n.t(@search.select_value.downcase)}" +
93
93
  (@dimensions && @dimensions.any? ? " by #{@dimensions.map { |d| d[:pretty_name] }.join(' and ')}" : '')
94
94
  end
95
95
  end
@@ -8,8 +8,11 @@ module SimpleDrilldown
8
8
  controller ||= path
9
9
  get "#{path}(.:format)" => "#{controller}#index", as: path
10
10
  scope path, controller: controller, as: path do
11
- %i[excel_export excel_export_records html_export].each { |action| get action }
12
- get "choices/:dimension_name", action: :choices, as: :choices
11
+ { excel_export: :xlsx, excel_export_records: :xlsx, html_export: :html }.each do |action, format|
12
+ get action, defaults: { format: format }
13
+ end
14
+ get 'choices/:dimension_name', action: :choices, as: :choices
15
+ yield if block_given?
13
16
  end
14
17
  end
15
18
  end
@@ -81,15 +81,15 @@ module SimpleDrilldown
81
81
 
82
82
  def url_options
83
83
  o = {
84
- search: {
85
- title: title,
86
- list: list ? '1' : '0',
87
- percent: percent ? '1' : '0',
88
- list_change_times: list_change_times ? '1' : '0',
89
- filter: filter,
90
- dimensions: dimensions,
91
- display_type: display_type,
92
- },
84
+ search: {
85
+ title: title,
86
+ list: list ? '1' : '0',
87
+ percent: percent ? '1' : '0',
88
+ list_change_times: list_change_times ? '1' : '0',
89
+ filter: filter,
90
+ dimensions: dimensions,
91
+ display_type: display_type,
92
+ },
93
93
  }
94
94
  o[:search][:fields] = fields unless fields == @default_fields
95
95
  o
@@ -1,3 +1,3 @@
1
1
  module SimpleDrilldown
2
- VERSION = '0.7.2'
2
+ VERSION = '0.8.2'
3
3
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_drilldown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.8.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uwe Kubosch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-03 00:00:00.000000000 Z
11
+ date: 2021-03-23 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: caxlsx_rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.6'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: chartkick
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -91,12 +105,13 @@ files:
91
105
  - app/mailers/simple_drilldown/application_mailer.rb
92
106
  - app/models/simple_drilldown/application_record.rb
93
107
  - app/views/drilldown/_chart.html.erb
94
- - app/views/drilldown/_excel_record_list.builder
95
- - app/views/drilldown/_excel_row.builder
108
+ - app/views/drilldown/_excel_record_list_xlsx.xlsx.axlsx
96
109
  - app/views/drilldown/_excel_row_header.builder
97
110
  - app/views/drilldown/_excel_styles.builder
98
111
  - app/views/drilldown/_excel_summary_row.builder
112
+ - app/views/drilldown/_excel_summary_row_xlsx.xlsx.axlsx
99
113
  - app/views/drilldown/_excel_summary_total_row.builder
114
+ - app/views/drilldown/_excel_summary_total_row_xlsx.xlsx.axlsx
100
115
  - app/views/drilldown/_export_links.html.erb
101
116
  - app/views/drilldown/_field.html.erb
102
117
  - app/views/drilldown/_fields.html.erb
@@ -114,6 +129,7 @@ files:
114
129
  - app/views/drilldown/data_3.builder
115
130
  - app/views/drilldown/excel_export.builder
116
131
  - app/views/drilldown/excel_export_records.builder
132
+ - app/views/drilldown/excel_export_xlsx.xlsx.axlsx
117
133
  - app/views/drilldown/html_export.html.erb
118
134
  - app/views/drilldown/index.html.erb
119
135
  - app/views/drilldown/print.html.erb
@@ -126,6 +142,7 @@ files:
126
142
  - lib/generators/drilldown_controller/templates/drilldown_controller.rb.erb
127
143
  - lib/generators/drilldown_controller/templates/drilldown_controller_test.rb.erb
128
144
  - lib/simple_drilldown.rb
145
+ - lib/simple_drilldown/changes.rb
129
146
  - lib/simple_drilldown/controller.rb
130
147
  - lib/simple_drilldown/engine.rb
131
148
  - lib/simple_drilldown/helper.rb
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- xml << render(partial: '/drilldown/excel_row_header')
4
-
5
- result[:records].each do |t|
6
- xml << render(
7
- partial: '/drilldown/excel_row',
8
- locals: { transaction: t, previous_transaction: nil, errors: [], error_row: false, meter1_errors: false }
9
- )
10
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- xml.Row do
4
- padding_cells = @dimensions.empty? ? 1 : @dimensions.size
5
- 1.upto(padding_cells - 1) { |_n| xml.Cell('ss:StyleID' => 'Outer') }
6
-
7
- @search.fields.each_with_index do |field, i|
8
- if field == 'time'
9
- value = ((
10
- if transaction.respond_to?(:completed_at)
11
- transaction.completed_at
12
- else
13
- transaction.created_at
14
- end)).localtime.strftime('%Y-%m-%d %H:%M')
15
- else
16
- value = if @transaction_fields_map[field.to_sym][:attr_method]
17
- @transaction_fields_map[field.to_sym][:attr_method].call(transaction)
18
- else
19
- transaction.send(field)
20
- end
21
- end
22
-
23
- field_def = @transaction_fields_map[field.to_sym]
24
-
25
- xml.Cell('ss:Index' => (padding_cells + i).to_s) do
26
- xml.Data value, 'ss:Type' => 'String'
27
- end
28
- end
29
- end