| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- <?php
- namespace App\Services;
- use App\LaborCompany;
- use App\LaborCompanyDispatch;
- use App\Traits\ServiceAppAop;
- use App\LaborApply;
- use App\Warehouse;
- use Illuminate\Database\Eloquent\Builder;
- use Illuminate\Database\Eloquent\Collection;
- use Illuminate\Support\Carbon;
- use Illuminate\Support\Facades\Cache;
- use Illuminate\Support\Facades\DB;
- use function DeepCopy\deep_copy;
- class LaborApplyService
- {
- //超时时间 默认为19:00
- const TIME_OUT_HOUR = 18;
- const LABOR_APPLY_STATUS = 'LABOR_APPLY_STATUS';
- //上次次临时工申请分配的时间
- const LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT = 'LATELY_LABOR_COMPANY_DISPATCH_CREATED_AT';
- const LABOR_APPLY_STATUS_TTL = 60 * 30;
- //到岗日期是申请日期的前一天 为保证数据正确 计算实际人数的时间为到岗日期的后一天 故时间为2
- const CALCULATION_ARRIVED_MAN_NUM_DEFAULT_SUB_DAYS = 2;
- //临时工工作时长最小值 低于这个时间的不计入
- const CALCULATION_ARRIVED_MAN_NUM_MIN_ONLINE_DURATION = 1;
- use ServiceAppAop;
- protected $modelClass = LaborApply::class;
- /**
- * 获取预约开放状态
- *
- * @return int 1 开放 2 禁止 3 临时开放
- */
- public function getCanCreateStatus(): int
- {
- $can_create_status = (now()->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);
- }
- }
- }
|