A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/moov-io/pamspr below:

moov-io/pamspr: A comprehensive Go library for reading, writing, and validating Payment Automation Manager (PAM) Standard Payment Request (SPR) files used by the U.S. Treasury Bureau of the Fiscal Service.

PAM SPR - Payment Automation Manager Standard Payment Request

A Go library for reading, writing, and validating Payment Automation Manager (PAM) Standard Payment Request (SPR) files used by the U.S. Treasury Bureau of the Fiscal Service for federal agency payment processing.

PAM SPR files are used by federal agencies to process various types of payments including:

The library supports both ACH (Automated Clearing House) and Check payment methods, with comprehensive validation for Same Day ACH requirements and agency-specific rules.

Performance & Scalability
go get github.com/moov-io/pamspr

Or install the CLI tool:

go install github.com/moov-io/pamspr/cmd/pamspr@latest
package main

import (
    "fmt"
    "log"
    "os"
    
    "github.com/moov-io/pamspr/pkg/pamspr"
)

func main() {
    // Open the file
    file, err := os.Open("payments.spr")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    // Parse the file
    reader := pamspr.NewReader(file)
    pamFile, err := reader.Read()
    if err != nil {
        log.Fatal(err)
    }

    // Display file information
    fmt.Printf("Input System: %s\n", pamFile.Header.InputSystem)
    fmt.Printf("Total Payments: %d\n", pamFile.Trailer.TotalCountPayments)
    fmt.Printf("Total Amount: $%.2f\n", float64(pamFile.Trailer.TotalAmountPayments)/100)
}
Creating an ACH Payment File
package main

import (
    "log"
    "os"
    
    "github.com/moov-io/pamspr/pkg/pamspr"
)

func main() {
    // Build file using fluent API
    builder := pamspr.NewFileBuilder()
    
    file, err := builder.
        WithHeader("MY_AGENCY_SYSTEM", "502", false).
        StartACHSchedule("SCH001", "Salary", "12345678", "PPD").
        AddACHPayment(&pamspr.ACHPayment{
            AgencyAccountIdentifier:      "EMP001",
            Amount:                       250000, // $2,500.00
            AgencyPaymentTypeCode:        "S",
            IsTOPOffset:                  "1",
            PayeeName:                    "JOHN DOE",
            PayeeAddressLine1:            "123 MAIN ST",
            CityName:                     "WASHINGTON",
            StateCodeText:                "DC",
            PostalCode:                   "20001",
            RoutingNumber:                "021000021",
            AccountNumber:                "1234567890",
            ACHTransactionCode:           "22", // Checking Credit
            PaymentID:                    "PAY001",
            TIN:                          "123456789",
            PaymentRecipientTINIndicator: "1", // SSN
        }).
        Build()
    
    if err != nil {
        log.Fatal(err)
    }

    // Write to file
    output, err := os.Create("ach_payments.spr")
    if err != nil {
        log.Fatal(err)
    }
    defer output.Close()

    writer := pamspr.NewWriter(output)
    if err := writer.Write(file); err != nil {
        log.Fatal(err)
    }
    
    fmt.Println("ACH payment file created successfully!")
}
Creating a Check Payment File
package main

import (
    "log"
    "os"
    
    "github.com/moov-io/pamspr/pkg/pamspr"
)

