You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
904 lines
33 KiB
904 lines
33 KiB
<?php
|
|
|
|
namespace app\job\transfer\schedule;
|
|
|
|
use app\model\course\Course;
|
|
use app\model\order_table\OrderTable;
|
|
use app\model\personnel\Personnel;
|
|
use app\model\resource_sharing\ResourceSharing;
|
|
use app\model\six_speed\SixSpeed;
|
|
use app\model\customer_resources\CustomerResources;
|
|
use app\service\admin\performance\PerformanceService;
|
|
use app\service\api\apiService\CommonService;
|
|
use core\base\BaseJob;
|
|
use think\facade\Db;
|
|
use think\facade\Log;
|
|
|
|
/**
|
|
* 销售绩效核算
|
|
* Class PerformanceCalculation
|
|
* @package app\job\transfer\schedule
|
|
*/
|
|
class PerformanceCalculation extends BaseJob
|
|
{
|
|
/**
|
|
* 员工工龄阶段
|
|
*/
|
|
const STAGE_TRIAL = '试用期1'; // 试用期
|
|
const STAGE_REGULAR = '转正'; // 转正
|
|
const STAGE_HALF_YEAR = '转正后半年'; // 转正后半年
|
|
|
|
/**
|
|
* 资源来源类型
|
|
*/
|
|
const SOURCE_INTERNAL_STAFF = 4; // 内部员工资源
|
|
|
|
/**
|
|
* 绩效服务类实例
|
|
* @var PerformanceService
|
|
*/
|
|
protected $performanceService = null;
|
|
|
|
/**
|
|
* 构造函数
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->performanceService = new PerformanceService();
|
|
}
|
|
|
|
/**
|
|
* 执行任务
|
|
*/
|
|
public function doJob()
|
|
{
|
|
// 添加执行锁,防止重复执行
|
|
$lockFile = runtime_path() . 'performance_calculation.lock';
|
|
if (file_exists($lockFile) && (time() - filemtime($lockFile)) < 1800) { // 30分钟锁定
|
|
Log::write('销售绩效核算任务正在执行中,跳过');
|
|
return ['status' => 'skipped', 'reason' => 'locked'];
|
|
}
|
|
|
|
// 创建锁文件
|
|
file_put_contents($lockFile, time());
|
|
|
|
try {
|
|
Log::write('开始执行销售绩效核算');
|
|
|
|
// 获取所有需要计算绩效的订单
|
|
$orders = $this->getOrders();
|
|
if (empty($orders)) {
|
|
Log::write('没有需要计算绩效的订单');
|
|
return ['status' => 'success', 'processed' => 0, 'message' => '没有需要计算绩效的订单'];
|
|
}
|
|
|
|
// 获取绩效配置
|
|
$performanceConfig = $this->getPerformanceConfig();
|
|
if (empty($performanceConfig)) {
|
|
Log::write('未找到绩效配置');
|
|
return ['status' => 'failed', 'message' => '未找到绩效配置'];
|
|
}
|
|
|
|
// 计算每个订单的绩效
|
|
$results = [];
|
|
$successCount = 0;
|
|
$failedCount = 0;
|
|
|
|
foreach ($orders as $order) {
|
|
try {
|
|
// 首先判断是否为内部员工资源
|
|
$isInternalStaffResource = $this->isInternalStaffResource($order);
|
|
|
|
if ($isInternalStaffResource) {
|
|
// 处理内部员工资源的绩效计算
|
|
$internalResult = $this->calculateInternalStaffPerformance($order, $performanceConfig);
|
|
if (!empty($internalResult) && $internalResult['status'] == 'success') {
|
|
$results[] = $internalResult;
|
|
$successCount++;
|
|
} else {
|
|
$failedCount++;
|
|
}
|
|
} else {
|
|
// 判断是否为多人介入的订单
|
|
$isMultiPersonInvolved = $this->isMultiPersonInvolved($order);
|
|
|
|
if ($isMultiPersonInvolved) {
|
|
// 处理多人介入的绩效计算
|
|
$multiResults = $this->calculateMultiPersonPerformance($order, $performanceConfig);
|
|
if (!empty($multiResults)) {
|
|
foreach ($multiResults as $result) {
|
|
if ($result['status'] == 'success') {
|
|
$results[] = $result;
|
|
$successCount++;
|
|
} else {
|
|
$failedCount++;
|
|
}
|
|
}
|
|
} else {
|
|
$failedCount++;
|
|
}
|
|
} else {
|
|
// 处理单人的绩效计算
|
|
$result = $this->calculateOrderPerformance($order, $performanceConfig);
|
|
if (!empty($result) && $result['status'] == 'success') {
|
|
$results[] = $result;
|
|
$successCount++;
|
|
} else {
|
|
$failedCount++;
|
|
}
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::write('处理订单绩效计算失败,订单ID:' . $order['id'] . ',错误:' . $e->getMessage());
|
|
$failedCount++;
|
|
}
|
|
}
|
|
|
|
// 保存绩效结果
|
|
$saveResult = $this->savePerformanceResults($results);
|
|
|
|
Log::write('销售绩效核算完成,共处理' . count($orders) . '个订单,成功:' . $successCount . '个,失败:' . $failedCount . '个');
|
|
|
|
return [
|
|
'status' => 'success',
|
|
'total_orders' => count($orders),
|
|
'success_count' => $successCount,
|
|
'failed_count' => $failedCount,
|
|
'save_result' => $saveResult
|
|
];
|
|
} finally {
|
|
// 删除锁文件
|
|
if (file_exists($lockFile)) {
|
|
unlink($lockFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 判断是否为内部员工资源
|
|
* @param array $order 订单信息
|
|
* @return bool 是否为内部员工资源
|
|
*/
|
|
protected function isInternalStaffResource($order)
|
|
{
|
|
if (empty($order['resource_id'])) {
|
|
return false;
|
|
}
|
|
|
|
// 查询资源表中的记录
|
|
$resource = CustomerResources::where('id', $order['resource_id'])->find();
|
|
|
|
// 如果没有找到资源记录,则不是内部员工资源
|
|
if (empty($resource)) {
|
|
return false;
|
|
}
|
|
|
|
// 判断资源来源是否为内部员工
|
|
return isset($resource['source']) && $resource['source'] == self::SOURCE_INTERNAL_STAFF;
|
|
}
|
|
|
|
/**
|
|
* 计算内部员工资源的绩效
|
|
* @param array $order 订单信息
|
|
* @param array $config 绩效配置
|
|
* @return array 绩效计算结果
|
|
*/
|
|
protected function calculateInternalStaffPerformance($order, $config)
|
|
{
|
|
$staffId = $order['staff_id'];
|
|
$campusId = isset($order['campus_id']) ? $order['campus_id'] : 0;
|
|
$resourceId = isset($order['resource_id']) ? $order['resource_id'] : 0;
|
|
|
|
// 获取员工信息
|
|
$staff = Personnel::where('id', $staffId)->find();
|
|
if (empty($staff)) {
|
|
Log::write('未找到员工信息,员工ID:' . $staffId);
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'performance_amount' => 0,
|
|
'status' => 'failed',
|
|
'message' => '未找到员工信息'
|
|
];
|
|
}
|
|
|
|
// 获取课程类型前缀
|
|
$courseType = $this->getCourseTypePrefix($order);
|
|
|
|
// 获取内部员工绩效配置
|
|
$xspjConfig = $config['XSPJ'];
|
|
$internalStaffKey = $courseType . '_internalStaff';
|
|
$performanceAmount = isset($xspjConfig[$internalStaffKey]) ? floatval($xspjConfig[$internalStaffKey]) : 0;
|
|
|
|
if ($performanceAmount <= 0) {
|
|
Log::write('未找到有效的内部员工绩效配置,订单ID:' . $order['id']);
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'performance_amount' => 0,
|
|
'status' => 'failed',
|
|
'message' => '未找到有效的内部员工绩效配置'
|
|
];
|
|
}
|
|
|
|
// 判断订单类型(新订单或续费)
|
|
$isRenewal = $this->isRenewalOrder($order);
|
|
|
|
// 获取新资源数和续费资源数
|
|
$newResourceCount = $isRenewal ? 0 : 1;
|
|
$renewResourceCount = $isRenewal ? 1 : 0;
|
|
|
|
// 保存使用的绩效配置和算法
|
|
$performanceConfig = json_encode([
|
|
'is_renewal' => $isRenewal,
|
|
'is_internal_staff' => true,
|
|
'performance_key' => $internalStaffKey
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
$performanceAlgorithm = json_encode([
|
|
'order_id' => $order['id'],
|
|
'resource_id' => $resourceId,
|
|
'internal_staff_resource' => true
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
// 添加一条绩效汇总记录
|
|
$this->addPerformanceSummary([
|
|
'staff_id' => $staffId,
|
|
'resource_id' => $resourceId,
|
|
'order_id' => $order['id'],
|
|
'order_status' => PerformanceService::ORDER_STATUS_PENDING,
|
|
'performance_type' => PerformanceService::PERFORMANCE_TYPE_SALES,
|
|
'performance_value' => $performanceAmount,
|
|
'remarks' => '内部员工关单绩效'
|
|
]);
|
|
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'personnel_id' => $staffId,
|
|
'campus_id' => $campusId,
|
|
'resource_id' => $resourceId,
|
|
'is_renewal' => $isRenewal,
|
|
'performance_amount' => $performanceAmount,
|
|
'new_resource_count' => $newResourceCount,
|
|
'renew_resource_count' => $renewResourceCount,
|
|
'performance_date' => date('Y-m-d'),
|
|
'performance_config' => $performanceConfig,
|
|
'performance_algorithm' => $performanceAlgorithm,
|
|
'remarks' => '内部员工关单绩效',
|
|
'status' => 'success',
|
|
'created_at' => time(),
|
|
'updated_at' => time()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取需要计算绩效的订单
|
|
* @return array 订单列表
|
|
*/
|
|
protected function getOrders()
|
|
{
|
|
// 这里可以根据实际需求筛选需要计算绩效的订单
|
|
// 例如:只计算已完成的订单、特定时间段内的订单等
|
|
$orders = OrderTable::with(['course', 'personnel'])
|
|
->where('order_status', 'completed') // 假设只计算已完成的订单
|
|
->where(function ($query) {
|
|
$query->whereNull('accounting_time'); // 或者核算时间为空的订单
|
|
})
|
|
->select()
|
|
->toArray();
|
|
|
|
// 额外检查:过滤掉已经在绩效汇总表中存在的订单
|
|
if (!empty($orders)) {
|
|
$orderIds = array_column($orders, 'id');
|
|
$existingOrderIds = Db::name('school_performance_summary')
|
|
->whereIn('order_id', $orderIds)
|
|
->where('performance_type', PerformanceService::PERFORMANCE_TYPE_SALES)
|
|
->column('order_id');
|
|
|
|
if (!empty($existingOrderIds)) {
|
|
Log::write('发现' . count($existingOrderIds) . '个订单已在绩效汇总表中存在,将被跳过');
|
|
$orders = array_filter($orders, function($order) use ($existingOrderIds) {
|
|
return !in_array($order['id'], $existingOrderIds);
|
|
});
|
|
}
|
|
}
|
|
|
|
Log::write('找到' . count($orders) . '个需要计算绩效的订单');
|
|
return $orders;
|
|
}
|
|
|
|
/**
|
|
* 获取绩效配置
|
|
* @return array 绩效配置
|
|
*/
|
|
protected function getPerformanceConfig()
|
|
{
|
|
$commonService = new CommonService();
|
|
|
|
// 获取销售基础绩效配置
|
|
$xsyjConfig = $commonService->getDictionary(['key' => 'XSYJ']);
|
|
|
|
// 获取多人介入绩效配置
|
|
$xspjConfig = $commonService->getDictionary(['key' => 'XSPJ']);
|
|
|
|
// 获取课程基础绩效配置
|
|
$courseTypeConfig = $commonService->getDictionary(['key' => 'course_type']);
|
|
|
|
return [
|
|
'XSYJ' => $xsyjConfig,
|
|
'XSPJ' => $xspjConfig,
|
|
'course_type' => $courseTypeConfig
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 判断是否为多人介入的订单
|
|
* @param array $order 订单信息
|
|
* @return bool 是否为多人介入
|
|
*/
|
|
protected function isMultiPersonInvolved($order)
|
|
{
|
|
if (empty($order['resource_id']) || empty($order['staff_id'])) {
|
|
return false;
|
|
}
|
|
|
|
// 查询资源共享表中的记录
|
|
$resourceSharing = ResourceSharing::where('resource_id', $order['resource_id'])
|
|
->where('shared_by', '<>', 0)
|
|
->order('id', 'asc')
|
|
->find();
|
|
|
|
// 如果没有找到资源共享记录,则不是多人介入
|
|
if (empty($resourceSharing)) {
|
|
return false;
|
|
}
|
|
|
|
// 如果资源共享记录中的user_id与订单的staff_id不同,则是多人介入
|
|
return $resourceSharing['user_id'] != $order['staff_id'];
|
|
}
|
|
|
|
/**
|
|
* 计算多人介入的绩效
|
|
* @param array $order 订单信息
|
|
* @param array $config 绩效配置
|
|
* @return array 绩效计算结果数组
|
|
*/
|
|
protected function calculateMultiPersonPerformance($order, $config)
|
|
{
|
|
$results = [];
|
|
$resourceId = $order['resource_id'];
|
|
$staffId = $order['staff_id'];
|
|
|
|
// 查询资源共享表中的记录(资源归属人)
|
|
$resourceOwner = ResourceSharing::where('resource_id', $resourceId)
|
|
->where('shared_by', '<>', 0)
|
|
->order('id', 'asc')
|
|
->find();
|
|
|
|
if (empty($resourceOwner)) {
|
|
Log::write('未找到资源归属人,订单ID:' . $order['id']);
|
|
return [];
|
|
}
|
|
|
|
$resourceOwnerId = $resourceOwner['user_id'];
|
|
|
|
// 查询六速表中的访问记录
|
|
$sixSpeed = SixSpeed::where('resource_id', $resourceId)->find();
|
|
|
|
// 确定介入类型
|
|
$visitType = 'followUp'; // 默认为跟进
|
|
$visitTypeDesc = '跟进关单';
|
|
|
|
if (!empty($sixSpeed)) {
|
|
if (!empty($sixSpeed['first_visit_time'])) {
|
|
$visitType = 'firstVisit';
|
|
$visitTypeDesc = '一访关单';
|
|
} elseif (!empty($sixSpeed['second_visit_time'])) {
|
|
$visitType = 'secondVisit';
|
|
$visitTypeDesc = '二访关单';
|
|
}
|
|
}
|
|
|
|
// 获取课程类型前缀
|
|
$courseType = $this->getCourseTypePrefix($order);
|
|
|
|
// 获取多人介入绩效配置
|
|
$xspjConfig = $config['XSPJ'];
|
|
$percentageKey = $courseType . '_' . $visitType;
|
|
$percentage = isset($xspjConfig[$percentageKey]) ? floatval($xspjConfig[$percentageKey]) : 0;
|
|
|
|
if ($percentage <= 0) {
|
|
Log::write('未找到有效的多人介入绩效配置,订单ID:' . $order['id']);
|
|
return [];
|
|
}
|
|
|
|
// 计算订单的基础绩效
|
|
$basePerformance = $this->calculateOrderBasePerformance($order, $config);
|
|
|
|
// 计算完成订单人的绩效
|
|
$staffPerformance = $basePerformance * ($percentage / 100);
|
|
|
|
// 计算资源归属人的绩效
|
|
$ownerPerformance = $basePerformance * (1 - $percentage / 100);
|
|
|
|
// 创建完成订单人的绩效记录
|
|
$staffResult = $this->createPerformanceResult($order, $staffId, $staffPerformance, $visitTypeDesc . '(完成订单人)');
|
|
$results[] = $staffResult;
|
|
|
|
// 创建资源归属人的绩效记录
|
|
$ownerResult = $this->createPerformanceResult($order, $resourceOwnerId, $ownerPerformance, $visitTypeDesc . '(资源归属人)');
|
|
$results[] = $ownerResult;
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* 获取课程类型前缀
|
|
* @param array $order 订单信息
|
|
* @return string 课程类型前缀(xj, xf, qt)
|
|
*/
|
|
protected function getCourseTypePrefix($order)
|
|
{
|
|
// 判断订单类型
|
|
if (isset($order['order_type'])) {
|
|
if ($order['order_type'] == 1) {
|
|
return 'xj'; // 新建
|
|
} elseif ($order['order_type'] == 2) {
|
|
return 'xf'; // 续费
|
|
}
|
|
}
|
|
|
|
return 'qt'; // 其他
|
|
}
|
|
|
|
/**
|
|
* 计算订单的基础绩效金额
|
|
* @param array $order 订单信息
|
|
* @param array $config 绩效配置
|
|
* @return float 基础绩效金额
|
|
*/
|
|
protected function calculateOrderBasePerformance($order, $config)
|
|
{
|
|
// 获取员工信息
|
|
$staff = Personnel::where('id', $order['staff_id'])->find();
|
|
if (empty($staff)) {
|
|
return 0;
|
|
}
|
|
|
|
// 获取课程信息
|
|
$course = Course::where('id', $order['course_id'])->find();
|
|
if (empty($course)) {
|
|
return 0;
|
|
}
|
|
|
|
// 判断员工工龄阶段
|
|
$employmentStage = $this->getEmploymentStage($staff);
|
|
|
|
// 判断订单类型(新订单或续费)
|
|
$isRenewal = $this->isRenewalOrder($order);
|
|
|
|
// 计算绩效
|
|
return $this->calculatePerformance($order, $course, $employmentStage, $isRenewal, $config);
|
|
}
|
|
|
|
/**
|
|
* 创建绩效计算结果
|
|
* @param array $order 订单信息
|
|
* @param int $staffId 员工ID
|
|
* @param float $performance 绩效金额
|
|
* @param string $remarks 备注
|
|
* @return array 绩效计算结果
|
|
*/
|
|
protected function createPerformanceResult($order, $staffId, $performance, $remarks)
|
|
{
|
|
$campusId = isset($order['campus_id']) ? $order['campus_id'] : 0;
|
|
$resourceId = isset($order['resource_id']) ? $order['resource_id'] : 0;
|
|
|
|
// 获取员工信息
|
|
$staff = Personnel::where('id', $staffId)->find();
|
|
if (empty($staff)) {
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'performance_amount' => 0,
|
|
'status' => 'failed',
|
|
'message' => '未找到员工信息'
|
|
];
|
|
}
|
|
|
|
// 判断员工工龄阶段
|
|
$employmentStage = $this->getEmploymentStage($staff);
|
|
|
|
// 判断订单类型(新订单或续费)
|
|
$isRenewal = $this->isRenewalOrder($order);
|
|
|
|
// 获取新资源数和续费资源数
|
|
$newResourceCount = $isRenewal ? 0 : 1;
|
|
$renewResourceCount = $isRenewal ? 1 : 0;
|
|
|
|
// 保存使用的绩效配置和算法
|
|
$performanceConfig = json_encode([
|
|
'employment_stage' => $employmentStage,
|
|
'is_renewal' => $isRenewal,
|
|
'remarks' => $remarks
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
$performanceAlgorithm = json_encode([
|
|
'order_id' => $order['id'],
|
|
'resource_id' => $resourceId,
|
|
'multi_person_involved' => true
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
// 添加一条绩效汇总记录
|
|
$this->addPerformanceSummary([
|
|
'staff_id' => $staffId,
|
|
'resource_id' => $resourceId,
|
|
'order_id' => $order['id'],
|
|
'order_status' => PerformanceService::ORDER_STATUS_PENDING,
|
|
'performance_type' => PerformanceService::PERFORMANCE_TYPE_SALES,
|
|
'performance_value' => $performance,
|
|
'remarks' => $remarks
|
|
]);
|
|
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'personnel_id' => $staffId,
|
|
'campus_id' => $campusId,
|
|
'resource_id' => $resourceId,
|
|
'employment_stage' => $employmentStage,
|
|
'is_renewal' => $isRenewal,
|
|
'performance_amount' => $performance,
|
|
'new_resource_count' => $newResourceCount,
|
|
'renew_resource_count' => $renewResourceCount,
|
|
'performance_date' => date('Y-m-d'),
|
|
'performance_config' => $performanceConfig,
|
|
'performance_algorithm' => $performanceAlgorithm,
|
|
'remarks' => $remarks,
|
|
'status' => 'success',
|
|
'created_at' => time(),
|
|
'updated_at' => time()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 计算单个订单的绩效
|
|
* @param array $order 订单信息
|
|
* @param array $config 绩效配置
|
|
* @return array 绩效计算结果
|
|
*/
|
|
protected function calculateOrderPerformance($order, $config)
|
|
{
|
|
$staffId = $order['staff_id'];
|
|
$courseId = $order['course_id'];
|
|
$campusId = isset($order['campus_id']) ? $order['campus_id'] : 0;
|
|
$resourceId = isset($order['resource_id']) ? $order['resource_id'] : 0;
|
|
|
|
// 获取员工信息
|
|
$staff = Personnel::where('id', $staffId)->find();
|
|
if (empty($staff)) {
|
|
Log::write('未找到员工信息,员工ID:' . $staffId);
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'performance_amount' => 0,
|
|
'status' => 'failed',
|
|
'message' => '未找到员工信息'
|
|
];
|
|
}
|
|
|
|
// 获取课程信息
|
|
$course = Course::where('id', $courseId)->find();
|
|
if (empty($course)) {
|
|
Log::write('未找到课程信息,课程ID:' . $courseId);
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'performance_amount' => 0,
|
|
'status' => 'failed',
|
|
'message' => '未找到课程信息'
|
|
];
|
|
}
|
|
|
|
// 判断员工工龄阶段
|
|
$employmentStage = $this->getEmploymentStage($staff);
|
|
|
|
// 判断订单类型(新订单或续费)
|
|
$isRenewal = $this->isRenewalOrder($order);
|
|
|
|
// 计算绩效
|
|
$performance = $this->calculatePerformance($order, $course, $employmentStage, $isRenewal, $config);
|
|
|
|
// 获取新资源数和续费资源数
|
|
$newResourceCount = $isRenewal ? 0 : 1;
|
|
$renewResourceCount = $isRenewal ? 1 : 0;
|
|
|
|
// 保存使用的绩效配置和算法
|
|
$performanceConfig = json_encode([
|
|
'employment_stage' => $employmentStage,
|
|
'is_renewal' => $isRenewal,
|
|
'course_type' => $course['course_type']
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
$performanceAlgorithm = json_encode([
|
|
'base_commission' => $isRenewal ? 'renewal_commission' : 'course_type_num',
|
|
'order_id' => $order['id'],
|
|
'course_id' => $courseId
|
|
], JSON_UNESCAPED_UNICODE);
|
|
|
|
// 同时添加一条绩效汇总记录
|
|
$this->addPerformanceSummary([
|
|
'staff_id' => $staffId,
|
|
'resource_id' => $resourceId,
|
|
'order_id' => $order['id'],
|
|
'order_status' => PerformanceService::ORDER_STATUS_PENDING,
|
|
'performance_type' => PerformanceService::PERFORMANCE_TYPE_SALES,
|
|
'performance_value' => $performance,
|
|
'remarks' => '订单绩效自动计算'
|
|
]);
|
|
|
|
return [
|
|
'order_id' => $order['id'],
|
|
'staff_id' => $staffId,
|
|
'personnel_id' => $staffId,
|
|
'campus_id' => $campusId,
|
|
'course_id' => $courseId,
|
|
'employment_stage' => $employmentStage,
|
|
'is_renewal' => $isRenewal,
|
|
'performance_amount' => $performance,
|
|
'new_resource_count' => $newResourceCount,
|
|
'renew_resource_count' => $renewResourceCount,
|
|
'performance_date' => date('Y-m-d'),
|
|
'performance_config' => $performanceConfig,
|
|
'performance_algorithm' => $performanceAlgorithm,
|
|
'status' => 'success',
|
|
'created_at' => time(),
|
|
'updated_at' => time()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 判断员工工龄阶段
|
|
* @param object $staff 员工信息
|
|
* @return string 工龄阶段
|
|
*/
|
|
protected function getEmploymentStage($staff)
|
|
{
|
|
$joinTime = strtotime($staff['join_time']);
|
|
$now = time();
|
|
$monthsDiff = floor(($now - $joinTime) / (30 * 24 * 60 * 60));
|
|
|
|
if ($monthsDiff < 3) {
|
|
return self::STAGE_TRIAL; // 试用期
|
|
} else if ($monthsDiff < 6) {
|
|
return self::STAGE_REGULAR; // 转正
|
|
} else {
|
|
return self::STAGE_HALF_YEAR; // 转正后半年
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 判断是否为续费订单
|
|
* @param array $order 订单信息
|
|
* @return bool 是否为续费订单
|
|
*/
|
|
protected function isRenewalOrder($order)
|
|
{
|
|
// 这里需要根据实际业务逻辑判断是否为续费订单
|
|
// 假设订单中有一个字段标记是否为续费
|
|
return isset($order['order_type']) && $order['order_type'] == 2;
|
|
}
|
|
|
|
/**
|
|
* 计算绩效金额
|
|
* @param array $order 订单信息
|
|
* @param object $course 课程信息
|
|
* @param string $employmentStage 工龄阶段
|
|
* @param bool $isRenewal 是否为续费订单
|
|
* @param array $config 绩效配置
|
|
* @return float 绩效金额
|
|
*/
|
|
protected function calculatePerformance($order, $course, $employmentStage, $isRenewal, $config)
|
|
{
|
|
// 获取对应工龄阶段的配置
|
|
$stageConfig = null;
|
|
foreach ($config['XSYJ'] as $item) {
|
|
if ($item['name'] == $employmentStage) {
|
|
$stageConfig = $item;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($stageConfig)) {
|
|
Log::write('未找到对应工龄阶段的配置:' . $employmentStage);
|
|
return 0;
|
|
}
|
|
|
|
// 获取课程类型配置
|
|
$courseTypeConfig = null;
|
|
$courseType = $course['course_type'];
|
|
foreach ($config['course_type'] as $item) {
|
|
if ($item['value'] == $courseType) {
|
|
$courseTypeConfig = $item;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($courseTypeConfig)) {
|
|
Log::write('未找到对应课程类型的配置:' . $courseType);
|
|
return 0;
|
|
}
|
|
|
|
// 获取基础提成金额
|
|
$baseCommission = $courseTypeConfig['num'];
|
|
|
|
// 如果是续费订单,根据续费率计算提成
|
|
if ($isRenewal) {
|
|
// 获取续费率
|
|
$renewalRate = $this->getRenewalRate($order['staff_id']);
|
|
|
|
// 查找适用的规则
|
|
$rule = null;
|
|
foreach ($stageConfig['rules'] as $r) {
|
|
$minRate = floatval($r['renewal_standard_min']);
|
|
$maxRate = !empty($r['renewal_standard_max']) ? floatval($r['renewal_standard_max']) : PHP_FLOAT_MAX;
|
|
|
|
if ($renewalRate >= $minRate && $renewalRate < $maxRate) {
|
|
$rule = $r;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!empty($rule)) {
|
|
return floatval($rule['renewal_commission']);
|
|
}
|
|
} else {
|
|
// 新订单,直接返回基础提成
|
|
return floatval($baseCommission);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取员工的续费率
|
|
* @param int $staffId 员工ID
|
|
* @return float 续费率
|
|
*/
|
|
protected function getRenewalRate($staffId)
|
|
{
|
|
// 这里需要根据实际业务逻辑计算员工的续费率
|
|
// 假设有一个表记录了员工的续费率
|
|
$rate = 95.0; // 默认值
|
|
|
|
// TODO: 从数据库中获取实际续费率
|
|
|
|
return $rate;
|
|
}
|
|
|
|
/**
|
|
* 保存绩效计算结果
|
|
* @param array $results 绩效计算结果
|
|
* @return array 保存结果统计
|
|
*/
|
|
protected function savePerformanceResults($results)
|
|
{
|
|
if (empty($results)) {
|
|
return ['saved' => 0, 'skipped' => 0, 'failed' => 0];
|
|
}
|
|
|
|
$savedCount = 0;
|
|
$skippedCount = 0;
|
|
$failedCount = 0;
|
|
$processedOrders = [];
|
|
|
|
try {
|
|
Db::startTrans();
|
|
|
|
// 按订单分组处理,避免重复更新订单状态
|
|
$orderGroups = [];
|
|
foreach ($results as $result) {
|
|
if ($result['status'] == 'success') {
|
|
$orderGroups[$result['order_id']][] = $result;
|
|
}
|
|
}
|
|
|
|
foreach ($orderGroups as $orderId => $orderResults) {
|
|
try {
|
|
// 检查订单是否已经完全处理过
|
|
$existingCount = Db::name('school_performance_summary')
|
|
->where('order_id', $orderId)
|
|
->where('performance_type', PerformanceService::PERFORMANCE_TYPE_SALES)
|
|
->count();
|
|
|
|
if ($existingCount > 0) {
|
|
Log::write('订单ID:' . $orderId . ' 已存在绩效记录,跳过整个订单');
|
|
$skippedCount += count($orderResults);
|
|
continue;
|
|
}
|
|
|
|
// 处理当前订单的所有绩效记录
|
|
$orderPerformanceAmount = 0;
|
|
foreach ($orderResults as $result) {
|
|
// 保存到绩效表 school_sales_performance
|
|
$performanceData = [
|
|
'personnel_id' => $result['personnel_id'],
|
|
'campus_id' => $result['campus_id'] ?? 0,
|
|
'performance_amount' => $result['performance_amount'],
|
|
'new_resource_count' => $result['new_resource_count'] ?? 0,
|
|
'renew_resource_count' => $result['renew_resource_count'] ?? 0,
|
|
'performance_date' => $result['performance_date'],
|
|
'performance_config' => $result['performance_config'] ?? '',
|
|
'performance_algorithm' => $result['performance_algorithm'] ?? '',
|
|
'created_at' => $result['created_at'],
|
|
'updated_at' => $result['updated_at']
|
|
];
|
|
|
|
Db::name('school_sales_performance')->insert($performanceData);
|
|
$orderPerformanceAmount += $result['performance_amount'];
|
|
$savedCount++;
|
|
|
|
Log::write('成功保存绩效记录,订单ID:' . $orderId . ',员工ID:' . $result['personnel_id'] . ',绩效金额:' . $result['performance_amount']);
|
|
}
|
|
|
|
// 统一更新订单状态(每个订单只更新一次)
|
|
OrderTable::where('id', $orderId)
|
|
->update([
|
|
'performance_calculated' => 1,
|
|
'performance_amount' => $orderPerformanceAmount,
|
|
'accounting_time' => time()
|
|
]);
|
|
|
|
$processedOrders[] = $orderId;
|
|
|
|
} catch (\Exception $e) {
|
|
Log::write('处理订单ID:' . $orderId . ' 的绩效记录失败:' . $e->getMessage());
|
|
$failedCount += count($orderResults);
|
|
}
|
|
}
|
|
|
|
Db::commit();
|
|
|
|
Log::write('成功保存绩效计算结果,保存:' . $savedCount . '个,跳过:' . $skippedCount . '个,失败:' . $failedCount . '个');
|
|
Log::write('成功更新' . count($processedOrders) . '个订单的核算状态');
|
|
|
|
return [
|
|
'saved' => $savedCount,
|
|
'skipped' => $skippedCount,
|
|
'failed' => $failedCount,
|
|
'processed_orders' => count($processedOrders)
|
|
];
|
|
|
|
} catch (\Exception $e) {
|
|
Db::rollback();
|
|
Log::write('保存绩效计算结果失败:' . $e->getMessage());
|
|
return [
|
|
'saved' => 0,
|
|
'skipped' => 0,
|
|
'failed' => count($results),
|
|
'error' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 添加绩效汇总记录
|
|
* @param array $data 绩效数据
|
|
* @return int|string 插入的ID
|
|
*/
|
|
public function addPerformanceSummary(array $data)
|
|
{
|
|
try {
|
|
if ($this->performanceService) {
|
|
return $this->performanceService->addPerformance($data);
|
|
} else {
|
|
Log::write('PerformanceService 未初始化');
|
|
return 0;
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::write('添加绩效汇总记录失败:' . $e->getMessage());
|
|
return 0;
|
|
}
|
|
}
|
|
}
|