Bulk PDF Print Feature
Overview
The Bulk PDF Print feature allows users to select multiple submissions and generate a single combined PDF document. This feature includes real-time progress tracking, email notifications, and a streamlined user interface.
User Guide
Selecting Submissions
- Navigate to the Submissions list page
- Use the checkboxes next to each submission to select individual items
- Use the "Select All" checkbox to select all submissions on the current page
- The selection count is displayed in a badge (e.g., "5 selected")
Printing Selected Submissions
- Click the Print button in the top toolbar
- If you have submissions selected, a print job will start automatically
- If no submissions are selected, the modal will show your last print job (if any)
Progress Tracking
When a print job starts:
- A modal displays real-time progress
- You'll see a progress bar showing X of Y submissions processed
- The modal can be closed to work in the background
- The job continues processing on the server
Download Options
Once complete:
- You'll receive an email notification with a download link
- The notification appears in your notification center
- Download links are valid for 7 days
- Click "Download PDF" in the progress modal
Print Job States
- Pending: Job created but not yet started
- Processing: PDFs are being generated and combined
- Completed: PDF is ready for download
- Failed: An error occurred during processing
Technical Implementation
Architecture
The feature follows a queue-based architecture:
User Selection → Print Job → Queue → Individual PDFs → Merge → Final PDF
↓ ↓
Database Notification
Components
Frontend Components
-
SubmissionsList (
app/Livewire/SubmissionsList.php)- Manages submission selection state
- Handles bulk actions UI
-
PrintProgress (
app/Livewire/PrintProgress.php)- Displays progress modal
- Polls for status updates every 5 seconds
- Handles job creation and monitoring
-
submission-card (
resources/views/components/submission-card.blade.php)- Individual submission cards with checkboxes
- Integrated with Flux UI checkbox groups
Backend Components
-
PrintJob Model (
app/Models/PrintJob.php)- Tracks print job status and progress
- Multi-tenant aware
- Progress calculation methods
-
PrintSubmissionsJob (
app/Jobs/PrintSubmissionsJob.php)- Processes submissions in chunks of 25
- Generates individual PDFs using
SubmissionPrintTrait - Handles errors gracefully
-
CombinePrintedPDFsJob (
app/Jobs/CombinePrintedPDFsJob.php)- Merges individual PDFs using
libmergepdf - Cleans up temporary files
- Sends completion notification
- Merges individual PDFs using
-
PrintCompleteNotification (
app/Notifications/PrintCompleteNotification.php)- Email notification with download link
- Database notification for tracking
Database Schema
CREATE TABLE print_jobs (
id BIGINT PRIMARY KEY,
user_id BIGINT NOT NULL,
status VARCHAR(255) DEFAULT 'pending',
total_submissions INTEGER DEFAULT 0,
processed_submissions INTEGER DEFAULT 0,
file_path VARCHAR(255) NULL,
completed_at TIMESTAMP NULL,
created_at TIMESTAMP,
updated_at TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
INDEX idx_user_status (user_id, status)
);
Queue Configuration
Jobs run on the exports queue:
- PrintSubmissionsJob
- CombinePrintedPDFsJob
- PrintCompleteNotification
Ensure your queue workers are running:
php artisan queue:work --queue=exports
File Storage
- Temporary PDFs:
storage/app/exports/temp/print/ - Final PDFs:
storage/app/exports/pdf/ - Files use ULID naming for uniqueness
- Temporary files are cleaned up after merging
Configuration
Memory Limits
The feature processes PDFs in chunks to manage memory:
- Default chunk size: 25 submissions
- Configurable in
PrintSubmissionsJob::$chunkSize
Storage Disk
Uses the exports disk defined in config/filesystems.php:
'exports' => [
'driver' => 'local',
'root' => storage_path('app/exports'),
'url' => env('APP_URL').'/storage/exports',
'visibility' => 'private',
],
PDF Generation
Uses existing SubmissionPrintTrait which supports:
- Blueprint-based PDF generation
- Blade template fallback
- Anonymous blueprint support
Error Handling
Individual PDF Failures
- Logged but don't stop the entire job
- Other submissions continue processing
- Failed submissions are skipped
Complete Job Failure
- Status set to 'failed'
- Temporary files cleaned up
- User can retry with new selection
Queue Failures
- Standard Laravel queue retry logic applies
- Failed jobs logged to
failed_jobstable
Security
- User can only access their own print jobs
- Temporary download URLs expire after 7 days
- Multi-tenant isolation enforced
- File paths use ULIDs to prevent guessing
Performance Considerations
- Chunked Processing: Prevents memory exhaustion
- Queue-based: Non-blocking UI experience
- Progress Updates: Database writes throttled per chunk
- Temporary Files: Cleaned up immediately after merge
Testing
The feature includes comprehensive test coverage:
Unit Tests
tests/Feature/BulkPrintTest.php- Selection and job creationtests/Feature/Livewire/PrintProgressTest.php- Progress tracking
Test Scenarios
- Submission selection/deselection
- Select all functionality
- Print job creation
- Progress modal display
- User isolation
- Empty selection handling
Run tests:
php artisan test tests/Feature/BulkPrintTest.php
php artisan test tests/Feature/Livewire/PrintProgressTest.php
Troubleshooting
Print job stuck in "processing"
- Check queue workers are running
- Check Laravel logs for errors
- Verify exports disk has write permissions
PDFs not generating
- Check SubmissionPrintTrait compatibility
- Verify blueprint templates exist
- Check memory limits in PHP configuration
Download links not working
- Verify exports disk configuration
- Check S3/storage permissions
- Confirm temporary URL generation
Future Enhancements
- Batch Templates: Apply different templates per submission type
- Cover Pages: Add summary/index pages
- Compression: ZIP option for very large jobs
- Scheduling: Queue priority based on job size
- Partial Downloads: Stream large files in chunks