Commit 53b7e656 by 杨树贤

完善脚本

parent b2f59072
<?php
namespace App\Console\Commands;
use App\Http\Services\SupplierService;
use Illuminate\Console\Command;
// 刷新历史数据:自动分配猎芯采购和数据跟单员
class RefreshHistoryPurchaseUser extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'refresh:history_purchase_user {--mode=prod : 运行模式(prod=生产模式执行更新,debug=调试模式仅打印)} {--num=0 : 处理数量限制(0=不限制)}';
/**
* The console command description.
*
* @var string
*/
protected $description = '刷新历史数据:自动分配猎芯采购和数据跟单员';
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$mode = $this->option('mode');
$num = (int)$this->option('num');
$isProdMode = ($mode === 'prod');
$this->info('========================================');
$this->info('开始刷新历史数据');
$this->info('模式: ' . ($isProdMode ? '生产模式(执行更新)' : '调试模式(仅打印)'));
$this->info('处理数量: ' . ($num > 0 ? $num : '不限制'));
$this->info('========================================');
// 调用服务方法
$result = SupplierService::refreshHistoryPurchaseUserWithProgress($mode, $num, function ($progress) {
$this->outputProgress($progress);
});
// 输出最终结果
$this->info('');
$this->info('========================================');
$this->info('处理完成');
$this->info('总计: ' . $result['total']);
$this->info('成功: ' . $result['success']);
$this->info('失败: ' . $result['failed']);
$this->info('跳过: ' . $result['skipped']);
$this->info('========================================');
// 如果有失败记录,打印详情
if (!empty($result['debug_info'])) {
$this->info('');
$this->warn('失败/跳过详情:');
foreach ($result['debug_info'] as $info) {
$this->warn(sprintf(
' [ID:%d] %s - %s',
$info['supplier_id'],
$info['supplier_name'] ?? '',
$info['fail_reason'] ?? $info['skip_reason'] ?? ''
));
}
}
return 0;
}
/**
* 输出进度信息
*/
private function outputProgress($progress)
{
$supplierId = $progress['supplier_id'];
$supplierName = $progress['supplier_name'];
$action = $progress['action'] ?? '';
$status = $progress['status'] ?? '';
$statusIcon = $status === 'success' ? '✓' : ($status === 'skip' ? '-' : '✗');
$statusColor = $status === 'success' ? 'info' : ($status === 'skip' ? 'comment' : 'error');
$this->$statusColor(sprintf(
' [%s] ID:%d %s - %s',
$statusIcon,
$supplierId,
$supplierName,
$action
));
}
}
...@@ -886,10 +886,10 @@ class SupplierApiController extends Controller ...@@ -886,10 +886,10 @@ class SupplierApiController extends Controller
//刷新历史数据:自动分配猎芯采购和数据跟单员 //刷新历史数据:自动分配猎芯采购和数据跟单员
public function RefreshHistoryPurchaseUser($request) public function RefreshHistoryPurchaseUser($request)
{ {
$updateData = $request->get('update_data', false); $mode = $request->get('mode', 'debug'); // prod=生产模式执行数据处理,其他=调试模式
$limit = $request->get('limit', 100); $num = $request->get('num', 50); // 处理数量限制
$result = SupplierService::refreshHistoryPurchaseUser($updateData, $limit); $result = SupplierService::refreshHistoryPurchaseUser($mode, $num);
$this->response(0, '刷新完成', $result); $this->response(0, '刷新完成', $result);
} }
......
...@@ -1067,8 +1067,14 @@ class SupplierService ...@@ -1067,8 +1067,14 @@ class SupplierService
* @param int $skuPurchaseCodeId 设置的SKU采购员codeId * @param int $skuPurchaseCodeId 设置的SKU采购员codeId
* @return bool * @return bool
*/ */
public function autoAssignPurchaseUser($supplierId, $skuPurchaseCodeId) public function autoAssignPurchaseUser($supplierId, $skuPurchaseCodeId, $executeUpdate = true)
{ {
$result = [
'success' => false,
'reason' => '',
'debug_info' => [],
];
$adminUserService = new AdminUserService(); $adminUserService = new AdminUserService();
// 检查供应商是否已有猎芯采购和数据跟单员,如果两者都有则跳过 // 检查供应商是否已有猎芯采购和数据跟单员,如果两者都有则跳过
...@@ -1081,25 +1087,30 @@ class SupplierService ...@@ -1081,25 +1087,30 @@ class SupplierService
if ($hasLiexinPurchase && $hasDataFollower) { if ($hasLiexinPurchase && $hasDataFollower) {
// 已有猎芯采购和数据跟单员,跳过自动分配 // 已有猎芯采购和数据跟单员,跳过自动分配
return true; $result['success'] = true;
$result['reason'] = '已有猎芯采购和数据跟单员,跳过';
return $result;
} }
// 获取SKU采购员信息 // 获取SKU采购员信息
$skuPurchaseUser = $adminUserService->getAdminUserInfoByCodeId($skuPurchaseCodeId); $skuPurchaseUser = $adminUserService->getAdminUserInfoByCodeId($skuPurchaseCodeId);
if (empty($skuPurchaseUser)) { if (empty($skuPurchaseUser)) {
return false; $result['reason'] = '获取SKU采购员信息失败,codeId: ' . $skuPurchaseCodeId;
return $result;
} }
// 获取SKU采购员的部门ID // 获取SKU采购员的部门ID
$skuPurchaseDepartmentId = $skuPurchaseUser['department_id']; $skuPurchaseDepartmentId = $skuPurchaseUser['department_id'];
if (empty($skuPurchaseDepartmentId)) { if (empty($skuPurchaseDepartmentId)) {
return false; $result['reason'] = 'SKU采购员没有部门ID,用户: ' . ($skuPurchaseUser['name'] ?? '未知');
return $result;
} }
// 获取供应商信息 // 获取供应商信息
$supplier = SupplierChannelModel::where('supplier_id', $supplierId)->first(); $supplier = SupplierChannelModel::where('supplier_id', $supplierId)->first();
if (empty($supplier)) { if (empty($supplier)) {
return false; $result['reason'] = '供应商不存在,supplierId: ' . $supplierId;
return $result;
} }
$supplierGroup = $supplier->supplier_group; // 供应商性质:1=代理商,2=现货商,4=原厂 $supplierGroup = $supplier->supplier_group; // 供应商性质:1=代理商,2=现货商,4=原厂
...@@ -1118,13 +1129,25 @@ class SupplierService ...@@ -1118,13 +1129,25 @@ class SupplierService
$isShangPinGongYingLian = strpos($departmentNamesStr, '商品供应链部') !== false; $isShangPinGongYingLian = strpos($departmentNamesStr, '商品供应链部') !== false;
$isXinZhiGongYingLian = strpos($departmentNamesStr, '新质供应链部') !== false; $isXinZhiGongYingLian = strpos($departmentNamesStr, '新质供应链部') !== false;
$result['debug_info'] = [
'sku_purchase_name' => $skuPurchaseUser['name'] ?? '未知',
'sku_purchase_department_id' => $skuPurchaseDepartmentId,
'department_names' => $departmentNames,
'supplier_group' => $supplierGroup,
'is_zhu_dong_guo_chan' => $isZhuDongGuoChan,
'is_bei_dong_guo_chan' => $isBeiDongGuoChan,
'is_shang_pin_gong_ying_lian' => $isShangPinGongYingLian,
'is_xin_zhi_gong_ying_lian' => $isXinZhiGongYingLian,
];
// 需要分配的采购员codeId列表 // 需要分配的采购员codeId列表
$assignCodeIds = []; $assignCodeIds = [];
if ($isZhuDongGuoChan || $isBeiDongGuoChan || $isShangPinGongYingLian) { if ($isZhuDongGuoChan || $isBeiDongGuoChan || $isShangPinGongYingLian) {
// 属于主动兼国产供应链部/被动兼国产供应链部/商品供应链部 // 属于主动兼国产供应链部/被动兼国产供应链部/商品供应链部
$dataFollowerGroup = config('field.ShangpinDataFollowerGroup', []); $dataFollowerGroup = config('field.ShangpinDataFollowerGroup', []);
if (empty($dataFollowerGroup)) { if (empty($dataFollowerGroup)) {
return false; $result['reason'] = '配置ShangpinDataFollowerGroup为空';
return $result;
} }
if ($supplierGroup == SupplierChannelModel::SUPPLIER_GROUP_SPOT) { if ($supplierGroup == SupplierChannelModel::SUPPLIER_GROUP_SPOT) {
...@@ -1135,6 +1158,7 @@ class SupplierService ...@@ -1135,6 +1158,7 @@ class SupplierService
$assignCodeIds[] = $codeId; $assignCodeIds[] = $codeId;
} }
} }
$result['debug_info']['assign_type'] = '现货商-分配4人';
} else { } else {
// 代理商/原厂:随机选商品供应链部数据跟单采购组的其中1人 // 代理商/原厂:随机选商品供应链部数据跟单采购组的其中1人
$randomFollower = $dataFollowerGroup[array_rand($dataFollowerGroup)]; $randomFollower = $dataFollowerGroup[array_rand($dataFollowerGroup)];
...@@ -1142,6 +1166,8 @@ class SupplierService ...@@ -1142,6 +1166,8 @@ class SupplierService
if ($codeId) { if ($codeId) {
$assignCodeIds[] = $codeId; $assignCodeIds[] = $codeId;
} }
$result['debug_info']['assign_type'] = '代理商/原厂-随机分配1人';
$result['debug_info']['random_follower'] = $randomFollower;
} }
} elseif ($isXinZhiGongYingLian) { } elseif ($isXinZhiGongYingLian) {
// 属于新质供应链部:默认欧阳海梅 // 属于新质供应链部:默认欧阳海梅
...@@ -1150,13 +1176,27 @@ class SupplierService ...@@ -1150,13 +1176,27 @@ class SupplierService
if ($codeId) { if ($codeId) {
$assignCodeIds[] = $codeId; $assignCodeIds[] = $codeId;
} }
$result['debug_info']['assign_type'] = '新质供应链部-分配默认人员';
$result['debug_info']['default_name'] = $defaultName;
} else { } else {
// 不属于以上部门,不自动分配 // 不属于以上部门,不自动分配
return false; $result['reason'] = 'SKU采购员不属于目标部门(主动兼国产/被动兼国产/商品/新质供应链部)';
return $result;
} }
if (empty($assignCodeIds)) { if (empty($assignCodeIds)) {
return false; $result['reason'] = '未能获取到要分配的采购员codeId';
return $result;
}
$result['debug_info']['assign_code_ids'] = $assignCodeIds;
// 如果只是调试模式,不执行更新
if (!$executeUpdate) {
$result['success'] = true;
$result['reason'] = '调试模式,未执行实际更新';
return $result;
} }
// 分配采购员:每个人都要分配猎芯采购和数据跟单员两种类型 // 分配采购员:每个人都要分配猎芯采购和数据跟单员两种类型
foreach ($assignCodeIds as $assignCodeId) { foreach ($assignCodeIds as $assignCodeId) {
// 检查是否已存在猎芯采购,不存在则分配 // 检查是否已存在猎芯采购,不存在则分配
...@@ -1178,7 +1218,9 @@ class SupplierService ...@@ -1178,7 +1218,9 @@ class SupplierService
} }
} }
return true; $result['success'] = true;
$result['reason'] = '分配成功';
return $result;
} }
/** /**
...@@ -1206,28 +1248,33 @@ class SupplierService ...@@ -1206,28 +1248,33 @@ class SupplierService
* - 供应商无猎芯采购和数据跟单员的采购员类型时,按规则同时更新猎芯采购和数据跟单员 * - 供应商无猎芯采购和数据跟单员的采购员类型时,按规则同时更新猎芯采购和数据跟单员
* - 供应商有猎芯采购的采购员类型无数据跟单员时,仅更新数据跟单员(将现有猎芯采购人员同时设为数据跟单员) * - 供应商有猎芯采购的采购员类型无数据跟单员时,仅更新数据跟单员(将现有猎芯采购人员同时设为数据跟单员)
* *
* @param bool $updateData 是否真正更新数据 * @param string $mode 模式:prod=生产模式执行数据处理,其他=调试模式仅打印信息
* @param int $limit 处理数量限制 * @param int $num 处理数量限制
* @return array 处理结果 * @return array 处理结果
*/ */
public static function refreshHistoryPurchaseUser($updateData = false, $limit = 100) public static function refreshHistoryPurchaseUser($mode = 'debug', $num = 50)
{ {
ini_set('memory_limit', -1); ini_set('memory_limit', -1);
$supplierService = new self(); $supplierService = new self();
// 判断是否为生产模式
$isProdMode = ($mode === 'prod');
// 获取所有正式供应商 // 获取所有正式供应商
$suppliers = SupplierChannelModel::where('is_type', 0) $suppliers = SupplierChannelModel::where('is_type', 0)
->where('yunxin_channel_uid', '!=', '') ->where('yunxin_channel_uid', '!=', '')
->whereNotNull('yunxin_channel_uid') ->whereNotNull('yunxin_channel_uid')
->limit($limit) ->limit($num)
->get(); ->get();
$result = [ $result = [
'mode' => $isProdMode ? 'production' : 'debug',
'total' => 0, 'total' => 0,
'success' => 0, 'success' => 0,
'failed' => 0, 'failed' => 0,
'skipped' => 0, 'skipped' => 0,
'details' => [], 'details' => [],
'debug_info' => [], // 调试信息
]; ];
foreach ($suppliers as $supplier) { foreach ($suppliers as $supplier) {
...@@ -1246,11 +1293,17 @@ class SupplierService ...@@ -1246,11 +1293,17 @@ class SupplierService
// 如果两者都有,跳过 // 如果两者都有,跳过
if ($hasLiexinPurchase && $hasDataFollower) { if ($hasLiexinPurchase && $hasDataFollower) {
$result['skipped']++; $result['skipped']++;
$result['debug_info'][] = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'skip_reason' => '已有猎芯采购和数据跟单员',
];
continue; continue;
} }
// 自动分配 // 生产模式:执行数据更新
if ($updateData) { if ($isProdMode) {
if ($hasLiexinPurchase && !$hasDataFollower) { if ($hasLiexinPurchase && !$hasDataFollower) {
// 有猎芯采购但没有数据跟单员:将现有猎芯采购人员同时设为数据跟单员 // 有猎芯采购但没有数据跟单员:将现有猎芯采购人员同时设为数据跟单员
$liexinPurchases = SupplierContactModel::where('supplier_id', $supplierId) $liexinPurchases = SupplierContactModel::where('supplier_id', $supplierId)
...@@ -1277,8 +1330,8 @@ class SupplierService ...@@ -1277,8 +1330,8 @@ class SupplierService
]; ];
} else { } else {
// 无猎芯采购和数据跟单员:按规则同时分配 // 无猎芯采购和数据跟单员:按规则同时分配
$assignResult = $supplierService->autoAssignPurchaseUser($supplierId, $yunxinChannelUid); $assignResult = $supplierService->autoAssignPurchaseUser($supplierId, $yunxinChannelUid, true);
if ($assignResult) { if ($assignResult['success']) {
$result['success']++; $result['success']++;
$result['details'][] = [ $result['details'][] = [
'supplier_id' => $supplierId, 'supplier_id' => $supplierId,
...@@ -1288,16 +1341,246 @@ class SupplierService ...@@ -1288,16 +1341,246 @@ class SupplierService
]; ];
} else { } else {
$result['failed']++; $result['failed']++;
$result['debug_info'][] = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'fail_reason' => $assignResult['reason'] ?? 'autoAssignPurchaseUser返回false',
];
}
}
} else {
// 调试模式:只打印信息,不执行更新
$debugItem = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'supplier_group' => $supplier->supplier_group,
'yunxin_channel_uid' => $yunxinChannelUid,
'has_liexin' => $hasLiexinPurchase,
'has_data_follower' => $hasDataFollower,
];
if ($hasLiexinPurchase && !$hasDataFollower) {
// 获取现有猎芯采购人员
$liexinPurchases = SupplierContactModel::where('supplier_id', $supplierId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_LIEXIN)
->pluck('can_check_uids')
->toArray();
$debugItem['action'] = '将现有猎芯采购设为数据跟单员';
$debugItem['liexin_purchase_code_ids'] = $liexinPurchases;
} else {
// 模拟自动分配,获取失败原因
$assignResult = $supplierService->autoAssignPurchaseUser($supplierId, $yunxinChannelUid, false);
$debugItem['action'] = '自动分配猎芯采购和数据跟单员';
$debugItem['assign_result'] = $assignResult;
}
$result['details'][] = $debugItem;
}
}
return $result;
}
/**
* 刷新历史数据(带进度回调,用于Artisan命令)
* @param string $mode 模式
* @param int $num 处理数量
* @param callable $progressCallback 进度回调函数
* @return array
*/
public static function refreshHistoryPurchaseUserWithProgress($mode = 'debug', $num = 0, $progressCallback = null)
{
ini_set('memory_limit', -1);
set_time_limit(0);
$supplierService = new self();
// 判断是否为生产模式
$isProdMode = ($mode === 'prod');
// 构建查询
$query = SupplierChannelModel::where('is_type', 0)
->where('yunxin_channel_uid', '!=', '')
->whereNotNull('yunxin_channel_uid');
// 如果num>0则限制数量,否则不限制
if ($num > 0) {
$query->limit($num);
}
$suppliers = $query->get();
$result = [
'mode' => $isProdMode ? 'production' : 'debug',
'total' => 0,
'success' => 0,
'failed' => 0,
'skipped' => 0,
'details' => [],
'debug_info' => [],
];
foreach ($suppliers as $supplier) {
$result['total']++;
$supplierId = $supplier->supplier_id;
$yunxinChannelUid = $supplier->yunxin_channel_uid;
// 检查是否有猎芯采购和数据跟单员
$hasLiexinPurchase = SupplierContactModel::where('supplier_id', $supplierId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_LIEXIN)
->exists();
$hasDataFollower = SupplierContactModel::where('supplier_id', $supplierId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_INVENTORY)
->exists();
// 如果两者都有,跳过
if ($hasLiexinPurchase && $hasDataFollower) {
$result['skipped']++;
$result['debug_info'][] = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'skip_reason' => '已有猎芯采购和数据跟单员',
];
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '跳过:已有猎芯采购和数据跟单员',
'status' => 'skip',
]);
}
continue;
} }
// 生产模式:执行数据更新
if ($isProdMode) {
if ($hasLiexinPurchase && !$hasDataFollower) {
// 有猎芯采购但没有数据跟单员:将现有猎芯采购人员同时设为数据跟单员
$liexinPurchases = SupplierContactModel::where('supplier_id', $supplierId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_LIEXIN)
->pluck('can_check_uids')
->toArray();
foreach ($liexinPurchases as $codeId) {
// 检查是否已存在数据跟单员记录
$exists = SupplierContactModel::where('supplier_id', $supplierId)
->where('can_check_uids', $codeId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_INVENTORY)
->exists();
if (!$exists) {
$supplierService->allocateChannelUser($supplierId, $codeId, SupplierContactModel::CHANNEL_USER_TYPE_INVENTORY, false);
}
}
$result['success']++;
$result['details'][] = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'action' => '仅分配数据跟单员(基于现有猎芯采购)',
];
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '成功:分配数据跟单员',
'status' => 'success',
]);
} }
} else { } else {
// 无猎芯采购和数据跟单员:按规则同时分配
$assignResult = $supplierService->autoAssignPurchaseUser($supplierId, $yunxinChannelUid, true);
if ($assignResult['success']) {
$result['success']++;
$result['details'][] = [ $result['details'][] = [
'supplier_id' => $supplierId, 'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code, 'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name, 'supplier_name' => $supplier->supplier_name,
'action' => '分配猎芯采购和数据跟单员',
];
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '成功:' . ($assignResult['reason'] ?? '分配成功'),
'status' => 'success',
]);
}
} else {
$result['failed']++;
$result['debug_info'][] = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'fail_reason' => $assignResult['reason'] ?? 'autoAssignPurchaseUser返回false',
];
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '失败:' . ($assignResult['reason'] ?? '未知原因'),
'status' => 'failed',
]);
}
}
}
} else {
// 调试模式:只打印信息,不执行更新
$debugItem = [
'supplier_id' => $supplierId,
'supplier_code' => $supplier->supplier_code,
'supplier_name' => $supplier->supplier_name,
'supplier_group' => $supplier->supplier_group,
'yunxin_channel_uid' => $yunxinChannelUid,
'has_liexin' => $hasLiexinPurchase, 'has_liexin' => $hasLiexinPurchase,
'has_data_follower' => $hasDataFollower, 'has_data_follower' => $hasDataFollower,
]; ];
if ($hasLiexinPurchase && !$hasDataFollower) {
// 获取现有猎芯采购人员
$liexinPurchases = SupplierContactModel::where('supplier_id', $supplierId)
->where('channel_user_type', SupplierContactModel::CHANNEL_USER_TYPE_LIEXIN)
->pluck('can_check_uids')
->toArray();
$debugItem['action'] = '将现有猎芯采购设为数据跟单员';
$debugItem['liexin_purchase_code_ids'] = $liexinPurchases;
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '调试:将现有猎芯采购设为数据跟单员',
'status' => 'debug',
]);
}
} else {
// 模拟自动分配,获取失败原因
$assignResult = $supplierService->autoAssignPurchaseUser($supplierId, $yunxinChannelUid, false);
$debugItem['action'] = '自动分配猎芯采购和数据跟单员';
$debugItem['assign_result'] = $assignResult;
// 回调进度
if ($progressCallback) {
$progressCallback([
'supplier_id' => $supplierId,
'supplier_name' => $supplier->supplier_name,
'action' => '调试:' . ($assignResult['reason'] ?? '模拟分配'),
'status' => 'debug',
]);
}
}
$result['details'][] = $debugItem;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment