# CLAUDE.md

为 Claude Code 在本仓库中工作提供指引。

## 项目概述

面向 SaaS 系统的 PHP 中转 API,两项功能共用 `core/` 与 `countries/` 层:

1. **撤回接口**(`index.php`)- 校验参数后路由到国家处理器,将 DB 记录状态置为该国撤回值。
2. **文件生成接口**(`api.php`)- 接收文件生成请求,透传完整数据到下游处理地址(如德国五合一文件生成器),返回统一响应。参考实现:`de.php::DE_VAT_REGISTER`。

## 技术栈

PHP ≥8.3 + MS SQL Server(`pdo_sqlsrv`)。纯 PHP,无框架、无 Composer(手动 `require_once`);测试为 `test/` 下独立脚本(`test_new_flows.php` 单元 198 项,mock 下游无需服务器/DB;`test_forward.php`、`test_de_vat_register.php` 为集成)。

## 架构

国家处理类位于 `countries/{xx}.php`(类名小写 = 文件名,继承 `CountryBase`)。基类四个 protected 助手:`execute()`/`fetchOne()`(撤回)、`httpPostJson()`/`resolveDownstreamUrl()`(转发,后者 fail-closed,常量未定义抛异常)。两个入口按各自规则动态路由到类方法,无需改其他文件:

- `index.php`(撤回):必填 `BusinessId`、`BusinessSerialNumber`、`PushId`、`PushScene`、`PushType`、`Country`;方法名 = `{PushScene 小写}_{PushType}`(如 `vatpushtax_101`)。
- `api.php`(转发):必填 `PushType`、`Country`(`Data` 可选);方法名 = `strtoupper(PushType)`(如 `DE_VAT_REGISTER`),响应外加 `ProcessMode:"sync"` 并回传 `bizParam`。国家类无对应方法时:若 `config/downstream.php` 配置了键名 = `PushType` 的 URL(如 `GB_VAT_REGISTER`)则走基类 `relayDefault()` 缺省转发(与 es.php 同一套"校验 Data → 透传 → 解析返回"),未配置返 400「没有找到对应的pushtype」。

**撤回方法**:按该国匹配字段(`BusinessSerialNumber` 或 `PushId`)取记录 -> `fetchOne()` 查状态(允许状态与撤回目标值各国不同,见该国代码;参考 `de.php`)-> `execute()` 置撤回值 -> 返回 `['code','msg','data']`。

**转发方法**(参考 `es.php::ES_EPR_REGISTER_HAGUE`):读 `Data`/`bizParam` -> `$this->resolveDownstreamUrl('XX_..._API_URL')` 取地址 -> `$this->httpPostJson()` 透传完整 `$requestParams` -> 解析返回。勿复制 `de.php` 的自实现 `httpPostJson()`(TLS 校验关闭;2026-08-14 已由同事改 protected 与父类一致)与私有 `getVatNewFileApiUrl()`(其 `HTTP_HOST` 回退有 SSRF/PII 风险,历史遗留,不修)。

## 关键约束

- **改代码前必须审批**:先提方案,获批准后再改文件。
- **`README.md`**:默认只读;仅可在完成某国家/业务撤回实现后作为收尾编辑,且只改该国在支持表、状态门控表的行及过时方法名引用,不得结构性/风格性改动或新增章节,应用前先向用户标记。
- **`docs/UNIFIED_API_DESIGN.md`**:只读,权威统一中转 API 规范,任何修改须先与用户提出。文档定位为**面向三方系统对接**(2026-08-24 起):只含对外接口契约与 §4 Data 业务字段,不含落地仓库实现细节;其他项目更新时只补齐 §4 Data 数据字段及说明(见文档开头维护说明)。
- **`countries/de.php`**:`DE_VAT_REGISTER` 为历史参考实现,归同事维护,不要修改;其自实现 cURL 助手(`httpPostJson` 2026-08-14 起 protected、`getVatNewFileApiUrl` 仍 private)与 `HTTP_HOST` 回退属已知遗留问题。
- **部署前置**:转发方法依赖的 `*_API_URL` 常量统一在 `config/downstream.php` 中定义(api.php 启动时幂等加载,环境已 define 则不覆盖),部署时只需填写该文件;未配置时 `resolveDownstreamUrl()` 抛异常致全部转发返 400。2026-08-14 起 ES/FR 常量已随 PushType 统一为 `{国家}_{业务大类}_REGISTER_{业务小类}_API_URL` 命名。另支持**键名 = `PushType` 本身(无 `_API_URL` 后缀)**的条目触发缺省转发(如 `GB_VAT_REGISTER` 指向 uk_vat_reg 落地仓库,国家类无需写方法)。
- **命名**:类名小写 = 文件名;撤回方法小写 `{pushscene}_{pushtype}`,转发方法大写 `PushType`。

## 新增国家

1. 创建 `countries/{code}.php`,类 `{code}` 继承 `CountryBase`。
2. 撤回方法 `{pushscene}_{pushtype}($requiredParams)`:状态门控 -> UPDATE -> 返回。
3. 转发方法 `strtoupper(PushType)($requestParams)`:复制 `es.php::ES_EPR_REGISTER_HAGUE` 模式,用基类 `resolveDownstreamUrl('XX_..._API_URL')`+`httpPostJson()` 转发至下游;勿照抄 `de.php`。
4. 路由全动态,无需改其他文件。
