LaborApplyService.php 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. namespace App\Services;
  3. use App\LaborCompany;
  4. use App\LaborCompanyDispatch;
  5. use App\Traits\ServiceAppAop;
  6. use App\LaborApply;
  7. use App\Warehouse;
  8. use Illuminate\Database\Eloquent\Builder;
  9. use Illuminate\Database\Eloquent\Collection;
  10. use Illuminate\Support\Carbon;
  11. use Illuminate\Support\Facades\Cache;
  12. use Illuminate\Support\Facades\DB;
  13. use function DeepCopy\deep_copy;
  14. class LaborApplyService
  15. {
  16. //超时时间 默认为19:00
  17. const TIME_OUT_HOUR = 19;
  18. const LABOR_APPLY_STATUS = 'LABOR_APPLY_STATUS';
  19. const LABOR_APPLY_STATUS_TTL = 60 * 30;
  20. //到岗日期是申请日期的前一天 为保证数据正确 计算实际人数的时间为到岗日期的后一天 故时间为2
  21. const CALCULATION_ARRIVED_MAN_NUM_DEFAULT_SUB_DAYS = 2;
  22. //临时工工作时长最小值 低于这个时间的不计入
  23. const CALCULATION_ARRIVED_MAN_NUM_MIN_ONLINE_DURATION = 1;
  24. use ServiceAppAop;
  25. protected $modelClass = LaborApply::class;
  26. /**
  27. * 获取预约开放状态
  28. *
  29. * @return int 1 开放 2 禁止 3 临时开放
  30. */
  31. public function getCanCreateStatus(): int
  32. {
  33. $can_create_status = (now()->lte(now()->startOfDay()->addHours(self::TIME_OUT_HOUR))) ? LaborApply::CAN_CREATE_STATUS_OPEN : LaborApply::CAN_CREATE_STATUS_FORBID;
  34. if (Cache::has(self::LABOR_APPLY_STATUS)) {
  35. $can_create_status = Cache::get(self::LABOR_APPLY_STATUS);
  36. }
  37. return $can_create_status;
  38. }
  39. /**
  40. * 设置预约开放状态 1 开放 2 禁止 3 临时开放
  41. * @param int $status
  42. */
  43. public function setCanCreateStatus(int $status)
  44. {
  45. Cache::put(self::LABOR_APPLY_STATUS, $status, self::LABOR_APPLY_STATUS_TTL);
  46. }
  47. /**
  48. * 生产劳务派遣报表
  49. *
  50. * 查询全部仓库
  51. * 遍历仓库
  52. * 按照仓库,查询当日的的申请,将申请的男女工分别加和
  53. * 按照仓库查询对应的劳务所 按照优先级排序
  54. * 将男女工之和依次分配到 劳务所
  55. * 如果分配完成后 发现还有剩下的 则将状态设置为2
  56. */
  57. public function allocationLaborToLaborCompany(): array
  58. {
  59. //当前时间小于 1.00 禁止生成数据
  60. if (now()->lte(now()->startOfDay()->addHours(1))) return ['success' => false, 'error_message' => '当前时间禁止生成临时工派遣数据'];
  61. //派遣日期 为报表生成日期的后一天
  62. $dispatch_date = now()->addDay()->startOfDay()->toDateTimeString();
  63. //接口幂等性,删除旧的数据
  64. LaborCompanyDispatch::query()->where('dispatch_date', $dispatch_date)->delete();
  65. //查询全部仓库
  66. $warehouses = Warehouse::all();
  67. //给每个仓库计算分配数据 更改申请状态为指派成功
  68. foreach ($warehouses as $warehouse) {
  69. //查询当日的的申请,将申请的男女工分别加和
  70. $apply_man_nums = DB::table('labor_applies')
  71. ->selectRaw("sum(man_num) as man_num ,sum(woman_num) as woman_num")
  72. ->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()])
  73. ->where('warehouse_id', $warehouse->id)
  74. ->groupBy('warehouse_id')
  75. ->first();
  76. if (empty($apply_man_nums)) continue;
  77. //按照仓库查询对应的劳务所 按照优先级排序 单号正序 双号逆序
  78. $companies = $this->getCompaniesOrderByDay($warehouse);
  79. //需要的男工人数
  80. $man_num = $apply_man_nums->man_num;
  81. //需要的女工人数
  82. $woman_num = $apply_man_nums->woman_num;
  83. //插入的分配数据
  84. $laborCompanyDispatchInsertArray = $this->buildLaborCompanyDispatchInsertArray($companies, $man_num, $woman_num, $dispatch_date);
  85. //插入分配数据
  86. LaborCompanyDispatch::query()->insert($laborCompanyDispatchInsertArray);
  87. LaborApply::query()
  88. ->whereBetween('created_at', [now()->startOfDay(), now()->endOfDay()])
  89. ->where('warehouse_id', $warehouse->id)
  90. ->update([
  91. 'status' => 2,//指派成功
  92. ]);
  93. }
  94. return ['success' => true, 'message' => '生成临时工派遣数据成功'];
  95. }
  96. /**
  97. * 设置为状态为溢出
  98. * @param array $laborCompanyAppliesTarget
  99. * @return array
  100. */
  101. private function setExceedMaxLaborNumStatusExceedMaxLaborNum(array $laborCompanyAppliesTarget): array
  102. {
  103. return array_map(function (&$item) {
  104. $item['exceed_max_labor_num_status'] = LaborCompanyDispatch::EXCEED_MAX_LABOR_NUM;
  105. return $item;
  106. }, $laborCompanyAppliesTarget);
  107. }
  108. /**
  109. * 构建插入的分配数据
  110. * @param $companies
  111. * @param $man_num
  112. * @param $woman_num
  113. * @param string $dispatch_date
  114. * @return array
  115. */
  116. private function buildLaborCompanyDispatchInsertArray($companies, $man_num, $woman_num, string $dispatch_date): array
  117. {
  118. $laborCompanyDispatchInsertArray = [];
  119. //遍历劳务公司
  120. foreach ($companies as $company) {
  121. if ($man_num > 0 || $woman_num > 0) {
  122. //分配给指定劳务的男工人数
  123. $dispatch_man_num = $man_num > $company->man_num ? $company->man_num : $man_num;
  124. //分配给指定劳务的女工人数
  125. $dispatch_woman_num = $woman_num > $company->woman_num ? $company->woman_num : $woman_num;
  126. //待分配的男工
  127. $man_num -= $dispatch_man_num;
  128. //待分配的女工
  129. $woman_num -= $dispatch_woman_num;
  130. $laborCompanyDispatchInsertArray[] = [
  131. 'labor_company_id' => $company->id,
  132. 'man_num' => $dispatch_man_num,
  133. 'woman_num' => $dispatch_woman_num,
  134. 'dispatch_date' => $dispatch_date,
  135. 'exceed_max_labor_num_status' => LaborCompanyDispatch::NOT_EXCEED_MAX_LABOR_NUM,//没有超限额
  136. 'status' => 1,//创建
  137. ];
  138. }
  139. }
  140. //全部劳务公司分配完后 还有剩余的男工/女工
  141. if ($man_num > 0 || $woman_num > 0) {
  142. //设置状态为超额
  143. $laborCompanyDispatchInsertArray = $this->setExceedMaxLaborNumStatusExceedMaxLaborNum($laborCompanyDispatchInsertArray);
  144. }
  145. return $laborCompanyDispatchInsertArray;
  146. }
  147. /**
  148. * 按照仓库查询对应的劳务所 按照优先级排序 单号正序 双号逆序
  149. * @param $warehouse
  150. * @return Builder[]|Collection
  151. */
  152. private function getCompaniesOrderByDay($warehouse)
  153. {
  154. $builder = LaborCompany::query()
  155. ->where('warehouse_id', $warehouse->id);
  156. if (now()->day % 2 === 0) {
  157. $builder->orderBy('priority');
  158. } else {
  159. $builder->orderBy('priority', 'desc');
  160. }
  161. return $builder->get();
  162. }
  163. /**
  164. * 按照给定的申请日期计算到岗人数
  165. *
  166. * 查询指定日期的 每个小组的申请人数
  167. * 遍历申请数据
  168. * 根据申请数据的仓库小组id,日期(申请日期后一天)查询打卡数据,计算人数之和 更新申请表actual_num
  169. * @param Carbon|null $apply_date
  170. */
  171. public function calculationArrivedManNum(Carbon $apply_date = null)
  172. {
  173. //查询的申请日期
  174. if (empty($apply_date)) {
  175. $apply_date = now()->subDays(self::CALCULATION_ARRIVED_MAN_NUM_DEFAULT_SUB_DAYS);
  176. }
  177. //查询指定日期的 每个小组的申请人数
  178. $laborApplies = DB::table('labor_applies')
  179. ->selectRaw('user_workgroup_id as user_workgroup_id , sum(man_num + woman_num) as apply_num , warehouse_id')
  180. ->whereDate('created_at', $apply_date->toDateString())
  181. ->groupBy('user_workgroup_id','warehouse_id')
  182. ->get();
  183. //根据申请数据的仓库小组id,日期(申请日期后一天)
  184. $check_in_at = deep_copy($apply_date)->addDay()->toDateString();
  185. //遍历申请数据
  186. foreach ($laborApplies as $laborApply) {
  187. //查询打卡数据,计算人数之和
  188. $arrived_num =
  189. DB::table('labor_reports')
  190. ->selectRaw("count( DISTINCT 'identity_number',identity_number) as num")//根据身份证号去重防止重复入组
  191. ->where('user_workgroup_id', $laborApply->user_workgroup_id)
  192. ->whereDate('check_in_at', $check_in_at)
  193. ->where('online_duration', '>=', self::CALCULATION_ARRIVED_MAN_NUM_MIN_ONLINE_DURATION)
  194. ->first()->num;
  195. //更新申请表actual_num
  196. LaborApply::query()
  197. ->whereDate('created_at', deep_copy($apply_date)->toDateString())
  198. ->where('user_workgroup_id', $laborApply->user_workgroup_id)
  199. ->update([
  200. 'actual_num' => $arrived_num,
  201. 'status' => 4,//任务完结
  202. ]);
  203. }
  204. //根据分配时间完结任务 $check_in_at:实际入场日期 就是 dispatch_date
  205. LaborCompanyDispatch::query()
  206. ->whereDate('dispatch_date', $check_in_at)
  207. ->update([
  208. 'status' => 3//任务完结
  209. ]);
  210. }
  211. }