phpcfdi/cfdi-cleaner

清理墨西哥CFDI

v1.3.3 2024-06-21 17:47 UTC

This package is auto-updated.

Last update: 2024-09-21 18:19:42 UTC


README

Source Code Packagist PHP Version Support Discord Latest Version Software License Build Status Reliability Maintainability Code Coverage Violations Total Downloads

用于清理墨西哥数字发票(CFDI)的工具。

🇺🇸 该项目的文档使用西班牙语,因为这是目标受众的自然语言。

关于 phpcfdi/cfdi-cleaner

数字发票(CFDI)的XML文件通常包含错误。这个库负责修复已知/常见的错误,以便可以处理它们。

这个库对CFDI的任何操作都不会影响原始字符串的生成或盖章。

安装

使用 composer

composer require phpcfdi/cfdi-cleaner

使用说明

工作类是 \PhpCfdi\CfdiCleaner\Cleaner,并提供以下清理方法

staticClean(string $xml): string

从字符串进行文本和XML文档的清理,并返回清理后的文本表示。

此方法是静态的,因此不需要创建 Cleaner 对象的实例。

<?php
use PhpCfdi\CfdiCleaner\Cleaner;

$xml = file_get_contents('cfdi.xml');
echo Cleaner::staticClean($xml);

cleanStringToString(string $xml): string

从字符串进行文本和XML文档的清理,并返回清理后的文本表示。

<?php
use PhpCfdi\CfdiCleaner\Cleaner;

$xml = file_get_contents('cfdi.xml');
$cleaner = new Cleaner();
echo $cleaner->cleanStringToString($xml);

cleanStringToDocument(string $xml): DOMDocument

从字符串进行文本和XML文档的清理,并返回清理后的XML文档。

此方法非常有用,如果需要立即使用XML文档对象。

<?php
use PhpCfdi\CfdiCleaner\Cleaner;

$xml = file_get_contents('cfdi.xml');
$cleaner = new Cleaner();
$document = $cleaner->cleanStringToDocument($xml);
echo $document->saveXML();

清理操作

可以进行两种类型的清理,一种是在尝试将XML内容加载为DOM对象之前对XML文本进行清理,另一种是在成功加载内容为DOM对象之后进行清理。

对XML文本的清理

这些清理器应在尝试读取XML内容之前执行,它们是为了防止无法创建文档对象。

RemoveNonXmlStrings

删除第一个字符 < 之前的所有内容以及最后一个字符 > 之后的全部内容。

SplitXmlDeclarationFromDocument

使用 LF ("\n") 将XML声明 <?xml version="1.0"?> 从XML主体中分开。

AppendXmlDeclaration

如果不存在,则在文件开始处添加 <?xml version="1.0"?>,这非常有用,因为MIME检测工具如果不能识别文件头,则不会识别XML文件。

XmlNsSchemaLocation

删除SAT(墨西哥税务机关)发出的CFDI中经常出现的错误,其中使用 xmlns:schemaLocation 而不是 xsi:schemaLocation。如果两者都存在,则只保留 xsi:schemaLocation

对XML文档(DOMDocument)的清理

这些清理是在XML文档上进行的。

RemoveAddenda

从命名空间 http://www.sat.gob.mx/cfd/3 中删除任何 Addenda 类型的节点。

RemoveIncompleteSchemaLocations

作用于每个 xsi:schemaLocations

读取内容并尝试解释命名空间和验证方案的位置。为了验证它是一个验证方案,它检查是否以 .xsd 结尾(不区分大小写)。如果没有方案而没有命名空间,则忽略它。如果找到有方案而没有命名空间,则忽略它。

RemoveNonSatNamespacesNodes

检查所有命名空间定义,如果它们不属于URI http://www.sat.gob.mx/** 的命名空间,则删除相关节点和属性。

RemoveNonSatSchemaLocations

作用于每个 xsi:schemaLocations

验证命名空间定义,并删除所有不对应于URI http://www.sat.gob.mx/** 的命名空间对。

RemoveUnusedNamespaces

移除所有未使用的命名空间声明(包括其前缀)。

RenameElementAddPrefix

为未使用简单 xmlns 定义的前缀节点添加前缀。此外,删除多余的命名空间和冗余的 xmlns 定义。

不干净的CFDI示例

