Invoice themes desktop v

Hi everyone,

I am using Manager Desktop version 26.5.6 and I am looking for a working custom invoice theme/template that is compatible with the current Desktop version.

I have spent quite a bit of time testing various custom themes from the forum, including some of the newer view-v1 themes, but unfortunately they either display placeholders such as {{recipient}}, {{business}}, etc., or remain stuck on “Rendering System Architecture…” and never load the invoice data.

The standard Manager invoice works perfectly and displays all invoice information correctly. My goal is simply to improve the appearance and layout of the invoice so that it looks more professional and better reflects my business branding.

I am not looking for anything overly complicated. I would be happy with a clean, professional invoice layout that correctly displays:

  • Business details
  • Customer details
  • Invoice number and date
  • Line items
  • Totals
  • Banking details
  • Footer notes/terms

Can anyone recommend a custom theme that is confirmed to work with Manager Desktop 26.5.6, or provide example code/templates that are known to be compatible?

Any assistance would be greatly appreciated.

Thank you.

@Lorenda_Mudge welcome to forum,

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>View</title>
<style>
:root { --bg: #f5f5f5; --paper: #fff; }
body { background-color: var(--bg); display: flex; margin: 0; padding: 0; }
main { background-color: var(--paper); margin: 1rem 1.5rem; border: 1px solid #e5e5e5; border-radius: 5px; box-shadow: 0px 4px 6px rgb(0 0 0 / 0.05); padding: 2rem; min-width: 80ch; width: 100%; box-sizing: border-box; }

@media (prefers-color-scheme: dark) {
  :root { --bg: #292524; --paper: #1c1917; }
  main { border: 1px solid #0c0a09; box-shadow: 0px 4px 6px rgb(0 0 0 / 0.50); }
}

@page { margin: 10mm; }
@media print {
  body { background-color: initial; display: initial; }
  main { padding: 0; border: initial; box-shadow: initial; border-radius: initial; margin: 0; min-width: initial; }
}
</style>
</head>
<body>

<main></main>

<script>
// Fetch API payload data safely matching current window contexts
fetch('/api4/view-v1' + window.location.search, {
  headers: { 'Accept': 'application/json' },
  credentials: 'same-origin',
})
  .then(response => response.json())
  .then(data => {
    renderDocument(data);
  });

function renderDocument(data) {
  if (!data) return;

  // 1. Update the document title dynamically for a meaningful PDF filename
  const docRef = data.reference ? ` — ${data.reference}` : '';
  const docBusiness = data.businessName || (data.business && data.business.name) || '';
  document.title = `${data.title || 'Document'}${docRef}${docBusiness ? ' — ' + docBusiness : ''}`;

  const main = document.querySelector('main');
  main.innerHTML = ''; // Clear previous content

  // Set general document properties (Direction and Language)
  if (data.direction) main.setAttribute('dir', data.direction);
  if (data.language) main.setAttribute('lang', data.language);

  // Inject Custom Embedded Styles for Layout and Professional Branding
  const style = document.createElement('style');
  style.textContent = `
    main { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; color: #1c1917; line-height: 1.5; font-size: 14px; }
    @media (prefers-color-scheme: dark) { main { color: #e7e5e4; } }
    
    /* Layout Framework */
    .doc-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 2.5rem; gap: 2rem; }
    .business-branding { flex: 1; }
    .business-logo { max-width: 220px; max-height: 80px; object-fit: contain; margin-bottom: 1rem; display: block; }
    .business-name { font-size: 1.4rem; font-weight: 700; margin: 0 0 0.5rem 0; letter-spacing: -0.02em; }
    .meta-panel { text-align: right; display: flex; flex-direction: column; align-items: flex-end; }
    main[dir="rtl"] .meta-panel { text-align: left; align-items: flex-start; }
    
    /* Typography & Titles */
    .doc-title { font-size: 2.2rem; font-weight: 800; text-transform: uppercase; letter-spacing: -0.02em; margin: 0 0 0.25rem 0; line-height: 1.1; color: #0f172a; }
    @media (prefers-color-scheme: dark) { .doc-title { color: #f8fafc; } }
    .doc-subtitle { font-size: 0.95rem; color: #64748b; margin: 0 0 0.25rem 0; font-weight: 500; }
    .doc-reference { font-size: 1.1rem; font-weight: 600; color: #334155; margin-top: 0.5rem; }
    @media (prefers-color-scheme: dark) { .doc-reference { color: #cbd5e1; } }
    
    /* Status Badge System */
    .status-badge { display: inline-block; padding: 0.35rem 0.75rem; font-size: 0.8rem; font-weight: 700; border-radius: 4px; text-transform: uppercase; letter-spacing: 0.05em; margin-top: 0.75rem; }
    .status-neutral { background-color: #f1f5f9; color: #475569; }
    .status-positive { background-color: #dcfce7; color: #15803d; }
    .status-negative { background-color: #fee2e2; color: #b91c1c; }
    @media (prefers-color-scheme: dark) {
      .status-neutral { background-color: #334155; color: #cbd5e1; }
      .status-positive { background-color: #14532d; color: #4ade80; }
      .status-negative { background-color: #7f1d1d; color: #f87171; }
    }
    
    /* Parties Distribution Grid */
    .parties-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2rem; margin-bottom: 2.5rem; border-top: 1px solid #e2e8f0; border-bottom: 1px solid #e2e8f0; padding: 1.5rem 0; }
    @media (prefers-color-scheme: dark) { .parties-grid { border-color: #2e2a24; } }
    .party-block-title { font-size: 0.8rem; font-weight: 700; text-transform: uppercase; color: #64748b; margin-bottom: 0.5rem; letter-spacing: 0.05em; }
    .party-name { font-weight: 600; font-size: 1.05rem; margin-bottom: 0.25rem; }
    .address-text { white-space: pre-line; color: #475569; font-size: 0.9rem; }
    @media (prefers-color-scheme: dark) { .address-text { color: #94a3b8; } }
    
    /* Top / Header Custom Fields Layout */
    .fields-panel { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 1rem; margin-bottom: 2.5rem; background-color: #f8fafc; padding: 1.25rem; border-radius: 6px; }
    @media (prefers-color-scheme: dark) { .fields-panel { background-color: #1e1b1a; } }
    .field-card { display: flex; flex-direction: column; }
    .field-label { font-size: 0.75rem; font-weight: 600; color: #64748b; text-transform: uppercase; letter-spacing: 0.02em; }
    .field-value { font-size: 0.95rem; font-weight: 600; color: #0f172a; margin-top: 0.15rem; }
    @media (prefers-color-scheme: dark) { .field-value { color: #f8fafc; } }
    .field-emphasized { font-weight: 800; color: #0284c7 !important; }
    
    /* Line Items Dynamic Table styling */
    .table-container { margin-bottom: 2rem; }
    .table-desc { font-style: italic; color: #475569; margin-bottom: 0.75rem; font-size: 0.95rem; }
    table { width: 100%; border-collapse: collapse; text-align: left; }
    main[dir="rtl"] table { text-align: right; }
    th { padding: 0.75rem 1rem; background-color: #f1f5f9; font-weight: 700; font-size: 0.8rem; text-transform: uppercase; color: #475569; border-bottom: 2px solid #cbd5e1; letter-spacing: 0.02em; }
    @media (prefers-color-scheme: dark) {
      th { background-color: #24201e; color: #94a3b8; border-bottom-color: #44403c; }
    }
    td { padding: 0.85rem 1rem; border-bottom: 1px solid #e2e8f0; vertical-align: top; font-size: 0.9rem; }
    @media (prefers-color-scheme: dark) { td { border-bottom-color: #2e2a24; } }
    
    /* Functional Alignment & Layout Classes matching API specification Flags */
    .align-start { text-align: left; }
    main[dir="rtl"] .align-start { text-align: right; }
    .align-center { text-align: center; }
    .align-end { text-align: right; }
    main[dir="rtl"] .align-end { text-align: left; }
    .align-right { text-align: right !important; }
    .nowrap { white-space: nowrap; }
    .emphasis { font-weight: 700; }
    .shrink-to-fit { width: 1%; white-space: nowrap; }
    
    /* Hierarchical Table Grouping Framework (Reports / Summaries) */
    .group-header-row td { background-color: #f8fafc; font-weight: 700; color: #1e293b; border-bottom: 1px solid #cbd5e1; padding: 0.6rem 1rem; }
    @media (prefers-color-scheme: dark) { .group-header-row td { background-color: #24201e; color: #e2e8f0; border-bottom-color: #44403c; } }
    .total-row td { font-weight: 700; background-color: #fafafa; border-top: 1px solid #cbd5e1; border-bottom: 2px double #94a3b8; }
    @media (prefers-color-scheme: dark) { .total-row td { background-color: #1c1917; border-top-color: #44403c; border-bottom-color: #6b7280; } }
    .cell-inline-img { display: inline-block; vertical-align: middle; max-height: 32px; object-fit: contain; margin-right: 0.5rem; }
    main[dir="rtl"] .cell-inline-img { margin-right: 0; margin-left: 0.5rem; }
    .cell-link { color: inherit; text-decoration: underline; text-decoration-color: #cbd5e1; }
    .cell-link:hover { color: #0284c7; }
    
    /* Structured Totals Section Layout */
    .totals-and-footers { display: flex; flex-direction: column; align-items: flex-end; margin-top: 1.5rem; gap: 1.5rem; }
    main[dir="rtl"] .totals-and-footers { align-items: flex-start; }
    .totals-box { width: 40%; min-width: 280px; display: flex; flex-direction: column; gap: 0.5rem; }
    .total-line { display: flex; justify-content: space-between; align-items: center; padding: 0.25rem 0; font-size: 0.95rem; }
    .total-line-label { color: #475569; }
    @media (prefers-color-scheme: dark) { .total-line-label { color: #94a3b8; } }
    .total-line-value { font-weight: 600; }
    .total-line-emphasis { font-size: 1.25rem; font-weight: 800; border-top: 1px solid #cbd5e1; padding-top: 0.75rem; margin-top: 0.25rem; color: #0f172a; }
    @media (prefers-color-scheme: dark) { .total-line-emphasis { color: #f8fafc; border-top-color: #44403c; } }
    
    /* Footer HTML Block Injections */
    .footers-box { width: 100%; border-top: 1px dashed #cbd5e1; padding-top: 1.5rem; margin-top: 1rem; color: #475569; font-size: 0.85rem; }
    @media (prefers-color-scheme: dark) { .footers-box { border-top-color: #44403c; color: #94a3b8; } }
    .footer-block { margin-bottom: 1rem; }
  `;
  main.appendChild(style);

  // --- BUILDING THE HEADER ---
  const headerContainer = document.createElement('div');
  headerContainer.className = 'doc-header';

  // Left Block: Business Branding
  const brandingBlock = document.createElement('div');
  brandingBlock.className = 'business-branding';

  if (data.business) {
    if (data.business.logo) {
      const logoImg = document.createElement('img');
      logoImg.src = data.business.logo;
      logoImg.className = 'business-logo';
      logoImg.alt = data.business.name || 'Business Logo';
      brandingBlock.appendChild(logoImg);
    }
    if (data.business.name) {
      const bName = document.createElement('h2');
      bName.className = 'business-name';
      bName.textContent = data.business.name;
      brandingBlock.appendChild(bName);
    }
    if (data.business.address) {
      const bAddr = document.createElement('div');
      bAddr.className = 'address-text';
      bAddr.textContent = data.business.address;
      brandingBlock.appendChild(bAddr);
    }
  } else if (data.businessName) {
    const bName = document.createElement('h2');
    bName.className = 'business-name';
    bName.textContent = data.businessName;
    brandingBlock.appendChild(bName);
  }
  headerContainer.appendChild(brandingBlock);

  // Right Block: Main Title Meta Info Panel
  const metaPanel = document.createElement('div');
  metaPanel.className = 'meta-panel';

  const docTitle = document.createElement('h1');
  docTitle.className = 'doc-title';
  docTitle.textContent = data.title;
  metaPanel.appendChild(docTitle);

  if (data.subtitles && Array.isArray(data.subtitles)) {
    data.subtitles.forEach(sub => {
      const subElem = document.createElement('div');
      subElem.className = 'doc-subtitle';
      subElem.textContent = sub;
      metaPanel.appendChild(subElem);
    });
  }

  if (data.reference) {
    const refElem = document.createElement('div');
    refElem.className = 'doc-reference';
    refElem.textContent = data.reference;
    metaPanel.appendChild(refElem);
  }

  if (data.status) {
    const statusElem = document.createElement('span');
    statusElem.className = `status-badge status-${data.status.tone || 'neutral'}`;
    statusElem.textContent = data.status.text;
    metaPanel.appendChild(statusElem);
  }
  headerContainer.appendChild(metaPanel);
  main.appendChild(headerContainer);

  // --- BUILDING THE TRANSACTION INVOLVED PARTIES GRID ---
  if (data.recipient || (data.business && data.business.fields && data.business.fields.length > 0)) {
    const partiesGrid = document.createElement('div');
    partiesGrid.className = 'parties-grid';

    // Business Associated Registration fields
    const bizFieldsBlock = document.createElement('div');
    if (data.business && data.business.fields && data.business.fields.length > 0) {
      bizFieldsBlock.className = 'business-meta-fields';
      data.business.fields.forEach(f => {
        const row = document.createElement('div');
        row.style.fontSize = '0.9rem';
        row.innerHTML = `<strong style="color:#64748b">${f.label}:</strong> ${renderFieldContentHtml(f)}`;
        bizFieldsBlock.appendChild(row);
      });
    }
    partiesGrid.appendChild(bizFieldsBlock);

    // Recipient Entity Information Card
    const recipientBlock = document.createElement('div');
    if (data.recipient) {
      recipientBlock.className = 'recipient-card';
      const pTitle = document.createElement('div');
      pTitle.className = 'party-block-title';
      pTitle.textContent = 'Bill To / Recipient';
      recipientBlock.appendChild(pTitle);

      if (data.recipient.name) {
        const rName = document.createElement('div');
        rName.className = 'party-name';
        rName.textContent = data.recipient.code ? `[${data.recipient.code}] ${data.recipient.name}` : data.recipient.name;
        recipientBlock.appendChild(rName);
      }
      if (data.recipient.address) {
        const rAddr = document.createElement('div');
        rAddr.className = 'address-text';
        rAddr.textContent = data.recipient.address;
        recipientBlock.appendChild(rAddr);
      }
      if (data.recipient.email) {
        const rEmail = document.createElement('div');
        rEmail.style.fontSize = '0.9rem';
        rEmail.style.marginTop = '0.25rem';
        rEmail.innerHTML = `<span style="color:#64748b">Email:</span> ${data.recipient.email}`;
        recipientBlock.appendChild(rEmail);
      }
    }
    partiesGrid.appendChild(recipientBlock);
    main.appendChild(partiesGrid);
  }

  // --- BUILDING TOP LEVEL RELEVANT CUSTOM FIELDS ---
  if (data.fields && data.fields.length > 0) {
    const topFields = data.fields.filter(f => f.displayAtTheTop !== false);
    if (topFields.length > 0) {
      const fieldsPanel = document.createElement('div');
      fieldsPanel.className = 'fields-panel';

      topFields.forEach(f => {
        const card = document.createElement('div');
        card.className = 'field-card';

        const label = document.createElement('span');
        label.className = 'field-label';
        label.textContent = f.label;
        card.appendChild(label);

        const val = document.createElement('span');
        val.className = 'field-value';
        if (f.emphasis) val.classList.add('field-emphasized');
        val.innerHTML = renderFieldContentHtml(f);

        card.appendChild(val);
        fieldsPanel.appendChild(card);
      });
      main.appendChild(fieldsPanel);
    }
  }

  // --- BUILDING THE CORE STRUCTURAL REPORTING TABLE ---
  if (data.table) {
    const tableContainer = document.createElement('div');
    tableContainer.className = 'table-container';

    if (data.table.description) {
      const desc = document.createElement('div');
      desc.className = 'table-desc';
      desc.textContent = data.table.description;
      tableContainer.appendChild(desc);
    }

    const htmlTable = document.createElement('table');
    const flatColumns = [];
    const collectColumns = (cols) => {
      if (!cols) return;
      cols.forEach(c => {
        if (c.subcolumns && c.subcolumns.length > 0) {
          collectColumns(c.subcolumns);
        } else {
          flatColumns.push(c);
        }
      });
    };
    collectColumns(data.table.columns);

    // Render Table Header
    const thead = document.createElement('thead');
    const headerRow = document.createElement('tr');
    flatColumns.forEach(col => {
      const th = document.createElement('th');
      th.textContent = col.label;
      if (col.align) th.className = `align-${col.align}`;
      if (col.nowrap) th.classList.add('nowrap');
      if (col.shrinkToFit) th.classList.add('shrink-to-fit');
      headerRow.appendChild(th);
    });
    thead.appendChild(headerRow);
    htmlTable.appendChild(thead);

    // Render Table Body
    const tbody = document.createElement('tbody');
    
    function renderRowsRecursive(rowsArray) {
      if (!rowsArray) return;
      
      rowsArray.forEach(rowData => {
        const tr = document.createElement('tr');
        if (rowData.isTotalRow) tr.className = 'total-row';

        if (rowData.cells && rowData.cells.length > 0) {
          if (rowData.rows && rowData.rows.length > 0) {
            tr.className = 'group-header-row';
            const td = document.createElement('td');
            td.colSpan = flatColumns.length;
            td.innerHTML = renderCellContentHtml(rowData.cells[0]);
            tr.appendChild(td);
            tbody.appendChild(tr);
          } else {
            rowData.cells.forEach((cellData, index) => {
              const td = document.createElement('td');
              td.innerHTML = renderCellContentHtml(cellData);

              const colMeta = flatColumns[index];
              if (colMeta) {
                if (colMeta.align) td.className = `align-${colMeta.align}`;
                if (colMeta.nowrap) td.classList.add('nowrap');
                if (colMeta.emphasis) td.classList.add('emphasis');
                if (colMeta.shrinkToFit) td.classList.add('shrink-to-fit');
              }
              tr.appendChild(td);
            });
            tbody.appendChild(tr);
          }
        }

        if (rowData.rows && rowData.rows.length > 0) {
          renderRowsRecursive(rowData.rows);
        }
      });
    }

    renderRowsRecursive(data.table.rows);
    htmlTable.appendChild(tbody);
    tableContainer.appendChild(htmlTable);
    main.appendChild(tableContainer);
  }

  // --- BUILDING DOCUMENT TOTALS & FOOTERS ---
  if ((data.totals && data.totals.length > 0) || (data.footers && data.footers.length > 0)) {
    const bottomContainer = document.createElement('div');
    bottomContainer.className = 'totals-and-footers';

    if (data.totals && data.totals.length > 0) {
      const totalsBox = document.createElement('div');
      totalsBox.className = 'totals-box';

      data.totals.forEach(t => {
        const line = document.createElement('div');
        line.className = 'total-line';
        if (t.emphasis) line.classList.add('total-line-emphasis');

        const lbl = document.createElement('span');
        lbl.className = 'total-line-label';
        lbl.textContent = t.label;

        const val = document.createElement('span');
        val.className = 'total-line-value';
        val.textContent = t.text;

        line.appendChild(lbl);
        line.appendChild(val);
        totalsBox.appendChild(line);
      });
      bottomContainer.appendChild(totalsBox);
    }

    if (data.footers && data.footers.length > 0) {
      const footersBox = document.createElement('div');
      footersBox.className = 'footers-box';

      data.footers.forEach(fBlockHtml => {
        const block = document.createElement('div');
        block.className = 'footer-block';
        block.innerHTML = fBlockHtml;
        footersBox.appendChild(block);
      });
      bottomContainer.appendChild(footersBox);
    }

    main.appendChild(bottomContainer);
  }
}

function renderCellContentHtml(cell) {
  if (!cell) return '';
  let content = '';

  if (cell.image) {
    const imgWidth = cell.image.width ? `width="${cell.image.width}"` : '';
    const imgHeight = cell.image.height ? `height="${cell.image.height}"` : '';
    content += `<img src="${cell.image.url}" alt="${cell.text || ''}" ${imgWidth} ${imgHeight} class="cell-inline-img" />`;
  } else if (cell.text) {
    content += cell.text;
  }

  if (cell.link && cell.link.url) {
    return `<a href="${cell.link.url}" target="_top" class="cell-link">${content}</a>`;
  }
  return content;
}

function renderFieldContentHtml(field) {
  if (!field) return '';
  let content = '';

  if (field.image) {
    const imgWidth = field.image.width ? `width="${field.image.width}"` : '';
    const imgHeight = field.image.height ? `height="${field.image.height}"` : '';
    content += `<img src="${field.image.url}" ${imgWidth} ${imgHeight} style="max-height: 24px; object-fit: contain;" />`;
  } else if (field.text) {
    content += field.text;
  }

  if (field.fields && field.fields.length > 0) {
    const subText = field.fields.map(sf => `${sf.label ? sf.label + ': ' : ''}${renderFieldContentHtml(sf)}`).join(', ');
    content += (content ? ' — ' : '') + subText;
  }

  if (field.link && field.link.url) {
    return `<a href="${field.link.url}" target="_top" class="cell-link">${content}</a>`;
  }
  return content;
}
</script>
</body>
</html>