WaterAgentManagement.php 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. <?php
  2. declare(strict_types=1);
  3. namespace plugin\saiadmin\app\service;
  4. use plugin\saiadmin\app\model\water\{WaterModel,WaterAgent,WaterOperator,WaterLedger};
  5. use plugin\saiadmin\app\service\agent\AgentHierarchyPolicy;
  6. use plugin\saiadmin\exception\ApiException;
  7. /** Transactional archive/account commands. Opening an account never assigns roles or global data access. */
  8. final class WaterAgentManagement
  9. {
  10. public function save(array $input,int $actor): array {
  11. return WaterModel::transaction(function () use ($input,$actor) {
  12. // Serialize hierarchy changes so concurrent reparenting cannot introduce cycles.
  13. $agents=WaterAgent::query()->orderBy('id')->lockForUpdate()->get(['id','parent_id','status'])->toArray();
  14. $id=WaterBusiness::positive($input['id']??0,'代理ID',true);
  15. if (array_key_exists('parent_id',$input)) {
  16. $parent=$input['parent_id']===null?null:WaterBusiness::positive($input['parent_id'],'上级代理',true);
  17. (new AgentHierarchyPolicy())->validate($agents,$id?:-1,$parent);
  18. }
  19. $result=(new WaterBusiness())->save('agent',$input,$actor);
  20. if (array_key_exists('parent_id',$input)) WaterAgent::query()->where('id',$result['id'])->update(['parent_id'=>$parent]);
  21. return $result;
  22. });
  23. }
  24. public function openAccount(array $input,int $actor): array {
  25. if ($actor!==1) throw new ApiException('仅超级管理员可开通代理登录账号',403);
  26. $username=$input['username']??''; $password=$input['password']??'';
  27. if (!is_string($username)||!preg_match('/^[A-Za-z0-9_.-]{3,64}$/D',$username)) throw new ApiException('登录账号须为3至64位字母、数字、点、下划线或短横线');
  28. if (!is_string($password)||strlen($password)<8||strlen($password)>72) throw new ApiException('密码须为8至72字节');
  29. return WaterModel::transaction(function () use ($input,$actor,$username,$password) {
  30. // Lock root operator to serialize new usernames across this opening workflow.
  31. WaterOperator::query()->where('id',1)->lockForUpdate()->first();
  32. if (WaterOperator::query()->where('username',$username)->exists()) throw new ApiException('登录账号已存在');
  33. $id=WaterBusiness::positive($input['id']??0,'代理ID',true);
  34. if ($id) {
  35. $agent=WaterAgent::query()->where('id',$id)->lockForUpdate()->first();
  36. if (!$agent) throw new ApiException('代理不存在');
  37. if ($agent->user_id) throw new ApiException('该代理已有关联账号,请勿重复开通');
  38. } else {
  39. $id=$this->save($input,$actor)['id'];
  40. $agent=WaterAgent::query()->findOrFail($id);
  41. }
  42. if (mb_strlen($agent->phone)>20 || mb_strlen($agent->contact)>64) throw new ApiException('账号联系电话不可超过20字,联系人不可超过64字');
  43. $now=date('Y-m-d H:i:s');
  44. $user=WaterOperator::query()->create(['username'=>$username,'password'=>password_hash($password,PASSWORD_DEFAULT),
  45. 'realname'=>$agent->contact,'phone'=>$agent->phone,'dept_id'=>null,'is_super'=>0,'status'=>1,
  46. 'remark'=>'供水代理待授权账号','created_by'=>$actor,'updated_by'=>$actor,'create_time'=>$now,'update_time'=>$now]);
  47. $agent->user_id=$user->id; $agent->updated_at=$now; $agent->save();
  48. WaterLedger::query()->create(['kind'=>'archive','created_by'=>$actor,'sku_id'=>0,'enterprise_id'=>0,'quantity'=>0,
  49. 'reference'=>'agent:'.$id,'note'=>'开通代理登录账号,待分配角色;user_id='.$user->id,'created_at'=>$now]);
  50. return ['id'=>$id,'user_id'=>(int)$user->id,'authorization'=>'pending'];
  51. });
  52. }
  53. }