phpcfdi/sat-estado-cfdi

查询 SAT 官方 web 服务中的 CFDI 状态

v2.0.0 2024-03-07 16:48 UTC

This package is auto-updated.

Last update: 2024-09-07 18:11:35 UTC


README

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

查询 SAT 官方 web 服务中的 CFDI 状态

🇺🇸 此库包含用于消费 SAT 的 CFDI 查询服务 的辅助函数。由于这是目标受众的自然语言,因此此项目的文档是西班牙语。

🇲🇽 此库用于消费 SAT 的 CFDI 查询服务。项目的文档是西班牙语,因为这是将要使用此库的用户使用的语言。

此库仅允许验证 常规 CFDI 的状态,而不是 滞纳金 CFDI 和支付信息 的状态。对于后者,请使用 phpcfdi/sat-estado-retenciones 库。

SAT CFDI 查询服务:

服务近期变更:

  • 由于取消流程的改变,2018 年增加了新的状态。
  • 由于一个无法解释的原因,从 2018 年到 2020 年,WSDL 不可用。此库使用一种策略,不依赖于 WSDL 来消费服务。
  • 2020 年底增加了响应字段 VerificacionEFOS

安装

使用 composer

composer require phpcfdi/sat-estado-cfdi

基本使用示例

基本步骤如下

  • 拥有一个实现 ConsumerClientInterface 的客户端。
  • 创建服务消费者 Consumer
  • 使用定义的表达式进行请求。
  • 使用结果
<?php
use PhpCfdi\SatEstadoCfdi\Consumer;
use PhpCfdi\SatEstadoCfdi\Contracts\ConsumerClientInterface;

/** @var ConsumerClientInterface $client */
$consumer = new Consumer($client);

$cfdiStatus = $consumer->execute('...expression');

if ($cfdiStatus->cancellable->isNotCancellable()) {
    echo 'CFDI no es cancelable';
}

消费客户端 ConsumerClientInterface

此库包括两个不同的消费客户端:SoapConsumerClientHttpConsumerClient

此外,您可以自己实现消费客户端,实现 ConsumerClientInterface 接口。

SOAP 客户端 SoapConsumerClient

SoapConsumerClient 客户端允许使用 SOAP 策略进行消费。

要求

  • ext-soap:PHP SOAP 扩展。

示例

<?php
use PhpCfdi\SatEstadoCfdi\Clients\Soap\SoapConsumerClient;
use PhpCfdi\SatEstadoCfdi\Consumer;

function createConsumerUsingSoap(): Consumer
{
    $client = new SoapConsumerClient();
    return new Consumer($client);
}

HTTP PSR 客户端 HttpConsumerClient

HttpConsumerClient 客户端允许使用基于 PSR 的 HTTP 策略进行消费。

使用标准

Guzzle 库 guzzlehttp/guzzleguzzlehttp/psr7 提供了必需的标准。

你可以在 Packagist 上查看你喜欢的库

要求

  • ext-dom: PHP的DOM扩展。
  • psr/http-client: ^1.0: PSR-18标准(HTTP客户端)。
  • psr/http-factory: ^1.0: PSR-17标准(HTTP消息工厂)。
  • 一些实现了PSR-18和PSR-17的库,例如
    • Guzzle: guzzlehttp/guzzleguzzlehttp/psr7
    • Symfony: symfony/http-clientnyholm/psr7laminas/laminas-diactoros

示例

<?php
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerClient;
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerFactory;
use PhpCfdi\SatEstadoCfdi\Consumer;

function createConsumerUsingGuzzle(): Consumer
{
    // Implements PSR-18 \Psr\Http\Client\ClientInterface
    $guzzleClient = new \GuzzleHttp\Client();
    // Implements PSR-17 \Psr\Http\Message\RequestFactoryInterface and PSR-17 \Psr\Http\Message\StreamFactoryInterface
    $guzzleFactory = new \GuzzleHttp\Psr7\HttpFactory();

    $factory = new HttpConsumerFactory($guzzleClient, $guzzleFactory, $guzzleFactory);
    $client = new HttpConsumerClient($factory);
    return new Consumer($client);
}

以下是一个使用 symfony/http-clientnyholm/psr7 的例子

use PhpCfdi\SatEstadoCfdi\Consumer;
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerClient;
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerFactory;

function createConsumerUsingSymfonyNyholm(): Consumer
{
    $httpClient = new \Symfony\Component\HttpClient\Psr18Client();
    $messageFactory = new \Nyholm\Psr7\Factory\Psr17Factory();
    
    $factory = new HttpConsumerFactory($httpClient, $messageFactory, $messageFactory);
    $client = new HttpConsumerClient($factory);
    return new Consumer($client);
}

