完成了基本调整调整

This commit is contained in:
2026-09-18 20:55:21 +08:00
parent 864187e105
commit 57e0854a0e
56 changed files with 3122 additions and 105 deletions
+145 -1
View File
@@ -44,6 +44,13 @@ class QytOil extends BaseService
/** @var EnterpriseModel|array|null 当前企业 */
protected $enterprise = null;
/**
* @var bool 最近一次请求是否属于「网络层异常」(超时、连不上、响应不是 JSON)。
* 这类失败不能说明上游没处理——对 7.16 这种没有幂等键的写接口,必须和
* 「上游明确返回失败」区分开,前者转人工确认,后者才可以放心重试。
*/
protected $transportError = false;
protected function initialize()
{
$this->conf = QytConfig::get();
@@ -204,6 +211,132 @@ class QytOil extends BaseService
return null;
}
// ================================================================
// 7.17 获取支付凭证(须真实 RSA 验签)
// ================================================================
/**
* 查询某司机在当前企业下的支付凭证,退款(7.16)要用其中的 quota_id
* @return array data.list[]: quota_id / total_amount / available_amount / used_amount / status ...(金额单位:元)
*/
public function getVoucherList(string $mobile, string $idCard, int $page = 1, int $pageSize = 50): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
return $this->post('/enterprise/api/quota/getVoucherList', [
'passageway' => (string) $this->channelCode(),
'business_license' => $this->businessLicense(),
'mobile' => $mobile,
'id_card' => $idCard,
'page' => $page,
'page_size' => $pageSize,
]);
}
// ================================================================
// 7.16 司机额度调整(须真实 RSA 验签;⚠️ 无幂等键,重复调用会重复调额)
// ================================================================
/**
* @param int|string $quotaId 7.17 返回的凭证主键
* @param string $changeType 02 增加额度 / 03 减少额度
* @param float $amount 调整金额(元)
* @param string $reason 操作原因(≤200 字);退款时写入退款单号,确认结果时靠它在 7.13 流水里定位
* @param string $waybillNo 运单号(可选)
*/
public function adjustVoucher($quotaId, string $changeType, float $amount, string $reason = '', string $waybillNo = ''): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
$params = [
'passageway' => (string) $this->channelCode(),
'business_license' => $this->businessLicense(),
'quota_id' => (int) $quotaId,
'change_type' => $changeType,
'amount' => round($amount, 2),
'operation_reason' => mb_substr($reason, 0, 200),
];
$waybillNo !== '' && $params['waybill_no'] = $waybillNo;
return $this->post('/enterprise/api/quota/adjustVoucher', $params);
}
// ================================================================
// 7.11 企业账户余额(仅平安银行通道支持,金额:分)
// ================================================================
public function distributable(): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
if ($this->channelCode() !== 2) {
return $this->fail('企业账户余额查询仅支持平安银行通道,支付宝企业码没有独立资金账户');
}
return $this->post('/enterprise/api/zhyk/distributable', [
'business_license' => $this->businessLicense(),
'passageway' => (string) $this->channelCode(),
]);
}
// ================================================================
// 7.12 司机钱包金额 / 7.13 司机钱包明细(金额:分)
// ================================================================
public function driverBalanceQuery(string $mobile, string $idCard, int $page = 1, int $pageSize = 20): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
return $this->post('/enterprise/api/zhyk/driverBalanceQuery', [
'business_license' => $this->businessLicense(),
'passageway' => (string) $this->channelCode(),
'mobile' => $mobile,
'id_card' => $idCard,
'page' => $page,
'page_size' => $pageSize,
]);
}
public function driverWalletQuery(string $mobile, string $idCard, int $page = 1, int $pageSize = 20): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
return $this->post('/enterprise/api/zhyk/driverWalletQuery', [
'business_license' => $this->businessLicense(),
'passageway' => (string) $this->channelCode(),
'mobile' => $mobile,
'id_card' => $idCard,
'page' => $page,
'page_size' => $pageSize,
]);
}
// ================================================================
// 7.14 企业发票下载(粒度:企业 + 通道 + 月份,可选按司机手机号收窄)
// ================================================================
/**
* @param string $month YYYY-MM
* @param string $mobile 司机手机号;传了只返回该司机相关发票与加油明细
* @return array data: business_license / invoice[] 发票地址集 / order_list[] 加油明细(分)
*/
public function invoice(string $month, string $mobile = ''): array
{
if (($err = $this->requireEnterprise()) !== null) {
return $err;
}
$params = [
'business_license' => $this->businessLicense(),
'passageway' => (string) $this->channelCode(),
'month' => $month,
];
$mobile !== '' && $params['mobile'] = $mobile;
return $this->post('/enterprise/api/zhyk/invoice', $params);
}
// ================================================================
// 7.2 企业申请创建
// ================================================================
@@ -295,12 +428,15 @@ class QytOil extends BaseService
['企业' => $this->enterpriseName(), 'url' => $url, 'params' => self::maskDeep($bizParams)],
JSON_UNESCAPED_UNICODE));
$this->transportError = false;
$resp = $this->curlPost($url, json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->saveLog("[响应] {$path} " . self::maskText($resp));
$json = json_decode($resp, true);
if (!is_array($json)) {
return ['code' => 'ERR', 'data' => [], 'message' => '响应解析失败', 'dup_batch' => false, 'raw' => ['body' => $resp]];
// 拿不到可解析的响应,无法判断上游是否已处理
return ['code' => 'ERR', 'data' => [], 'message' => '响应解析失败', 'dup_batch' => false,
'transport_error' => true, 'raw' => ['body' => mb_substr((string) $resp, 0, 500)]];
}
// 通用响应结构:{ status: ok|error, data, message, serialNo, sign }
@@ -323,6 +459,8 @@ class QytOil extends BaseService
'data' => $json['data'] ?? [],
'message' => $message,
'dup_batch' => $dupBatch,
// cURL 失败时 curlPost 会伪造一个 {"status":"error"} 的 JSON,靠标记区分
'transport_error' => $this->transportError,
'raw' => $json,
];
}
@@ -344,9 +482,15 @@ class QytOil extends BaseService
if ($resp === false) {
$err = curl_error($ch);
curl_close($ch);
$this->transportError = true;
return json_encode(['status' => 'error', 'message' => 'cURL: ' . $err], JSON_UNESCAPED_UNICODE);
}
$httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 网关层 5xx:请求可能已到达上游业务层,也按结果未知处理
if ($httpCode >= 500) {
$this->transportError = true;
}
return (string) $resp;
}