Commit graph

34 commits

Author SHA1 Message Date
dlawler489
a789f01bb4 Fix duplicate ledger fees: explicit idempotency + auto-dedupe
The unique expense index can silently fail to build over pre-existing
duplicate data, so re-syncs were re-adding ledger fees every run.

- syncLedgerEntries now explicitly checks existing references (and
  de-dupes within the batch) instead of trusting the unique index
- dedupeLedgerExpenses keeps one row per etsy-ledger-<entry_id> and
  deletes the rest; runs automatically at the start of each sync so
  existing duplicates self-heal. Distinct entries sharing a date/amount
  are untouched (each has its own reference).
- Sync response/toast report deduped and already-imported counts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 17:23:01 +10:00
dlawler489
8e6680f2de Handle refunds: net revenue = order total - refunds
- Order model gains refundTotal; sync sums receipt.refunds (Money
  objects) onto each order and marks fully-refunded orders 'refunded'
- orderNetRevenue() helper (total - refundTotal); profit metrics,
  monthly trends, and per-order analysis now use net revenue so
  refunded sales no longer overstate profit
- ProfitMetrics adds totalRefunds; Analytics revenue card shows net
  revenue with the refunded amount, and monthly revenue is net

Note: product-level profitability stays gross since receipt refunds are
order-level amounts with no line-item breakdown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 17:07:48 +10:00
dlawler489
03979a9b48 Phase 2: sync Etsy payment ledger into expenses (exact fees)
- syncLedgerEntries pulls payment-account ledger entries (chunked by 90d
  over required min_created/max_created), classifies debits into fee
  categories, and inserts them as idempotent expenses (reference
  etsy-ledger-<entry_id>). Amounts are integer minor units -> /100.
- Conservative classifier: only genuine costs become expenses; sale
  credits, disbursements, and refunds are skipped. Unclassified debits
  are reported back so rules can be refined.
- Folded into POST /api/etsy/sync alongside orders; response includes
  ledger result and a legacyEtsyExpenses count (pre-ledger CSV fees).
- DELETE /api/etsy/legacy-fees removes CSV-imported Etsy fee expenses to
  avoid double counting; Settings surfaces the count with a one-click
  remove, plus a list of skipped/unknown ledger charge types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 15:16:15 +10:00
dlawler489
46d1ca3375 Fix size-aware product suggestions in resolver
Previously a different-size variant was boosted to 0.95 confidence
('same product, different size'), so a Small order would be confidently
suggested the Large product. Now suggestions require the same size; a
known different size is suppressed entirely (you create the right one
instead). Also handle 'Size: X for ...' phrasing, medium sizes, and
American 'Color:' spelling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 13:05:17 +10:00
dlawler489
3c3adcdea9 Let resolver process a subset; skip untouched rows
Previously submitting created a £0 product for every unmatched row the
user didn't touch, silently hiding it from the unmatched list. Now rows
with no chosen product and no printing cost are skipped and stay
unmatched, so items can be resolved a few at a time across syncs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 12:24:38 +10:00
dlawler489
acce14c000 Add Resolve Items flow for unmatched Etsy sync titles
Reuses the missing-products modal on the Settings page: each unmatched
listing title can be aliased to an existing product or created with a
printing cost, then orders re-sync automatically to fill in costs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 11:37:12 +10:00
dlawler489
4333b1c55d Add Etsy shared secret for API calls
Etsy returns 403 'Shared secret is required in x-api-key header' when the
keystring is used on resource endpoints: the keystring is only the OAuth
client id. Store the shared secret alongside it (Settings form + env
fallback) and send it as x-api-key on users/me and receipt requests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 11:12:50 +10:00
dlawler489
08160775e7 Surface Etsy OAuth errors and use form-encoded token requests
- Callback failures now redirect with the underlying error message, shown
  in the Settings toast, instead of a generic failure
- Token endpoint requests use application/x-www-form-urlencoded per
  RFC 6749 instead of JSON

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 11:09:09 +10:00
dlawler489
64aae6adf7 Add Settings link to the navigation bar
The /settings route existed but had no nav entry, leaving the Etsy
integration and data management UI unreachable by clicking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 08:14:49 +10:00
dlawler489
4759db4c5b Store Etsy API credentials in the database instead of env vars
- New EtsySettings model holds the per-user API keystring and callback URL,
  managed via GET/PUT /api/etsy/config; env vars remain as optional fallback
