Affichage des floats amélioré et alignement des montants à droite pour formulaire...
[bilio:bilio.git] / document.rb
1 # coding: utf-8
2
3 class Document < Gtk::VBox
4
5         def initialize window
6         
7                 super(false, 3)
8                 
9                 set_border_width 10
10                 
11                 @window = window
12                 @db = window.db
13                 @login = window.login
14                 
15                 @id = 0
16                 @type = 0
17                 
18                 @ligne_modif_id = []
19                 
20                 @imprimer = Gtk::Button.new Gtk::Stock::PRINT
21                 @valider = Gtk::Button.new Gtk::Stock::OK
22                 @annuler = Gtk::Button.new Gtk::Stock::CANCEL
23                 
24                 agencement
25                 
26                 @valider.signal_connect( "clicked" ) { validate }
27                 @annuler.signal_connect( "clicked" ) { quit }
28                 @imprimer.signal_connect( "clicked" ) { imprimer }
29         
30         end
31         
32         def agencement
33         
34                 vbox = Gtk::VBox.new false, 3
35                 @frame = Gtk::Frame.new
36                 @frame.label = "Nouveau document"
37                 vbox.pack_start( @frame, true, true, 3 )
38                 
39                 vbox_corps = Gtk::VBox.new false, 3
40                 @frame.add vbox_corps
41                 vbox_corps.pack_start( en_tete, false, false, 3 )
42                 vbox_corps.pack_start( lignes, true, true, 3 )
43                 vbox_corps.pack_start( pieds, false, false, 3 )
44                 
45                 hbox_button = Gtk::HBox.new false, 2
46                 hbox3 = Gtk::HBox.new false, 2
47                 align0 = Gtk::Alignment.new 0, 0, 0, 0
48                 align0.add @imprimer
49                 align1 = Gtk::Alignment.new 1, 1, 0, 0
50                 hbox3.pack_start( @annuler, true, true, 3 )
51                 hbox3.pack_start( @valider, true, true, 3 )
52                 align1.add hbox3
53                 hbox_button.add align0
54                 hbox_button.add align1
55                 
56                 vbox.pack_start( hbox_button, false, false, 3 )
57                 
58                 self.add vbox
59         
60         end
61
62         def en_tete
63         
64                 # Objets
65                 @client = Gtk::Entry.new
66                 @date_document = Gtk::Entry.new
67                 @date_livraison = Gtk::Entry.new
68                 @label_livraison = Gtk::Label.new "Date de livraison :"
69                 @note = Gtk::TextView.new
70                 
71                 # Agencement            
72                 table = Gtk::Table.new 4, 3, false
73                 
74                 table.attach( Gtk::Label.new("Client :"), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
75                 table.attach( @client, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 5, 5 )
76                 
77                 table.attach( Gtk::Label.new("Date du document :"), 2, 3, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
78                 table.attach( @date_document, 3, 4, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
79                 
80                 table.attach( @label_livraison, 2, 3, 2, 3, Gtk::FILL, Gtk::FILL, 5, 5 )
81                 table.attach( @date_livraison, 3, 4, 2, 3, Gtk::FILL, Gtk::FILL, 5, 5 )
82                 
83                 scroll_note = Gtk::ScrolledWindow.new
84                 scroll_note.add @note
85                 scroll_note.set_policy Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC
86                 scroll_note.shadow_type = Gtk::SHADOW_IN
87                 
88                 align_note = Gtk::Alignment.new 0, 0, 0, 0
89                 align_note.add Gtk::Label.new( "Note :" )
90                 
91                 table.attach( align_note, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL, 5, 5 )
92                 table.attach( scroll_note, 0, 2, 2, 3, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 5, 5 )
93                 
94                 table
95         
96         end
97         
98         def lignes
99         
100                 @article_store = Gtk::ListStore.new(String)
101                 refresh_code_article
102                 
103                 # list_store (id, id_document, id_article, code, designation, qtite, id_tva, colisage, pu, remise, total_ligne)
104                 @list_store = Gtk::ListStore.new(Integer, Integer, Integer, String, String, Integer, String, Integer, String, Integer, String)
105                 @view = Gtk::TreeView.new(@list_store)
106                 @view.signal_connect ("row-activated") { |view, path, column|
107                          #p @view.model.get_value(@view.selection.selected, 0)
108                 }
109                 
110                 # Create a renderer with the background property set
111                 renderer_center = Gtk::CellRendererText.new
112                 renderer_center.background = "white"
113                 renderer_center.xalign = 0.5
114                 renderer_center.mode = Gtk::CellRendererText::MODE_EDITABLE
115                 
116                 # Create a renderer with the background property set
117                 renderer_left = Gtk::CellRendererText.new
118                 renderer_left.xalign = 0
119                 renderer_left.mode = Gtk::CellRendererText::MODE_EDITABLE
120                 
121                 # Create a renderer with the background property set
122                 renderer_right = Gtk::CellRendererText.new
123                 renderer_right.xalign = 1
124                 renderer_right.mode = Gtk::CellRendererText::MODE_EDITABLE
125                 
126                 # Create a renderer with the background property set
127                 renderer_right_bold = Gtk::CellRendererText.new
128                 renderer_right_bold.xalign = 1
129                 renderer_right_bold.mode = Gtk::CellRendererText::MODE_EDITABLE
130                 renderer_right_bold.background = "#eee"
131                 
132                 # Colonne pour le code article :
133                 renderer_code = Gtk::CellRendererText.new
134                 renderer_code.xalign = 0
135                 renderer_code.mode = Gtk::CellRendererText::MODE_EDITABLE
136                 renderer_code.editable = true
137                 renderer_code.signal_connect('edited') { |combo, data, text|
138                         edit_cell(data, text, 3)
139                 }  
140                 col = Gtk::TreeViewColumn.new("Code article", renderer_code, :text => 3)
141                 col.resizable = true
142                 @view.append_column(col)
143                 
144                 # Colonne pour la quantité :
145                 renderer_designation = Gtk::CellRendererText.new
146                 renderer_designation.xalign = 0
147                 renderer_designation.mode = Gtk::CellRendererText::MODE_EDITABLE
148                 renderer_designation.editable = true
149                 renderer_designation.signal_connect('edited') { |combo, data, text|
150                         if !text.empty? then
151                                 search = Search.new @window, text
152                                 search.run { |response| 
153                                         if ( !search.liste.view.selection.selected.nil? ) then
154                                                 code = search.liste.view.model.get_value( search.liste.view.selection.selected, 1 )
155                                                 add_article code, true
156                                         end
157                                         search.destroy                  
158                                 }
159                         end
160                 }  
161                 col = Gtk::TreeViewColumn.new("Désignation", renderer_designation, :text => 4)
162                 col.resizable = true
163                 col.expand = true
164                 @view.append_column(col)
165                 
166                 # Colonne pour la quantité :
167                 renderer_qtite = Gtk::CellRendererSpin.new
168                 renderer_qtite.adjustment = Gtk::Adjustment.new(0, 0, 999999, 1, 10, 0)
169                 renderer_qtite.xalign = 1
170                 renderer_qtite.mode = Gtk::CellRendererText::MODE_EDITABLE
171                 renderer_qtite.editable = true
172                 renderer_qtite.signal_connect('edited') { |combo, data, text|
173                         edit_cell(data, text, 5)
174                 } 
175                 col = Gtk::TreeViewColumn.new("Quantité", renderer_qtite, :text => 5)
176                 #col.sort_column_id = 5
177                 col.resizable = true
178                 @view.append_column(col)
179                 
180                 col = Gtk::TreeViewColumn.new("Colisage", renderer_right, :text => 7)
181                 #col.sort_column_id = 7
182                 col.resizable = true
183                 @view.append_column(col)
184                 
185                 # Colonne pour le PU :
186                 renderer_pu = Gtk::CellRendererSpin.new
187                 renderer_pu.adjustment = Gtk::Adjustment.new(0, 0, 999999, 1, 10, 0)
188                 renderer_pu.digits = 2
189                 renderer_pu.xalign = 1
190                 renderer_pu.mode = Gtk::CellRendererText::MODE_EDITABLE
191                 renderer_pu.editable = true
192                 renderer_pu.signal_connect('edited') { |combo, data, text|
193                         edit_cell(data, text, 8)
194                 } 
195                 col = Gtk::TreeViewColumn.new("Prix unitaire", renderer_pu, :text => 8)
196                 #col.sort_column_id = 8
197                 col.resizable = true
198                 @view.append_column(col)
199                 
200                 # Colonne pour la remise :
201                 renderer_remise = Gtk::CellRendererSpin.new
202                 renderer_remise.adjustment = Gtk::Adjustment.new(0, 0, 100, 1, 10, 0)
203                 renderer_remise.xalign = 1
204                 renderer_remise.mode = Gtk::CellRendererText::MODE_EDITABLE
205                 renderer_remise.editable = true
206                 renderer_remise.signal_connect('edited') { |combo, data, text|
207                         edit_cell(data, text, 9)
208                 } 
209                 col = Gtk::TreeViewColumn.new("Remise %", renderer_remise, :text => 9)
210                 #col.sort_column_id = 9
211                 col.resizable = true
212                 @view.append_column(col)
213                 
214                 col = Gtk::TreeViewColumn.new("Total ligne", renderer_right_bold, :text => 10)
215                 #col.sort_column_id = 10
216                 col.resizable = true
217                 @view.append_column(col)
218                 
219                 col = Gtk::TreeViewColumn.new("TVA", renderer_center, :text => 6)
220                 #col.sort_column_id = 6
221                 col.resizable = true
222                 @view.append_column(col)
223                 
224                 scroll = Gtk::ScrolledWindow.new
225         scroll.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)
226         scroll.add @view
227         
228         scroll
229         
230         end
231         
232         def pieds
233         
234                 @ht = Gtk::Entry.new
235                 @tva = Gtk::Entry.new
236                 @ttc = Gtk::Entry.new
237                 
238                 @ht.editable = false
239                 @ht.width_chars = 8
240                 @ht.xalign = 1
241                 @tva.editable = false
242                 @tva.width_chars = 8
243                 @tva.xalign = 1
244                 @ttc.editable = false
245                 @ttc.width_chars = 8
246                 @ttc.xalign = 1
247         
248                 align = Gtk::Alignment.new 1, 0, 0, 0
249                 
250                 table = Gtk::Table.new 3, 2, false
251                 align.add table
252                 
253                 table.attach( Gtk::Label.new("HT :"), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 2, 2 )
254                 table.attach( @ht, 1, 2, 0, 1, Gtk::EXPAND, Gtk::FILL, 2, 2 )
255                 
256                 table.attach( Gtk::Label.new("TVA :"), 0, 1, 1, 2, Gtk::FILL, Gtk::FILL, 2, 2 )
257                 table.attach( @tva, 1, 2, 1, 2, Gtk::EXPAND, Gtk::FILL, 2, 2 )
258                 
259                 table.attach( Gtk::Label.new("TTC :"), 0, 1, 2, 3, Gtk::FILL, Gtk::FILL, 2, 2 )
260                 table.attach( @ttc, 1, 2, 2, 3, Gtk::EXPAND, Gtk::FILL, 2, 2 )
261                 
262                 align
263         
264         end
265         
266         def refresh id, type
267         
268                 @id = id
269                 @type = type
270                 
271                 @ligne_modif_id = []
272                 
273                 @date_livraison.sensitive = type.eql?(3)
274                 
275                 if id>0 then
276                         @frame.label = @window.type_doc[type] + " n° #{id}" 
277                         
278                         req = "SELECT * FROM documents WHERE id=#{id}"
279                         res = @db.requete req
280                         
281                         remplir_en_tete res
282                         
283                         req = "SELECT T0.id, T0.id_document, T0.id_article, T0.code, T0.designation, T0.qtite, T0.id_tva, T0.colisage, T0.pu, T0.remise, T0.total_ligne FROM documents_lignes T0 WHERE id_document=#{id} ORDER BY T0.id"
284                         res = @db.requete req
285                         
286                         remplir_lignes res
287                         
288                         remplir_pieds
289                 else
290                         case type
291                                 when 1, 3
292                                         @frame.label = "Nouveau "
293                                 when 5
294                                         @frame.label = "Nouvel "
295                                 else
296                                         @frame.label = "Nouvelle "
297                         end
298                 
299                         @frame.label += @window.type_doc[type].downcase 
300                         
301                         empty_component
302                         @list_store.append
303                 end
304         
305         end
306         
307         def refresh_code_article
308                 
309                 @article_store.clear
310                 
311                 res = @db.requete "SELECT * FROM articles LIMIT 100"
312                 
313                 res.each { |h| 
314                         
315                         iter = @article_store.append
316                         iter[0] = h['code']
317                 }
318
319         
320         end
321         
322         def remplir_en_tete res
323         
324                 date_document = ""
325                 date_livraison = ""
326                 res.each { |doc|
327                         @client.text = doc['client']
328                         date_document = doc['date_document']
329                         date_livraison = doc['date_livraison']
330                         @note.buffer.text = doc['note']
331                 }
332                 @date_document.text = "#{date_document.split("-")[2]}/#{date_document.split("-")[1]}/#{date_document.split("-")[0]}"            
333                 @date_livraison.text = "#{date_livraison.split("-")[2]}/#{date_livraison.split("-")[1]}/#{date_livraison.split("-")[0]}"
334         
335         end
336         
337         def remplir_lignes res
338         
339                 @list_store.clear
340                 
341                 res.each { |h| 
342                         
343                         iter = @list_store.append
344                         iter[0] = h['id'].to_i
345                         iter[1] = h['id_document'].to_i
346                         iter[2] = h['id_article'].to_i
347                         iter[3] = h['code']
348                         iter[4] = h['designation']
349                         iter[5] = h['qtite'].to_i
350                         iter[6] = "%.2f" % h['id_tva']
351                         iter[7] = h['colisage'].to_i
352                         iter[8] = "%.2f" % h['pu']
353                         iter[9] = h['remise'].to_i
354                         iter[10] = "%.2f €" % h['total_ligne']
355                 }
356                 
357                 @list_store.append
358
359         end
360         
361         def remplir_pieds
362                 
363                 ht = 0.0
364                 tva = 0.0
365         
366                 @list_store.each { |model, path, iter|
367                         ligne = @view.model.get_iter(path)
368                         ht += ligne[10].to_f unless ligne[10].nil?
369                         tva += ligne[10].to_f*(ligne[6].to_f/100) unless ligne[10].nil? or ligne[6].nil? 
370                 }
371                 
372                 ht = ht.round(2)
373                 tva = tva.round(2)
374                 
375                 @ht.text = "%.2f €" % ht
376                 @tva.text = "%.2f €" % tva
377                 @ttc.text = "%.2f €" % (ht+tva).round(2)
378                 
379         end
380         
381         def empty_component
382         
383                 @client.text = ""
384                 @date_document.text = "#{DateTime.now.day}/#{DateTime.now.month}/#{DateTime.now.year}"
385                 @date_livraison.text = "#{DateTime.now.day+1}/#{DateTime.now.month}/#{DateTime.now.year}"
386                 @note.buffer.text = ""
387                 
388                 @list_store.clear
389                 
390                 @ht.text = "0 €"
391                 @tva.text = "0 €"
392                 @ttc.text = "0 €"
393         
394         end
395         
396         def edit_cell data, text, col
397         
398                 p text
399                 ligne = @view.model.get_iter(data)
400                 
401                 if !text.empty? then
402                         
403                         case col
404                         
405                                 when 3
406                                         add_article text                                        
407                                 when 4
408                                         ligne[col] = text
409                                 when 5
410                                         ligne[col] = text.to_i if text.to_i>=0
411                                 when 8
412                                         ligne[col] = text if text.to_f>=0.0
413                                 when 9
414                                         ligne[col] = text.to_i if (text.to_i>=0 and text.to_i<=100)
415                         
416                         end             
417                         
418                         calcule_total_ligne ligne
419                         
420                 end
421                 
422         end
423         
424         def add_article code, recalcule=false
425                 
426                 ligne = @view.selection.selected
427                 
428                 req = "SELECT * FROM articles WHERE code='#{code}'"
429                 res = @db.requete req
430                 
431                 if res.count>0 then
432                         article = res.first
433                         
434                         @list_store.append if ligne[3].nil?
435                         ligne[3] = code
436                         
437                         ligne[2] = article['id'].to_i
438                         ligne[4] = article['designation']
439                         ligne[6] = "%.2f" % article['id_tva']
440                         ligne[7] = article['colisage'].to_i
441                         ligne[8] = "%.2f" % article['pu']
442                         ligne[5] = 1 if ligne[5].eql?(0)
443                 
444                 end
445                 
446                 calcule_total_ligne ligne if recalcule
447                 
448                 # On indique quels sont les lignes qui ont été modifiées ou ajoutées
449                 id_ligne = @view.selection.selected[0]
450                 @ligne_modif_id << id_ligne unless @ligne_modif_id.include?(id_ligne)
451                 
452         end
453         
454         def calcule_total_ligne ligne
455                 ligne[10] = "%.2f €" % ( ligne[5]*ligne[8].to_f*ligne[7]*( 1-ligne[9].to_f/100 ) ).round(2)
456                 remplir_pieds
457         end
458         
459         def imprimer
460                 validate
461                 Edition.new @db, @id            
462         end
463         
464         def validate quitter=true
465                 
466                 jour = @date_document.text.split("/")[0].to_i
467                 jour_label = ( jour/10 >= 1 ? jour.to_s : "0#{jour}" )
468                 mois = @date_document.text.split("/")[1].to_i
469                 mois_label = ( mois/10 >= 1 ? mois.to_s : "0#{mois}" )
470                 
471                 date_document = "#{@date_document.text.split("/")[2]}-#{mois_label}-#{jour_label}"      
472                 
473                 jour = @date_livraison.text.split("/")[0].to_i
474                 jour_label = ( jour/10 >= 1 ? jour.to_s : "0#{jour}" )
475                 mois = @date_livraison.text.split("/")[1].to_i
476                 mois_label = ( mois/10 >= 1 ? mois.to_s : "0#{mois}" )
477                                         
478                 date_livraison = "#{@date_livraison.text.split("/")[2]}-#{mois_label}-#{jour_label}"    
479                         
480                 if @id>0 then
481                         req = "UPDATE documents SET "
482                         req += " client='#{@client.text.gsub("'", "''")}', date_document='#{date_document}', note='#{@note.buffer.text}', id_type_document=#{@type}, date_livraison='#{date_livraison}' "
483                         req += " WHERE id=#{@id}"
484                         
485                         if !@ligne_modif_id.empty? then
486                                 p @ligne_modif_id
487                                 
488                                 @list_store.each { |model, path, iter|
489                                         
490                                         id_ligne = @view.model.get_iter(path)[0]
491                                         
492                                         if ( @ligne_modif_id.include?(id_ligne) and !@view.model.get_iter(path)[3].nil? ) then
493                                         
494                                                 id_article = @view.model.get_iter(path)[2]
495                                                 code = @view.model.get_iter(path)[3].gsub("'", "''")
496                                                 designation = @view.model.get_iter(path)[4].gsub("'", "''")
497                                                 qtite = @view.model.get_iter(path)[5]
498                                                 id_tva = @view.model.get_iter(path)[6]
499                                                 colisage = @view.model.get_iter(path)[7]
500                                                 pu = @view.model.get_iter(path)[8]
501                                                 remise = @view.model.get_iter(path)[9]
502                                                 total_ligne = @view.model.get_iter(path)[10]
503                                                                 
504                                                 if id_ligne.eql?(0) then
505                                                         p "Insertion de ligne : #{id_article}"
506                                                         req_ligne = "INSERT INTO documents_lignes (id_document, id_article, qtite, id_tva, colisage, pu, remise, code, designation, total_ligne) "
507                                                         req_ligne += " VALUES (#{@id}, #{id_article}, #{qtite}, '#{id_tva}', #{colisage}, "
508                                                         req_ligne += " '#{pu}', #{remise}, '#{code}', '#{designation}', '#{total_ligne.to_f}') "
509                                                 else
510                                                         p "Modification de ligne : #{id_article}"
511                                                         req_ligne = "UPDATE documents_lignes SET "
512                                                         req_ligne += " id_article=#{id_article}, code='#{code}', designation='#{designation}', "
513                                                         req_ligne += " qtite=#{qtite}, id_tva='#{id_tva}', colisage=#{colisage}, pu='#{pu}', remise=#{remise}, total_ligne='#{total_ligne}' "
514                                                         req_ligne += " WHERE id=#{id_ligne} "
515                                                 end                             
516                                                 
517                                                 res = @db.requete req_ligne
518                                         
519                                         end
520                                         
521                                 }                               
522                                                                 
523                         end
524                         
525                 else                    
526                         p "Nouveau document"
527                         
528                         req = "INSERT INTO documents (client, date_document, note, id_type_document, date_livraison, id_user)"
529                         req += " VALUES ('#{@client.text.gsub("'", "''")}', '#{date_document}', '#{@note.buffer.text}', #{@type}, '#{date_livraison}', '#{@login.user.id}')"
530                 end
531                 
532                 res = @db.requete req
533                 
534                 if (res.empty? and @id.eql?(0)) then
535                 
536                         req = "SELECT id FROM documents ORDER BY id DESC LIMIT 1"
537                         res = @db.requete req
538                         
539                         @id = res.first['id']
540                         
541                         @list_store.each { |model, path, iter|
542                                         
543                                 if !@view.model.get_iter(path)[3].nil? then
544                                         
545                                         id_ligne = @view.model.get_iter(path)[0]
546                                         id_article = @view.model.get_iter(path)[2]
547                                         code = @view.model.get_iter(path)[3].gsub("'", "''")
548                                         designation = @view.model.get_iter(path)[4].gsub("'", "''")
549                                         qtite = @view.model.get_iter(path)[5]
550                                         id_tva = @view.model.get_iter(path)[6]
551                                         colisage = @view.model.get_iter(path)[7]
552                                         pu = @view.model.get_iter(path)[8]
553                                         remise = @view.model.get_iter(path)[9]
554                                         total_ligne = @view.model.get_iter(path)[10]
555                                                         
556                                         p "Insertion de ligne"
557                                         req_ligne = "INSERT INTO documents_lignes (id_document, id_article, qtite, id_tva, colisage, pu, remise, code, designation, total_ligne) "
558                                         req_ligne += " VALUES (#{@id}, #{id_article}, #{qtite}, '#{id_tva}', #{colisage}, "
559                                         req_ligne += " '#{pu}', #{remise}, '#{code}', '#{designation}', '#{total_ligne}') "
560                                         res = @db.requete req_ligne
561                                         
562                                 end
563                         }
564                 
565                 end
566                 
567                 quit @type if quitter
568         
569         end
570         
571         def quit statut=nil
572                 
573                 @window.liste_documents.refresh statut unless statut.nil?       
574                 @window.affiche @window.liste_documents
575         
576         end
577         
578 end