# 航信电子发票 SDK (huapiaoer-sdk)

基于航信（票慧通）乐企版 v5.1 的电子发票 Java SDK，封装了发票开具、红冲、查询、发送邮件等全部接口。

## 引入依赖

```xml
<dependency>
    <groupId>com.kym</groupId>
    <artifactId>huapiaoer-sdk</artifactId>
    <version>5.1.0</version>
</dependency>
```

## 快速开始

```java
// 1. 创建配置
HuapiaoerConfig config = HuapiaoerConfig.builder()
        .appSecret("你的票慧通 appsecret")
        .build();

// 2. 创建客户端
HuapiaoerClient client = new HuapiaoerClient(config);

// 3. 调用接口
List<DrawerInfo> drawers = client.getDrawerIdList("915001*******460R");
```

## 配置参数

| 参数 | 类型 | 必填 | 默认值 | 说明 |
|------|------|------|--------|------|
| `appSecret` | String | 是 | — | 票慧通提供的密钥 |
| `baseUrl` | String | 否 | `https://erp.huapiaoer.com` | API 正式环境地址 |

> `appSecret` 由 SDK 自动注入到所有请求中，无需手动设置。

---

## API 参考

### 1. 查询开票人列表

查询当前企业下所有开票人。

```java
List<DrawerInfo> getDrawerIdList(String nsrsbh)
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `nsrsbh` | String | 开票方税号（商家税号） |

---

### 2. 授权订单号

微信支付商户授权，在发起开票前调用。

```java
AuthorizeOrderResponse getAuthorizeOrderId(AuthorizeOrderRequest request)
```

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `omsoutputorderid` | String | 是 | 订单号（企业号 + 流水号） |
| `appid` | String | 是 | 商户 AppID |
| `openid` | String | 是 | 微信 OpenID |
| `source` | String | 否 | `WEB` / `MINIPROGRAM` |

---

### 3. 发票开具

开具蓝字发票。

```java
OpenInvoiceResponse openBlueInvoice(OpenBlueInvoiceRequest request)
```

请求核心字段：

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `issuerid` | String | 否 | 开票人 ID |
| `tradeinfo.payType` | String | 是 | 支付渠道编码，见 `PayType` 枚举 |
| `tradeinfo.outTradeNo` | String | 是 | 支付流水号 |
| `head.kpje` | String | 是 | 开票总金额 |
| `head.orderId` | String | 是 | 开票订单号 |
| `head.b2cshopid` | String | 是 | 商家税号 |
| `head.invoicetitle` | String | 是 | 购方抬头 |
| `head.invoiceTypeCode` | String | 是 | 发票类型，见 `InvoiceType` 枚举 |
| `head.registrationnumber` | String | 否 | 购方税号 |
| `head.companyaddress` | String | 否 | 购方地址 |
| `head.mobilenumber` | String | 否 | 购方手机号 |
| `head.openaccountbank` | String | 否 | 银行名称 |
| `head.bankaccount` | String | 否 | 银行账号 |
| `head.remark` | String | 否 | 发票备注 |
| `head.recmail` | String | 否 | 接收邮箱 |
| `details` | List | 是 | 商品明细 |

商品明细 (`DetailInfo`)：

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `goodsname` | String | 是 | 商品名称 |
| `price` | Double | 是 | 商品单价（元） |
| `sl` | Double | 是 | 数量 |
| `goodscategory` | String | 否 | 商品大类（与 taxcode/tax 二选一） |
| `taxcode` | String | 否 | 税目编码（与 goodscategory 二选一） |
| `tax` | String | 否 | 税率（与 goodscategory 二选一） |
| `attributes` | String | 否 | 规格型号 |
| `unitname` | String | 否 | 单位 |
| `discount` | Double | 否 | 折扣金额（元） |

使用示例：

```java
OpenInvoiceResponse resp = client.openBlueInvoice(
    new OpenBlueInvoiceRequest()
        .setIssuerid("1868914789939154946")
        .setTradeinfo(new TradeInfo()
            .setPayType(PayType.WECHAT_PAY.getCode())
            .setOutTradeNo("WX20240410000001"))
        .setHead(new HeadInfo()
            .setOrderId("1019000000000001")
            .setB2cshopid("914403008888888888")
            .setKpje("1.00")
            .setInvoicetitle("深圳柯适科技有限公司")
            .setRegistrationnumber("91440300MA5FB8A214")
            .setInvoiceTypeCode(InvoiceType.DIGITAL_NORMAL.getCode())
            .setRecmail("test@qq.com"))
        .setDetails(List.of(
            new DetailInfo()
                .setGoodsname("充电服务费")
                .setPrice(1.0)
                .setSl(1.0)
                .setTaxcode("1030302000000000xxx")
                .setTax("0.13")
        ))
);
// resp.getCode()        → "200"
// resp.getData()         → "订单生成成功！请让用户授权。"
// resp.getOrderId()      → "1019000000000001"
// resp.getAuthorizeQRCode() → "https://image.huapiaoer.com/xxx.png"
```

---

### 4. 发票红冲

冲红已开具的发票。

```java
HuapiaoerResponse<String> openRedInvoice(String orderId)
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `orderId` | String | 发票订单号 |

