README
🚀 PayBySquare 生成器
PayBySquare 生成器是一个全面的 Node.js/TypeScript 库,用于生成、解码和验证支付二维码。PayBySquare 是斯洛伐克银行协会(SBA)采用的支付二维码国家标准。
✨ 主要特性
生成功能
- ✅ 基于简单的 JSON 接口
- ✅ 生成 PNG 格式的二维码缓冲区或文件
- ✅ 支持所有 PayBySquare 支付字段
- ✅ 可自定义二维码样式(尺寸、颜色、纠错级别)
解码功能
- ✅ 从 PNG 缓冲区解码 PayBySquare 二维码
- ✅ 将支付数据提取为 JSON 格式
- ✅ 往返验证(无损编码/解码)
合规性与验证
- ✅ IBAN 校验和验证(mod - 97 算法)
- ✅ 字段格式合规性检查
- ✅ 银行标准验证(BIC/SWIFT、货币代码)
- ✅ 带有错误严重程度级别的详细合规性报告
开发特性
- ✅ 完全支持 TypeScript 并提供类型定义
- ✅ 零 UI 依赖 - 纯基于函数的接口
- ✅ ESM 模块格式(Node.js >= 18)
- ✅ 经过全面测试(96 个单元测试,覆盖率超过 90%)
- ✅ MCP 服务器 - 可与 Claude Desktop 和其他 MCP 客户端配合使用
📦 安装指南
npm install paybysquare-generator
要求
- Node.js >= 18.0.0
- 支持 ESM 模块
🚀 快速开始
import { generatePayBySquare } from 'paybysquare-generator';
// 生成支付二维码
const buffer = await generatePayBySquare({
iban: 'SK9611000000002918599669',
beneficiaryName: 'John Doe',
amount: 100.50,
currency: 'EUR',
variableSymbol: '123456',
paymentNote: 'Invoice payment'
});
// buffer 是一个 PNG 图像的 Buffer - 可以保存、发送等
📚 详细文档
API 参考
generatePayBySquare(input, options?)
根据支付数据生成 PayBySquare 二维码 PNG 图像。
参数:
input: PayBySquareInput- 支付数据(见下文)options?: GenerationOptions- 可选的二维码生成选项
返回值: Promise<Buffer> - 以 Node.js Buffer 形式的 PNG 图像
抛出错误:
ValidationError- 如果输入数据无效EncodingError- 如果支付数据编码失败GenerationError- 如果二维码 PNG 生成失败
generatePayBySquareToFile(input, filePath, options?)
生成 PayBySquare 二维码并保存到文件。
参数:
input: PayBySquareInput- 支付数据filePath: string- 保存 PNG 文件的路径options?: GenerationOptions- 可选的二维码生成选项
返回值: Promise<void>
decodePayBySquare(buffer)
从 PNG 缓冲区解码 PayBySquare 二维码,还原为支付数据。
参数:
buffer: Buffer- 包含 PayBySquare 二维码的 PNG 图像缓冲区
返回值: Promise<PayBySquareInput> - 解码后的支付数据
抛出错误:
DecodingError- 如果二维码无法读取或解码
示例:
import { readFile } from 'fs/promises';
import { decodePayBySquare } from 'paybysquare-generator';
const qrBuffer = await readFile('./payment-qr.png');
const paymentData = await decodePayBySquare(qrBuffer);
console.log(paymentData.iban, paymentData.amount);
isCompliant(input)
对支付数据进行简单的合规性检查,返回通过或失败结果。
参数:
input: PayBySquareInput- 要验证的支付数据
返回值: boolean - 如果完全合规返回 true,否则返回 false
示例:
import { isCompliant } from 'paybysquare-generator';
const isValid = isCompliant({
iban: 'SK9611000000002918599669',
beneficiaryName: 'Test'
});
console.log(isValid); // true 或 false
checkCompliance(input)
提供详细的合规性报告,包含错误、警告和严重程度级别。
参数:
input: PayBySquareInput- 要验证的支付数据
返回值: Promise<ComplianceResult> - 结构化的合规性报告
示例:
import { checkCompliance } from 'paybysquare-generator';
const report = await checkCompliance(paymentData);
if (!report.isCompliant) {
console.log('错误:', report.errors);
console.log('警告:', report.warnings);
console.log('详情:', report.details);
}
ComplianceResult 接口:
interface ComplianceResult {
isCompliant: boolean;
errors: ComplianceIssue[]; // 阻止支付的关键问题
warnings: ComplianceIssue[]; // 非关键问题
details: {
ibanValid: boolean;
fieldsValid: boolean;
bankingStandardsValid: boolean;
totalIssues: number;
};
}
interface ComplianceIssue {
type: 'error' | 'warning';
field: string;
message: string;
severity: 'critical' | 'major' | 'minor';
}
checkQRCompliance(buffer)
直接从 PNG 缓冲区检查二维码的合规性。
参数:
buffer: Buffer- 包含二维码的 PNG 图像缓冲区
返回值: Promise<ComplianceResult> - 解码数据的合规性报告
verifyRoundTrip(input)
验证支付数据在编码和解码过程中是否无损。
参数:
input: PayBySquareInput- 原始支付数据
返回值: Promise<RoundTripResult> - 往返验证结果
示例:
import { verifyRoundTrip } from 'paybysquare-generator';
const result = await verifyRoundTrip(originalData);
if (!result.isLossless) {
console.log('检测到数据丢失:', result.differences);
}
RoundTripResult 接口:
interface RoundTripResult {
isLossless: boolean;
differences: FieldDifference[];
input: PayBySquareInput; // 原始数据
decoded: PayBySquareInput; // 编码/解码循环后的数据
}
interface FieldDifference {
field: string;
original: any;
decoded: any;
}
输入数据格式
PayBySquareInput
interface PayBySquareInput {
// 必需字段
iban: string; // 例如,"SK9611000000002918599669"
beneficiaryName: string; // 收款人姓名(最多 70 个字符)
// 可选支付详情
amount?: number; // 支付金额(正数)
currency?: string; // ISO 4217 代码(默认: "EUR")
variableSymbol?: string; // 1 - 10 位数字
constantSymbol?: string; // 1 - 4 位数字
specificSymbol?: string; // 1 - 10 位数字
paymentNote?: string; // 最多 140 个字符
dueDate?: string; // ISO 格式: "YYYY-MM-DD"
swift?: string; // SWIFT/BIC 代码
originatorReference?: string; // 参考信息
// 可选收款人地址
beneficiaryAddress?: {
street?: string; // 最多 70 个字符
city?: string; // 最多 70 个字符
};
}
GenerationOptions
interface GenerationOptions {
width?: number; // 二维码宽度(像素)(默认: 300)
margin?: number; // 二维码周围的边距(默认: 4)
errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H'; // 默认: 'M'
color?: {
dark?: string; // 深色(默认: '#000000')
light?: string; // 浅色(默认: '#ffffff')
};
removeAccents?: boolean; // 去除变音符号(默认: true)
}
💻 使用示例
最小支付示例
import { generatePayBySquare } from 'paybysquare-generator';
import { writeFile } from 'fs/promises';
const buffer = await generatePayBySquare({
iban: 'SK9611000000002918599669',
beneficiaryName: 'John Doe'
});
await writeFile('payment.png', buffer);
包含所有字段的完整支付示例
const buffer = await generatePayBySquare({
iban: 'SK9611000000002918599669',
beneficiaryName: 'Acme Corporation',
amount: 150.50,
currency: 'EUR',
variableSymbol: '2026001',
constantSymbol: '0308',
paymentNote: 'Invoice #2026001',
dueDate: '2026-02-15',
swift: 'TATRSKBX',
originatorReference: 'REF-2026-001',
beneficiaryAddress: {
street: 'Business Street 123',
city: 'Bratislava 81108'
}
});
捐赠示例(无固定金额)
// 自愿捐赠可以省略金额
const buffer = await generatePayBySquare({
iban: 'SK9611000000002918599669',
beneficiaryName: 'Charity Organization',
paymentNote: 'Voluntary donation'
});
自定义二维码样式示例
const buffer = await generatePayBySquare(
{
iban: 'SK9611000000002918599669',
beneficiaryName: 'Shop Name',
amount: 99.99
},
{
width: 500, // 更大的二维码
margin: 2, // 更小的边距
errorCorrectionLevel: 'H', // 高纠错级别
color: {
dark: '#1E40AF', // 蓝色二维码
light: '#FFFFFF' // 白色背景
}
}
);
直接保存到文件示例
import { generatePayBySquareToFile } from 'paybysquare-generator';
await generatePayBySquareToFile(
{
iban: 'SK9611000000002918599669',
beneficiaryName: 'Recipient',
amount: 25.00
},
'./payment.png'
);
错误处理示例
import {
generatePayBySquare,
ValidationError,
EncodingError,
GenerationError
} from 'paybysquare-generator';
try {
const buffer = await generatePayBySquare({
iban: 'INVALID',
beneficiaryName: 'Test'
});
} catch (error) {
if (error instanceof ValidationError) {
console.error('输入无效:', error.message);
} else if (error instanceof EncodingError) {
console.error('编码失败:', error.message);
} else if (error instanceof GenerationError) {
console.error('二维码生成失败:', error.message);
}
}
解码二维码示例
import { decodePayBySquare } from 'paybysquare-generator';
import { readFile } from 'fs/promises';
// 从文件读取二维码
const qrBuffer = await readFile('./payment-qr.png');
// 解码支付数据
const paymentData = await decodePayBySquare(qrBuffer);
console.log('IBAN:', paymentData.iban);
console.log('收款人:', paymentData.beneficiaryName);
console.log('金额:', paymentData.amount, paymentData.currency);
console.log('可变符号:', paymentData.variableSymbol);
简单合规性检查示例
import { isCompliant } from 'paybysquare-generator';
const paymentData = {
iban: 'SK9611000000002918599669',
beneficiaryName: 'Test Merchant',
amount: 100,
currency: 'EUR'
};
if (isCompliant(paymentData)) {
console.log('✓ 支付数据有效');
} else {
console.log('✗ 支付数据存在问题');
}
详细合规性报告示例
import { checkCompliance } from 'paybysquare-generator';
const paymentData = {
iban: 'SK9999999999999999999999', // 无效校验和
beneficiaryName: 'Test',
amount: -50, // 负数金额
variableSymbol: 'ABC123', // 应为纯数字
swift: 'INVALID' // 无效 BIC 格式
};
const report = await checkCompliance(paymentData);
console.log('是否合规:', report.isCompliant);
console.log('\n错误:');
report.errors.forEach(err => {
console.log(` [${err.severity}] ${err.field}: ${err.message}`);
});
console.log('\n验证详情:');
console.log(' IBAN 是否有效:', report.details.ibanValid);
console.log(' 字段是否有效:', report.details.fieldsValid);
console.log(' 银行标准是否有效:', report.details.bankingStandardsValid);
console.log(' 总问题数:', report.details.totalIssues);
往返验证示例
import { verifyRoundTrip } from 'paybysquare-generator';
const originalData = {
iban: 'SK9611000000002918599669',
beneficiaryName: 'Test Company',
amount: 250.75,
currency: 'EUR',
variableSymbol: '123456',
paymentNote: 'Testing round-trip'
};
const result = await verifyRoundTrip(originalData);
if (result.isLossless) {
console.log('✓ 数据在编码/解码循环中完美保留!');
} else {
console.log('✗ 检测到数据丢失:');
result.differences.forEach(diff => {
console.log(` ${diff.field}:`);
console.log(` 原始值: ${diff.original}`);
console.log(` 解码后的值: ${diff.decoded}`);
});
}
🔧 技术细节
验证规则
该库对所有输入进行全面验证:
- IBAN:必需,必须是有效格式(2 位国家代码 + 2 位数字 + 11 - 30 位字母数字)
- 收款人姓名:必需,最多 70 个字符
- 金额:可选,提供时必须为正数且有限
- 货币:可选,必须是 3 位 ISO 4217 代码(默认: EUR)
- 可变符号:可选,仅 1 - 10 位数字
- 常量符号:可选,仅 1 - 4 位数字
- 特定符号:可选,仅 1 - 10 位数字
- 支付备注:可选,最多 140 个字符
- 到期日期:可选,必须是 ISO 8601 格式(YYYY - MM - DD)
- 地址字段:可选,每个最多 70 个字符
运行示例
仓库中包含完整的示例:
git clone https://github.com/yourusername/paybysquare-generator
cd paybysquare-generator
npm install
npm run example
这将生成几个不同用例的示例二维码。
运行测试
npm test # 运行一次测试
npm run test:watch # 在监视模式下运行测试
npm run test:coverage # 运行测试并生成覆盖率报告
从源代码构建
npm run build # 将 TypeScript 编译到 dist/ 目录
PayBySquare 标准
该库实现了斯洛伐克银行协会(SBA)定义的 PayBySquare 标准 1.1.0 版本。更多信息:
依赖项
生产环境依赖
- bysquare - 官方 PayBySquare 编码器/解码器
- qrcode - 二维码 PNG 生成器
- jsqr - 二维码扫描器(纯 JavaScript)
- jimp - 用于二维码解码的图像处理库
- ibantools - 带有 mod - 97 校验和的 IBAN 验证库
TypeScript 支持
该库使用 TypeScript 编写,并包含完整的类型定义。所有类型都已导出,方便使用:
import type {
// 输入/输出类型
PayBySquareInput,
BeneficiaryAddress,
GenerationOptions,
// 合规性类型
ComplianceResult,
ComplianceIssue,
ComplianceDetails,
RoundTripResult,
FieldDifference
} from 'paybysquare-generator';
// 错误类也已导出
import {
PayBySquareError,
ValidationError,
EncodingError,
GenerationError,
DecodingError
} from 'paybysquare-generator';
MCP 服务器
该库包含一个 模型上下文协议(MCP)服务器,可将所有功能暴露给 Claude 和其他 MCP 客户端。
可用工具
generate_paybysquare- 根据支付数据生成二维码(保存到文件,返回文件路径)- 必需参数:
beneficiaryName(收款人的全名) - 建议参数:
swift(国际转账的 BIC 代码) - 可选参数:
outputDirectory(自定义保存位置,默认:~/paybysquare-qr-codes/)
- 必需参数:
decode_paybysquare- 将二维码解码为支付数据(从 base64 编码的 PNG 图像)check_compliance- 验证支付数据的合规性,并提供详细的错误报告verify_roundtrip- 验证无损编码/解码(数据完整性检查)
快速设置
- 构建服务器:
npm run build:mcp - 配置 Claude Desktop:
在
claude_desktop_config.json中添加以下内容:{ "mcpServers": { "paybysquare": { "command": "node", "args": ["/absolute/path/to/paybysquare/dist/mcp-server/index.js"] } } } - 重启 Claude Desktop
在 Claude 中的示例用法
配置完成后,你可以使用自然语言进行操作:
为以下信息生成 PayBySquare 二维码:
- IBAN: SK9611000000002918599669
- 收款人: John Doe
- 金额: 100.50 EUR
- SWIFT: TATRSKBX
- 支付备注: Invoice #12345
Claude 将生成二维码并保存到文件,返回:
✓ 二维码生成成功!
文件保存路径: /Users/username/paybysquare-qr-codes/paybysquare-1705331234567-a3f2.png
解码这个 PayBySquare 二维码并告诉我支付详情
[上传图像]
检查以下支付数据是否符合银行标准:
- IBAN: SK9611000000002918599669
- 收款人: Test Company
- 金额: 250 EUR
- SWIFT: TATRSKBX
注意: 二维码默认自动保存到 ~/paybysquare-qr-codes/ 目录。你可以使用 outputDirectory 选项指定自定义目录。
详细的 MCP 服务器文档请参阅 mcp-server/README.md。
📄 许可证
本项目采用 MIT 许可证。
贡献
欢迎贡献代码!请随时提交拉取请求。
相关项目
- bysquare - 官方 PayBySquare 编码器库
- node-qrcode - Node.js 的二维码生成器
支持
如果你遇到任何问题或有疑问,请在 GitHub 上 提交问题。
为斯洛伐克开发者社区用心打造 ❤️
Scan to join WeChat group