480 行
18 KiB
PHP
480 行
18 KiB
PHP
<?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'],
|
||
];
|
||
}
|