diff --git a/README.md b/README.md index 0f3b635..5795f02 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![Live App](https://img.shields.io/badge/Live-cspinsights.app-6366f1)](https://cspinsights.app) -**A free, local-first billing reconciliation and pricing management toolkit for Microsoft CSP Direct (Tier 1) partners.** +**A free, local-first billing reconciliation, pricing management, and incentives analytics toolkit for Microsoft CSP Direct (Tier 1) partners.** > Your data never leaves your browser. No backend, no account, no cloud uploads. @@ -13,7 +13,7 @@ ## Why CSP Insights? -Managing Microsoft CSP operations means wrestling with massive reconciliation CSVs and complex price lists every month. CSP Insights gives you immediate visual clarity and powerful tools — without backend servers or third-party data processing. +Managing Microsoft CSP operations means wrestling with massive reconciliation CSVs, complex price lists, and incentive earnings reports every month. CSP Insights gives you immediate visual clarity and powerful tools — without backend servers or third-party data processing. ## Features @@ -37,6 +37,21 @@ Managing Microsoft CSP operations means wrestling with massive reconciliation CS - **Version comparison** — load two price lists and spot price changes - **Shopping cart & quotes** — build a cart and export professional PDF quotes +### Incentives & Earnings +- **Earnings Report** — import the Partner Center Incentives → Earnings → Export (Default) CSV + - Dashboard with total earnings, customer count, product count, and program breakdown + - Earnings over time (monthly bar chart) + - Top customers and top products by earning amount + - Drill-down: click a customer or product to open a detail view with per-lever and per-product charts + - Full records table with search filter and sortable columns +- **Payments Report** — import the Partner Center Incentives → Payments CSV + - Summary cards: total earned, total paid, total tax withheld, and payment count + - Payments by month chart (grouped earned vs. paid) + - Payment method breakdown with color-coded horizontal bar + - Sortable payments table with status, date, and amounts +- **Multi-file upload** — append multiple CSV exports to build a combined dataset +- **Session persistence** — earnings and payment data survive page refreshes via IndexedDB + ### Data Management - **Snapshots** — save and restore billing data and pricing catalogs - **Backup & restore** — export/import all your data @@ -50,6 +65,17 @@ Managing Microsoft CSP operations means wrestling with massive reconciliation CS - **No telemetry** — no analytics, no tracking, no data collection - Clearing your browser data removes everything +## Data Sources + +| Report | Where to export in Partner Center | +|--------|----------------------------------| +| Billing reconciliation | Billing → Reconciliation → Download CSV | +| CSP price list | Pricing → License-based / Usage-based → Download | +| Incentives Earnings | Incentives → Earnings → Export → Default | +| Incentives Payments | Incentives → Payments → Export | + +All files are processed entirely in your browser. Nothing is uploaded anywhere. + ## Getting Started ### Use the hosted version diff --git a/package.json b/package.json index 2a6729d..638e884 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "csp-insights", - "version": "1.0.0", - "description": "A local-first billing reconciliation and pricing management toolkit for Microsoft CSP Direct partners", + "version": "1.2.0", + "description": "A local-first billing reconciliation, pricing management, and incentives analytics toolkit for Microsoft CSP Direct partners", "homepage": "https://cspinsights.app", "license": "MIT", "type": "module", diff --git a/src/App.tsx b/src/App.tsx index fb04d54..be4787c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,11 +6,14 @@ import { HistoryModal } from './components/HistoryModal'; import { parseBillingCSVs } from './utils/csvParser'; import { useBillingStore } from './store/billingStore'; import { useSettingsStore } from './store/settingsStore'; +import { useEarningsStore } from './store/earningsStore'; import { AzureAnalyzer } from './components/AzureAnalyzer'; import { NceAnalyzer } from './components/NceAnalyzer'; +import { RenewalCalendar } from './components/RenewalCalendar'; import { PricingView } from './components/PricingView'; import { HomeDashboard } from './components/HomeDashboard'; -import { Loader2, Settings, History, Sun, Moon, Search, LayoutGrid, BarChart3, Cloud, ShieldCheck, ExternalLink } from 'lucide-react'; +import { EarningsView } from './components/EarningsView'; +import { Loader2, Settings, History, Sun, Moon, Search, LayoutGrid, BarChart3, Cloud, ShieldCheck, ExternalLink, TrendingUp, CalendarDays } from 'lucide-react'; import { generateDemoData } from './utils/demoData'; import './App.css'; @@ -29,9 +32,10 @@ function App() { } = useBillingStore(); const { loadSettings, theme, setTheme, companyDetails } = useSettingsStore(); + const { loadFromDisk: loadEarningsFromDisk } = useEarningsStore(); // Navigation State - const [currentView, setCurrentView] = useState<'home' | 'dashboard' | 'settings' | 'azure' | 'nce' | 'pricing'>('home'); + const [currentView, setCurrentView] = useState<'home' | 'dashboard' | 'settings' | 'azure' | 'nce' | 'renewals' | 'pricing' | 'incentives'>('home'); const [showHistory, setShowHistory] = useState(false); const [isUploading, setIsUploading] = useState(false); // New state to control upload view overlay @@ -39,6 +43,7 @@ function App() { useEffect(() => { loadFromDisk(); loadSettings(); + loadEarningsFromDisk(); }, []); const handleFileSelect = async (files: File[]) => { @@ -111,7 +116,7 @@ function App() { {/* Search Section */} -
+
- {(currentView === 'dashboard' || currentView === 'azure' || currentView === 'nce' || currentView === 'pricing') && ( + {(currentView === 'dashboard' || currentView === 'azure' || currentView === 'nce' || currentView === 'renewals' || currentView === 'pricing' || currentView === 'incentives') && ( +
+ +
+ )} + + {(currentView === 'dashboard' || currentView === 'azure' || currentView === 'nce' || currentView === 'renewals') && ( <> {showDashboard && (
@@ -232,6 +261,17 @@ function App() { > NCE Insights +
)} @@ -277,6 +317,7 @@ function App() { {currentView === 'dashboard' && } {currentView === 'azure' && } {currentView === 'nce' && } + {currentView === 'renewals' && } )} @@ -284,7 +325,7 @@ function App() {