- Settings UI gains an API Configuration form (masked saved key, callback URL
  prefilled with this origin's /api/etsy/callback); Connect is enabled once
  configuration is saved
- OAuth and sync resolve the key per user; post-callback redirect derives
  from the stored callback URL origin instead of CLIENT_URL

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 08:02:05 +10:00
dlawler489
715562c96a Add Etsy API integration: OAuth connect and receipt-to-order sync
- OAuth 2.0 authorization code flow with PKCE; /api/etsy/connect returns the
  consent URL, /api/etsy/callback exchanges the code (validated via one-time
  state, no JWT) and stores tokens per user with automatic refresh
- /api/etsy/sync pulls all shop receipts and upserts orders by receipt id:
  items with SKU/variations, totals, shipping address, tracking, and status,
  with catalog costs snapshotted at sync time
- Product matching by exact title/alias first, then etsyListingId
  (size-disambiguated); listing ids are learned onto products on first match
- Packing-slip items with cost data are preserved when synced items can't all
  be matched
- Settings page: Connect Etsy Shop, Sync Orders Now, Disconnect, and a list
  of unmatched item titles after each sync
- Requires ETSY_API_KEY and ETSY_REDIRECT_URI env vars (see .env.example)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-13 07:54:41 +10:00
dlawler489
b27ede4131 Add alias matching, cost snapshots, reference-based fee allocation; remove debug tooling
- Products store packing-slip title aliases; matcher checks exact title/alias
  first so previously-matched items skip fuzzy matching entirely
- Packing-slip imports snapshot printingCost/costOfGoods/productId onto order
  items; profit analysis reads stored costs so catalog edits don't rewrite history
- Etsy statement fees allocate to orders via Order # references in Title/Info
  instead of date proximity; shop-level fees (listings, ads) no longer leak
  into order fees
- Remove broken transaction-fee exclusion guard (order totals are gross, so
  all expenses count once)
- Remove debug buttons, date-fix banner, test files, and console.log noise;
  Clear All Orders now uses a bulk DELETE /orders endpoint

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 18:39:59 +10:00
dlawler489
d325d547be enhance: improve revenue chart visualization and top products display
- Add value labels on revenue chart bars with smart formatting (1.2k for >)
- Implement proper bar scaling with 75% max height for better proportions
- Add enhanced hover tooltips with revenue and profit breakdown
- Fix top profitable products to show meaningful names instead of generic titles
- Improve product identification for orders with generic 'Product from Etsy' names
- Add comprehensive debugging for product sales tracking
- Enhanced visual design with better gradients and transitions
- Show units sold and total revenue in product details
- Improve month labels with cleaner formatting (no rotation)
- Better empty state handling and responsive layout
2026-05-06 06:58:24 +10:00
dlawler489
04069ef954 fix: resolve revenue trend chart and top profitable products issues
- Fix revenue trend chart to display month-year format for multi-year data
- Implement proper date sorting (newest first) for monthly revenue data
- Enhance chart with gradients, hover tooltips, and better visual design
- Fix top profitable products to use actual sales data instead of catalog data
- Calculate profits based on real order performance within date range
- Add comprehensive debugging and empty state handling
- Change default date range to 'All Time' for better initial experience
- Improve month-year parsing and data validation
2026-05-06 06:34:25 +10:00
dlawler489
701c805d0c feat: implement dynamic date selection with custom range support
- Add dynamic date range generation based on actual order data
- Implement custom date range picker with start/end date inputs
- Unify date filtering logic between Analytics and ProfitAnalysis pages
- Support multiple date formats (YYYY, YYYY-MM, YYYY-QX, custom ranges)
- Remove hardcoded years for future-proof date selection
- Enhance ProfitAnalysisService with custom date range support
2026-05-05 22:04:52 +10:00
dlawler489
db752f55f4 fix: standardize date filtering between Analytics and Profit Analysis pages
🎯 ISSUE RESOLVED: Profit calculations were different between pages due to inconsistent date filtering

📊 ROOT CAUSE:
- Profit Analysis Dashboard: "2026" = calendar year 2026 (Jan-Dec 2026)
- Analytics Page: "This Year" = rolling 365 days (May 2025-May 2026)

🔧 FIXES APPLIED:
- Unified date filtering logic using consistent calendar year approach
- Added "2026 Full Year" option to Analytics page for exact comparison
- Changed default to "2026" to match Profit Analysis dashboard
- Updated "This Year" to mean current calendar year (2026), not rolling 365 days

 NOW BOTH PAGES SHOW IDENTICAL DATA when comparing same date ranges!

The profit calculations will now match exactly when comparing equivalent time periods.
2026-05-05 21:56:01 +10:00
dlawler489
5f94e3ed71 perf: drastically improve expense processing speed with bulk API
🚀 PERFORMANCE IMPROVEMENTS:
- Add bulk expenses API endpoint (/expenses/bulk) for fast batch processing
- Replace slow sequential processing (3 seconds per expense) with instant bulk operations
- Use MongoDB insertMany with ordered:false for optimal bulk inserts
- Handle duplicates, validation errors, and partial failures gracefully

🧹 CODE CLEANUP:
- Remove excessive date parsing test logs that were spamming console
- Clean up unused imports and test code
- Improve error handling with detailed bulk operation results

 SPEED IMPROVEMENT:
- Before: 60+ seconds for 20 expenses (3 seconds each)
- After: <2 seconds for any number of expenses (bulk operation)

This eliminates the painfully slow background processing while maintaining duplicate prevention and error handling.
2026-05-05 21:15:56 +10:00
dlawler489
c1fc9309b1 fix: improve error handling in background expense processing
- Add proper array validation for existingExpenses API response
- Handle different API response structures (data.expenses vs data)
- Add try-catch blocks around individual expense processing loops
- Improve error messages to show specific error details
- Prevent TypeError when API response format is unexpected

Resolves 'gt.some is not a function' error in background processing.
2026-05-05 20:55:33 +10:00
dlawler489
212dc77df7 feat: move expense processing to background during CSV upload
- Process expenses immediately when CSV files are uploaded, not when user clicks analyze
- Use much more conservative rate limiting (3 seconds between expenses) to prevent 429 errors
- Remove bulk batch processing that was overwhelming the rate limiter
- Add background processing status indicator with spinner animation
- Clean up unused state variables and functions
- Improve user experience by eliminating long wait times during analysis

This prevents HTTP 429 rate limiting errors by spreading expense creation over time naturally as files are uploaded, rather than trying to process 60+ expenses rapidly in batches.
2026-05-05 20:35:10 +10:00
dlawler489
c2bdaa3c0d fix: enhance CSV import rate limiting and UI protection
- Reduce batch size from 3 to 2 expenses per batch for more conservative processing
- Increase delay between batches from 1.5s to 2s to prevent HTTP 429 errors
- Add isProcessingExpenses state to prevent multiple simultaneous imports
- Disable import buttons during expense processing for better UX
- Ensure processing state is always cleared in finally block

Resolves HTTP 429 rate limiting errors during bulk expense creation from CSV imports.
2026-05-05 20:02:30 +10:00
dlawler489
b8d0416a79 Fix CSV import rate limiting to prevent HTTP 429 errors
Frontend improvements:
- Add batch processing for expense creation (3 expenses per batch)
- Implement 1.5 second delays between batches to avoid overwhelming server
- Better progress logging and user feedback during batch processing
- Handle rate limit errors gracefully with proper error categorization

Backend improvements:
- Add specific rate limiter for expense creation endpoint (50 per minute)
- More informative error messages for rate limit violations
- Separate rate limiting for expense creation vs general API usage

This prevents the HTTP 429 'Too Many Requests' errors when importing large CSV files with many individual expense records (listing fees, ads, GST entries, etc.).
2026-05-05 19:31:46 +10:00
dlawler489
e89bb8e0d4 Fix GitHub Actions build errors and Node.js deprecation warnings
- Remove unused orderCosts parameter from createExpensesFromCsvData function
- Update function call to match new signature
- Upgrade GitHub Actions to use Node.js 24 instead of deprecated Node.js 20
- Add FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 environment variable

This should resolve the build failure and deprecation warnings in CI/CD.
2026-05-05 18:37:29 +10:00
dlawler489
a36582b843 Fix Etsy fee categorization to include listing fees, ads, and other business expenses
Major improvements to expense categorization and profit calculations:

NEW: Granular Etsy Fee Parsing
- Parse individual Etsy fees with proper categorization:
  * Listing Fees (should be included in expenses)
  * Marketing & Advertising (Etsy Ads - should be included)
  * Transaction Fees (tied to orders - excluded to avoid double-counting)
  * Processing Fees (tied to orders - excluded to avoid double-counting)
  * Taxes & GST (should be included)
  * Shipping & Postage (should be included)

FIXED: Profit Calculation Logic
- Only exclude sale transaction fees that have order references
- Include all other Etsy business expenses (ads, listing fees, GST)
- More accurate profit margins that account for all business costs

ENHANCED: CSV Import
- Creates specific expense categories instead of lumping as 'Transaction Fees'
- Better duplicate detection based on description, amount, date, and category
- Improved user feedback showing specific fee types created

This fixes the issue where listing fees and advertising costs were incorrectly excluded from profit calculations, resulting in unrealistically high profit margins.
2026-05-05 18:32:23 +10:00
dlawler489
99068d6710 Fix Australia Post CSV duplicate imports with comprehensive duplicate prevention
Multi-layer duplicate prevention system:
- Enhanced frontend duplicate detection with tracking number, amount, and date comparison
- Added MongoDB compound index to prevent database-level duplicates
- Improved backend error handling for duplicate key violations
- Added cleanup endpoint to remove existing duplicates
- Enhanced user feedback for import operations

Frontend changes:
- Stricter duplicate detection comparing tracking number, vendor, amount, and date
- Better error handling and user feedback for duplicate scenarios
- Added 'Clean Duplicates' button to remove existing duplicates

Backend changes:
- Database compound index on reference, vendor, userId, amount, date
- Enhanced error responses with duplicate detection flags
- New POST /expenses/cleanup-duplicates endpoint
- Improved duplicate key error handling

This should eliminate the double Australia Post expense entries.
2026-05-05 13:40:28 +10:00
dlawler489
761fce047a Fix profit analysis calculations to include shipping expenses and other costs
- Updated ProfitAnalysisService to accept and integrate expense data
- Modified calculateProfitMetrics to include expenses in profit calculations
- Added totalExpenses field to ProfitMetrics interface
- Updated ProfitAnalysis component to pass filtered expenses to calculations
- Enhanced UI to show breakdown of expenses vs printing costs
- Fixed inconsistency between Analytics and ProfitAnalysis profit calculations
- Now shipping expenses and Etsy fees are properly deducted from profits
- Excluded transaction fees to avoid double-counting
2026-05-05 13:21:00 +10:00
dlawler489
22799cb732 Integrate Data Import with Expenses tab
 FIXES MAJOR WORKFLOW ISSUE:
- Data Import CSV processing now automatically creates expenses
- Etsy fees → 'Transaction Fees' category expenses
- Australia Post shipping → 'Shipping & Postage' expenses
- Prevents duplicate expense creation with reference checking
- Added user notices in both Data Import and Expenses tabs

🔄 INTEGRATION FEATURES:
- Automatic expense creation from CSV order costs
- Duplicate prevention by order number/tracking number
- Proper categorization and tax-deductible flagging
- Clear user notifications and workflow guidance

📊 USER EXPERIENCE:
- Expenses tab now shows integration notice
- Data Import shows automatic expense creation info
- Seamless workflow between sales data and expense tracking
2026-05-05 12:29:07 +10:00
dlawler489
f39d4ca266 Fix modal persistence issue
- Add duplicate prevention with isProcessing state
- Implement loading spinner and disabled states
- Enhance modal closure logic in DataImport.tsx
- Add proper state reset on modal close
- Prevent multiple button clicks during processing
- Improve user feedback with console logging
2026-05-01 15:31:26 +10:00
dlawler489
461e424e5e Fix product matching for Modern Minimalist Shelf Decor variants
Enhanced product matching algorithm to properly handle:
- Large vs Small size variants for shelf decor products
- Improved size extraction from product titles
- Higher confidence thresholds for shelf decor products to prevent wrong matches
- Better handling of 3D-Printed product variations
- Enhanced logging for debugging matching issues

This fixes the issue where packing slips would create duplicate products
instead of matching to existing Large/Small variants of the same product.
2026-05-01 15:02:46 +10:00
dlawler489
ec1d204c36 Add comprehensive CSV product import system with templates and enhanced UI
Features Added:
- Enhanced CSV import service with smart parsing for product data
- Two CSV templates: simple and complete with example data
- Advanced product import UI with template downloads
- Comprehensive CSV import documentation and guide
- Support for all product fields including costs, dimensions, materials
- Error handling and validation for bulk imports
- Integration with profit analysis system for accurate cost tracking

UI Improvements:
- Template download buttons (Simple Template, Full Template)
- Enhanced import workflow with progress feedback
- Better error messaging and validation
- Updated Products page with CSV functionality

Documentation:
- Complete CSV_IMPORT_GUIDE.md with examples and best practices
- Updated DEPLOYMENT_STATUS.md reflecting production readiness
- Enhanced README.md with current feature status
- CHANGELOG.md with comprehensive development history

Production Ready:
- All functionality tested and integrated with existing profit analysis
- Bulk import capability for efficient product catalog setup
- Supports accurate cost tracking for comprehensive profit margins
2026-05-01 13:26:33 +10:00
dlawler489
1bc7daf33a Remove Vite template dark-mode styles from index.css
The default :root styles (dark background, white text, centered #root)
were overriding Tailwind and making all pages appear blank/dark.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 20:02:07 +10:00
dlawler489
a820ed4729 Fix unused import TypeScript errors in DataImport and Orders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 11:50:34 +10:00
dlawler489
1a3bd33be8 Migrate frontend from localStorage to MongoDB API
- Remove localStorage from all 4 Redux slices (products, orders, expenses, customers)
- Layout fetches all data from API on mount; adds logout button with active nav highlighting
- Wire API calls in Products, Orders, Expenses pages for all CRUD operations
- DataImport uses POST /orders/bulk for CSV upserts and API for PDF slip orders
- MissingProductsModal creates products via API
- Relax Order model: optional customerId, embedded customer, fees, printingCost on items, default paymentStatus=paid
- Relax Expense model: free-string category, add taxDeductible/vendor/reference fields
- Add printingCost to Product model
- Add POST /orders/bulk endpoint for upsert-by-orderNumber
- Raise rate limit to 1000 req/15min for bulk imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 08:48:05 +10:00
dlawler489
0d42d97d70 Add JWT auth with protected routes and per-user data isolation
Frontend:
- Login and Register pages wired up to API
- PrivateRoute redirects unauthenticated users to /login
- Token persisted in localStorage, restored on page load
- Axios instance automatically attaches Bearer token, redirects on 401

Backend:
- userId field added to all models (Product, Order, Customer, Expense)
- All queries scoped to authenticated user's userId
- Register/login return JWT token

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-22 08:16:51 +10:00
dlawler489
9e1a098a70 Initial commit: Complete Etsy Business Tracker with Profit Analysis Dashboard
Features:
- React + TypeScript frontend with Tailwind CSS
- Node.js + Express backend with TypeScript
- Comprehensive order tracking and management
- Product catalog with inventory tracking
- Customer data management
- Expense tracking and categorization
- Advanced Profit Analysis Dashboard with:
  - Real-time profit metrics and KPI visualization
  - Detailed order-level profit breakdown
  - Product performance analysis
  - Enhanced time range filtering (monthly, quarterly, yearly)
  - Interactive expandable order analysis
  - Performance categorization and color coding
- CSV import functionality for Etsy statements
- PDF parsing capabilities
- Redux state management with persistence
- Responsive design with mobile support
- Australian date formatting and currency display
2026-04-20 09:44:54 +10:00