PSTW_CentralizeSystem/Areas/IT/Printing/ItRequestPdfService.cs
2025-11-10 15:25:14 +08:00

731 lines
32 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using QuestPDF.Drawing;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace PSTW_CentralSystem.Areas.IT.Printing
{
public class ItRequestPdfService
{
public byte[] Generate(ItRequestReportModel m)
{
QuestPDF.Settings.License = LicenseType.Community;
return Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(14);
page.DefaultTextStyle(x => x.FontSize(7));
page.Content().Column(col =>
{
col.Item().Element(e => HeaderStrip(e, m));
col.Item().PaddingTop(4).Text(
"This form is digitally generated. Submit to http://support.transwater.com.my");
// ===== SECTION A =====
col.Item().PaddingTop(4).Text("Section A").Bold().FontSize(7);
col.Item().Element(e => SectionA_IdentityEmployment(e, m));
// two-column layout (left = Hardware+OS+Software, right = Email+Internet+Shared+Copier)
col.Item().Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1); // LEFT
cols.ConstantColumn(8); // gutter
cols.RelativeColumn(1); // RIGHT
});
// left cell (entire left stack)
t.Cell()
.Element(x => x.MinHeight(380)) // optional: set a floor so both look balanced
.Element(e => SectionA_HardwareOsSoftware(e, m));
// gutter cell
t.Cell().Text("");
// right cell (entire right stack)
t.Cell()
.Element(x => x.MinHeight(380)) // same floor as left
.Element(e => SectionA_RightPane_EmailInternetShared(e, m));
});
col.Item().Element(e => FormArrangementBlock(e, m));
col.Item().Element(e => SectionB_TwoBlocks(e, m));
});
});
}).GeneratePdf();
}
// ---------------- helpers & styles ----------------
#region HELPERS
static string Box(bool on) => on ? "☒" : "☐";
static string F(DateTime? dt) => dt.HasValue ? dt.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture) : "";
static IContainer Cell(IContainer x) => x.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(4);
static IContainer CellHead(IContainer x) => x.Background(Colors.Grey.Lighten4).Border(1).BorderColor(Colors.Grey.Lighten2).Padding(4);
static IContainer CellMandatory(IContainer x) => x.Background(Colors.Grey.Lighten2).Border(1).BorderColor(Colors.Grey.Lighten2).Padding(4);
#endregion
// ================= HEADER (boxed like your screenshot) =================
void HeaderStrip(IContainer c, ItRequestReportModel m)
{
c.Border(1).Padding(0).Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(2); // LEFT: big title
cols.RelativeColumn(1); // RIGHT: meta table
});
// LEFT pane: centered title
t.Cell().BorderRight(1).Padding(8).MinHeight(10).AlignCenter().AlignMiddle().Column(left =>
{
left.Item().Text("I.T. REQUEST FORM").SemiBold().FontSize(14).AlignCenter();
left.Item().Text("(Group IT)").SemiBold().FontSize(14).AlignCenter();
});
// RIGHT pane: 2-column grid with borders
t.Cell().Padding(0).Element(x => RightMetaBox(x, m));
});
}
// draws the right-side 2-column table with boxed rows
void RightMetaBox(IContainer c, ItRequestReportModel m)
{
c.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1); // label
cols.RelativeColumn(1); // value
});
void Row(string label, string value, bool isLast = false)
{
// label cell (left)
t.Cell().BorderBottom(1).Padding(2).Text(label);
// value cell (right) — add vertical divider between label/value
t.Cell().BorderLeft(1).BorderBottom(1).Padding(0).AlignMiddle().Text(value ?? "");
}
Row("Document No.", m.DocumentNo);
Row("Effective Date", (m.EffectiveDate == default) ? "" : m.EffectiveDate.ToString("dd/MM/yyyy"));
Row("Rev. No", m.RevNo); // <- shows dynamic StatusId value
Row("Doc. Page No", m.DocPageNo); // last row still gets bottom border for boxed look
});
}
// ================= SECTION A =================
#region SECTION A Identity & Employment
// ================= SECTION A Identity & Employment (refined layout) =================
// SECTION A — Identity + Employment as ONE BLOCK (matches screenshot)
// ================= SECTION A Compact Unified Block (new refined layout) =================
void SectionA_IdentityEmployment(IContainer c, ItRequestReportModel m)
{
// helpers
var emp = (m.EmploymentStatus ?? "").Trim().ToLowerInvariant();
bool isPerm = emp == "permanent";
bool isContract = emp == "contract";
bool isTemp = emp == "temp" || emp == "temporary";
bool isNew = emp == "new staff" || emp == "new";
IContainer L(IContainer x) => x.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(4);
IContainer V(IContainer x) => x.Border(1).BorderColor(Colors.Grey.Lighten2).Padding(4);
c.Table(t =>
{
// 6-column consistent grid
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1); // L1
cols.RelativeColumn(2); // V1
cols.RelativeColumn(1); // L2
cols.RelativeColumn(2); // V2
cols.RelativeColumn(1); // L3
cols.RelativeColumn(2); // V3
});
// === Row 1: Staff Name / Company / Div ===
t.Cell().Element(L).Text("Staff Name:");
t.Cell().Element(V).Text(m.StaffName ?? "");
t.Cell().Element(L).Text("Company:");
t.Cell().Element(V).Text(m.CompanyName ?? "");
t.Cell().Element(L).Text("Div/Dept:");
t.Cell().Element(V).Text(m.DepartmentName ?? "");
// === Row 2: Designation / Location ===
t.Cell().Element(L).Text("Designation:");
t.Cell().Element(V).Text(m.Designation ?? "");
t.Cell().Element(L).Text("Location:");
t.Cell().Element(V).Text(m.Location ?? "");
// fill the last two cells to maintain full-width grid
t.Cell().Element(L).Text("");
t.Cell().Element(V).Text("");
// === Row 3: Employment Status + Contract End Date beside it ===
t.Cell().Element(L).Text("Employment Status:");
t.Cell().ColumnSpan(3).Element(V).Row(r =>
{
r.Spacing(12);
r.ConstantItem(50).Text($"{Box(isPerm)} Permanent");
r.ConstantItem(50).Text($"{Box(isContract)} Contract");
r.ConstantItem(50).Text($"{Box(isTemp)} Temp");
r.ConstantItem(50).Text($"{Box(isNew)} New Staff");
});
t.Cell().Element(L).Text("If Temp / Contract End Date:");
t.Cell().Element(V).Text(F(m.ContractEndDate));
// === Row 4: Phone Ext + Required Date beside it ===
t.Cell().Element(L).Text("Phone Ext:");
t.Cell().Element(V).Text(m.PhoneExt ?? "");
t.Cell().Element(L).Text("Required Date:");
t.Cell().Element(V).Text(F(m.RequiredDate));
// keep remaining two cells empty to close grid
t.Cell().Element(L).Text("");
t.Cell().Element(V).Text("");
});
}
#endregion
#region SECTION A HardwareOsSoftware
// ===================== SECTION A HARDWARE + OS + SOFTWARE =====================
void SectionA_HardwareOsSoftware(IContainer c, ItRequestReportModel m)
{
bool HasSoft(string name) =>
m.Software.Any(s => (s.Name ?? "").Equals(name, StringComparison.InvariantCultureIgnoreCase));
var general = new[] { "MS Word", "MS Excel", "MS Outlook", "MS PowerPoint", "MS Access", "MS Project", "Acrobat Standard", "AutoCAD", "Worktop/ERP Login" };
var utility = new[] { "PDF Viewer", "7Zip", "AutoCAD Viewer", "Smart Draw" };
c.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1);
});
// --- HEADER: Hardware Requirements ---
t.Cell().Element(x => x.Background(Colors.Black).Padding(3))
.Text("Hardware Requirements").FontColor(Colors.White).Bold();
// --- Hardware Body ---
t.Cell().Border(1).Padding(1).Column(col =>
{
col.Spacing(5);
col.Item().Row(r =>
{
// Left column: Purpose + Justification
r.RelativeItem().Column(left =>
{
left.Item().Text($"{Box(m.HwPurposeNewRecruitment)} New Staff Recruitment");
left.Item().Text($"{Box(m.HwPurposeReplacement)} Replacement");
left.Item().Text($"{Box(m.HwPurposeAdditional)} Additional");
left.Item().PaddingTop(5).Text("Justification (for hardware change) :");
left.Item().Border(1).Height(40).Padding(4)
.Text(string.IsNullOrWhiteSpace(m.Justification) ? "" : m.Justification);
});
// Right column: Category selection
r.RelativeItem().Column(right =>
{
right.Item().Text("Select below:");
right.Item().Text($"{Box(m.HwDesktopAllIn)} Desktop (all inclusive)");
right.Item().Text($"{Box(m.HwNotebookAllIn)} Notebook (all inclusive)");
right.Item().Text($"{Box(m.HwDesktopOnly)} Desktop only");
right.Item().Text($"{Box(m.HwNotebookOnly)} Notebook only");
right.Item().Text($"{Box(m.HwNotebookBattery)} Notebook battery");
right.Item().Text($"{Box(m.HwPowerAdapter)} Power Adapter");
right.Item().Text($"{Box(m.HwMouse)} Computer Mouse");
right.Item().Text($"{Box(m.HwExternalHdd)} External Hard Drive");
right.Item().Text("Other (Specify):");
right.Item().Border(1).Height(18).Padding(3)
.Text(string.IsNullOrWhiteSpace(m.HwOtherText) ? "-" : m.HwOtherText);
});
});
});
// --- HEADER: OS Requirements ---
t.Cell().Element(x => x.Background(Colors.Black).Padding(3))
.Text("OS Requirements (Leave blank if no specific requirement)")
.FontColor(Colors.White).Bold();
// --- OS Body ---
t.Cell().Border(1).Padding(5).Column(col =>
{
col.Item().Text("Requirements:");
col.Item().Border(1).Height(30).Padding(4)
.Text(m.OsRequirements.Any() ? string.Join(Environment.NewLine, m.OsRequirements) : "-");
});
// --- HEADER: Software Requirements ---
t.Cell().Element(x => x.Background(Colors.Black).Padding(3))
.Text("Software Requirements").FontColor(Colors.White).Bold();
// --- Software Body (3 columns) ---
t.Cell().Border(1).Padding(5).Table(st =>
{
st.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1); // General
cols.RelativeColumn(1); // Utility
cols.RelativeColumn(1); // Custom
});
// Headings
st.Header(h =>
{
h.Cell().Element(CellHead).Text("General Software");
h.Cell().Element(CellHead).Text("Utility Software");
h.Cell().Element(CellHead).Text("Custom Software");
});
int maxRows = Math.Max(general.Length, utility.Length);
for (int i = 0; i < maxRows; i++)
{
st.Cell().Element(Cell)
.Text(i < general.Length ? $"{Box(HasSoft(general[i]))} {general[i]}" : "");
st.Cell().Element(Cell)
.Text(i < utility.Length ? $"{Box(HasSoft(utility[i]))} {utility[i]}" : "");
if (i == 0)
{
st.Cell().Element(Cell).Text("Others (Specify) :");
}
else if (i == 1)
{
st.Cell().Element(Cell).Border(1).Height(15).Padding(3).Text("-");
}
else st.Cell().Element(Cell).Text("");
}
});
});
}
#endregion
#region SECTION A EmailInternetSharedperm
// ===================== SECTION A RIGHT PANE =====================
void SectionA_RightPane_EmailInternetShared(IContainer c, ItRequestReportModel m)
{
c.Column(col =>
{
// ===== Email =====
col.Item().Element(x => x.Background(Colors.Black).Padding(3))
.Text("Email").FontColor(Colors.White).Bold();
col.Item().Border(1).Padding(6).Column(cc =>
{
// single-line "Email Address:" with inline box
cc.Item().Row(r =>
{
r.ConstantItem(100).Text("Email Address:"); // label column width
r.RelativeItem().Border(1).Height(16).PaddingHorizontal(4).AlignMiddle()
.Text(m.Emails.Any() ? string.Join("; ", m.Emails) : "");
});
cc.Item().PaddingTop(4).Text("Arrangement Guide: FirstName&LastName or Name&Surname or Surname&Name.");
cc.Item().Text("Full name and short form/ initial is allowed to be used if the name is too long.");
cc.Item().Text("e.g. siti.nurhaliza, jackie.chan, ks.chan");
});
// ===== Internet Permissions =====
col.Item().Element(x => x.Background(Colors.Black).Padding(3))
.Text("Internet Permissions").FontColor(Colors.White).Bold();
col.Item().Border(1).Padding(0).Column(cc =>
{
cc.Item().BorderBottom(1).Padding(6).Text($"{Box(false)} Unlimited Internet Access");
cc.Item().BorderBottom(1).Padding(6).Text($"{Box(false)} Limited Internet Access");
cc.Item().BorderBottom(1).Padding(6).Text($"{Box(false)} PSI Instant Messenger");
cc.Item().BorderBottom(1).Padding(6).Text($"{Box(false)} VPN");
cc.Item().PaddingLeft(14).PaddingTop(4).Text("Justification for the Internet Permissions:");
cc.Item().Padding(6).Border(1).Height(20).Padding(4).Text("-");
});
// ===== Shared Permissions =====
col.Item().PaddingTop(0).Element(x => x.Background(Colors.Black).Padding(3))
.Text("Shared Permissions").FontColor(Colors.White).Bold();
col.Item().Border(1).Padding(0).Element(x => SharedPermissionsTable(x, m));
// ===== Copier =====
col.Item().PaddingTop(0).Element(x => x.Border(1).Padding(8)).Column(cc =>
{
cc.Item().Row(rr =>
{
rr.RelativeItem().Row(r1 =>
{
r1.RelativeItem().Text("Copier Scanner");
r1.RelativeItem().Text($"{Box(true)} Black");
r1.RelativeItem().Text($"{Box(false)} Color");
});
rr.RelativeItem().Row(r2 =>
{
r2.RelativeItem().Text("Copier Printing");
r2.RelativeItem().Text($"{Box(true)} Black");
r2.RelativeItem().Text($"{Box(false)} Color");
});
});
});
});
}
void SharedPermissionsTable(IContainer c, ItRequestReportModel m)
{
c.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.ConstantColumn(18); // #
cols.RelativeColumn(6); // Share
cols.RelativeColumn(1); // Read
cols.RelativeColumn(1); // Write
cols.RelativeColumn(1); // Delete
cols.RelativeColumn(1); // Remove
});
// header band
t.Header(h =>
{
h.Cell().Element(CellHead).Text("");
h.Cell().Element(CellHead).Text("Shared Permissions");
h.Cell().Element(CellHead).Text("Read");
h.Cell().Element(CellHead).Text("Write");
h.Cell().Element(CellHead).Text("Delete");
h.Cell().Element(CellHead).Text("Remove");
});
var rows = m.SharedPerms.Select((sp, i) => new
{
Index = i + 1,
sp.Share,
sp.R,
sp.W,
sp.D,
sp.Remove
}).ToList();
foreach (var r in rows)
{
t.Cell().Element(Cell).Text(r.Index.ToString());
t.Cell().Element(Cell).Text(r.Share ?? "");
t.Cell().Element(Cell).Text(Box(r.R));
t.Cell().Element(Cell).Text(Box(r.W));
t.Cell().Element(Cell).Text(Box(r.D));
t.Cell().Element(Cell).Text(Box(r.Remove));
}
int start = rows.Count + 1; // no hardcoded row; if no data, start at 1
for (int i = start; i <= 6; i++)
{
t.Cell().Element(Cell).Text(i.ToString());
t.Cell().Element(Cell).Text("");
t.Cell().Element(Cell).Text("");
t.Cell().Element(Cell).Text("");
t.Cell().Element(Cell).Text("");
t.Cell().Element(Cell).Text("");
}
});
}
#endregion
#region SECTION A OS Requirements
// ===================== SECTION A Form Arrangement =====================
void FormArrangementBlock(IContainer c, ItRequestReportModel m)
{
// tiny helper: draws the vertical borders for each cell so it looks like 5 boxed panels
IContainer BoxCell(IContainer x, bool isLast) =>
x.BorderLeft(1)
.BorderRight(isLast ? 1 : 0) // last cell closes the right border
.Padding(6)
.MinHeight(45); // keep all equal; adjust to taste
c.Column(col =>
{
// italic guide line
col.Item()
.PaddingBottom(4)
.Text("Form Arrangement: User → HOD → IT HOD → FINANCE HOD → CEO/CFO/COO")
.Italic();
// OUTER frame
col.Item().Border(1).Element(frame =>
{
frame.Table(t =>
{
// 5 equal columns
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1);
cols.RelativeColumn(1);
cols.RelativeColumn(1);
cols.RelativeColumn(1);
cols.RelativeColumn(1);
});
// local function to render a boxed panel
void Panel(int index0to4, string title, string name, string date)
{
bool last = index0to4 == 4;
t.Cell().Element(x => BoxCell(x, last)).Column(cc =>
{
cc.Item().Text(title);
// signature line
// Name / Date rows
cc.Item().PaddingTop(8).Row(r =>
{
r.ConstantItem(40).Text("Name :");
r.RelativeItem().Text(string.IsNullOrWhiteSpace(name) ? "" : name);
});
cc.Item().Row(r =>
{
r.ConstantItem(40).Text("Date :");
r.RelativeItem().Text(string.IsNullOrWhiteSpace(date) ? "" : date);
});
});
}
// build the 5 panels (plug in your resolved names/dates)
Panel(0, "Requested by:", m.RequestorName ?? "", F(m.SubmitDate) ?? "");
Panel(1, "Approved by HOD:", m.HodApprovedBy ?? "", F(m.HodSubmitDate) ?? "");
Panel(2, "Approved by Group IT HOD:", m.GitHodApprovedBy ?? "", F(m.GitHodSubmitDate) ?? "");
Panel(3, "Supported by Finance HOD:", m.FinHodApprovedBy ?? "", F(m.FinHodSubmitDate) ?? "");
Panel(4, "Reviewed & Approved by Management:", m.MgmtApprovedBy ?? "", F(m.MgmtSubmitDate) ?? "");
});
});
});
}
#endregion
#region SECTION A Approvals
void Approvals(IContainer c, ItRequestReportModel m)
{
c.Column(col =>
{
col.Item().Row(r =>
{
r.RelativeItem().Column(cc =>
{
cc.Item().Text("Requested by:");
cc.Item().PaddingTop(12).Text("Name : MANDATORY");
cc.Item().Row(rr =>
{
rr.ConstantItem(40).Text("Date :");
rr.RelativeItem().Border(1).Height(14).Text(F(m.SubmitDate));
});
});
r.RelativeItem().Column(cc =>
{
cc.Item().Text("Approved by HOD:");
cc.Item().PaddingTop(12).Text("Name :");
cc.Item().Row(rr =>
{
rr.ConstantItem(40).Text("Date :");
rr.RelativeItem().Border(1).Height(16).Text("");
});
});
});
col.Item().Row(r =>
{
r.RelativeItem().Column(cc =>
{
cc.Item().Text("Approved by Group IT HOD:");
cc.Item().PaddingTop(12).Text("Name :");
cc.Item().Row(rr =>
{
rr.ConstantItem(40).Text("Date :");
rr.RelativeItem().Border(1).Height(16).Text("");
});
});
r.RelativeItem().Column(cc =>
{
cc.Item().Text("Supported by Finance HOD:");
cc.Item().PaddingTop(12).Text("Name :");
cc.Item().Row(rr =>
{
rr.ConstantItem(40).Text("Date :");
rr.RelativeItem().Border(1).Height(16).Text("");
});
});
});
col.Item().Row(r =>
{
r.RelativeItem().Column(cc =>
{
cc.Item().Text("Reviewed & Approved by");
cc.Item().Text("Management:");
cc.Item().PaddingTop(12).Text("Name :");
cc.Item().Row(rr =>
{
rr.ConstantItem(40).Text("Date :");
rr.RelativeItem().Border(1).Height(16).Text("");
});
});
r.RelativeItem().Text("");
});
});
}
#endregion
// ================= SECTION B =================
#region SECTION B Asset Information/ Acknowledgment
void SectionB_TwoBlocks(IContainer c, ItRequestReportModel m)
{
c.Column(col =>
{
// Title line exactly like screenshot (italic note on same line)
col.Item().Text(text =>
{
text.Span("Section B ").Bold();
text.Span("(To be completed by IT Staff only)").Italic();
});
// ===== Block 1: Asset Information (left) + Remarks (right) =====
col.Item().PaddingTop(4).Border(1).Element(block1 =>
{
block1.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1);
cols.ConstantColumn(1); // skinny divider (we'll draw borders on cells)
cols.RelativeColumn(1);
});
// Header row with black bands
// Left header
t.Cell().Element(x => x.Background(Colors.Black).Padding(3).BorderRight(1))
.Text("Asset Information").FontColor(Colors.White).Bold();
// divider (invisible content, keeps structure)
t.Cell().BorderLeft(0).BorderRight(0).Text("");
// Right header
t.Cell().Element(x => x.Background(Colors.Black).Padding(3))
.Text("Remarks:-").FontColor(Colors.White).Bold();
// Content row (equal height because same table row)
// Left: asset info table
t.Cell().Element(x => x.BorderTop(1).BorderRight(1).Padding(0))
.Element(x => SectionB_AssetInfoTable(x, m));
// divider
t.Cell().Border(0).Text("");
// Right: remarks box
t.Cell().Element(x => x.BorderTop(1).Padding(6).MinHeight(108))
.Text(string.IsNullOrWhiteSpace(m.Remarks) ? "" : m.Remarks);
});
});
// ===== Block 2: Requestor Acknowledgement (left) + Completed By (right) =====
// ===== Block 2: Requestor Acknowledgement (left) + Completed By (right) =====
col.Item().PaddingTop(6).Border(1).Element(block2 =>
{
block2.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(1);
cols.ConstantColumn(1); // divider
cols.RelativeColumn(1);
});
// Left pane (no signature line, compact height)
t.Cell().Element(x => x.Padding(8).BorderRight(1)).Column(cc =>
{
cc.Item().Text("Requestor Acknowledgement:").Bold();
cc.Item().PaddingTop(4).Row(r =>
{
r.ConstantItem(44).Text("Name:");
r.RelativeItem().Text(m.RequestorName ?? "");
r.ConstantItem(44).Text("Date:");
r.RelativeItem().Text(F(m.RequestorAcceptedAt));
});
});
// divider
t.Cell().Border(0).Text("");
// Right pane (no signature line)
t.Cell().Element(x => x.Padding(8)).Column(cc =>
{
cc.Item().Text("Completed by:").Bold();
cc.Item().PaddingTop(4).Row(r =>
{
r.ConstantItem(44).Text("Name:");
r.RelativeItem().Text(m.ItCompletedBy ?? "");
r.ConstantItem(44).Text("Date:");
r.RelativeItem().Text(F(m.ItAcceptedAt));
});
});
});
});
});
}
// Left-pane table used in Block 1 (matches your rows & borders)
void SectionB_AssetInfoTable(IContainer c, ItRequestReportModel m)
{
c.Table(t =>
{
t.ColumnsDefinition(cols =>
{
cols.RelativeColumn(2); // label
cols.RelativeColumn(2); // value box
});
void Row(string label, string value)
{
t.Cell().BorderBottom(1).Padding(6).Text(label);
t.Cell().BorderLeft(1).BorderBottom(1).Padding(3).Text(value ?? "");
}
// top row gets its own bottom borders; left cell also has right divider
Row("Asset No:", m.AssetNo);
Row("Machine ID:", m.MachineId);
Row("IP Add:", m.IpAddress);
Row("Wired Mac Add:", m.WiredMac);
Row("Wi-Fi Mac Add:", m.WifiMac);
Row("Dial-up Acc:", m.DialupAcc);
});
}
#endregion
}
}