building-sign/app/service/Pay.php

226 lines
9.9 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace app\service;
use app\model\ClockLog;
use app\model\Log;
use app\model\OvertimeLog;
use app\model\PayLog;
use app\model\PayMonthLog;
use think\facade\Db;
use think\Model;
/**
* 薪资计算
*
* Class Pay
* @package app\service
*/
class Pay
{
// 基本逻辑 工人工资=基本工资+加班工资 一个月的工资=有效打卡的天数*基本工资+加班工资(=天工资/6*加班小时)
//基本工资在员工入职就要填入
//基本工资按天计算,打卡确认一天算一天
//加班工资按6小时为一天天工资÷6小时=每小时工资
/*
基本工资按天计算,打卡确认一天算一天,可能会出现的漏洞(本期暂不考虑)
晚上加班如23:10打上班卡第二天03:10打下班卡这样就会认为上班2天。
若正常一天,必须至少要有上班和下班两次打卡的话,上述则两天都不算上班
*/
// $sql = "
// insert into bee_pay_log(`account_id`, `worksite_id`,`time`, `year`, `month`, `day`)
// select ".$item['account_id'].",".$item['worksite_id'].",".$item['day'].",".$year.",".$month.",".$day." from DUAL
// where not exists (select `account_id`, `worksite_id`,`time` from bee_pay_log where `account_id` = ".$item['account_id']." AND `worksite_id` = ".$item['worksite_id']." AND `time` = ".$item['day'].")
//";
// Db::execute($sql);
// 生成工人每个工地月薪资汇总
/**
* 汇总指定日期间的工资
* 汇总到pay_log表
*
* @param int $begin 开始时间 为0则不限制 格式为Ymd 如20221103
* @param int $end 结束时间 为0则不限制 格式为Ymd 如20221103
*/
public static function statistic(int $begin = 0, int $end = 0)
{
set_time_limit(0);
$where = [];
if ($begin) {
$where[] = ['l.day', '>=', $begin];
}
if ($end) {
$where[] = ['l.day', '<=', $end];
}
// 打卡记录表 每300条处理一次 打卡记录表中同一个indexs只计算一次
ClockLog::alias('l')
->leftJoin('account a', 'a.id = l.account_id')
->leftJoin('pay_log pl', 'pl.indexs = l.indexs')
->where('l.is_statistic', ClockLog::COMMON_OFF)
->where('l.status', ClockLog::COMMON_ON)
->where('a.pay', '>', 0)
->where('l.handle_count', '<=', 10) //查询处理次数10次以下
->where($where)
->group('l.indexs')
->fieldRaw('count(l.id),l.id,l.account_id,l.worksite_id,l.created_at,l.day,l.indexs,a.pay,pl.id as pay_log_id,pl.base_amount_count')
->chunk(300, function ($items) {
$update = [];
$indexsList = [];
$ids = $items->column('id');
\think\facade\Log::write($ids);
// 每查询一次就增加一次handle_count 避免未处理成功后 死循环一直查询
(new ClockLog)->whereIn('id', $ids)->save([
'handle_count' => Db::raw('`handle_count` + 1')
]);
foreach ($items as $item) {
if ($item['pay_log_id'] && $item['base_amount_count'] == 0) {
$update[] = [
'id' => $item['pay_log_id'],
'amount' => Db::raw('`amount` + '.$item['pay']),
'base_amount' => Db::raw('`base_amount` + '.$item['pay']),
'remarks' => Db::raw('CONCAT_WS(char(10), `remarks`,"基本工资入账 '.$item['pay'].'元")'),
'base_amount_count' => 1,
];
$indexsList[] = $item['indexs'];
}
}
if (!empty($update)) {
// \think\facade\Log::write($update);
// 启动事务
Db::startTrans();
try {
(new PayLog())->saveAll($update);
ClockLog::whereIn('indexs', $indexsList)->update(['is_statistic' => ClockLog::COMMON_ON]);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
\think\facade\Log::error('批量统计基本工资失败'.$e->getMessage().' file:'.$e->getFile().' line:'.$e->getLine());
}
}
}, 'pl.id', 'desc');
// 加班记录表 每300条处理一次
OvertimeLog::alias('l')
->leftJoin('account a', 'a.id = l.account_id')
->leftJoin('pay_log pl', 'pl.indexs = l.indexs')
->where('l.is_statistic', ClockLog::COMMON_OFF)
->where('l.status', ClockLog::COMMON_ON)
->where('a.pay', '>', 0)
->where('l.handle_count', '<=', 10) //查询处理次数10次以下
->where($where)
->fieldRaw('l.id,l.account_id,l.worksite_id,l.created_at,l.`day`,l.time,l.indexs,a.pay,pl.id as pay_log_id,pl.overtime_amount_count')
->chunk(300, function ($items) {
$update = [];
$ids = [];
$handleIds = $items->column('id');
// 每查询一次就增加一次handle_count 避免未处理成功后 死循环一直查询
(new OvertimeLog)->whereIn('id', $handleIds)->save([
'handle_count' => Db::raw('`handle_count` + 1')
]);
foreach ($items as $item) {
if ($item['pay_log_id']) {
// 加班工资=基本工资/6小时 * 加班小时
$overtimeAmount = round(Math::mul(Math::div($item['pay'], 6), $item['time']), 2);
$update[] = [
'id' => $item['pay_log_id'],
'amount' => Db::raw('`amount` + '.$overtimeAmount),
'overtime_amount' => Db::raw('`overtime_amount` + '.$overtimeAmount),
'remarks' => Db::raw('CONCAT_WS(char(10), `remarks`,"加班工资入账 '.$overtimeAmount.'元")'),
'overtime_amount_count' => Db::raw('`overtime_amount_count` + 1'),
];
$ids[] = $item['id'];
}
}
// \think\facade\Log::write($update);
if (!empty($update)) {
Db::startTrans();
try {
(new PayLog())->saveAll($update);
OvertimeLog::whereIn('id', $ids)->update(['is_statistic' => OvertimeLog::COMMON_ON]);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
\think\facade\Log::error('批量统计加班工资失败'.$e->getMessage().' file:'.$e->getFile().' line:'.$e->getLine());
}
}
}, 'l.id', 'desc');
}
/**
* 生成月份工资记录
*
* @param int $time 生成时间 按月份 格式为年月 如202209 date('Ym')
* @return bool
*/
public static function generateMonthLog(int $time = 0): bool
{
if ($time == 0) {
// 默认生成上个月
$time = date('Ym', strtotime('last month'));
}
$timestamp = strtotime($time.'01');
$year = date('Y', $timestamp);
$month = date('m', $timestamp);
$where = [
['year', '=', $year],
['month', '=', $month],
];
// 每次统计 都讲之前的结果清理,插入新计算结果
$insert = [];
// 每日工资记录(基本工资和加班工资)
PayLog::where($where)
->chunk(300, function ($items) use (&$insert, $time, $year, $month) {
foreach ($items as $item) {
$indexs = $item['account_id'].'-'.$item['worksite_id'].'-'.$time;
if (!isset($insert[$indexs])) {
$insert[$indexs] = [
'account_id' => $item['account_id'],
'worksite_id' => $item['worksite_id'],
'indexs' => $indexs,
'time' => $time,
'year' => $year,
'month' => $month,
'created_at' => date('Y-m-d H:i:s'),
'amount' => $item['amount'],
'base_amount' => $item['base_amount'],
'overtime_amount' => $item['overtime_amount'],
];
} else {
$insert[$indexs]['amount'] = $insert[$indexs]['amount'] + $item['amount'];
$insert[$indexs]['base_amount'] = $insert[$indexs]['base_amount'] + $item['base_amount'];
$insert[$indexs]['overtime_amount'] = $insert[$indexs]['overtime_amount'] + $item['overtime_amount'];
}
}
});
if (!empty($insert)) {
// \think\facade\Log::write($insert);
// 启动事务
Db::startTrans();
try {
PayMonthLog::where('time', $time)->delete();
(new PayMonthLog())->insertAll($insert);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
\think\facade\Log::error('统计['.$time.']工资失败'.$e->getMessage().' file:'.$e->getFile().' line:'.$e->getLine());
}
}
return true;
}
}