Skip to content

Commit 72e4b6e

Browse files
committed
Initial commit
1 parent b4bd7bc commit 72e4b6e

File tree

10 files changed

+543
-1
lines changed

10 files changed

+543
-1
lines changed

.github/workflows/gitleaks.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Secret Value found!!
2+
on:
3+
push:
4+
public:
5+
jobs:
6+
scan:
7+
name: gitleaks
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout
11+
uses: actions/checkout@v4.2.2
12+
- name: Install the gitleaks
13+
run: wget https://github.com/zricethezav/gitleaks/releases/download/v8.15.2/gitleaks_8.15.2_linux_x64.tar.gz
14+
shell: pwsh
15+
- name: Extract the tar file
16+
run: tar xzvf gitleaks_8.15.2_linux_x64.tar.gz
17+
- name: Generate the report
18+
id: gitleaks
19+
run: $GITHUB_WORKSPACE/gitleaks detect -s $GITHUB_WORKSPACE -f json -r $GITHUB_WORKSPACE/leaksreport.json
20+
shell: bash
21+
continue-on-error: true
22+
- name: Setup NuGet.exe
23+
if: steps.gitleaks.outcome != 'success'
24+
uses: nuget/setup-nuget@v2
25+
with:
26+
nuget-version: latest
27+
- name: Install Mono
28+
if: steps.gitleaks.outcome != 'success'
29+
run: |
30+
sudo apt update
31+
sudo apt install -y mono-complete
32+
- name: Install the dotnet SDK to a custom directory
33+
if: steps.gitleaks.outcome != 'success'
34+
run: |
35+
mkdir -p $GITHUB_WORKSPACE/dotnet
36+
curl -sSL https://dot.net/v1/dotnet-install.sh | bash /dev/stdin --install-dir $GITHUB_WORKSPACE/dotnet --channel 6.0
37+
- name: Install the report tool packages
38+
if: steps.gitleaks.outcome != 'success'
39+
run: |
40+
export PATH=$GITHUB_WORKSPACE/dotnet:$PATH
41+
nuget install "Syncfusion.Email" -source ${{ secrets.NexusFeedLink }} -ExcludeVersion
42+
dir $GITHUB_WORKSPACE/Syncfusion.Email/lib/net6.0
43+
dotnet $GITHUB_WORKSPACE/Syncfusion.Email/lib/net6.0/GitleaksReportMail.dll ${{ secrets.CITEAMCREDENTIALS }} "$GITHUB_REF_NAME" ${{ secrets.NETWORKCREDENTIALS }} ${{ secrets.NETWORKKEY }} "$GITHUB_WORKSPACE" ${{ secrets.ORGANIZATIONNAME }}
44+
exit 1

CompanyInvoice.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
namespace InvoiceHTMLtoPDF
2+
{
3+
/// <summary>
4+
/// Represents the invoice details for a company including seller, customer, and purchased items.
5+
/// </summary>
6+
public class CompanyInvoice
7+
{
8+
// Seller Information
9+
10+
/// <summary>
11+
/// Gets or sets the seller's address.
12+
/// </summary>
13+
public string SellerAddress { get; set; }
14+
15+
/// <summary>
16+
/// Gets or sets the seller's phone number.
17+
/// </summary>
18+
public string SellerPhoneNumber { get; set; }
19+
20+
/// <summary>
21+
/// Gets or sets the seller's email address.
22+
/// </summary>
23+
public string SellerEmail { get; set; }
24+
25+
/// <summary>
26+
/// Gets or sets the seller's sales tax number.
27+
/// </summary>
28+
public string SalesTaxNumber { get; set; }
29+
30+
/// <summary>
31+
/// Gets or sets the base64-encoded company logo image.
32+
/// </summary>
33+
public string CompanyLogo { get; set; }
34+
35+
// Invoice Details
36+
37+
/// <summary>
38+
/// Gets or sets the title of the invoice (e.g., Tax Invoice).
39+
/// </summary>
40+
public string InvoiceTitle { get; set; }
41+
42+
/// <summary>
43+
/// Gets or sets the invoice date.
44+
/// </summary>
45+
public string InvoiceDate { get; set; }
46+
47+
/// <summary>
48+
/// Gets or sets the due date.
49+
/// </summary>
50+
public string DueDate { get; set; }
51+
52+
/// <summary>
53+
/// Gets or sets the invoice number.
54+
/// </summary>
55+
public string InvoiceNumber { get; set; }
56+
57+
// Customer Information
58+
59+
/// <summary>
60+
/// Gets or sets the customer's name.
61+
/// </summary>
62+
public string CustomerName { get; set; }
63+
64+
/// <summary>
65+
/// Gets or sets the customer's email address.
66+
/// </summary>
67+
public string CustomerEmail { get; set; }
68+
69+
/// <summary>
70+
/// Gets or sets the customer's address.
71+
/// </summary>
72+
public string CustomerAddress { get; set; }
73+
74+
/// <summary>
75+
/// Gets or sets the customer's phone number.
76+
/// </summary>
77+
public string CustomerPhone { get; set; }
78+
79+
/// <summary>
80+
/// Gets or sets the list of items purchased.
81+
/// </summary>
82+
public List<Item> PurchaseItems { get; set; }
83+
84+
// Footer Content
85+
86+
/// <summary>
87+
/// Gets or sets the terms and conditions displayed in the invoice footer.
88+
/// </summary>
89+
public string TermsAndConditions { get; set; }
90+
}
91+
}

