文件
xionggeshop/addons/shopro/tests/commission_setup_test_users.php

480 行
18 KiB
PHP

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<?php
/**
* 分销测试用户 & 配置初始化
*
* 用法(项目根目录):
* php addons/shopro/tests/commission_setup_test_users.php
* php addons/shopro/tests/commission_setup_test_users.php --goods-id=123
* php addons/shopro/tests/commission_setup_test_users.php --addresses-only --goods-id=195
* php addons/shopro/tests/commission_setup_test_users.php --addresses-only --money=10000
*
* 清理测试数据:
* php addons/shopro/tests/commission_cleanup_test_users.php --dry-run
* php addons/shopro/tests/commission_cleanup_test_users.php --confirm
*/
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit("请通过命令行运行\n");
}
define('APP_PATH', __DIR__ . '/../../../application/');
define('ROOT_PATH', __DIR__ . '/../../../');
if (!is_file(APP_PATH . 'admin/command/Install/install.lock')) {
fwrite(STDERR, "项目未安装。\n");
exit(1);
}
require ROOT_PATH . 'thinkphp/base.php';
\think\App::initCommon();
use think\Db;
const TEST_PASSWORD = 'Test@123456';
const TEST_SALT = 'fxtest01';
const TEST_PASSWORD_HASH = '2e6b7166bb58caa2a84dd3eca3391f67';
const TEST_USER_MONEY = 10000;
$argv = $GLOBALS['argv'] ?? [];
$goodsId = 0;
$userMoney = TEST_USER_MONEY;
$addressesOnly = in_array('--addresses-only', $argv, true);
foreach ($argv as $arg) {
if (strpos($arg, '--goods-id=') === 0) {
$goodsId = intval(substr($arg, 11));
}
if (strpos($arg, '--money=') === 0) {
$userMoney = max(0, floatval(substr($arg, 8)));
}
}
echo "=== 分销测试数据初始化 ===\n\n";
if ($addressesOnly) {
if (!$goodsId) {
$goodsId = intval(Db::name('shopro_commission_goods')->where('status', 1)->value('goods_id')) ?: 195;
}
try {
setupTestUserMoney($userMoney);
$area = setupTestAddresses($goodsId);
echo "\n配送区域内地址: {$area['province_name']}{$area['city_name']}{$area['area_name']}\n";
echo "测试用户余额: {$userMoney} 元\n";
echo "请重新进入下单页或刷新后再提交订单。\n";
} catch (\Throwable $e) {
fwrite(STDERR, "失败: " . $e->getMessage() . "\n");
exit(1);
}
exit(0);
}
Db::startTrans();
try {
setupCommissionConfig();
setupAgentLevels();
setupUsersAndAgents();
setupTestUserMoney($userMoney);
$goodsId = setupCommissionGoods($goodsId);
if ($goodsId) {
setupTestAddresses($goodsId);
}
Db::commit();
} catch (\Throwable $e) {
Db::rollback();
fwrite(STDERR, "失败: " . $e->getMessage() . "\n");
exit(1);
}
echo "\n========================================\n";
echo " 初始化完成 · 登录信息如下\n";
echo "========================================\n\n";
echo "小程序登录:我的 → 账号登录\n";
echo "统一密码:" . TEST_PASSWORD . "\n";
echo "测试余额:{$userMoney} 元(可用 --money= 自定义)\n\n";
$users = getTestUserDefs();
foreach ($users as $u) {
echo sprintf(" [%s] %s\n", $u['role'], $u['nickname']);
echo sprintf(" 手机号: %s(推荐,账号登录填这个)\n", $u['mobile']);
echo sprintf(" 用户名: %s\n", $u['username']);
echo sprintf(" 用户ID: %d\n\n", $u['id']);
}
echo "推荐验证账号:\n";
echo " 首购场景 → 用【测试D-买家】19900000004 下单\n";
echo " 自购场景 → 用【测试C-直推】19900000003 自己下单\n";
echo " 复购场景 → D 先下一单,再下一单\n\n";
if ($goodsId) {
$goods = Db::name('shopro_goods')->where('id', $goodsId)->field('id,title,price')->find();
echo "测试商品: ID={$goodsId} {$goods['title']} 价格={$goods['price']}元\n";
echo "(请用该商品下单,单价1000左右最易对照预期佣金)\n\n";
$addr = Db::name('shopro_user_address')->where('user_id', 900004)->where('is_default', '1')->find();
if ($addr) {
echo "默认收货地址(D): {$addr['province_name']}{$addr['city_name']}{$addr['area_name']}{$addr['address']}\n\n";
}
}
echo "支付后验证:\n";
echo " php addons/shopro/tests/commission_verify.php verify-item {订单明细ID}\n\n";
echo "关系链: A(三级) ← B(二级) ← C(直推) ← D(买家)\n";
function getTestUserDefs()
{
return [
['id' => 900001, 'username' => 'test_agent_a', 'nickname' => '测试A-三级', 'mobile' => '19900000001', 'parent' => 0, 'role' => '三级分销商A'],
['id' => 900002, 'username' => 'test_agent_b', 'nickname' => '测试B-二级', 'mobile' => '19900000002', 'parent' => 900001, 'role' => '二级分销商B'],
['id' => 900003, 'username' => 'test_agent_c', 'nickname' => '测试C-直推', 'mobile' => '19900000003', 'parent' => 900002, 'role' => '一级分销商C'],
['id' => 900004, 'username' => 'test_buyer_d', 'nickname' => '测试D-买家', 'mobile' => '19900000004', 'parent' => 900003, 'role' => '买家D'],
];
}
function setupCommissionConfig()
{
$pairs = [
30 => ['chain_commission_enable', '1', 'basic', '关系链分佣开关'],
31 => ['differential_commission_enable', '1', 'basic', '级差奖开关'],
];
foreach ($pairs as $id => $row) {
$exists = Db::name('shopro_commission_config')->where('id', $id)->find();
if ($exists) {
Db::name('shopro_commission_config')->where('id', $id)->update(['value' => $row[1]]);
} else {
Db::name('shopro_commission_config')->insert([
'id' => $id, 'name' => $row[0], 'value' => $row[1], 'group' => $row[2], 'description' => $row[3],
]);
}
}
$updates = [
'management_award_enable' => '1',
'repurchase_referrer_enable' => '1',
'repurchase_self_enable' => '1',
'repurchase_self_type' => 'fixed',
'repurchase_self_amount' => '5',
'chain_commission_enable' => '1',
'differential_commission_enable' => '1',
'commission_level' => '3',
'self_buy' => '1',
'commission_price_type' => 'goods_price',
'commission_event' => 'payed',
'agent_check' => '0',
];
foreach ($updates as $name => $value) {
Db::name('shopro_commission_config')->where('name', $name)->update(['value' => $value]);
}
echo "[OK] 分销配置已更新(三级、内购开、支付后结算、商品价、免审核)\n";
}
function setupAgentLevels()
{
$levels = [
1 => '{"commission_1":"10.00","commission_2":"0.00","commission_3":"0.00","differential_amount":"40","management_rate":"5"}',
2 => '{"commission_1":"10.00","commission_2":"5.00","commission_3":"0.00","differential_amount":"80","management_rate":"3"}',
3 => '{"commission_1":"10.00","commission_2":"5.00","commission_3":"3.00","differential_amount":"120","management_rate":"2"}',
];
foreach ($levels as $level => $rules) {
$row = Db::name('shopro_commission_agent_level')->where('level', $level)->find();
if ($row) {
Db::name('shopro_commission_agent_level')->where('level', $level)->update(['commission_rules' => $rules]);
} else {
Db::name('shopro_commission_agent_level')->insert([
'level' => $level,
'name' => '测试等级' . $level,
'image' => '',
'commission_rules' => $rules,
'upgrade_type' => 0,
'upgrade_rules' => '{}',
]);
}
}
echo "[OK] 分销商等级档位已设置(L1:40/5% L2:80/3% L3:120/2%)\n";
}
function setupUsersAndAgents()
{
$ts = time();
$host = 'test.local';
$agents = [
900001 => ['level' => 3, 'parent_agent_id' => 0],
900002 => ['level' => 2, 'parent_agent_id' => 900001],
900003 => ['level' => 1, 'parent_agent_id' => 900002],
];
foreach (getTestUserDefs() as $u) {
$conflict = Db::name('user')->where('mobile', $u['mobile'])->where('id', '<>', $u['id'])->find();
if ($conflict) {
Db::name('user')->where('id', $conflict['id'])->update([
'mobile' => $u['mobile'] . '_old' . $conflict['id'],
'updatetime' => $ts,
]);
echo "[WARN] 手机号 {$u['mobile']} 曾被用户 {$conflict['id']} 占用,已改号\n";
}
$exists = Db::name('user')->where('id', $u['id'])->find();
$base = [
'username' => $u['username'],
'nickname' => $u['nickname'],
'password' => TEST_PASSWORD_HASH,
'salt' => TEST_SALT,
'mobile' => $u['mobile'],
'email' => $u['mobile'] . '@' . $host,
'parent_user_id' => $u['parent'],
'status' => 'normal',
'updatetime' => $ts,
'level' => 1,
'score' => 0,
'total_consume' => 0,
];
if ($exists) {
Db::name('user')->where('id', $u['id'])->update($base);
echo "[UPD] 用户 {$u['nickname']} ({$u['id']})\n";
} else {
$base['id'] = $u['id'];
$base['createtime'] = $ts;
$base['jointime'] = $ts;
$base['joinip'] = '127.0.0.1';
$base['loginip'] = '127.0.0.1';
$base['logintime'] = $ts;
$base['prevtime'] = $ts;
Db::name('user')->insert($base);
echo "[NEW] 用户 {$u['nickname']} ({$u['id']})\n";
}
}
foreach ($agents as $userId => $agent) {
$exists = Db::name('shopro_commission_agent')->where('user_id', $userId)->find();
$data = [
'level' => $agent['level'],
'parent_agent_id' => $agent['parent_agent_id'],
'status' => 'normal',
'info_status' => 1,
'becometime' => $ts,
'updatetime' => $ts,
];
if ($exists) {
Db::name('shopro_commission_agent')->where('user_id', $userId)->update($data);
} else {
$data['user_id'] = $userId;
$data['createtime'] = $ts;
Db::name('shopro_commission_agent')->insert($data);
}
}
echo "[OK] 分销商 A/B/C 已就绪,D 为普通买家\n";
}
function setupTestUserMoney($money)
{
$money = number_format(floatval($money), 2, '.', '');
$ts = time();
foreach (getTestUserDefs() as $u) {
$exists = Db::name('user')->where('id', $u['id'])->find();
if (!$exists) {
echo "[SKIP] 用户 {$u['id']} 不存在,跳过充值\n";
continue;
}
Db::name('user')->where('id', $u['id'])->update([
'money' => $money,
'updatetime' => $ts,
]);
echo "[OK] 余额 {$u['nickname']} ({$u['id']}) = {$money} 元\n";
}
}
function setupCommissionGoods($goodsId)
{
if (!$goodsId) {
$row = Db::name('shopro_commission_goods')
->alias('cg')
->join('shopro_goods g', 'g.id = cg.goods_id')
->where('cg.status', 1)
->where('cg.differential_enable', 1)
->field('cg.goods_id, g.title')
->find();
if ($row) {
$goodsId = intval($row['goods_id']);
echo "[OK] 使用已有分销商品 ID={$goodsId} {$row['title']}\n";
}
}
if (!$goodsId) {
$row = Db::name('shopro_goods')->where('status', 'up')->order('id desc')->field('id,title,price')->find();
if ($row) {
$goodsId = intval($row['id']);
echo "[INFO] 自动选用上架商品 ID={$goodsId} {$row['title']}\n";
}
}
if (!$goodsId) {
echo "[WARN] 未找到可用商品,请手动在后台配置分销商品,或执行: --goods-id=商品ID\n";
return 0;
}
$exists = Db::name('shopro_commission_goods')->where('goods_id', $goodsId)->find();
$data = [
'status' => 1,
'self_rules' => 0,
'commission_rules' => '{}',
'commission_config' => '',
'commission_order_status' => 1,
'differential_enable' => 1,
'management_enable' => 1,
'repurchase_enable' => 1,
];
if ($exists) {
Db::name('shopro_commission_goods')->where('goods_id', $goodsId)->update($data);
} else {
$data['goods_id'] = $goodsId;
Db::name('shopro_commission_goods')->insert($data);
}
echo "[OK] 商品 {$goodsId} 已开启:参与分销 + 级差 + 管理奖 + 复购返现\n";
return $goodsId;
}
function setupTestAddresses($goodsId)
{
$area = resolveDeliveryAreaForGoods($goodsId);
if (!$area) {
throw new \Exception('无法解析商品配送区域,请检查运费模板');
}
$ts = time();
foreach (getTestUserDefs() as $u) {
$exists = Db::name('shopro_user_address')
->where('user_id', $u['id'])
->where(function ($query) {
$query->whereNull('deletetime')->whereOr('deletetime', 0);
})
->order('id asc')
->find();
$data = [
'is_default' => '1',
'consignee' => str_replace('测试', '', $u['nickname']),
'phone' => $u['mobile'],
'province_name' => $area['province_name'],
'city_name' => $area['city_name'],
'area_name' => $area['area_name'],
'address' => '分销测试地址1号',
'province_id' => $area['province_id'],
'city_id' => $area['city_id'],
'area_id' => $area['area_id'],
'updatetime' => $ts,
];
if ($exists) {
Db::name('shopro_user_address')->where('user_id', $u['id'])->update(['is_default' => '0']);
Db::name('shopro_user_address')->where('id', $exists['id'])->update($data);
echo "[UPD] 地址 {$u['nickname']} -> {$area['province_name']}{$area['city_name']}{$area['area_name']}\n";
} else {
$data['user_id'] = $u['id'];
$data['createtime'] = $ts;
Db::name('shopro_user_address')->insert($data);
echo "[NEW] 地址 {$u['nickname']} -> {$area['province_name']}{$area['city_name']}{$area['area_name']}\n";
}
}
echo "[OK] 测试用户默认收货地址已写入(与商品运费模板配送范围一致)\n";
return $area;
}
function resolveDeliveryAreaForGoods($goodsId)
{
$goods = Db::name('shopro_goods')->where('id', $goodsId)->field('dispatch_ids,dispatch_type')->find();
if ($goods && strpos($goods['dispatch_type'] ?? '', 'express') !== false && !empty($goods['dispatch_ids'])) {
$dispatchIds = array_filter(explode(',', $goods['dispatch_ids']));
$dispatch = Db::name('shopro_dispatch')->where('type', 'express')->where('id', 'in', $dispatchIds)->find();
if ($dispatch && !empty($dispatch['type_ids'])) {
$expressIds = array_filter(explode(',', $dispatch['type_ids']));
$expressList = Db::name('shopro_dispatch_express')
->where('id', 'in', $expressIds)
->where(function ($query) {
$query->whereNull('deletetime')->whereOr('deletetime', 0);
})
->order('weigh desc,id asc')
->select();
foreach ($expressList as $express) {
$area = pickAreaFromExpress($express);
if ($area) {
return $area;
}
}
}
}
// 默认:贵州省贵阳市南明区(多数本地店铺配送范围)
return buildAreaInfo(520102);
}
function pickAreaFromExpress($express)
{
foreach (['area_ids', 'city_ids', 'province_ids'] as $field) {
if (empty($express[$field])) {
continue;
}
$ids = array_filter(array_map('trim', explode(',', $express[$field])));
foreach ($ids as $id) {
$id = intval($id);
if ($id <= 0) {
continue;
}
$row = Db::name('shopro_area')->where('id', $id)->find();
if (!$row) {
continue;
}
if (intval($row['level']) === 3) {
$area = buildAreaInfo($id);
if ($area) {
return $area;
}
}
if (intval($row['level']) === 2) {
$areaRow = Db::name('shopro_area')->where('pid', $id)->where('level', 3)->order('id asc')->find();
if ($areaRow) {
$area = buildAreaInfo($areaRow['id']);
if ($area) {
return $area;
}
}
}
if (intval($row['level']) === 1) {
$city = Db::name('shopro_area')->where('pid', $id)->where('level', 2)->order('id asc')->find();
if ($city) {
$areaRow = Db::name('shopro_area')->where('pid', $city['id'])->where('level', 3)->order('id asc')->find();
if ($areaRow) {
$area = buildAreaInfo($areaRow['id']);
if ($area) {
return $area;
}
}
}
}
}
}
return null;
}
function buildAreaInfo($areaId)
{
$area = Db::name('shopro_area')->where('id', $areaId)->find();
if (!$area || intval($area['level']) !== 3) {
return null;
}
$city = Db::name('shopro_area')->where('id', $area['pid'])->find();
if (!$city) {
return null;
}
$province = Db::name('shopro_area')->where('id', $city['pid'])->find();
if (!$province) {
return null;
}
return [
'province_id' => intval($province['id']),
'province_name' => $province['name'],
'city_id' => intval($city['id']),
'city_name' => $city['name'],
'area_id' => intval($area['id']),
'area_name' => $area['name'],
];
}