我已经使用Laravel 5.7构建了一个员工管理系统。计算薪水对于100-150名员工来说很好(但是要花费很长时间来处理数据),而对于150多名员工来说,这表明存在超时错误。
我想添加该功能以一次性计算所有员工的薪水,同时也减少处理时间。为此使用chunk()是否合适?如果是,该如何实施?
注意: Web应用程序是针对BPO的,因此在计算薪水时要应用多种逻辑。该代码太长,无法在此处共享,但是如果有人想查看该代码,我可以共享它。
Front-end form screenshot
Page after calculation
<?php
public function calculate_salary(Request $request){
$this->validate($request,[
'employee_id' => 'required',
'attendance_types' => 'required',
'month' => 'required_without:choose_date',
'choose_date' => 'required_without:month'
]);
$download_salary = false;
$submit_salary = false;
if ($request->has('submit_data'))
{
$submit_salary = true;
}
else
{
$submit_salary = false;
}
if ($request->has('download_data'))
{
$download_salary = true;
}
else
{
$download_salary = false;
}
$dept = $request->input('salary_department');
$role = $request->input('salary_role');
$process = $request->input('salary_process');
$salary_dept = Department::where('id', $dept)->pluck('dept_name')->first();
$salary_role = Role::where('id', $role)->pluck('role_name')->first();
$salary_process = Process::where('id', $process)->pluck('process_name')->first();
if ($submit_salary == true || $download_salary == true)
{
$months = $request->input('month');
$month = $months[0];
$employee_ids = $request->input('employee_id');
$attendance_types = $request->input('attendance_types');
$attendance_type_temp_insert = $attendance_types[0];
$attendance_type = explode(',', $attendance_type_temp_insert);
if (!empty($request->input('choose_date')))
{
$dates = $request->input('choose_date');
$date = $dates[0];
}
else
{
$date = "";
}
}
else
{
$month = $request->input('month');
$employee_ids = $request->input('employee_id');
$attendance_type = $request->input('attendance_types');
$attendance_type_temp_insert = implode(',', $request->input('attendance_types'));
$date = $request->input('choose_date');
}
// Get start & end dates
$data = $this->get_salary_dates($month, $date);
$start_date = $data['start_date'];
$end_date = $data['end_date'];
$salary_start_date = $start_date->toDateString();
$salary_end_date = $end_date->toDateString();
$working_days_by_month = $this->get_working_days_of_given_month($start_date, $end_date);
$working_days = $working_days_by_month['working_days'];
$no_days = $working_days_by_month['no_days'];
Schema::create('temp_salary', function (Blueprint $table) {
$table->increments('id');
$table->integer('employee_id');
$table->string('employee_name');
$table->integer('working_days');
$table->float('emp_working_days');
$table->float('basic');
$table->float('hra');
$table->float('conveyance');
$table->float('spcl_inc');
$table->float('gross_salary');
$table->float('pf');
$table->float('esi');
$table->integer('headphone');
$table->integer('id_card');
$table->float('deductions');
$table->integer('pl_balance');
$table->integer('combo_balance');
$table->float('net_payable');
$table->string('month')->nullable();
$table->string('attendance_types');
$table->string('choose_date')->nullable();
$table->string('department')->nullable();
$table->string('role')->nullable();
$table->string('process')->nullable();
$table->timestamps();
$table->temporary();
});
$csv[] = ['Employee ID', 'Name','Department','Role','Process','Bank','Bank Account Number', 'Basic', 'HRA', 'Conveyance', 'Spcl Inc', 'Gross Salary','PF', 'ESI', 'Deductions', 'Total Working Days', 'Net Payable','Salary Month', 'Salary Start Date','Salary End Date'];
$csv1[] = ['Employee ID', 'Name','Department','Role','Process','Bank','Bank Account Number', 'Basic', 'HRA', 'Conveyance', 'Spcl Inc', 'Gross Salary','PF', 'ESI', 'Deductions', 'P','H','A','WO','WOP','WOH','UAL','Paid Leaves','PL','Combo','ual_deduct','Total Working Days', 'Net Payable','Salary Month', 'Salary Start Date','Salary End Date'];
foreach($employee_ids as $id) {
if($submit_salary == true){
DB::table('attendances')->where('employee_id', '=', $id)->whereBetween('attendance_date', [$start_date, $end_date])->update(['salary_status' => 1]);
}
$employee = Employee::find($id);
$name = $employee->name;
$emp_role = $employee->empRole->role_name;
$emp_department = $employee->empDepartment->dept_name;
$emp_process = $employee->empProcess->process_name;
$bank_account_number = $employee->bank_account_number;
$bank_name = $employee->bank_name;
$salary = Salary::where('employee_id', $id)->first();
$pl_balance = $salary->pl_balance;
$combo_balance = $salary->combo_balance;
$attendances = DB::table('attendances')->where('employee_id', '=', $id)->get();
if ($attendances->count() > 0)
{
foreach($attendances as $attendance)
{
$att_id = $attendance->id;
$att_date = Carbon::parse($attendance->attendance_date);
$dialer_in = strtotime($attendance->dialer_in_time);
$dialer_out = strtotime($attendance->dialer_out_time);
$bio_in = strtotime($attendance->biometric_in_time);
$bio_out = strtotime($attendance->biometric_out_time);
$bio_diff = $bio_out - $bio_in;
$crm_in = strtotime($attendance->crm_in_time);
$crm_out = strtotime($attendance->crm_out_time);
$week_off = $attendance->week_off;
$combo = $attendance->combo;
$holiday = $attendance->holiday;
$ual = $attendance->ual;
$dialer_duration = $attendance->dialer_difference;
$bio_duration = $attendance->biometric_difference;
$crm_duration = $attendance->crm_difference;
$chkatt = $this->get_attendance($attendance_type, $attendance->dialer_in_time, $attendance->dialer_out_time,$attendance->crm_in_time,$attendance->crm_out_time, $dialer_duration, $bio_duration, $crm_duration);
$attendance_status = $this->attendance_status($id, $chkatt, $holiday, $week_off, $ual);
DB::table('attendances')->where('id', $att_id)->update(['attendance_status' => $attendance_status]);
//echo $attendance_status;
}
}
$totalWorkingDays = $this->get_work_days($id,$start_date,$end_date,$combo_balance,$pl_balance, $submit_salary);
$totalWorkingDays = number_format((float)$totalWorkingDays, 2, '.', '');
$salary_data = $this->get_calculated_salary_data($no_days, $totalWorkingDays, $id, $submit_salary);
$basic = $salary_data['basic'];
$hra = $salary_data['hra'];
$conveyance = $salary_data['conveyance'];
$spcl_inc = $salary_data['spcl_inc'];
$gross_salary = $salary_data['gross_salary'];
$pf = $salary_data['pf'];
$esi = $salary_data['esi'];
$hp_charges = $salary_data['hp_charges'];
$idcard_charges = $salary_data['idcard_charges'];
$deductions = $salary_data['deductions'];
$net_payable = $salary_data['net_payable'];
DB::table('temp_salary')->insert(['employee_id' => $id, 'employee_name' => $name, 'working_days' => $working_days, 'emp_working_days' => $totalWorkingDays, 'basic' => $basic, 'hra' => $hra, 'conveyance' => $conveyance, 'spcl_inc' => $spcl_inc, 'gross_salary' => $gross_salary, 'pf' => $pf, 'esi' => $esi, 'headphone' => $hp_charges, 'id_card' => $idcard_charges, 'deductions' => $deductions, 'pl_balance' => $pl_balance, 'combo_balance' => $combo_balance, 'net_payable' => $net_payable, 'month' => $month, 'attendance_types' => $attendance_type_temp_insert, 'choose_date' => $date, 'department' => $salary_dept, 'role' => $salary_role, 'process' => $salary_process]);
$csv[] = [$id, $name, $emp_department, $emp_role, $emp_process, $bank_name, $bank_account_number, $basic, $hra, $conveyance, $spcl_inc, $gross_salary, $pf, $esi, $deductions, $totalWorkingDays, $net_payable, $month, $start_date, $end_date];
$get_days_status = $this->get_days_status($id, $start_date, $end_date);
$pCount = $get_days_status['pCount'];
$HalfDaysCount = $get_days_status['hCount'];
$lateLeaveCount = $get_days_status['late_leave'];
$wopCount = $get_days_status['wopCount'];
$leaves_count = $get_days_status['leaves_count'];
$UalCount = $get_days_status['UalCount'];
$woCount = $get_days_status['woCount'];
$wohCount = $get_days_status['wohCount'];
$ual_deduct = ($UalCount * 1.5) - $UalCount;
$get_paid_leaves_row = $get_days_status['pl_leaves'];
$csv1[] = [$id, $name, $emp_department, $emp_role, $emp_process, $bank_name, $bank_account_number, $basic, $hra, $conveyance, $spcl_inc, $gross_salary, $pf, $esi, $deductions, $pCount,$HalfDaysCount,$leaves_count,$woCount,$wopCount,$wohCount,$UalCount,$get_paid_leaves_row,$pl_balance, $combo_balance,$ual_deduct, $totalWorkingDays, $net_payable, $month, $start_date, $end_date];
}
$datas = DB::table('temp_salary')->get();
if($submit_salary == true){
return Excel::create('Employee_salary_report', function($excel) use ($csv) {
$excel->sheet('Employee_salary_report', function($sheet) use ($csv) {
$sheet->fromArray($csv, null, 'A1', false, false)
->getStyle('A1')
->getAlignment()
->setWrapText(true);
});
})->download('csv');
}
if($download_salary == true){
return Excel::create('salary_report', function($excel) use ($csv1) {
$excel->sheet('salary_report', function($sheet) use ($csv1) {
$sheet->fromArray($csv1, null, 'A1', false, false)
->getStyle('A1')
->getAlignment()
->setWrapText(true);
});
})->download('csv');
}
Schema::drop('temp_salary');
$departments = Department::all();
$processes = Process::all();
$roles = Role::all();
return view('sys_mg.salaries.get-salary')->with(['datas'=>$datas,'departments' => $departments, 'processes' => $processes, 'roles' => $roles, 'salary_dept' => $salary_dept, 'salary_role' => $salary_role, 'salary_process'=>$salary_process, 'salary_month'=>$month,'salary_startDate' => $salary_start_date, 'salary_endDate' => $salary_end_date, 'attendance_check_type' => $attendance_type]);
}
答案 0 :(得分:1)
这是一个巨大的过程,一次要做很多事情,其中有些相互嵌套。
该函数非常非常长,这意味着它可能需要抽象为各种方法和类(更好的OOP)。
您也可能会通过一些Laravel查询遇到N + 1问题,尽管一眼很难说出来。
我建议使用Laravel的队列,并将每个员工的工资计算添加到队列中:https://laravel.com/docs/5.8/queues
然后您可以使用辅助进程来单独执行每个进程。
所有数据库更新和事务都意味着PHP会不断在数据库中往返移动。尝试以纯代码执行尽可能多的操作,然后在完成后写入数据库。 (在可能的情况下,这不是总括规则)。
首先,我想考虑使用SalaryCalculator
和getAttendances()
之类的方法创建一个calculateSalaryFromEmployeeAttendances()
类。
分别创建CSV导出程序类。首先处理所有薪资计算,将结果存储在数据库中,然后再按需转换为CSV。
一旦您能够查看所有不同部分,您将在以后进行重构,其他人也许可以提出更好的方法来分解它,但是在某些方面没有正确的答案...只是开始加上一些OOP和方法抽象,它将变得更好。
使用microtime(true)
获取并计算开始和结束操作之间的时间差,开始跟踪每个函数运行多长时间...然后首先寻找重大优化。最慢的部分是什么?为什么?
您可能会问十几个Stack Overflow问题,以优化每种方法,没关系!