- Get link
- X
- Other Apps
```html
<!DOCTYPE html>
<html lang="en" class="h-full bg-slate-50">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Audit Assessment & Control Simulator</title>
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Alpine.js for lightweight reactivity -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<!-- FontAwesome Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Chart.js for visuals -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
brand: {
50: '#eff6ff',
100: '#dbeafe',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
}
}
}
}
}
</script>
<style>
[x-cloak] { display: none !important; }
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #f1f5f9;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #cbd5e1;
border-radius: 4px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #94a3b8;
}
</style>
</head>
<body class="h-full text-slate-800 font-sans antialiased" x-data="auditSimulator()" x-init="initApp()">
<div class="min-h-full flex flex-col">
<!-- Top Navigation -->
<header class="bg-slate-900 text-white shadow-md sticky top-0 z-50">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex items-center justify-between h-16">
<div class="flex items-center space-x-3">
<div class="p-2 bg-brand-600 rounded-lg">
<i class="fa-solid fa-file-signature text-xl text-white"></i>
</div>
<div>
<h1 class="text-lg font-bold leading-none">AuditAssure <span class="text-xs font-normal px-2 py-0.5 bg-brand-800 text-brand-200 rounded-full ml-1">Pro Simulator</span></h1>
<p class="text-xs text-slate-400">Core Management Assertions & Control Assessment Engine</p>
</div>
</div>
<!-- Navigation Links / Tabs -->
<nav class="flex space-x-2">
<button @click="activeTab = 'assessment'"
:class="activeTab === 'assessment' ? 'bg-brand-600 text-white' : 'text-slate-300 hover:bg-slate-800 hover:text-white'"
class="px-3 py-2 rounded-md text-sm font-medium transition flex items-center space-x-2">
<i class="fa-solid fa-sliders text-xs"></i>
<span>Control Testing Studio</span>
</button>
<button @click="activeTab = 'matrix'"
:class="activeTab === 'matrix' ? 'bg-brand-600 text-white' : 'text-slate-300 hover:bg-slate-800 hover:text-white'"
class="px-3 py-2 rounded-md text-sm font-medium transition flex items-center space-x-2">
<i class="fa-solid fa-table-cells text-xs"></i>
<span>Assertion Matrix</span>
</button>
<button @click="activeTab = 'workingpaper'"
:class="activeTab === 'workingpaper' ? 'bg-brand-600 text-white' : 'text-slate-300 hover:bg-slate-800 hover:text-white'"
class="px-3 py-2 rounded-md text-sm font-medium transition flex items-center space-x-2">
<i class="fa-solid fa-file-invoice text-xs"></i>
<span>Audit Working Paper</span>
</button>
</nav>
<div class="hidden md:flex items-center space-x-4">
<span class="text-xs bg-slate-800 text-slate-300 px-3 py-1.5 rounded-full border border-slate-700">
Target AR: <strong class="text-emerald-400">5.0% (Low)</strong>
</span>
<button @click="resetData()" class="text-xs text-slate-400 hover:text-white flex items-center space-x-1 transition">
<i class="fa-solid fa-rotate-left"></i>
<span>Reset</span>
</button>
</div>
</div>
</div>
</header>
<!-- Main Content Area -->
<main class="flex-1 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-6">
<!-- Global Cycle Switcher Banner -->
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-4 mb-6 flex flex-wrap items-center justify-between gap-4">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 rounded-lg bg-slate-100 border border-slate-200 flex items-center justify-center text-slate-700">
<i :class="getCycleIcon(selectedCycleKey)" class="text-lg"></i>
</div>
<div>
<label class="block text-xs font-bold uppercase tracking-wider text-slate-400">Select Business Cycle</label>
<select x-model="selectedCycleKey" @change="onCycleChange()" class="text-base font-bold text-slate-900 bg-transparent border-none p-0 focus:ring-0 cursor-pointer">
<template x-for="(cycle, key) in cycles" :key="key">
<option :value="key" x-text="cycle.name"></option>
</template>
</select>
</div>
</div>
<!-- Live Audit Risk Model Summary Card -->
<div class="flex items-center space-x-6 bg-slate-50 border border-slate-200 px-4 py-2.5 rounded-lg">
<div class="text-center">
<div class="text-xs text-slate-500 font-semibold">Inherent Risk (IR)</div>
<div class="text-sm font-bold" :class="getRiskTextColor(currentCycleStats.avgIR)" x-text="currentCycleStats.avgIR"></div>
</div>
<div class="text-slate-300 font-bold">×</div>
<div class="text-center">
<div class="text-xs text-slate-500 font-semibold">Control Risk (CR)</div>
<div class="text-sm font-bold" :class="getRiskTextColor(currentCycleStats.avgCR)" x-text="currentCycleStats.avgCR"></div>
</div>
<div class="text-slate-300 font-bold">=</div>
<div class="text-center">
<div class="text-xs text-slate-500 font-semibold">RMM (IR × CR)</div>
<div class="text-sm font-bold" :class="getRiskTextColor(currentCycleStats.rmmLevel)" x-text="currentCycleStats.rmmLevel"></div>
</div>
<div class="h-8 w-px bg-slate-300"></div>
<div class="text-center">
<div class="text-xs text-slate-500 font-semibold">Detection Risk (DR)</div>
<div class="text-sm font-bold text-brand-600" x-text="currentCycleStats.reqDR + '% (' + currentCycleStats.drLevel + ')'"></div>
</div>
<div class="text-center">
<div class="text-xs text-slate-500 font-semibold">Substantive Scope</div>
<span class="text-xs px-2 py-0.5 rounded font-bold" :class="getSubstantiveBadgeClass(currentCycleStats.substantiveScope)" x-text="currentCycleStats.substantiveScope"></span>
</div>
</div>
</div>
<!-- TAB 1: CONTROL TESTING STUDIO -->
<div x-show="activeTab === 'assessment'" class="space-y-6" x-cloak>
<div class="grid grid-cols-1 lg:grid-cols-12 gap-6">
<!-- Left Column: Controls List -->
<div class="lg:col-span-5 space-y-4">
<div class="flex items-center justify-between">
<h2 class="text-base font-bold text-slate-900 flex items-center space-x-2">
<span>Cycle Controls</span>
<span class="bg-slate-200 text-slate-700 text-xs px-2 py-0.5 rounded-full" x-text="currentCycleControls.length"></span>
</h2>
<span class="text-xs text-slate-500">Select control to assess</span>
</div>
<div class="space-y-3 custom-scrollbar max-h-[700px] overflow-y-auto pr-1">
<template x-for="(ctrl, idx) in currentCycleControls" :key="ctrl.id">
<div @click="selectedControlId = ctrl.id"
:class="selectedControlId === ctrl.id ? 'border-brand-600 bg-brand-50/40 shadow-sm' : 'border-slate-200 bg-white hover:border-slate-300'"
class="p-4 rounded-xl border transition cursor-pointer relative group">
<div class="flex items-start justify-between gap-2 mb-1.5">
<span class="font-mono text-xs font-bold text-brand-700 bg-brand-100 px-2 py-0.5 rounded" x-text="ctrl.code"></span>
<span class="text-xs font-semibold px-2 py-0.5 rounded-full"
:class="getAssertionBadgeClass(ctrl.assertion)" x-text="ctrl.assertion"></span>
</div>
<h3 class="text-sm font-bold text-slate-900 mb-1" x-text="ctrl.name"></h3>
<p class="text-xs text-slate-600 line-clamp-2 mb-3" x-text="ctrl.description"></p>
<!-- Status Chips -->
<div class="flex items-center justify-between text-xs pt-2 border-t border-slate-100">
<div class="flex items-center space-x-3">
<div>
<span class="text-slate-400">D&I:</span>
<span class="font-bold" :class="ctrl.dniStatus === 'Effective' ? 'text-emerald-600' : 'text-amber-600'" x-text="ctrl.dniStatus"></span>
</div>
<div>
<span class="text-slate-400">OE Exception:</span>
<span class="font-bold" :class="ctrl.exceptionRate > 5 ? 'text-rose-600' : 'text-slate-700'" x-text="ctrl.exceptionRate + '%'"></span>
</div>
</div>
<span class="text-xs font-bold px-2 py-0.5 rounded" :class="getControlRiskBadgeClass(ctrl.controlRiskAssessed)" x-text="'CR: ' + ctrl.controlRiskAssessed"></span>
</div>
</div>
</template>
</div>
</div>
<!-- Right Column: Control Assessment Workbench -->
<div class="lg:col-span-7">
<template x-if="activeControl">
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6 space-y-6">
<!-- Workbench Header -->
<div class="border-b border-slate-200 pb-4 flex flex-wrap items-start justify-between gap-4">
<div>
<div class="flex items-center space-x-2 mb-1">
<span class="font-mono text-xs font-bold bg-slate-900 text-white px-2 py-0.5 rounded" x-text="activeControl.code"></span>
<span class="text-xs font-semibold px-2 py-0.5 rounded-full" :class="getAssertionBadgeClass(activeControl.assertion)" x-text="'Asserts: ' + activeControl.assertion"></span>
<span class="text-xs text-slate-500" x-text="'Frequency: ' + activeControl.frequency"></span>
</div>
<h2 class="text-lg font-bold text-slate-900" x-text="activeControl.name"></h2>
<p class="text-xs text-slate-600 mt-1" x-text="activeControl.description"></p>
</div>
<div class="text-right">
<div class="text-xs text-slate-400 font-semibold">Assessed CR Level</div>
<div class="text-lg font-black" :class="getRiskTextColor(activeControl.controlRiskAssessed)" x-text="activeControl.controlRiskAssessed"></div>
</div>
</div>
<!-- STEP 1: Design & Implementation (D&I) -->
<div class="space-y-3 bg-slate-50 p-4 rounded-xl border border-slate-200">
<div class="flex items-center justify-between">
<h3 class="text-xs font-bold uppercase tracking-wider text-slate-700 flex items-center space-x-2">
<span class="w-5 h-5 rounded-full bg-slate-900 text-white flex items-center justify-center text-xs">1</span>
<span>Design & Implementation (D&I) Assessment</span>
</h3>
<span class="text-xs text-slate-500">Walkthrough Procedure</span>
</div>
<p class="text-xs text-slate-600" x-text="'Auditor Walkthrough: ' + activeControl.walkthroughProcedure"></p>
<div class="grid grid-cols-2 gap-4 pt-2">
<div>
<label class="block text-xs font-bold text-slate-700 mb-1">Control Design</label>
<select x-model="activeControl.designEffectiveness" @change="recalculateControl()" class="w-full text-xs rounded-lg border-slate-300 focus:ring-brand-500 focus:border-brand-500">
<option value="Suitable">Suitable Design</option>
<option value="Deficient">Design Deficiency</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-700 mb-1">Implementation Status</label>
<select x-model="activeControl.implementationStatus" @change="recalculateControl()" class="w-full text-xs rounded-lg border-slate-300 focus:ring-brand-500 focus:border-brand-500">
<option value="Implemented">Implemented</option>
<option value="Not Implemented">Not Implemented</option>
</select>
</div>
</div>
</div>
<!-- STEP 2: Operating Effectiveness (OE) Sample Testing -->
<div class="space-y-3 bg-slate-50 p-4 rounded-xl border border-slate-200">
<div class="flex items-center justify-between">
<h3 class="text-xs font-bold uppercase tracking-wider text-slate-700 flex items-center space-x-2">
<span class="w-5 h-5 rounded-full bg-slate-900 text-white flex items-center justify-center text-xs">2</span>
<span>Operating Effectiveness (OE) Sample Testing</span>
</h3>
<span class="text-xs text-slate-500">Substantive Test of Controls</span>
</div>
<div class="grid grid-cols-3 gap-3 bg-white p-3 rounded-lg border border-slate-200 text-center">
<div>
<label class="block text-xs text-slate-400 font-semibold mb-1">Sample Size</label>
<input type="number" min="1" max="100" x-model.number="activeControl.sampleTested" @input="recalculateControl()" class="w-full text-center text-sm font-bold border-slate-300 rounded focus:ring-brand-500">
</div>
<div>
<label class="block text-xs text-slate-400 font-semibold mb-1">Exceptions Found</label>
<input type="number" min="0" :max="activeControl.sampleTested" x-model.number="activeControl.exceptionsFound" @input="recalculateControl()" class="w-full text-center text-sm font-bold border-slate-300 rounded focus:ring-brand-500 text-rose-600">
</div>
<div>
<label class="block text-xs text-slate-400 font-semibold mb-1">Exception Rate</label>
<div class="text-sm font-extrabold mt-2" :class="activeControl.exceptionRate > 5 ? 'text-rose-600' : 'text-emerald-600'" x-text="activeControl.exceptionRate + '%'"></div>
</div>
</div>
<!-- Sample Testing Log Table -->
<div class="pt-2">
<div class="flex items-center justify-between mb-2">
<span class="text-xs font-bold text-slate-700">Sample Item Details</span>
<button @click="addSampleLog()" class="text-xs bg-brand-50 text-brand-700 hover:bg-brand-100 font-bold px-2.5 py-1 rounded transition">
<i class="fa-solid fa-plus mr-1"></i> Add Sample
</button>
</div>
<div class="overflow-x-auto rounded-lg border border-slate-200 bg-white">
<table class="w-full text-left text-xs">
<thead class="bg-slate-100 text-slate-600 font-bold border-b border-slate-200">
<tr>
<th class="p-2">Sample ID</th>
<th class="p-2">Doc Ref</th>
<th class="p-2">Assertion Tested</th>
<th class="p-2">Result</th>
<th class="p-2 text-right">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
<template x-for="(sample, sIdx) in activeControl.sampleLogs" :key="sIdx">
<tr class="hover:bg-slate-50">
<td class="p-2 font-mono" x-text="sample.id"></td>
<td class="p-2">
<input type="text" x-model="sample.ref" class="text-xs p-1 border rounded w-24">
</td>
<td class="p-2">
<span class="text-xs font-semibold px-2 py-0.5 rounded" :class="getAssertionBadgeClass(activeControl.assertion)" x-text="activeControl.assertion"></span>
</td>
<td class="p-2">
<select x-model="sample.status" @change="syncSampleStatus()" class="text-xs p-1 border rounded">
<option value="Pass">Pass</option>
<option value="Exception">Exception</option>
</select>
</td>
<td class="p-2 text-right">
<button @click="removeSampleLog(sIdx)" class="text-slate-400 hover:text-rose-600">
<i class="fa-solid fa-trash-can"></i>
</button>
</td>
</tr>
</template>
<template x-if="activeControl.sampleLogs.length === 0">
<tr>
<td colspan="5" class="p-3 text-center text-slate-400 italic">No individual sample logs added. Defaults based on sample counters above.</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
</div>
<!-- STEP 3: Risk Assessment & Substantive Impact -->
<div class="space-y-3 bg-slate-50 p-4 rounded-xl border border-slate-200">
<h3 class="text-xs font-bold uppercase tracking-wider text-slate-700 flex items-center space-x-2">
<span class="w-5 h-5 rounded-full bg-slate-900 text-white flex items-center justify-center text-xs">3</span>
<span>Risk of Material Misstatement (RMM) & Audit Impact</span>
</h3>
<div class="grid grid-cols-2 gap-4">
<div>
<label class="block text-xs font-bold text-slate-700 mb-1">Inherent Risk (IR) for Assertion</label>
<select x-model="activeControl.inherentRisk" @change="recalculateControl()" class="w-full text-xs rounded-lg border-slate-300 focus:ring-brand-500 focus:border-brand-500">
<option value="High">High (High Complexity / Fraud Risk)</option>
<option value="Medium">Medium (Moderate Volume)</option>
<option value="Low">Low (Routine / Automated)</option>
</select>
</div>
<div>
<label class="block text-xs font-bold text-slate-700 mb-1">Assessed Control Risk (CR)</label>
<input type="text" readonly :value="activeControl.controlRiskAssessed" class="w-full text-xs font-bold rounded-lg border-slate-200 bg-slate-100 text-slate-700">
</div>
</div>
<div class="p-3 rounded-lg border bg-white flex items-center justify-between"
:class="activeControl.controlRiskAssessed === 'High' ? 'border-rose-200 bg-rose-50/50' : 'border-emerald-200 bg-emerald-50/50'">
<div>
<div class="text-xs font-bold text-slate-800" x-text="'Required Substantive Audit Strategy for ' + activeControl.assertion"></div>
<div class="text-xs text-slate-600 mt-0.5" x-text="getSubstantiveRecommendation(activeControl)"></div>
</div>
<i :class="activeControl.controlRiskAssessed === 'High' ? 'fa-triangle-exclamation text-rose-500' : 'fa-circle-check text-emerald-500'" class="text-xl"></i>
</div>
</div>
<!-- Auditor Working Paper Notes -->
<div>
<label class="block text-xs font-bold text-slate-700 mb-1">Auditor Conclusion Notes</label>
<textarea x-model="activeControl.notes" rows="2" placeholder="Record qualitative considerations, management inquiry response, or audit conclusion..." class="w-full text-xs border-slate-300 rounded-lg focus:ring-brand-500 focus:border-brand-500"></textarea>
</div>
</div>
</template>
</div>
</div>
</div>
<!-- TAB 2: ASSERTION MATRIX & HEATMAP -->
<div x-show="activeTab === 'matrix'" class="space-y-6" x-cloak>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-6">
<div class="flex items-center justify-between mb-4">
<div>
<h2 class="text-lg font-bold text-slate-900">Core Management Assertion Audit Matrix</h2>
<p class="text-xs text-slate-500">Cross-mapping of cycle assertions, control effectiveness, and evaluated residual risk levels.</p>
</div>
<div class="flex items-center space-x-2 text-xs">
<span class="flex items-center"><span class="w-3 h-3 rounded-full bg-emerald-500 mr-1"></span> Low Risk</span>
<span class="flex items-center"><span class="w-3 h-3 rounded-full bg-amber-500 mr-1"></span> Moderate Risk</span>
<span class="flex items-center"><span class="w-3 h-3 rounded-full bg-rose-500 mr-1"></span> High Risk</span>
</div>
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse text-xs">
<thead>
<tr class="bg-slate-100 text-slate-700 font-bold border-b border-slate-200">
<th class="p-3 border-r border-slate-200">Assertion Category</th>
<th class="p-3 border-r border-slate-200">Management Assertion</th>
<th class="p-3 border-r border-slate-200">Mapped Controls</th>
<th class="p-3 border-r border-slate-200 text-center">Avg Design Effectiveness</th>
<th class="p-3 border-r border-slate-200 text-center">Avg Exception Rate</th>
<th class="p-3 border-r border-slate-200 text-center">Assessed CR</th>
<th class="p-3 text-center">Substantive Focus</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
<template x-for="row in matrixRows" :key="row.assertion">
<tr class="hover:bg-slate-50 transition">
<td class="p-3 font-semibold text-slate-500 border-r border-slate-200" x-text="row.category"></td>
<td class="p-3 font-bold border-r border-slate-200">
<span class="px-2 py-1 rounded text-xs" :class="getAssertionBadgeClass(row.assertion)" x-text="row.assertion"></span>
</td>
<td class="p-3 border-r border-slate-200 font-mono text-slate-600" x-text="row.controlCodes.join(', ') || 'No mapped control'"></td>
<td class="p-3 border-r border-slate-200 text-center">
<span :class="row.designPass ? 'text-emerald-600 font-bold' : 'text-rose-600 font-bold'" x-text="row.designPass ? 'Effective' : 'Deficient'"></span>
</td>
<td class="p-3 border-r border-slate-200 text-center font-bold" :class="row.avgException > 5 ? 'text-rose-600' : 'text-slate-700'" x-text="row.avgException + '%'"></td>
<td class="p-3 border-r border-slate-200 text-center">
<span class="px-2.5 py-1 rounded font-bold text-xs" :class="getControlRiskBadgeClass(row.assessedCR)" x-text="row.assessedCR"></span>
</td>
<td class="p-3 text-center">
<span class="px-2 py-0.5 rounded text-xs font-bold" :class="getSubstantiveBadgeClass(row.substantiveScope)" x-text="row.substantiveScope"></span>
</td>
</tr>
</template>
</tbody>
</table>
</div>
</div>
<!-- Visualization Row -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-5">
<h3 class="text-sm font-bold text-slate-900 mb-4">Control Exception Rates by Assertion</h3>
<div class="h-64">
<canvas id="assertionChart"></canvas>
</div>
</div>
<div class="bg-white rounded-xl shadow-sm border border-slate-200 p-5">
<h3 class="text-sm font-bold text-slate-900 mb-4">Audit Risk Breakdown (IR vs CR)</h3>
<div class="h-64">
<canvas id="riskChart"></canvas>
</div>
</div>
</div>
</div>
<!-- TAB 3: AUDIT WORKING PAPER REPORT -->
<div x-show="activeTab === 'workingpaper'" class="space-y-6" x-cloak>
<div class="flex justify-end space-x-3 print:hidden">
<button onclick="window.print()" class="px-4 py-2 bg-slate-900 text-white font-bold rounded-lg text-xs hover:bg-slate-800 transition flex items-center space-x-2">
<i class="fa-solid fa-print"></i>
<span>Print Working Paper (Ref: WP-2026-A)</span>
</button>
</div>
<!-- Printable Working Paper Document -->
<div class="bg-white rounded-xl shadow-sm border border-slate-300 p-8 text-slate-900 space-y-6 print:shadow-none print:border-none print:p-0">
<!-- Paper Header -->
<div class="border-b-2 border-slate-900 pb-4 flex justify-between items-start">
<div>
<div class="text-xs uppercase tracking-widest text-slate-500 font-bold">INDEPENDENT AUDIT WORKING PAPER</div>
<h1 class="text-2xl font-black text-slate-900" x-text="cycles[selectedCycleKey].name + ' - Control Assessment Summary'"></h1>
<p class="text-xs text-slate-600 mt-1">Audit Period: FY 2026 | ISA 315 & ISA 330 Compliance Evaluation</p>
</div>
<div class="text-right font-mono text-xs">
<div><strong>WP REF:</strong> WP-C-2026</div>
<div><strong>DATE:</strong> October 15, 2026</div>
<div><strong>PREPARED BY:</strong> Lead Auditor</div>
</div>
</div>
<!-- Executive Audit Summary -->
<div class="grid grid-cols-4 gap-4 bg-slate-50 p-4 rounded-lg border border-slate-200 text-xs">
<div>
<span class="text-slate-500">Total Controls Tested:</span>
<div class="text-base font-bold" x-text="currentCycleControls.length"></div>
</div>
<div>
<span class="text-slate-500">Overall Cycle RMM:</span>
<div class="text-base font-bold" :class="getRiskTextColor(currentCycleStats.rmmLevel)" x-text="currentCycleStats.rmmLevel"></div>
</div>
<div>
<span class="text-slate-500">Target Detection Risk:</span>
<div class="text-base font-bold text-brand-700" x-text="currentCycleStats.reqDR + '% (' + currentCycleStats.drLevel + ')'"></div>
</div>
<div>
<span class="text-slate-500">Audit Strategy:</span>
<div class="text-base font-bold text-slate-900" x-text="currentCycleStats.substantiveScope + ' Testing'"></div>
</div>
</div>
<!-- Detailed Assessment Findings Table -->
<div>
<h3 class="text-sm font-bold text-slate-900 mb-2 border-b border-slate-200 pb-1">Detailed Assertion Control Assessment Log</h3>
<table class="w-full text-left text-xs border-collapse">
<thead>
<tr class="bg-slate-100 border-b border-slate-300 font-bold">
<th class="p-2">Ref</th>
<th class="p-2">Assertion</th>
<th class="p-2">Control Name</th>
<th class="p-2 text-center">D&I Status</th>
<th class="p-2 text-center">Sample / Exception</th>
<th class="p-2 text-center">Control Risk</th>
<th class="p-2">Auditor Conclusion & Impact</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
<template x-for="ctrl in currentCycleControls" :key="ctrl.id">
<tr>
<td class="p-2 font-mono font-bold" x-text="ctrl.code"></td>
<td class="p-2">
<span class="px-1.5 py-0.5 rounded text-[10px] font-bold" :class="getAssertionBadgeClass(ctrl.assertion)" x-text="ctrl.assertion"></span>
</td>
<td class="p-2 font-medium" x-text="ctrl.name"></td>
<td class="p-2 text-center font-semibold" :class="ctrl.dniStatus === 'Effective' ? 'text-emerald-700' : 'text-amber-700'" x-text="ctrl.dniStatus"></td>
<td class="p-2 text-center font-mono" x-text="ctrl.sampleTested + ' / ' + ctrl.exceptionsFound + ' (' + ctrl.exceptionRate + '%)'"></td>
<td class="p-2 text-center font-bold" :class="getRiskTextColor(ctrl.controlRiskAssessed)" x-text="ctrl.controlRiskAssessed"></td>
<td class="p-2 text-slate-600" x-text="ctrl.notes || getSubstantiveRecommendation(ctrl)"></td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- Audit Sign-off Section -->
<div class="pt-8 border-t border-slate-300 grid grid-cols-2 gap-8 text-xs">
<div>
<div class="font-bold mb-6">Prepared By (Senior Auditor):</div>
<div class="border-b border-slate-400 w-48 mb-1"></div>
<div class="text-slate-500">Date: Oct 15, 2026</div>
</div>
<div>
<div class="font-bold mb-6">Reviewed & Approved By (Audit Manager):</div>
<div class="border-b border-slate-400 w-48 mb-1"></div>
<div class="text-slate-500">Date: Oct 15, 2026</div>
</div>
</div>
</div>
</div>
</main>
</div>
<!-- Application Script -->
<script>
function auditSimulator() {
return {
activeTab: 'assessment',
selectedCycleKey: 'revenue',
selectedControlId: 'REV-01',
// Chart instances
assertionChart: null,
riskChart: null,
// Comprehensive Cycle & Assertion Dataset
cycles: {
revenue: {
name: 'Revenue & Accounts Receivable',
controls: [
{
id: 'REV-01',
code: 'C-REV-01',
name: 'Automated Three-Way Matching',
assertion: 'Occurrence',
frequency: 'Automated / Continuous',
description: 'System automatically matches sales order, shipping advice (BOL), and billing invoice prior to posting sales revenue.',
walkthroughProcedure: 'Selected 5 sales entries and verified automated system matching locks.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 25,
exceptionsFound: 0,
inherentRisk: 'High',
sampleLogs: [
{ id: 'S-01', ref: 'INV-8801', status: 'Pass' },
{ id: 'S-02', ref: 'INV-8802', status: 'Pass' },
{ id: 'S-03', ref: 'INV-8803', status: 'Pass' }
],
notes: 'Automated controls operating effectively without overrides.'
},
{
id: 'REV-02',
code: 'C-REV-02',
name: 'Sequential Shipping Log Reconciliations',
assertion: 'Completeness',
frequency: 'Weekly',
description: 'Independent review of unbilled dispatch notes to guarantee all shipped goods are invoiced within the period.',
walkthroughProcedure: 'Inspected weekly reconciliation files signed off by accounting lead.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 20,
exceptionsFound: 2,
inherentRisk: 'Medium',
sampleLogs: [
{ id: 'S-01', ref: 'DN-4011', status: 'Pass' },
{ id: 'S-02', ref: 'DN-4012', status: 'Exception' }
],
notes: 'Minor backlog noted during peak quarter.'
},
{
id: 'REV-03',
code: 'C-REV-03',
name: 'Approved Price Master File Locks',
assertion: 'Accuracy',
frequency: 'Monthly',
description: 'System restricts price list modifications to authorized sales VP and logs all price changes.',
walkthroughProcedure: 'Verified user access permissions list for master price configuration.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 15,
exceptionsFound: 0,
inherentRisk: 'Medium',
sampleLogs: [],
notes: 'Access rights restricted properly.'
},
{
id: 'REV-04',
code: 'C-REV-04',
name: 'Period-End Shipping Cut-off Review',
assertion: 'Cut-off',
frequency: 'Period-End',
description: 'Finance performs cut-off testing on dispatches 5 days before and after financial year-end.',
walkthroughProcedure: 'Reperformed cut-off log review on Dec 31 shipments.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 10,
exceptionsFound: 1,
inherentRisk: 'High',
sampleLogs: [],
notes: 'One shipment on Dec 31 billed in Jan.'
},
{
id: 'REV-05',
code: 'C-REV-05',
name: 'ECL Allowance Valuation Review',
assertion: 'Valuation & Allocation',
frequency: 'Quarterly',
description: 'Management reviews aging receivables and calculates Expected Credit Loss (ECL) under IFRS 9.',
walkthroughProcedure: 'Evaluated historical loss rate assumptions in ECL model.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 5,
exceptionsFound: 0,
inherentRisk: 'High',
sampleLogs: [],
notes: 'Provision matrix adequately adjusted for forward-looking indicators.'
}
]
},
procurement: {
name: 'Procurement & Accounts Payable',
controls: [
{
id: 'AP-01',
code: 'C-AP-01',
name: 'PO Authorization & Receiving Match',
assertion: 'Occurrence',
frequency: 'Daily',
description: 'All vendor invoices require matched Purchase Order and Goods Received Note (GRN) prior to voucher approval.',
walkthroughProcedure: 'Vouched sample voucher packages against PO signatures.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 30,
exceptionsFound: 1,
inherentRisk: 'Medium',
sampleLogs: [],
notes: 'Control operating as intended.'
},
{
id: 'AP-02',
code: 'C-AP-02',
name: 'Unrecorded Liabilities Search Log',
assertion: 'Completeness',
frequency: 'Period-End',
description: 'Accounting examines subsequent cash disbursements to detect unrecorded payables.',
walkthroughProcedure: 'Inspected post-period disbursement review file.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 15,
exceptionsFound: 0,
inherentRisk: 'High',
sampleLogs: [],
notes: 'No unrecorded accruals detected.'
},
{
id: 'AP-03',
code: 'C-AP-03',
name: 'Vendor Balance Confirmations',
assertion: 'Existence',
frequency: 'Annual',
description: 'Direct external balance confirmation with key suppliers at year-end.',
walkthroughProcedure: 'Reviewed supplier statement reconciliations.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 12,
exceptionsFound: 0,
inherentRisk: 'Medium',
sampleLogs: [],
notes: 'Reconciling items verified.'
}
]
},
payroll: {
name: 'Payroll & Employee Expenses',
controls: [
{
id: 'PAY-01',
code: 'C-PAY-01',
name: 'HR Master Data Modification Approval',
assertion: 'Occurrence',
frequency: 'Event-driven',
description: 'Dual authorization required to create or alter employee bank detail records.',
walkthroughProcedure: 'Tested HR audit trail logs for new hires.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 10,
exceptionsFound: 0,
inherentRisk: 'High',
sampleLogs: [],
notes: 'Dual approval verified.'
},
{
id: 'PAY-02',
code: 'C-PAY-02',
name: 'Timecard Supervisor Approval',
assertion: 'Accuracy',
frequency: 'Bi-Weekly',
description: 'Department supervisors approve employee clock-in hours before payroll processing.',
walkthroughProcedure: 'Sampled timesheets for supervisory sign-off.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 25,
exceptionsFound: 3,
inherentRisk: 'Medium',
sampleLogs: [],
notes: 'Supervisory sign-off missing on 3 timesheets.'
}
]
},
assets: {
name: 'Fixed Assets & Inventory',
controls: [
{
id: 'FA-01',
code: 'C-FA-01',
name: 'Physical Asset Tagging & Verification',
assertion: 'Existence',
frequency: 'Annual',
description: 'Physical floor-to-sheet and sheet-to-floor count of fixed assets.',
walkthroughProcedure: 'Observed physical count procedures at main plant.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 20,
exceptionsFound: 0,
inherentRisk: 'Medium',
sampleLogs: [],
notes: 'Assets exist and tags matched register.'
},
{
id: 'FA-02',
code: 'C-FA-02',
name: 'Inventory Obsolescence NRV Test',
assertion: 'Valuation & Allocation',
frequency: 'Quarterly',
description: 'Review slow-moving inventory items for write-down to Net Realizable Value.',
walkthroughProcedure: 'Re-performed inventory valuation calculations.',
designEffectiveness: 'Suitable',
implementationStatus: 'Implemented',
sampleTested: 10,
exceptionsFound: 2,
inherentRisk: 'High',
sampleLogs: [],
notes: 'Obsolete stock write-down understated.'
}
]
}
},
// Computed getters
get currentCycleControls() {
return this.cycles[this.selectedCycleKey].controls;
},
get activeControl() {
return this.currentCycleControls.find(c => c.id === this.selectedControlId) || this.currentCycleControls[0];
},
get currentCycleStats() {
const ctrls = this.currentCycleControls;
if (!ctrls || ctrls.length === 0) return {};
let highCRCount = ctrls.filter(c => c.controlRiskAssessed === 'High').length;
let medCRCount = ctrls.filter(c => c.controlRiskAssessed === 'Medium').length;
let avgCR = highCRCount > 0 ? 'High' : (medCRCount > 0 ? 'Medium' : 'Low');
// Inherent risk average
let highIRCount = ctrls.filter(c => c.inherentRisk === 'High').length;
let avgIR = highIRCount > 0 ? 'High' : 'Medium';
// RMM assessment
let rmmLevel = (avgIR === 'High' || avgCR === 'High') ? 'High' : (avgCR === 'Medium' ? 'Medium' : 'Low');
// Required Detection Risk Calculation (Target AR = 5%)
let reqDR = 5;
let drLevel = 'Low';
let substantiveScope = 'Extensive Substantive';
if (rmmLevel === 'High') {
reqDR = 5; // Must be very low
drLevel = 'Low (Tight)';
substantiveScope = 'High / Detailed Testing';
} else if (rmmLevel === 'Medium') {
reqDR = 15;
drLevel = 'Medium';
substantiveScope = 'Moderate Substantive';
} else {
reqDR = 40;
drLevel = 'High (Flexible)';
substantiveScope = 'Limited / Analytical Procedures';
}
return { avgIR, avgCR, rmmLevel, reqDR, drLevel, substantiveScope };
},
get matrixRows() {
return this.currentCycleControls.map(c => ({
category: this.getAssertionCategory(c.assertion),
assertion: c.assertion,
controlCodes: [c.code],
designPass: c.designEffectiveness === 'Suitable' && c.implementationStatus === 'Implemented',
avgException: c.exceptionRate,
assessedCR: c.controlRiskAssessed,
substantiveScope: this.getSubstantiveScopeForCR(c.controlRiskAssessed)
}));
},
// Logic methods
initApp() {
this.recalculateAllControls();
this.$watch('activeTab', (val) => {
if (val === 'matrix') {
this.$nextTick(() => this.renderCharts());
}
});
},
onCycleChange() {
if (this.currentCycleControls.length > 0) {
this.selectedControlId = this.currentCycleControls[0].id;
}
this.recalculateAllControls();
if (this.activeTab === 'matrix') {
this.$nextTick(() => this.renderCharts());
}
},
recalculateControl() {
const c = this.activeControl;
if (!c) return;
// Compute exception rate
if (c.sampleTested > 0) {
c.exceptionRate = Math.round((c.exceptionsFound / c.sampleTested) * 100);
} else {
c.exceptionRate = 0;
}
// Compute D&I
if (c.designEffectiveness === 'Suitable' && c.implementationStatus === 'Implemented') {
c.dniStatus = 'Effective';
} else {
c.dniStatus = 'Deficient';
}
// Assess Control Risk
if (c.dniStatus === 'Deficient') {
c.controlRiskAssessed = 'High';
} else if (c.exceptionRate > 5) {
c.controlRiskAssessed = 'High';
} else if (c.exceptionRate > 0) {
c.controlRiskAssessed = 'Medium';
} else {
c.controlRiskAssessed = 'Low';
}
if (this.activeTab === 'matrix') {
this.renderCharts();
}
},
recalculateAllControls() {
this.currentCycleControls.forEach(c => {
c.exceptionRate = c.sampleTested > 0 ? Math.round((c.exceptionsFound / c.sampleTested) * 100) : 0;
c.dniStatus = (c.designEffectiveness === 'Suitable' && c.implementationStatus === 'Implemented') ? 'Effective' : 'Deficient';
if (c.dniStatus === 'Deficient' || c.exceptionRate > 5) {
c.controlRiskAssessed = 'High';
} else if (c.exceptionRate > 0) {
c.controlRiskAssessed = 'Medium';
} else {
c.controlRiskAssessed = 'Low';
}
});
},
addSampleLog() {
const c = this.activeControl;
const newId = 'S-' + String(c.sampleLogs.length + 1).padStart(2, '0');
c.sampleLogs.push({
id: newId,
ref: 'DOC-' + Math.floor(1000 + Math.random() * 9000),
status: 'Pass'
});
c.sampleTested = c.sampleLogs.length;
this.syncSampleStatus();
},
removeSampleLog(idx) {
const c = this.activeControl;
c.sampleLogs.splice(idx, 1);
c.sampleTested = Math.max(1, c.sampleLogs.length);
this.syncSampleStatus();
},
syncSampleStatus() {
const c = this.activeControl;
const exceptions = c.sampleLogs.filter(s => s.status === 'Exception').length;
c.exceptionsFound = exceptions;
this.recalculateControl();
},
resetData() {
location.reload();
},
// Helper styling & text formatters
getCycleIcon(key) {
const icons = {
revenue: 'fa-solid fa-file-invoice-dollar',
procurement: 'fa-solid fa-cart-flatbed',
payroll: 'fa-solid fa-users-gear',
assets: 'fa-solid fa-boxes-stacked'
};
return icons[key] || 'fa-solid fa-folder';
},
getAssertionBadgeClass(assertion) {
const map = {
'Occurrence': 'bg-blue-100 text-blue-800 border border-blue-200',
'Completeness': 'bg-emerald-100 text-emerald-800 border border-emerald-200',
'Accuracy': 'bg-purple-100 text-purple-800 border border-purple-200',
'Cut-off': 'bg-amber-100 text-amber-800 border border-amber-200',
'Classification': 'bg-indigo-100 text-indigo-800 border border-indigo-200',
'Existence': 'bg-teal-100 text-teal-800 border border-teal-200',
'Rights & Obligations': 'bg-slate-100 text-slate-800 border border-slate-200',
'Valuation & Allocation': 'bg-rose-100 text-rose-800 border border-rose-200'
};
return map[assertion] || 'bg-slate-100 text-slate-700';
},
getAssertionCategory(assertion) {
if (['Occurrence', 'Completeness', 'Accuracy', 'Cut-off', 'Classification'].includes(assertion)) {
return 'Transactions & Events';
}
if (['Existence', 'Rights & Obligations', 'Completeness', 'Valuation & Allocation'].includes(assertion)) {
return 'Account Balances';
}
return 'Presentation & Disclosure';
},
getControlRiskBadgeClass(level) {
if (level === 'High') return 'bg-rose-100 text-rose-800 border border-rose-200';
if (level === 'Medium') return 'bg-amber-100 text-amber-800 border border-amber-200';
return 'bg-emerald-100 text-emerald-800 border border-emerald-200';
},
getRiskTextColor(level) {
if (level === 'High') return 'text-rose-600';
if (level === 'Medium') return 'text-amber-600';
return 'text-emerald-600';
},
getSubstantiveBadgeClass(scope) {
if (scope.includes('High') || scope.includes('Extensive')) return 'bg-rose-100 text-rose-800';
if (scope.includes('Moderate')) return 'bg-amber-100 text-amber-800';
return 'bg-emerald-100 text-emerald-800';
},
getSubstantiveScopeForCR(cr) {
if (cr === 'High') return 'Extensive Substantive Details';
if (cr === 'Medium') return 'Moderate Substantive Sample';
return 'Limited / Analytical Review';
},
getSubstantiveRecommendation(ctrl) {
if (ctrl.controlRiskAssessed === 'High') {
return `Control is ineffective or has high exceptions (${ctrl.exceptionRate}%). Auditor cannot rely on control. Perform 100% substantive detail testing or enlarged sample size for ${ctrl.assertion}.`;
}
if (ctrl.controlRiskAssessed === 'Medium') {
return `Control operates with minor exceptions. Perform moderate substantive testing to corroborate ${ctrl.assertion}.`;
}
return `Control evaluated as operating effectively. Reduce substantive detail testing for ${ctrl.assertion} and rely on dual-purpose analytical procedures.`;
},
// Chart Rendering
renderCharts() {
const ctrls = this.currentCycleControls;
const labels = ctrls.map(c => c.assertion);
const exceptionData = ctrls.map(c => c.exceptionRate);
// Exception Rate Chart
const ctx1 = document.getElementById('assertionChart');
if (ctx1) {
if (this.assertionChart) this.assertionChart.destroy();
this.assertionChart = new Chart(ctx1, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Control Exception Rate (%)',
data: exceptionData,
backgroundColor: exceptionData.map(v => v > 5 ? '#ef4444' : '#3b82f6'),
borderRadius: 6
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, max: 100, title: { display: true, text: 'Exception %' } }
}
}
});
}
// Risk Radar Chart
const ctx2 = document.getElementById('riskChart');
if (ctx2) {
if (this.riskChart) this.riskChart.destroy();
const riskScore = (val) => val === 'High' ? 3 : (val === 'Medium' ? 2 : 1);
this.riskChart = new Chart(ctx2, {
type: 'radar',
data: {
labels: labels,
datasets: [
{
label: 'Inherent Risk Level',
data: ctrls.map(c => riskScore(c.inherentRisk)),
borderColor: '#f59e0b',
backgroundColor: 'rgba(245, 158, 11, 0.2)'
},
{
label: 'Assessed Control Risk',
data: ctrls.map(c => riskScore(c.controlRiskAssessed)),
borderColor: '#ef4444',
backgroundColor: 'rgba(239, 68, 68, 0.2)'
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
r: {
min: 0,
max: 3,
ticks: { stepSize: 1, callback: (v) => ['','Low','Med','High'][v] }
}
}
}
});
}
}
}
}
</script>
</body>
</html>
```
Comments