| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- <?php
- namespace App\Service;
- use App\Model\DailyPwOrder;
- use App\Model\DailyPwOrderDetails;
- use App\Model\ExpenseClaims;
- use App\Model\ExpenseClaimsDetails;
- use App\Model\Fee;
- use App\Model\Item;
- use App\Model\MonthlyDdOrder;
- use App\Model\MonthlyDdOrderDetails;
- use App\Model\MonthlyPsOrder;
- use App\Model\MonthlyPsOrderDetails;
- use App\Model\PLeaveOverOrder;
- use App\Model\PLeaveOverOrderDetails;
- class BIService extends Service
- {
- private function commonRule($data)
- {
- if (isset($data['time']) && !empty($data['time'])) {
- $start = $this->changeDateToDate($data['time'][0]);
- $end = $this->changeDateToDate($data['time'][1], true);
- $data['month_start'] = date("Y-m-d", $start);
- $data['month_end'] = date("Y-m-d", $end);
- }
- if (!isset($data['month_start'])) $month_start = date('Y-01-01', strtotime('-1 year'));
- else $month_start = date('Y-m-01', strtotime($data['month_start']));
- if (!isset($data['month_end'])) $month_end = date('Y-01-01', strtotime('+1 year', strtotime($month_start)));
- else {
- $start_year = date('Y', strtotime($month_start));
- $end_year = date('Y', strtotime($data['month_end']));
- if ($start_year != $end_year) return [false, "查询不得跨年!", ""];
- $month_end = date('Y-m-01', strtotime($data['month_end'] . ' +1 month'));
- }
- return [true, strtotime($month_start), strtotime($month_end)];
- }
- public function homePageData($data, $user)
- {
- $model = Item::TopClear($user,$data);
- $start_time = $model->where('del_time',0)
- ->orderby('id', 'desc')->value("start_time");
- $year = date('Y-01-01',$start_time);
- $data['month_start'] = $year;
- // $data['month_start'] = "2024-01-01";
- list($status, $month_start, $month_end) = $this->commonRule($data);
- if (!$status) return [false, $month_start];
- //人员费用
- list($total_man, $salary_map) = $this->getEmployeeSalary($month_start, $month_end, $data, $user);
- //折旧费用
- list($total_zj, $zj_map) = $this->getDeviceSalary($month_start, $month_end, $data, $user);
- //费用报销
- list($total_other, $other_map, $return_fee) = $this->getFeeItemSalary($month_start, $month_end, $data, $user);
- //研发费用总额
- $total = bcadd(bcadd($total_man, $total_zj,3), $total_other,3);
- //研发费用结构
- $rd = [
- 0 => [
- 'title' => '人工费用',
- 'rate' => $total == 0 ? 0 : bcmul(bcdiv($total_man,$total,4),100,2),
- 'rate_unit' => '%',
- 'total' => $total_man,
- 'total_unit' => '¥',
- ],
- 1 => [
- 'title' => '折旧费用',
- 'rate' => $total == 0 ? 0 :bcmul(bcdiv($total_zj,$total,4),100,2),
- 'rate_unit' => '%',
- 'total' => $total_zj,
- 'total_unit' => '¥',
- ],
- 2 => [
- 'title' => '费用报销',
- 'rate' => $total == 0 ? 0 :bcmul(bcdiv($total_other,$total,4),100,2),
- 'rate_unit' => '%',
- 'total' => $total_other,
- 'total_unit' => '¥',
- ],
- ];
- //研发费用趋势
- $rd_trend = $this->makeTrend($month_start, $salary_map, $zj_map, $other_map);
- //研发费用报销占比
- $rd_rate = $return_fee;
- //加班 请假 总时长
- list($over_time, $leave_time) = $this->overLeave($month_start, $month_end, $data, $user);
- // 项目人员工时汇总
- $man_work = $this->manWork($month_start, $month_end, $data, $user);
- //加计扣除金额
- $statisticService = new StatisticService();
- $attendance = $statisticService->employeeAttendanceMonthStatistic(["year"=>$year, "s" => "/api/employeeAttendanceMonthStatistic"],$user);
- $discount = 0; //todo
- foreach ($attendance[1]['list'] as $v){
- $discount += $v['jj_total_amount']*100;
- }
- return [true, [
- 'rd_total' => $total,
- 'rd_unit' => '¥',
- 'rd_title' => '研发费用总额', //-----
- 'discount_total' => round($discount/100,2),
- 'discount_unit' => '¥',
- 'discount_title' => '加计扣除金额', //------
- 'over_time' => $over_time, // 加班
- 'leave_time' => $leave_time, // 请假
- 'rd' => $rd, //研发费用结构
- 'rd_trend' => $rd_trend, //研发费用趋势
- 'rd_rate' => $rd_rate, // 研发费用报销占比
- 'man_work' => $man_work, //项目人员工时汇总
- 'year' => date('Y',strtotime($year)),
- ]];
- }
- private function getEmployeeSalary($month_start, $month_end, $data, $user)
- {
- $monthly_ps_order = MonthlyPsOrder::Clear($user, $data)
- ->where('del_time', 0)
- ->where("month", ">=", $month_start)
- ->where("month", "<", $month_end)
- ->pluck('month','id')
- ->toArray();
- $monthly_ps_order_ids = array_keys($monthly_ps_order);
- $month_employee_salary = MonthlyPsOrderDetails::whereIn('main_id', $monthly_ps_order_ids)
- ->select("base_salary","performance_salary","other","bonus", "main_id")
- ->get()
- ->toArray();
- $total = 0;
- $salary_map = [];
- foreach ($month_employee_salary as $value) {
- $currentAmount = bcadd($value['base_salary'], $value['performance_salary'],3);
- $currentAmount = bcadd($currentAmount, $value['other'],3);
- $currentAmount = bcadd($currentAmount, $value['bonus'],3);
- if(isset($monthly_ps_order[$value['main_id']])){
- $month = $monthly_ps_order[$value['main_id']];
- if(isset($salary_map[$month])){
- $salary_map[$month] = bcadd($salary_map[$month], $currentAmount,3);
- }else{
- $salary_map[$month] = $currentAmount;
- }
- }
- $total = bcadd($total, $currentAmount,3);
- }
- return [$total, $salary_map];
- }
- private function getDeviceSalary($month_start, $month_end, $data, $user)
- {
- $monthly_dd_order= MonthlyDdOrder::Clear($user, $data)
- ->where('del_time', 0)
- ->where("month", ">=", $month_start)
- ->where("month", "<", $month_end)
- ->pluck('month','id')
- ->toArray();
- $monthly_dd_order_ids = array_keys($monthly_dd_order);
- $month_device_salary = MonthlyDdOrderDetails::whereIn('main_id', $monthly_dd_order_ids)
- ->select("depreciation_amount as amount", "main_id")
- ->get()
- ->toArray();
- $total = 0;
- $amount_map = [];
- foreach ($month_device_salary as $value) {
- $currentAmount = (string)$value['amount'];
- if(isset($monthly_dd_order[$value['main_id']])){
- $month = $monthly_dd_order[$value['main_id']];
- if(isset($amount_map[$month])){
- $amount_map[$month] = bcadd($amount_map[$month], $currentAmount,3);
- }else{
- $amount_map[$month] = $currentAmount;
- }
- }
- $total = bcadd($total, $currentAmount,3);
- }
- return [$total, $amount_map];
- }
- private function getFeeItemSalary($month_start, $month_end, $data, $user)
- {
- $e_order = ExpenseClaims::Clear($user, $data)
- ->where('del_time', 0)
- ->where("month", ">=", $month_start)
- ->where("month", "<", $month_end)
- ->pluck('month','id')
- ->toArray();
- $e_order_ids = array_keys($e_order);
- $e_order_detail = ExpenseClaimsDetails::whereIn('expense_claims_id', $e_order_ids)
- ->select("amount", "expense_claims_id as main_id", "fee_id")
- ->get()
- ->toArray();
- $fee = Fee::TopClear($user, $data);
- $fee_map = $fee->whereIn('id', array_unique(array_column($e_order_detail,'fee_id')))->pluck('title','id')->toArray();
- $total = 0;
- $amount_map = [];
- $fee_amount_map = [];
- foreach ($e_order_detail as $value) {
- $currentAmount = (string)$value['amount'];
- if(isset($e_order[$value['main_id']])){
- $month = $e_order[$value['main_id']];
- if(isset($amount_map[$month])){
- $amount_map[$month] = bcadd($amount_map[$month], $currentAmount,3);
- }else{
- $amount_map[$month] = $currentAmount;
- }
- }
- $fee_tmp = $fee_map[$value['fee_id']] ?? "";
- if(! empty($fee_tmp)){
- if(isset($fee_amount_map[$fee_tmp])){
- $fee_amount_map[$fee_tmp] = bcadd($fee_amount_map[$fee_tmp], $currentAmount,3);
- }else{
- $fee_amount_map[$fee_tmp] = $currentAmount;
- }
- }
- $total = bcadd($total, $currentAmount,3);
- }
- $return_fee = [];
- foreach ($fee_amount_map as $key => $value){
- $amount = (string)$value;
- $return_fee[] = [
- "title" => $key,
- "total" => $amount,
- "total_unit" => "元",
- "rate" => bcmul(bcdiv($amount,$total,4),100,2),
- "rate_unit" => "%"
- ];
- }unset($fee_amount_map);
- return [$total, $amount_map, $return_fee];
- }
- private function makeTrend($month_start, $salary_map, $zj_map, $other_map)
- {
- $trend = [];
- for ($i = 0; $i < 12; $i++) {
- // 计算每个月第一天的时间戳作为 Key
- $timestamp = strtotime("+$i month", $month_start);
- $monthName = ($i + 1) . '月';
- $trend[$timestamp] = [
- 'month' => $monthName,
- // 'salary' => "0.000",
- // 'zj' => "0.000",
- // 'other' => "0.000",
- 'total' => "0.000",
- ];
- }
- // 2. 将传入的 Map 数据填充进去
- foreach ($trend as $timestamp => &$item) {
- // 使用 ?? "0" 容错,并强制转为 string 保证 bcadd 精度
- $s = $salary_map[$timestamp] ?? "0";
- $z = $zj_map[$timestamp] ?? "0";
- $o = $other_map[$timestamp] ?? "0";
- // $item['salary'] = bcadd($s, "0", 3);
- // $item['zj'] = bcadd($z, "0", 3);
- // $item['other'] = bcadd($o, "0", 3);
- // 计算该月总计
- $item['total'] = bcadd(bcadd($s, $z, 3), $o, 3);
- }
- return array_values($trend);
- }
- private function overLeave($month_start, $month_end, $data, $user)
- {
- $id = PLeaveOverOrder::Clear($user, $data)
- ->where('del_time', 0)
- ->where("order_time", ">=", $month_start)
- ->where("order_time", "<", $month_end)
- ->pluck('id')
- ->toArray();
- $p = PLeaveOverOrderDetails::whereIn('main_id', $id)
- ->select("type", "total_min")
- ->get()
- ->toArray();
- $total = $total_1 = 0;
- foreach ($p as $value) {
- $total_min = (string)$value['total_min'];
- if($value['type'] == PLeaveOverOrderDetails::TYPE_ONE){
- $total = bcadd($total, $total_min,2);
- }else{
- $total_1 = bcadd($total_1, $total_min,2);
- }
- }
- // 最终返回或输出前转换
- $total_hours = bcdiv($total, 60, 2);
- $total_1_hours = bcdiv($total_1, 60, 2);
- return [$total_1_hours, $total_hours];
- }
- private function manWork($month_start, $month_end, $data, $user)
- {
- $daily_pw = DailyPwOrder::Clear($user, $data)
- ->where('del_time', 0)
- ->where("order_time", ">=", $month_start)
- ->where("order_time", "<", $month_end)
- ->select('id','item_id')
- ->get()->toArray();
- $item_map = Item::whereIn('id',array_unique(array_column($daily_pw,'item_id')))
- ->pluck('title','id')
- ->toArray();
- $p = DailyPwOrderDetails::whereIn('main_id', array_column($daily_pw,'id'))
- ->select("item_id", "total_work_min")
- ->get()
- ->toArray();
- $total = 0;
- $map = [];
- foreach ($p as $value) {
- $total_min = (string)$value['total_work_min'];
- if(isset($map[$value['item_id']])){
- $map[$value['item_id']] = bcadd($map[$value['item_id']], $total_min,2);
- }else{
- $map[$value['item_id']] = $total_min;
- }
- $total = bcadd($total, $total_min,2);
- }
- $return = [];
- foreach ($map as $key => $value){
- $rate = bcmul(bcdiv($value, $total,4),100,2);
- $total_hours = bcdiv($value, 60, 2);
- $return[] = [
- 'title' => $item_map[$key] ?? "",
- 'total_work_hour' => $total_hours,
- 'total_work_hour_unit' => "小时",
- "rate" => $rate,
- "rate_unit" => "%",
- ];
- }
- return $return;
- }
- }
|