setCommon($data, $user); $list = $this->limit($model,'',$data); $list = $this->fillData($list); return [true, $list]; } // private function setCommon($data,$user, $field = []){ if(empty($field)) $field = AuxiliaryAccount::$field; $data['top_depart_id'] = $user['top_depart_id']; $model = AuxiliaryAccount::Clear($user,$data); $model = $model->where('del_time',0) ->select($field) ->orderby('month', 'desc'); if(! empty($data['month'])) $model->where('month', $data['month']); if(! empty($data['code'])) $model->where('code', 'LIKE', '%'.$data['code'].'%'); return $model; } public function fillData($data){ if(empty($data['data'])) return $data; $emp = (new EmployeeService())->getEmployeeMap(array_unique(array_column($data['data'],'crt_id'))); foreach ($data['data'] as $key => $value){ $data['data'][$key]['crt_time'] = $value['crt_time'] ? date('Y-m-d H:i:s',$value['crt_time']) : ''; $data['data'][$key]['crt_name'] = $emp[$value['crt_id']] ?? ''; $data['data'][$key]['month'] = $value['month'] ? date('Y-m',$value['month']) : ''; } return $data; } public function auxiliaryAccountSummary($data,$user){ //传参月份 if(!isset($data['month'])) return [201,'月份必传']; $month = $data['month']; $monthStart = strtotime($month); $monthEnd = strtotime("$month +1 month") - 1; //获取员工汇总月份工资 list($status,$employee_month_amount) = $this->employeeMonthAmount($data,$user,$monthStart,$monthEnd); if (!$status) return [$status,$employee_month_amount]; //获取设备折旧费用 list($status,$device_month_amount) = $this->deviceMonthAmount($data,$user,$monthStart,$monthEnd); if (!$status) return [$status,$device_month_amount]; //获取费用汇总的费用数据 list($status,$fee_month_amount) = $this->feeMonthAmount($data,$user,$monthStart,$monthEnd); if (!$status) return [$status,$fee_month_amount]; return [true,[ "employee_month_amount" => $employee_month_amount, "device_month_amount" => $device_month_amount, "fee_month_amount" => $fee_month_amount, ]]; } private function employeeMonthAmount($month,$user,$monthStart,$monthEnd){ $data['top_depart_id'] = $user['top_depart_id']; $month_ps_order = MonthlyPsOrder::Clear($user,$data); $month_ps_order_id = $month_ps_order->where("month",$monthStart)->first(); if(empty($month_ps_order_id)){ return [false,"请补充对应月份人员月度工资信息"]; }else{ $month_ps_order_id = $month_ps_order_id->id; } $model = MonthlyPsOrderDetails::Clear($user,$data); //总金额 $total_amount = $model->where('main_id',$month_ps_order_id)->where('del_time',0)->sum("salary"); //委内 $entrust_in_amount = $model->where('main_id',$month_ps_order_id)->where("entrust_type",1)->sum("salary"); //委外 $entrust_out_amount = $model->where('main_id',$month_ps_order_id)->where("entrust_type",2)->sum("salary"); return [true,[ "total_amount" => $total_amount, "entrust_in_amount" => $entrust_in_amount, "entrust_out_amount" => $entrust_out_amount, ]]; } private function deviceMonthAmount($month,$user,$monthStart,$monthEnd){ $data['top_depart_id'] = $user['top_depart_id']; $month_ps_order = MonthlyDdOrder::Clear($user,$data); $month_ps_order_id = $month_ps_order->where('del_time',0)->where("month",$monthStart)->first(); if(empty($month_ps_order_id)){ return [false,"请补充对应月份设备月度折旧信息"]; }else{ $month_ps_order_id = $month_ps_order_id->id; } $model = MonthlyDdOrderDetails::Clear($user,$data); //总金额 $total_amount = $model->where('main_id',$month_ps_order_id)->sum("depreciation_amount"); return [true,[ "total_amount" => $total_amount, ]]; } private function feeMonthAmount($month,$user,$monthStart,$monthEnd){ $data['top_depart_id'] = $user['top_depart_id']; $month_ps_order = ExpenseClaims::Clear($user,$data); $month_ps_order_id = $month_ps_order->where('del_time',0)->where("month",$monthStart)->first(); if(empty($month_ps_order_id)){ return [false,"请补充对应月份费用信息"]; }else{ $month_ps_order_id = $month_ps_order_id->id; } $model = new ExpenseClaimsDetails(); //总金额 $list = $model->where('expense_claims_id',$month_ps_order_id)->select("fee_id","amount","remark","entrust_type","item_id")->get()->toArray(); ///分组 $fee_type_list = Fee::Clear($user,$data)->where('del_time',0)->select("title","id","parent_id")->get()->toArray(); return [true,$this->groupListByRoot($list,$fee_type_list)]; } /** * 将报销明细按照一级费用分类进行分组 * * @param array $list 报销明细列表 (含 fee_id, amount 等) * @param array $fee_type_list 费用类型树 (含 id, parent_id, title) * @return array */ public function groupListByRoot(array $list, array $fee_type_list) { // 1. 建立 ID 索引,方便快速查找 $idMap = array_column($fee_type_list, null, 'id'); // 2. 预处理映射表:让所有子 ID 直接指向它的最顶层“祖宗” ID $childToRoot = []; $grouped = []; foreach ($fee_type_list as $type) { $current = $type; // 向上追溯直到 parent_id 为 0,即找到一级分类 while ($current['parent_id'] != 0) { $current = $idMap[$current['parent_id']]; } $childToRoot[$type['id']] = [ 'id' => $current['id'], 'title' => $current['title'] ]; if (!isset($grouped[$current['id']])) { $grouped[$current['id']] = [ 'first_level_id' => $current['id'], 'first_level_title' => $current['title'], 'details' => [] ]; } } // 3. 遍历明细数据进行分组 foreach ($list as $item) { $feeId = $item['fee_id']; // 获取该费用对应的一级分类信息 $rootInfo = $childToRoot[$feeId] ?? ['id' => 0, 'title' => '其他费用']; $rootId = $rootInfo['id']; if (!isset($grouped[$rootId])) { $grouped[$rootId] = [ 'first_level_id' => $rootId, 'first_level_title' => $rootInfo['title'], 'details' => [] ]; } $grouped[$rootId]['details'][] = $item; } // 4. 重置数组索引并返回 return array_values($grouped); } public function auxiliaryAccountAdd($data,$user){ list($status,$msg) = $this->auxiliaryAccountRule($data, $user); if(!$status) return [$status,$msg]; //费用报销结构 try { DB::beginTransaction(); $model = new AuxiliaryAccount(); $model->code = $this->generateBillNo([ 'top_depart_id' => $user['top_depart_id'], 'type' => ExpenseClaims::Order_type, 'period' => date("Ym", strtotime($data['month'])) ]); $model->month = strtotime($data['month']); $model->crt_id = $user['id']; $model->top_depart_id = $user['top_depart_id']; $model->save(); $data['top_depart_id'] = $user['top_depart_id']; $this->saveDetail($model->id, time(), $data,$user['id']); DB::commit(); }catch (\Exception $exception){ DB::rollBack(); return [false,$exception->getMessage()]; } return [true, '']; } private function saveDetail($id, $time, $data,$crt_id){ if(! empty($data['details'])){ $unit = []; foreach ($data['details'] as $value){ $unit[] = [ 'auxiliary_account_id' => $id, 'voucher_date' => strtotime($value['voucher_date']), 'voucher_type' => $value['voucher_type'], 'voucher_no' => $value['voucher_no'], 'voucher_remark' => $value['voucher_remark'], 'voucher_amount' => $value['voucher_amount'], 'entrust_type' => $value['entrust_type']??"", 'type' => $value['type'], 'fee_id' => $value['fee_id']??0, 'remark' => $value['remark']??"", 'entrust1_amount' => $value['entrust1_amount']??0, 'entrust2_amount' => $value['entrust2_amount']??0, 'aggregation_amount' => $value['aggregation_amount']??00, 'total_amount' => $value['total_amount'], 'top_depart_id' => $data['top_depart_id'], 'item_id' => $data['item_id'], 'crt_time' => $time, 'crt_id' => $crt_id, ]; } if(!empty($unit)) AuxiliaryAccountDetails::insert($unit); } } private function auxiliaryAccountRule($data,$user){ if(!isset($data['month'])) return [false,"月份必传"]; $monthStr = $data['month']; // 假设是 "2026-03" $monthStart = strtotime($monthStr); // 2026-03-01 00:00:00 // 获取该月最后一秒:下个月 1 号减去 1 秒 $monthEnd = strtotime("$monthStr +1 month") - 1; foreach ($data['details'] as $index => $item) { if (!isset($item['voucher_date'])) { return [false, "第" . ($index + 1) . "凭证日期缺失"]; } if (!isset($item['voucher_no'])) { return [false, "第" . ($index + 1) . "凭证号数缺失"]; } if (!isset($item['voucher_amount'])) { return [false, "第" . ($index + 1) . "凭证记载金额缺失"]; } if (!isset($item['voucher_type'])) { return [false, "第" . ($index + 1) . "凭证类型缺失"]; } if (!isset($item['aggregation_amount'])) { return [false, "第" . ($index + 1) . "凭证归集金额缺失"]; } if (!isset($item['voucher_remark'])) { return [false, "第" . ($index + 1) . "凭证摘要缺失"]; } // 将报销日期转换为时间戳 $claimTime = strtotime($item['voucher_date']); // 判断:voucher_date 必须早于 month // 如果 voucher_date 是 2026-02-28,而 month 是 2026-03-01,则校验通过 if ($claimTime < $monthStart || $claimTime > $monthEnd) { return [false, "第" . ($index + 1) . "凭证日期必须早于当前结算月份(" . $data['month'] . ")"]; } } return [true,""]; } public function auxiliaryAccountEdit($data,$user){ list($status,$msg) = $this->auxiliaryAccountRule($data, $user, false); if(!$status) return [$status,$msg]; try { DB::beginTransaction(); $model = AuxiliaryAccount::where('id',$data['id'])->first(); //不允许修改头部 // $model->save(); $time = time(); AuxiliaryAccountDetails::where('del_time',0) ->where('auxiliary_account_id', $model->id) ->update(['del_time' => $time]); $data['top_depart_id'] = $user['top_depart_id']; $this->saveDetail($model->id, $time, $data,$user['id']); DB::commit(); }catch (\Exception $exception){ DB::rollBack(); return [false,$exception->getMessage()]; } return [true, '']; } public function auxiliaryAccountDel($data){ if($this->isEmpty($data,'id')) return [false,'请选择数据!']; try { DB::beginTransaction(); $time = time(); AuxiliaryAccount::where('del_time',0) ->whereIn('id',$data['id']) ->update(['del_time' => $time]); AuxiliaryAccountDetails::where('del_time',0) ->whereIn('auxiliary_account_id', $data['id']) ->update(['del_time' => $time]); DB::commit(); }catch (\Exception $exception){ DB::rollBack(); return [false,$exception->getMessage()]; } return [true, '']; } public function auxiliaryAccountDetail($data, $user){ if($this->isEmpty($data,'id')) return [false,'请选择数据!']; $customer = AuxiliaryAccount::where('del_time',0) ->where('id',$data['id']) ->first(); if(empty($customer)) return [false,'单据不存在或已被删除']; $customer = $customer->toArray(); $customer['crt_name'] = Employee::where('id',$customer['crt_id'])->value('title'); $customer['crt_time'] =$this->utcTime($customer['crt_time']); $customer['month'] =$this->utcTime($customer['month']); $details = $this->getDetail($data['id']); $customer["details"] = $details; return [true, $customer]; } private function getDetail($id){ $data = AuxiliaryAccountDetails::where('del_time',0) ->where('auxiliary_account_id', $id) ->select('*') ->get()->toArray(); foreach ($data as &$v){ $v['voucher_date'] = $this->utcTime($v['voucher_date']); } return $data; } private function utcTime($time){ return Carbon::createFromTimestamp($time, 'UTC') ->toIso8601ZuluString(); } }