2023-01-09 08:41:41 +00:00
< ? 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 )
2023-01-13 08:18:38 +00:00
-> where ( 'l.need_statistic' , ClockLog :: COMMON_ON )
-> where ( 'l.role' , ClockLog :: COMMON_ON ) //工人
2023-01-09 08:41:41 +00:00
-> 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 ;
}
}