添加其他字段
This commit is contained in:
parent
511fffe26a
commit
c3ed03c92f
|
|
@ -60,7 +60,7 @@ POST /api/offline-stats
|
|||
|
||||
对应工具:`get_offline_stats`
|
||||
|
||||
用途:订单状态分布、支付方式分布、订单类型分布、平均订单金额、平均实付金额、最大订单金额。
|
||||
用途:订单状态分布、支付方式分布、订单类型分布、营销中台分布、退款状态分布、抵扣金额、手续费、`diamond` 字段代币值汇总、平均订单金额、平均实付金额、最大订单金额、活跃商户数、实付金额 Top 商户。
|
||||
|
||||
### 3.3 商户排行榜
|
||||
|
||||
|
|
@ -204,7 +204,30 @@ AI 默认不要使用 `date`,除非调用平台只能传固定后台日期格
|
|||
| `type` | string | 订单类型,对应后台 `type` |
|
||||
| `btcId` | integer | 商户分类 ID,对应后台 `btc_id` |
|
||||
|
||||
### 7.1 订单状态 `status` 取值
|
||||
### 7.1 `diamond` 字段与 `btc_id` 的关系
|
||||
|
||||
后台订单里存在 `diamond` 字段。该字段不是固定只表示“钻石”,需要结合 `btc_id` 判断业务含义:
|
||||
|
||||
| btc_id | `diamond` 字段含义 |
|
||||
| --- | --- |
|
||||
| `1` | 钻石值 |
|
||||
| `3` | 绿宝石值 |
|
||||
| `4` | 算力值 |
|
||||
|
||||
`/api/offline-stats` 会返回:
|
||||
|
||||
| 字段 | 含义 |
|
||||
| --- | --- |
|
||||
| `totalTokenValue` | 所有订单 `diamond` 字段本身的合计 |
|
||||
| `tokenValueSummary` | 按 `btc_id` 解释后的 `diamond` 字段汇总,例如钻石值、绿宝石值、算力值 |
|
||||
|
||||
注意:
|
||||
|
||||
- `diamond` 表示本单关联/附赠/记录的代币值。
|
||||
- `diamond_ded` 表示消费券/钻石抵扣金额。
|
||||
- 两者不是同一个字段,不要混淆。
|
||||
|
||||
### 7.2 订单状态 `status` 取值
|
||||
|
||||
| status | 含义 | 用户常见说法 |
|
||||
| --- | --- | --- |
|
||||
|
|
|
|||
|
|
@ -133,21 +133,52 @@ AI 必须严格遵守:
|
|||
"data": {
|
||||
"orderCount": 100,
|
||||
"statusDistribution": {
|
||||
"1": 47,
|
||||
"2": 10
|
||||
"1 已完成": 47,
|
||||
"2 已取消": 10
|
||||
},
|
||||
"payTypeDistribution": {
|
||||
"wechat": 50,
|
||||
"balance": 20
|
||||
"7 蜜传微信支付": 50,
|
||||
"2 微信支付": 20
|
||||
},
|
||||
"typeDistribution": {
|
||||
"offline": 100
|
||||
"0 扫码订单": 70,
|
||||
"5 视频团单": 30
|
||||
},
|
||||
"btcDistribution": {
|
||||
"3 绿宝石中台(绿宝石)": 80,
|
||||
"4 算力中台(算力)": 20
|
||||
},
|
||||
"refundDistribution": {
|
||||
"0 未退款": 95,
|
||||
"1 已退款": 5
|
||||
},
|
||||
"totalOrderAmount": 882.89,
|
||||
"totalRealPay": 662.39,
|
||||
"totalCoinDeduction": 100.00,
|
||||
"totalBrokerDeduction": 10.00,
|
||||
"totalDiamondDeduction": 20.00,
|
||||
"totalTokenValue": 123.456789,
|
||||
"tokenValueSummary": {
|
||||
"diamond 钻石值": 10.000000,
|
||||
"diamond 绿宝石值": 100.000000,
|
||||
"diamond 算力值": 13.456789
|
||||
},
|
||||
"totalPreferentialAmount": 5.00,
|
||||
"totalMerchantRatePrice": 2.50,
|
||||
"totalDeductionAmount": 135.00,
|
||||
"averageOrderAmount": 8.83,
|
||||
"averageRealPay": 6.62,
|
||||
"maxOrderAmount": 99.99,
|
||||
"activeMerchantCount": 5,
|
||||
"topMerchantsByRealPay": [
|
||||
{
|
||||
"merchantId": 110,
|
||||
"merchantName": "示例商户",
|
||||
"orderCount": 20,
|
||||
"totalOrderAmount": 200.00,
|
||||
"totalRealPay": 180.00
|
||||
}
|
||||
],
|
||||
"_debug_query": {
|
||||
"time": "2026/06/18-2026/06/24"
|
||||
}
|
||||
|
|
@ -163,11 +194,23 @@ AI 必须严格遵守:
|
|||
| `statusDistribution` | 订单状态分布 |
|
||||
| `payTypeDistribution` | 支付方式分布 |
|
||||
| `typeDistribution` | 订单类型分布 |
|
||||
| `btcDistribution` | 营销代币中台分布,如积分、钻石、绿宝石、算力 |
|
||||
| `refundDistribution` | 退款状态分布 |
|
||||
| `totalOrderAmount` | 订单总金额 |
|
||||
| `totalRealPay` | 实付总金额 |
|
||||
| `totalCoinDeduction` | 抵用券/积分抵扣金额合计,对应 `coin_ded` |
|
||||
| `totalBrokerDeduction` | 佣金抵扣金额合计,对应 `broker_ded` |
|
||||
| `totalDiamondDeduction` | 消费券/钻石抵扣金额合计,对应 `diamond_ded` |
|
||||
| `totalTokenValue` | `diamond` 字段本身的总值,不是抵扣金额 |
|
||||
| `tokenValueSummary` | 按 `btc_id` 解释后的 `diamond` 字段汇总 |
|
||||
| `totalPreferentialAmount` | 平台让利抵扣券金额合计,对应 `pr_amount` |
|
||||
| `totalMerchantRatePrice` | 商户承担通道手续费合计,对应 `merchant_rate_price` |
|
||||
| `totalDeductionAmount` | 抵扣类金额合计,包含抵用券、佣金、消费券、平台让利抵扣券 |
|
||||
| `averageOrderAmount` | 平均订单金额 |
|
||||
| `averageRealPay` | 平均实付金额 |
|
||||
| `maxOrderAmount` | 最大订单金额 |
|
||||
| `activeMerchantCount` | 当前返回数据中的活跃商户数量 |
|
||||
| `topMerchantsByRealPay` | 按实付金额排序的前 10 个商户 |
|
||||
|
||||
状态值参考:
|
||||
|
||||
|
|
@ -191,9 +234,18 @@ AI 必须严格遵守:
|
|||
- 订单数:{orderCount} 单
|
||||
- 订单总金额:{totalOrderAmount}
|
||||
- 实付总金额:{totalRealPay}
|
||||
- 抵用券/积分抵扣:{totalCoinDeduction}
|
||||
- 佣金抵扣:{totalBrokerDeduction}
|
||||
- 消费券/钻石抵扣:{totalDiamondDeduction}
|
||||
- diamond 字段总值:{totalTokenValue}
|
||||
- diamond 字段分中台汇总:{tokenValueSummary 中逐项列出}
|
||||
- 平台让利抵扣券:{totalPreferentialAmount}
|
||||
- 通道手续费:{totalMerchantRatePrice}
|
||||
- 抵扣合计:{totalDeductionAmount}
|
||||
- 平均订单金额:{averageOrderAmount}
|
||||
- 平均实付金额:{averageRealPay}
|
||||
- 最大订单金额:{maxOrderAmount}
|
||||
- 活跃商户数:{activeMerchantCount}
|
||||
|
||||
状态分布:
|
||||
- {statusDistribution 中逐项列出}
|
||||
|
|
@ -204,9 +256,31 @@ AI 必须严格遵守:
|
|||
订单类型分布:
|
||||
- {typeDistribution 中逐项列出}
|
||||
|
||||
营销中台分布:
|
||||
- {btcDistribution 中逐项列出}
|
||||
|
||||
退款状态分布:
|
||||
- {refundDistribution 中逐项列出}
|
||||
|
||||
实付金额 Top 商户:
|
||||
- {topMerchantsByRealPay 中逐项列出}
|
||||
|
||||
注意:以上结果基于接口本次返回的数据统计。
|
||||
```
|
||||
|
||||
`diamond` 字段业务解释规则:
|
||||
|
||||
| btc_id | `diamond` 字段含义 |
|
||||
| --- | --- |
|
||||
| `1` | 钻石值 |
|
||||
| `3` | 绿宝石值 |
|
||||
| `4` | 算力值 |
|
||||
|
||||
注意:`diamond` 和 `diamond_ded` 不是同一个含义。
|
||||
|
||||
- `diamond`:本单关联/附赠/记录的代币值,需结合 `btc_id` 判断是钻石、绿宝石还是算力。
|
||||
- `diamond_ded`:消费券/钻石抵扣金额,属于抵扣金额。
|
||||
|
||||
## 6. 商户排行榜 JSON 字段说明
|
||||
|
||||
接口:`POST /api/merchant-ranking`
|
||||
|
|
|
|||
|
|
@ -32,37 +32,103 @@ final readonly class AnalyzeOfflineOrdersTool
|
|||
$statusDistribution = [];
|
||||
$payTypeDistribution = [];
|
||||
$typeDistribution = [];
|
||||
$btcDistribution = [];
|
||||
$refundDistribution = [];
|
||||
$merchantStats = [];
|
||||
$totalOrderAmount = 0.0;
|
||||
$totalRealPay = 0.0;
|
||||
$totalCoinDeduction = 0.0;
|
||||
$totalBrokerDeduction = 0.0;
|
||||
$totalDiamondDeduction = 0.0;
|
||||
$totalTokenValue = 0.0;
|
||||
$tokenValueSummary = [];
|
||||
$totalPreferentialAmount = 0.0;
|
||||
$totalMerchantRatePrice = 0.0;
|
||||
$maxOrderAmount = 0.0;
|
||||
|
||||
foreach ($orders as $order) {
|
||||
$statusKey = (string) ($order['status'] ?? 'unknown');
|
||||
$payTypeKey = (string) ($order['pay_type'] ?? 'unknown');
|
||||
$typeKey = (string) ($order['type'] ?? 'unknown');
|
||||
$statusKey = $this->statusLabel($order);
|
||||
$payTypeKey = $this->payTypeLabel($order['pay_type'] ?? null);
|
||||
$typeKey = $this->orderTypeLabel($order['type'] ?? null, $order['is_backend'] ?? null);
|
||||
$btcKey = $this->btcLabel($order['btc_id'] ?? null, $order['btc_type'] ?? null);
|
||||
$refundKey = $this->refundLabel($order['refund_status'] ?? null);
|
||||
$orderAmount = (float) ($order['order_price'] ?? 0);
|
||||
$realPay = (float) ($order['real_pay'] ?? 0);
|
||||
$coinDeduction = (float) ($order['coin_ded'] ?? 0);
|
||||
$brokerDeduction = (float) ($order['broker_ded'] ?? 0);
|
||||
$diamondDeduction = (float) ($order['diamond_ded'] ?? 0);
|
||||
$tokenValue = (float) ($order['diamond'] ?? 0);
|
||||
$preferentialAmount = (float) ($order['pr_amount'] ?? 0);
|
||||
$merchantRatePrice = (float) ($order['merchant_rate_price'] ?? 0);
|
||||
$merchantId = (int) ($order['merchant_id'] ?? 0);
|
||||
$tokenValueKey = $this->tokenValueLabel($order['btc_id'] ?? null);
|
||||
|
||||
$statusDistribution[$statusKey] = ($statusDistribution[$statusKey] ?? 0) + 1;
|
||||
$payTypeDistribution[$payTypeKey] = ($payTypeDistribution[$payTypeKey] ?? 0) + 1;
|
||||
$typeDistribution[$typeKey] = ($typeDistribution[$typeKey] ?? 0) + 1;
|
||||
$btcDistribution[$btcKey] = ($btcDistribution[$btcKey] ?? 0) + 1;
|
||||
$refundDistribution[$refundKey] = ($refundDistribution[$refundKey] ?? 0) + 1;
|
||||
$totalOrderAmount += $orderAmount;
|
||||
$totalRealPay += $realPay;
|
||||
$totalCoinDeduction += $coinDeduction;
|
||||
$totalBrokerDeduction += $brokerDeduction;
|
||||
$totalDiamondDeduction += $diamondDeduction;
|
||||
$totalTokenValue += $tokenValue;
|
||||
$tokenValueSummary[$tokenValueKey] = round(($tokenValueSummary[$tokenValueKey] ?? 0) + $tokenValue, 6);
|
||||
$totalPreferentialAmount += $preferentialAmount;
|
||||
$totalMerchantRatePrice += $merchantRatePrice;
|
||||
$maxOrderAmount = max($maxOrderAmount, $orderAmount);
|
||||
|
||||
if ($merchantId > 0) {
|
||||
if (!isset($merchantStats[$merchantId])) {
|
||||
$merchantStats[$merchantId] = [
|
||||
'merchantId' => $merchantId,
|
||||
'merchantName' => (string) ($order['merchant_name'] ?? ''),
|
||||
'orderCount' => 0,
|
||||
'totalOrderAmount' => 0.0,
|
||||
'totalRealPay' => 0.0,
|
||||
];
|
||||
}
|
||||
|
||||
$merchantStats[$merchantId]['orderCount']++;
|
||||
$merchantStats[$merchantId]['totalOrderAmount'] += $orderAmount;
|
||||
$merchantStats[$merchantId]['totalRealPay'] += $realPay;
|
||||
}
|
||||
}
|
||||
|
||||
$orderCount = count($orders);
|
||||
$topMerchants = array_values($merchantStats);
|
||||
|
||||
usort($topMerchants, static fn (array $left, array $right): int => $right['totalRealPay'] <=> $left['totalRealPay']);
|
||||
$topMerchants = array_slice($topMerchants, 0, 10);
|
||||
|
||||
foreach ($topMerchants as $index => $merchant) {
|
||||
$topMerchants[$index]['totalOrderAmount'] = round((float) $merchant['totalOrderAmount'], 2);
|
||||
$topMerchants[$index]['totalRealPay'] = round((float) $merchant['totalRealPay'], 2);
|
||||
}
|
||||
|
||||
return [
|
||||
'orderCount' => $orderCount,
|
||||
'statusDistribution' => $statusDistribution,
|
||||
'payTypeDistribution' => $payTypeDistribution,
|
||||
'typeDistribution' => $typeDistribution,
|
||||
'btcDistribution' => $btcDistribution,
|
||||
'refundDistribution' => $refundDistribution,
|
||||
'totalOrderAmount' => round($totalOrderAmount, 2),
|
||||
'totalRealPay' => round($totalRealPay, 2),
|
||||
'totalCoinDeduction' => round($totalCoinDeduction, 2),
|
||||
'totalBrokerDeduction' => round($totalBrokerDeduction, 2),
|
||||
'totalDiamondDeduction' => round($totalDiamondDeduction, 2),
|
||||
'totalTokenValue' => round($totalTokenValue, 6),
|
||||
'tokenValueSummary' => $tokenValueSummary,
|
||||
'totalPreferentialAmount' => round($totalPreferentialAmount, 2),
|
||||
'totalMerchantRatePrice' => round($totalMerchantRatePrice, 2),
|
||||
'totalDeductionAmount' => round($totalCoinDeduction + $totalBrokerDeduction + $totalDiamondDeduction + $totalPreferentialAmount, 2),
|
||||
'averageOrderAmount' => $orderCount > 0 ? round($totalOrderAmount / $orderCount, 2) : 0,
|
||||
'averageRealPay' => $orderCount > 0 ? round($totalRealPay / $orderCount, 2) : 0,
|
||||
'maxOrderAmount' => round($maxOrderAmount, 2),
|
||||
'activeMerchantCount' => count($merchantStats),
|
||||
'topMerchantsByRealPay' => $topMerchants,
|
||||
'_debug_query' => $query,
|
||||
];
|
||||
}
|
||||
|
|
@ -75,4 +141,102 @@ final readonly class AnalyzeOfflineOrdersTool
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $order
|
||||
*/
|
||||
private function statusLabel(array $order): string
|
||||
{
|
||||
$status = (int) ($order['status'] ?? -999);
|
||||
$refundStatus = (int) ($order['refund_status'] ?? 0);
|
||||
|
||||
if ($status === 1 && $refundStatus === 1) {
|
||||
return '1 已完成(已退款)';
|
||||
}
|
||||
|
||||
if ($status === 1 && $refundStatus > 1) {
|
||||
return '1 已完成(部分退款)';
|
||||
}
|
||||
|
||||
return match ($status) {
|
||||
0 => '0 待付款',
|
||||
1 => '1 已完成',
|
||||
2 => '2 已取消',
|
||||
3 => '3 待使用/待核销',
|
||||
4 => '4 已退款',
|
||||
default => 'unknown 未知状态',
|
||||
};
|
||||
}
|
||||
|
||||
private function payTypeLabel(mixed $payType): string
|
||||
{
|
||||
return match ((int) $payType) {
|
||||
0 => '0 中台微信',
|
||||
1 => '1 中台支付宝',
|
||||
2 => '2 微信支付',
|
||||
3 => '3 公众号支付',
|
||||
4 => '4 中台公众号',
|
||||
7 => '7 蜜传微信支付',
|
||||
default => 'unknown 未知支付渠道',
|
||||
};
|
||||
}
|
||||
|
||||
private function orderTypeLabel(mixed $type, mixed $isBackend): string
|
||||
{
|
||||
$orderType = (int) $type;
|
||||
|
||||
if ($orderType === 0 && (int) $isBackend === 1) {
|
||||
return '0 后台扫码订单';
|
||||
}
|
||||
|
||||
if ($orderType === 0) {
|
||||
return '0 扫码订单';
|
||||
}
|
||||
|
||||
return match ($orderType) {
|
||||
1 => '1 点餐订单',
|
||||
2 => '2 团购订单',
|
||||
3 => '3 收银系统订单',
|
||||
4 => '4 曹操出行订单',
|
||||
5 => '5 视频团单',
|
||||
default => 'unknown 未知订单类型',
|
||||
};
|
||||
}
|
||||
|
||||
private function btcLabel(mixed $btcId, mixed $btcType): string
|
||||
{
|
||||
$label = match ((int) $btcId) {
|
||||
0 => '0 积分中台',
|
||||
1 => '1 钻石中台',
|
||||
3 => '3 绿宝石中台',
|
||||
4 => '4 算力中台',
|
||||
default => 'unknown 未知中台',
|
||||
};
|
||||
|
||||
if ($btcType !== null && trim((string) $btcType) !== '') {
|
||||
return $label . '(' . $btcType . ')';
|
||||
}
|
||||
|
||||
return $label;
|
||||
}
|
||||
|
||||
private function tokenValueLabel(mixed $btcId): string
|
||||
{
|
||||
return match ((int) $btcId) {
|
||||
1 => 'diamond 钻石值',
|
||||
3 => 'diamond 绿宝石值',
|
||||
4 => 'diamond 算力值',
|
||||
default => 'diamond 其他中台值',
|
||||
};
|
||||
}
|
||||
|
||||
private function refundLabel(mixed $refundStatus): string
|
||||
{
|
||||
return match ((int) $refundStatus) {
|
||||
0 => '0 未退款',
|
||||
1 => '1 已退款',
|
||||
2 => '2 部分退款',
|
||||
default => 'unknown 未知退款状态',
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue