ig3tool 0.1.0

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.
Files changed (63) hide show
  1. data/bin/ig3tool +114 -0
  2. data/lib/glade/bib.glade +539 -0
  3. data/lib/glade/bibliotheek.glade +994 -0
  4. data/lib/glade/icons/cola.png +0 -0
  5. data/lib/glade/icons/emblem-money.png +0 -0
  6. data/lib/glade/icons/emblem-package.png +0 -0
  7. data/lib/glade/icons/emblem-penning.xpm +98 -0
  8. data/lib/glade/icons/emblem-people.png +0 -0
  9. data/lib/glade/icons/emblem-sales.png +0 -0
  10. data/lib/glade/icons/gdict.png +0 -0
  11. data/lib/glade/icons/members_klein.png +0 -0
  12. data/lib/glade/icons/members_xklein.png +0 -0
  13. data/lib/glade/icons/no.xpm +34 -0
  14. data/lib/glade/icons/stock_book.svg +338 -0
  15. data/lib/glade/icons/stock_book_klein.png +0 -0
  16. data/lib/glade/icons/stock_book_xklein.png +0 -0
  17. data/lib/glade/icons/stock_bookmark.svg +327 -0
  18. data/lib/glade/icons/stock_bookmark_klein.png +0 -0
  19. data/lib/glade/icons/stock_bookmark_xklein.png +0 -0
  20. data/lib/glade/icons/stock_print.png +0 -0
  21. data/lib/glade/interne.glade +228 -0
  22. data/lib/glade/loginwindow.glade +255 -0
  23. data/lib/glade/memberinfo.svg +411 -0
  24. data/lib/glade/memberinfo_klein.png +0 -0
  25. data/lib/glade/memberinfo_xklein.png +0 -0
  26. data/lib/glade/members.glade +596 -0
  27. data/lib/glade/members.svg +559 -0
  28. data/lib/glade/members_klein.png +0 -0
  29. data/lib/glade/members_xklein.png +0 -0
  30. data/lib/glade/penningtool.glade +731 -0
  31. data/lib/glade/people.glade +947 -0
  32. data/lib/glade/printen.glade +358 -0
  33. data/lib/glade/printer.png +0 -0
  34. data/lib/glade/printer_klein.png +0 -0
  35. data/lib/glade/printer_xklein.png +0 -0
  36. data/lib/glade/printerlog_klein.png +0 -0
  37. data/lib/glade/printerlog_xklein.png +0 -0
  38. data/lib/glade/printing.glade +841 -0
  39. data/lib/glade/products.glade +404 -0
  40. data/lib/glade/sales.glade +426 -0
  41. data/lib/glade/stock_book.svg +338 -0
  42. data/lib/glade/stock_book_klein.png +0 -0
  43. data/lib/glade/stock_book_xklein.png +0 -0
  44. data/lib/glade/stock_bookmark_klein.png +0 -0
  45. data/lib/glade/stock_bookmark_xklein.png +0 -0
  46. data/lib/glade/vendingmachine.glade +207 -0
  47. data/lib/lib/errors.rb +90 -0
  48. data/lib/lib/util.rb +89 -0
  49. data/lib/ui/automaatwindow.rb +107 -0
  50. data/lib/ui/bibliotheekwindow.rb +453 -0
  51. data/lib/ui/bibwindow.rb +537 -0
  52. data/lib/ui/gladehelper.rb +110 -0
  53. data/lib/ui/internewindow.rb +126 -0
  54. data/lib/ui/loginwindow.rb +60 -0
  55. data/lib/ui/memberswindow.rb +327 -0
  56. data/lib/ui/messagebox.rb +23 -0
  57. data/lib/ui/peoplewindow.rb +333 -0
  58. data/lib/ui/printenwindow.rb +329 -0
  59. data/lib/ui/printingwindow.rb +395 -0
  60. data/lib/ui/productswindow.rb +160 -0
  61. data/lib/ui/saleswindow.rb +207 -0
  62. data/lib/ui/toolwindow.rb +97 -0
  63. metadata +128 -0
@@ -0,0 +1,395 @@
1
+ module Ig3tool
2
+
3
+ class PrintingWindow < GladeHelper
4
+ include GetText
5
+
6
+ MENU_PATH = ["Printer", "Printing"]
7
+ ICON = "stock_print.png"
8
+
9
+ attr :glade
10
+
11
+ #def initialize(path_or_data, root = nil, domain = nil, localedir = nil, flag = GladeXML::FILE)
12
+ def initialize
13
+ super("printing.glade")
14
+
15
+ #@c = Client.new("infogroep.be")
16
+ @c = $global["client"]
17
+
18
+ #bindtextdomain(domain, localedir, nil, "UTF-8")
19
+ #@glade = GladeXML.new(path_or_data, root, domain, localedir, flag) {|handler| method(handler)}
20
+
21
+ @tabs = @glade.get_widget("tabs")
22
+
23
+ @firstname = @glade.get_widget("firstname")
24
+ @lastname = @glade.get_widget("lastname")
25
+ @username = @glade.get_widget("username")
26
+ @email = @glade.get_widget("email")
27
+ @saldo = @glade.get_widget("saldo")
28
+ @notification = @glade.get_widget("notification")
29
+ @apply = @glade.get_widget("apply")
30
+ @clear = @glade.get_widget("clear")
31
+ @delta = @glade.get_widget("delta")
32
+ @statussearch = @glade.get_widget("statussearch")
33
+ @status = @glade.get_widget("status")
34
+ @usernames = @glade.get_widget("usernames")
35
+ @usernames.model = @usernames_store = Gtk::ListStore.new(Object, String)
36
+ r = Gtk::CellRendererText.new
37
+ @usernames.insert_column(-1, "username", r, :text => 1)
38
+ @usernames.enable_search = true
39
+
40
+
41
+ @filteredlog = @glade.get_widget("filteredlog")
42
+ @filteredlog.model = @filteredlog_store = Gtk::ListStore.new(Object, String)
43
+ fl = Gtk::CellRendererText.new
44
+ @filteredlog.insert_column(-1, "message", fl) do |tvc, cell, m ,iter|
45
+ if iter[0].category == "print"
46
+ message = "#{iter[0].username} printed #{iter[0].pages} pages for #{iter[0].amount} cents: #{iter[0].job}"
47
+ else
48
+ message = iter[0].message
49
+ end
50
+ cell.text = message
51
+ cell.strikethrough = iter[0].refunded.to_i.to_b
52
+ end
53
+
54
+
55
+ @log = @glade.get_widget("log")
56
+ @log.model = @log_store = Gtk::ListStore.new(Object, String, String, String, String, String, String, String, String)
57
+ l = Gtk::CellRendererText.new
58
+ @log.insert_column(-1, "time", l) do |tvc, cell, m, iter|
59
+ cell.text = Time.parse(iter[0].time).strftime("%d/%m %H:%M")
60
+ end
61
+ @log.insert_column(-1, "type", l) do |tvc, cell, m, iter|
62
+ cell.text = iter[0].category
63
+ cell.strikethrough = iter[0].refunded.to_i.to_b
64
+ end
65
+ @log.insert_column(-1, "username", l) do |tvc, cell, m, iter|
66
+ cell.text = iter[0].username
67
+ end
68
+ @log.insert_column(-1, "queue", l) do |tvc, cell, m, iter|
69
+ cell.text = iter[0].queue
70
+ end
71
+ @log.insert_column(-1, "amount", l) do |tvc, cell, m, iter|
72
+ cell.text = iter[0].amount
73
+ end
74
+ @log.insert_column(-1, "host", l) do |tvc, cell, m, iter|
75
+ cell.text = iter[0].host
76
+ end
77
+ @log.insert_column(-1, "pages", l) do |tvc, cell, m, iter|
78
+ cell.text = iter[0].pages
79
+ end
80
+ @log.insert_column(-1, "job", l) do |tvc, cell, m, iter|
81
+ cell.text = iter[0].job
82
+ end
83
+
84
+ _update_usernames
85
+ _update_log
86
+ @statussearch.active = 0
87
+
88
+ end
89
+
90
+ def fl_row_activated(view, path, col)
91
+ logentry = @filteredlog.model.get_iter(path)[0]
92
+ if logentry.category != "print"
93
+ _show(logentry.username)
94
+ else
95
+ begin
96
+ @c.print_refund!({"logid" => logentry["id"]})
97
+ @notification.text = "refunded print of #{logentry["amount"]} to #{logentry["username"]}"
98
+ _update_log
99
+ rescue Exception => e
100
+ #puts "ERR: " + e.message.to_s
101
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
102
+ end
103
+ end
104
+ end
105
+
106
+ def log_row_activated(view, path, col)
107
+ logentry = @filteredlog.model.get_iter(path)[0]
108
+ if logentry.category != "print"
109
+ _show(logentry.username)
110
+ else
111
+ begin
112
+ @c.print_refund!({"logid" => logentry["id"]})
113
+ @notification.text = "refunded print of #{logentry["amount"]} to #{logentry["username"]}"
114
+ rescue Exception => e
115
+ #puts "ERR: " + e.message.to_s
116
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
117
+ end
118
+ end
119
+ @tabs.page = 0
120
+ end
121
+
122
+ def changed(widget) # triggers when fields change
123
+ #puts "changed " + widget.text
124
+ @apply.image = Gtk::Image.new(Gtk::Stock::APPLY, Gtk::IconSize::BUTTON)
125
+ @apply.label = Gtk::Stock::APPLY
126
+ end
127
+
128
+ def refresh(widget) # refreshes the usernames list and the small log
129
+ _update_usernames
130
+ _update_log
131
+ end
132
+
133
+
134
+ def refreshlog(widget) #refreshes the big log on page 2
135
+ _update_biglog
136
+ end
137
+
138
+ def to_apply(widget)
139
+ if(@username.text.strip != "")
140
+ @apply.grab_focus
141
+ @notification.text = "Save changes?"
142
+ else
143
+ @username.grab_focus
144
+ end
145
+ end
146
+
147
+ def to_add(widget)
148
+ if(@username.text.strip != "")
149
+ if(@delta.text.strip != "")
150
+ @apply.grab_focus
151
+ @notification.text = "Add credits?"
152
+ else
153
+ @delta.grab_focus
154
+ end
155
+ else
156
+ @username.grab_focus
157
+ end
158
+
159
+ end
160
+
161
+ def tabfocus(a,b,c)
162
+ if c == 1
163
+ _update_biglog
164
+ else
165
+ refresh(nil)
166
+ end
167
+ end
168
+
169
+
170
+ def smart_search(widget)
171
+ if @username.text.strip == ""
172
+ @notification.text = "the imps want you to look up a user first..."
173
+ clear_all(nil, false)
174
+ else
175
+ begin
176
+ user = @c.print_user(@username.text)
177
+ person = @c.person_lookup({"username" => @username.text})
178
+ raise NotFound, "the ig3tool imps found no such user..." if person.nil?
179
+ person = person[0]
180
+ @email.text = person["email"]
181
+ @saldo.text = user["saldo"]
182
+ @firstname.text = person["first_name"]
183
+ @lastname.text = person["last_name"]
184
+ @status.text = @c.person_status(person["username"])
185
+ @notification.text = "the ig3tool imps found #{user["username"]}..."
186
+ @apply.image = Gtk::Image.new(Gtk::Stock::ADD, Gtk::IconSize::BUTTON)
187
+ @apply.label = Gtk::Stock::ADD
188
+ @delta.grab_focus
189
+ rescue Exception => e
190
+ begin
191
+ person = @c.person_lookup({"username" => @username.text})
192
+ raise NotFound, "the ig3tool imps found no such user..." if person.nil? or person.empty?
193
+ person = person[0]
194
+ @email.text = person["email"]
195
+ @saldo.text = "0"
196
+ @firstname.text = person["first_name"]
197
+ @lastname.text = person["last_name"]
198
+ @status.text = @c.person_status(person["username"])
199
+ @notification.text = "the ig3tool imps found #{person["username"]}..."
200
+ @apply.image = Gtk::Image.new(Gtk::Stock::ADD, Gtk::IconSize::BUTTON)
201
+ @apply.label = Gtk::Stock::ADD
202
+ @delta.grab_focus
203
+ rescue Exception => e
204
+ #puts "user not found"
205
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
206
+ puts e.inspect
207
+ @notification.text += "\n fill in the blanks to create a new user"
208
+ @email.text = @username.text.strip + "@vub.ac.be"
209
+ @firstname.grab_focus
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ def clear_all(widget, clearnotification=true)
216
+ @username.text = ""
217
+ @email.text = ""
218
+ @saldo.text = ""
219
+ @firstname.text = ""
220
+ @lastname.text = ""
221
+ @notification.text = "" if clearnotification
222
+ @delta.text = ""
223
+ @apply.image = Gtk::Image.new(Gtk::Stock::APPLY, Gtk::IconSize::BUTTON)
224
+ @apply.label = Gtk::Stock::APPLY
225
+ @usernames.grab_focus
226
+ @statussearch.active = -1
227
+ end
228
+
229
+ def clear_most(widget)
230
+ @email.text = ""
231
+ @saldo.text = ""
232
+ @firstname.text = ""
233
+ @lastname.text = ""
234
+ @notification.text = ""
235
+ @delta.text = ""
236
+ @apply.image = Gtk::Image.new(Gtk::Stock::APPLY, Gtk::IconSize::BUTTON)
237
+ @apply.label = Gtk::Stock::APPLY
238
+ #@statussearch.active = -1
239
+ end
240
+
241
+ def username_del(a,b,c)
242
+ clear_most(nil)
243
+ end
244
+ def username_ins(a,b,c,d)
245
+ clear_most(nil)
246
+ end
247
+
248
+ def smart_add(widget)
249
+ begin
250
+ @c.print_addcredit!({:username => @username.text, :amount => @delta.text})
251
+ @notification.text = "the imps added #{@delta.text} euro's to #{@username.text}'s account..."
252
+ rescue Exception => e
253
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
254
+ end
255
+ end
256
+
257
+ def notification_focus_in_event_cb(widget, arg0)
258
+ puts "notification_focus_in_event_cb() is not implemented yet."
259
+ end
260
+
261
+ def smart_update(widget)
262
+ if @username.text.strip == ""
263
+ quick_message("\n you can't do that with no username looked up... \n")
264
+ clear_all(nil)
265
+ else
266
+ begin
267
+ amount = @delta.text.strip.gsub(/,/, ".")
268
+ if amount.to_f < 0
269
+ quick_message("\n the ig3tool imps do not accept negative values... \n")
270
+ else
271
+ @c.print_update!({:username => @username.text,
272
+ :first_name => @firstname.text,
273
+ :last_name => @lastname.text,
274
+ :email => @email.text,
275
+ :amount => amount.to_c })
276
+ clear_all(nil)
277
+ @notification.text = "smart update done!"
278
+ Thread.new do
279
+ refresh(true)
280
+ end
281
+ end
282
+ rescue Exception => e
283
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
284
+ end
285
+ end
286
+ end
287
+
288
+ def select (widget, path, column)
289
+ iter = widget.model.get_iter(path)
290
+ _show iter[1]
291
+ end
292
+
293
+ private
294
+
295
+ def _show(username)
296
+ #puts "show: #{username}"
297
+ begin
298
+ user = @c.print_user(username)
299
+ person = @c.person_lookup({"username", username})[0]
300
+ @username.text = username
301
+ @email.text = person["email"]
302
+ @saldo.text = user["saldo"].from_c.to_s
303
+ @firstname.text = person["first_name"]
304
+ @lastname.text = person["last_name"]
305
+ @status.text = @c.person_status(username)
306
+ @notification.text = "the ig3tool imps found #{username}..."
307
+ @apply.image = Gtk::Image.new(Gtk::Stock::ADD, Gtk::IconSize::BUTTON)
308
+ @apply.label = Gtk::Stock::ADD
309
+ @delta.grab_focus
310
+ rescue Exception => e
311
+ #puts "EXC: " + e.message
312
+ begin
313
+ person = @c.person_lookup({"username", @username.text})
314
+ raise NotFound, "the ig3tool imps found no such user..." if person.nil? or person.empty?
315
+ person = person[0]
316
+ @username.text = username
317
+ @email.text = person["email"]
318
+ @saldo.text = "0"
319
+ @firstname.text = person["first_name"]
320
+ @lastname.text = person["last_name"]
321
+ @status.text = @c.person_status(username)
322
+ @notification.text = "the ig3tool imps found #{username}..."
323
+ @apply.image = Gtk::Image.new(Gtk::Stock::ADD, Gtk::IconSize::BUTTON)
324
+ @apply.label = Gtk::Stock::ADD
325
+ @delta.grab_focus
326
+ rescue Exception => e
327
+ #puts "user not found"
328
+ @notification.text = (e.class.to_s + " - " + e.message).smaller
329
+ puts e.inspect
330
+ @notification.text += "\n fill in the blanks to create a new user"
331
+ @email.text = @username.text.strip + "@vub.ac.be"
332
+ @firstname.grab_focus
333
+ end
334
+ end
335
+ end
336
+
337
+ def _update_usernames(clear=true)
338
+ @usernames.model = nil
339
+ @usernames_store.clear if clear
340
+ Thread.new do
341
+ if @statussearch.active > 0
342
+ users = @c.person_everybody.sort{|x,y| x["username"] <=> y["username"]}
343
+ else
344
+ users = @c.print_users
345
+ end
346
+ users.each do |user|
347
+ row = @usernames_store.append
348
+ row[1] = user["username"]
349
+ end
350
+ @usernames.model = @usernames_store
351
+ end
352
+ end
353
+
354
+
355
+ def _update_log(clear=true)
356
+ @filteredlog_store.clear if clear
357
+ Thread.new do
358
+ loglines = @c.print_logs
359
+ loglines.each do |ll|
360
+ @filteredlog_store.append[0] = ll
361
+ end
362
+ end
363
+ end
364
+
365
+ def _update_biglog(clear=true)
366
+ @log_store.clear if clear
367
+ Thread.new do
368
+ loglines = @c.print_logs
369
+ loglines.each do |ll|
370
+ @log_store.append[0] = ll
371
+ end
372
+ end
373
+ end
374
+
375
+ def quick_message(message, title="ig3tool message")
376
+ # Create the dialog
377
+ dialog = Gtk::Dialog.new(title,
378
+ $main_application_window,
379
+ Gtk::Dialog::DESTROY_WITH_PARENT,
380
+ [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_NONE ])
381
+
382
+ # Ensure that the dialog box is destroyed when the user responds.
383
+ dialog.signal_connect('response') { dialog.destroy }
384
+
385
+ # Add the message in a label, and show everything we've added to the dialog.
386
+ dialog.vbox.add(Gtk::Label.new(message))
387
+ dialog.show_all
388
+ end
389
+
390
+ end
391
+
392
+ register_window(PrintingWindow)
393
+
394
+ end
395
+
@@ -0,0 +1,160 @@
1
+ module Ig3tool
2
+
3
+ class ProductsWindow < GladeHelper
4
+ MENU_PATH = ["Producten", "Producten"]
5
+ ICON = "emblem-package.png"
6
+
7
+ def initialize
8
+ super("products.glade")
9
+
10
+ @product_view = @glade.get_widget("producttree")
11
+ @barcode_entry = @glade.get_widget("barcode")
12
+ @name_entry = @glade.get_widget("name")
13
+ @category = @glade.get_widget("category")
14
+ @category_combo = @glade.get_widget("category_combo")
15
+ @dprice_entry = @glade.get_widget("dprice")
16
+ @lprice_entry = @glade.get_widget("lprice")
17
+ @nlprice_entry = @glade.get_widget("nlprice")
18
+ @stock_label = @glade.get_widget("stock")
19
+ @purchase_view = @glade.get_widget("purchaselist")
20
+ @date_entry = @glade.get_widget("date")
21
+ @new_price = @glade.get_widget("new_price")
22
+ @new_stock = @glade.get_widget("new_stock")
23
+
24
+ s1 = Gtk::SizeGroup.new(Gtk::SizeGroup::BOTH)
25
+ %w(slabel1 slabel2 slabel3 slabel4 slabel5).each do |w|
26
+ s1.add_widget(@glade.get_widget(w))
27
+ end
28
+ s2 = Gtk::SizeGroup.new(Gtk::SizeGroup::BOTH)
29
+ %w(update_button new_stock_button stock_correction_button return_button).each do |w|
30
+ s2.add_widget(@glade.get_widget(w))
31
+ end
32
+
33
+ @purchase_list = Gtk::ListStore.new(Object, String, String, Integer, String)
34
+ @purchase_view.model = @purchase_list
35
+ renderer = Gtk::CellRendererText.new
36
+ renderer.xalign = 1
37
+ @purchase_view.insert_column(-1, "Datum", renderer, :text => 1)
38
+ @purchase_view.insert_column(-1, "Totaalprijs", renderer, :text => 2)
39
+ @purchase_view.insert_column(-1, "Aantal", renderer, :text => 3)
40
+
41
+ renderer = Gtk::CellRendererText.new
42
+ @products = Gtk::ListStore.new(Object, String)
43
+ @product_view.model = @products
44
+ @product_view.insert_column(-1, "Product", renderer, :text => 1)
45
+
46
+ cat_model = Gtk::ListStore.new(String)
47
+ cat_model.prepend[0] = "Alle categorieën"
48
+ $global["client"].product_categories.collect {|x| x.name}.sort.each do |cat|
49
+ r = cat_model.append
50
+ r[0] = cat
51
+ end
52
+ @category_combo.model = cat_model
53
+ @category_combo.active = 0
54
+
55
+ renderer = Gtk::CellRendererText.new
56
+ @category_combo.pack_start(renderer, true)
57
+ @category_combo.set_attributes(renderer, :text => 0)
58
+
59
+ @stock_label.text = "0"
60
+ @date_entry.text = Date.today.to_s
61
+
62
+ [@lprice_entry, @nlprice_entry, @new_price, @new_stock].each do |widget|
63
+ make_eval_widget widget
64
+ end
65
+
66
+ @window.show
67
+ @glade = nil
68
+
69
+ @selected_product = nil
70
+
71
+ end
72
+
73
+ def product_row_activated (widget, path, column)
74
+ prod = @product_view.selection.selected[0]
75
+ @selected_product = prod
76
+ @barcode_entry.editable = false
77
+ @name_entry.text = prod.name
78
+ @barcode_entry.text = prod.barcode
79
+ @category.child.text = prod.category
80
+ @new_price.text = sprintf("%.2f", prod.dprice.to_i.from_c)
81
+ @dprice_entry.text = sprintf("%.2f", prod.dprice.to_i.from_c)
82
+ @lprice_entry.text = sprintf("%.2f", prod.mprice.to_i.from_c)
83
+ @nlprice_entry.text = sprintf("%.2f", prod.nmprice.to_i.from_c)
84
+ @stock_label.text = prod.stock.to_s
85
+ _fill_purchases
86
+ end
87
+
88
+ def btn_clear_clicked_cb
89
+ _clear
90
+ end
91
+
92
+ def btn_apply_clicked_cb
93
+ # todo
94
+ end
95
+
96
+ def add_button_clicked
97
+ return if @selected_product.nil?
98
+ amount = @new_stock.text
99
+ price = @new_price.text
100
+
101
+ args = { :debugger => "dharnie",
102
+ :items => { @selected_product.barcode => [amount, price] } }
103
+
104
+ $global["client"].product_purchase! args
105
+ end
106
+
107
+ def category_combo_changed
108
+ active = @category_combo.active
109
+ products = $global["client"].product_all
110
+ if active > 0
111
+ category = @category_combo.active_iter[0]
112
+ products = products.select {|p| p.category == category}
113
+ end
114
+ _fill_products products
115
+ end
116
+
117
+ private
118
+ def _clear
119
+ @selected_product = nil
120
+ @barcode_entry.editable = true
121
+ @barcode_entry.text = ""
122
+ @name_entry.text = ""
123
+ @category.child.text = ""
124
+ @dprice_entry.text = ""
125
+ @lprice_entry.text = ""
126
+ @nlprice_entry.text = ""
127
+ @stock_label.text = "0"
128
+ @new_price.text = ""
129
+ @new_stock.text = ""
130
+ _fill_purchases
131
+ end
132
+
133
+ def _fill_products (products)
134
+ @product_view.model = nil
135
+ @products.clear
136
+ products.sort {|a,b| a.name.downcase <=> b.name.downcase}.each do |prod|
137
+ row = @products.append
138
+ row[0] = prod
139
+ row[1] = prod.name
140
+ end
141
+ @product_view.model = @products
142
+ end
143
+
144
+ def _fill_purchases
145
+ @purchase_list.clear
146
+ return if @selected_product.nil?
147
+ @selected_product.purchases.each do |p|
148
+ row = @purchase_list.append
149
+ row[0] = p
150
+ row[1] = p.time.to_s
151
+ row[2] = sprintf("%.2f", p.cost.to_s)
152
+ row[3] = p.count.to_i
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ register_window(ProductsWindow)
159
+
160
+ end