<cfdi:Comprobante xmlns="http://www.sat.gob.mx/cfd/4" xmlns:cfdi="http://www.sat.gob.mx/cfd/4">
  <Emisor xmlns="http://www.sat.gob.mx/cfd/4" />
  <cfdi:Receptor xmlns:cfdi="http://www.sat.gob.mx/cfd/4" />
</cfdi:Comprobante>

干净的CFDI示例

<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4">
  <cfdi:Emisor />
  <cfdi:Receptor />
</cfdi:Comprobante>

MoveNamespaceDeclarationToRoot

将所有命名空间声明移动到根节点。

通常SAT要求在技术文档中在根节点定义命名空间,尽管它们通常定义在实现它们的节点上。

有些CFDI极端情况遵循XML规则,但不遵循CFDI规则,生成重叠的前缀。在这种情况下,仅将不重叠的命名空间移动,例如

<?xml version="1.0" encoding="utf-8" ?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3">
  <cfdi:Complemento>
    <cfdi:Otro xmlns:cfdi="http://www.sat.gob.mx/otro" />
    <tfd:TimbreFiscalDigital xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" />
  </cfdi:Complemento>
</cfdi:Comprobante>

生成以下结果

<?xml version="1.0" encoding="utf-8" ?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital">
  <cfdi:Complemento>
    <cfdi:Otro xmlns:cfdi="http://www.sat.gob.mx/otro" />
    <tfd:TimbreFiscalDigital />
  </cfdi:Complemento>
</cfdi:Comprobante>

对于上述情况,未遵循附录20和补充中的既定规则。最好是始终将这种情况视为无效的CFDI,即使已签名,也应请求替换为包含正确命名空间前缀的CFDI。

MoveSchemaLocationsToRoot

将所有架构文件位置声明移动到主节点。

通常SAT要求在技术文档中在主节点定义架构文件位置,尽管它们通常定义在实现它们的节点上。

SetKnownSchemaLocations

验证已知命名空间架构的位置是否完全符合已知地址,如果不一致则进行修改。

以前,SAT允许架构文件位置在不区分大小写的情况下书写,甚至有多个位置来获取这些文件。然而,最近已经取消了对此类位置的容忍,并只允许官方定义。

此清理器根据项目 phpcfdi/sat-ns-registry 的信息,包含命名空间信息、应用版本和已知位置。

如果找不到命名空间的已知路径,则不会应用任何修正,并保留原始值。

CollapseComplemento

此清理器是为了解决SAT文档中的不一致性。

一方面,在CFDI 3.3的附录20中,SAT要求存在一个且仅存在一个 cfdi:Complemento 节点。然而,在验证XSD文件中允许存在多个。

通过这种清理,只保留一个包含所有补充的 cfdi:Complemento 节点。

清理器排除

为了不修改清理器的创建,并允许排除特定清理器,以及因此与库的新更新兼容,可以创建标准清理器,然后应用排除。

以下示例演示了如何排除影响 Addenda 的清理器。

<?php

use PhpCfdi\CfdiCleaner\Cleaner;
use PhpCfdi\CfdiCleaner\ExcludeList;
use PhpCfdi\CfdiCleaner\XmlDocumentCleaners\RemoveAddenda,
use PhpCfdi\CfdiCleaner\XmlDocumentCleaners\RemoveNonSatNamespacesNodes,
use PhpCfdi\CfdiCleaner\XmlDocumentCleaners\RemoveNonSatSchemaLocations,

/**
 * @var string $contents El contenido XML sucio.
 */

$exclude = new ExcludeList(
    RemoveAddenda::class,
    RemoveNonSatNamespacesNodes::class,
    RemoveNonSatSchemaLocations::class,
);

$cleaner = new Cleaner();
$cleaner->exclude($exclude);

$contents = $cleaner->cleanStringToString($contents);

支持

您可以通过在GitHub上创建工单来获得支持。

此外,此库属于 PhpCfdi 社区,因此您可以使用相同的通信渠道从社区成员那里获得帮助。

兼容性

此库将至少保持与最新的具有PHP活跃支持的版本兼容。

我们还使用语义化版本2.0.0,因此你可以放心使用此库而不用担心破坏你的应用程序。

贡献

欢迎贡献。请阅读CONTRIBUTING获取更多详细信息,并记得检查待办事项文件TODO以及变更日志文件CHANGELOG

版权和许可证

phpcfdi/cfdi-cleaner库版权所有© PhpCfdi,许可使用MIT许可证(MIT)。请参阅LICENSE获取更多信息。