clevic 0.12.0 → 0.13.0.b1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Manifest.txt +209 -30
- data/README.txt +16 -20
- data/Rakefile +8 -8
- data/TODO +6 -7
- data/bin/clevic +12 -73
- data/lib/clevic/action_builder.rb +168 -0
- data/lib/clevic/ar_methods.rb +120 -0
- data/lib/clevic/attribute_list.rb +56 -0
- data/lib/clevic/cache_table.rb +60 -37
- data/lib/clevic/default_view.rb +3 -16
- data/lib/clevic/delegate.rb +46 -0
- data/lib/clevic/emitter.rb +38 -0
- data/lib/clevic/extensions.rb +61 -114
- data/lib/clevic/field.rb +159 -228
- data/lib/clevic/field_valuer.rb +165 -0
- data/lib/clevic/filter_command.rb +2 -6
- data/lib/clevic/generic_format.rb +52 -0
- data/lib/clevic/{ui → icons}/icon.png +0 -0
- data/lib/clevic/many_field.rb +7 -0
- data/lib/clevic/model_builder.rb +234 -146
- data/lib/clevic/model_column.rb +61 -13
- data/lib/clevic/order_attribute.rb +10 -0
- data/lib/clevic/qt.rb +35 -0
- data/lib/clevic/qt/action_builder.rb +47 -0
- data/lib/clevic/qt/boolean_delegate.rb +8 -0
- data/lib/clevic/{browser.rb → qt/browser.rb} +35 -14
- data/lib/clevic/qt/clipboard.rb +35 -0
- data/lib/clevic/qt/combo_delegate.rb +198 -0
- data/lib/clevic/qt/delegates.rb +1 -0
- data/lib/clevic/qt/distinct_delegate.rb +35 -0
- data/lib/clevic/qt/extensions.rb +52 -0
- data/lib/clevic/qt/field.rb +18 -0
- data/lib/clevic/{item_delegate.rb → qt/item_delegate.rb} +8 -4
- data/lib/clevic/qt/relational_delegate.rb +87 -0
- data/lib/clevic/{search_dialog.rb → qt/search_dialog.rb} +1 -11
- data/lib/clevic/qt/set_delegate.rb +44 -0
- data/lib/clevic/qt/table_model.rb +331 -0
- data/lib/clevic/qt/table_view.rb +344 -0
- data/lib/clevic/qt/text_area_delegate.rb +8 -0
- data/lib/clevic/{text_delegate.rb → qt/text_delegate.rb} +6 -4
- data/lib/clevic/{ui → qt/ui}/.gitignore +0 -0
- data/lib/clevic/{ui → qt/ui}/browser.ui +0 -0
- data/lib/clevic/{ui → qt/ui}/search_dialog.ui +0 -0
- data/lib/clevic/rails_models_loaders.rb +56 -0
- data/lib/clevic/record.rb +2 -17
- data/lib/clevic/sampler.rb +81 -0
- data/lib/clevic/sequel_ar_adapter.rb +215 -0
- data/lib/clevic/sequel_length_validation.rb +23 -0
- data/lib/clevic/sequel_meta.rb +65 -0
- data/lib/clevic/sequel_naked.rb +30 -0
- data/lib/clevic/swing.rb +38 -0
- data/lib/clevic/swing/action.rb +125 -0
- data/lib/clevic/swing/action_builder.rb +47 -0
- data/lib/clevic/swing/boolean_delegate.rb +26 -0
- data/lib/clevic/swing/browser.rb +282 -0
- data/lib/clevic/swing/cell_editor.rb +95 -0
- data/lib/clevic/swing/cell_renderer.rb +44 -0
- data/lib/clevic/swing/clipboard.rb +135 -0
- data/lib/clevic/swing/combo_delegate.rb +336 -0
- data/lib/clevic/swing/confirm_dialog.rb +57 -0
- data/lib/clevic/swing/delegate.rb +40 -0
- data/lib/clevic/swing/distinct_delegate.rb +30 -0
- data/lib/clevic/swing/extensions.rb +274 -0
- data/lib/clevic/swing/field.rb +35 -0
- data/lib/clevic/swing/relational_delegate.rb +48 -0
- data/lib/clevic/swing/row_header.rb +210 -0
- data/lib/clevic/swing/search_dialog.rb +230 -0
- data/lib/clevic/swing/selection_model.rb +90 -0
- data/lib/clevic/swing/set_delegate.rb +41 -0
- data/lib/clevic/swing/swing_table_index.rb +43 -0
- data/lib/clevic/swing/table_model.rb +200 -0
- data/lib/clevic/swing/table_view.rb +385 -0
- data/lib/clevic/swing/table_view_focus.rb +47 -0
- data/lib/clevic/swing/tag_delegate.rb +127 -0
- data/lib/clevic/swing/tag_editor.rb +101 -0
- data/lib/clevic/swing/text_area_delegate.rb +46 -0
- data/lib/clevic/swing/text_delegate.rb +31 -0
- data/lib/clevic/swing/ui/build.xml +74 -0
- data/lib/clevic/swing/ui/dist/README.TXT +33 -0
- data/lib/clevic/swing/ui/dist/lib/swing-layout-1.0.3.jar +0 -0
- data/lib/clevic/swing/ui/manifest.mf +3 -0
- data/lib/clevic/swing/ui/nbproject/build-impl.xml +731 -0
- data/lib/clevic/swing/ui/nbproject/genfiles.properties +8 -0
- data/lib/clevic/swing/ui/nbproject/private/config.properties +0 -0
- data/lib/clevic/swing/ui/nbproject/private/private.properties +6 -0
- data/lib/clevic/swing/ui/nbproject/private/private.xml +4 -0
- data/lib/clevic/swing/ui/nbproject/project.properties +70 -0
- data/lib/clevic/swing/ui/nbproject/project.xml +14 -0
- data/lib/clevic/swing/ui/src/SearchDialog.form +158 -0
- data/lib/clevic/swing/ui/src/SearchDialog.java +163 -0
- data/lib/clevic/swing/ui/src/TagEditor.form +106 -0
- data/lib/clevic/swing/ui/src/TagEditor.java +108 -0
- data/lib/clevic/swing/ui/src/resources/SearchDialog.properties +0 -0
- data/lib/clevic/table_index.rb +100 -0
- data/lib/clevic/table_model.rb +54 -425
- data/lib/clevic/table_searcher.rb +113 -116
- data/lib/clevic/table_view.rb +171 -399
- data/lib/clevic/table_view_paste.rb +199 -0
- data/lib/clevic/version.rb +3 -2
- data/lib/clevic/view.rb +94 -43
- data/models/accounts_models.rb +13 -13
- data/models/minimal_models.rb +5 -9
- data/models/times_models.rb +19 -14
- data/models/times_psql_models.rb +10 -0
- data/models/times_sqlite_models.rb +1 -8
- data/models/values_models.rb +2 -8
- data/tasks/clevic.rake +1 -1
- data/tasks/rdoc.rake +1 -5
- data/tasks/website.rake +1 -1
- data/test/test_cache_table.rb +15 -29
- data/test/test_helper.rb +14 -83
- data/test/test_order_attribute.rb +1 -1
- data/test/test_table_model.rb +0 -21
- data/test/test_table_searcher.rb +67 -61
- metadata +262 -78
- data/lib/clevic.rb +0 -4
- data/lib/clevic/db_options.rb +0 -112
- data/lib/clevic/delegates.rb +0 -386
@@ -0,0 +1,199 @@
|
|
1
|
+
# This has all the code for handling pasting
|
2
|
+
require 'hpricot'
|
3
|
+
|
4
|
+
module Clevic
|
5
|
+
|
6
|
+
class PasteError < RuntimeError
|
7
|
+
end
|
8
|
+
|
9
|
+
class TableView
|
10
|
+
# get something from the clipboard and put it at the current selection
|
11
|
+
# intended to be called by action / keyboard / menu handlers
|
12
|
+
def paste
|
13
|
+
busy_cursor do
|
14
|
+
sanity_check_read_only
|
15
|
+
|
16
|
+
# Try text/html then text/plain as tsv or csv
|
17
|
+
# LATER maybe use the java-native-application at some point for
|
18
|
+
# cut'n'paste internally?
|
19
|
+
case
|
20
|
+
when clipboard.html?
|
21
|
+
paste_html
|
22
|
+
when clipboard.text?
|
23
|
+
paste_text
|
24
|
+
else
|
25
|
+
raise PasteError, "clipboard has neither text nor html, so can't paste"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
rescue PasteError => e
|
29
|
+
show_error e.message
|
30
|
+
end
|
31
|
+
|
32
|
+
# Paste suitable html to the selection
|
33
|
+
# Check for presence of tr tags, and make sure there are no colspan or rowspan attributes
|
34
|
+
# on td tags.
|
35
|
+
def paste_html
|
36
|
+
emit_status_text "Fetching data."
|
37
|
+
html = clipboard.html
|
38
|
+
|
39
|
+
# This should really be factored out somewhere and tested thoroughly
|
40
|
+
emit_status_text "Analysing data."
|
41
|
+
doc =
|
42
|
+
if html.is_a? Hpricot::Doc
|
43
|
+
html
|
44
|
+
else
|
45
|
+
Hpricot.parse( html )
|
46
|
+
end
|
47
|
+
|
48
|
+
# call the plain text paste if we don't have tabular data
|
49
|
+
if doc.search( "//tr" ).size == 0
|
50
|
+
paste_text
|
51
|
+
else
|
52
|
+
# throw exception if there are [col|row]span > 1
|
53
|
+
spans = doc.search( "//td[@rowspan > 1 || @colspan > 1]" )
|
54
|
+
if spans.size > 0
|
55
|
+
# make an itemised list of
|
56
|
+
cell_list = spans.map{|x| "- #{x.inner_text}"}.join("\n")
|
57
|
+
raise PasteError, <<-EOF
|
58
|
+
Pasting will not work because source contains spanning cells.
|
59
|
+
If the source is a spreadsheet, you probably have merged cells
|
60
|
+
somewhere. Split them, and try copy and paste again.
|
61
|
+
Cells contain
|
62
|
+
#{cell_list}
|
63
|
+
EOF
|
64
|
+
end
|
65
|
+
|
66
|
+
# run through the tabular data and convert to simple array
|
67
|
+
emit_status_text "Pasting data."
|
68
|
+
ary = ( doc / :tr ).map do |row|
|
69
|
+
( row / :td ).map do |cell|
|
70
|
+
# trim leading and trailing \r\n\t
|
71
|
+
|
72
|
+
# check for br
|
73
|
+
unless cell.search( '//br' ).empty?
|
74
|
+
# treat br as separate lines
|
75
|
+
cell.search('//text()').map( &:to_s ).join("\n")
|
76
|
+
else
|
77
|
+
# otherwise just join text elements
|
78
|
+
cell.search( '//text()' ).join('')
|
79
|
+
end.gsub( /^[\r\n\t]*/, '').gsub( /[\r\n\t]*$/, '')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
paste_array ary
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# LATER probably need a PasteParser or something, to figure
|
88
|
+
# out if a file is tsv or csv
|
89
|
+
# Try tsv first, because number formats often have embedded ','.
|
90
|
+
# if tsv doesn't work, try with csv and test for rectangularness
|
91
|
+
# otherwise assume it's one string.
|
92
|
+
# TODO could also heuristically check paste selection area
|
93
|
+
def paste_text
|
94
|
+
text = clipboard.text
|
95
|
+
|
96
|
+
case text
|
97
|
+
when /\t/
|
98
|
+
paste_array( FasterCSV.parse( text, :col_sep => "\t" ) )
|
99
|
+
# assume multi-line text, or text with commas, is csv
|
100
|
+
when /[,\n]/
|
101
|
+
paste_array( FasterCSV.parse( text, :col_sep => ',' ) )
|
102
|
+
else
|
103
|
+
paste_value_to_selection( text )
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Paste array to either a single selection or a matching multiple selection
|
108
|
+
# TODO Check for rectangularness, ie csv_arr.map{|row| row.size}.uniq.size == 1
|
109
|
+
def paste_array( arr )
|
110
|
+
if selection_model.single_cell?
|
111
|
+
# only one cell selected, so paste like a spreadsheet
|
112
|
+
selected_index = selection_model.selected_indexes.first
|
113
|
+
if arr.size == 0 or ( arr.size == 1 and arr.first.size == 0 )
|
114
|
+
# empty array, so just clear the current selection
|
115
|
+
selected_index.attribute_value = nil
|
116
|
+
else
|
117
|
+
paste_to_index( selected_index, arr )
|
118
|
+
end
|
119
|
+
else
|
120
|
+
if arr.size == 1 && arr.first.size == 1
|
121
|
+
# single value to multiple selection
|
122
|
+
paste_value_to_selection arr.first.first
|
123
|
+
else
|
124
|
+
if selection_model.ranges.size != 1
|
125
|
+
raise PasteError, "Can't paste tabular data to multiple selection."
|
126
|
+
end
|
127
|
+
|
128
|
+
if selection_model.ranges.first.height != arr.size
|
129
|
+
raise PasteError, "Height of paste area (#{selection_model.ranges.first.height}) doesn't match height of data (#{arr.size})."
|
130
|
+
end
|
131
|
+
|
132
|
+
if selection_model.ranges.first.width != arr.first.size
|
133
|
+
raise PasteError, "Width of paste area (#{selection_model.ranges.first.width}) doesn't match width of data (#{arr.first.size})."
|
134
|
+
end
|
135
|
+
|
136
|
+
# size is the same, so do the paste
|
137
|
+
paste_to_index( selected_index, arr )
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# set all indexes in the selection to the value
|
143
|
+
def paste_value_to_selection( value )
|
144
|
+
selection_model.selected_indexes.each do |index|
|
145
|
+
index.text_value = value
|
146
|
+
# save records to db via view, so we get error messages
|
147
|
+
save_row( index )
|
148
|
+
end
|
149
|
+
|
150
|
+
# notify of changed data
|
151
|
+
model.data_changed do |change|
|
152
|
+
sorted = selection_model.selected_indexes.sort
|
153
|
+
change.top_left = sorted.first
|
154
|
+
change.bottom_right = sorted.last
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Paste an array to the index, replacing whatever is at that index
|
159
|
+
# and whatever is at other indices matching the size of the pasted
|
160
|
+
# csv array. Create new rows if there aren't enough.
|
161
|
+
def paste_to_index( top_left_index, csv_arr )
|
162
|
+
csv_arr_size = csv_arr.size
|
163
|
+
csv_arr.each_with_index do |row,row_index|
|
164
|
+
# append row if we need one
|
165
|
+
model.add_new_item if top_left_index.row + row_index >= model.row_count
|
166
|
+
|
167
|
+
row.each_with_index do |field, field_index|
|
168
|
+
unless top_left_index.column + field_index >= model.column_count
|
169
|
+
# do paste
|
170
|
+
cell_index = top_left_index.choppy {|i| i.row += row_index; i.column += field_index }
|
171
|
+
emit_status_text( "pasted #{row_index+1} of #{csv_arr_size}")
|
172
|
+
begin
|
173
|
+
cell_index.text_value = field
|
174
|
+
rescue
|
175
|
+
puts $!.message
|
176
|
+
puts $!.backtrace
|
177
|
+
show_error( $!.message )
|
178
|
+
end
|
179
|
+
else
|
180
|
+
emit_status_text( "#{pluralize( top_left_index.column + field_index, 'column' )} for pasting data is too large. Truncating." )
|
181
|
+
end
|
182
|
+
end
|
183
|
+
# save records to db via view, so we get error messages
|
184
|
+
save_row( top_left_index.choppy {|i| i.row += row_index; i.column = 0 } )
|
185
|
+
end
|
186
|
+
|
187
|
+
# make the gui refresh
|
188
|
+
model.data_changed do |change|
|
189
|
+
change.top_left = top_left_index
|
190
|
+
change.bottom_right = top_left_index.choppy do |i|
|
191
|
+
i.row += csv_arr.size - 1
|
192
|
+
i.column += csv_arr.first.size - 1
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
data/lib/clevic/version.rb
CHANGED
data/lib/clevic/view.rb
CHANGED
@@ -5,79 +5,130 @@ module Clevic
|
|
5
5
|
# This contains the definition of a particular view of an entity.
|
6
6
|
# See Clevic::ModelBuilder.
|
7
7
|
class View
|
8
|
-
@order = []
|
9
|
-
def self.order
|
10
|
-
@order
|
11
|
-
end
|
12
8
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
9
|
+
class << self
|
10
|
+
def define_ui_block( &block )
|
11
|
+
@define_ui_block ||= block
|
12
|
+
end
|
13
|
+
|
14
|
+
def order
|
15
|
+
@order ||= []
|
16
|
+
end
|
17
|
+
|
18
|
+
# sometimes order has duplicates. So this is all unique
|
19
|
+
# defined views in order of definition, or as specified.
|
20
|
+
def views
|
21
|
+
order.uniq
|
22
|
+
end
|
23
|
+
|
24
|
+
def []( view_name )
|
25
|
+
order.find do |view|
|
26
|
+
view.name =~ /#{view_name.to_s}/i
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Handle situations where the array passed to
|
31
|
+
# Clevic::View.order has entity_class
|
32
|
+
# objects in it. In other words, if there is one, pass back it's
|
33
|
+
# default view class rather than the entity_class
|
34
|
+
def order=( array )
|
35
|
+
@order = array.map do |x|
|
36
|
+
if x.ancestors.include?( Clevic.base_entity_class )
|
37
|
+
x.default_view_class
|
38
|
+
else
|
39
|
+
x
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def entity_class( *args )
|
45
|
+
if args.size == 0
|
46
|
+
@entity_class || raise( "entity_class not specified for #{name}" )
|
21
47
|
else
|
22
|
-
|
48
|
+
self.entity_class = args.first
|
23
49
|
end
|
24
50
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
51
|
+
|
52
|
+
def entity_class=( some_class )
|
53
|
+
@entity_class = some_class
|
54
|
+
end
|
55
|
+
|
56
|
+
def widget_name( *args )
|
57
|
+
if args.size == 0
|
58
|
+
# the class name by default
|
59
|
+
@widget_name || name
|
60
|
+
else
|
61
|
+
@widget_name = args.first
|
62
|
+
end
|
32
63
|
end
|
33
64
|
end
|
34
65
|
|
35
|
-
|
36
|
-
|
66
|
+
# args can be anything that has a writer method. Often this
|
67
|
+
# will be entity_class
|
68
|
+
# block contains the ModelBuilder DSL
|
69
|
+
def initialize( args = {}, &block )
|
70
|
+
@define_ui_block = block
|
71
|
+
unless args.nil?
|
72
|
+
args.each do |key,value|
|
73
|
+
self.send( "#{key}=", value )
|
74
|
+
end
|
75
|
+
end
|
37
76
|
end
|
38
77
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@widget_name || name
|
43
|
-
else
|
44
|
-
@widget_name = args.first
|
45
|
-
end
|
78
|
+
# use block from constructor, or class ui block from eg Clevic::Record
|
79
|
+
def define_ui_block
|
80
|
+
@define_ui_block || self.class.define_ui_block
|
46
81
|
end
|
47
82
|
|
48
83
|
# For descendants to override easily
|
49
84
|
def entity_class
|
50
|
-
self.class.entity_class
|
85
|
+
@entity_class || self.class.entity_class
|
51
86
|
end
|
87
|
+
attr_writer :entity_class
|
52
88
|
|
53
89
|
# The title to display, eg in a tab
|
54
90
|
def title
|
55
|
-
self.class.name
|
91
|
+
@title || self.class.name
|
56
92
|
end
|
93
|
+
attr_writer :title
|
57
94
|
|
58
|
-
|
59
|
-
|
95
|
+
def fields
|
96
|
+
@fields ||= define_ui.fields
|
97
|
+
end
|
98
|
+
|
99
|
+
# used by the framework-specific code to name widgets
|
60
100
|
def widget_name
|
61
|
-
self.class.widget_name
|
101
|
+
@widget_name || self.class.widget_name
|
62
102
|
end
|
63
103
|
|
64
|
-
def model_builder( &block )
|
65
|
-
|
66
|
-
|
104
|
+
def model_builder( value = nil, &block )
|
105
|
+
if value.nil?
|
106
|
+
@model_builder ||= ModelBuilder.new( self )
|
107
|
+
@model_builder.exec_ui_block( &block )
|
108
|
+
else
|
109
|
+
@model_builder
|
110
|
+
end
|
67
111
|
end
|
112
|
+
attr_writer :model_builder
|
68
113
|
|
69
114
|
# return a default UI constructed from model metadata
|
70
115
|
def define_ui
|
71
|
-
|
72
|
-
|
116
|
+
if define_ui_block.nil?
|
117
|
+
# use the define_ui from Clevic::View to build a default UI
|
118
|
+
model_builder do
|
119
|
+
default_ui
|
120
|
+
end
|
121
|
+
else
|
122
|
+
# use the provided block
|
123
|
+
model_builder( &define_ui_block )
|
73
124
|
end
|
74
125
|
end
|
75
126
|
|
76
|
-
#
|
127
|
+
# callback for view/model specific actions
|
77
128
|
def define_actions( table_view, action_builder )
|
78
129
|
end
|
79
130
|
|
80
|
-
# notify
|
131
|
+
# callback for notify
|
81
132
|
def notify_field( table_view, model_index )
|
82
133
|
ndc = model_index.field.notify_data_changed
|
83
134
|
case ndc
|
@@ -91,7 +142,7 @@ module Clevic
|
|
91
142
|
|
92
143
|
# Define data changed events. Default is to call notify_data_changed
|
93
144
|
# for each field in the rectangular area defined by top_left and bottom_right
|
94
|
-
# (which are
|
145
|
+
# (which are include Clevic::TableIndex)
|
95
146
|
def notify_data_changed( table_view, top_left, bottom_right )
|
96
147
|
if top_left == bottom_right
|
97
148
|
# shortcut to just the one, seeing as it's probably the most common
|
@@ -107,7 +158,7 @@ module Clevic
|
|
107
158
|
end
|
108
159
|
end
|
109
160
|
|
110
|
-
#
|
161
|
+
# callback for key presses
|
111
162
|
def notify_key_press( table_view, key_press_event, current_model_index )
|
112
163
|
end
|
113
164
|
|
data/models/accounts_models.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
require 'clevic.rb'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
username options[:username].blank? ? 'accounts' : options[:username]
|
3
|
+
host = ENV['PGHOST'] || 'localhost'
|
4
|
+
$options ||= {}
|
5
|
+
|
6
|
+
if respond_to?( :'jruby?' ) && jruby?
|
7
|
+
constring = "jdbc:postgresql://#{host}/accounts_test?user=#{$options[:username] || 'accounts'}&password=general"
|
8
|
+
puts "constring: #{constring.inspect}"
|
9
|
+
Sequel.connect( constring )
|
10
|
+
else
|
11
|
+
Sequel.connect( "postgres://#{host}/accounts_test?user=#{$options[:username] || 'accounts'}&password=general" )
|
13
12
|
end
|
14
13
|
|
15
|
-
class Entry <
|
14
|
+
class Entry < Sequel::Model
|
16
15
|
belongs_to :debit, :class_name => 'Account', :foreign_key => 'debit_id'
|
17
16
|
belongs_to :credit, :class_name => 'Account', :foreign_key => 'credit_id'
|
18
17
|
|
@@ -33,6 +32,7 @@ class Entry < ActiveRecord::Base
|
|
33
32
|
end
|
34
33
|
end
|
35
34
|
end
|
35
|
+
distinct :supplier
|
36
36
|
relational :debit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
|
37
37
|
relational :credit, :display => 'name', :conditions => 'active = true', :order => 'lower(name)', :sample => 'Leilani Member Loan'
|
38
38
|
plain :amount, :sample => 999999.99
|
@@ -49,7 +49,7 @@ class Entry < ActiveRecord::Base
|
|
49
49
|
def self.update_from_description( current_index )
|
50
50
|
return if current_index.attribute_value.nil?
|
51
51
|
# most recent entry, ordered in reverse
|
52
|
-
similar = self.find(
|
52
|
+
similar = self.adaptor.find(
|
53
53
|
:first,
|
54
54
|
:conditions => ["#{current_index.attribute} = ?", current_index.attribute_value],
|
55
55
|
:order => 'date desc'
|
@@ -69,7 +69,7 @@ class Entry < ActiveRecord::Base
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
-
class Account <
|
72
|
+
class Account < Sequel::Model
|
73
73
|
has_many :debits, :class_name => 'Entry', :foreign_key => 'debit_id'
|
74
74
|
has_many :credits, :class_name => 'Entry', :foreign_key => 'credit_id'
|
75
75
|
|