Examples#
Real-world examples demonstrating Pain001 usage.
Example 1: Basic SEPA Payment Processing#
Create a simple pain.001.001.03 file from a CSV file:
from pain001 import main
# Simple SEPA payment file generation
main(
xml_message_type='pain.001.001.03',
xml_template_file_path='sepa_template.xml',
xsd_schema_file_path='pain.001.001.03.xsd',
data_file_path='payments.csv'
)
CSV Input (payments.csv):
InitiatingParty,InitiatingPartyId,PaymentInformationId,DebtorName,DebtorId,DebtorAccountNumber,TransactionId,EndToEndId,Amount,CreditorName,CreditorAccountNumber,RemittanceInfo
Company XYZ,COMP123,PMT001,Acme Corp,ACME001,DE89370400440532013000,TXN001,E2E001,1000.00,Supplier ABC,DE89370400440532013001,Invoice #001
Example 2: Batch Payment Processing from CSV#
Process multiple payment files and generate XML outputs:
from pathlib import Path
from pain001 import main
from datetime import datetime
from pain001.exceptions import ValidationError
# Define directories
input_dir = Path('payments_input')
output_dir = Path('payments_output')
output_dir.mkdir(exist_ok=True)
# Process all CSV files
for csv_file in input_dir.glob('*.csv'):
try:
print(f"Processing: {csv_file.name}")
# Generate output filename with timestamp
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
output_file = output_dir / f"{csv_file.stem}_{timestamp}.xml"
# Generate payment file
main(
xml_message_type='pain.001.001.03',
xml_template_file_path='template.xml',
xsd_schema_file_path='pain.001.001.03.xsd',
data_file_path=str(csv_file)
)
print(f"✅ Generated: {output_file}")
except ValidationError as e:
print(f"❌ Validation error in {csv_file.name}: {e}")
# Log the error and continue with next file
continue
except Exception as e:
print(f"❌ Error processing {csv_file.name}: {e}")
continue
Example 3: Database-Driven Payment Processing#
Generate payment files from SQLite database:
import sqlite3
from pain001 import main
# Connect to database
conn = sqlite3.connect('payments.db')
cursor = conn.cursor()
# Query pending payments
cursor.execute('''
SELECT * FROM payments
WHERE status = 'pending'
AND payment_date <= date('now')
ORDER BY payment_date
''')
# Generate payment file for pending payments
main(
xml_message_type='pain.001.001.03',
xml_template_file_path='template.xml',
xsd_schema_file_path='pain.001.001.03.xsd',
data_file_path='payments.db'
)
# Update payment status
cursor.execute('''
UPDATE payments
SET status = 'processed'
WHERE status = 'pending'
''')
conn.commit()
conn.close()
Example 4: Multi-Version Support#
Handle different ISO 20022 versions:
from pain001 import main
from pain001.exceptions import ValidationError
versions = {
'sepa': 'pain.001.001.03',
'international': 'pain.001.001.04',
'instant': 'pain.001.001.06',
'modern': 'pain.001.001.11'
}
# Process different payment types with different versions
payment_configs = [
('sepa_payments.csv', versions['sepa'], 'sepa_template.xml'),
('international_payments.csv', versions['international'], 'international_template.xml'),
('instant_payments.csv', versions['instant'], 'instant_template.xml'),
]
for csv_file, version, template in payment_configs:
try:
print(f"Processing {csv_file} with {version}")
main(
xml_message_type=version,
xml_template_file_path=template,
xsd_schema_file_path=f'{version}.xsd',
data_file_path=csv_file
)
print(f"✅ {version} processed successfully")
except ValidationError as e:
print(f"❌ Validation error for {version}: {e}")
Example 5: Error Handling and Logging#
Robust error handling with detailed logging:
import logging
from pain001 import main
from pain001.exceptions import (
ValidationError,
XMLGenerationError,
SchemaValidationError,
DataLoadError
)
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('pain001.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def process_payment_file(csv_path, version, template, schema):
"""Process payment file with comprehensive error handling."""
try:
logger.info(f"Starting payment processing for {csv_path}")
main(
xml_message_type=version,
xml_template_file_path=template,
xsd_schema_file_path=schema,
data_file_path=csv_path
)
logger.info(f"✅ Successfully processed {csv_path}")
return True
except DataLoadError as e:
logger.error(f"Failed to load data from {csv_path}: {e}")
return False
except ValidationError as e:
logger.error(f"Data validation failed: {e}")
logger.debug(f"Validation details: {e.details}")
return False
except XMLGenerationError as e:
logger.error(f"XML generation failed: {e}")
return False
except SchemaValidationError as e:
logger.error(f"XSD validation failed: {e}")
logger.debug(f"Schema validation details: {e.details}")
return False
except Exception as e:
logger.exception(f"Unexpected error processing {csv_path}: {e}")
return False
# Usage
success = process_payment_file(
'payments.csv',
'pain.001.001.03',
'template.xml',
'pain.001.001.03.xsd'
)
Example 6: Large Batch Processing with Chunking#
Process large CSV files by splitting into chunks:
import pandas as pd
from pain001 import main
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
def process_large_file(csv_path, chunk_size=1000):
"""Process large CSV file in chunks."""
output_dir = Path('output')
output_dir.mkdir(exist_ok=True)
# Read CSV without loading entire file into memory
chunks = pd.read_csv(csv_path, chunksize=chunk_size)
chunk_num = 0
processed_chunks = 0
for chunk in chunks:
chunk_num += 1
chunk_file = output_dir / f"chunk_{chunk_num}.csv"
try:
# Save chunk to temporary file
chunk.to_csv(chunk_file, index=False)
logger.info(f"Processing chunk {chunk_num} ({len(chunk)} rows)")
# Generate payment file for chunk
main(
xml_message_type='pain.001.001.03',
xml_template_file_path='template.xml',
xsd_schema_file_path='pain.001.001.03.xsd',
data_file_path=str(chunk_file)
)
processed_chunks += 1
logger.info(f"✅ Chunk {chunk_num} processed successfully")
except Exception as e:
logger.error(f"❌ Error processing chunk {chunk_num}: {e}")
continue
finally:
# Clean up temporary chunk file
chunk_file.unlink(missing_ok=True)
logger.info(f"Processing complete: {processed_chunks}/{chunk_num} chunks successful")
return processed_chunks == chunk_num
# Usage
success = process_large_file('large_payments.csv', chunk_size=2000)
Example 7: Payment Amount Validation#
Validate payment amounts before processing:
import pandas as pd
from pain001 import main
import logging
logger = logging.getLogger(__name__)
def validate_amounts(csv_path):
"""Validate payment amounts."""
df = pd.read_csv(csv_path)
# Check for negative amounts
negative_amounts = df[df['Amount'] < 0]
if not negative_amounts.empty:
logger.warning(f"Found {len(negative_amounts)} negative amounts")
logger.warning(negative_amounts[['Amount', 'CreditorName']])
# Check for zero amounts
zero_amounts = df[df['Amount'] == 0]
if not zero_amounts.empty:
logger.warning(f"Found {len(zero_amounts)} zero amounts")
# Check for unusually large amounts
threshold = 1000000 # 1 million
large_amounts = df[df['Amount'] > threshold]
if not large_amounts.empty:
logger.warning(f"Found {len(large_amounts)} amounts > {threshold}")
logger.warning(large_amounts[['Amount', 'CreditorName']])
return len(df), len(negative_amounts), len(zero_amounts), len(large_amounts)
# Validate before processing
total, negative, zero, large = validate_amounts('payments.csv')
logger.info(f"Validation: Total={total}, Negative={negative}, Zero={zero}, Large={large}")
if negative > 0 or zero > 0:
logger.error("Payment amounts contain invalid values. Fix before processing.")
else:
main(
xml_message_type='pain.001.001.03',
xml_template_file_path='template.xml',
xsd_schema_file_path='pain.001.001.03.xsd',
data_file_path='payments.csv'
)
Example 8: Custom Data Processing Pipeline#
Build a complete payment processing pipeline:
from dataclasses import dataclass
from typing import List
import logging
from pain001 import main
from pain001.exceptions import ValidationError
logger = logging.getLogger(__name__)
@dataclass
class PaymentConfig:
"""Payment processing configuration."""
csv_path: str
version: str
template: str
schema: str
output_dir: str
class PaymentProcessor:
"""Complete payment processing pipeline."""
def __init__(self, config: PaymentConfig):
self.config = config
def validate_input(self) -> bool:
"""Validate input CSV file."""
try:
import pandas as pd
df = pd.read_csv(self.config.csv_path)
logger.info(f"Input validation: {len(df)} records found")
return True
except Exception as e:
logger.error(f"Input validation failed: {e}")
return False
def process(self) -> bool:
"""Process payment file."""
try:
if not self.validate_input():
return False
logger.info(f"Processing payments with {self.config.version}")
main(
xml_message_type=self.config.version,
xml_template_file_path=self.config.template,
xsd_schema_file_path=self.config.schema,
data_file_path=self.config.csv_path
)
logger.info("✅ Payment processing complete")
return True
except ValidationError as e:
logger.error(f"Validation failed: {e}")
return False
except Exception as e:
logger.error(f"Processing failed: {e}")
return False
# Usage
config = PaymentConfig(
csv_path='payments.csv',
version='pain.001.001.03',
template='template.xml',
schema='pain.001.001.03.xsd',
output_dir='output'
)
processor = PaymentProcessor(config)
success = processor.process()