func main() {
    builder := pamspr.NewFileBuilder()
    
    file, err := builder.
        WithHeader("CHECK_SYSTEM", "502", false).
        StartCheckSchedule("CHK001", "Vendor", "87654321", "stub").
        AddCheckPayment(&pamspr.CheckPayment{
            AgencyAccountIdentifier:      "VEND001",
            Amount:                       150000, // $1,500.00
            AgencyPaymentTypeCode:        "V",
            IsTOPOffset:                  "1",
            PayeeName:                    "ACME CORP",
            PayeeAddressLine1:            "789 BUSINESS BLVD",
            PayeeAddressLine2:            "SUITE 100",
            CityName:                     "NEW YORK",
            StateCodeText:                "NY",
            PostalCode:                   "10001",
            CheckLegendText1:             "INVOICE #12345",
            CheckLegendText2:             "PO #67890",
            PaymentID:                    "CHK001",
            TIN:                          "123456789",
            PaymentRecipientTINIndicator: "2", // EIN
            Stub: &pamspr.CheckStub{
                RecordCode: "13",
                PaymentID:  "CHK001",
                PaymentIdentificationLines: [14]string{
                    "Invoice Date: 01/15/2024",
                    "Invoice Number: 12345",
                    "Purchase Order: 67890",
                    "Description: Office Supplies",
                    "",
                    "Item Details:",
                    "  Paper - 10 reams @ $50.00 = $500.00",
                    "  Toner - 5 units @ $100.00 = $500.00",
                    "  Misc Supplies = $500.00",
                    "",
                    "Subtotal: $1,500.00",
                    "Tax: $0.00",
                    "Total: $1,500.00",
                    "",
                },
            },
        }).
        Build()
    
    if err != nil {
        log.Fatal(err)
    }

    // Write to file
    output, err := os.Create("check_payments.spr")
    if err != nil {
        log.Fatal(err)
    }
    defer output.Close()

    writer := pamspr.NewWriter(output)
    if err := writer.Write(file); err != nil {
        log.Fatal(err)
    }
    
    fmt.Println("Check payment file created successfully!")
}

The library includes comprehensive validation capabilities:

package main

import (
    "fmt"
    "log"
    "os"
    
    "github.com/moov-io/pamspr/pkg/pamspr"
)

func main() {
    // Read file
    file, err := os.Open("payments.spr")
    if err != nil {
        log.Fatal(err)
    }
    defer file.Close()

    reader := pamspr.NewReader(file)
    pamFile, err := reader.Read()
    if err != nil {
        log.Fatal(err)
    }

    // Create validator
    validator := pamspr.NewValidator()

    // Validate file structure
    if err := validator.ValidateFileStructure(pamFile); err != nil {
        log.Printf("Structure validation failed: %v", err)
    }

    // Validate balancing (totals match)
    if err := validator.ValidateBalancing(pamFile); err != nil {
        log.Printf("Balancing validation failed: %v", err)
    }

    // Validate Same Day ACH requirements
    if err := validator.ValidateSameDayACH(pamFile); err != nil {
        log.Printf("Same Day ACH validation failed: %v", err)
    }

    // Validate individual payments
    for _, schedule := range pamFile.Schedules {
        for _, payment := range schedule.GetPayments() {
            if achPayment, ok := payment.(*pamspr.ACHPayment); ok {
                if err := validator.ValidateACHPayment(achPayment); err != nil {
                    log.Printf("ACH payment validation failed: %v", err)
                }
            }
            if checkPayment, ok := payment.(*pamspr.CheckPayment); ok {
                if err := validator.ValidateCheckPayment(checkPayment); err != nil {
                    log.Printf("Check payment validation failed: %v", err)
                }
            }
        }
    }

    fmt.Println("Validation completed!")
}

The included command-line tool provides easy file operations:

pamspr -validate -input payments.spr
pamspr -info -input payments.spr
# Create sample ACH file
pamspr -create ach -output sample_ach.spr

# Create sample Check file
pamspr -create check -output sample_check.spr
Convert to JSON (Future Feature)
pamspr -convert -input payments.spr -output payments.json
Performance & Memory Management

The PAM SPR library is designed to handle files of any size efficiently through streaming processing. All Reader and Writer instances use streaming algorithms that maintain constant memory usage regardless of file size.

Memory-Efficient Processing

The library uses a streaming approach by default, providing:

// All readers and writers are streaming by default
reader := pamspr.NewReader(file)   // Memory-efficient streaming
writer := pamspr.NewWriter(output) // Memory-efficient streaming
Performance Characteristics File Size Memory Usage Processing Speed Notes 1MB ~64KB High Fast startup 100MB ~64KB High Constant memory 1GB ~64KB High No memory growth 10GB+ ~64KB High Linear scaling

The reader provides three optimized processing modes:

1. Payment-Only Processing (Fastest)

For applications that only need payment data:

reader := pamspr.NewReader(file)

err := reader.ProcessPaymentsOnly(func(payment pamspr.Payment, scheduleIndex, paymentIndex int) bool {
    // Process each payment as it's read
    fmt.Printf("Payment %s: $%.2f\n", payment.GetPaymentID(), float64(payment.GetAmount())/100)
    
    // Return false to stop processing early
    return true
})

Use Case: Payment processing, reporting, data extraction Memory Usage: Constant ~64KB regardless of file size
Performance: Fastest option - skips schedule object creation

2. Full File Processing with Callbacks

For applications needing complete file structure:

reader := pamspr.NewReader(file)

err := reader.ProcessFile(
    // Schedule callback
    func(schedule pamspr.Schedule, scheduleIndex int) bool {
        fmt.Printf("Processing schedule: %s\n", schedule.GetScheduleNumber())
        return true
    },
    // Payment callback  
    func(payment pamspr.Payment, scheduleIndex, paymentIndex int) bool {
        // Process payment within context of its schedule
        return true
    },
    // Optional record callback for debugging
    func(recordType string, lineNumber int, line string) {
        // Monitor all records as they're processed
    },
)

Use Case: Full file processing, validation, transformation Memory Usage: Constant ~64KB + callback data Performance: Full control with memory efficiency

3. Structure Validation Only (Ultra-Fast)

For quick file validation without object creation:

reader := pamspr.NewReader(file)

err := reader.ValidateFileStructureOnly()
if err != nil {
    log.Printf("File structure invalid: %v", err)
}

stats := reader.GetStats()
fmt.Printf("Validated %d lines, %d payments in %v\n", 
    stats.LinesProcessed, stats.PaymentsProcessed, elapsed)

Use Case: File validation, integrity checking, format verification Memory Usage: Minimal ~8KB
Performance: Ultra-fast - no object allocation

For applications that need the complete file structure in memory:

// Traditional API (uses streaming internally)
reader := pamspr.NewReader(file)
pamFile, err := reader.Read()  // Uses ReadAll() internally

Note: This builds the complete file structure in memory but uses streaming parsing internally for optimal performance.

For optimal performance with different file sizes and systems, configure buffer sizes:

Standard Configuration (Default)
// Default settings - optimal for most use cases
reader := pamspr.NewReader(file)
writer := pamspr.NewWriter(output)

For files > 1GB or high-throughput processing:

config := &pamspr.ReaderConfig{
    BufferSize:         256 * 1024,  // 256KB buffer
    EnableValidation:   true,        // Keep validation enabled
    CollectErrors:      false,       // Disable error collection for speed
    SkipInvalidRecords: false,       // Fail fast on errors
}
reader := pamspr.NewReaderWithConfig(file, config)

writerConfig := &pamspr.WriterConfig{
    BufferSize:    256 * 1024,  // 256KB buffer
    FlushInterval: 1000,        // Flush every 1000 records
}
writer := pamspr.NewWriterWithConfig(output, writerConfig)
Memory-Constrained Configuration

For embedded systems or containers with limited memory:

config := &pamspr.ReaderConfig{
    BufferSize:       16 * 1024,  // 16KB buffer
    MaxErrors:        100,        // Limit error collection
    CollectErrors:    true,       // Still collect some errors
}
reader := pamspr.NewReaderWithConfig(file, config)
High-Throughput Configuration

For maximum processing speed:

config := &pamspr.ReaderConfig{
    BufferSize:         512 * 1024,  // 512KB buffer
    EnableValidation:   false,       // Skip validation for speed
    CollectErrors:      false,       // No error collection
    SkipInvalidRecords: true,        // Continue on errors
}
reader := pamspr.NewReaderWithConfig(file, config)

Track processing performance with built-in statistics:

reader := pamspr.NewReader(file)

// Process file...
err := reader.ProcessPaymentsOnly(paymentCallback)

// Get statistics
stats := reader.GetStats()
fmt.Printf(`Processing Statistics:
  Lines Processed: %d
  Payments Processed: %d  
  Schedules Processed: %d
  Errors Encountered: %d
  Bytes Processed: %d
`, stats.LinesProcessed, stats.PaymentsProcessed, 
   stats.SchedulesProcessed, stats.ErrorsEncountered, stats.BytesProcessed)
  1. Use Payment-Only Mode when you don't need full file structure
  2. Avoid ReadAll() for large files - use callbacks instead
  3. Configure appropriate buffer sizes based on your system resources
  4. Disable error collection for maximum performance in trusted environments
  1. Process in chunks using early termination in callbacks
  2. Use goroutines for parallel processing of payment data
  3. Monitor memory usage with runtime.ReadMemStats()
  4. Implement backpressure if downstream processing is slower
  1. Set MaxErrors to prevent memory growth from error collection
  2. Use SkipInvalidRecords for fault-tolerant processing
  3. Log errors asynchronously to avoid blocking I/O
  4. Implement circuit breakers for downstream service failures
Example: Processing 10GB File
reader := pamspr.NewReaderWithConfig(file, &pamspr.ReaderConfig{
    BufferSize:         1024 * 1024,  // 1MB buffer for large files
    EnableValidation:   true,
    CollectErrors:      false,        // Don't collect errors for memory efficiency
    MaxErrors:          0,
    SkipInvalidRecords: false,        // Fail fast on corruption
})

processed := 0
start := time.Now()

err := reader.ProcessPaymentsOnly(func(payment pamspr.Payment, scheduleIndex, paymentIndex int) bool {
    // Process payment (e.g., send to database, queue, etc.)
    processPayment(payment)
    
    processed++
    if processed%10000 == 0 {
        elapsed := time.Since(start)
        rate := float64(processed) / elapsed.Seconds()
        fmt.Printf("Processed %d payments (%.0f payments/sec)\n", processed, rate)
    }
    
    return true  // Continue processing
})

fmt.Printf("Total processed: %d payments in %v\n", processed, time.Since(start))
Optimizing for Large Files

Traditional approach (loads entire file):

reader := pamspr.NewReader(file)
pamFile, err := reader.Read()  // Loads complete file structure
if err != nil {
    return err
}

for _, schedule := range pamFile.Schedules {
    for _, payment := range schedule.GetPayments() {
        processPayment(payment)
    }
}

Optimized approach (streaming processing):

reader := pamspr.NewReader(file)  // Same constructor

err := reader.ProcessPaymentsOnly(func(payment pamspr.Payment, scheduleIndex, paymentIndex int) bool {
    processPayment(payment)
    return true
})

Benefits of optimization:

The complete PAM SPR file format specification is available in the docs/ directory, organized into easily-navigable sections:

The specification includes detailed field definitions, validation rules, error codes, and agency-specific requirements extracted from the official Treasury documentation.

File Format Specifications

PAM SPR files use a hierarchical structure with fixed-width records:

File Header (H)
├── Schedule Header (01=ACH, 11=Check)
│   ├── Payment Record (02=ACH, 12=Check)
│   │   ├── Addendum Records (03, 04) [Optional]
│   │   ├── CARS TAS/BETC Records (G) [Optional]
│   │   ├── Check Stub (13) [Check Only]
│   │   └── DNP Record (DD) [Optional]
│   └── Schedule Trailer (T)
└── File Trailer (E)
Agency-Specific Validation

The library includes specialized validation for all federal agencies with complete implementation:

All Agencies Fully Implemented (100% Coverage) IRS (Internal Revenue Service) - FULLY IMPLEMENTED VA (Department of Veterans Affairs) - FULLY IMPLEMENTED SSA (Social Security Administration) - FULLY IMPLEMENTED RRB (Railroad Retirement Board) - FULLY IMPLEMENTED CCC (Commodity Credit Corporation) - FULLY IMPLEMENTED 🎯 Validation Coverage Status

The library fully supports Same Day ACH processing with validation for:

The library provides helpful utilities for common operations:

