lte(now()->startOfDay()->addHours(self::TIME_OUT_HOUR))) ? LaborApply::CAN_CREATE_STATUS_OPEN : LaborApply::CAN_CREATE_STATUS_FORBID; if (Cache::has(self::LABOR_APPLY_STATUS)) { $can_create_status = Cache::get(self::LABOR_APPLY_STATUS); } return $can_create_status; } /** * 设置预约开放状态 1 开放 2 禁止 3 临时开放 * @param int $status */ public function setCanCreateStatus(int $status) { Cache::put(self::LABOR_APPLY_STATUS, $status, self::LABOR_APPLY_STATUS_TTL); } public function allocationAppendLaborToLaborCompany() { $lately_allocation_at = Cache::get(self::LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT); $labor_applies = LaborApply::query() ->where('created_at', '>=', $lately_allocation_at) ->get(); } /** * 生产劳务派遣报表 * * 查询全部仓库 * 遍历仓库 * 按照仓库,查询当日的的申请,将申请的男女工分别加和 * 根据仓库 找到对应的劳务公司集合 * 遍历男工人数 * 确定每个劳务公司提供的男工人数 * 女工也一样 * 如果分配完成后 发现还有剩下的 则将状态设置为2 * @param bool $isAppend * @return array */ public function allocationLaborToLaborCompany(bool $isAppend = false): array { //当前时间小于 1.00 禁止生成数据 if (now()->lte(now()->startOfDay()->addHours(1))) return ['success' => false, 'error_message' => '当前时间禁止生成临时工派遣数据']; //上次分配时间 默认为前一天的18:00 $lately_allocation_at = now()->subDay()->startOfDay()->addHours(self::TIME_OUT_HOUR); //缓存中有上次的同步时间 if (Cache::has(self::LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT)) { $lately_allocation_at = Cache::get(self::LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT); } //派遣日期 为报表生成日期的后一天 $dispatch_date = now()->addDay()->startOfDay()->toDateTimeString(); //查询全部仓库 $warehouses = Warehouse::all(); //给每个仓库计算分配数据 更改申请状态为指派成功 foreach ($warehouses as $warehouse) { //根据时间,仓库,状态 查询当日的的申请,将申请的男女工分别加和 $builder = DB::table('labor_applies') ->selectRaw("sum(man_num) as man_num ,sum(woman_num) as woman_num") ->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()]) ->where('warehouse_id', $warehouse->id) ->where('status', 1); //如果是追加模式 if ($isAppend) { //只查询最后一次分配后的申请 $builder->where('created_at', '>=', $lately_allocation_at); } $apply_man_nums = $builder ->groupBy('warehouse_id') ->first(); if (empty($apply_man_nums)) continue; //按照仓库查询对应的劳务所 $companies = $this->getCompanies($warehouse); //没有找到劳务所直接跳出 if ($companies->isEmpty()) continue; //需要的男工人数 $man_num = $apply_man_nums->man_num; //需要的女工人数 $woman_num = $apply_man_nums->woman_num; //插入的分配数据 $laborCompanyDispatchInsertArray = $this->buildLaborCompanyDispatchInsertArray($companies, $man_num, $woman_num, $dispatch_date, $warehouse->id); //插入分配数据 LaborCompanyDispatch::query()->insert($laborCompanyDispatchInsertArray); //更新申请状态 LaborApply::query() ->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()]) ->where('warehouse_id', $warehouse->id) ->update([ 'status' => 2,//指派成功 ]); } //保存分配时间为当前时间 Cache::put(self::LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT, now()); return ['success' => true, 'message' => '生成临时工派遣数据成功']; } /** * 构建插入的分配数据 * @param Collection $companies * @param $man_num * @param $woman_num * @param string $dispatch_date * @param int $warehouse_id * @return array */ private function buildLaborCompanyDispatchInsertArray(Collection $companies, $man_num, $woman_num, string $dispatch_date, int $warehouse_id): array { //分配数组 $laborCompanyDispatchInsertArray = []; //使用劳务公司填充默认值 foreach ($companies as $company) { $laborCompanyDispatchInsertArray[$company->id] = [ 'labor_company_id' => $company->id, 'dispatch_date' => $dispatch_date, 'man_num' => 0, 'woman_num' => 0, 'exceed_max_labor_num_status' => LaborCompanyDispatch::NOT_EXCEED_MAX_LABOR_NUM,//没有超限额 'status' => 1,//创建 'warehouse_id' => $warehouse_id, 'created_at' => now(), 'updated_at' => now(), ]; } //分配男工 $this->dispatchWorker($man_num, $laborCompanyDispatchInsertArray, $companies, 'man_num'); //分配女工 $this->dispatchWorker($woman_num, $laborCompanyDispatchInsertArray, $companies, 'woman_num'); //保留 man_num || woman_num 不为0的 return array_filter($laborCompanyDispatchInsertArray, function ($item) { return $item['man_num'] > 0 || $item['woman_num'] > 0; }); } /** * 按照仓库查询对应的劳务所 按照优先级排序 单号正序 双号逆序 * @param $warehouse * @return Builder[]|Collection */ private function getCompanies($warehouse): Collection { return LaborCompany::query() ->where('warehouse_id', $warehouse->id) ->where('status', 1)//状态为启用 ->get(); } /** * 按照给定的申请日期计算到岗人数 * * 查询指定日期的 每个小组的申请人数 * 遍历申请数据 * 根据申请数据的仓库小组id,日期(申请日期后一天)查询打卡数据,计算人数之和 更新申请表actual_num * @param Carbon|null $apply_date */ public function calculationArrivedManNum(Carbon $apply_date = null) { //查询的申请日期 if (empty($apply_date)) { $apply_date = now()->subDays(self::CALCULATION_ARRIVED_MAN_NUM_DEFAULT_SUB_DAYS); } //查询指定日期的 每个小组的申请人数 $laborApplies = DB::table('labor_applies') ->selectRaw('user_workgroup_id as user_workgroup_id , sum(man_num + woman_num) as apply_num , warehouse_id') ->whereDate('created_at', $apply_date->toDateString()) ->groupBy('user_workgroup_id', 'warehouse_id') ->get(); //根据申请数据的仓库小组id,日期(申请日期后一天) $check_in_at = deep_copy($apply_date)->addDay()->toDateString(); //遍历申请数据 foreach ($laborApplies as $laborApply) { //查询打卡数据,计算人数之和 $arrived_num = DB::table('labor_reports') ->selectRaw("count( DISTINCT 'identity_number',identity_number) as num")//根据身份证号去重防止重复入组 ->where('user_workgroup_id', $laborApply->user_workgroup_id) ->whereDate('check_in_at', $check_in_at) ->where('online_duration', '>=', self::CALCULATION_ARRIVED_MAN_NUM_MIN_ONLINE_DURATION) ->first()->num; //更新申请表actual_num LaborApply::query() ->whereDate('created_at', deep_copy($apply_date)->toDateString()) ->where('user_workgroup_id', $laborApply->user_workgroup_id) ->update([ 'actual_num' => $arrived_num, 'status' => 4,//任务完结 ]); } //根据分配时间完结任务 $check_in_at:实际入场日期 就是 dispatch_date LaborCompanyDispatch::query() ->whereDate('dispatch_date', $check_in_at) ->update([ 'status' => 4//任务完结 ]); } /** * 将需要的工人 依次分配给劳务公司 不管劳务公司能否承担这个人 假设都分配给他(-1) 不能的标记一下不分配 能的就真分配 * @param $need_workers int 需要的人数 * @param array $laborCompanyDispatchInsertArray 插入的分配数据 * @param Collection $companies 劳务公司 * @param string $key 性别 man | woman */ private function dispatchWorker(int $need_workers, array &$laborCompanyDispatchInsertArray, Collection $companies, string $key) { while ($need_workers > 0) { foreach ($laborCompanyDispatchInsertArray as &$laborCompanyDispatchInsertItem) { if ($need_workers <= 0) continue; //当前 要分配到该劳务的男工数量 $current_worker_num = ($laborCompanyDispatchInsertItem[$key] ?? 0) + 1; //该劳务公司最大的分配人数 $company_can_apply_worker_num = $companies->find($laborCompanyDispatchInsertItem['labor_company_id'])[$key]; //超了 if ($current_worker_num > $company_can_apply_worker_num) { //设置状态为超量 $laborCompanyDispatchInsertItem['exceed_max_labor_num_status'] = LaborCompanyDispatch::EXCEED_MAX_LABOR_NUM; } else { //赋值给插入的数组 $laborCompanyDispatchInsertItem[$key] = $current_worker_num; } //需要分配的人数 -1 //不管人数超了还是没超 都要-1 $need_workers--; } unset($laborCompanyDispatchInsertItem); } } }