Skip to content

Instantly share code, notes, and snippets.

@Al-Muhandis
Created October 23, 2025 21:38
Show Gist options
  • Select an option

  • Save Al-Muhandis/4ccea5793ef0e3b2ed4ac6df2d32abbc to your computer and use it in GitHub Desktop.

Select an option

Save Al-Muhandis/4ccea5793ef0e3b2ed4ac6df2d32abbc to your computer and use it in GitHub Desktop.
Пример генерации счета в FreePascal с помощью fcl-pdf
unit invoice_pdf;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, fppdf, cmn_globals
;
type
{ TInvoicePDFGenerator }
TInvoicePDFGenerator = class
private
FCurrency: String;
FFontFilePath: String;
FFontName: String;
FPayeeBankBIC: Int64;
FPayeeBankName: String;
FPayeeINN: Int64;
FPayeeKPP: Int64;
FPayerEmail: String;
FPayerINN: String;
FPayerKPP: String;
FPayerName: String;
FPayerPhone: String;
FPayerTypeEnum: TPayerType;
FPrice: Integer;
FAcc, FCorrAcc: String;
FDocNum: Integer;
FPayeeName: String;
FPaymentName: String;
FPage: TPDFPage;
FXBlockIndent, FXBlockIndent2: Integer;
FY: Integer;
procedure DrawLine(X, Y, L: Integer);
function GetPayerType: String;
procedure SetPayerType(AValue: String);
procedure WriteText(X, Y: Integer; const S: string; aFont, aSize: Integer);
procedure WriteBigText(X, Y: Integer; const S: string; aFont: Integer);
procedure WriteSmallText(X, Y: Integer; const S: string; aFont: Integer);
procedure WriteInfoBlockWithLine(const aInfoValue, aInfoName: String; aFont: Integer);
procedure WriteInfoBlockWithLine(const aInfoValue1, aInfoName1, aInfoValue2, aInfoName2: String; aFont: Integer);
public
function Generate: TMemoryStream;
property DocNum: Integer read FDocNum write FDocNum;
property PayeeName: String read FPayeeName write FPayeeName;
property PayeeINN: Int64 read FPayeeINN write FPayeeINN;
property PayeeKPP: Int64 read FPayeeKPP write FPayeeKPP;
property PayeeBankName: String read FPayeeBankName write FPayeeBankName;
property PayeeBankBIC: Int64 read FPayeeBankBIC write FPayeeBankBIC;
property PaymentName: String read FPaymentName write FPaymentName;
property PayerType: String read GetPayerType write SetPayerType;
property PayerTypeEnum: TPayerType read FPayerTypeEnum write FPayerTypeEnum;
property PayerName: String read FPayerName write FPayerName;
property PayerEmail: String read FPayerEmail write FPayerEmail;
property PayerPhone: String read FPayerPhone write FPayerPhone;
property PayerINN: String read FPayerINN write FPayerINN;
property PayerKPP: String read FPayerKPP write FPayerKPP;
property PayeeBankCorrAcc: String read FCorrAcc write FCorrAcc;
property PayeeBankAcc: String read FAcc write FAcc;
property Price: Integer read FPrice write FPrice;
property Currency: String read FCurrency write FCurrency;
property FontFilePath: String read FFontFilePath write FFontFilePath;
property FontName: String read FFontName write FFontName;
end;
function InvoiceFullID(const aText: String; aDocNum: Integer; aDate: TDate): String;
implementation
function InvoiceFullID(const aText: String; aDocNum: Integer; aDate: TDate): String;
begin
Result:=Format(aText, [aDocNum, FormatDateTime('dd.mm.yyyy', aDate)]);
end;
{ TInvoicePDFGenerator }
procedure TInvoicePDFGenerator.DrawLine(X, Y, L: Integer);
begin
FPage.MoveTo(X, Y);
FPage.DrawLine(X,Y, x+L, Y, 0.5, False);
FPage.StrokePath;
end;
function TInvoicePDFGenerator.GetPayerType: String;
begin
Result:=PayerTypeToString(FPayerTypeEnum);
end;
procedure TInvoicePDFGenerator.SetPayerType(AValue: String);
begin
FPayerTypeEnum:=StringToPayerType(AValue);
end;
procedure TInvoicePDFGenerator.WriteText(X, Y: Integer; const S: string; aFont, aSize: Integer);
begin
FPage.SetFont(aFont, aSize);
FPage.WriteText(X, Y, S);
end;
procedure TInvoicePDFGenerator.WriteBigText(X, Y: Integer; const S: string; aFont: Integer);
begin
WriteText(X, Y, S, aFont, 12);
end;
procedure TInvoicePDFGenerator.WriteSmallText(X, Y: Integer; const S: string; aFont: Integer);
begin
WriteText(X, Y, S, aFont, 9);
end;
procedure TInvoicePDFGenerator.WriteInfoBlockWithLine(const aInfoValue, aInfoName: String; aFont: Integer);
begin
WriteBigText(FXBlockIndent, FY, aInfoValue, aFont); FY -= 2;
DrawLine(FXBlockIndent, FY, 140); FY -= 3;
WriteSmallText(FXBlockIndent+5, FY, aInfoName, aFont); FY -= 8;
end;
procedure TInvoicePDFGenerator.WriteInfoBlockWithLine(const aInfoValue1, aInfoName1, aInfoValue2, aInfoName2: String;
aFont: Integer);
begin
WriteBigText(FXBlockIndent, FY, aInfoValue1, aFont); WriteBigText(FXBlockIndent2, FY, aInfoValue2, aFont); FY -= 2;
DrawLine(FXBlockIndent, FY, 60); DrawLine(FXBlockIndent2, FY, 60); FY -= 3;
WriteSmallText(FXBlockIndent+5, FY, aInfoName1, aFont); WriteSmallText(FXBlockIndent2+5, FY, aInfoName2, aFont); FY -= 8;
end;
function TInvoicePDFGenerator.Generate: TMemoryStream;
var
aDoc: TPDFDocument;
aFont: Integer;
aSection: TPDFSection;
InvoiceNo, aInvoiceNum: string;
begin
Result := TMemoryStream.Create;
aDoc := TPDFDocument.Create(nil);
try
aDoc.StartDocument;
aSection := aDoc.Sections.AddSection;
FPage := aDoc.Pages.AddPage;
aSection.AddPage(FPage);
if FFontFilePath.IsEmpty then
aFont := aDoc.AddFont(FFontName)
else
aFont := aDoc.AddFont(FFontFilePath, FFontName);
FY := Round(FPage.GetPaperHeight) - 10;
InvoiceNo := InvoiceFullID('Счет на оплату № %d от %s г.', DocNum, Date);
WriteBigText(40, FY, InvoiceNo, aFont); FY -= 16;
FXBlockIndent:=40;
FXBlockIndent2:=120;
WriteInfoBlockWithLine(PayeeBankName, 'Банк получателя', aFont);
WriteInfoBlockWithLine(PayeeBankBIC.ToString, 'БИК банка получателя', PayeeBankCorrAcc,
'Номер корр.счета банка получателя', aFont);
WriteInfoBlockWithLine(PayeeINN.ToString, 'ИНН получателя', PayeeKPP.ToString, 'КПП получателя', aFont);
WriteInfoBlockWithLine(PayeeBankAcc, 'Счет получателя платежа', aFont);
WriteInfoBlockWithLine(PayeeName, 'Получатель платежа', aFont);
aInvoiceNum:=Format(PaymentName, [InvoiceFullID('№ %d от %s г.', DocNum, Date)]);
WriteInfoBlockWithLine(aInvoiceNum, 'Наименование платежа', aFont);
FY -= 8;
WriteBigText(FXBlockIndent+40, FY, Format('Сумма платежа: %s', [CurrencyToStr(FPrice, FCurrency)]), aFont); FY -= 8;
WriteBigText(FXBlockIndent+40, FY, 'НДС не облагается', aFont); FY -= 8;
FY -= 8;
WriteBigText(FXBlockIndent+5, FY, 'Плательщик: ' + PayerName, aFont); FY -= 8;
if FPayerTypeEnum=pteEntity then
begin
WriteBigText(FXBlockIndent+5, FY, 'ИНН плательщика: ' + PayerINN, aFont); FY -= 8;
WriteBigText(FXBlockIndent+5, FY, 'КПП плательщика: ' + PayerKPP, aFont); FY -= 8;
end;
WriteBigText(FXBlockIndent+5, FY, 'Email: ' + PayerEmail, aFont);
WriteBigText(FXBlockIndent2+5, FY, 'Тел.: +' + PayerPhone, aFont); FY -= 12;
aDoc.SaveToStream(Result);
finally
aDoc.Free;
end;
Result.Position := 0;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment