# 开发文档

#### 所有文档

[官方对接地址 文件统计](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU.html)

- [<span dir="auto"><span dir="auto">计费记录设计文档</span></span>](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/Documento_Diseno_de_registro_de_facturacion/Documento_Diseno_de_registro_de_facturacion.html)
- [<span dir="auto"><span dir="auto">验证和错误</span></span>](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/Validaciones_y_errores/Validaciones_y_errores.html)
- [<span dir="auto"><span dir="auto">Web 服务描述文档（v1.0.3）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Veri-Factu_Descripcion_SWeb.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（1.673 KB）</span></span></span>
- [<span dir="auto"><span dir="auto">Web 服务描述文档（v1.0.3，英文版）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Veri-Factu_Descripcion_SWeb_EN.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（1,715 KB）</span></span></span>
- [<span dir="auto"><span dir="auto">Web 服务的 WSDL</span></span>](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/WSDL_de_los_servicios_web/WSDL_de_los_servicios_web.html)
- [<span dir="auto"><span dir="auto">Web 服务示意图</span></span>](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/Esquemas_de_los_servicios_web/Esquemas_de_los_servicios_web.html)
- [<span dir="auto"><span dir="auto">生成记录指纹或哈希的技术规范详情（v0.1.2）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Veri-Factu_especificaciones_huella_hash_registros.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（1.11 MB）</span></span></span>
- [<span dir="auto"><span dir="auto">发票二维码技术规格说明文档（v0.4.7）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/DetalleEspecificacTecnCodigoQRfactura.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（1.9 MB）</span></span></span>
- <span style="color: rgb(224, 62, 45);">[<span dir="auto"><span dir="auto">生成账单记录电子签名的技术规范</span></span>](https://www.agenciatributaria.es/AEAT.desarrolladores/Desarrolladores/_menu_/Documentacion/Sistemas_Informaticos_de_Facturacion_y_Sistemas_VERI_FACTU/Especificaciones_tecnicas_para_generacion_de_la_firma_electronica_de_los_registros_de_facturacion/Especificaciones_tecnicas_para_generacion_de_la_firma_electronica_de_los_registros_de_facturacion.html)</span>
    - <span style="color: rgb(224, 62, 45);">[<span dir="auto"><span dir="auto">生成账单记录电子签名的技术规范（v0.1.5）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Espec-Tecnicas/EspecTecGenerFirmaElectRfact.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（1.46 MB） 这个暂不开发 NO VERIFACTU </span></span></span></span>
    - <span style="color: rgb(224, 62, 45);">[<span dir="auto"><span dir="auto">ZIP文件：包含账单记录签名样本的附件</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Espec-Tecnicas/AnexosEjemplosFirmaRegFact.zip) ![ZIP压缩文件](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_zip.png "ZIP压缩文件") <span class="letrita"><span dir="auto"><span dir="auto">（5.74 KB）</span></span></span></span>
- <span style="color: rgb(224, 62, 45);">[<span dir="auto"><span dir="auto">无法核实的计费记录验证服务说明文档（v0.2）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Descripcion_ServicioWeb_ValidacionNoVerifactu.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（576 KB） 这个暂不开发 NO VERIFACTU </span></span></span></span>
- [<span dir="auto"><span dir="auto">开发公司常见问题解答（更新于 2025 年 9 月 19 日）</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/FAQs-Desarrolladores.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（666 KB）</span></span></span>
- [<span dir="auto"><span dir="auto">负责任声明示例</span></span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/EjemplosDeclaracionResponsable.pdf) ![PDF文档](https://www.agenciatributaria.es/static_files/common/internet/img/icos/ico_pdf.gif "PDF文档") <span class="letrita"><span dir="auto"><span dir="auto">（708 KB）</span></span></span>

##### 测试环境（带证书） 

发送票务地址：

https://prewww10.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP

##### 生产环境 （带证书）

发送票务地址：

[https://www10.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP](https://www10.agenciatributaria.gob.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP)

<div class="line" id="bkmrk-%3Csum1%3Adetalledesglos"><span class="html-tag">&lt;sum1:DetalleDesglose&gt;</span></div><div class="opened" id="bkmrk-%3Csum1%3Aclaveregimen%3E0"><div class="line"><span class="html-tag">&lt;sum1:ClaveRegimen&gt;</span>01<span class="html-tag">&lt;/sum1:ClaveRegimen&gt;</span></div><div class="line"><span class="comment html-comment">&lt;!-- 税务制度代码（01=普通IVA） --&gt;</span></div><div class="line"><span class="html-tag">&lt;sum1:CalificacionOperacion&gt;</span>S1<span class="html-tag">&lt;/sum1:CalificacionOperacion&gt;</span></div><div class="line"><span class="comment html-comment">&lt;!-- 操作类型 --&gt;</span></div><div class="line"><span class="html-tag">&lt;sum1:TipoImpositivo&gt;</span>4<span class="html-tag">&lt;/sum1:TipoImpositivo&gt;</span></div><div class="line"><span class="comment html-comment">&lt;!-- 税率4% --&gt;</span></div><div class="line"><span class="html-tag">&lt;sum1:BaseImponibleOimporteNoSujeto&gt;</span>10<span class="html-tag">&lt;/sum1:BaseImponibleOimporteNoSujeto&gt;</span></div><div class="line"><span class="comment html-comment">&lt;!-- 不含税金额 --&gt;</span></div><div class="line"><span class="html-tag">&lt;sum1:CuotaRepercutida&gt;</span>0.4<span class="html-tag">&lt;/sum1:CuotaRepercutida&gt;</span></div><div class="line"><span class="comment html-comment">&lt;!-- 税额 --&gt;</span></div></div><div class="line" id="bkmrk-%3C%2Fsum1%3Adetalledesglo"><span class="html-tag">&lt;/sum1:DetalleDesglose</span></div>##### 常用节点意思介绍

<table id="bkmrk-%E8%8A%82%E7%82%B9-%E5%90%AB%E4%B9%89-%E5%8F%AF%E7%94%A8%E5%80%BC-%2F-%E6%A0%BC%E5%BC%8F-%E8%AF%B4%E6%98%8E-%3Cs"><thead><tr><th>节点</th><th>含义</th><th>可用值 / 格式</th><th>说明</th></tr></thead><tbody><tr><td>`<sum1:Subsanacion>`</td><td>修正标志</td><td>`S` 或 省略</td><td>`S` 表示此记录为修正（例如纠正错误或重新提交）</td></tr><tr><td>`<sum1:TipoFactura>`</td><td>发票类型</td><td>`F1` 普通发票`F2` 简易发票`R1` 作废`R2` 更正`R3` 替换</td><td>可以参见 TipoFactura 段落  
  
</td></tr><tr><td>`<sum1:ClaveRegimen>`</td><td>税制代码</td><td>`01` 普通制度`02` 简易制度`03` 免税</td><td>取决于发票适用税法</td></tr><tr><td>`<sum1:CalificacionOperacion>`</td><td>交易类型</td><td>`S1` 受IVA约束`N1` 不受约束`E1` 免税</td><td>常见餐饮类一般使用 `S1`</td></tr><tr><td>`<sum1:TipoImpositivo>`</td><td>税率</td><td>4, 10, 21 , 0 几种税率</td><td>西班牙标准IVA税率</td></tr><tr><td>`<sum1:TipoHuella>`</td><td>指纹类型</td><td>`01`</td><td>表示 SHA-256 Base64</td></tr><tr><td>`<sum1:TipoUsoPosibleSoloVerifactu>`</td><td>是否专属VeriFactu</td><td>`S` 或 `N`</td><td>如果你的系统只用于VeriFactu，则为 `S`</td></tr><tr><td>`<sum1:TipoUsoPosibleMultiOT>`</td><td>是否支持多义务人</td><td>`S` 或 `N`</td><td>SaaS类一般 `S`</td></tr><tr><td>`<sum1:IndicadorMultiplesOT>`</td><td>是否有多个义务人使用中</td><td>`S` 或 `N`</td><td>如果服务器下多家餐厅，则为 `S`</td></tr><tr><td>`<sum1:NumeroInstalacion>`</td><td>安装编号</td><td>数字或字符串</td><td>每个部署/门店唯一</td></tr><tr><td>`<sum1:Huella>`</td><td>指纹</td><td>Base64 编码字符串</td><td>SHA-256(关键字段串联)</td></tr></tbody></table>

##### TipoFactura 的几种类型

<table class="w-fit min-w-(--thread-content-width)" data-end="1119" data-start="135" id="bkmrk-c%C3%B3digo-%E5%90%8D%E7%A7%B0-%E9%80%82%E7%94%A8%E6%83%85%E5%BD%A2-%E5%85%B3%E9%94%AE%E7%82%B9-f"><thead data-end="163" data-start="135"><tr data-end="163" data-start="135"><th data-col-size="sm" data-end="144" data-start="135">Código</th><th data-col-size="md" data-end="149" data-start="144">名称</th><th data-col-size="sm" data-end="156" data-start="149">适用情形</th><th data-col-size="md" data-end="163" data-start="156">关键点</th></tr></thead><tbody data-end="1119" data-start="207"><tr data-end="370" data-start="207"><td data-col-size="sm" data-end="216" data-start="207">**F1**</td><td data-col-size="md" data-end="279" data-start="216">**Factura completa**  
(Art. 6, 7.2 y 7.3 del RD 1619/2012)</td><td data-col-size="sm" data-end="301" data-start="279">标准完整发票，识别买方、含增值税细节。</td><td data-col-size="md" data-end="370" data-start="301">是最常见的发票类型。必须包含：  
- 客户身份（NIF / NombreRazon）  
- 分项税额 (Desglose)</td></tr><tr data-end="489" data-start="371"><td data-col-size="sm" data-end="380" data-start="371">**F2**</td><td data-col-size="md" data-end="436" data-start="380">**Factura simplificada**  
(Art. 6.1.d RD 1619/2012)</td><td data-col-size="sm" data-end="462" data-start="436">金额较小、无需识别买方的发票（小票、餐饮等）。</td><td data-col-size="md" data-end="489" data-start="462">通常对应 **Ticket**。买方信息可选。</td></tr><tr data-end="646" data-start="490"><td data-col-size="sm" data-end="499" data-start="490">**F3**</td><td data-col-size="md" data-end="562" data-start="499">**Factura emitida en sustitución de facturas simplificadas**</td><td data-col-size="sm" data-end="595" data-start="562">当企业把之前已申报的简易发票（F2）替换为完整发票（F1）。</td><td data-col-size="md" data-end="646" data-start="595">属于**更正性质的“补开发票”**，用于“由 ticket 转发票”。这正是你现在在做的情况。</td></tr><tr data-end="792" data-start="647"><td data-col-size="sm" data-end="656" data-start="647">**R1**</td><td data-col-size="md" data-end="730" data-start="656">**Factura rectificativa** (Art. 80.1 y 80.2 y error fundado en derecho)</td><td data-col-size="sm" data-end="757" data-start="730">纠正税基、税率或金额错误（因判决、行政原因等）。</td><td data-col-size="md" data-end="792" data-start="757">Rectificación 依据法条 80.1 / 80.2。</td></tr><tr data-end="882" data-start="793"><td data-col-size="sm" data-end="802" data-start="793">**R2**</td><td data-col-size="md" data-end="842" data-start="802">**Factura rectificativa** (Art. 80.3)</td><td data-col-size="sm" data-end="863" data-start="842">因退货、折扣、无效合同等导致的修正。</td><td data-col-size="md" data-end="882" data-start="863">对应业务更改（例如取消销售）。</td></tr><tr data-end="962" data-start="883"><td data-col-size="sm" data-end="892" data-start="883">**R3**</td><td data-col-size="md" data-end="932" data-start="892">**Factura rectificativa** (Art. 80.4)</td><td data-col-size="sm" data-end="950" data-start="932">客户破产或无力偿付引起的修正。</td><td data-col-size="md" data-end="962" data-start="950">专用于破产情形。</td></tr><tr data-end="1036" data-start="963"><td data-col-size="sm" data-end="972" data-start="963">**R4**</td><td data-col-size="md" data-end="1008" data-start="972">**Factura rectificativa (Resto)**</td><td data-col-size="sm" data-end="1024" data-start="1008">其他未涵盖情形的更正发票。</td><td data-col-size="md" data-end="1036" data-start="1024">一般性修正用途。</td></tr><tr data-end="1119" data-start="1037"><td data-col-size="sm" data-end="1046" data-start="1037">**R5**</td><td data-col-size="md" data-end="1087" data-start="1046">**Factura rectificativa simplificada**</td><td data-col-size="sm" data-end="1100" data-start="1087">针对简易发票的修正。</td><td data-col-size="md" data-end="1119" data-start="1100">通常用于 ticket 更正。</td></tr></tbody></table>

#### QR 生成地址 以及规则

 QR 尺寸 40\*40 mm

以地址为准生成 QR 码，并在下方 打印： Factura verificable en la sede electrónica de la AEAT

##### 测试环境地址：

https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?nif=XXXXXXXXY&amp;numserie=YYYY...YYYY&amp;fecha=DD- DD-AAAA&amp;importe=NNNNNNNNN.DD

##### 生产环境地址：

<div id="bkmrk-https%3A%2F%2Fwww2.agencia">https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=XXXXXXXXY&amp;numserie=YYYY...YYYY&amp;fecha=DD- DD-AAAA&amp;importe=NNNNNNNNN.DD</div>XML 返回的资料进行拼接 " &amp;" = " 链接 xia

nif= XXXXXXXXXXXX &amp;numseria= 123456 &amp;fecha= &amp;importe=

 URL base: https://prewww2.aeat.es/wlpl/TIKE-CONT/ValidarQR?   
 Parámetro nif: 89890001K   
 Parámetro numserie: 12345678&amp;G33   
 Parámetro fecha: 01-01-2024   
 Parámetro importe: 241.4

### 开发流程

设置中 添加 加载电子证书按钮 + 密码框 ， 解析 + 使用

#####  1 - 解析证书 （ 获取证书中的 ID, 姓名资料 ） 

- CN ： CERTIFICADO FISICA PRUEBAS -99999910G' （- 前是公司/个人名字 - 后面是税号）
- SN ： 公司或者个人名称
- O : 有这个字段代表公司 否则是个人
- SERIALNUMBER - 后面是 税号  
    C 是国家
- NotAfter 证书到期时间

参考一下代码

```c#
using System;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;

namespace CertInfoExtractor
{
    public enum CertType
    {
        Unknown,
        Personal,
        Organization
    }

    public class CertInfo
    {
        public CertType Type { get; set; }
        public string Name { get; set; }           // 姓名或公司名
        public string TaxNumber { get; set; }      // 税号 / NIF / CIF
        public DateTime NotAfter { get; set; }     // 到期时间
        public int DaysRemaining { get; set; }     // 剩余天数
    }

    public class CertParser
    {
        public static CertInfo Parse(string pfxPath, string password)
        {
            var cert = new X509Certificate2(pfxPath, password,
                X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);

            string subject = cert.Subject;
            string issuer = cert.Issuer;

            string cn = GetField(subject, "CN");
            string org = GetField(subject, "O");
            string serial = GetField(subject, "SERIALNUMBER");

            // 税号兜底正则
            if (string.IsNullOrEmpty(serial))
            {
                var m = Regex.Match(subject, @"(SERIALNUMBER|NIF|CIF|NIE|UID)\s*=\s*([A-Z0-9\-\/]{6,20})",
                    RegexOptions.IgnoreCase);
                if (m.Success)
                    serial = m.Groups[2].Value.Trim();
            }

            // 判断类型
            CertType type = DetectType(org, serial, issuer);

            // 名称：企业用 O，个人用 CN
            string name = (type == CertType.Organization && !string.IsNullOrEmpty(org))
                ? org
                : cn;

            var notAfter = cert.NotAfter;
            int daysRemaining = (int)(notAfter - DateTime.Now).TotalDays;

            return new CertInfo
            {
                Type = type,
                Name = name,
                TaxNumber = serial,
                NotAfter = notAfter,
                DaysRemaining = daysRemaining
            };
        }

        private static CertType DetectType(string org, string serial, string issuer)
        {
            bool hasOrg = !string.IsNullOrEmpty(org);
            bool looksLikeCompanyId = Regex.IsMatch(serial ?? "", @"^[A-Z]\d{7,8}", RegexOptions.IgnoreCase);
            bool looksLikePersonId = Regex.IsMatch(serial ?? "", @"\d{7,8}[A-Z]$", RegexOptions.IgnoreCase);

            if (hasOrg || looksLikeCompanyId)
                return CertType.Organization;
            if (looksLikePersonId)
                return CertType.Personal;

            if (issuer.Contains("Persona Física", StringComparison.OrdinalIgnoreCase))
                return CertType.Personal;
            if (issuer.Contains("Representante", StringComparison.OrdinalIgnoreCase))
                return CertType.Organization;

            return CertType.Unknown;
        }

        private static string GetField(string subject, string key)
        {
            var m = Regex.Match(subject, key + @"\s*=\s*([^,]+)", RegexOptions.IgnoreCase);
            return m.Success ? m.Groups[1].Value.Trim() : null;
        }

        // 测试入口
        public static void Main()
        {
            string pfxPath = @"C:\certs\yourcert.pfx";
            string password = "yourPassword";

            var info = Parse(pfxPath, password);

            Console.WriteLine("🔍 证书类型: " + info.Type);
            Console.WriteLine("📛 名称: " + info.Name);
            Console.WriteLine("🧾 税号: " + info.TaxNumber);
            Console.WriteLine("📅 到期时间: " + info.NotAfter.ToString("yyyy-MM-dd HH:mm:ss"));
            Console.WriteLine("⏳ 剩余天数: " + info.DaysRemaining);
        }
    }
}

```

##### 系统信息部分 SistemaInformatico XML 

```xml
               <sum1:SistemaInformatico> 
                  <sum1:NombreRazon>JIECHENG INFORMATICA SL</sum1:NombreRazon>                   
                  <sum1:NIF>B67287789</sum1:NIF> 
                  <sum1:NombreSistemaInformatico>JIECHENG TPV</sum1:NombreSistemaInformatico> 
                  <sum1:IdSistemaInformatico>J2</sum1:IdSistemaInformatico> 
                  <sum1:Version>1.0.03</sum1:Version> 
                  <sum1:NumeroInstalacion>383</sum1:NumeroInstalacion>   // 主机1 副机 2
                  <sum1:TipoUsoPosibleSoloVerifactu>N</sum1:TipoUsoPosibleSoloVerifactu> 
                  <sum1:TipoUsoPosibleMultiOT>S</sum1:TipoUsoPosibleMultiOT> 
                  <sum1:IndicadorMultiplesOT>S</sum1:IndicadorMultiplesOT> 
               </sum1:SistemaInformatico> 
```

#### 🔒 针对 .NET Framework 4.0 的解决方案

要解决 **403 错误**（极有可能是 TLS 版本不兼容），您需要执行以下两个关键步骤：

##### 1. 强制启用 TLS 1.2（最关键步骤）

在 .NET Framework 4.0 中，您需要通过代码显式设置 **`ServicePointManager.SecurityProtocol`**。但是，**TLS 1.1** 和 **TLS 1.2** 枚举值在 .NET Framework **4.5** 版本中才被正式引入。

**解决方案（通过类型转换）：**

您必须使用其底层整数值来引用 **TLS 1.1** 和 **TLS 1.2**，以绕过编译时缺少枚举的问题。

<div _ngcontent-ng-c3292687821="" class="code-block ng-tns-c3292687821-46 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiZp6Sy1rCRAxUAAAAAHQAAAAAQOg" decode-data-ved="1" id="bkmrk-c%23" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_6939ac24b4de3970","c_5be2d685494dbfce",null,"rc_f75f93d6ff7e1687",null,null,"zh",null,1,null,null,1,0]]"><div _ngcontent-ng-c3292687821="" class="code-block-decoration header-formatted gds-title-s ng-tns-c3292687821-46 ng-star-inserted"><span class="ng-tns-c3292687821-46">C#</span><div _ngcontent-ng-c3292687821="" class="buttons ng-tns-c3292687821-46 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c3292687821-46 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c3292687821="" class="formatted-code-block-internal-container ng-tns-c3292687821-46"><div _ngcontent-ng-c3292687821="" class="animated-opacity ng-tns-c3292687821-46">  
</div></div></div>```
using System.Net;

// 检查您的项目是否已经引用了 System.Net.dll

// 1. 定义或使用 TLS 1.2 和 TLS 1.1 的数值
// Tls12 = 3072 (十六进制 0xC00)
// Tls11 = 768 (十六进制 0x300)
const SslProtocols Tls12 = (SslProtocols)3072;
const SslProtocols Tls11 = (SslProtocols)768;
const SslProtocols SystemDefault = (SslProtocols)0; // SystemDefault 是 .NET 4.6.2+ 才有的，在 4.0 中忽略

public static void EnableTls12()
{
    // 强制全局使用 Tls12 和 Tls11（和旧的 Tls/Ssl3 兼容）
    ServicePointManager.SecurityProtocol = 
        (SecurityProtocolType)Tls12 | 
        (SecurityProtocolType)Tls11 | 
        SecurityProtocolType.Tls; 
        // SecurityProtocolType.Tls 对应 TLS 1.0
}

// 在应用程序启动或发送请求前调用此方法
EnableTls12();

```

<div _ngcontent-ng-c3292687821="" class="code-block ng-tns-c3292687821-46 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiZp6Sy1rCRAxUAAAAAHQAAAAAQOg" decode-data-ved="1" id="bkmrk--3" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_6939ac24b4de3970","c_5be2d685494dbfce",null,"rc_f75f93d6ff7e1687",null,null,"zh",null,1,null,null,1,0]]"><div _ngcontent-ng-c3292687821="" class="formatted-code-block-internal-container ng-tns-c3292687821-46"><div _ngcontent-ng-c3292687821="" class="animated-opacity ng-tns-c3292687821-46"></div></div></div>**注意：** 您必须确保您的运行环境（运行您的程序的机器）已经安装了 **.NET Framework 4.0 的最新更新**，以确保底层操作系统（Windows）支持 TLS 1.2。

---

##### 2. 证书加载和附加到 WebRequest 🔑

由于 .NET Framework 4.0 没有 `HttpClient` 类（它是在 4.5 引入的），您通常会使用 **`HttpWebRequest`** 类来发送请求。

**证书加载代码（与之前类似）：**

<div _ngcontent-ng-c3292687821="" class="code-block ng-tns-c3292687821-47 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiZp6Sy1rCRAxUAAAAAHQAAAAAQOw" decode-data-ved="1" id="bkmrk-c%23-1" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_6939ac24b4de3970","c_5be2d685494dbfce",null,"rc_f75f93d6ff7e1687",null,null,"zh",null,1,null,null,1,0]]"><div _ngcontent-ng-c3292687821="" class="code-block-decoration header-formatted gds-title-s ng-tns-c3292687821-47 ng-star-inserted"><span class="ng-tns-c3292687821-47">C#</span><div _ngcontent-ng-c3292687821="" class="buttons ng-tns-c3292687821-47 ng-star-inserted"><button aria-label="Copiar código" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-mdc-tooltip-trigger copy-button ng-tns-c3292687821-47 mat-unthemed ng-star-inserted"></button></div></div><div _ngcontent-ng-c3292687821="" class="formatted-code-block-internal-container ng-tns-c3292687821-47"><div _ngcontent-ng-c3292687821="" class="animated-opacity ng-tns-c3292687821-47">  
</div></div></div>```
using System.Security.Cryptography.X509Certificates;
using System.Net;

// ... (您的 CertParser.Parse 方法) ...

// 假设这是您获取证书的方法
X509Certificate2 clientCert = new X509Certificate2(
    pfxPath, 
    password, 
    // 再次强调，使用 UserKeySet 确保私钥在当前用户下可访问
    X509KeyStorageFlags.Exportable | 
    X509KeyStorageFlags.PersistKeySet | 
    X509KeyStorageFlags.UserKeySet 
);

if (!clientCert.HasPrivateKey)
{
    throw new InvalidOperationException("Private key is missing/inaccessible.");
}

// ----------------------------------------------------------------

// HTTP 请求发送代码
public void SendVerifactuRequest(string url, X509Certificate2 cert)
{
    // 确保 TLS 1.2 已启用 (见上一步)
    EnableTls12(); 

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/json"; // 或 VeriFactu 要求的其他类型

    // ⭐️ 关键：将客户端证书添加到请求中
    request.ClientCertificates.Add(cert);

    try
    {
        // 写入请求体（alta factura 数据）
        using (var stream = request.GetRequestStream())
        {
            // stream.Write(...); 
            // 写入您的 factura XML/JSON 数据
        }

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            if (response.StatusCode == HttpStatusCode.OK)
            {
                // 处理成功响应
                // ...
            }
            // ...
        }
    }
    catch (WebException ex)
    {
        // 处理 Web 异常，特别是 403 错误
        if (ex.Response is HttpWebResponse errorResponse && errorResponse.StatusCode == HttpStatusCode.Forbidden)
        {
            // 错误可能是 TLS 或证书问题，记录详情
            Console.WriteLine("Error 403 Forbidden: Check TLS version and certificate chain.");
        }
        else
        {
            // 其他网络错误
        }
    }
}

```

<div _ngcontent-ng-c3292687821="" class="code-block ng-tns-c3292687821-47 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="0" data-ved="0CAAQhtANahcKEwiZp6Sy1rCRAxUAAAAAHQAAAAAQOw" decode-data-ved="1" id="bkmrk--7" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_6939ac24b4de3970","c_5be2d685494dbfce",null,"rc_f75f93d6ff7e1687",null,null,"zh",null,1,null,null,1,0]]"><div _ngcontent-ng-c3292687821="" class="formatted-code-block-internal-container ng-tns-c3292687821-47"><div _ngcontent-ng-c3292687821="" class="animated-opacity ng-tns-c3292687821-47"></div></div></div>请优先尝试 **第 1 步**（强制启用 TLS 1.2）。如果服务器只支持 TLS 1.2，这是您在 .NET 4.0 中解决 403 错误的关键。

您是否想尝试使用这些修改后的代码，或者您需要我帮助您检查证书链的完整性？

##### 2- 解析证书后 参考文档生成指纹 [<span dir="auto">生成记录指纹或哈希的技术规范详情</span>](https://www.agenciatributaria.es/static_files/AEAT_Desarrolladores/EEDD/IVA/VERI-FACTU/Veri-Factu_especificaciones_huella_hash_registros.pdf) 

发送发票 /小票 hash 计算

<div id="bkmrk-a%29-datos-de-campos-a">a) Datos de campos a utilizar en el caso de registros de facturación de alta</div><div id="bkmrk-%28y-la-%E2%80%9Cruta%E2%80%9D-de-su-l">(y la “ruta” de su localización dentro del registro):</div><div id="bkmrk-1.-idemisorfactura-%28">1. IDEmisorFactura (RegistroAlta/IDFactura/IDEmisorFactura)</div><div id="bkmrk-2.-numseriefactura-%28">2. NumSerieFactura (RegistroAlta/IDFactura/NumSerieFactura)</div><div id="bkmrk-3.-fechaexpedicionfa">3. FechaExpedicionFactura</div><div id="bkmrk-%28registroalta%2Fidfact">(RegistroAlta/IDFactura/FechaExpedicionFactura)</div><div id="bkmrk-4.-tipofactura-%28regi">4. TipoFactura (RegistroAlta/TipoFactura)</div><div id="bkmrk-5.-cuotatotal-%28regis">5. CuotaTotal (RegistroAlta/CuotaTotal)</div><div id="bkmrk-6.-importetotal-%28reg">6. ImporteTotal (RegistroAlta/ImporteTotal)</div><div id="bkmrk-7.-huella-%28registroa">7. Huella (RegistroAlta/Encadenamiento/RegistroAnterior/Huella)</div><div id="bkmrk-8.-fechahorahusogenr">8. FechaHoraHusoGenRegistro</div><div id="bkmrk-%28registroalta%2Ffechah">(RegistroAlta/FechaHoraHusoGenRegistro)</div>数据需要以以上顺序生成 string 进行连接

如 nombreCampo1=valorCampo1&amp;nombreCampo2=valorCampo2&amp;nombreCampoN=valorCampoN

可参考一下代码 （官方代码 翻译 可能需要操作 合并xml ）

```c#
using System;
using System.Security.Cryptography;
using System.Text;

public class GeneradorHuella
{
    /// <summary>
    /// 计算 SHA-256 哈希并输出 Base64（与 Java 逻辑完全一致）
    /// </summary>
    public static string GetHashVerifactu(string msg)
    {
        try
        {
            using (var sha = SHA256.Create())
            {
                byte[] hash = sha.ComputeHash(Encoding.UTF8.GetBytes(msg));
                return Convert.ToBase64String(hash);
            }
        }
        catch (Exception e)
        {
            throw new Exception("生成 SHA 哈希时发生错误", e);
        }
    }

    /// <summary>
    /// 生成 RegistroAlta 记录对应的字段拼接字符串
    /// 顺序与 Java 完全相同
    /// </summary>
    public static string GetReferenciaRegistroAlta(
        string nifEmisor,
        string numFacturaSerie,
        string fechaExpedicion,
        string tipoFactura,
        string cuotaTotal,
        string importeTotal,
        string huellaAnterior,
        string fechaHoraUsoRegistro)
    {
        var sb = new StringBuilder();

        sb.Append(GetValorCampo("IDEmisorFactura", nifEmisor, true))
          .Append(GetValorCampo("NumSerieFactura", numFacturaSerie, true))
          .Append(GetValorCampo("FechaExpedicionFactura", fechaExpedicion, true))
          .Append(GetValorCampo("TipoFactura", tipoFactura, true))
          .Append(GetValorCampo("CuotaTotal", cuotaTotal, true))
          .Append(GetValorCampo("ImporteTotal", importeTotal, true))
          .Append(GetValorCampo("Huella", huellaAnterior, true))
          .Append(GetValorCampo("FechaHoraUsoRegistro", fechaHoraUsoRegistro, false)); // 最后一项不加 &

        return sb.ToString();
    }

    /// <summary>
    /// 生成一个字段的格式：Nombre=Valor 或 Nombre=Valor&
    /// </summary>
    public static string GetValorCampo(string nombre, string valor, bool separador)
    {
        string campo = nombre + "=" + (valor == null ? "" : valor.Trim());

        if (separador)
            return campo + "&";
        else
            return campo;
    }

    /// <summary>
    /// 计算 Alta 记录的 huella（Base64 SHA-256）
    /// </summary>
    public static string CalcularHuellaAlta(
        string nifEmisor,
        string numFacturaSerie,
        string fechaExpedicion,
        string tipoFactura,
        string cuotaTotal,
        string importeTotal,
        string huellaAnterior,
        string fechaHoraUsoRegistro)
    {
        string referencia = GetReferenciaRegistroAlta(
            nifEmisor,
            numFacturaSerie,
            fechaExpedicion,
            tipoFactura,
            cuotaTotal,
            importeTotal,
            huellaAnterior,
            fechaHoraUsoRegistro);

        return GetHashVerifactu(referencia);
    }
}

```

其他方法：

##### 📌 1. 主入口（你只需要调用这个）

```c#
string xml = File.ReadAllText("miFactura.xml");
string huella = VerifactuHashGenerator.CalcularHuellaDesdeXml(xml);

Console.WriteLine("Huella generada = " + huella);

```

🚀 **2. VerifactuHashGenerator.cs（完整可运行）**

```c#
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Xml;

public static class VerifactuHashGenerator
{
    // =============================
    // PUBLIC ENTRY
    // =============================
    public static string CalcularHuellaDesdeXml(string xml)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);

        // Detectar tipo de registro (Alta / Evento / Anulación)
        string tipo = DetectarTipoRegistro(doc);

        // Obtener campos según el tipo
        var campos = tipo switch
        {
            "RegistroAlta" => ExtraerCamposRegistroAlta(doc),
            "RegistroEvento" => ExtraerCamposRegistroEvento(doc),
            "RegistroAnulacion" => ExtraerCamposRegistroAnulacion(doc),
            _ => throw new Exception("Tipo de registro no reconocido")
        };

        // Construir cadena ordenada
        string cadena = ConstruirCadena(campos);

        // Calcular hash HEX
        return Sha256Hex(cadena);
    }

    // =============================
    // DETECCIÓN DE TIPO DE REGISTRO
    // =============================
    private static string DetectarTipoRegistro(XmlDocument doc)
    {
        if (doc.GetElementsByTagName("RegistroAlta").Count > 0) return "RegistroAlta";
        if (doc.GetElementsByTagName("RegistroEvento").Count > 0) return "RegistroEvento";
        if (doc.GetElementsByTagName("RegistroAnulacion").Count > 0) return "RegistroAnulacion";

        throw new Exception("No se encontró nodo RegistroAlta / RegistroEvento / RegistroAnulacion");
    }

    // =============================
    // CAMPO EXTRACTION (ALTA)
    // =============================
    private static List<(string, string)> ExtraerCamposRegistroAlta(XmlDocument doc)
    {
        var lista = new List<(string, string)>();

        lista.Add(("IDEmisorFactura", Get(doc, "IDEmisorFactura")));
        lista.Add(("NumSerieFactura", Get(doc, "NumSerieFactura")));
        lista.Add(("FechaExpedicionFactura", Get(doc, "FechaExpedicionFactura")));
        lista.Add(("TipoFactura", Get(doc, "TipoFactura")));
        lista.Add(("CuotaTotal", NormalizarNumero(Get(doc, "CuotaTotal"))));
        lista.Add(("ImporteTotal", NormalizarNumero(Get(doc, "ImporteTotal"))));
        lista.Add(("Huella", Get(doc, "Huella")));
        lista.Add(("FechaHoraUsoRegistro", Get(doc, "FechaHoraUsoRegistro")));

        return lista;
    }

    // =============================
    // CAMPO EXTRACTION (EVENTO)
    // =============================
    private static List<(string, string)> ExtraerCamposRegistroEvento(XmlDocument doc)
    {
        var lista = new List<(string, string)>();

        lista.Add(("IDEmisorFactura", Get(doc, "IDEmisorFactura")));
        lista.Add(("NumSerieFactura", Get(doc, "NumSerieFactura")));
        lista.Add(("TipoEvento", Get(doc, "TipoEvento")));
        lista.Add(("DescripcionEvento", Get(doc, "DescripcionEvento")));
        lista.Add(("Huella", Get(doc, "Huella")));
        lista.Add(("FechaHoraUsoRegistro", Get(doc, "FechaHoraUsoRegistro")));

        return lista;
    }

    // =============================
    // CAMPO EXTRACTION (ANULACION)
    // =============================
    private static List<(string, string)> ExtraerCamposRegistroAnulacion(XmlDocument doc)
    {
        var lista = new List<(string, string)>();

        lista.Add(("IDEmisorFactura", Get(doc, "IDEmisorFactura")));
        lista.Add(("NumSerieFactura", Get(doc, "NumSerieFactura")));
        lista.Add(("FechaExpedicionFactura", Get(doc, "FechaExpedicionFactura")));
        lista.Add(("TipoFactura", Get(doc, "TipoFactura")));
        lista.Add(("MotivoAnulacion", Get(doc, "MotivoAnulacion")));
        lista.Add(("Huella", Get(doc, "Huella")));
        lista.Add(("FechaHoraUsoRegistro", Get(doc, "FechaHoraUsoRegistro")));

        return lista;
    }

    // =============================
    // XML GETTER
    // =============================
    private static string Get(XmlDocument doc, string tag)
    {
        var list = doc.GetElementsByTagName(tag);
        if (list.Count == 0) return "";
        return list[0].InnerText.Trim();
    }

    // =============================
    // STRING BUILDING
    // =============================
    private static string ConstruirCadena(List<(string campo, string valor)> lista)
    {
        var sb = new StringBuilder();

        for (int i = 0; i < lista.Count; i++)
        {
            bool addAmp = i < lista.Count - 1;
            sb.Append(lista[i].campo)
              .Append("=")
              .Append(lista[i].valor);

            if (addAmp) sb.Append("&");
        }

        return sb.ToString();
    }

    // =============================
    // NORMALIZACIÓN DE NUMEROS
    // =============================
    private static string NormalizarNumero(string raw)
    {
        if (decimal.TryParse(raw, NumberStyles.Any, CultureInfo.InvariantCulture, out var d))
            return d.ToString("G29", CultureInfo.InvariantCulture);

        return raw?.Trim();
    }

    // =============================
    // SHA256 → HEX
    // =============================
    private static string Sha256Hex(string input)
    {
        using var sha = SHA256.Create();
        byte[] bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
        var sb = new StringBuilder();

        foreach (var b in bytes)
            sb.Append(b.ToString("X2"));

        return sb.ToString();
    }
}

```

以下是针对西班牙税务局 (AEAT) Verifactu SOAP 服务的完整实现，使用 XML 和客户端证书发送请求：

### 对接流程： 

**可直接用于 Veri\*factu（AEAT tikeV1.0）发送 XML 的 C# 代码模板**，包括：

- **加载 p12 客户端证书**
- **创建 HttpClient**
- **构造 SOAP XML**
- **发送到 AEAT（测试 / 生产）**
- **读取返回结果**
- **兼容 Veri\*factu Alta（RegistroAlta）、Envio、Consulta 等所有操作**

## **1. 初始化 HttpClient（含证书）**

```c#
using System.Net.Http;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Text;

public class VeriFactuClient
{
    private readonly HttpClient _client;

    public VeriFactuClient(string certPath, string certPassword, bool ignoreSsl = false)
    {
        var handler = new HttpClientHandler();

        // 加载 p12证书
        var cert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.MachineKeySet);
        handler.ClientCertificates.Add(cert);

        // 忽略 SSL（仅测试环境）
        if (ignoreSsl)
        {
            handler.ServerCertificateCustomValidationCallback = 
                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
        }

        _client = new HttpClient(handler);
    }

```

#### HASH sha-256 加密方法

```c#
using System;
using System.Security.Cryptography;
using System.Text;

public class GeneradorHuella
{
    // =========================
    // SHA256 HEX (Base16)
    // =========================
    public static string GetHashVerifactu(string msg)
    {
        try
        {
            using (SHA256 sha = SHA256.Create())
            {
                byte[] digest = sha.ComputeHash(Encoding.UTF8.GetBytes(msg));
                return BytesToHex(digest); // 等效 Base16
            }
        }
        catch (Exception e)
        {
            throw new ArgumentException("Error al generar la huella SHA", e);
        }
    }

    private static string BytesToHex(byte[] data)
    {
        StringBuilder sb = new StringBuilder(data.Length * 2);
        foreach (byte b in data)
            sb.AppendFormat("{0:x2}", b);
        return sb.ToString();
    }

    // =========================
    // 生成 RegistroAlta 引用字符串
    // =========================
    public static string GetReferenciaRegistroAlta(
        string nifEmisor,
        string numFacturaSerie,
        string fechaExpedicion,
        string tipoFactura,
        string cuotaTotal,
        string importeTotal,
        string huellaAnterior,
        string fechaHoraUsoRegistro)
    {
        StringBuilder sb = new StringBuilder();

        sb.Append(GetValorCampo("IDEmisorFactura", nifEmisor, true))
          .Append(GetValorCampo("NumSerieFactura", numFacturaSerie, true))
          .Append(GetValorCampo("FechaExpedicionFactura", fechaExpedicion, true))
          .Append(GetValorCampo("TipoFactura", tipoFactura, true))
          .Append(GetValorCampo("CuotaTotal", cuotaTotal, true))
          .Append(GetValorCampo("ImporteTotal", importeTotal, true))
          .Append(GetValorCampo("Huella", huellaAnterior, true))
          .Append(GetValorCampo("FechaHoraUsoGenRegistro", fechaHoraUsoRegistro, false));

        return sb.ToString();
    }

    // =========================
    // 拼接 X="value";
    // =========================
    public static string GetValorCampo(string nombre, string valor, bool separador)
    {
        string campo = nombre + "=" + (valor == null ? "" : valor.Trim());
        return separador ? campo + ";" : campo;
    }

    // =========================
    // 拼接并 URL 编码
    // =========================
    public static string GetValorCampoEncoded(string nombre, string valor, bool separador)
    {
        string campo = nombre + "=" + Uri.EscapeDataString(valor ?? "");
        return separador ? campo + ";" : campo;
    }

    // =========================
    // 计算 huellaAlta
    // =========================
    public static string CalcularHuellaAlta(
        string nifEmisor,
        string numFacturaSerie,
        DateTime fechaExpedicion,
        string tipoFactura,
        string cuotaTotal,
        string importeTotal,
        string huellaAnterior,
        string fechaHoraUsoRegistro)
    {
        string fecha = fechaExpedicion.ToString("yyyy-MM-dd"); // Java 的 formatea()

        string refStr = GetReferenciaRegistroAlta(
            nifEmisor,
            numFacturaSerie,
            fecha,
            tipoFactura,
            cuotaTotal,
            importeTotal,
            huellaAnterior,
            fechaHoraUsoRegistro
        );

        return GetHashVerifactu(refStr);
    }
}

```

#####  Excel 中的 发送错误处理以及解释 以及决策 ：

[![image.png](https://wiki.visiontec.es/uploads/images/gallery/2025-11/scaled-1680-/dXWimage.png)](https://wiki.visiontec.es/uploads/images/gallery/2025-11/dXWimage.png)

**表格总体说明**

这是一张 **“发票记录 ALTA（新增）类型操作”** 的决策表，用于说明在不同情况下，SIF（Sistema Informático de Facturación）向 AEAT 上报发票信息时，应如何处理“Alta”（新增登记）、“Alta por rechazo”（因被拒绝而重新新增）、“Alta de subsanación”（因更正而新增）等操作。

表格横向分为：

- **Operación**：操作类型（Alta、Alta por rechazo、Alta de subsanación…）
- **Descripción**：该操作在什么情况下使用
- **Operativa**：该操作对应的字段（Subsanación / RechazoPrevio）
- **Tipo SIF**：适用于 VERI*FACTU 或非 VERI*FACTU 系统
- **Condiciones**：触发此类操作的条件
- **Consecuencias**：执行后的效果
- **Situación en la AEAT**：AEAT 当前是否已有相关记录 → 决定本次操作是否 OK 或 ERROR

最右侧三栏为 **关键判断依据**（仅适用于 VERI\*FACTU）：

1. **No existe registro de facturación**：AEAT 中不存在记录
2. **Existe registro de alta**：AEAT 已存在一个 Alta 记录
3. **Existe registro de anulación**：AEAT 中存在该发票的 Anulación 记录

底部有 **LEYENDA（图例）**，说明 OK(1)、ERROR(2)… 等含义。

---

🟨 **第一部分：ALTA DE REGISTRO（普通新增）**

✔ 用途：

正常开票时的新增登记。

🔧 Operativa：

- 不应发送 `<Subsanacion>` 或 `<RechazoPrevio>`

🔍 Condiciones：

- AEAT 中不应已有该发票的记录。

🎯 结果：

新增发票记录。

📊 决策：

- AEAT 无记录 → **OK（1）**
- AEAT 已有 Alta → **ERROR（2）**
- AEAT 有 Anulación → **ERROR（2）**

---

🟧 **ALTA POR RECHAZO（因被拒重新提交）**

当你之前发送的记录被 AEAT 拒绝后，需要重新发送，此时为“Alta por rechazo”。

🔧 Operativa：

- `<Subsanacion> = S`
- `<RechazoPrevio> = X`

🔍 Condiciones：

- 之前确实被 AEAT 拒绝
- AEAT 中不能存在已注册记录

📊 决策：

- AEAT 无记录 → **Alta OK**
- AEAT 已有 Alta → **ERROR（2）**
- AEAT 有 Anulación → **ERROR（2）**

---

🟩 **ALTA DE SUBSANACIÓN（错误更正的新增）**

用于更正已有记录的情况。

类型 1：有原记录且需更正（正常场景）

- AEAT 中应已有此发票记录

决策：

- AEAT 无记录 → **ERROR（3）**
- AEAT 有 Alta → **OK（4）**
- AEAT 有 Anulación → **OK（5）**

类型 2：原记录不存在且允许更正（特殊情况）

用于以下情形，例如：

- 在非 VERI\*FACTU 状态下发票未按要求发送
- 系统切换后需补发
- 之前未上报但现在需要以“更正方式”上报

Operativa 可能包含：

- Subsanación = S
- RechazoPrevio = X（可选）

决策：

- AEAT 无记录 → **OK（1）**
- AEAT 有 Alta → **ERROR（2）**
- AEAT 有 Anulación → **ERROR（2）**

---

🟥 **ALTA POR RECHAZO DE SUBSANACIÓN（更正也被拒绝后再次提交）**

当你发送“更正记录”也被 AEAT 拒绝后，要再次发送。

Operativa：

- Subsanación = S
- RechazoPrevio = X

条件：

- 原记录不应存在于 AEAT

决策同前：

- AEAT 无记录 → OK（1）
- AEAT 有 Alta → ERROR（2）
- AEAT 有 Anulación → ERROR（2）

---

🟦 **LEYENDA（图例解释）**

<div class="group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse" id="bkmrk-%E4%BB%A3%E7%A0%81-%E5%90%AB%E4%B9%89-ok%281%29-%E5%8F%AF%E6%AD%A3%E5%B8%B8%E6%96%B0%E5%A2%9E%E8%AE%B0%E5%BD%95-" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="2386" data-start="2169"><thead data-end="2180" data-start="2169"><tr data-end="2180" data-start="2169"><th data-col-size="sm" data-end="2174" data-start="2169">代码</th><th data-col-size="sm" data-end="2180" data-start="2174">含义</th></tr></thead><tbody data-end="2386" data-start="2196"><tr data-end="2219" data-start="2196"><td data-col-size="sm" data-end="2208" data-start="2196">**OK(1)**</td><td data-col-size="sm" data-end="2219" data-start="2208">可正常新增记录</td></tr><tr data-end="2268" data-start="2220"><td data-col-size="sm" data-end="2235" data-start="2220">**ERROR(2)**</td><td data-col-size="sm" data-end="2268" data-start="2235">不应新增，AEAT 已有 Alta 或 Anulación</td></tr><tr data-end="2306" data-start="2269"><td data-col-size="sm" data-end="2284" data-start="2269">**ERROR(3)**</td><td data-col-size="sm" data-end="2306" data-start="2284">应该已有记录但不存在（系统顺序错误）</td></tr><tr data-end="2343" data-start="2307"><td data-col-size="sm" data-end="2319" data-start="2307">**OK(4)**</td><td data-col-size="sm" data-end="2343" data-start="2319">有 Alta → 用收到的新数据更正记录</td></tr><tr data-end="2386" data-start="2344"><td data-col-size="sm" data-end="2356" data-start="2344">**OK(5)**</td><td data-col-size="sm" data-end="2386" data-start="2356">有 Anulación → 记录恢复为有效并替换数据</td></tr></tbody></table>

</div>---

📌 总结（简单理解）

<div class="group _tableWrapper_1rjym_13 flex w-fit flex-col-reverse" id="bkmrk-%E6%93%8D%E4%BD%9C%E7%B1%BB%E5%9E%8B-aeat-%E6%97%A0%E8%AE%B0%E5%BD%95-aeat-%E6%9C%89" tabindex="-1"><table class="w-fit min-w-(--thread-content-width)" data-end="2674" data-start="2408"><thead data-end="2460" data-start="2408"><tr data-end="2460" data-start="2408"><th data-col-size="sm" data-end="2415" data-start="2408">操作类型</th><th data-col-size="sm" data-end="2426" data-start="2415">AEAT 无记录</th><th data-col-size="sm" data-end="2440" data-start="2426">AEAT 有 Alta</th><th data-col-size="sm" data-end="2460" data-start="2440">AEAT 有 Anulación</th></tr></thead><tbody data-end="2674" data-start="2522"><tr data-end="2546" data-start="2522"><td data-col-size="sm" data-end="2533" data-start="2522">**正常新增**</td><td data-col-size="sm" data-end="2537" data-start="2533">✔</td><td data-col-size="sm" data-end="2541" data-start="2537">❌</td><td data-col-size="sm" data-end="2546" data-start="2541">❌</td></tr><tr data-end="2572" data-start="2547"><td data-col-size="sm" data-end="2559" data-start="2547">**拒绝后重发**</td><td data-col-size="sm" data-end="2563" data-start="2559">✔</td><td data-col-size="sm" data-end="2567" data-start="2563">❌</td><td data-col-size="sm" data-end="2572" data-start="2567">❌</td></tr><tr data-end="2610" data-start="2573"><td data-col-size="sm" data-end="2586" data-start="2573">**更正（正常）**</td><td data-col-size="sm" data-end="2590" data-start="2586">❌</td><td data-col-size="sm" data-end="2598" data-start="2590">✔（更正）</td><td data-col-size="sm" data-end="2610" data-start="2598">✔（恢复+替换）</td></tr><tr data-end="2644" data-start="2611"><td data-col-size="sm" data-end="2631" data-start="2611">**更正（特殊情况，无原记录）**</td><td data-col-size="sm" data-end="2635" data-start="2631">✔</td><td data-col-size="sm" data-end="2639" data-start="2635">❌</td><td data-col-size="sm" data-end="2644" data-start="2639">❌</td></tr><tr data-end="2674" data-start="2645"><td data-col-size="sm" data-end="2661" data-start="2645">**更正被拒后再次提交**</td><td data-col-size="sm" data-end="2665" data-start="2661">✔</td><td data-col-size="sm" data-end="2669" data-start="2665">❌</td><td data-col-size="sm" data-end="2674" data-start="2669">❌</td></tr></tbody></table>

</div>---

如果你需要，我可以为你 **将此表格转换为程序逻辑（if/else 或 flowchart）**，用于实现 Veri\*factu 的自动决策。