Subversion Repositories delphiutils

Rev

Rev 79 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
78 daniel-mar 1
unit ZeiterfassungMain;
2
 
3
interface
4
 
5
uses
6
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7
  Dialogs, DB, ADODB, Grids, Wwdbigrd, Wwdbgrid, ExtCtrls, DBCtrls, StdCtrls;
8
 
9
type
10
  TForm1 = class(TForm)
11
    ADOConnection1: TADOConnection;
12
    wwDBGrid1: TwwDBGrid;
13
    ADOTable1: TADOTable;
14
    DataSource1: TDataSource;
15
    ADOTable1TAG: TWideStringField;
16
    ADOTable1KOMMEN: TWideStringField;
17
    ADOTable1PAUSE_START: TWideStringField;
18
    ADOTable1PAUSE_ENDE: TWideStringField;
19
    ADOTable1GEHEN: TWideStringField;
20
    ADOTable1SONSTIGER_ABZUG: TWideStringField;
21
    ADOTable1ZUHAUSE: TWideStringField;
22
    ADOTable1BERSTUNDEN_SALDO: TIntegerField;
23
    ADOTable1BERSTUNDEN: TIntegerField;
24
    ADOTable1FREIER_TAG: TBooleanField;
25
    Panel1: TPanel;
26
    Button1: TButton;
27
    DBNavigator1: TDBNavigator;
28
    ADOTable1WOCHENTAG: TStringField;
29
    ADOTable1USERNAME: TStringField;
30
    ComboBox1: TComboBox;
31
    Label1: TLabel;
32
    Label2: TLabel;
33
    procedure ADOTable1NewRecord(DataSet: TDataSet);
34
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
35
    procedure ADOTable1BeforePost(DataSet: TDataSet);
36
    procedure ADOTable1BERSTUNDEN_SALDOGetText(Sender: TField; var Text: string;
37
      DisplayText: Boolean);
38
    procedure ADOTable1BERSTUNDENGetText(Sender: TField; var Text: string;
39
      DisplayText: Boolean);
40
    procedure wwDBGrid1CalcCellColors(Sender: TObject; Field: TField;
41
      State: TGridDrawState; Highlight: Boolean; AFont: TFont; ABrush: TBrush);
42
    procedure ADOTable1AfterPost(DataSet: TDataSet);
43
    procedure Button1Click(Sender: TObject);
44
    procedure ADOTable1TAGChange(Sender: TField);
45
    procedure ADOTable1SONSTIGER_ABZUGSetText(Sender: TField;
46
      const Text: string);
47
    procedure ADOTable1ZUHAUSESetText(Sender: TField; const Text: string);
48
    procedure ADOTable1GEHENSetText(Sender: TField; const Text: string);
49
    procedure ADOTable1PAUSE_ENDESetText(Sender: TField; const Text: string);
50
    procedure ADOTable1PAUSE_STARTSetText(Sender: TField; const Text: string);
51
    procedure ADOTable1KOMMENSetText(Sender: TField; const Text: string);
52
    procedure FormShow(Sender: TObject);
53
    procedure ADOTable1WOCHENTAGGetText(Sender: TField; var Text: string;
54
      DisplayText: Boolean);
55
    procedure ComboBox1Change(Sender: TObject);
56
    procedure ADOTable1TAGSetText(Sender: TField; const Text: string);
57
    procedure ADOTable1AfterDelete(DataSet: TDataSet);
58
    procedure ADOTable1TAGGetText(Sender: TField; var Text: string;
59
      DisplayText: Boolean);
60
    procedure ADOTable1KOMMENGetText(Sender: TField; var Text: string;
61
      DisplayText: Boolean);
62
    procedure ADOTable1PAUSE_STARTGetText(Sender: TField; var Text: string;
63
      DisplayText: Boolean);
64
    procedure ADOTable1PAUSE_ENDEGetText(Sender: TField; var Text: string;
65
      DisplayText: Boolean);
