Document Scripting: Difference between revisions
No edit summary Tag: Manual revert |
|||
| (3 intermediate revisions by the same user not shown) | |||
| Line 7: | Line 7: | ||
Every document script follows this basic structure: | Every document script follows this basic structure: | ||
public class DocumentScripter | public class DocumentScripter | ||
{ | { | ||
| Line 21: | Line 21: | ||
} | } | ||
} | } | ||
'''Important:''' Your class must be named <code>DocumentScripter</code> and have a <code>Main</code> method with these exact parameters. | '''Important:''' Your class must be named <code>DocumentScripter</code> and have a <code>Main</code> method with these exact parameters. | ||
| Line 29: | Line 29: | ||
=== Creating and Loading Documents === | === Creating and Loading Documents === | ||
// Create a new document | // Create a new document | ||
ZinWord document = new ZinWord(zinBL); | ZinWord document = new ZinWord(zinBL); | ||
| Line 41: | Line 41: | ||
// Clone an existing document (useful when processing multiple records) | // Clone an existing document (useful when processing multiple records) | ||
ZinWord clonedDoc = sourceDocument.Clone(true); | ZinWord clonedDoc = sourceDocument.Clone(true); | ||
=== Saving Documents === | === Saving Documents === | ||
// Save to file - format determined by extension | // Save to file - format determined by extension | ||
document.SaveDocument(saveFileName); | document.SaveDocument(saveFileName); | ||
| Line 52: | Line 52: | ||
document.SaveDocument("MyFile.pdf"); // Saves as PDF | document.SaveDocument("MyFile.pdf"); // Saves as PDF | ||
document.SaveDocument("MyFile.docx"); // Saves as Word document | document.SaveDocument("MyFile.docx"); // Saves as Word document | ||
=== Checking Document Content === | === Checking Document Content === | ||
// Check if document has any content (text, tables, or images) | // Check if document has any content (text, tables, or images) | ||
bool hasContent = zinBL.DocumentFunctions.DocumentHasContent(document); | bool hasContent = zinBL.DocumentFunctions.DocumentHasContent(document); | ||
=== Attaching Documents === | === Attaching Documents === | ||
// Combine multiple documents into one (useful for bulk processing) | // Combine multiple documents into one (useful for bulk processing) | ||
ZinWord bulkDocument = new ZinWord(zinBL); | ZinWord bulkDocument = new ZinWord(zinBL); | ||
| Line 69: | Line 69: | ||
bulkDocument.AttachDocument(sourceDocument2); | bulkDocument.AttachDocument(sourceDocument2); | ||
bulkDocument.SaveDocument("Bulk_Output.pdf"); | bulkDocument.SaveDocument("Bulk_Output.pdf"); | ||
== Working with Bookmarks == | == Working with Bookmarks == | ||
| Line 77: | Line 77: | ||
=== Setting Bookmark Values === | === Setting Bookmark Values === | ||
// Set text value | // Set text value | ||
document.SetBookmarkString("BookmarkName", "Value"); | document.SetBookmarkString("BookmarkName", "Value"); | ||
| Line 92: | Line 92: | ||
// Set image from Picture object | // Set image from Picture object | ||
document.SetBookmarkImage("BookmarkName", pictureItem); | document.SetBookmarkImage("BookmarkName", pictureItem); | ||
=== Deleting Bookmarks === | === Deleting Bookmarks === | ||
// Remove a bookmark and its content | // Remove a bookmark and its content | ||
document.DeleteBookmark("BookmarkName"); | document.DeleteBookmark("BookmarkName"); | ||
=== Getting All Bookmarks === | === Getting All Bookmarks === | ||
// Retrieve all bookmarks in the document | // Retrieve all bookmarks in the document | ||
var bookmarks = document.GetBookmarks(); | var bookmarks = document.GetBookmarks(); | ||
| Line 113: | Line 113: | ||
// ... do something with the bookmark | // ... do something with the bookmark | ||
} | } | ||
== Standard Bookmarks == | == Standard Bookmarks == | ||
| Line 121: | Line 121: | ||
=== ProcessStandardBookmarks === | === ProcessStandardBookmarks === | ||
zinBL.DocumentFunctions.ProcessStandardBookmarks( | zinBL.DocumentFunctions.ProcessStandardBookmarks( | ||
document, // ZinWord document to process | document, // ZinWord document to process | ||
| Line 133: | Line 133: | ||
stateAsCity // Treat state as city (NZ DB) (default: false) | stateAsCity // Treat state as city (NZ DB) (default: false) | ||
); | ); | ||
'''Supported Standard Bookmarks:''' | '''Supported Standard Bookmarks:''' | ||
| Line 159: | Line 159: | ||
For invoice-specific bookmarks (duplicated bookmarks with "2" suffix): | For invoice-specific bookmarks (duplicated bookmarks with "2" suffix): | ||
zinBL.DocumentFunctions.ProcessExtraInvoiceBookmarks( | zinBL.DocumentFunctions.ProcessExtraInvoiceBookmarks( | ||
document, otherParty, parameters, zinBL, | document, otherParty, parameters, zinBL, | ||
| Line 165: | Line 165: | ||
addresseeFirstLineAddress, stateAsCity | addresseeFirstLineAddress, stateAsCity | ||
); | ); | ||
=== ProcessInvoiceBookmarks === | === ProcessInvoiceBookmarks === | ||
| Line 171: | Line 171: | ||
Handles delivery address for invoices: | Handles delivery address for invoices: | ||
zinBL.DocumentFunctions.ProcessInvoiceBookmarks( | zinBL.DocumentFunctions.ProcessInvoiceBookmarks( | ||
document, otherParty, parameters, zinBL, transaction, | document, otherParty, parameters, zinBL, transaction, | ||
minAddressLines, stateAsCity, "DELIVERY" | minAddressLines, stateAsCity, "DELIVERY" | ||
); | ); | ||
'''Supported Bookmark:''' | '''Supported Bookmark:''' | ||
| Line 185: | Line 185: | ||
For statement-specific bookmarks (duplicated bookmarks with "2" suffix): | For statement-specific bookmarks (duplicated bookmarks with "2" suffix): | ||
zinBL.DocumentFunctions.ProcessExtraStatementBookmarks( | zinBL.DocumentFunctions.ProcessExtraStatementBookmarks( | ||
document, otherParty, parameters, zinBL, | document, otherParty, parameters, zinBL, | ||
| Line 191: | Line 191: | ||
addresseeFirstLineAddress, stateAsCity | addresseeFirstLineAddress, stateAsCity | ||
); | ); | ||
== Working with Parameters == | == Working with Parameters == | ||
| Line 199: | Line 199: | ||
=== Getting Parameter Values === | === Getting Parameter Values === | ||
// Get string value | // Get string value | ||
string documentId = parameters.GetItemString("DocumentId"); | string documentId = parameters.GetItemString("DocumentId"); | ||
| Line 212: | Line 212: | ||
string extension = parameters.GetItemString("OutputExtension"); | string extension = parameters.GetItemString("OutputExtension"); | ||
string filter = parameters.GetItemString("OutputExtensionFilter"); | string filter = parameters.GetItemString("OutputExtensionFilter"); | ||
=== Setting Return Parameters === | === Setting Return Parameters === | ||
// Return the save location to the caller | // Return the save location to the caller | ||
returnParameters.SetItemString("SaveLocation", saveLocation); | returnParameters.SetItemString("SaveLocation", saveLocation); | ||
| Line 222: | Line 222: | ||
// Return error message if something fails | // Return error message if something fails | ||
returnParameters.SetItemString("ReturnError", "No File Save Location Chosen!"); | returnParameters.SetItemString("ReturnError", "No File Save Location Chosen!"); | ||
== File Operations == | == File Operations == | ||
| Line 228: | Line 228: | ||
=== Save File Dialog === | === Save File Dialog === | ||
string saveLocation = FileFunctions.OpenSaveFileDialog( | string saveLocation = FileFunctions.OpenSaveFileDialog( | ||
document.DocumentOutputFolder, // Default folder | document.DocumentOutputFolder, // Default folder | ||
| Line 246: | Line 246: | ||
return false; | return false; | ||
} | } | ||
=== Creating Directories === | === Creating Directories === | ||
string folderPath = Path.Combine(baseFolderPath, $"OtherParty_{otherPartyId}"); | string folderPath = Path.Combine(baseFolderPath, $"OtherParty_{otherPartyId}"); | ||
| Line 259: | Line 259: | ||
string saveFileName = Path.Combine(folderPath, "Statement.pdf"); | string saveFileName = Path.Combine(folderPath, "Statement.pdf"); | ||
== Working with DataTables == | == Working with DataTables == | ||
| Line 265: | Line 265: | ||
When processing multiple records (e.g., statements for multiple customers): | When processing multiple records (e.g., statements for multiple customers): | ||
// Validate the DataTable parameter | // Validate the DataTable parameter | ||
DataTable otherPartyDataTable; | DataTable otherPartyDataTable; | ||
| Line 288: | Line 288: | ||
// Process document for this party | // Process document for this party | ||
} | } | ||
== Progress Bar == | == Progress Bar == | ||
| Line 294: | Line 294: | ||
Show progress when processing multiple records: | Show progress when processing multiple records: | ||
ProgressBarManager.Start("Processing Statements", true, totalCount, progressBar => | ProgressBarManager.Start("Processing Statements", true, totalCount, progressBar => | ||
{ | { | ||
| Line 318: | Line 318: | ||
ProgressBarManager.Finished(); | ProgressBarManager.Finished(); | ||
}); | }); | ||
== Financial Functions == | == Financial Functions == | ||
| Line 324: | Line 324: | ||
=== Statement Data === | === Statement Data === | ||
// Get statement details (aged balances) | // Get statement details (aged balances) | ||
ZinStatementDetails details = zinBL.DocumentFunctions.GetStatementDetails( | ZinStatementDetails details = zinBL.DocumentFunctions.GetStatementDetails( | ||
| Line 339: | Line 339: | ||
decimal threeMonths = details.ThreeMonthsOverdue; | decimal threeMonths = details.ThreeMonthsOverdue; | ||
decimal total = details.TotalDue; | decimal total = details.TotalDue; | ||
=== Transaction Data === | === Transaction Data === | ||
// Get monthly running transactions (preferred method) | // Get monthly running transactions (preferred method) | ||
var (transactions, statementDetails) = zinBL.DocumentFunctions.GetMonthlyRunningTransactions2( | var (transactions, statementDetails) = zinBL.DocumentFunctions.GetMonthlyRunningTransactions2( | ||
| Line 364: | Line 364: | ||
decimal subTotal = tran.SubTotal; | decimal subTotal = tran.SubTotal; | ||
} | } | ||
=== Combining Transaction Lists === | === Combining Transaction Lists === | ||
// Combine and sort multiple transaction lists by date | // Combine and sort multiple transaction lists by date | ||
var combined = zinBL.DocumentFunctions.CombineTransactions(listOne, listTwo); | var combined = zinBL.DocumentFunctions.CombineTransactions(listOne, listTwo); | ||
=== Date Utilities === | === Date Utilities === | ||
// Get last day of month | // Get last day of month | ||
DateTime monthEnd = DocumentFunctions.GetEndOfMonth(someDate); | DateTime monthEnd = DocumentFunctions.GetEndOfMonth(someDate); | ||
// Example: 15/03/2024 returns 31/03/2024 | // Example: 15/03/2024 returns 31/03/2024 | ||
== Building HTML Tables == | == Building HTML Tables == | ||
| Line 385: | Line 385: | ||
For inserting formatted tables into bookmarks: | For inserting formatted tables into bookmarks: | ||
var htmlTable = new StringBuilder(); | var htmlTable = new StringBuilder(); | ||
| Line 412: | Line 412: | ||
// Insert into document | // Insert into document | ||
document.SetBookmarkHtml("TableBookmark", htmlTable.ToString()); | document.SetBookmarkHtml("TableBookmark", htmlTable.ToString()); | ||
'''Tips for HTML Tables:''' | '''Tips for HTML Tables:''' | ||
| Line 425: | Line 425: | ||
=== Sending Documents via Email === | === Sending Documents via Email === | ||
// Get email addresses for specific contacts | // Get email addresses for specific contacts | ||
var emailAddresses = otherParty.GetEmailContactsAsEmailCompatibleStringById(document.EmailContactIds); | var emailAddresses = otherParty.GetEmailContactsAsEmailCompatibleStringById(document.EmailContactIds); | ||
| Line 454: | Line 454: | ||
} | } | ||
} | } | ||
== Best Practices == | == Best Practices == | ||
| Line 460: | Line 460: | ||
=== Error Handling === | === Error Handling === | ||
try | try | ||
{ | { | ||
| Line 479: | Line 479: | ||
return true; // Success | return true; // Success | ||
=== Memory Management === | === Memory Management === | ||
| Line 485: | Line 485: | ||
When processing many documents, clean up: | When processing many documents, clean up: | ||
foreach (DataRow row in dataTable.Rows) | foreach (DataRow row in dataTable.Rows) | ||
{ | { | ||
| Line 495: | Line 495: | ||
clonedDoc = null; | clonedDoc = null; | ||
} | } | ||
=== Conditional Processing === | === Conditional Processing === | ||
// Only add to bulk document if not emailed | // Only add to bulk document if not emailed | ||
bool wasEmailed = false; | bool wasEmailed = false; | ||
| Line 513: | Line 513: | ||
bulkDocument.AttachDocument(processedDoc); | bulkDocument.AttachDocument(processedDoc); | ||
} | } | ||
== Common Patterns == | == Common Patterns == | ||
| Line 519: | Line 519: | ||
=== Pattern: Individual vs Bulk Documents === | === Pattern: Individual vs Bulk Documents === | ||
bool individual = parameters.GetItemBoolean("IndividualDocuments"); | bool individual = parameters.GetItemBoolean("IndividualDocuments"); | ||
ZinWord bulkDoc = new ZinWord(zinBL); | ZinWord bulkDoc = new ZinWord(zinBL); | ||
| Line 545: | Line 545: | ||
bulkDoc.SaveDocument(saveLocation); | bulkDoc.SaveDocument(saveLocation); | ||
} | } | ||
=== Pattern: Processing with Progress === | === Pattern: Processing with Progress === | ||
ProgressBarManager.Start("Processing Documents", true, dataTable.Rows.Count, progressBar => | ProgressBarManager.Start("Processing Documents", true, dataTable.Rows.Count, progressBar => | ||
{ | { | ||
| Line 570: | Line 570: | ||
ProgressBarManager.Finished(); | ProgressBarManager.Finished(); | ||
}); | }); | ||
=== Pattern: Empty Row Padding === | === Pattern: Empty Row Padding === | ||
int minLines = 13; | int minLines = 13; | ||
int currentLines = dataList.Count; | int currentLines = dataList.Count; | ||
| Line 585: | Line 585: | ||
htmlTable.AppendLine("</tr>"); | htmlTable.AppendLine("</tr>"); | ||
} | } | ||
== Debugging == | == Debugging == | ||
// Add this using statement at top of your script: | // Add this using statement at top of your script: | ||
using ZinformAccounts.Debugger; | using ZinformAccounts.Debugger; | ||
| Line 598: | Line 598: | ||
// Show debug information | // Show debug information | ||
MessageBox.Show($"Debug: {variableName}"); | MessageBox.Show($"Debug: {variableName}"); | ||
== Complete Example == | == Complete Example == | ||
| Line 604: | Line 604: | ||
Here's a simplified but complete statement script: | Here's a simplified but complete statement script: | ||
using System; | using System; | ||
using System.Text; | using System.Text; | ||
| Line 706: | Line 706: | ||
} | } | ||
} | } | ||
== Troubleshooting == | == Troubleshooting == | ||
Latest revision as of 03:49, 10 November 2025
Document Scripting
Document Scripting allows you to create custom documents in ZinformAccounts by writing C# code that processes templates and data. This guide covers the core functions and patterns you'll use.
Getting Started
Every document script follows this basic structure:
public class DocumentScripter
{
public static BusinessLayerMain zinBL;
public static Document document;
public bool Main(BusinessLayerMain bl, object documentTemplate, object? otherPartyDataTable,
ZinParameters parameters, ZinParameters returnParameters, User? user)
{
zinBL = bl;
// Your code here
return true; // or false if error
}
}
Important: Your class must be named DocumentScripter and have a Main method with these exact parameters.
Working with ZinWord Documents
Creating and Loading Documents
// Create a new document ZinWord document = new ZinWord(zinBL);
// Load from file document.LoadDocument(documentFileName);
// Load from stream document.LoadStream(memoryStream);
// Clone an existing document (useful when processing multiple records) ZinWord clonedDoc = sourceDocument.Clone(true);
Saving Documents
// Save to file - format determined by extension document.SaveDocument(saveFileName);
// Examples: document.SaveDocument("MyFile.pdf"); // Saves as PDF document.SaveDocument("MyFile.docx"); // Saves as Word document
Checking Document Content
// Check if document has any content (text, tables, or images) bool hasContent = zinBL.DocumentFunctions.DocumentHasContent(document);
Attaching Documents
// Combine multiple documents into one (useful for bulk processing) ZinWord bulkDocument = new ZinWord(zinBL); bulkDocument.AttachDocument(sourceDocument1); bulkDocument.AttachDocument(sourceDocument2); bulkDocument.SaveDocument("Bulk_Output.pdf");
Working with Bookmarks
Bookmarks are placeholders in your Word templates that you replace with actual data.
Setting Bookmark Values
// Set text value document.SetBookmarkString("BookmarkName", "Value");
// Set HTML content (for formatted text, tables, etc.) document.SetBookmarkHtml("BookmarkName", htmlString);
// Set hyperlink document.SetBookmarkHyperLink("BookmarkName", hyperLinkItem);
// Set image from file document.SetBookmarkImageFromFile("BookmarkName", pictureFileName);
// Set image from Picture object document.SetBookmarkImage("BookmarkName", pictureItem);
Deleting Bookmarks
// Remove a bookmark and its content document.DeleteBookmark("BookmarkName");
Getting All Bookmarks
// Retrieve all bookmarks in the document var bookmarks = document.GetBookmarks();
foreach (var bookmark in bookmarks) {
// Process each bookmark string name = bookmark.Name; // ... do something with the bookmark
}
Standard Bookmarks
ZinformAccounts provides automatic processing for common bookmarks:
ProcessStandardBookmarks
zinBL.DocumentFunctions.ProcessStandardBookmarks(
document, // ZinWord document to process otherParty, // ZOtherParty object (customer/supplier) parameters, // ZinParameters with document settings zinBL, // Business layer instance logoWidth, // Logo width in pixels (e.g., 193) logoHeight, // Logo height in pixels (e.g., 70) minAddressLines, // Minimum address lines (default: 4) addresseeFirstLineAddress, // Use first line as addressee (default: false) stateAsCity // Treat state as city (NZ DB) (default: false)
);
Supported Standard Bookmarks:
OrganisationLogo- Your company logoOrganisationName- Your company nameOrganisationAddress- Your postal addressOrganisationPhone- Your phone numberOrganisationEmail- Your email addressOrganisationWebsite- Your website URLOrganisationBankAccount- Bank account name and numberOrganisationBankAccountNumber- Bank account number onlyOrganisationBankAccountName- Bank account name onlyDocumentDate- Current date (formatted as "dd MMMM yyyy")DocumentId- Document ID from parametersGSTNumber- Tax registration numberOtherPartyId- Customer/Supplier IDOtherPartyName- Customer/Supplier nameOtherPartyAddress- Customer/Supplier postal addressOtherPartySalutation- Greeting (from Administrator/Manager contact)ReferenceId- Reference IDOrganisationNameFooter- Company name for footer
ProcessExtraInvoiceBookmarks
For invoice-specific bookmarks (duplicated bookmarks with "2" suffix):
zinBL.DocumentFunctions.ProcessExtraInvoiceBookmarks(
document, otherParty, parameters, zinBL, logoWidth, logoHeight, minAddressLines, addresseeFirstLineAddress, stateAsCity
);
ProcessInvoiceBookmarks
Handles delivery address for invoices:
zinBL.DocumentFunctions.ProcessInvoiceBookmarks(
document, otherParty, parameters, zinBL, transaction, minAddressLines, stateAsCity, "DELIVERY"
);
Supported Bookmark:
DeliverToDetails- Delivery address (deleted if no delivery address exists)
ProcessExtraStatementBookmarks
For statement-specific bookmarks (duplicated bookmarks with "2" suffix):
zinBL.DocumentFunctions.ProcessExtraStatementBookmarks(
document, otherParty, parameters, zinBL, logoWidth, logoHeight, minAddressLines, addresseeFirstLineAddress, stateAsCity
);
Working with Parameters
Parameters pass data between the UI and your script.
Getting Parameter Values
// Get string value string documentId = parameters.GetItemString("DocumentId");
// Get datetime value DateTime asAtDate = (DateTime)parameters.GetItemDateTime("DateAsAt");
// Get boolean value bool individual = parameters.GetItemBoolean("IndividualDocuments");
// Get output extension string extension = parameters.GetItemString("OutputExtension"); string filter = parameters.GetItemString("OutputExtensionFilter");
Setting Return Parameters
// Return the save location to the caller returnParameters.SetItemString("SaveLocation", saveLocation);
// Return error message if something fails returnParameters.SetItemString("ReturnError", "No File Save Location Chosen!");
File Operations
Save File Dialog
string saveLocation = FileFunctions.OpenSaveFileDialog(
document.DocumentOutputFolder, // Default folder
String.Format("Statement_{0}", DateTime.Now.ToString("yyyyMMdd_hhmmss")), // Default filename
parameters.GetItemString("OutputExtension"), // Default extension (e.g., "pdf")
parameters.GetItemString("OutputExtensionFilter") // File type filter
);
if (saveLocation != null && saveLocation.Length > 0) {
// User selected a location
} else {
// User cancelled - handle error
returnParameters.SetItemString("ReturnError", "No File Save Location Chosen!");
return false;
}
Creating Directories
string folderPath = Path.Combine(baseFolderPath, $"OtherParty_{otherPartyId}");
if (!Directory.Exists(folderPath)) {
Directory.CreateDirectory(folderPath);
}
string saveFileName = Path.Combine(folderPath, "Statement.pdf");
Working with DataTables
When processing multiple records (e.g., statements for multiple customers):
// Validate the DataTable parameter
DataTable otherPartyDataTable;
if (otherPartyDataTable != null && otherPartyDataTable is DataTable)
{
otherPartyDataTable = (DataTable)otherPartyDataTable;
} else {
throw new InvalidOperationException("otherPartyDataTable is not a valid DataTable");
}
// Loop through rows foreach (DataRow row in otherPartyDataTable.Rows) {
// Get values from the row string otherPartyId = (string)row["OtherPartyId"]; // Load the full OtherParty object var otherParty = zinBL.OtherPartyFunctions.GetOtherPartyById(otherPartyId); // Process document for this party
}
Progress Bar
Show progress when processing multiple records:
ProgressBarManager.Start("Processing Statements", true, totalCount, progressBar =>
{
int currentCount = 1;
foreach (DataRow row in dataTable.Rows)
{
// Check for cancellation
if (progressBar.CancellationPending || ProgressBarManager.IsCancelled())
{
break;
}
// Update progress
progressBar.ReportProgress(currentCount, $"Processing: {customerName}");
// Do work here...
currentCount++;
}
// Mark as finished
ProgressBarManager.Finished();
});
Financial Functions
Statement Data
// Get statement details (aged balances) ZinStatementDetails details = zinBL.DocumentFunctions.GetStatementDetails(
zinBL, otherParty, statementDate, DocumentTypes.ARStatement // or DocumentTypes.APRemittance
);
// Access aged balances decimal current = details.CurrentBalance; decimal oneMonth = details.OneMonthOverdue; decimal twoMonths = details.TwoMonthsOverdue; decimal threeMonths = details.ThreeMonthsOverdue; decimal total = details.TotalDue;
Transaction Data
// Get monthly running transactions (preferred method) var (transactions, statementDetails) = zinBL.DocumentFunctions.GetMonthlyRunningTransactions2(
statementDate, otherPartyId, zinBL
);
// transactions is List<StatementTransaction2> // statementDetails is ZinStatementDetails with aged balances
// Process transactions foreach (var tran in transactions) {
DateTime date = tran.Date; int type = tran.Type; string reference = tran.Reference; decimal value = tran.Value; decimal runningBalance = tran.RunningBalance; decimal subTotal = tran.SubTotal;
}
Combining Transaction Lists
// Combine and sort multiple transaction lists by date var combined = zinBL.DocumentFunctions.CombineTransactions(listOne, listTwo);
Date Utilities
// Get last day of month DateTime monthEnd = DocumentFunctions.GetEndOfMonth(someDate); // Example: 15/03/2024 returns 31/03/2024
Building HTML Tables
For inserting formatted tables into bookmarks:
var htmlTable = new StringBuilder();
htmlTable.AppendLine("
"); htmlTable.AppendLine("<thead>"); htmlTable.AppendLine(""); htmlTable.AppendLine(""); htmlTable.AppendLine(""); htmlTable.AppendLine(""); htmlTable.AppendLine(""); htmlTable.AppendLine("</thead>"); htmlTable.AppendLine("<tbody>"); foreach (var item in dataList) { htmlTable.AppendLine(""); htmlTable.AppendLine($""); htmlTable.AppendLine($""); htmlTable.AppendLine($""); htmlTable.AppendLine(""); } htmlTable.AppendLine("</tbody>"); htmlTable.AppendLine("| Date | Reference | Amount |
| {item.Date:dd/MM/yyyy} | {item.Reference} | {item.Amount:$#,##0.00} |
");
// Insert into document document.SetBookmarkHtml("TableBookmark", htmlTable.ToString());
Tips for HTML Tables:
- Use inline styles (external CSS won't work)
- Specify
font-family: "Aptos", sans-serif;for consistency - Use
text-align: rightfor numbers - Add padding for readability:
padding: 5px; - Format currency:
{value:$#,##0.00}
Email Integration
Sending Documents via Email
// Get email addresses for specific contacts var emailAddresses = otherParty.GetEmailContactsAsEmailCompatibleStringById(document.EmailContactIds);
if (emailAddresses.Length > 0) {
// Replace placeholders in email body
string emailBody = document.EmailBody.Replace("[OtherPartyName]", otherParty.Name);
// Send email with attachment
var result = zinBL.Emailing.SendEmailWithImage(
emailAddresses, // To addresses
"", // CC addresses
"", // BCC addresses
document.EmailSubject, // Subject
emailBody, // HTML body
zinBL, // Business layer
attachmentFilePath, // Path to attachment
false, // Is HTML
70L, // Image quality
444, // Max image width
"unsubscribe@yourdomain.com" // Unsubscribe email
);
if (!result.success)
{
MessageBox.Show(result.errorMessage);
}
}
Best Practices
Error Handling
try {
// Your code here
if (somethingWentWrong)
{
returnParameters.SetItemString("ReturnError", "Clear error message here");
return false;
}
} catch (Exception ex) {
MessageBox.Show($"An error occurred: {ex.Message}\n{ex.StackTrace}", "Error");
returnParameters.SetItemString("ReturnError", ex.Message);
return false;
}
return true; // Success
Memory Management
When processing many documents, clean up:
foreach (DataRow row in dataTable.Rows)
{
var clonedDoc = sourceDoc.Clone(true); // Process document... // If not saving this document, explicitly dispose clonedDoc = null;
}
Conditional Processing
// Only add to bulk document if not emailed bool wasEmailed = false;
if (document.EmailIfPossible && emailAddresses.Length > 0) {
// Send email wasEmailed = true;
}
if (!wasEmailed) {
bulkDocument.AttachDocument(processedDoc);
}
Common Patterns
Pattern: Individual vs Bulk Documents
bool individual = parameters.GetItemBoolean("IndividualDocuments"); ZinWord bulkDoc = new ZinWord(zinBL);
foreach (var otherParty in otherParties) {
var doc = ProcessDocument(otherParty);
if (individual)
{
// Save individual file
string fileName = $"{folderPath}/Document_{otherParty.OtherPartyId}.pdf";
doc.SaveDocument(fileName);
}
else
{
// Add to bulk document
bulkDoc.AttachDocument(doc);
}
}
// Save bulk document if not individual if (!individual && zinBL.DocumentFunctions.DocumentHasContent(bulkDoc)) {
bulkDoc.SaveDocument(saveLocation);
}
Pattern: Processing with Progress
ProgressBarManager.Start("Processing Documents", true, dataTable.Rows.Count, progressBar => {
int currentCount = 1;
foreach (DataRow row in dataTable.Rows)
{
if (progressBar.CancellationPending || ProgressBarManager.IsCancelled())
{
break;
}
progressBar.ReportProgress(currentCount, $"Processing: {currentItem}");
// Do work...
currentCount++;
}
ProgressBarManager.Finished();
});
Pattern: Empty Row Padding
int minLines = 13; int currentLines = dataList.Count; int emptyLines = Math.Max(0, minLines - currentLines);
for (int i = 0; i < emptyLines; i++) {
htmlTable.AppendLine(""); htmlTable.AppendLine(""); htmlTable.AppendLine(""); }
Debugging
// Add this using statement at top of your script: using ZinformAccounts.Debugger;
// Launch debugger at any point DebuggerExtensions.LaunchNow("Starting Main method");
// Show debug information MessageBox.Show($"Debug: {variableName}");
Complete Example
Here's a simplified but complete statement script:
using System;
using System.Text;
using System.Windows;
using System.Data;
using ZinBusinessLayer;
using ZinBusinessLayer.HelperClasses;
using ZinBusinessLayer.Enums;
using ZinBusinessLayer.Word;
public class DocumentScripter {
public static BusinessLayerMain zinBL; public static Document document;
public bool Main(BusinessLayerMain bl, object documentTemplate, object? otherPartyDataTable,
ZinParameters parameters, ZinParameters returnParameters, User? user)
{
zinBL = bl;
if (!(documentTemplate is ZinWord sourceDoc))
{
returnParameters.SetItemString("ReturnError", "Invalid document template");
return false;
}
document = zinBL.DocumentFunctions.GetDocument(parameters.GetItemString("DocumentId"));
DateTime statementDate = (DateTime)parameters.GetItemDateTime("DateAsAt");
string saveLocation = FileFunctions.OpenSaveFileDialog(
document.DocumentOutputFolder,
$"Statement_{DateTime.Now:yyyyMMdd_hhmmss}",
parameters.GetItemString("OutputExtension"),
parameters.GetItemString("OutputExtensionFilter")
);
if (string.IsNullOrEmpty(saveLocation))
{
returnParameters.SetItemString("ReturnError", "No save location chosen");
return false;
}
DataTable dataTable = (DataTable)otherPartyDataTable;
ZinWord bulkDoc = new ZinWord(zinBL);
ProgressBarManager.Start("Processing Statements", true, dataTable.Rows.Count, progressBar =>
{
int count = 1;
foreach (DataRow row in dataTable.Rows)
{
if (progressBar.CancellationPending) break;
string otherPartyId = (string)row["OtherPartyId"];
var otherParty = zinBL.OtherPartyFunctions.GetOtherPartyById(otherPartyId);
progressBar.ReportProgress(count, $"Processing: {otherParty.Name}");
var doc = sourceDoc.Clone(true);
// Process bookmarks
zinBL.DocumentFunctions.ProcessStandardBookmarks(
doc, otherParty, parameters, zinBL, 193, 70, 5
);
// Get statement data
var (transactions, details) = zinBL.DocumentFunctions.GetMonthlyRunningTransactions2(
statementDate, otherPartyId, zinBL
);
// Build transaction table
var html = new StringBuilder();
html.AppendLine("
"); foreach (var tran in transactions) { html.AppendLine(""); html.AppendLine($""); html.AppendLine($""); html.AppendLine($""); html.AppendLine(""); } html.AppendLine("| {tran.Date:dd/MM/yyyy} | {tran.Reference} | {tran.Value:$#,##0.00} |
");
doc.SetBookmarkHtml("Transactions", html.ToString());
doc.SetBookmarkString("TotalDue", details.TotalDue.ToString("#,##0.00"));
bulkDoc.AttachDocument(doc);
count++;
}
ProgressBarManager.Finished();
});
if (zinBL.DocumentFunctions.DocumentHasContent(bulkDoc))
{
bulkDoc.SaveDocument(saveLocation);
}
returnParameters.SetItemString("SaveLocation", saveLocation);
return true;
}
}
Troubleshooting
| Problem | Solution |
|---|---|
| Bookmark not found error | Check spelling - bookmarks are case-sensitive |
| HTML not rendering properly | Use inline styles only, no external CSS |
| Progress bar not showing | Ensure you call ProgressBarManager.Finished()
|
| Document won't save | Check file path and ensure extension matches format |
| Changes not appearing | Make sure you're modifying the correct document instance (not the template) |