CodeIssuesPull RequestsActionsSecurityInsights
✨ AI
More
Settings

feat: complete TradeQuote AI — all spec features, security fixes, CI/CD #3945

Merged⚡ AI-generatedXLccantynz wants to mergeclaude/tradequote-ai-plugin-spec-ADZYGmainopened May 30, 20260/13 tasks
ccantynzcommented May 30, 2026

Originally written by @ccantynz-alt on GitHub.
Imported from https://github.com/ccantynz-alt/-AI-Quote-to-Invoice-for-Trades/pull/3


What's in this PR

Full completion of the TradeQuote AI plugin, closing all 42 gaps identified in a post-v1 audit. 26 files changed, ~1,936 lines added/modified.


Security & Bug Fixes

  • Quota enforcementai/generate and quotes POST now return HTTP 402 before hitting Claude or the DB when free tier is exhausted
  • API key save — never overwrites an existing key with empty string or masked placeholder
  • Upload directory protection.htaccess (Deny from all) + index.php written on first PDF save so generated PDFs can't be enumerated
  • Email pre-check — send quote/invoice now validates customer has an email before attempting delivery
  • Logo field — sanitised with esc_url_raw() instead of sanitize_text_field() (which stripped URL characters)
  • Quote counter — atomic increment inside DB transaction to avoid race condition on concurrent saves
  • Unique DB constraintsUNIQUE KEY on quote_number and invoice_number; acceptance_token also unique

New Features

Freemius Licensing (class-tqa-freemius.php)

  • Loads Freemius SDK if present at vendor/freemius/wordpress-sdk/start.php
  • Graceful degradation to HMAC offline license key verification when SDK not installed
  • tqa_is_pro(), tqa_can_create_quote(), tqa_quota_remaining() helper functions used throughout

Public Quote Acceptance Portal (class-tqa-public.php)

  • Customers visit /?tqa_accept=TOKEN — no WordPress login required
  • Mobile-responsive acceptance page with full quote breakdown
  • Accept / Decline buttons update quote status and notify the business owner by email
  • REST endpoints: GET /public/quotes/{token} and POST /public/quotes/{token}/respond
  • 48-char hex token stored in acceptance_token column (added via dbDelta)

Trade-Specific AI Prompts (class-tqa-ai.php)

  • 10 trade types: general, plumber, electrician, builder, painter, landscaper, HVAC, cleaner, roofer, tiler
  • Each has tailored system prompt and unit suggestions
  • trade_type param passed from React to REST to Claude
  • test_api_key() method for Settings page validation

React Settings Page (src/components/SettingsPage.jsx)

  • Full settings form replacing PHP-only fallback
  • WordPress media uploader for logo (using wp.media)
  • Test API Key button — validates key against Claude before saving
  • Currency symbol + code fields
  • License key field
  • Saves via REST API; PHP form remains as <noscript> fallback

Admin Notices (class-tqa-admin-notices.php)

  • Missing Claude API key → warning on all TQA pages + dashboard
  • Missing business name → info notice
  • Low quota warning when ≤1 free quote remains
  • mPDF not installed → info notice

UI Improvements

  • QuotesList: PDF download button (via admin-post.php + pdfNonce), inline date picker modal for invoice conversion, search bar, copy-to-clipboard acceptance link button
  • InvoicesList: PDF download button, outstanding invoice total banner, overdue date indicator
  • QuoteBuilder: trade type selector dropdown with 10 options, job example placeholder per trade, quota exceeded blocker with upgrade CTA, low quota warning, acceptance link display after save
  • CustomerSearch: inline new-customer form replacing three sequential prompt() calls
  • Dashboard: currency-aware formatting, isPro stat card, Upgrade CTA when quota low

CI/CD

Workflow Trigger What it does
build.yml Push / PR JS build, PHP parallel-lint (8.1/8.2/8.3), WPCS
release.yml v*.*.* tag push Full build → composer install --no-devrsync clean package → zip → GitHub Release

bin/make-zip.sh — same packaging logic for local use.


Files Added/Changed

New PHP: class-tqa-freemius.php, class-tqa-public.php, class-tqa-admin-notices.php
New React: SettingsPage.jsx
New templates: quote-acceptance.php
New assets: placeholder-logo.svg, languages/.gitkeep
New CI: .github/workflows/build.yml, .github/workflows/release.yml, bin/make-zip.sh
Updated: all core PHP classes, all React components, admin.css

Test plan

  • Fresh install → activation redirects to Settings page with welcome banner
  • No API key → warning notice appears on dashboard and TQA pages
  • Enter API key → click "Test Key" → shows ✓ Valid / ✗ Invalid
  • Save settings → logo upload via media library works; tax rate, currency symbol save correctly
  • Create 5 quotes on free plan → 6th attempt returns quota error in UI
  • Generate quote with trade type "Plumber" → line items reflect plumbing context
  • Save quote → acceptance link appears; visit link as logged-out user → see quote, click Accept
  • Business owner receives email notification on quote accepted
  • QuotesList → click PDF → downloads file (HTML until mPDF installed)
  • QuotesList → click → Invoice: date picker modal appears; create invoice
  • InvoicesList → outstanding banner shown; overdue badge on past-due invoices
  • npm install && npm run build → bundle generated at admin/js/app/index.js
  • Tag v1.0.1 → GitHub Actions builds and attaches zip to release

https://claude.ai/code/session_01SYko81ETdN3uyZ8GVdH1s5


Generated by Claude Code

Cross-repo impact

See what breaks downstream if this PR merges.

Analyze →
⮌ Merged

This pull request was merged into main.

c comment · e edit title · m merge · a approve · r request changes · ? shortcuts