66
    procedure ADOTable1GEHENGetText(Sender: TField; var Text: string;
67
      DisplayText: Boolean);
68
    procedure ADOTable1SONSTIGER_ABZUGGetText(Sender: TField; var Text: string;
69
      DisplayText: Boolean);
70
    procedure ADOTable1ZUHAUSEGetText(Sender: TField; var Text: string;
71
      DisplayText: Boolean);
72
  private
73
    function GueltigeZeile: boolean;
74
  protected
75
    procedure ReorgDataSet;
76
    procedure ReorgAll;
77
    function RegelArbeitszeit: integer;
78
  end;
79
 
80
var
81
  Form1: TForm1;
82
 
83
implementation
84
 
85
{$R *.dfm}
86
 
87
// TODO: Trennstriche zwischen Wochen oder zwischen Urlauben
88
// TODO: Anmerkungen
89
 
90
uses
91
  DateUtils, StrUtils, IniFiles;
92
 
93
{$REGION 'Hilfsfunktionen'}
94
 
95
function SQL_Escape(const s: string): string;
96
begin
97
  result := StringReplace(s, '''', '\''', [rfReplaceAll]);
98
end;
99
 
100
function IstLeer(f: TField): boolean;
101
begin
102
  result := f.IsNull or (f.AsString = '') or (f.AsString = '00:00:00');
103
end;
104
 
105
function Minuten(f: TField): integer;
106
begin
107
  if IstLeer(f) then
108
  begin
109
    result := 0;
110
  end
111
  else
112
  begin
113
    result := MinuteOfTheDay(f.AsDateTime);
114
  end;
115
end;
116
 
117
function MinutenZuHF(f: TField): string;
118
var
119
  d: integer;
120
begin
121
  if IstLeer(f) then
122
  begin
123
    result := '';
124
  end
125
  else
126
  begin
127
    d := f.AsInteger;
128
    if d < 0 then
129
    begin
130
      result := '-';
131
      d := -d;
132
    end
133
    else
134
    begin
135
      result := '';
136
    end;
137
    result := result + Format('%.2d:%.2d', [d div 60, d mod 60]);
138
  end;
139
end;
140
 
141
function EchtesDatum(f: TField): TDate;
142
begin
143
  if Copy(f.AsString, 5, 1) = '-' then
144
  begin
145
    result := EncodeDate(
146
    StrtoInt(Copy(f.AsString, 1, 4)),
147
    StrtoInt(Copy(f.AsString, 6, 2)),
148
    StrtoInt(Copy(f.AsString, 9, 2))
149
    );
150
  end
151
  else
152
    result := StrToDate(f.AsString);
153
end;
154
 
155
function WUserName: String;
156
var
157
  nSize: DWord;
158
begin
159
  nSize := 1024;
160
  SetLength(Result, nSize);
161
  if GetUserName(PChar(Result), nSize) then
162
    SetLength(Result, nSize-1)
163
  else
164
    RaiseLastOSError;
165
end;
166
 
167
{$ENDREGION}
168
 
169
function TForm1.RegelArbeitszeit: integer;
170
var
171
  test: TADOQuery;
172
begin
173
  test := TADOQuery.Create(nil);
174
  try
175
    test.Connection := ADOConnection1;
176
    test.Close;
177
    test.SQL.Text := 'select MINUTEN from REGELARBEITSZEIT where USERNAME = ''' + SQL_Escape(ComboBox1.Text) + '''';
178
    test.Open;
179
    if test.RecordCount = 0 then
180
    begin
181
      result := 8 * 60;
182
    end
183
    else
184
    begin
185
      result := test.FieldByName('MINUTEN').AsInteger;
186
    end;
187
  finally
188
    test.Free;
189
  end;
190
end;
191
 
192
procedure TForm1.ReorgAll;
193
var
194
  saldo: integer;
195
  baks: string;
196
  bakEv: TDataSetNotifyEvent;
197
  dead: boolean;
198
begin
199
  if ADOTable1.ReadOnly then exit;
200
 
201
  if ADOTable1TAG.IsNull then
202
  begin
203
    baks := '';
204
  end
205
  else
206
  begin
207
    if Copy(ADOTable1TAG.AsString, 5, 1) = '-' then
208
      baks := ADOTable1TAG.AsString
209
    else
210
      DateTimeToString(baks, 'YYYY-MM-DD', ADOTable1TAG.AsDateTime);
211
  end;
212
  bakEv := ADOTable1.AfterPost;
213
  ADOTable1.AfterPost := nil;
214
  ADOTable1.Requery();
215
  try
216
    ADOTable1.First;
217
    saldo := 0;
218
    dead := false;
219
    while not ADOTable1.Eof do
220
    begin
221
      ADOTable1.Edit;
222
      if not dead then ReorgDataSet;
223
      dead := dead or ADOTable1BERSTUNDEN.IsNull;
224
      if dead then
225
      begin
226
        ADOTable1BERSTUNDEN_SALDO.Clear;
227
      end
228
      else
229
      begin
230
        saldo := saldo + ADOTable1BERSTUNDEN.AsInteger;
231
        ADOTable1BERSTUNDEN_SALDO.AsInteger := saldo;
232
        saldo := ADOTable1BERSTUNDEN_SALDO.AsInteger;
233
      end;
234
      ADOTable1.Post;
235
      ADOTable1.Next;
236
    end;
237
  finally
238
    if baks <> '' then ADOTable1.Locate('USERNAME;TAG', VarArrayOf([WUserName, baks]), []);
239
    ADOTable1.AfterPost := bakEv;
240
  end;
241
end;
242
 
243
procedure TForm1.ADOTable1AfterDelete(DataSet: TDataSet);
244
begin
245
  ReorgAll;
246
end;
247
 
248
procedure TForm1.ADOTable1AfterPost(DataSet: TDataSet);
249
begin
250
  ReorgAll;
251
end;
252
 
253
function TForm1.GueltigeZeile: boolean;
254
begin
255
  result := false;
256
 
257
  if IstLeer(ADOTable1KOMMEN) <> IstLeer(ADOTable1GEHEN) then exit;
258
  if IstLeer(ADOTable1PAUSE_START) <> IstLeer(ADOTable1PAUSE_ENDE) then exit;
259
  if not IstLeer(ADOTable1PAUSE_START) and (ADOTable1PAUSE_START.AsDateTime < ADOTable1KOMMEN.AsDateTime) then exit;
260
  if not IstLeer(ADOTable1PAUSE_ENDE) and (ADOTable1PAUSE_ENDE.AsDateTime < ADOTable1PAUSE_START.AsDateTime) then exit;
261
  if not IstLeer(ADOTable1GEHEN) and (ADOTable1GEHEN.AsDateTime < ADOTable1KOMMEN.AsDateTime) then exit;
262
  if not IstLeer(ADOTable1GEHEN) and not IstLeer(ADOTable1PAUSE_START) and (ADOTable1GEHEN.AsDateTime < ADOTable1PAUSE_START.AsDateTime) then exit;
263
  if not IstLeer(ADOTable1GEHEN) and not IstLeer(ADOTable1PAUSE_ENDE) and (ADOTable1GEHEN.AsDateTime < ADOTable1PAUSE_ENDE.AsDateTime) then exit;
264
 
265
  result := true;
266
end;
267
 
268
procedure TForm1.ReorgDataSet;
269
var
270
  m: integer;
271
begin
272
  if GueltigeZeile then
273
  begin
274
    m :=   (Minuten(ADOTable1GEHEN) - Minuten(ADOTable1KOMMEN))
275
         - (Minuten(ADOTable1PAUSE_ENDE) - Minuten(ADOTable1PAUSE_START))
276
         - Minuten(ADOTable1SONSTIGER_ABZUG)
277
         + Minuten(ADOTable1ZUHAUSE);
278
 
279
    if not ADOTable1FREIER_TAG.AsBoolean then
280
    begin
281
      m := m - RegelArbeitszeit;
282
    end;
283
 
284
    ADOTable1BERSTUNDEN.AsInteger := m;
285
  end
286
  else
287
  begin
288
    ADOTable1BERSTUNDEN.Clear;
289
  end;
290
end;
291
 
292
procedure TForm1.ADOTable1BeforePost(DataSet: TDataSet);
293
begin
294
  if (ADOTable1.State = dsInsert) and ADOTable1TAG.IsNull then
295
  begin
296
    AdoTable1.Cancel;
297
    Abort;
298
  end;
299
 
300
  ReorgDataSet;
301
end;
302
 
303
procedure TForm1.ADOTable1BERSTUNDENGetText(Sender: TField; var Text: string;
304
  DisplayText: Boolean);
305
begin
306
  Text := MinutenZuHF(ADOTable1BERSTUNDEN);
307
end;
308
 
309
procedure TForm1.ADOTable1BERSTUNDEN_SALDOGetText(Sender: TField;
310
  var Text: string; DisplayText: Boolean);
311
begin
312
  Text := MinutenZuHF(ADOTable1BERSTUNDEN_SALDO);
313
end;
314
 
315
procedure TForm1.ADOTable1GEHENGetText(Sender: TField; var Text: string;
316
  DisplayText: Boolean);
317
begin
318
  Text := Copy(Sender.AsString, 1, 5);
319
end;
320
 
321
procedure TForm1.ADOTable1GEHENSetText(Sender: TField; const Text: string);
322
begin
323
  if Text = '' then
324
  begin
325
    ADOTable1GEHEN.Clear;
326
  end
327
  else
328
  begin
329
    ADOTable1GEHEN.AsString := Text;
330
  end;
331
end;
332
 
333
procedure TForm1.ADOTable1KOMMENGetText(Sender: TField; var Text: string;
334
  DisplayText: Boolean);
335
begin
336
  Text := Copy(Sender.AsString, 1, 5);
337
end;
338
 
339
procedure TForm1.ADOTable1KOMMENSetText(Sender: TField; const Text: string);
340
begin
341
  if Text = '' then
342
  begin
343
    ADOTable1KOMMEN.Clear;
344
  end
345
  else
346
  begin
347
    ADOTable1KOMMEN.AsString := Text;
348
  end;
349
end;
350
 
351
procedure TForm1.ADOTable1NewRecord(DataSet: TDataSet);
352
var
353
  test: TADOQuery;
354
begin
355
  ADOTable1FREIER_TAG.AsBoolean := false;
356
  ADOTable1USERNAME.AsString := WUserName;
357
  test := TADOQuery.Create(nil);
358
  try
359
    test.Connection := ADOConnection1;
360
    test.Close;
361
    test.SQL.Text := 'select * from TAGE where TAG = ''' + DateToStr(Date) + '''';
362
    test.Open;
363
    if test.RecordCount = 0 then
364
    begin
365
      ADOTable1TAG.AsDateTime := Date;
366
      ADOTable1KOMMEN.AsString := TimeToStr(Time);
367
      ADOTable1FREIER_TAG.AsBoolean := (DayOfWeek(Date) = 1{Sunday}) or
368
                                       (DayOfWeek(Date) = 7{Saturday});
369
    end;
370
  finally
371
    test.Free;
372
  end;
373
 
374
  wwDBGrid1.SelectedField := ADOTable1TAG;
375
end;
376
 
377
procedure TForm1.ADOTable1PAUSE_ENDEGetText(Sender: TField; var Text: string;
378
  DisplayText: Boolean);
379
begin
380
  Text := Copy(Sender.AsString, 1, 5);
381
end;
382
 
383
procedure TForm1.ADOTable1PAUSE_ENDESetText(Sender: TField; const Text: string);
384
begin
385
  if Text = '' then
386
  begin
387
    ADOTable1PAUSE_ENDE.Clear;
388
  end
389
  else
390
  begin
391
    ADOTable1PAUSE_ENDE.AsString := Text;
392
  end;
393
end;
394
 
395
procedure TForm1.ADOTable1PAUSE_STARTGetText(Sender: TField; var Text: string;
396
  DisplayText: Boolean);
397
begin
398
  Text := Copy(Sender.AsString, 1, 5);
399
end;
400
 
401
procedure TForm1.ADOTable1PAUSE_STARTSetText(Sender: TField;
402
  const Text: string);
403
begin
404
  if Text = '' then
405
  begin
406
    ADOTable1PAUSE_START.Clear;
407
  end
408
  else
409
  begin
410
    ADOTable1PAUSE_START.AsString := Text;
411
  end;
412
end;
413
 
414
procedure TForm1.ADOTable1SONSTIGER_ABZUGGetText(Sender: TField;
415
  var Text: string; DisplayText: Boolean);
416
begin
417
  Text := Copy(Sender.AsString, 1, 5);
418
end;
419
 
420
procedure TForm1.ADOTable1SONSTIGER_ABZUGSetText(Sender: TField;
421
  const Text: string);
422
begin
423
  if Text = '' then
424
  begin
425
    ADOTable1SONSTIGER_ABZUG.Clear;
426
  end
427
  else
428
  begin
429
    ADOTable1SONSTIGER_ABZUG.AsString := Text;
430
  end;
431
end;
432
 
433
procedure TForm1.ADOTable1TAGChange(Sender: TField);
434
begin
435
  ADOTable1FREIER_TAG.AsBoolean := (DayOfWeek(ADOTable1TAG.AsDateTime) = 1{Sunday}) or
436
                                   (DayOfWeek(ADOTable1TAG.AsDateTime) = 7{Saturday});
437
  // TODO: "Wochentag" Feld aktualisieren
438
end;
439
 
440
procedure TForm1.ADOTable1TAGGetText(Sender: TField; var Text: string;
441
  DisplayText: Boolean);
442
begin
443
  Text := DateToStr(EchtesDatum(Sender));
444
end;
445
 
446
procedure TForm1.ADOTable1TAGSetText(Sender: TField; const Text: string);
447
var
448
  i, punktCount: integer;
449
begin
450
  punktCount := 0;
451
  for i := 1 to Length(Text) do
452
  begin
453
    if Text[i] = '.' then inc(punktCount);
454
  end;
455
 
456
  if punktCount = 1 then
457
  begin
458
    ADOTable1TAG.AsString := Text + '.' + IntToStr(CurrentYear);
459
  end
460
  else if (PunktCount = 2) and EndsStr('.',Text) then
461
  begin
462
    ADOTable1TAG.AsString := Text + IntToStr(CurrentYear);
463
  end
464
  else
465
  begin
466
    ADOTable1TAG.AsString := Text;
467
  end;
468
end;
469
 
470
procedure TForm1.ADOTable1WOCHENTAGGetText(Sender: TField; var Text: string;
471
  DisplayText: Boolean);
472
begin
473
  try
474
    if ADOTable1TAG.AsString <> '' then
475
      Text := ShortDayNames[DayOfWeek(EchtesDatum(ADOTable1TAG))]
476
    else
477
      Text := '';
478
  except
479
    Text := '??';
480
  end;
481
end;
482
 
483
procedure TForm1.ADOTable1ZUHAUSEGetText(Sender: TField; var Text: string;
484
  DisplayText: Boolean);
485
begin
486
  Text := Copy(Sender.AsString, 1, 5);
487
end;
488
 
489
procedure TForm1.ADOTable1ZUHAUSESetText(Sender: TField; const Text: string);
490
begin
491
  if Text = '' then
492
  begin
493
    ADOTable1ZUHAUSE.Clear;
494
  end
495
  else
496
  begin
497
    ADOTable1ZUHAUSE.AsString := Text;
498
  end;
499
end;
500
 
501
procedure TForm1.Button1Click(Sender: TObject);
502
begin
503
  ReorgAll;
504
end;
505
 
506
procedure TForm1.ComboBox1Change(Sender: TObject);
507
begin
508
  ADOTable1.Active := false;
509
  ADOTable1.ReadOnly := ComboBox1.Text <> WUserName;
510
  ADOTable1.Filter := 'USERNAME = ''' + SQL_Escape(ComboBox1.Text) + '''';
511
  ADOTable1.Filtered := true;
512
  ADOTable1.Active := true;
513
  ADOTable1.Last;
514
 
515
  Button1.Enabled := not ADOTable1.ReadOnly;
516
 
517
  Label2.Caption := IntToStr(RegelArbeitszeit);
518
 
519
  ReorgAll;
520
end;
521
 
522
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
523
begin
524
  if ADOTable1.State in [dsEdit, dsInsert] then
525
  begin
526
    try
527
      ADOTable1.Post;
528
    except
529
      on E: EAbort do
530
      begin
531
        exit;
532
      end;
533
    end;
534
  end;
535
end;
536
 
537
procedure TForm1.FormShow(Sender: TObject);
538
var
539
  test: TADOQuery;
540
  ini: TMemIniFile;
541
resourcestring
542
  DefaultConnectionString = 'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Zeiterfassung;' +
543
                            'Data Source=SHS\FiVe,49007;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=MARSCHALL;Use Encryption for Data=False;Tag with column collation when possible=False;';
544
begin
545
  ini := TMemIniFile.Create(IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + ChangeFileExt(ExtractFileName(ParamStr(0)), '.ini'));
546
  try
547
    ADOConnection1.ConnectionString := ini.ReadString('Connection', 'ConnectionString', DefaultConnectionString);
548
  finally
549
    ini.Free;
550
  end;
551
  ADOConnection1.Connected := true;
552
 
553
  {$REGION 'Username Combobox füllen'}
554
  test := TADOQuery.Create(nil);
555
  try
556
    test.Connection := ADOConnection1;
557
    test.Close;
558
    test.SQL.Text := 'select distinct USERNAME from TAGE';
559
    test.Open;
560
    ComboBox1.Items.Clear;
561
    while not test.EOF do
562
    begin
563
      ComboBox1.Items.Add(test.FieldByName('USERNAME').AsString);
564
      test.Next;
565
    end;
566
  finally
567
    test.Free;
568
  end;
569
 
570
  if ComboBox1.Items.IndexOf(WUserName) = -1 then
571
    ComboBox1.Items.Add(WUserName);
572
 
573
  ComboBox1.Sorted := true;
574
 
575
  ComboBox1.ItemIndex := ComboBox1.Items.IndexOf(WUserName);
576
 
577
  ComboBox1Change(ComboBox1);
578
  {$ENDREGION}
579
 
580
  if wwDBGrid1.CanFocus then wwDBGrid1.SetFocus;
581
  wwDBGrid1.SelectedField := ADOTable1TAG;
582
end;
583
 
584
procedure TForm1.wwDBGrid1CalcCellColors(Sender: TObject; Field: TField;
585
  State: TGridDrawState; Highlight: Boolean; AFont: TFont; ABrush: TBrush);
586
begin
587
  if Highlight then exit;
588
 
589
  if (Field.FieldName = ADOTable1BERSTUNDEN.FieldName) or
590
     (Field.FieldName = ADOTable1BERSTUNDEN_SALDO.FieldName) then
591
  begin
592
    ABrush.Color := clBtnFace;
593
  end;
594
 
595
  if (Field.FieldName = ADOTable1BERSTUNDEN.FieldName) then
596
  begin
597
    if ADOTable1BERSTUNDEN.AsInteger < 0 then
598
    begin
599
      AFont.Color := clRed;
600
    end;
601
  end;
602
 
603
  if (Field.FieldName = ADOTable1BERSTUNDEN_SALDO.FieldName) then
604
  begin
605
    if ADOTable1BERSTUNDEN_SALDO.AsInteger < 0 then
606
    begin
607
      AFont.Color := clRed;
608
    end;
609
  end;
610
end;
611
 
612
end.