// Pad left with zeros
padded := pamspr.PadLeft("123", 5, '0') // "00123"

// Pad right with spaces  
padded = pamspr.PadRight("ABC", 7, ' ') // "ABC    "

// Extract and pad numeric values
numeric := pamspr.PadNumeric("ABC123DEF", 5) // "00123"
// Convert cents to dollar string
dollars := pamspr.FormatCents(12345) // "123.45"

// Parse dollar string to cents
cents, err := pamspr.ParseAmount("$1,234.56") // 123456, nil
// Clean problematic characters
clean := pamspr.CleanAddress(`123 "Main" & <Company>`) // `123 'Main' + (Company)`
// Format SSN
ssn := pamspr.FormatTIN("123456789", "1") // "123-45-6789"

// Format EIN  
ein := pamspr.FormatTIN("123456789", "2") // "12-3456789"

Run the comprehensive test suite:

# Run all tests
go test ./...

# Run tests with coverage
go test -cover ./...

# Run specific package tests
go test ./pkg/pamspr/

# Run specific test
go test -run TestReaderParseFile ./pkg/pamspr/

# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

See the examples/ directory for complete working examples:

# Run example code
go run examples/examples.go

The examples demonstrate:

  1. Creating ACH payment files with addenda and CARS records
  2. Creating check payment files with stubs
  3. Parsing and validating existing files
  4. Same Day ACH validation scenarios

We welcome contributions! Please see our contributing guidelines for details.

# Clone the repository
git clone https://github.com/moov-io/pamspr.git
cd pamspr

# Run tests
go test ./...

# Build CLI tool
go build -o pamspr cmd/pamspr/main.go

# Format code
go fmt ./...

# Run linter
golangci-lint run
Contributing & Making the Library More Robust

We welcome contributions to improve the PAM SPR library! Here are critical areas where community help is needed to make this library production-ready for federal agencies:

🚨 Critical Needs for Production Readiness 1. Real Treasury Test Data & Validation Rules

Current Gap: The library uses synthetic test data and lacks real Treasury-approved validation specifications.

What We Need:

Impact: Without real Treasury data, federal agencies cannot use this library in production as it may accept payments that Treasury would reject.

2. Enhanced Business Rule Validation

Current Status: 100% format validation coverage, business rules need agency input

Remaining Work:

How to Help: If you work at or with these agencies, we need SMEs to provide business validation requirements.

3. JSON/XML Export Implementation

Current Gap: CLI has -convert flag but it's not implemented

What's Needed:

4. Enhanced Test Coverage & Real-World Scenarios

Current Gap: Limited to synthetic test files

What's Needed:

🎯 Priority Contribution Areas Area Priority Impact Effort Real Treasury test files CRITICAL High Contact Treasury Business rule validation High Medium Agency coordination JSON export implementation Medium High 1 week Performance optimization Low Medium 2 weeks Streaming support Low Medium 2 weeks
  1. For Agency SMEs: Help us get real validation requirements

    # Contact these Treasury resources:
    # PAM.SAT@fiscal.treasury.gov - Test data access
    # FS.AgencyOutreach@fiscal.treasury.gov - Business rules
  2. For Developers: Implement enhanced features

    git clone https://github.com/moov-io/pamspr.git
    cd pamspr
    
    # Focus areas for enhancement:
    # - JSON/XML export in cmd/pamspr/main.go
    # - Business rule validation in pkg/pamspr/validator.go
    # - Performance optimization for large files
  3. For Treasury Integration: Help obtain real test files

    # We need files in testdata/treasury/ structure:
    # - testdata/treasury/valid/ach/
    # - testdata/treasury/valid/check/
    # - testdata/treasury/agency/{IRS,VA,SSA,RRB,CCC}/
    # - testdata/treasury/invalid/ (for error testing)
🔗 Resources for Contributors

The Goal: Make this library production-ready so federal agencies can confidently process payments without risk of Treasury rejection.

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Disclaimer: This library is not affiliated with the U.S. Treasury or any federal agency. It is an open-source implementation of the PAM SPR file format for integration purposes.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4