phpcfdi / finkok
用于连接 FINKOK 服务 API 的库
Requires
- php: >=7.3
- ext-dom: *
- ext-json: *
- ext-openssl: *
- ext-soap: *
- eclipxe/enum: ^0.2.0
- eclipxe/micro-catalog: ^0.1.0
- phpcfdi/cfdi-expresiones: ^3.2
- phpcfdi/credentials: ^1.0.1
- phpcfdi/xml-cancelacion: ^2.0.2
- psr/log: ^1.1 || ^2.0 || ^3.0
- robrichards/xmlseclibs: ^3.0.4
Requires (Dev)
- ext-fileinfo: *
- eclipxe/cfdiutils: ^2.23.2
- phpcfdi/rfc: ^1.1
- phpunit/phpunit: ^9.5.10
- symfony/dotenv: ^5.1 || ^6.0 || ^7.0
README
用于连接 FINKOK 服务 API(墨西哥)的库
🇺🇸 本项目的文档是西班牙语,因为这是目标受众的自然语言。
关于 phpcfdi/finkok
这个库是 https://www.phpcfdi.com/ 社区为了有一个可以利用 FINKOK 集成商提供的功能而做出的努力。
与 Finkok 无关,Finkok 是 FINKOK, SAPI DE CV 的注册商标。
安装
使用 composer
composer require phpcfdi/finkok
基本用法示例
use PhpCfdi\Finkok\FinkokEnvironment; use PhpCfdi\Finkok\FinkokSettings; use PhpCfdi\Finkok\QuickFinkok; $settings = new FinkokSettings('user@host.com', 'secret', FinkokEnvironment::makeProduction()); $finkok = new QuickFinkok($settings); // el PreCFDI a firmar, podría venir de CfdiUtils ;) $creator->asXml() $precfdi = file_get_contents('precfdi-to-sign.xml'); $stampResult = $finkok->stamp($precfdi); // <- aquí contactamos a Finkok if ($stampResult->hasAlerts()) { // stamp es un objeto con propiedades nombradas foreach ($stampResult->alerts() as $alert) { echo $alert->id() . ' - ' . $alert->message() . PHP_EOL; } } else { file_put_contents($stampResult->uuid() . '.xml', $stampResult->xml()); // CFDI firmado }
还有其他解释性的示例
以及所有集成测试,其中测试了与测试平台的通信和响应。
建议使用 PhpCfdi\Finkok\QuickFinkok
类快速使用 finkok 命令,不过也可以使用完全显式和粒度化的 命令、服务 和 结果 模式。
实现的方法
该库使用基于命令、服务和结果的模型。命令是对我们想要执行的操作的定义,包含所有必要的参数。服务负责使用该命令作为输入,在 Finkok(通过 SOAP)中执行它,并根据响应构建结果。结果是表示响应的数据。
我们没有有意实现需要传输 CSD(数字签名证书)或 eFirma/FIEL(电子签名)的私钥的命令。我们不认为我们会实现它们,因为 a) 不需要,b) 不安全。
打印服务
Finkok 有两种签名方法:stamp
和 quickstamp
。
stamp(Stamping\StampingCommand $command): Stamping\StampingResult
quickstamp(Stamping\StampingCommand $command): Stamping\StampingResult
用于检查是否已生成 CFDI 的 stamped
服务
stamped(Stamping\StampingCommand $command): Stamping\StampingResult
如果使用 pending buffer
,则使用 stampQueryPending
stampQueryPending(Stamping\QueryPendingCommand $command): Stamping\QueryPendingResult
取消服务
只能使用 cancelSignature
通过这个库取消 CFDI,因为这是唯一不需要传输机密信息的命令。
cancelSignature(Cancel\CancelSignatureCommand $command): Cancel\CancelSignatureResult
您可以使用 getSatStatus
查询 CFDI 的状态(取消前后)
getSatStatus(Cancel\GetSatStatusCommand $command): Cancel\GetSatStatusResult
您可以使用 getCancelReceipt
获取取消请求的 SAT 最后收据。虽然请记住,拥有收据并不意味着已取消,收据只包含提交给 SAT 的取消响应。
getCancelReceipt(Cancel\GetReceiptResult $command): Cancel\GetReceiptResult
通过 getPendingToCancel
可以获取由接收方待取消的 CFDI 列表。
getPendingToCancel(Cancel\GetPendingCommand $command): Cancel\GetPendingResult
可以通过使用 getRelatedSignature
获取相关子项(与查询的 UUID 相关)和父项(与查询的 UUID 相关联)。正如 cancelSignature
方法一样,此方法需要签名消息。
getRelatedSignature(Cancel\GetRelatedSignatureCommand $command): Cancel\GetRelatedSignatureResult
此外,可以使用 acceptRejectSignature
接受或拒绝取消请求。此方法可以处理多个 UUID,但 Finkok 建议一次只执行一个。与 cancelSignature
方法一样,此方法需要签名消息。
acceptRejectSignature(Cancel\AcceptRejectSignatureCommand $command): Cancel\AcceptRejectSignatureResult
工具和客户管理
获取 Finkok 的时间(如果遇到 CFDI 时间问题)
datetime(): Utilities\DatetimeResult
获取过去 3 个月内使用 Finkok 签署的 CFDI
downloadXml(Utilities\DownloadXmlCommand $command): Utilities\DownloadXmlResult
获取信用消费和客户管理报告
reportCredit(Utilities\ReportCreditCommand $command): Utilities\ReportCreditResult
reportTotal(Utilities\ReportTotalCommand $command): Utilities\ReportTotalResult
reportUuid(Utilities\ReportUuidCommand $command): Utilities\ReportUuidResult
registrationAdd(Registration\AddCommand $command): Registration\AddResult
registrationAssign(Registration\AssignCommand $command): Registration\AssignResult
registrationEdit(Registration\EditCommand $command): Registration\EditResult
registrationSwitch(Registration\SwitchCommand $command): Registration\SwitchResult
registrationObtain(Registration\ObtainCommand $command): Registration\ObtainResult
registrationCustomers(Registration\ObtainCustomersCommand $command): Registration\ObtainCustomersResult
清单和合同
获取合同和发送签名分别使用 getContracts
和 signContracts
。
getContracts(Manifest\GetContractsCommand $command): Manifest\GetContractsResult
signContracts(Manifest\SignContractsCommand $command): Manifest\SignContractsResult
扣缴
扣缴 CFDI 和付款信息(RET)遵循与 CFDI 3.2 更相似的标准。其取消是即时的(与当前的取消请求不同)。
stamp(Retentions\StampCommand $command): Retentions\StampResult
stamped(Retentions\StampedCommand $command): Retentions\StampedResult
cancelSignature(Retentions\CancelSignatureCommand $command): Retentions\StampedResult
要下载扣缴,应使用预先实现的 Utilerias
服务中的 get_xml
方法。同样,已创建 QuickFinkok::retentionDownload($uuid, $rfc)
方法以简化其实施。
为 SAT 和 Finkok 签署 XML 的帮助
此库实现了与 SAT 消息的 CSD 签署以取消、获取相关 UUID 和接受或拒绝取消请求。创建签名 XML 所涉及的所有逻辑都位于库 phpcfdi/xml-cancelacion
中。
它还实现了与 Finkok 的 清单 的 FIEL 签署。
为这些任务创建了以下对象,以允许执行签名信息
Helpers\CancelSigner
:帮助签署取消请求。Helpers\GetRelatedSigner
:帮助签署相关 UUID 信息请求。Helpers\AcceptRejectSigner
:帮助签署单个 UUID 的取消响应。Helpers\DocumentSigner
:帮助签署 Finkok 的 清单 文档。
此外,这些方法使用库 phpcfdi/credentials
来创建 SAT 或 Finkok 所需的签名和信息。
QuickFinkok
类节省了签署请求数据的过程,并自动执行,但以下示例显示了使用证书和私钥在文件中签署单个 UUID 取消请求的过程。
use PhpCfdi\Credentials\Credential; use PhpCfdi\Finkok\Helpers\CancelSigner; use PhpCfdi\Finkok\Services\Cancel\CancelSignatureCommand; // el objeto con el que se van a firmar las solicitudes $credential = Credential::openFiles('certificate.cer', 'privateKey.pem', 'password'); // el firmador de datos $signer = new CancelSigner(['11111111-2222-3333-4444-000000000001']); $signedXml = $signer->sign($credential); // el comando a pasar al método Finkok::cancelSignature o al comando CancelSignatureService $cancelCommand = new CancelSignatureCommand($signedXml);
实现说明
在实施过程中,我创建了各种笔记和文档
-
取消:取消流程、方法、凭证、待处理缓冲区等信息。
-
服务:服务的基本文档。
-
服务列表:Finkok所有可用的服务列表,包括是否已实施,以及不实施的服务列表。
-
客户登记:如果您要使用Finkok的子分销商功能来管理客户数据。
-
集成测试:集成测试功能和配置环境的文档。
-
发现的问题
- 取消新创建的CFDI
- 使用新创建的CFDI消耗
queryPending
- 使用
stamp
生成双重盖章不返回数据 - 缺少不需要CSD/FIEL即可接受或拒绝取消请求的服务
- 缺少不需要CSD/FIEL即可获取相关CFDI的服务
- 在取消和请求凭证时,提供的取消凭证不一致
- 取消保留1308 - 证书已吊销或过期错误
- 在保留CFDI的取消中缺少
CodEstatus
值 - 使用空
taxpayer_id
的Registration#Get
方法不返回客户列表 - 使用
&
文本盖章返回705 - XML结构无效
捕获HTTP会话
有时,在向Finkok报告问题时,我们需要HTTP会话(请求和响应)以便检查发送的信息。
此库使用PSR-3: Logger Interface生成消息,并在SoapFactory
对象内使用,以创建SoapCaller
对象。此对象发送两种类型的信息:LogLevel::ERROR
在建立服务通信时发生错误,以及LogLevel::DEBUG
在执行SOAP调用时。这两种信息都表示为JSON格式的字符串,因此,为了便于阅读,解码它很重要。
JSON格式更好,因为它允许分析文本并找到特殊字符,而将它们转换为更易于人类理解的文字时,这些特殊字符可能会被隐藏或错误解释。
提供PhpCfdi\Finkok\Helpers\FileLogger
类作为LoggerInterface
的实用工具,将接收到的消息发送到标准输出或文件。
还提供PhpCfdi\Finkok\Helpers\JsonDecoderLogger
类作为LoggerInterface
的实用工具,它解码JSON消息并将其转换为字符串,然后使用print_r()
将其发送到另一个LoggerInterface
对象。
以下示例显示了设置Logger
对象的建议方法,还显示了使用JsonDecoderLogger
将JSON转换为文本以及使用FileLogger
将消息发送到特定文件的方法。
JsonDecoderLogger
可能会丢失信息,但消息更易于理解。如果也想包含JSON消息,可以使用JsonDecoderLogger::setAlsoLogJsonMessage(true)
。
use PhpCfdi\Finkok\FinkokEnvironment; use PhpCfdi\Finkok\FinkokSettings; use PhpCfdi\Finkok\Helpers\FileLogger; use PhpCfdi\Finkok\Helpers\JsonDecoderLogger; $logger = new JsonDecoderLogger(new FileLogger('/tmp/finkok.log')); $logger->setAlsoLogJsonMessage(true); // enviar en texto simple y también en formato JSON $settings = new FinkokSettings('user@host.com', 'secret', FinkokEnvironment::makeProduction()); $settings->soapFactory()->setLogger($logger);
如果您使用Laravel,则已经具有LoggerInterface
的实现,因此建议使用
/** @var \Psr\Log\LoggerInterface $logger */ $logger = app(\Psr\Log\LoggerInterface::class); // Encapsular el logger en el decodificador JSON: $logger = new \PhpCfdi\Finkok\Helpers\JsonDecoderLogger($logger);
兼容性
此库将保持与最新的具有PHP活跃支持版本的兼容性。
我们还使用了语义化版本 2.0.0,因此你可以使用这个库而不用担心破坏你的应用程序。
贡献
欢迎贡献。请阅读CONTRIBUTING以获取更多详细信息,并记得查看待办事项文件TODO以及变更日志文件CHANGELOG。
版权和许可
phpcfdi/finkok库的版权© PhpCfdi,并许可在MIT许可证(MIT)下使用。请参阅LICENSE以获取更多信息。