Ajour des Fiches d'intervention + corrections de divers bugs
[bilio:bilio.git] / src / intervention.rb
1 # coding: utf-8
2
3 class Intervention_box < Gtk::VBox
4
5         attr_reader :doc
6         
7         def initialize window
8         
9                 super(false, 3)
10                 
11                 set_border_width 10
12                 
13                 @window = window
14                 @login = window.login
15                 
16                 @id = 0
17                 @mail = ""
18                 
19                 @ligne_modif_id = []
20                 @ligne_supp_id = []
21                 
22                 @imprimer = Gtk::Button.new
23                 hbox_imprimer = Gtk::HBox.new false, 2
24                 hbox_imprimer.add Gtk::Image.new( "./resources/icons/print.png" )
25                 hbox_imprimer.add Gtk::Label.new "Imprimer"
26                 @imprimer.add hbox_imprimer
27                 
28                 @valider = Gtk::Button.new
29                 hbox_valider = Gtk::HBox.new false, 2
30                 hbox_valider.add Gtk::Image.new( "./resources/icons/ok.png" )
31                 hbox_valider.add Gtk::Label.new "Valider"
32                 @valider.add hbox_valider
33                 
34                 @annuler = Gtk::Button.new
35                 hbox_annuler = Gtk::HBox.new false, 2
36                 hbox_annuler.add Gtk::Image.new( "./resources/icons/cancel.png" )
37                 hbox_annuler.add Gtk::Label.new "Annuler"
38                 @annuler.add hbox_annuler
39                 
40                 @transfert = Gtk::Button.new
41                 hbox_transfert = Gtk::HBox.new false, 2
42                 hbox_transfert.add Gtk::Image.new( "./resources/icons/transfert.png" )
43                 hbox_transfert.add Gtk::Label.new "Transférer"
44                 @transfert.add hbox_transfert
45                 
46                 @email = Gtk::Button.new
47                 hbox_email = Gtk::HBox.new false, 2
48                 hbox_email.add Gtk::Image.new( "./resources/icons/transfert.png" )
49                 hbox_email.add Gtk::Label.new "Email"
50                 @email.add hbox_email
51                 
52                 agencement
53                 
54                 @valider.signal_connect( "clicked" ) { validate }
55                 @annuler.signal_connect( "clicked" ) { quit }
56                 @imprimer.signal_connect( "clicked" ) { imprimer }
57                 @transfert.signal_connect("clicked") { transfert }
58                 @email.signal_connect("clicked") { mailer }
59         
60         end
61         
62         def agencement
63         
64                 vbox = Gtk::VBox.new false, 3
65                 @frame = Gtk::Frame.new
66                 @frame.label = "Nouvelle intervention"
67                 vbox.pack_start( @frame, true, true, 3 )
68                 
69                 vbox_corps = Gtk::VBox.new false, 3
70                 @frame.add vbox_corps
71                 vbox_corps.pack_start( en_tete, false, false, 3 )
72                 vbox_corps.pack_start( lignes, true, true, 3 )
73                 vbox_corps.pack_start( pieds, false, false, 3 )
74                 
75                 hbox_button = Gtk::HBox.new false, 2
76                 hbox2 = Gtk::HBox.new false, 2
77                 hbox2.pack_start( @imprimer, true, true, 3 )
78                 hbox2.pack_start( @email, true, true, 3 )
79                 hbox2.pack_start( @transfert, true, true, 3 )
80                 hbox3 = Gtk::HBox.new false, 2
81                 align0 = Gtk::Alignment.new 0, 0, 0, 0
82                 align0.add hbox2
83                 align1 = Gtk::Alignment.new 1, 1, 0, 0
84                 hbox3.pack_start( @annuler, true, true, 3 )
85                 hbox3.pack_start( @valider, true, true, 3 )
86                 align1.add hbox3
87                 hbox_button.add align0
88                 hbox_button.add align1
89                 
90                 vbox.pack_start( hbox_button, false, false, 3 )
91                 
92                 self.add vbox
93         
94         end
95
96         def en_tete
97         
98                 # Objets
99                 @id_client = 0
100                 @client = Gtk::Entry.new
101                 @date = Gtk::Entry.new
102                 @note = Gtk::TextView.new       
103                 @note_priv = Gtk::TextView.new          
104                 @tranfere = false
105                 
106                 # Propriétés
107                 @note.wrap_mode = Gtk::TextTag::WRAP_WORD
108                 @note.set_size_request(10, 60)
109                 @note_priv.wrap_mode = Gtk::TextTag::WRAP_WORD
110                 @note_priv.set_size_request(10, 60)
111                 @client.primary_icon_stock = Gtk::Stock::FIND
112                 
113                 # Agencement            
114                 table = Gtk::Table.new 6, 3, false
115                 
116                 table.attach( Gtk::Label.new("Client :"), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
117                 table.attach( @client, 1, 4, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::FILL, 5, 5 )
118                 
119                 table.attach( Gtk::Label.new("Date de l'intervention :"), 4, 5, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
120                 table.attach( @date, 5, 6, 0, 1, Gtk::FILL, Gtk::FILL, 5, 5 )
121                 
122                 @client.signal_connect('activate') { 
123                         chercher_tiers @client.text
124                 }
125                 
126                 @client.signal_connect('icon-press') { 
127                         chercher_tiers @client.text
128                 }
129                 
130                 table
131         
132         end
133         
134         def chercher_tiers text
135                 search = SearchTiers.new @window, @client.text, 0
136                 search.run { |response| 
137                         if ( !search.liste.view.selection.selected.nil? ) then
138                                 @client.sensitive = false
139                                 @client.text = search.liste.view.model.get_value( search.liste.view.selection.selected, 1 )
140                                 @id_client = search.liste.view.model.get_value( search.liste.view.selection.selected, 0 )
141                                 @mail = search.liste.view.model.get_value( search.liste.view.selection.selected, 9 )
142                                 @email.sensitive = @mail.nil? ? false : !@mail.empty?
143                         else
144                                 @client.text = ""
145                         end
146                         search.destroy
147                         focus_dernière_ligne unless @client.sensitive?
148                 }
149         end
150         
151         def lignes
152                 
153                 # list_store (                      id,   id_document, commentaire duree trash)
154                 @list_store = Gtk::ListStore.new(Integer, Integer, String, String, Gdk::Pixbuf)
155                 @view = Gtk::TreeView.new(@list_store)  
156                 
157                 @view.signal_connect ("button-release-event") { |tree,event|
158                         # Si clic gauche
159                         e = npath = @view.get_path_at_pos(event.x, event.y)
160                         if (e and event.button.eql?(1))
161                                 colonne = e[1]
162                                 #si clic sur colonne supprimer
163                                 if colonne.eql?(@view.get_column(2))
164                                         suppr_ligne @list_store.get_iter(e[0])
165                                 #si clic sur colonne commentaire
166                                 elsif colonne.eql?(@view.get_column(0))
167                                         modif_commentaire @list_store.get_iter(e[0])
168                                 end
169                         end
170                 }       
171                 
172                 renderer_commentaires = Gtk::CellRendererText.new
173                 renderer_commentaires.xalign = 0
174                 renderer_commentaires.yalign = 0
175                 renderer_commentaires.mode = Gtk::CellRendererText::MODE_EDITABLE 
176                 col = Gtk::TreeViewColumn.new("Commentaires", renderer_commentaires, :text => 2)
177                 col.resizable = true
178                 col.expand = true
179                 @view.append_column(col)
180                 
181                 # Colonne pour la duree :
182                 renderer_duree = Gtk::CellRendererSpin.new
183                 renderer_duree.adjustment = Gtk::Adjustment.new(0, 0, 999999, 1, 10, 0)
184                 renderer_duree.digits = 2
185                 renderer_duree.xalign = 1
186                 renderer_duree.yalign = 0
187                 renderer_duree.mode = Gtk::CellRendererText::MODE_EDITABLE
188                 renderer_duree.editable = true
189                 renderer_duree.signal_connect('edited') { |combo, data, text|
190                         ligne = @view.model.get_iter(data)
191                         ligne[3] = "%.2f" % text.to_f
192                         remplir_pieds
193                 } 
194                 col = Gtk::TreeViewColumn.new("Durée", renderer_duree, :text => 3)
195                 col.resizable = true
196                 #col.sort_column_id = 5
197                 @view.append_column(col)
198                 
199                 # Colonne pour la corbeille
200                 renderer_pix = Gtk::CellRendererPixbuf.new      
201                 renderer_pix.xalign = 0.5
202                 renderer_pix.yalign = 0
203                 @pix_trash = Gdk::Pixbuf.new("resources/icons/trash-full.png", 20, 20)
204                 col = Gtk::TreeViewColumn.new("", renderer_pix, :pixbuf => 4)
205                 col.resizable = true
206                 @view.append_column(col)
207                 
208                 scroll = Gtk::ScrolledWindow.new
209         scroll.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC)
210         scroll.add @view
211         
212         scroll
213         
214         end
215         
216         def modif_commentaire ligne
217                 if possible_modif?
218                         mod = DialCommentaire.new @window, ligne[2]
219                         mod.run { |response| 
220                                 text = ""
221                                 modif = false
222                                 if response.eql?(-5)
223                                         text = mod.memo.buffer.text
224                                         modif = true
225                                 end
226                                 mod.destroy
227                                 ajout_commentaire ligne, text if modif
228                         }
229                 end
230         end
231         
232         def ajout_commentaire ligne, text
233                 ligne[2] = text
234                 @ligne_modif_id << ligne[0] unless @ligne_modif_id.include?(ligne[0])
235                 ligne[4] = @pix_trash
236                 # On détermine le nombre de lignes
237                 i = -1
238                 @list_store.each { i += 1 }
239                 n = @view.selection.selected.path.to_s.to_i
240                 # Nouvelle ligne si on est sur une ligne de commentaire seul
241                 if (ligne[0].eql?(0) and i.eql?(n))
242                         iter = @list_store.append
243                         iter[4] = @pix_comm
244                 end             
245                 
246         end
247         
248         def suppr_ligne ligne, conf=true
249         
250                 if possible_modif?
251                 
252                         if conf
253                                 suppr = false
254                         
255                                 dialog = Gtk::MessageDialog.new(@window, 
256                                             Gtk::Dialog::DESTROY_WITH_PARENT,
257                                             Gtk::MessageDialog::QUESTION,
258                                             Gtk::MessageDialog::BUTTONS_YES_NO,
259                                             "Voulez-vous réellement supprimer cette ligne ?")
260                                 response = dialog.run
261                                 case response
262                                   when Gtk::Dialog::RESPONSE_YES
263                                         suppr = true
264                                 end 
265                                 dialog.destroy
266                         else
267                                 suppr = true
268                         end
269                 
270                         if suppr
271                                 # Si la ligne était déjà enregistrée dans la base, on la marque à supprimer
272                                 @ligne_supp_id << ligne[0].to_i if ligne[0].to_i>0              
273
274                                 # On réinitialise les valeurs des champs
275                                 ligne[0] = ligne[1] = 0
276                                 ligne[2] = ""
277                                 ligne[3] = 0.0
278                 
279                                 # On détermine le nombre de lignes
280                                 i = -1
281                                 @list_store.each { i += 1 }
282                                 n = @view.selection.selected.path.to_s.to_i
283                 
284                                 # Puis on retire la ligne du tableau sauf si il s'agit de la dernière ligne
285                                 @list_store.remove @view.selection.selected unless i.eql?(n)
286                 
287                                 # on recalcule le pieds
288                                 remplir_pieds
289                         end
290                 end
291         
292         end
293         
294         def pieds
295         
296                 @duree = Gtk::Entry.new
297                 
298                 @duree.editable = false
299                 @duree.width_chars = 8
300                 @duree.xalign = 1
301                 
302                 table_montants = Gtk::Table.new 1,1,false
303                 
304                 table_montants.attach( Gtk::Label.new("Durée totale :"), 0, 1, 0, 1, Gtk::FILL, Gtk::FILL, 2, 2 )
305                 table_montants.attach( @duree, 1, 2, 0, 1, Gtk::FILL, Gtk::FILL, 2, 2 )
306                 
307                 table_montants
308         
309         end
310         
311         def ged
312                 @ged = Ged_box.new @window, type="documents"
313         end
314         
315         def refresh id
316         
317                 @id = id                
318                 @ligne_modif_id = []
319                 @ligne_supp_id = []             
320                 
321                 if id>0 then
322                         
323                         @intervention = Intervention.includes(:tiers).where(:id => id).first
324                         if @intervention then
325                                 remplir_en_tete @intervention
326                         end
327                         
328                         interventionlignes = Interventionligne.where(:intervention_id => id).order(:id)
329                         if interventionlignes then
330                                 remplir_lignes interventionlignes
331                         end
332                         
333                         remplir_pieds
334                 else
335                         @intervention = Intervention.new
336                         empty_component
337                         iter = @list_store.append
338                         iter[4] = @pix_trash
339                         @intervention.duree = 0.0
340                         @mail = ""      
341                 end
342                 
343                 @email.sensitive = !@mail.empty? unless @mail.nil?
344         
345         end
346         
347         def remplir_en_tete intervention
348
349                 @id_client = intervention.tiers_id
350                 @client.text = intervention.tiers.nom
351                 @mail = intervention.tiers.mail
352                 @client.sensitive = false
353                 date = intervention.date.to_s
354                 begin
355                         @date.text = Date.parse(date).strftime("%d/%m/%Y")
356                 rescue
357                 end
358                 #@transfert.sensitive = (!@transfere and !@type.eql?(5) and !@type.eql?(8))
359         end
360         
361         def remplir_lignes interventionlignes
362         
363                 @list_store.clear
364                 
365                 interventionlignes.each { |h| 
366                         
367                         iter = @list_store.append
368                         iter[0] = h.id
369                         iter[1] = h.intervention_id
370                         iter[2] = h.commentaire
371                         iter[3] = "%.2f" % h.duree
372                         iter[4] = @pix_trash
373                 }
374                 
375                 iter = @list_store.append
376                 iter[4] = @pix_trash
377
378         end
379         
380         def remplir_pieds
381                 
382                 duree = 0.0
383         
384                 @list_store.each { |model, path, iter|
385                         ligne = @view.model.get_iter(path)
386                         duree += ligne[3].to_f unless ligne[3].nil?
387                 }
388                 
389                 duree = duree.round(2)
390                 
391                 @duree.text = "%.2f €" % duree
392                 
393         end
394         
395         def empty_component entierement=true
396         
397                 @client.text = "" if entierement
398                 @client.sensitive = true if entierement
399                 @id_client = 0 if entierement
400                 date = DateTime.now
401                 @date.text = date.strftime("%d/%m/%Y")
402                 
403                 @list_store.clear if entierement
404                 
405                 @duree.text = "0 €" if entierement
406         
407         end
408         
409         # Indique si le document est modifiable ou pas
410         def possible_modif?
411                 return true
412         end
413         
414         def focus_dernière_ligne
415                 Thread.new { 
416                         sleep 0
417                         # on trouve la dernière ligne du tableau
418                         npath = nil
419                         @view.model.each {|model, path, iter| 
420                                 npath = path
421                         }
422                         # et on met le focus sur la première colonne.
423                         @view.set_cursor(npath, @view.get_column(0), true)
424                 }
425         end
426         
427         def imprimer
428                 validate
429                 chemin = @window.config_db.chemin_temp
430                 Edition.new [@doc.id], chemin
431                 if RUBY_PLATFORM.include?("linux") then 
432                         system "xdg-open","#{chemin}/#{@doc.ref}.pdf"
433                 else
434                         if RUBY_PLATFORM.include?("mingw") then 
435                                 system "start","#{chemin}/#{@doc.ref}.pdf"
436                         else
437                                 
438                         end
439                 end
440         end
441         
442         def mailer
443                 validate
444                 chemin = @window.config_db.chemin_temp
445                 Edition.new [@doc.id], chemin
446                 if RUBY_PLATFORM.include?("linux") then 
447                         system "xdg-email --subject '#{@window.type_doc[@type][:nom].downcase}' --attach #{chemin}/#{@doc.ref}.pdf #{@mail}" 
448                 else
449                         if RUBY_PLATFORM.include?("mingw") then 
450                                 # TODO
451                         else
452                                 
453                         end
454                 end
455         end
456         
457         def validate quitter=true
458         
459                 continu = true
460                 begin
461                         date = Date.parse(@date.text).strftime("%Y-%m-%d")
462                 rescue
463                         continu = false
464                         erreur = "Il y a un problème de date. Veuillez les vérifier."
465                         dialog = Gtk::MessageDialog.new @window, Gtk::Dialog::MODAL, Gtk::MessageDialog::ERROR, Gtk::MessageDialog::BUTTONS_CLOSE, erreur
466                         dialog.title = "Erreur"
467                         dialog.signal_connect('response') { dialog.destroy }
468                         dialog.run
469                         return false                     
470                 end
471                 
472                 if continu
473                         
474                         res = !@id_client.eql?(0)  # Il faut qu'un client soit sélectionné pour pouvoir enregistrer le document !
475                         
476                         if res then
477                                 
478                                 @intervention.tiers_id = @id_client
479                                 @intervention.date = date
480                                 @intervention.utilisateur_id = @login.user.id
481                                 @intervention.duree = @duree.text.to_f
482                         
483                                 res = @intervention.save
484                         else
485                                 erreur = "Vous devez sélectionner un client valide !"
486                                 dialog = Gtk::MessageDialog.new @window, Gtk::Dialog::MODAL, Gtk::MessageDialog::ERROR, Gtk::MessageDialog::BUTTONS_CLOSE, erreur
487                                 dialog.title = "Erreur"
488                                 dialog.signal_connect('response') { dialog.destroy }
489                                 dialog.run                               
490                         end
491                 
492                         if res and !@ligne_modif_id.empty? then
493                         
494                                 @list_store.each { |model, path, iter|
495                                 
496                                         if !@view.model.get_iter(path)[2].nil?
497                                                 id_ligne = @view.model.get_iter(path)[0]
498                                                 commentaire = @view.model.get_iter(path)[2]
499                                                 duree = @view.model.get_iter(path)[3]
500                                                 
501                                                 dl = nil
502                                                 if id_ligne>0 then
503                                                         dl = Interventionligne.find(id_ligne)
504                                                 else
505                                                         dl = Interventionligne.new
506                                                 end
507                                         
508                                                 dl.intervention_id = @intervention.id
509                                                 dl.commentaire = commentaire
510                                                 dl.duree = duree
511                                         
512                                                 res = dl.save
513                                 
514                                         end
515                                 
516                                 }
517                         
518                         end
519                 
520                         if res then 
521                                 # suppression en base des lignes supprimées dans le tableau
522                                 @ligne_supp_id.each { |l|                                                               
523                                         dl = Interventionligne.find(l)                          
524                                         if dl then
525                                                 res = dl.destroy
526                                                 p "Suppresion de ligne : #{l}" if res
527                                         end                             
528                                 }
529                         end
530                 
531                         if res
532                                 if quitter
533                                         quit @type
534                                 else
535                                         refresh @intervention.id
536                                 end
537                         end
538                         return res
539                 end
540         end
541         
542         def focus
543                 @client.grab_focus
544         end
545         
546         def quit statut=nil
547                 
548                 @window.liste_interventions.refresh
549                 @window.affiche @window.liste_interventions
550         
551         end
552         
553 end