{*******************************************************} { } { Responsive Software http://www.responsive.co.nz } { } { Copyright (c) 2003-2006 Responsive Software Limited } { } {*******************************************************} unit AccountStatementReportFormat; interface uses DatabaseObjects, GeneralUtilities; procedure FormatAccountStatementReportDetails (AccountId : int64; UseBeginPeriod : boolean; BeginPeriodDate : TDateTime; UseEndPeriod : boolean; EndPeriodDate : TDateTime; Summary : boolean; ReportData : TReportData); implementation uses Classes, SysUtils, DatabaseManager, Globals, Progress, BusinessObjects, AccountsCacheUnit; type TLineType = (ltHeading,ltDetail,ltOpeningBalance,ltClosingBalance,ltPeriodBalance,ltSummaryDetail); function CompareSummaryEntries (Item1, Item2 : pointer) : integer; var Entry1, Entry2 : TEntry; begin Entry1 := TEntry(Item1); Entry2 := TEntry(Item2); if (Entry1 = nil) and (Entry2 = nil) then Result := 0 else if (Entry1 = nil) and (Entry2 <> nil) then Result := -1 else if (Entry1 <> nil) and (Entry2 = nil) then Result := 1 else begin // compare on other account name Result := CompareText(Entry1.OtherAccountName,Entry2.OtherAccountName); // if same then put debits first if Result = 0 then begin if Entry1.Debit and Entry2.Credit then Result := -1 else if Entry1.Credit and Entry2.Debit then Result := 1 else Result := 0; end; end; end; procedure FormatAccountStatementReportDetails (AccountId : int64; UseBeginPeriod : boolean; BeginPeriodDate : TDateTime; UseEndPeriod : boolean; EndPeriodDate : TDateTime; Summary : boolean; ReportData : TReportData); var i : integer; Account : TAccount; Entry : TEntry; SummaryEntries : TDatabaseObjectCollection; procedure PrintLine (LineType : TLineType; Entry : TEntry); var Str : string; Balance : int64; begin // first determine balance if it is a balance line if LineType = ltOpeningBalance then begin if not UseBeginPeriod then Balance := 0 else Balance := Account.BalanceAsAt(BeginPeriodDate-1); end else if LineType = ltClosingBalance then begin if not UseEndPeriod then Balance := Account.TotalBalance else Balance := Account.BalanceAsAt(EndPeriodDate); end else if LineType = ltPeriodBalance then Balance := Account.Balance(UseBeginPeriod,BeginPeriodDate,UseEndPeriod,EndPeriodDate) else Balance := 0; // now assemble details of line to output Str := ''; // print date if LineType = ltHeading then begin if Summary then Str := Str + ' ' else Str := Str + 'Date '; end else if LineType = ltDetail then Str := Str + Format('%-8.8s ',[ShortFormatDate(Entry.Date)]) else if LineType = ltOpeningBalance then begin if UseBeginPeriod then Str := Str + Format('%-8.8s ',[ShortFormatDate(BeginPeriodDate)]) else Str := Str + ' '; end else if LineType = ltClosingBalance then begin if UseEndPeriod then Str := Str + Format('%-8.8s ',[ShortFormatDate(EndPeriodDate)]) else Str := Str + ' '; end else if LineType = ltPeriodBalance then Str := Str + ' ' else if LineType = ltSummaryDetail then Str := Str + ' '; // print description if LineType = ltHeading then Str := Str + 'Description ' else if LineType = ltDetail then begin if Entry.Description <> '' then Str := Str + Format('%-38.38s ',[Entry.Description]) // if no description then show other account name else Str := Str + Format('%-38.38s ',[Entry.OtherAccountName]); end else if LineType = ltOpeningBalance then Str := Str + Format('%-38.38s ',['Opening Balance']) else if LineType = ltClosingBalance then Str := Str + Format('%-38.38s ',['Closing Balance']) else if LineType = ltPeriodBalance then Str := Str + Format('%-38.38s ',['Total for period']) else if LineType = ltSummaryDetail then Str := Str + Format('%-38.38s ',[Entry.OtherAccountName]); // print debit if LineType = ltHeading then Str := Str + ' Debit ' else if LineType = ltDetail then begin if Entry.Debit then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Entry.AbsoluteAmount)]) else Str := Str + ' '; end else if LineType in [ltOpeningBalance,ltClosingBalance,ltPeriodBalance] then begin if (Account.Debit and (Balance > 0)) or (Account.Credit and (Balance < 0)) then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Abs(Balance))]) else if Balance <> 0 then Str := Str + ' ' else begin if Account.Debit then Str := Str + ' 0.00 ' else Str := Str + ' '; end; end else if LineType = ltSummaryDetail then begin if Entry.Debit then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Entry.AbsoluteAmount)]) else Str := Str + ' '; end; // print credit if LineType = ltHeading then Str := Str + ' Credit ' else if LineType = ltDetail then begin if Entry.Credit then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Entry.AbsoluteAmount)]) else Str := Str + ' '; end else if LineType in [ltOpeningBalance,ltClosingBalance,ltPeriodBalance] then begin if (Account.Debit and (Balance > 0)) or (Account.Credit and (Balance < 0)) then Str := Str + ' ' else if Balance <> 0 then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Abs(Balance))]) else begin if Account.Credit then Str := Str + ' 0.00 ' else Str := Str + ' '; end; end else if LineType = ltSummaryDetail then begin if Entry.Credit then Str := Str + Format('%14s ',[FormatCurrencyForDisplay(Entry.AbsoluteAmount)]) else Str := Str + ' '; end; // print other account if LineType = ltHeading then begin if Summary then Str := Str + ' ' else Str := Str + ' Other '; end else if LineType = ltDetail then Str := Str + Format(' %5.5s ',[Entry.OtherAccountAbbreviation]) else Str := Str + ' '; // output completed line if LineType = ltHeading then ReportData.WriteBoldLine(Str) else if LineType = ltDetail then ReportData.WriteLine(Str) else if LineType = ltOpeningBalance then ReportData.WriteBoldLine(Str) else if LineType = ltClosingBalance then ReportData.WriteBoldLine(Str) else if LineType = ltPeriodBalance then ReportData.WriteBoldLine(Str) else if LineType = ltSummaryDetail then ReportData.WriteLine(Str); end; procedure ProcessEntry (Entry : TEntry); var i : integer; SummaryEntry : TEntry; begin SummaryEntry := nil; for i := 0 to SummaryEntries.Count - 1 do begin SummaryEntry := TEntry(SummaryEntries[i]); if (SummaryEntry.OtherAccountId = Entry.OtherAccountId) and (SummaryEntry.Debit = Entry.Debit) then Break else SummaryEntry := nil; end; // create a summary entry and add to list if not found if SummaryEntry = nil then begin SummaryEntry := TEntry.Create; SummaryEntries.Add(SummaryEntry); SummaryEntry.AccountId := AccountId; SummaryEntry.OtherAccountId := Entry.OtherAccountId; end; // accumulate amounts SummaryEntry.Amount := SummaryEntry.Amount + Entry.Amount; end; begin Account := AccountsCache.GetAccount(AccountId); if Account = nil then begin ReportData.WriteLine('Account not found'); Exit; end; ProgressForm.SetPosition(0); ProgressForm.SetCaption('Generating account statement. Please wait...'); ProgressForm.Show; // create collection to hold summary information if Summary then begin SummaryEntries := TDatabaseObjectCollection.Create; SummaryEntries.Owned := true; end else SummaryEntries := nil; try // display headings PrintLine(ltHeading,nil); // if it is a balance sheet type account then show opening balance if Account.BalanceSheet then PrintLine(ltOpeningBalance,nil); // show or process transactions in period for i := 0 to Account.Entries.Count - 1 do begin Entry := TEntry(Account.Entries[i]); if UseBeginPeriod and (Entry.Date < BeginPeriodDate) then Continue; if UseEndPeriod and (Entry.Date > EndPeriodDate) then Break; if Summary then ProcessEntry(Entry) else PrintLine(ltDetail,Entry); ProgressForm.SetPosition(i * 100 div Account.Entries.Count); end; // if summary then show summary information if Summary then begin SummaryEntries.Sort(CompareSummaryEntries); for i := 0 to SummaryEntries.Count - 1 do begin Entry := TEntry(SummaryEntries[i]); PrintLine(ltSummaryDetail,Entry); end; end; // show closing balance if balance sheet type account if Account.BalanceSheet then PrintLine(ltClosingBalance,nil) // otherwise show balance for period else PrintLine(ltPeriodBalance,nil); finally SummaryEntries.Free; ProgressForm.Hide; end; end; end.