12 KiB
PAYE Payroll Integration
Overview
The PAYE (Pay As You Earn) integration provides comprehensive Real Time Information (RTI) reporting capabilities for HMRC compliance. This system enables businesses to submit Full Payment Submissions (FPS), Employer Payment Summaries (EPS), and other statutory returns directly from completed payroll runs.
Features
Real Time Information (RTI) Submissions
The system supports all standard HMRC RTI submission types:
- FPS (Full Payment Submission): Reports employee payments, tax, and National Insurance deductions
- EPS (Employer Payment Summary): Reports statutory payments, CIS deductions, and allowances
- EAS (Earlier Year Update): Corrects previous year submissions
- NVR (NINO Verification Request): Requests verification of National Insurance numbers
Validation & Compliance
Comprehensive validation ensures all submissions meet HMRC requirements:
- National Insurance number format validation
- Tax code format validation
- Employee details completeness checks
- Payment calculation validation
- Address and postcode validation
- Warning detection for potential issues
Submission Management
Full lifecycle management of PAYE submissions:
- Draft creation and editing
- Pre-submission validation
- HMRC submission simulation
- Status tracking (draft → ready → submitted → accepted/rejected)
- HMRC reference tracking
- Resubmission and correction workflows
Components
PAYEManager
Main interface for managing PAYE RTI submissions.
Location: /src/components/PAYEManager.tsx
Features:
- View pending and submitted returns
- Validate submissions before sending
- Submit to HMRC
- Download RTI reports
- View validation errors and warnings
- Track HMRC acceptance status
Usage:
<PAYEManager
payrollRunId={payrollRun.id}
open={showManager}
onOpenChange={setShowManager}
/>
CreatePAYESubmissionDialog
Dialog for creating new PAYE submissions from payroll runs.
Location: /src/components/CreatePAYESubmissionDialog.tsx
Features:
- Generate FPS from completed payroll
- Configure payment date
- Review employer details
- Preview submission contents
Usage:
<CreatePAYESubmissionDialog
payrollRunId={payrollRun.id}
open={showDialog}
onOpenChange={setShowDialog}
onSuccess={() => {
// Handle successful creation
}}
/>
Hooks
usePAYEIntegration
Core hook providing PAYE functionality.
Location: /src/hooks/use-paye-integration.ts
Key Functions:
createFPS
Creates a Full Payment Submission with employee payment data.
const fps = createFPS(
payrollRunId,
employees,
paymentDate
)
Parameters:
payrollRunId: ID of the payroll runemployees: Array of FPSEmployee objectspaymentDate: ISO date string for payment date
Returns: FPSData object
createEPS
Creates an Employer Payment Summary for statutory payments and deductions.
const eps = createEPS(
taxYear,
taxMonth,
{
statutorySickPay: 1500,
cisDeductionsSuffered: 2000,
employmentAllowance: true
}
)
validateSubmission
Validates a submission before sending to HMRC.
const result = await validateSubmission(submissionId)
if (result.isValid) {
// Proceed with submission
} else {
// Show errors
console.log(result.errors)
}
Returns: RTIValidationResult with:
isValid: Boolean indicating if validation passederrors: Array of validation errorswarnings: Array of validation warningscanSubmit: Boolean indicating if submission is allowed
submitToHMRC
Submits a validated return to HMRC.
const result = await submitToHMRC(submissionId)
if (result.success) {
console.log('HMRC Reference:', result.hmrcReference)
} else {
console.log('Errors:', result.errors)
}
Returns: Object with:
success: BooleanhmrcReference: HMRC tracking reference (if successful)errors: Array of errors (if failed)
generateRTIReport
Generates a human-readable RTI report for download.
const report = generateRTIReport(submissionId)
// Returns formatted text report
calculateApprenticeshipLevy
Calculates apprenticeship levy for annual payroll.
const levy = calculateApprenticeshipLevy(totalAnnualPayroll)
// Returns levy amount in £
Data Structures
FPSEmployee
Complete employee payment record for FPS submissions:
interface FPSEmployee {
workerId: string
employeeRef: string
niNumber: string
title: string
firstName: string
lastName: string
dateOfBirth: string
gender: 'M' | 'F' | 'X'
address: EmployeeAddress
taxCode: string
niCategory: string
grossPay: number
taxableGrossPay: number
incomeTax: number
employeeNI: number
employerNI: number
studentLoan?: number
studentLoanPlan?: 'Plan1' | 'Plan2' | 'Plan4' | 'PostGrad'
pensionContribution?: number
paymentMethod: 'BACS' | 'Cheque' | 'Cash'
payFrequency: 'Weekly' | 'Fortnightly' | 'FourWeekly' | 'Monthly'
hoursWorked?: number
irregularPayment?: boolean
leavingDate?: string
starterDeclaration?: StarterDeclaration
}
PAYESubmission
Tracks the status of an RTI submission:
interface PAYESubmission {
id: string
type: 'FPS' | 'EPS' | 'EAS' | 'NVR'
taxYear: string
taxMonth: number
status: 'draft' | 'ready' | 'submitted' | 'accepted' | 'rejected' | 'corrected'
createdDate: string
submittedDate?: string
acceptedDate?: string
payrollRunId: string
employerRef: string
employeesCount: number
totalPayment: number
totalTax: number
totalNI: number
hmrcReference?: string
errors?: PAYEError[]
warnings?: PAYEWarning[]
}
PAYEConfig
Employer configuration for PAYE submissions:
interface PAYEConfig {
employerRef: string // e.g., '123/AB45678'
accountsOfficeRef: string // e.g., '123PA00045678'
companyName: string
companyAddress: EmployeeAddress
contactName: string
contactPhone: string
contactEmail: string
apprenticeshipLevy: boolean
employmentAllowance: boolean
}
Integration Workflow
1. Complete Payroll Run
First, process a standard payroll run with all employee payments calculated.
2. Create PAYE Submission
From a completed payroll run, create an FPS submission:
// Click "Create PAYE" button on completed payroll run
<Button onClick={() => {
setSelectedPayrollForPAYE(run.id)
setShowCreatePAYE(true)
}}>
<FileText size={16} />
Create PAYE
</Button>
3. Validate Submission
Before sending to HMRC, validate the submission:
const validation = await validateSubmission(submission.id)
if (!validation.isValid) {
// Show errors to user
validation.errors.forEach(error => {
console.error(`${error.code}: ${error.message}`)
})
}
4. Submit to HMRC
Once validated, submit to HMRC:
const result = await submitToHMRC(submission.id)
if (result.success) {
toast.success(`Submitted to HMRC: ${result.hmrcReference}`)
} else {
toast.error('Submission failed')
}
5. Track Acceptance
Monitor submission status and HMRC acceptance:
const submission = getSubmissionStatus(submissionId)
switch (submission.status) {
case 'submitted':
// Waiting for HMRC response
break
case 'accepted':
// Successfully processed by HMRC
console.log('Accepted:', submission.acceptedDate)
break
case 'rejected':
// Review and correct errors
console.log('Errors:', submission.errors)
break
}
Validation Rules
The system enforces the following validation rules:
Required Fields
- Employee first name and last name
- Valid National Insurance number (format: AB123456C)
- Valid tax code (e.g., 1257L, BR, 0T)
- Date of birth
- Complete address with postcode
- Payment amounts (gross, tax, NI)
Format Validation
- NI Number: 2 letters, 6 digits, 1 letter (excluding certain letters)
- Tax Code: Valid HMRC tax code format
- Postcode: UK postcode format
Business Rules
- Gross pay must not be negative
- Tax must not be negative
- Taxable gross pay should not exceed total gross pay
- Student loan deductions require loan plan type
- Employee NI calculated correctly for NI category
Warnings (Non-blocking)
- Taxable gross exceeds total gross
- Missing student loan plan when deductions present
- Irregular payment patterns
- Missing optional fields
Error Handling
The system provides detailed error information:
interface PAYEError {
code: string // Error code (e.g., 'INVALID_NI')
message: string // Human-readable message
field?: string // Field name if applicable
severity: 'error' | 'warning'
}
Common error codes:
INVALID_NI: National Insurance number format invalidINVALID_TAX_CODE: Tax code format invalidMISSING_FIRST_NAME: First name requiredMISSING_LAST_NAME: Last name requiredMISSING_DOB: Date of birth requiredMISSING_POSTCODE: Postcode requiredNEGATIVE_PAY: Gross pay cannot be negativeNEGATIVE_TAX: Tax cannot be negative
Tax Year Calculations
The system automatically calculates tax year and tax month:
// Tax year runs April to April
const taxYear = calculateTaxYear(new Date())
// Returns: "2024/25" if date is between Apr 2024 - Mar 2025
// Tax month is 1-12 starting from April
const taxMonth = calculateTaxMonth(new Date())
// Returns: 1 for April, 2 for May, etc.
Reporting
RTI Reports
Generate detailed RTI reports for record-keeping:
const report = generateRTIReport(submissionId)
Report includes:
- Employer reference and tax year
- Tax month and payment date
- Employee count
- Summary totals (gross pay, tax, NI, student loans)
- Individual employee breakdowns
Example output:
FULL PAYMENT SUBMISSION (FPS)
============================================================
Employer Reference: 123/AB45678
Tax Year: 2024/25
Tax Month: 10
Payment Date: 31/01/2025
Employees: 25
SUMMARY
------------------------------------------------------------
Total Gross Pay: £87,500.00
Total Tax: £14,250.00
Total Employee NI: £8,890.00
Total Employer NI: £10,750.00
Total Student Loan: £1,250.00
EMPLOYEES
------------------------------------------------------------
1. Sarah Johnson
NI Number: AB123456C
Tax Code: 1257L
Gross Pay: £3,500.00
Tax: £477.50
NI: £354.60
...
Best Practices
1. Validate Before Submission
Always validate submissions before sending to HMRC to catch errors early.
2. Keep Records
Download and store RTI reports for audit purposes.
3. Monitor Submissions
Regularly check submission status and HMRC responses.
4. Handle Corrections
If a submission is rejected, review errors, make corrections, and resubmit.
5. Timely Submissions
Submit FPS on or before payment date to comply with RTI requirements.
6. Data Accuracy
Ensure employee data is up-to-date before generating PAYE submissions.
7. Test Thoroughly
Use the validation features to test submissions before live use.
Future Enhancements
Planned improvements include:
- Direct Government Gateway integration
- Automatic HMRC response polling
- Bulk employee data import
- Historical submission archive
- Advanced error correction workflows
- Integration with payroll calculation hook
- P45 and P60 generation
- CIS subcontractor returns
- Gender pay gap reporting
- Auto-enrolment pension integration
Related Documentation
Support
For issues or questions about PAYE integration:
- Check validation errors for specific guidance
- Review HMRC RTI documentation
- Consult with payroll compliance specialist
- Contact HMRC employer helpline: 0300 200 3200
Last Updated: January 2025 Version: 1.0