Back to MCP directory
publicPublicdnsLocal runtime

pbsq-sk

一个用于生成、解码和验证PayBySquare支付二维码的Node.js/TypeScript库,支持完整的支付字段、合规性检查,并提供MCP服务器集成,便于与Claude等AI助手交互使用。

article

README

🚀 PayBySquare 生成器

PayBySquare 生成器是一个全面的 Node.js/TypeScript 库,用于生成、解码和验证支付二维码。PayBySquare 是斯洛伐克银行协会(SBA)采用的支付二维码国家标准。

npm 版本 许可证:MIT

✨ 主要特性

生成功能

  • ✅ 基于简单的 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 - 验证无损编码/解码(数据完整性检查)

快速设置

  1. 构建服务器:
    npm run build:mcp
    
  2. 配置 Claude Desktop:claude_desktop_config.json 中添加以下内容:
    {
      "mcpServers": {
        "paybysquare": {
          "command": "node",
          "args": ["/absolute/path/to/paybysquare/dist/mcp-server/index.js"]
        }
      }
    }
    
  3. 重启 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 许可证。

贡献

欢迎贡献代码!请随时提交拉取请求。

相关项目

支持

如果你遇到任何问题或有疑问,请在 GitHub 上 提交问题


为斯洛伐克开发者社区用心打造 ❤️

help

Runtime guide

cloud

Hosted runtime

Hosted servers run from a provider-managed environment. You usually connect the MCP client to the hosted endpoint or follow the provider's authorization flow, without keeping a local process alive

  1. Open provider connection page
  2. Authorize or copy endpoint
  3. Connect from your MCP client
terminal

Local runtime / other methods

Local servers run on your own machine or infrastructure. You normally copy the server_config into your MCP client, install the required package, and provide env variables from env_schema when needed

  1. Copy server_config
  2. Install required package
  3. Fill env variables and restart client