对于Laravel,你可以使用一些额外的包,例如 wimski/laravel-psr-http,它利用了自身的框架和 php-http/discovery,使得创建对象更加方便,无论是直接通过容器创建,还是作为依赖项注入。

<?php
use PhpCfdi\SatEstadoCfdi\Consumer;
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerClient;
use PhpCfdi\SatEstadoCfdi\Clients\Http\HttpConsumerFactory;

function createConsumerUsingLaravel(): Consumer
{
    $httpClient = app(\Psr\Http\Client\ClientInterface::class);
    $requestFactory = app(Psr\Http\Message\RequestFactoryInterface::class);
    $streamFactory = app(Psr\Http\Message\StreamFactoryInterface::class);
    
    $factory = new HttpConsumerFactory($httpClient, $requestFactory, $streamFactory);
    $client = new HttpConsumerClient($factory);
    return new Consumer($client);
}

我还建议你创建自己的 Service Provider 或配置 Service Container,并且只要求类 Consumer 作为任何其他依赖项,并允许它被注入。

表达式(输入)

消费者需要一个表达式来查询。这个表达式是打印出来的CFDI表示中的二维码中的文本。

表达式对于CFDI 3.2、CFDI 3.3、CFDI 4.0、RET 1.0和RET 2.0是不同的。它们有特定的格式规则和包含的信息规则。

如果你没有表达式,我建议你使用库 phpcfdi/cfdi-expresiones,你可以使用 composer require phpcfdi/cfdi-expresiones 来安装。

<?php
use PhpCfdi\CfdiExpresiones\DiscoverExtractor;
use PhpCfdi\SatEstadoCfdi\Consumer;

// lectura del contenido del CFDI
$document = new DOMDocument();
$document->load('archivo-cfdi.xml');

// creación de la expresión
$expressionExtractor = new DiscoverExtractor();
$expression = $expressionExtractor->extract($document);

// realizar la consulta con la expresión obtenida
/** @var Consumer $consumer */
$cfdiStatus = $consumer->execute($expression);

// usar el estado
if ($cfdiStatus->document->isActive()) {
    echo 'El CFDI se encuentra vigente';
}

状态(输出)

在消费服务后,将返回一个包含四个状态的 CfdiStatus 对象。

状态是枚举,你可以使用辅助方法 is* 快速比较,例如:$response->document->isCancelled()

可能的状态

  • CodigoEstatus: query: QueryStatus

    • Found: 如果状态以 S - 开头。
    • NotFound: 在其他情况下。
  • Estado: document: DocumentStatus

    • Active: 如果状态报告了 Vigente
    • Cancelled: 如果状态报告了 Cancelado
    • NotFound: 在其他情况下。
  • EsCancelable: cancellable: CancellableStatus

    • CancellableByDirectCall: 如果状态报告了 Cancelable sin aceptación
    • CancellableByApproval: 如果状态报告了 Cancelable con aceptación
    • NotCancellable: 在其他情况下。
  • EstatusCancelacion: cancellation: CancellationStatus

    • CancelledByDirectCall: 如果状态报告了 Cancelado sin aceptación
    • CancelledByApproval: 如果状态报告了 Cancelado con aceptación
    • CancelledByExpiration: 如果状态报告了 Plazo vencido
    • Pending: 如果状态报告了 En proceso
    • Disapproved: 如果状态报告了 Solicitud rechazada
    • Undefined: 在其他情况下。
  • ValidacionEFOS: efos: EfosStatus

    • Included: 如果状态没有报告 200201
    • Excluded: 如果状态报告了 200201

相互排斥的状态

当你有一个状态为 Cancelable with acceptance 的CFDI并提交取消请求时,其取消状态将变为 In process

接收者可以接受取消请求(Cancelled with acceptance)或拒绝取消请求(Disapproved)。

如果是第一次提交申请,接收方有72小时的时间来接受或拒绝,如果未在规定时间内处理,则申请将自动取消(逾期)。

即使申请之前已被拒绝,你也可以再次提交取消申请的请求。

在这种情况下,接收方可以接受或拒绝取消申请,但不再适用72小时的期限。因此,CFDI的状态可能会无限期地保持在取消中,甚至可能是在预期时间之后的几个月。

兼容性

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

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

贡献

欢迎贡献。请阅读CONTRIBUTING以获取更多详细信息,并请记住查看TODO文件和变更日志文件。

版权和许可

phpcfdi/sat-estado-cfdi库版权归PhpCfdi所有,并许可在MIT许可(MIT)下使用。有关更多信息,请参阅LICENSE