+
+
Total Completed
+
{summary.totalAllocations}
-
- {summary.totalAllocations}
+
+
Total Amount
+
+ ₹{parseFloat(summary.totalAmount).toLocaleString()}
+
+
+
+
Total Units
+
+ {parseFloat(summary.totalUnits).toLocaleString()}
+
-
-
- Total Amount
-
-
- ₹{parseFloat(summary.totalAmount).toLocaleString()}
-
-
-
-
- Total Units
-
-
- {parseFloat(summary.totalUnits).toLocaleString()}
-
+ )}
+
+ {/* Search */}
+
+
+
+ setSearchQuery(e.target.value)}
+ className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
+ />
+
+
+ Refresh
+
- )}
- {/* Search and Refresh */}
-
-
-
- setSearchQuery(e.target.value)}
- className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-transparent"
- />
-
-
-
- Refresh
-
-
+ {error && (
+
Error: {error}
+ )}
- {/* Error */}
- {error && (
-
- Error: {error}
-
- )}
-
- {/* Table */}
- {loading
- ?
Loading report data...
- : filteredAllocations.length > 0
- ? (
+ {/* Table */}
+ {loading ? (
+
Loading report data...
+ ) : filteredAllocations.length > 0 ? (
@@ -412,71 +474,111 @@ export const ReportingPage: React.FC = () => {
Activity
Assigned
Completed
- Rate (₹)
+ Actual Rate (₹)
+ Standard Rate (₹)
+ Difference (₹)
Units
Total (₹)
{filteredAllocations.map((allocation) => {
const rate = parseFloat(allocation.rate) || 0;
+ const standardRate = parseFloat(allocation.standard_rate) || 0;
+ const difference = rate - standardRate;
const units = parseFloat(allocation.units) || 0;
const total = parseFloat(allocation.total_amount) || rate;
return (
{allocation.id}
-
- {allocation.employee_name || "-"}
-
+ {allocation.employee_name || "-"}
+ {allocation.contractor_name || "-"}
+ {allocation.department_name || "-"}
+ {allocation.sub_department_name || "-"}
- {allocation.contractor_name || "-"}
-
-
- {allocation.department_name || "-"}
-
-
- {allocation.sub_department_name || "-"}
-
-
-
+
{allocation.activity || "Standard"}
+ {new Date(allocation.assigned_date).toLocaleDateString()}
- {new Date(allocation.assigned_date)
- .toLocaleDateString()}
-
-
- {allocation.completion_date
- ? new Date(allocation.completion_date)
- .toLocaleDateString()
- : "-"}
+ {allocation.completion_date ? new Date(allocation.completion_date).toLocaleDateString() : "-"}
₹{rate.toFixed(2)}
- {units > 0 ? units : "-"}
-
- ₹{total.toFixed(2)}
+ {standardRate > 0 ? `₹${standardRate.toFixed(2)}` : "-"}
+
+ {standardRate > 0 ? (
+ 0 ? "text-red-600" : difference < 0 ? "text-green-600" : "text-gray-600"
+ }`}>
+ {difference > 0 ? "+" : ""}₹{difference.toFixed(2)}
+
+ ) : "-"}
+ {units > 0 ? units : "-"}
+ ₹{total.toFixed(2)}
);
})}
- )
- : (
+ ) : (
- No completed work allocations found. Adjust your filters or
- check back later.
+ No completed work allocations found for the selected criteria.
)}
+
+
+
+ );
+ }
+
+ // Wizard view
+ return (
+
+
+
+
+
+
Generate Work Allocation Report
+
+
+
+
+
+
+
+ {renderWizardContent()}
+
+ {/* Navigation */}
+
+
setWizardStep((prev) => Math.max(1, prev - 1) as WizardStep)}
+ disabled={wizardStep === 1}
+ >
+
+ Back
+
+
+ {wizardStep < 4 ? (
+
setWizardStep((prev) => (prev + 1) as WizardStep)} disabled={!canProceed()}>
+ Next
+
+
+ ) : (
+
+ {loading ? "Generating..." : "Generate Report"}
+
+
+ )}
+
+
diff --git a/src/utils/excelExport.ts b/src/utils/excelExport.ts
index 6548291..a3440c3 100644
--- a/src/utils/excelExport.ts
+++ b/src/utils/excelExport.ts
@@ -324,3 +324,150 @@ export const exportAllocationsToXLSX = (
// Write and download
XLSX.writeFile(wb, outputFilename);
};
+
+/**
+ * Combined export function with improved formatting
+ * Includes standard rate and difference columns
+ */
+export const exportReportToXLSX = (
+ allocations: AllocationData[],
+ departmentName: string,
+ dateRange: { startDate: string; endDate: string },
+) => {
+ if (allocations.length === 0) {
+ alert("No data to export");
+ return;
+ }
+
+ // Create workbook
+ const wb = XLSX.utils.book_new();
+
+ // ===== Sheet 1: Detailed Report =====
+ const detailedData = allocations.map((a, index) => {
+ const rate = parseFloat(String(a.rate)) || 0;
+ const standardRate = parseFloat(String((a as any).standard_rate)) || 0;
+ const difference = standardRate > 0 ? rate - standardRate : 0;
+ const units = parseFloat(String(a.units)) || 0;
+ const total = parseFloat(String(a.total_amount)) || rate;
+
+ return {
+ "S.No": index + 1,
+ "Employee": a.employee_name || "",
+ "Contractor": a.contractor_name || "",
+ "Department": a.department_name || "",
+ "Sub-Department": a.sub_department_name || "",
+ "Activity": a.activity || "Standard",
+ "Assigned Date": a.assigned_date
+ ? new Date(a.assigned_date).toLocaleDateString()
+ : "",
+ "Completed Date": a.completion_date
+ ? new Date(a.completion_date).toLocaleDateString()
+ : "",
+ "Actual Rate (₹)": rate,
+ "Standard Rate (₹)": standardRate > 0 ? standardRate : "-",
+ "Difference (₹)": standardRate > 0 ? difference : "-",
+ "Units": units > 0 ? units : "-",
+ "Total Amount (₹)": total,
+ };
+ });
+
+ const ws1 = XLSX.utils.json_to_sheet(detailedData);
+
+ // Set column widths for detailed sheet
+ ws1["!cols"] = [
+ { wch: 6 }, // S.No
+ { wch: 22 }, // Employee
+ { wch: 20 }, // Contractor
+ { wch: 15 }, // Department
+ { wch: 18 }, // Sub-Department
+ { wch: 15 }, // Activity
+ { wch: 12 }, // Assigned Date
+ { wch: 14 }, // Completed Date
+ { wch: 14 }, // Actual Rate
+ { wch: 16 }, // Standard Rate
+ { wch: 14 }, // Difference
+ { wch: 8 }, // Units
+ { wch: 16 }, // Total Amount
+ ];
+
+ XLSX.utils.book_append_sheet(wb, ws1, "Detailed Report");
+
+ // ===== Sheet 2: Summary by Activity =====
+ const activitySummary = new Map
();
+
+ allocations.forEach((a) => {
+ const activity = a.activity || "Standard";
+ const existing = activitySummary.get(activity) || { count: 0, totalAmount: 0, totalUnits: 0 };
+ existing.count += 1;
+ existing.totalAmount += parseFloat(String(a.total_amount)) || parseFloat(String(a.rate)) || 0;
+ existing.totalUnits += parseFloat(String(a.units)) || 0;
+ activitySummary.set(activity, existing);
+ });
+
+ const summaryData = Array.from(activitySummary.entries()).map(([activity, data]) => ({
+ "Activity": activity,
+ "Total Completed": data.count,
+ "Total Units": data.totalUnits,
+ "Total Amount (₹)": data.totalAmount.toFixed(2),
+ }));
+
+ // Add grand total row
+ const grandTotal = {
+ "Activity": "GRAND TOTAL",
+ "Total Completed": allocations.length,
+ "Total Units": allocations.reduce((sum, a) => sum + (parseFloat(String(a.units)) || 0), 0),
+ "Total Amount (₹)": allocations.reduce((sum, a) =>
+ sum + (parseFloat(String(a.total_amount)) || parseFloat(String(a.rate)) || 0), 0
+ ).toFixed(2),
+ };
+ summaryData.push(grandTotal);
+
+ const ws2 = XLSX.utils.json_to_sheet(summaryData);
+ ws2["!cols"] = [
+ { wch: 25 }, // Activity
+ { wch: 16 }, // Total Completed
+ { wch: 12 }, // Total Units
+ { wch: 18 }, // Total Amount
+ ];
+
+ XLSX.utils.book_append_sheet(wb, ws2, "Summary by Activity");
+
+ // ===== Sheet 3: Summary by Contractor =====
+ const contractorSummary = new Map }>();
+
+ allocations.forEach((a) => {
+ const contractor = a.contractor_name || "Unknown";
+ const existing = contractorSummary.get(contractor) || { count: 0, totalAmount: 0, employees: new Set() };
+ existing.count += 1;
+ existing.totalAmount += parseFloat(String(a.total_amount)) || parseFloat(String(a.rate)) || 0;
+ if (a.employee_name) existing.employees.add(a.employee_name);
+ contractorSummary.set(contractor, existing);
+ });
+
+ const contractorData = Array.from(contractorSummary.entries()).map(([contractor, data]) => ({
+ "Contractor": contractor,
+ "Employees": data.employees.size,
+ "Total Completed": data.count,
+ "Total Amount (₹)": data.totalAmount.toFixed(2),
+ }));
+
+ const ws3 = XLSX.utils.json_to_sheet(contractorData);
+ ws3["!cols"] = [
+ { wch: 25 }, // Contractor
+ { wch: 12 }, // Employees
+ { wch: 16 }, // Total Completed
+ { wch: 18 }, // Total Amount
+ ];
+
+ XLSX.utils.book_append_sheet(wb, ws3, "Summary by Contractor");
+
+ // Generate filename
+ const dateStr = dateRange.startDate && dateRange.endDate
+ ? `${dateRange.startDate}_to_${dateRange.endDate}`
+ : new Date().toISOString().split("T")[0];
+ const deptStr = departmentName.toLowerCase().replace(/\s+/g, "_");
+ const filename = `work_report_${deptStr}_${dateStr}.xlsx`;
+
+ // Write and download
+ XLSX.writeFile(wb, filename);
+};