---

### 5. 发票查询

查询发票开票结果。

```java
InvoiceInfo getInvoice(String orderId, int invoicetype)
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `orderId` | String | 航信订单号 |
| `invoicetype` | int | `1` 蓝票，`2` 红票，见 `InvoiceQueryType` |

返回 `InvoiceInfo` 包含：`invoicenumber`（发票号码）、`invoicecode`（发票代码）、`invoiceurl`（PDF 地址）、`ofdurl`（OFD 地址）、`xmlurl`（XML 地址）、`ticketTotalAmountHasTax`（金额）等。

---

### 6. 发送邮件

将发票发送到指定邮箱。

```java
HuapiaoerResponse<String> sendMail(String orderId, int invoiceType, String email)
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `orderId` | String | 订单号 |
| `invoiceType` | int | `1` 蓝票，`2` 红票 |
| `email` | String | 目标邮箱 |

---

### 7. 生成开票二维码

生成自助开票二维码，用户扫码填写抬头开票。

```java
HuapiaoerResponse<QrcodeResponse> getInvoiceQrcode(InvoiceQrcodeRequest request)
```

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `head.orderId` | String | 是 | 开票订单号 |
| `head.b2cshopid` | String | 是 | 商家税号 |
| `head.invoiceTypeCode` | String | 是 | 发票类型 |
| `head.remark` | String | 否 | 发票备注 |
| `details` | List | 是 | 商品明细（不含 discount） |

---

### 8. 企业搜索

根据企业简称查询企业基本信息。

```java
List<EnterpriseInfo> searchEnterprise(String enterpriseName)
```

| 参数 | 类型 | 说明 |
|------|------|------|
| `enterpriseName` | String | 公司简称（4 个字符起生效） |

---

## 枚举常量

### InvoiceType 发票类型

| 枚举 | 编码 | 说明 |
|------|------|------|
| `DIGITAL_SPECIAL` | `"081"` | 数电专票 |
| `DIGITAL_NORMAL` | `"082"` | 数电普票 |

### InvoiceQueryType 查询类型

| 枚举 | 值 | 说明 |
|------|-----|------|
| `BLUE` | `1` | 蓝票 |
| `RED` | `2` | 红票 |

### PayType 支付渠道

| 枚举 | 编码 | 说明 |
|------|------|------|
| `CASH` | `"01"` | 现金 |
| `BANK_TRANSFER` | `"02"` | 银行转账 |
| `ALIPAY` | `"09"` | 支付宝 |
| `WECHAT_PAY` | `"10"` | 微信支付 |
| `UNIONPAY_QUICK` | `"11"` | 云闪付 |
| ... | ... | 共 14 种支付渠道 |

---

## 异常处理

所有接口在 `code != "200"` 或网络异常时抛出 `HuapiaoerException`：

```java
try {
    List<DrawerInfo> drawers = client.getDrawerIdList("...");
} catch (HuapiaoerException e) {
    // e.getCode()    — 状态码
    // e.getMessage() — 错误描述
}
```
