From 95e4effcd9b7c7fd03d617c5fe39c8809259fda3 Mon Sep 17 00:00:00 2001 From: Ghost <106998207@qq.com> Date: Mon, 13 Apr 2026 10:38:56 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=81=E4=B8=9A=E8=AE=A1=E8=B4=B9?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E4=B8=8E=E8=B6=85=E7=AE=A1/=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E7=AB=AF=E8=AE=BE=E7=BD=AE=E5=8F=8A=E5=AE=9A=E4=BB=B7?= =?UTF-8?q?=E8=A7=84=E5=88=99=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、修复了财务、Analyze/Test 等与定价、账务相关的接口行为。 2、新增 EnterpriseBillingService 与定价企业账务规则说明文档。 3、优化超管 Settings、PricingConfig 及小程序 app 入口逻辑。 Made-with: Cursor --- admin/src/views/superadmin/Settings.vue | 1 + .../service/EnterpriseBillingService.php | 125 ++++++++++ api/app/controller/admin/Finance.php | 2 +- api/app/controller/api/Analyze.php | 20 +- api/app/controller/api/Test.php | 17 +- api/app/controller/superadmin/Settings.php | 39 +++- api/app/model/PricingConfig.php | 218 ++++++++---------- api/docs/定价与企业账务规则说明.md | 147 ++++++++++++ miniprogram/app.js | 4 +- 9 files changed, 430 insertions(+), 143 deletions(-) create mode 100644 api/app/common/service/EnterpriseBillingService.php create mode 100644 api/docs/定价与企业账务规则说明.md diff --git a/admin/src/views/superadmin/Settings.vue b/admin/src/views/superadmin/Settings.vue index 7794418..42847b1 100644 --- a/admin/src/views/superadmin/Settings.vue +++ b/admin/src/views/superadmin/Settings.vue @@ -602,6 +602,7 @@ const handleSave = async (section: string) => { maintenanceMode: !!systemConfig.maintenanceMode }) if (response.code === 200) { + await loadSettings() ElMessage.success(systemConfig.maintenanceMode ? '审核模式已开启,小程序将隐藏AI功能' : '审核模式已关闭,AI功能已恢复') saveSuccess.value = section setTimeout(() => { saveSuccess.value = null }, 3000) diff --git a/api/app/common/service/EnterpriseBillingService.php b/api/app/common/service/EnterpriseBillingService.php new file mode 100644 index 0000000..6ffc877 --- /dev/null +++ b/api/app/common/service/EnterpriseBillingService.php @@ -0,0 +1,125 @@ +where('id', $enterpriseId) + ->field('id, balance') + ->lock(true) + ->find(); + if (!$enterprise) { + Db::rollback(); + return; + } + + $exists = Db::name('finance_records') + ->where('enterpriseId', $enterpriseId) + ->where('type', 'consume') + ->whereNull('orderId') + ->where('description', $description) + ->find(); + if ($exists) { + Db::commit(); + return; + } + + $beforeFen = (int) ($enterprise['balance'] ?? 0); + // 平台费独立记账,允许与企业测试收入分列后形成净额。 + $afterFen = $beforeFen - $amountFen; + + Db::name('enterprises') + ->where('id', $enterpriseId) + ->update([ + 'balance' => $afterFen, + 'updatedAt' => $now, + ]); + + Db::name('finance_records')->insert([ + 'enterpriseId' => $enterpriseId, + 'type' => 'consume', + 'amount' => $amountFen, + 'balanceBefore' => $beforeFen, + 'balanceAfter' => $afterFen, + 'description' => $description, + 'orderId' => null, + 'createdAt' => $now, + ]); + + Db::commit(); + } catch (\Throwable $e) { + Db::rollback(); + } + } + + /** + * 从超管全局 enterprise 定价读取平台费(分)。 + */ + public static function getPlatformFeeFen(string $testType): int + { + $config = PricingConfigModel::where('type', 'enterprise')->whereNull('enterpriseId')->find(); + if (!$config || empty($config->config)) { + return 0; + } + + $raw = $config->config; + $pricing = is_array($raw) ? $raw : (array) $raw; + $key = $testType === 'team_analysis' ? 'teamAnalysis' : $testType; + if (!isset($pricing[$key])) { + return 0; + } + + $yuan = (float) $pricing[$key]; + return $yuan > 0 ? (int) round($yuan * 100) : 0; + } + + private static function buildPlatformFeeDescription(string $testType, int $testResultId): string + { + return '平台扣费:' . self::getTestTypeLabel($testType) . '测试(testResultId=' . $testResultId . ')'; + } + + private static function getTestTypeLabel(string $testType): string + { + $map = [ + 'face' => '人脸', + 'mbti' => 'MBTI', + 'sbti' => 'SBTI', + 'disc' => 'DISC', + 'pdp' => 'PDP', + 'resume' => '简历', + ]; + + return $map[$testType] ?? strtoupper($testType); + } +} diff --git a/api/app/controller/admin/Finance.php b/api/app/controller/admin/Finance.php index ab3dd26..62aad62 100644 --- a/api/app/controller/admin/Finance.php +++ b/api/app/controller/admin/Finance.php @@ -101,7 +101,7 @@ class Finance extends BaseController $direction = $type === 'consume' ? 'out' : 'in'; $description = (string) ($row['description'] ?? ''); $typeLabel = $type === 'consume' - ? '佣金扣减' + ? (strpos($description, '平台扣费:') === 0 ? '平台扣费' : '佣金扣减') : (strpos($description, '企业余额充值') !== false ? '余额充值' : ($orderId > 0 ? '测试收入' : '余额充值')); return [ diff --git a/api/app/controller/api/Analyze.php b/api/app/controller/api/Analyze.php index 04818c2..ad525f7 100644 --- a/api/app/controller/api/Analyze.php +++ b/api/app/controller/api/Analyze.php @@ -2,7 +2,7 @@ namespace app\controller\api; use app\BaseController; -use app\common\SystemDefaultEnterprise; +use app\common\service\EnterpriseBillingService; use app\controller\api\Test as TestController; use app\model\AiProvider as AiProviderModel; use app\model\SystemConfig as SystemConfigModel; @@ -51,7 +51,7 @@ class Analyze extends BaseController // 三个变量各司其职(同 Test::submit 逻辑): // $enterpriseId —— 仅企业测试(请求体传入)才非 null,决定走 admin_enterprise 定价 // $pricingEnterpriseId —— 个人测试时从 wechat_users 取,走 admin_personal + eid 定价 - // $writeEnterpriseId —— 写入 test_results.enterpriseId(企业测试 or 绑定企业都记录) + // $writeEnterpriseId —— 写入 test_results.enterpriseId(仅企业测试或真实绑定企业时记录) $pricingEnterpriseId = $enterpriseId; $writeEnterpriseId = $enterpriseId; if ($enterpriseId === null && $earlyUserId > 0) { @@ -59,12 +59,6 @@ class Analyze extends BaseController if (!empty($boundEid)) { $pricingEnterpriseId = (int) $boundEid; // admin_personal + eid $writeEnterpriseId = (int) $boundEid; // 历史记录展示企业名 - } else { - $defEid = SystemDefaultEnterprise::getId(); - if ($defEid !== null) { - $pricingEnterpriseId = $defEid; - $writeEnterpriseId = $defEid; - } } } @@ -189,6 +183,11 @@ class Analyze extends BaseController ]); } } + try { + EnterpriseBillingService::chargePlatformFeeForTestResult($testResultId, 'face', $writeEnterpriseId); + } catch (\Throwable $e) { + // 平台费扣款失败不阻断主流程 + } // 面相分析由本接口直接写入 test_results,也要补触发测试完成佣金 try { \app\controller\api\Distribution::settleTestCommission($testResultId, $userId, 'face'); @@ -376,6 +375,11 @@ class Analyze extends BaseController ]); } } + try { + EnterpriseBillingService::chargePlatformFeeForTestResult($testResultId, 'resume', $enterpriseId > 0 ? $enterpriseId : null); + } catch (\Throwable $e) { + // 平台费扣款失败不阻断主流程 + } } } catch (\Throwable $e) { Log::error('resumeAnalysis: save test_result failed ' . $e->getMessage()); diff --git a/api/app/controller/api/Test.php b/api/app/controller/api/Test.php index c945755..87e0e34 100644 --- a/api/app/controller/api/Test.php +++ b/api/app/controller/api/Test.php @@ -2,8 +2,8 @@ namespace app\controller\api; use app\BaseController; -use app\common\SystemDefaultEnterprise; use app\common\PdpDiscResultText; +use app\common\service\EnterpriseBillingService; use app\model\Enterprise as EnterpriseModel; use app\model\PricingConfig as PricingConfigModel; use app\model\Question as QuestionModel; @@ -668,7 +668,7 @@ class Test extends BaseController // 三个变量各司其职: // $enterpriseId —— 仅企业测试(请求体传入)才非 null,决定走 admin_enterprise 定价 // $pricingEnterpriseId —— 个人测试时从 wechat_users 取,走 admin_personal + eid 定价 - // $writeEnterpriseId —— 写入 test_results.enterpriseId(企业测试 or 绑定企业都记录) + // $writeEnterpriseId —— 写入 test_results.enterpriseId(仅企业测试或真实绑定企业时记录) $pricingEnterpriseId = $enterpriseId; $writeEnterpriseId = $enterpriseId; if ($enterpriseId === null) { @@ -676,13 +676,6 @@ class Test extends BaseController if (!empty($boundEid)) { $pricingEnterpriseId = (int) $boundEid; // admin_personal + eid $writeEnterpriseId = (int) $boundEid; // 历史记录展示企业名 - } else { - // 主入口无参数且未绑定企业:回落超管配置的默认企业(与个人版 getEnterpriseIdForApiPayload 不传参一致,由服务端统一落库) - $defEid = SystemDefaultEnterprise::getId(); - if ($defEid !== null) { - $pricingEnterpriseId = $defEid; - $writeEnterpriseId = $defEid; - } } } $requiresPayment = $this->getRequiresPaymentByTestType($testType, $enterpriseId, $pricingEnterpriseId); @@ -715,6 +708,12 @@ class Test extends BaseController ]); } } + // 已绑定企业时,独立按超管企业版单价扣平台费,与用户实付分列记账。 + try { + EnterpriseBillingService::chargePlatformFeeForTestResult($id, $testType, $writeEnterpriseId); + } catch (\Throwable $e) { + // 平台费扣款失败不阻断主流程 + } // 测试完成佣金结算(无需付款,异步不影响主流程) try { \app\controller\api\Distribution::settleTestCommission($id, $userId, $testType); diff --git a/api/app/controller/superadmin/Settings.php b/api/app/controller/superadmin/Settings.php index 0b0990a..8d23d40 100644 --- a/api/app/controller/superadmin/Settings.php +++ b/api/app/controller/superadmin/Settings.php @@ -61,19 +61,19 @@ class Settings extends BaseController 'defaultEnterpriseId' => null, ]; $systemOut = $systemDefault; + // 仅当 system 行「未包含」maintenanceMode 键时,才用旧表 review_mode 回退(否则关闭审核后会被 review_mode.enabled 再次顶成「已开启」) + $hasMaintenanceKeyInSystem = false; if ($systemConfig && $systemConfig->value !== null && $systemConfig->value !== '') { $raw = $systemConfig->value; $decoded = is_array($raw) ? $raw : (is_string($raw) ? json_decode($raw, true) : null); if (is_array($decoded)) { + $hasMaintenanceKeyInSystem = array_key_exists('maintenanceMode', $decoded); $systemOut = array_merge($systemDefault, $decoded); } } - // 审核模式唯一口径:system.maintenanceMode(布尔)。兼容旧版 review_mode.enabled - $maint = false; - if (isset($systemOut['maintenanceMode'])) { - $maint = (bool) $systemOut['maintenanceMode']; - } - if (!$maint && $reviewModeConfig && !empty($reviewModeConfig->value)) { + // 审核模式:system.maintenanceMode 为唯一口径;兼容旧数据仅在没有该键时读 review_mode.enabled + $maint = (bool) ($systemOut['maintenanceMode'] ?? false); + if (!$hasMaintenanceKeyInSystem && !$maint && $reviewModeConfig && !empty($reviewModeConfig->value)) { $rv = $reviewModeConfig->value; if (is_string($rv)) { $rv = json_decode($rv, true); @@ -187,6 +187,21 @@ class Settings extends BaseController $config->value = array_merge($oldArr, $data); $config->save(); + // 与旧版 review_mode 行同步,避免库内 enabled=true 与 system.maintenanceMode=false 并存 + if (array_key_exists('maintenanceMode', $data)) { + $rmRow = SystemConfigModel::where('key', 'review_mode')->where('enterprise_id', 0)->find(); + if ($rmRow) { + $rv = $rmRow->value; + $rv = is_array($rv) ? $rv : (is_string($rv) ? (json_decode($rv, true) ?: []) : []); + if (!is_array($rv)) { + $rv = []; + } + $rv['enabled'] = !empty($data['maintenanceMode']); + $rmRow->value = $rv; + $rmRow->save(); + } + } + // 更新站点信息 $this->updateSiteInfo($data); @@ -528,6 +543,18 @@ class Settings extends BaseController $config->value = $oldArr; $config->save(); + $rmRow = SystemConfigModel::where('key', 'review_mode')->where('enterprise_id', 0)->find(); + if ($rmRow) { + $rv = $rmRow->value; + $rv = is_array($rv) ? $rv : (is_string($rv) ? (json_decode($rv, true) ?: []) : []); + if (!is_array($rv)) { + $rv = []; + } + $rv['enabled'] = (bool) $on; + $rmRow->value = $rv; + $rmRow->save(); + } + return success([ 'maintenanceMode' => (bool) $on, 'enabled' => (bool) $on, diff --git a/api/app/model/PricingConfig.php b/api/app/model/PricingConfig.php index 53aa3ed..6071635 100644 --- a/api/app/model/PricingConfig.php +++ b/api/app/model/PricingConfig.php @@ -1,117 +1,101 @@ - 'int', - 'type' => 'string', - 'enterpriseId' => 'int', - 'config' => 'string', - 'createdAt' => 'int', - 'updatedAt' => 'int', - ]; - - // 自动时间戳(使用驼峰命名,时间戳格式) - protected $autoWriteTimestamp = 'int'; - - // 时间戳字段名(驼峰命名,匹配数据库) - protected $createTime = 'createdAt'; - protected $updateTime = 'updatedAt'; - - // 时间字段类型(时间戳格式) - protected $type = [ - 'createdAt' => 'integer', - 'updatedAt' => 'integer', - ]; - - // JSON字段自动转换 - protected $json = ['config']; - - /** - * 配置修改器(自动转换为JSON) - */ - public function setConfigAttr($value) - { - if (is_array($value)) { - return json_encode($value, JSON_UNESCAPED_UNICODE); - } - return $value; - } - - /** - * 配置获取器(自动解析JSON) - */ - public function getConfigAttr($value) - { - if (is_string($value)) { - return json_decode($value, true); - } - return $value; - } - - /** - * 按类型与可选企业ID取定价配置 - * - * personal(个人版)优先级: - * 1. admin_personal + enterpriseId(企业专属管理端配置,有 eid 时) - * 2. admin_personal + null(通用管理端配置) - * 3. 任意一条 admin_personal(兜底:只要管理端配过就不走超管) - * 4. personal + null(超管全局,仅在管理端完全未配置时使用) - * - * enterprise(企业版)优先级: - * 1. admin_enterprise + enterpriseId(有 eid 时) - * 2. admin_enterprise + null(通用管理端企业配置) - * 3. 任意一条 admin_enterprise - * 4. enterprise + null(超管全局兜底) - * - * @param string $type personal|enterprise|deep - * @param int|null $enterpriseId 有则优先读该企业专属配置 - * @return \app\model\PricingConfig|null - */ - public static function getByTypeAndEnterprise(string $type, ?int $enterpriseId = null): ?self - { - if ($type === 'personal') { - if (!empty($enterpriseId)) { - $row = self::where('type', 'admin_personal')->where('enterpriseId', $enterpriseId)->find(); - if ($row) return $row; - } - // 通用管理端个人配置(admin_personal + null) - $row = self::where('type', 'admin_personal')->whereNull('enterpriseId')->find(); - if ($row) return $row; - // 任意管理端个人配置(兜底:管理端配过就不走超管) - $row = self::where('type', 'admin_personal')->order('id', 'asc')->find(); - if ($row) return $row; - // 超管全局个人定价(最后兜底,仅管理端完全未配置时使用) - return self::where('type', 'personal')->whereNull('enterpriseId')->find(); - } - if ($type === 'enterprise') { - if (!empty($enterpriseId)) { - $row = self::where('type', 'admin_enterprise')->where('enterpriseId', $enterpriseId)->find(); - if ($row) return $row; - } - // 通用管理端企业配置(admin_enterprise + null) - $row = self::where('type', 'admin_enterprise')->whereNull('enterpriseId')->find(); - if ($row) return $row; - // 任意管理端企业配置(兜底) - $row = self::where('type', 'admin_enterprise')->order('id', 'asc')->find(); - if ($row) return $row; - return self::where('type', 'enterprise')->whereNull('enterpriseId')->find(); - } - if ($type === 'deep') { - return self::where('type', 'deep')->whereNull('enterpriseId')->find(); - } - return self::where('type', $type)->whereNull('enterpriseId')->find(); - } -} - + 'int', + 'type' => 'string', + 'enterpriseId' => 'int', + 'config' => 'string', + 'createdAt' => 'int', + 'updatedAt' => 'int', + ]; + + // 自动时间戳(使用驼峰命名,时间戳格式) + protected $autoWriteTimestamp = 'int'; + + // 时间戳字段名(驼峰命名,匹配数据库) + protected $createTime = 'createdAt'; + protected $updateTime = 'updatedAt'; + + // 时间字段类型(时间戳格式) + protected $type = [ + 'createdAt' => 'integer', + 'updatedAt' => 'integer', + ]; + + // JSON字段自动转换 + protected $json = ['config']; + + /** + * 配置修改器(自动转换为JSON) + */ + public function setConfigAttr($value) + { + if (is_array($value)) { + return json_encode($value, JSON_UNESCAPED_UNICODE); + } + return $value; + } + + /** + * 配置获取器(自动解析JSON) + */ + public function getConfigAttr($value) + { + if (is_string($value)) { + return json_decode($value, true); + } + return $value; + } + + /** + * 按类型与可选企业ID取定价配置 + * + * personal(个人版)优先级: + * 1. admin_personal + enterpriseId(企业专属管理端配置,有 eid 时) + * 2. personal + null(超管全局,仅未绑定企业或该企业未配置时使用) + * + * enterprise(企业版)优先级: + * 1. admin_enterprise + enterpriseId(有 eid 时) + * 2. enterprise + null(超管全局兜底) + * + * @param string $type personal|enterprise|deep + * @param int|null $enterpriseId 有则优先读该企业专属配置 + * @return \app\model\PricingConfig|null + */ + public static function getByTypeAndEnterprise(string $type, ?int $enterpriseId = null): ?self + { + if ($type === 'personal') { + if (!empty($enterpriseId)) { + $row = self::where('type', 'admin_personal')->where('enterpriseId', $enterpriseId)->find(); + if ($row) return $row; + } + // 超管全局个人定价(最后兜底,仅管理端完全未配置时使用) + return self::where('type', 'personal')->whereNull('enterpriseId')->find(); + } + if ($type === 'enterprise') { + if (!empty($enterpriseId)) { + $row = self::where('type', 'admin_enterprise')->where('enterpriseId', $enterpriseId)->find(); + if ($row) return $row; + } + return self::where('type', 'enterprise')->whereNull('enterpriseId')->find(); + } + if ($type === 'deep') { + return self::where('type', 'deep')->whereNull('enterpriseId')->find(); + } + return self::where('type', $type)->whereNull('enterpriseId')->find(); + } +} + diff --git a/api/docs/定价与企业账务规则说明.md b/api/docs/定价与企业账务规则说明.md new file mode 100644 index 0000000..41c7aed --- /dev/null +++ b/api/docs/定价与企业账务规则说明.md @@ -0,0 +1,147 @@ +# 定价与企业账务规则说明 + +> **文档用途**:供产品/运营阅读业务口径,供 AI 与研发对齐实现与测试用例。 +> **状态**:下述「目标账务口径」与线上代码可能不一致,落地前需对照 `Test` / `Payment` / `finance_records` 做改造与验收。 + +--- + +## 1. 一句话摘要 + +- **用户付多少**:主要由**企业端**「个人版 / 企业版」单价决定;**未绑定企业**时回落**超管个人版**单价。 +- **企业扣款(平台费)**:在**已绑定企业**且满足条件时,按**超管「企业版」**维度配置的单价(示例中 PDP **1 元**)从企业余额扣费。 +- **企业收入**:通常对应**用户实付**进入企业的部分(与「平台扣款」分列科目,净额可另做报表)。 + +--- + +## 2. 术语表 + +| 术语 | 含义 | +|:---|:---| +| **超管全局价** | 超级管理员在「全局定价」中维护的 `pricing_config`:`type = personal \| enterprise` 且 `enterpriseId` 为空。 | +| **企业端价** | 企业在管理后台维护的:`admin_personal`、`admin_enterprise`(可按企业 ID 覆盖)。 | +| **个人版测试** | 请求未带企业测试上下文,`test_results.testScope = personal`(用户从个人入口完成测评)。 | +| **企业版测试** | 请求带企业测试上下文,`test_results.testScope = enterprise`。 | +| **绑定企业** | 用户账号 `wechat_users.enterpriseId` 指向某企业(或业务上认可的等价判定)。 | +| **用户付费** | 终端用户通过微信支付等方式支付的金额。 | +| **企业扣款** | 从企业**余额**中扣减(`finance_records.type = consume` 等),表示平台向企业收取的费用。 | +| **企业收入** | 企业因该笔业务获得的收入(常与用户实付入账对应;与扣款分列)。 | + +--- + +## 3. 配置分层(示例) + +以下数值仅为**文档示例**,实际以数据库配置为准。 + +### 3.1 超管全局 + +| 维度 | PDP 单价(示例) | +|:---|:---:| +| 超管 · **个人版** | 0 元 | +| 超管 · **企业版** | 1 元 | + +### 3.2 某企业(企业端) + +| 维度 | PDP 单价(示例) | +|:---|:---:| +| 企业端 · **个人版**(`admin_personal`) | 0.1 元 | +| 企业端 · **企业版**(`admin_enterprise`) | 0 元 | + +--- + +## 4. 业务规则(目标口径) + +下列规则按**优先级**书写,便于实现与单测。 + +### 4.1 用户侧应付金额 + +1. **已绑定企业**且走**个人版测试**:按该企业 **企业端个人版** 定价计算是否需付费及金额(示例 PDP **0.1 元**)。 +2. **已绑定企业**且走**企业版测试**:按该企业 **企业端企业版** 定价计算(示例 PDP **0 元** → 用户无需付费)。 +3. **未绑定企业**且走**个人版测试**:按 **超管个人版** 定价计算(示例 PDP **0 元** → 用户无需付费)。 +4. 若存在「小程序默认企业」等回落逻辑,是否视为绑定,**须单独在产品上定稿**(本文示例 **C** 按**未绑定**处理)。 + +### 4.2 企业侧平台扣款(示例中的「扣 1」) + +1. 当用户**已绑定企业**,且业务要求对该笔测试收取**平台费**时:扣费金额取 **超管「企业版」** 中对应测试类型单价(示例 PDP **1 元**)。 +2. **个人版测试**与**企业版测试**只要满足「已绑定企业 + 触发扣费条件」,均可发生该企业扣款(示例 **A、B** 均扣 **1 元**)。 +3. **未绑定企业**(示例 **C**):不发生面向企业的平台扣款。 + +### 4.3 企业收入(与用户实付对应) + +1. 用户有实付时,企业收入可按实付记账(示例 **A**:用户付 **0.1 元** → 企业收入 **0.1 元**)。 +2. 用户无实付时,企业收入为 **0**(示例 **B**)。 +3. 「企业扣款」与「企业收入」**分列**;是否在报表中汇总为**净额**,由财务/产品另定。 + +--- + +## 5. 场景对照表(文档示例) + +**前提**:超管个人 0 / 企业 PDP 1;该企业端个人 0.1 / 企业 0。 + +| 编号 | 绑定企业 | 测试方式 | 用户付费 | 企业扣款(平台费,示例) | 企业收入(示例) | +|:---:|:---:|:---|:---:|:---:|:---:| +| **A** | 是 | 个人版 | 0.1 元 | 1 元 | 0.1 元 | +| **B** | 是 | 企业版 | 0 | 1 元 | 0 | +| **C** | 否 | 个人版 | 0 | — | — | + +--- + +## 6. 机器可读摘要(供 AI / 自动化) + +下列 YAML 与正文一致,便于检索与生成测试数据。 + +```yaml +# 定价与企业账务规则说明 — 规则摘要(示例配置内嵌) +version: 1 +currency: CNY +test_type_example: pdp + +super_admin_global: + personal: { pdp: 0 } + enterprise: { pdp: 1 } + +enterprise_admin_example: + admin_personal: { pdp: 0.1 } + admin_enterprise: { pdp: 0 } + +scenarios: + - id: A + user_bound_enterprise: true + test_scope: personal + user_pays_yuan: 0.1 + enterprise_platform_fee_yuan: 1 + enterprise_revenue_yuan: 0.1 + - id: B + user_bound_enterprise: true + test_scope: enterprise + user_pays_yuan: 0 + enterprise_platform_fee_yuan: 1 + enterprise_revenue_yuan: 0 + - id: C + user_bound_enterprise: false + test_scope: personal + user_pays_yuan: 0 + enterprise_platform_fee_yuan: null + enterprise_revenue_yuan: null + +rule_hints: + user_price_source: enterprise_admin_when_bound_else_super_admin_personal + enterprise_fee_source_super_admin: enterprise_tier_global + note: 实现时需确认与现有 Payment 入账逻辑是否合并或拆分科目 +``` + +--- + +## 7. 与当前实现的差异(给研发) + +- 现有逻辑中,**用户支付成功**常将金额记入企业余额(入账),**未必**存在「按超管企业版单价固定扣平台费」的独立流水。 +- 若完全实现本文 **4.2**,需在测试完成或支付闭环处增加**幂等**的企业扣款(`consume`)及与订单、分销的**顺序**约定。 +- 「企业收入 0.1」与「企业扣款 1」并存时,**余额净变化**需在财务口径上明确(避免与现网「只加不减」假设冲突)。 + +--- + +## 8. 修订记录 + +| 日期 | 说明 | +|:---|:---| +| 2026-04-13 | 初稿:整合超管/企业端示例与 A/B/C 场景及 YAML 摘要 | +| 2026-04-13 | 文档文件名改为中文:`定价与企业账务规则说明.md` | diff --git a/miniprogram/app.js b/miniprogram/app.js index 6273602..d46c4e3 100644 --- a/miniprogram/app.js +++ b/miniprogram/app.js @@ -47,8 +47,8 @@ App({ // 超管配置的默认企业 ID(无 scene/eid 等入口参数时回落) defaultEnterpriseId: null, // API基础地址(开发时用本地,生产环境替换为实际域名) - apiBase: 'https://mbtiapi.quwanzhi.com', - //apiBase: 'http://mbti.com', + //apiBase: 'https://mbtiapi.quwanzhi.com', + apiBase: 'http://mbti.com', // VIP信息 vipInfo: null, // 测试次数