add-new-case-history-tab #1
258
coretabs.user.js
258
coretabs.user.js
@@ -48,11 +48,14 @@
|
||||
let allMyCases = [],
|
||||
allCaseDocuments = [],
|
||||
allCaseUsers = [],
|
||||
refundReviewData = [];
|
||||
let filteredRefundData = [];
|
||||
let selectedCaseId = null;
|
||||
let loadedDocsForCaseId = null;
|
||||
let loadedUsersForCaseId = null;
|
||||
caseHistoryData = [],
|
||||
caseSubProcessData = {},
|
||||
refundReviewData = [],
|
||||
filteredRefundData = [],
|
||||
selectedCaseId = null,
|
||||
loadedDocsForCaseId = null,
|
||||
loadedUsersForCaseId = null,
|
||||
loadedHistoryForCaseId = null;
|
||||
|
||||
function addStyles() {
|
||||
GM_addStyle(`
|
||||
@@ -109,12 +112,20 @@
|
||||
<button class="ct-tab-button active" data-tab="tab-my-cases">My Cases</button>
|
||||
<button class="ct-tab-button" data-tab="tab-docs">Case Documents</button>
|
||||
<button class="ct-tab-button" data-tab="tab-users">Case Users</button>
|
||||
<button class="ct-tab-button" data-tab="tab-history">Case History</button>
|
||||
<button class="ct-tab-button" data-tab="tab-refund">Refund Review</button>
|
||||
</div>
|
||||
<div id="ct-tab-content-area">
|
||||
<div id="tab-my-cases" class="ct-tab-panel active"><div class="filter-container"><div><label for="cases-status-filter">Filter by Status:</label><select id="cases-status-filter"></select></div><button id="toggle-cases-btn" class="action-btn" style="margin-left:auto">Collapse All</button></div><div class="results-container"><p style="padding:15px;color:#666;">Loading my cases...</p></div></div>
|
||||
<div id="tab-docs" class="ct-tab-panel"><div class="filter-container"><div><label for="docs-status-filter">Filter by Status:</label><select id="docs-status-filter"></select></div><button id="toggle-docs-btn" class="action-btn" style="margin-left:auto">Collapse All</button></div><div class="results-container"><p style="padding:15px;color:#666;">Please select a case to view its documents.</p></div></div>
|
||||
<div id="tab-users" class="ct-tab-panel"><div class="filter-container"><div><label for="users-role-filter">Filter by Role:</label><select id="users-role-filter"></select></div></div><div class="results-container"><p style="padding:15px;color:#666;">Please select a case to view its users.</p></div></div>
|
||||
<div id="tab-history" class="ct-tab-panel">
|
||||
<div class="filter-container">
|
||||
<div><label for="history-type-filter">Filter by Case Type:</label><select id="history-type-filter"></select></div>
|
||||
<button id="toggle-history-btn" class="action-btn" style="margin-left:auto">Collapse All</button>
|
||||
</div>
|
||||
<div class="results-container"><p style="padding:15px;color:#666;">Please select a case to view its history.</p></div>
|
||||
</div>
|
||||
<div id="tab-refund" class="ct-tab-panel">
|
||||
<div class="filter-container">
|
||||
<div><label for="refund-reported-filter">Filter by Reported:</label><select id="refund-reported-filter"></select></div>
|
||||
@@ -298,6 +309,118 @@
|
||||
(responseArea.innerHTML = ""),
|
||||
responseArea.appendChild(table));
|
||||
}
|
||||
function renderCaseHistoryTable() {
|
||||
const responseArea = document.querySelector(
|
||||
"#tab-history .results-container",
|
||||
);
|
||||
if (!caseHistoryData || caseHistoryData.length === 0) {
|
||||
responseArea.innerHTML =
|
||||
'<p style="padding:15px;color:#666;">No history data available for this case.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const filterValue = document.getElementById("history-type-filter").value;
|
||||
const filteredHistory = caseHistoryData.filter(
|
||||
(item) => filterValue === "all" || item.CaseType === filterValue,
|
||||
);
|
||||
|
||||
if (filteredHistory.length === 0) {
|
||||
responseArea.innerHTML =
|
||||
'<p style="padding:15px;color:#666;">No history items match the selected filter.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
const table = createTable([
|
||||
"Routing Date",
|
||||
"Performed By",
|
||||
"Workflow Step",
|
||||
]),
|
||||
tbody = document.createElement("tbody");
|
||||
|
||||
// Group items by CaseType
|
||||
const groupedHistory = {};
|
||||
filteredHistory.forEach((item) => {
|
||||
const caseType = item.CaseType || "Unknown";
|
||||
if (!groupedHistory[caseType]) {
|
||||
groupedHistory[caseType] = [];
|
||||
}
|
||||
groupedHistory[caseType].push(item);
|
||||
});
|
||||
|
||||
// Create table rows with grouping
|
||||
Object.keys(groupedHistory).forEach((caseType) => {
|
||||
const groupItems = groupedHistory[caseType];
|
||||
|
||||
// Create group header row
|
||||
const sanitizedCaseType = caseType.replace(/[^a-zA-Z0-9]/g, "_");
|
||||
tbody.innerHTML += `<tr class="group-header expanded" data-group-id="history-group-${sanitizedCaseType}"><td colspan="3"><span class="toggle-icon"></span>${caseType} (${groupItems.length} items)</td></tr>`;
|
||||
|
||||
// Add current role type at the top of each group
|
||||
// Find the most recent item (with latest RoutingDate)
|
||||
const mostRecentItem = groupItems.reduce((latest, current) => {
|
||||
const latestDate = new Date(latest.RoutingDate);
|
||||
const currentDate = new Date(current.RoutingDate);
|
||||
return currentDate > latestDate ? current : latest;
|
||||
});
|
||||
const currentCaseRoleTypeCode = mostRecentItem.ToWorkflowStepIdentifier
|
||||
? caseSubProcessData[mostRecentItem.ToWorkflowStepIdentifier]
|
||||
: null;
|
||||
|
||||
// Always add the current role row, even if CaseRoleTypeCode is not available
|
||||
const currentRoleRow = document.createElement("tr");
|
||||
currentRoleRow.className = `group-member history-group-${sanitizedCaseType}`;
|
||||
|
||||
// Empty Routing Date
|
||||
const emptyDateCell = document.createElement("td");
|
||||
emptyDateCell.textContent = "";
|
||||
currentRoleRow.appendChild(emptyDateCell);
|
||||
|
||||
// CaseRoleTypeCode in Performed By column
|
||||
const roleCell = document.createElement("td");
|
||||
if (currentCaseRoleTypeCode) {
|
||||
roleCell.innerHTML = `<strong>Current Role:</strong><br><small style="color: #666;">${currentCaseRoleTypeCode}</small>`;
|
||||
} else {
|
||||
roleCell.innerHTML = `<strong>Current Role:</strong><br><small style="color: #666; font-style: italic;">Not available</small>`;
|
||||
}
|
||||
currentRoleRow.appendChild(roleCell);
|
||||
|
||||
// Last To Step in Workflow Step column
|
||||
const workflowStepCell = document.createElement("td");
|
||||
workflowStepCell.textContent = mostRecentItem.ToWorkflowStep || "-";
|
||||
currentRoleRow.appendChild(workflowStepCell);
|
||||
|
||||
tbody.appendChild(currentRoleRow);
|
||||
|
||||
// Create member rows for this group
|
||||
groupItems.forEach((item) => {
|
||||
const row = document.createElement("tr");
|
||||
row.className = `group-member history-group-${sanitizedCaseType}`;
|
||||
|
||||
// Format RoutingDate
|
||||
const routingDate = new Date(item.RoutingDate);
|
||||
const dateCell = document.createElement("td");
|
||||
dateCell.textContent = routingDate.toLocaleString("id-ID");
|
||||
row.appendChild(dateCell);
|
||||
|
||||
// PerformedByUser
|
||||
const performedByCell = document.createElement("td");
|
||||
performedByCell.textContent = item.PerformedByUser || "-";
|
||||
row.appendChild(performedByCell);
|
||||
|
||||
// FromWorkflowStep (renamed to Workflow Step)
|
||||
const workflowStepCell = document.createElement("td");
|
||||
workflowStepCell.textContent = item.FromWorkflowStep || "-";
|
||||
row.appendChild(workflowStepCell);
|
||||
|
||||
tbody.appendChild(row);
|
||||
});
|
||||
});
|
||||
|
||||
responseArea.innerHTML = "";
|
||||
table.appendChild(tbody);
|
||||
responseArea.appendChild(table);
|
||||
tbody.addEventListener("click", handleGroupToggle);
|
||||
}
|
||||
function renderRefundReviewTable() {
|
||||
const responseArea = document.querySelector(
|
||||
"#tab-refund .results-container",
|
||||
@@ -481,6 +604,91 @@
|
||||
handleError(error, responseArea);
|
||||
}
|
||||
}
|
||||
async function fetchCaseHistory(caseId) {
|
||||
const responseArea = document.querySelector(
|
||||
"#tab-history .results-container",
|
||||
);
|
||||
responseArea.innerHTML =
|
||||
'<p style="padding:15px;color:#666;">Loading history...</p>';
|
||||
try {
|
||||
if (!caseId) throw new Error("No Case ID provided.");
|
||||
const apiUrl =
|
||||
"https://coretax.intranet.pajak.go.id/casemanagement/api/caseroutinghistory/list",
|
||||
payload = {
|
||||
AggregateIdentifier: caseId,
|
||||
First: 0,
|
||||
Rows: 1000,
|
||||
SortField: "RoutingDate",
|
||||
SortOrder: -1,
|
||||
Filters: [],
|
||||
LanguageId: "id-ID",
|
||||
},
|
||||
fetchOptions = {
|
||||
method: "POST",
|
||||
headers: getHeaders(caseId),
|
||||
body: JSON.stringify(payload),
|
||||
},
|
||||
response = await fetch(apiUrl, fetchOptions);
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
`API Error: ${errorData.Message || response.statusText}`,
|
||||
);
|
||||
}
|
||||
const data = await response.json();
|
||||
caseHistoryData = data?.Payload?.Data || [];
|
||||
loadedHistoryForCaseId = caseId;
|
||||
|
||||
// Fetch CaseRoleTypeCode for each ToWorkflowStepIdentifier
|
||||
await fetchCaseSubProcessData(caseId);
|
||||
|
||||
populateFilter("history-type-filter", caseHistoryData, "CaseType");
|
||||
renderCaseHistoryTable();
|
||||
} catch (error) {
|
||||
handleError(error, responseArea);
|
||||
}
|
||||
}
|
||||
async function fetchCaseSubProcessData(caseId) {
|
||||
try {
|
||||
const apiUrl =
|
||||
"https://coretax.intranet.pajak.go.id/casemanagement/api/casesubprocess/list",
|
||||
payload = {
|
||||
First: 0,
|
||||
Rows: 10000,
|
||||
Filters: [],
|
||||
AggregateIdentifier: caseId,
|
||||
},
|
||||
fetchOptions = {
|
||||
method: "POST",
|
||||
headers: getHeaders(caseId),
|
||||
body: JSON.stringify(payload),
|
||||
},
|
||||
response = await fetch(apiUrl, fetchOptions);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
`Case SubProcess API Error: ${errorData.Message || response.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const subProcessData = data?.Payload?.Data || [];
|
||||
|
||||
// Create a lookup map for WorkflowStepIdentifier to CaseRoleTypeCode
|
||||
caseSubProcessData = {};
|
||||
subProcessData.forEach((item) => {
|
||||
if (item.WorkflowStepIdentifier && item.CaseRoleTypeCode) {
|
||||
caseSubProcessData[item.WorkflowStepIdentifier] =
|
||||
item.CaseRoleTypeCode;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching case subprocess data:", error);
|
||||
caseSubProcessData = {};
|
||||
}
|
||||
}
|
||||
|
||||
async function downloadDocument(docId, filename, button) {
|
||||
const originalText = button.textContent;
|
||||
((button.textContent = "Downloading..."), (button.disabled = !0));
|
||||
@@ -673,11 +881,9 @@
|
||||
const table = document.createElement("table");
|
||||
table.className = "ct-results-table";
|
||||
const thead = document.createElement("thead");
|
||||
return (
|
||||
(thead.innerHTML = `<tr>${headers.map((e) => `<th>${e}</th>`).join("")}</tr>`),
|
||||
table.appendChild(thead),
|
||||
table
|
||||
);
|
||||
thead.innerHTML = `<tr>${headers.map((e) => `<th>${e}</th>`).join("")}</tr>`;
|
||||
table.appendChild(thead);
|
||||
return table;
|
||||
}
|
||||
function handleError(error, area) {
|
||||
console.error("Userscript Error:", error);
|
||||
@@ -823,7 +1029,7 @@
|
||||
headerRow.classList.toggle("expanded");
|
||||
const isCollapsed = headerRow.classList.contains("collapsed");
|
||||
const tableBody = headerRow.parentElement;
|
||||
const memberRows = tableBody.querySelectorAll(`.group-member.${groupId}`);
|
||||
const memberRows = tableBody.querySelectorAll(`tr.group-member.${groupId}`);
|
||||
memberRows.forEach((row) => {
|
||||
row.style.display = isCollapsed ? "none" : "table-row";
|
||||
});
|
||||
@@ -837,14 +1043,18 @@
|
||||
.forEach((e) => e.classList.remove("active")),
|
||||
document.querySelector(`[data-tab="${tabId}"]`).classList.add("active"),
|
||||
document.getElementById(tabId).classList.add("active"),
|
||||
"tab-docs" === tabId
|
||||
? selectedCaseId &&
|
||||
selectedCaseId !== loadedDocsForCaseId &&
|
||||
fetchCaseDocuments(selectedCaseId)
|
||||
: "tab-users" === tabId &&
|
||||
selectedCaseId &&
|
||||
selectedCaseId !== loadedUsersForCaseId &&
|
||||
fetchCaseUsers(selectedCaseId));
|
||||
"tab-docs" === tabId &&
|
||||
selectedCaseId &&
|
||||
selectedCaseId !== loadedDocsForCaseId &&
|
||||
fetchCaseDocuments(selectedCaseId),
|
||||
"tab-users" === tabId &&
|
||||
selectedCaseId &&
|
||||
selectedCaseId !== loadedUsersForCaseId &&
|
||||
fetchCaseUsers(selectedCaseId),
|
||||
"tab-history" === tabId &&
|
||||
selectedCaseId &&
|
||||
selectedCaseId !== loadedHistoryForCaseId &&
|
||||
fetchCaseHistory(selectedCaseId));
|
||||
}
|
||||
function downloadRefundExcel() {
|
||||
if (!filteredRefundData || filteredRefundData.length === 0) {
|
||||
@@ -992,6 +1202,10 @@
|
||||
if (usersFilterEl)
|
||||
usersFilterEl.addEventListener("change", renderCaseUsersTable);
|
||||
|
||||
const historyFilterEl = document.getElementById("history-type-filter");
|
||||
if (historyFilterEl)
|
||||
historyFilterEl.addEventListener("change", renderCaseHistoryTable);
|
||||
|
||||
const refundFilterEl = document.getElementById("refund-reported-filter");
|
||||
if (refundFilterEl)
|
||||
refundFilterEl.addEventListener("change", renderRefundReviewTable);
|
||||
@@ -1018,6 +1232,12 @@
|
||||
toggleAllGroups("#tab-refund .results-container", e.target),
|
||||
);
|
||||
|
||||
const toggleHistoryBtn = document.getElementById("toggle-history-btn");
|
||||
if (toggleHistoryBtn)
|
||||
toggleHistoryBtn.addEventListener("click", (e) =>
|
||||
toggleAllGroups("#tab-history .results-container", e.target),
|
||||
);
|
||||
|
||||
// initial load
|
||||
fetchMyCases();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user