InvoiceHTMLtoPDF.csproj

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Syncfusion.HtmlToPdfConverter.Net.Windows" Version="30.1.42" />
12+
</ItemGroup>
13+
14+
<ItemGroup>
15+
<None Update="company-logo.jpg">
16+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
17+
</None>
18+
<None Update="customer_data.json">
19+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
20+
</None>
21+
<None Update="invoice_template.html">
22+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
23+
</None>
24+
</ItemGroup>
25+
26+
</Project>

InvoiceHTMLtoPDF.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.9.34723.18
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InvoiceHTMLtoPDF", "InvoiceHTMLtoPDF.csproj", "{8A497967-51CA-4F28-A762-9DFC2C9A6C11}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{8A497967-51CA-4F28-A762-9DFC2C9A6C11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{8A497967-51CA-4F28-A762-9DFC2C9A6C11}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{8A497967-51CA-4F28-A762-9DFC2C9A6C11}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{8A497967-51CA-4F28-A762-9DFC2C9A6C11}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {1BA0D5EF-CF45-4B65-97EA-6BC751764FE8}
24+
EndGlobalSection
25+
EndGlobal

Item.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace InvoiceHTMLtoPDF
2+
{
3+
4+
/// <summary>
5+
/// Represents an individual item purchased in the invoice.
6+
/// </summary>
7+
public class Item
8+
{
9+
/// <summary>
10+
/// Gets or sets the name or description of the item.
11+
/// </summary>
12+
public string ItemName { get; set; }
13+
14+
/// <summary>
15+
/// Gets or sets the number of licenses purchased for the item.
16+
/// </summary>
17+
public int NoOfLicensePurchased { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets the price per license for the item.
21+
/// </summary>
22+
public decimal UnitPrice { get; set; }
23+
}
24+
}

Program.cs

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using InvoiceHTMLtoPDF;
2+
using Syncfusion.Drawing;
3+
using Syncfusion.HtmlConverter;
4+
using Syncfusion.Pdf;
5+
using Syncfusion.Pdf.Graphics;
6+
using System.Text;
7+
using System.Text.Json;
8+
9+
// Load customer data from JSON file
10+
string customerDataJsonPath = "customer_data.json";
11+
string customerDataJsonContent = File.ReadAllText(customerDataJsonPath);
12+
List<CompanyInvoice> companies = JsonSerializer.Deserialize<List<CompanyInvoice>>(customerDataJsonContent);
13+
14+
// Load HTML invoice template
15+
string templatePath = "invoice_template.html";
16+
string htmlTemplate = File.ReadAllText(templatePath);
17+
18+
// Initialize HTML to PDF converter with Blink rendering engine
19+
HtmlToPdfConverter htmlConverter = new HtmlToPdfConverter();
20+
BlinkConverterSettings settings = new BlinkConverterSettings
21+
{
22+
Scale = 1.0f
23+
};
24+
htmlConverter.ConverterSettings = settings;
25+
26+
foreach (var company in companies)
27+
{
28+
string filledHtmlTemplate = htmlTemplate;
29+
StringBuilder itemRows = new StringBuilder();
30+
decimal subtotal = 0;
31+
32+
foreach (var item in company.PurchaseItems)
33+
{
34+
decimal itemTotal = item.NoOfLicensePurchased * item.UnitPrice;
35+
subtotal += itemTotal;
36+
37+
itemRows.AppendLine($@"
38+
<tr>
39+
<td>{item.ItemName}</td>
40+
<td>{item.NoOfLicensePurchased}</td>
41+
<td class='unit-price' data-price='{item.UnitPrice}'>{item.UnitPrice:C2}</td>
42+
<td class='row-total'>{itemTotal:C2}</td>
43+
</tr>");
44+
}
45+
46+
// Calculate Tax and Total
47+
decimal taxRate = 0.085m;
48+
decimal salesTax = subtotal * taxRate;
49+
decimal total = subtotal + salesTax;
50+
51+
// Replace placeholders in HTML template with actual values
52+
filledHtmlTemplate = htmlTemplate
53+
.Replace("{{PurchasedItems}}", itemRows.ToString())
54+
.Replace("{{Subtotal}}", subtotal.ToString("F2"))
55+
.Replace("{{SalesTax}}", salesTax.ToString("F2"))
56+
.Replace("{{TotalAmountDue}}", total.ToString("F2"));
57+
58+
// Convert filled HTML to PDF document
59+
PdfDocument document = htmlConverter.Convert(filledHtmlTemplate, "");
60+
61+
#region Header
62+
// ----------------------------
63+
// HEADER SECTION
64+
// ----------------------------
65+
66+
// Create header section in PDF Document
67+
PdfPageTemplateElement header = new PdfPageTemplateElement(document.Pages[0].GetClientSize().Width, 120);
68+
PdfGraphics gHeader = header.Graphics;
69+
70+
PdfFont headerFont = new PdfStandardFont(PdfFontFamily.Helvetica, 10, PdfFontStyle.Bold);
71+
PdfFont subFont = new PdfStandardFont(PdfFontFamily.Helvetica, 9);
72+
73+
float currentYLeft = 0;
74+
float currentYRight = 0;
75+
76+
string imagePath = "company-logo.jpg";
77+
byte[] imageBytes = File.ReadAllBytes(imagePath);
78+
string base64String = Convert.ToBase64String(imageBytes);
79+
company.CompanyLogo = "data:image/jpeg;base64," + base64String;
80+
81+
using (MemoryStream ms = new MemoryStream(imageBytes))
82+
{
83+
PdfBitmap logo = new PdfBitmap(ms);
84+
gHeader.DrawImage(logo, new RectangleF(35, currentYLeft, 100, 30));
85+
currentYLeft += 45;
86+
currentYRight += 45;
87+
}
88+
89+
// Add customer billing information to the left
90+
gHeader.DrawString("Bill To:", headerFont, PdfBrushes.Black, new PointF(35, currentYLeft += 15));
91+
gHeader.DrawString(company.CustomerName, headerFont, PdfBrushes.Black, new PointF(35, currentYLeft += 15));
92+
gHeader.DrawString(company.CustomerAddress, subFont, PdfBrushes.Black, new PointF(35, currentYLeft += 15));
93+
gHeader.DrawString($"Phone: {company.CustomerPhone} | Email: {company.CustomerEmail}", subFont, PdfBrushes.Black, new PointF(35, currentYLeft += 15));
94+
95+
// Add invoice details on the right
96+
float rightX = 400;
97+
PdfFont largeHeaderFont = new PdfStandardFont(PdfFontFamily.Helvetica, 18, PdfFontStyle.Bold);
98+
gHeader.DrawString("Invoice", largeHeaderFont, PdfBrushes.Black, new PointF(rightX, 5));
99+
gHeader.DrawString($"{company.InvoiceTitle} - #{company.InvoiceNumber}", headerFont, PdfBrushes.Black, new PointF(rightX, currentYRight += 15));
100+
gHeader.DrawString($"Date: {company.InvoiceDate:dd MMM yyyy}", subFont, PdfBrushes.Black, new PointF(rightX, currentYRight += 15));
101+
gHeader.DrawString($"Due Date: {company.DueDate:dd MMM yyyy}", subFont, PdfBrushes.Black, new PointF(rightX, currentYRight += 15));
102+
gHeader.DrawString($"Sales Tax No: {company.SalesTaxNumber}", subFont, PdfBrushes.Black, new PointF(rightX, currentYRight += 15));
103+
104+
document.Template.Top = header;
105+
106+
#endregion
107+
108+
#region Footer
109+
// ----------------------------
110+
// Footer SECTION
111+
// ----------------------------
112+
113+
// Create Footer section in PDF Document
114+
PdfPageTemplateElement footer = new PdfPageTemplateElement(document.Pages[0].GetClientSize().Width, 70);
115+
PdfGraphics gFooter = footer.Graphics;
116+
117+
PdfFont footerFont = new PdfStandardFont(PdfFontFamily.Helvetica, 9);
118+
PdfFont footerFontBold = new PdfStandardFont(PdfFontFamily.Helvetica, 10, PdfFontStyle.Bold);
119+
120+
// Add thanks message
121+
string thankYouText = "Thank you for your business!";
122+
SizeF textSize = footerFont.MeasureString(thankYouText);
123+
float centerX = (document.Pages[0].GetClientSize().Width - textSize.Width) / 2;
124+
gFooter.DrawString(thankYouText, footerFont, PdfBrushes.Black, new PointF(centerX, 0));
125+
126+
// Add terms and conditions
127+
string termsLabel = "Terms and Conditions: ";
128+
SizeF termsLabelSize = footerFontBold.MeasureString(termsLabel);
129+
gFooter.DrawString(termsLabel, footerFontBold, PdfBrushes.Black, new PointF(0, 20));
130+
gFooter.DrawString(company.TermsAndConditions, footerFont, PdfBrushes.Black, new PointF(termsLabelSize.Width, 20));
131+
132+
// Add separator line
133+
gFooter.DrawLine(new PdfPen(PdfBrushes.Black, 0.5f), new PointF(0, 40), new PointF(600, 40));
134+
135+
// Add seller address and contact info
136+
gFooter.DrawString("Address:", footerFontBold, PdfBrushes.Black, new PointF(0, 45));
137+
gFooter.DrawString(company.SellerAddress, footerFont, PdfBrushes.Black, new PointF(0, 60));
138+
139+
string emailLabel = "Email: ";
140+
SizeF emailLabelSize = footerFontBold.MeasureString(emailLabel);
141+
gFooter.DrawString(emailLabel, footerFontBold, PdfBrushes.Black, new PointF(450, 45));
142+
gFooter.DrawString(company.SellerEmail, footerFont, PdfBrushes.Black, new PointF(450 + emailLabelSize.Width, 45));
143+
144+
string phoneLabel = "Phone: ";
145+
SizeF phoneLabelSize = footerFontBold.MeasureString(phoneLabel);
146+
gFooter.DrawString(phoneLabel, footerFontBold, PdfBrushes.Black, new PointF(450, 60));
147+
gFooter.DrawString(company.SellerPhoneNumber, footerFont, PdfBrushes.Black, new PointF(450 + phoneLabelSize.Width, 60));
148+
149+
document.Template.Bottom = footer;
150+
151+
#endregion
152+
153+
// Save PDF
154+
Directory.CreateDirectory("../../../Output");
155+
string outputPath = $"../../../Output/Invoice_{company.CustomerName}.pdf";
156+
using MemoryStream stream = new MemoryStream();
157+
document.Save(stream);
158+
File.WriteAllBytes(outputPath, stream.ToArray());
159+
160+
// Close the document to release resources
161+
document.Close(true);
162+
}
163+
Console.WriteLine("Documents saved successfully!");

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
# Automate-Sales-Invoices-with-Dynamic-HTML-to-PDF-and-Custom-Headers-Footers
1+
# Automating Sales Invoice Generation Using Dynamic HTML to PDF Conversion with Custom Headers and Footers
22
This repository provides a working example of how to automate sales invoice generation by converting dynamic HTML templates into PDF documents with custom headers and footers. Built using .NET (C#), this solution is ideal for developers looking to streamline invoice workflows and integrate PDF generation into business applications.

company-logo.jpg

20.9 KB
Loading

0 commit comments

Comments
 (0)