|
@@ -525,6 +525,115 @@ class StatisticService extends StatisticCommonService
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function itemDeviceMonthStatistic($data, $user)
|
|
public function itemDeviceMonthStatistic($data, $user)
|
|
|
|
|
+ {
|
|
|
|
|
+ // 1. 基础校验与时间初始化
|
|
|
|
|
+ list($status, $month_start, $month_end) = $this->commonRule($data);
|
|
|
|
|
+ if (!$status) return [false, $month_start];
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 获取设备工时数据 (项目+设备+月)
|
|
|
|
|
+ $month_device_list = DailyDwOrderDetails::Clear($user, $data)
|
|
|
|
|
+ ->where("order_time", ">=", $month_start)
|
|
|
|
|
+ ->where("order_time", "<", $month_end)
|
|
|
|
|
+ ->where('del_time', 0)
|
|
|
|
|
+ ->select(
|
|
|
|
|
+ "item_id",
|
|
|
|
|
+ "device_id",
|
|
|
|
|
+ DB::raw("FROM_UNIXTIME(order_time, '%Y-%m') as order_month"),
|
|
|
|
|
+ DB::raw("SUM(total_work_min) as total_work")
|
|
|
|
|
+ )
|
|
|
|
|
+ ->groupBy(DB::raw("FROM_UNIXTIME(order_time, '%Y-%m')"), "item_id", "device_id")->get()->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 获取折旧费主表及详情
|
|
|
|
|
+ $monthly_dd_query = MonthlyDdOrder::Clear($user, $data)->where('del_time', 0)
|
|
|
|
|
+ ->where("month", ">=", $month_start)->where("month", "<", $month_end);
|
|
|
|
|
+
|
|
|
|
|
+ $monthly_dd_ids = $monthly_dd_query->pluck('id')->toArray();
|
|
|
|
|
+ $monthly_dd_months = $monthly_dd_query->select('id', DB::raw("FROM_UNIXTIME(month, '%Y-%m') as month_str"))
|
|
|
|
|
+ ->pluck("month_str", 'id')->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ $device_salary_details = MonthlyDdOrderDetails::wherein('main_id', $monthly_dd_ids)
|
|
|
|
|
+ ->select("device_id", "depreciation_amount", "main_id")->get()->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 构建高精度折旧池 (单位:分)
|
|
|
|
|
+ $depreciation_pool = [];
|
|
|
|
|
+ foreach ($device_salary_details as $val) {
|
|
|
|
|
+ $m = $monthly_dd_months[$val['main_id']] ?? '';
|
|
|
|
|
+ if ($m) {
|
|
|
|
|
+ $key = $val['device_id'] . '_' . $m;
|
|
|
|
|
+ // 同一个设备在同一个月可能存在多条折旧记录,需累加
|
|
|
|
|
+ $depreciation_pool[$key] = ($depreciation_pool[$key] ?? 0) + (int)round($val['depreciation_amount'] * 100);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 计算全月总工时及初始化余额池
|
|
|
|
|
+ $device_monthly_total_min = [];
|
|
|
|
|
+ foreach ($month_device_list as $row) {
|
|
|
|
|
+ $key = $row['device_id'] . '_' . $row['order_month'];
|
|
|
|
|
+ $device_monthly_total_min[$key] = ($device_monthly_total_min[$key] ?? 0) + $row['total_work'];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $rem_depreciation_cents = $depreciation_pool; // 折旧余额池
|
|
|
|
|
+ $rem_hours_cents = []; // 工时余额池 (小时*100)
|
|
|
|
|
+ foreach ($device_monthly_total_min as $key => $min) {
|
|
|
|
|
+ $rem_hours_cents[$key] = (int)round(($min / 60), 2) * 100;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 6. 统计项目数用于判断“最后一条”
|
|
|
|
|
+ $device_count = collect($month_device_list)->groupBy(fn($i) => $i['device_id'].'_'.$i['order_month'])
|
|
|
|
|
+ ->map(fn($g) => $g->count())->toArray();
|
|
|
|
|
+
|
|
|
|
|
+ // 7. 预加载设备与项目基础信息
|
|
|
|
|
+ $items_ids = collect($month_device_list)->pluck('item_id')->unique()->all();
|
|
|
|
|
+ $device_ids = collect($month_device_list)->pluck('device_id')->unique()->all();
|
|
|
|
|
+
|
|
|
|
|
+ $item_info = Item::TopClear($user, $data)->whereIn('id', $items_ids)->get()->keyBy('id');
|
|
|
|
|
+ $device_info = Device::TopClear($user, $data)->whereIn('id', $device_ids)->get()->keyBy('id');
|
|
|
|
|
+
|
|
|
|
|
+ // 8. 核心转换逻辑
|
|
|
|
|
+ $item_month_list = collect($month_device_list)->sortBy('order_month')->values()->transform(function ($item) use (
|
|
|
|
|
+ $item_info, $device_info, $depreciation_pool, $device_monthly_total_min,
|
|
|
|
|
+ &$device_count, &$rem_depreciation_cents, &$rem_hours_cents
|
|
|
|
|
+ ) {
|
|
|
|
|
+ $key = $item['device_id'] . '_' . $item['order_month'];
|
|
|
|
|
+ $total_min = $device_monthly_total_min[$key] ?? 0;
|
|
|
|
|
+
|
|
|
|
|
+ $item['item_title'] = $item_info[$item['item_id']]->title ?? "未知项目";
|
|
|
|
|
+ $item['item_code'] = $item_info[$item['item_id']]->code ?? "-";
|
|
|
|
|
+ $item['device_title'] = $device_info[$item['device_id']]->title ?? "未知设备";
|
|
|
|
|
+ $item['device_original'] = $device_info[$item['device_id']]->original_value ?? 0;
|
|
|
|
|
+
|
|
|
|
|
+ $item['month'] = $item['order_month'];
|
|
|
|
|
+ $item['total_depreciatio'] = ($depreciation_pool[$key] ?? 0) / 100;
|
|
|
|
|
+ $item['total_hours'] = round($total_min / 60, 2);
|
|
|
|
|
+
|
|
|
|
|
+ // 分摊比例计算
|
|
|
|
|
+ $ratio = $total_min > 0 ? ($item['total_work'] / $total_min) : 0;
|
|
|
|
|
+ $item['ratio'] = round($ratio, 4);
|
|
|
|
|
+
|
|
|
|
|
+ if (--$device_count[$key] > 0) {
|
|
|
|
|
+ // 非最后一条项目
|
|
|
|
|
+ $cur_hours = round($item['total_work'] / 60, 2);
|
|
|
|
|
+ $item['hours'] = $cur_hours;
|
|
|
|
|
+ $rem_hours_cents[$key] -= (int)round($cur_hours * 100);
|
|
|
|
|
+
|
|
|
|
|
+ $cur_depre = round($item['total_depreciatio'] * $ratio, 2);
|
|
|
|
|
+ $item['allocated_depreciatio'] = $cur_depre;
|
|
|
|
|
+ $rem_depreciation_cents[$key] -= (int)round($cur_depre * 100);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 最后一条项目,余额补平
|
|
|
|
|
+ $item['hours'] = round(($rem_hours_cents[$key] ?? 0) / 100, 2);
|
|
|
|
|
+ $item['allocated_depreciatio'] = round(($rem_depreciation_cents[$key] ?? 0) / 100, 2);
|
|
|
|
|
+ // 比例也做个平账展示
|
|
|
|
|
+ $item['ratio'] = round($item['hours'] / ($item['total_hours'] ?: 1), 4);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $item;
|
|
|
|
|
+ })->all();
|
|
|
|
|
+
|
|
|
|
|
+ return [true, $item_month_list];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function itemDeviceMonthStatistic1($data, $user)
|
|
|
{
|
|
{
|
|
|
//项目编码、项目名称、设备名称、项目工时、研发工时占比、设备原值、设备折旧额、本项目帐面归集的折旧额、确定的本项目折旧额、加计调整金额、当月工时、日期
|
|
//项目编码、项目名称、设备名称、项目工时、研发工时占比、设备原值、设备折旧额、本项目帐面归集的折旧额、确定的本项目折旧额、加计调整金额、当月工时、日期
|
|
|
list($status, $month_start, $month_end) = $this->commonRule($data);
|
|
list($status, $month_start, $month_end) = $this->commonRule($data);
|