AgentApply.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. <?php
  2. namespace app\common\Service\commission;
  3. use app\common\model\commission\Apply as ApplyModel;
  4. use app\common\model\commission\Identity as IdentityModel;
  5. use app\common\model\commission\Agent as AgentModel;
  6. use app\common\model\Area;
  7. use app\common\Service\ShopConfigService;
  8. use app\common\Enum\AgentType;
  9. use think\Db;
  10. use think\Exception;
  11. class AgentApply
  12. {
  13. /**
  14. * 获取可用的代理商身份列表
  15. */
  16. public function getIdentityList()
  17. {
  18. return IdentityModel::getEnabledList();
  19. }
  20. /**
  21. * 提交代理商申请
  22. */
  23. public function submitApply($userId, $data)
  24. {
  25. // 验证用户是否已经有申请记录
  26. $existApply = ApplyModel::where('user_id', $userId)
  27. ->where('status', 'in', ['pending', 'approved'])
  28. ->find();
  29. if ($existApply) {
  30. if ($existApply->status == 'approved') {
  31. throw new Exception('您已经是代理商,无需重复申请');
  32. } else {
  33. throw new Exception('您已有待审核的申请,请等待审核结果');
  34. }
  35. }
  36. // 验证身份是否存在
  37. $identity = IdentityModel::where('id', $data['agent_identity_id'])
  38. ->where('status', IdentityModel::STATUS_ENABLED)
  39. ->find();
  40. if (!$identity) {
  41. throw new Exception('选择的代理商身份不存在或已禁用');
  42. }
  43. // 验证地区信息
  44. $this->validateArea($data);
  45. // 根据申请类型验证必要字段
  46. $this->validateApplyData($data);
  47. return Db::transaction(function () use ($userId, $data, $identity) {
  48. // 创建申请记录
  49. $apply = new ApplyModel();
  50. $apply->user_id = $userId;
  51. $apply->apply_type = $data['apply_type'];
  52. $apply->agent_identity_id = $data['agent_identity_id'];
  53. $apply->agent_type = $identity->agent_type; // 从身份配置获取代理商类型
  54. $apply->status = ApplyModel::STATUS_PENDING; // 设置初始状态为待审核
  55. // 地区信息 - 根据代理商类型设置需要的地区字段并查询名称
  56. $requiredFields = AgentType::getRequiredAreaFields($identity->agent_type);
  57. if (in_array('province_id', $requiredFields)) {
  58. $apply->province_id = $data['province_id'] ?? null;
  59. // 主动查询省份名称
  60. if (!empty($data['province_id'])) {
  61. $province = Area::where('id', $data['province_id'])->where('level', 1)->find();
  62. $apply->province_name = $province ? $province->name : '';
  63. } else {
  64. $apply->province_name = '';
  65. }
  66. }
  67. if (in_array('city_id', $requiredFields)) {
  68. $apply->city_id = $data['city_id'] ?? null;
  69. // 主动查询城市名称
  70. if (!empty($data['city_id'])) {
  71. $city = Area::where('id', $data['city_id'])->where('level', 2)->find();
  72. $apply->city_name = $city ? $city->name : '';
  73. } else {
  74. $apply->city_name = '';
  75. }
  76. }
  77. if (in_array('district_id', $requiredFields)) {
  78. $apply->district_id = $data['district_id'] ?? null;
  79. // 主动查询区域名称
  80. if (!empty($data['district_id'])) {
  81. $district = Area::where('id', $data['district_id'])->where('level', 3)->find();
  82. $apply->district_name = $district ? $district->name : '';
  83. } else {
  84. $apply->district_name = '';
  85. }
  86. }
  87. // 根据申请类型填充对应字段
  88. if ($data['apply_type'] == ApplyModel::APPLY_TYPE_PERSONAL) {
  89. $apply->real_name = $data['real_name'];
  90. $apply->id_card = $data['id_card'];
  91. $apply->id_card_front = $data['id_card_front'];
  92. $apply->id_card_back = $data['id_card_back'];
  93. $apply->mobile = $data['mobile'];
  94. } else {
  95. $apply->company_name = $data['company_name'];
  96. $apply->legal_person = $data['legal_person'];
  97. $apply->legal_mobile = $data['legal_mobile'];
  98. $apply->legal_id_card = $data['legal_id_card'];
  99. $apply->legal_id_front = $data['legal_id_front'];
  100. $apply->legal_id_back = $data['legal_id_back'];
  101. $apply->business_license = $data['business_license'];
  102. }
  103. $apply->save();
  104. // 检查是否需要审核
  105. $needCheck = ShopConfigService::getConfigField('shop.commission.agent_apply_check');
  106. if (!$needCheck) {
  107. // 不需要审核,直接通过
  108. $this->approveApply($apply);
  109. }
  110. return $apply;
  111. });
  112. }
  113. /**
  114. * 验证地区信息
  115. */
  116. private function validateArea($data)
  117. {
  118. // 获取代理商身份信息
  119. $identity = IdentityModel::where('id', $data['agent_identity_id'])
  120. ->where('status', IdentityModel::STATUS_ENABLED)
  121. ->find();
  122. if (!$identity) {
  123. throw new Exception('代理商身份不存在');
  124. }
  125. // 根据代理商类型获取需要的地区字段
  126. $requiredFields = AgentType::getRequiredAreaFields($identity->agent_type);
  127. if (empty($requiredFields)) {
  128. // 普通代理商不需要地区信息
  129. return;
  130. }
  131. // 验证必需的地区字段
  132. foreach ($requiredFields as $field) {
  133. if (empty($data[$field])) {
  134. $fieldTexts = [
  135. 'province_id' => '省份',
  136. 'city_id' => '城市',
  137. 'district_id' => '区域'
  138. ];
  139. throw new Exception($fieldTexts[$field] . '不能为空');
  140. }
  141. }
  142. // 验证地区ID的有效性和层级关系
  143. $this->validateAreaIds($data, $requiredFields);
  144. }
  145. /**
  146. * 验证地区ID的有效性和层级关系
  147. */
  148. private function validateAreaIds($data, $requiredFields)
  149. {
  150. // 验证省份
  151. if (in_array('province_id', $requiredFields) && !empty($data['province_id'])) {
  152. $province = Area::where('id', $data['province_id'])->where('level', 1)->find();
  153. if (!$province) {
  154. throw new Exception('选择的省份不存在');
  155. }
  156. }
  157. // 验证城市
  158. if (in_array('city_id', $requiredFields) && !empty($data['city_id'])) {
  159. $city = Area::where('id', $data['city_id'])->where('level', 2)->find();
  160. if (!$city) {
  161. throw new Exception('选择的城市不存在');
  162. }
  163. // 验证城市是否属于选择的省份
  164. if (!empty($data['province_id']) && $city->pid != $data['province_id']) {
  165. throw new Exception('选择的城市不属于该省份');
  166. }
  167. }
  168. // 验证区域
  169. if (in_array('district_id', $requiredFields) && !empty($data['district_id'])) {
  170. $district = Area::where('id', $data['district_id'])->where('level', 3)->find();
  171. if (!$district) {
  172. throw new Exception('选择的区域不存在');
  173. }
  174. // 验证区域是否属于选择的城市
  175. if (!empty($data['city_id']) && $district->pid != $data['city_id']) {
  176. throw new Exception('选择的区域不属于该城市');
  177. }
  178. }
  179. }
  180. /**
  181. * 验证申请数据
  182. */
  183. private function validateApplyData($data)
  184. {
  185. if ($data['apply_type'] == ApplyModel::APPLY_TYPE_PERSONAL) {
  186. $requiredFields = ['real_name', 'id_card', 'id_card_front', 'id_card_back', 'mobile'];
  187. foreach ($requiredFields as $field) {
  188. if (empty($data[$field])) {
  189. throw new Exception('个人申请信息不完整');
  190. }
  191. }
  192. // 验证身份证格式
  193. if (!$this->validateIdCard($data['id_card'])) {
  194. throw new Exception('身份证号格式不正确');
  195. }
  196. } else {
  197. $requiredFields = ['company_name', 'legal_person', 'legal_mobile', 'legal_id_card', 'legal_id_front', 'legal_id_back', 'business_license'];
  198. foreach ($requiredFields as $field) {
  199. if (empty($data[$field])) {
  200. throw new Exception('企业申请信息不完整');
  201. }
  202. }
  203. // 验证法人身份证格式
  204. if (!$this->validateIdCard($data['legal_id_card'])) {
  205. throw new Exception('法人身份证号格式不正确');
  206. }
  207. }
  208. }
  209. /**
  210. * 验证身份证号格式
  211. */
  212. private function validateIdCard($idCard)
  213. {
  214. return preg_match('/^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/', $idCard);
  215. }
  216. /**
  217. * 审核通过申请
  218. */
  219. public function approveApply(ApplyModel $apply, $adminId = null)
  220. {
  221. return Db::transaction(function () use ($apply, $adminId) {
  222. // 更新申请状态
  223. $apply->status = ApplyModel::STATUS_APPROVED;
  224. $apply->admin_id = $adminId;
  225. $apply->audit_time = time();
  226. $apply->save();
  227. // 创建代理商记录
  228. $this->createAgentFromApply($apply);
  229. return $apply;
  230. });
  231. }
  232. /**
  233. * 审核拒绝申请
  234. */
  235. public function rejectApply(ApplyModel $apply, $reason, $adminId = null)
  236. {
  237. $apply->status = ApplyModel::STATUS_REJECTED;
  238. $apply->reject_reason = $reason;
  239. $apply->admin_id = $adminId;
  240. $apply->audit_time = time();
  241. return $apply->save();
  242. }
  243. /**
  244. * 根据申请信息创建代理商
  245. */
  246. private function createAgentFromApply(ApplyModel $apply)
  247. {
  248. // 检查用户是否已经是分销商
  249. $existAgent = AgentModel::where('user_id', $apply->user_id)->find();
  250. if ($existAgent) {
  251. return $existAgent;
  252. }
  253. // 获取身份信息
  254. $identity = IdentityModel::where('id', $apply->agent_identity_id)->find();
  255. // 创建分销商记录
  256. $agent = new AgentModel();
  257. $agent->user_id = $apply->user_id;
  258. $agent->level = 1; // 默认等级
  259. $agent->agent_type = $apply->agent_type;
  260. $agent->status = AgentModel::AGENT_STATUS_NORMAL;
  261. $agent->become_time = time();
  262. // 如果是区域代理商(省级、市级、区域级),设置管辖区域(包括ID和名称)
  263. if (AgentType::isRegionalAgent($apply->agent_type)) {
  264. // 根据代理商类型设置对应的管辖区域
  265. if ($apply->agent_type == AgentType::PROVINCE && !empty($apply->province_id)) {
  266. $agent->manage_province_id = $apply->province_id;
  267. $agent->manage_province_name = $apply->province_name;
  268. } elseif ($apply->agent_type == AgentType::CITY) {
  269. if (!empty($apply->province_id)) {
  270. $agent->manage_province_id = $apply->province_id;
  271. $agent->manage_province_name = $apply->province_name;
  272. }
  273. if (!empty($apply->city_id)) {
  274. $agent->manage_city_id = $apply->city_id;
  275. $agent->manage_city_name = $apply->city_name;
  276. }
  277. } elseif ($apply->agent_type == AgentType::DISTRICT) {
  278. if (!empty($apply->province_id)) {
  279. $agent->manage_province_id = $apply->province_id;
  280. $agent->manage_province_name = $apply->province_name;
  281. }
  282. if (!empty($apply->city_id)) {
  283. $agent->manage_city_id = $apply->city_id;
  284. $agent->manage_city_name = $apply->city_name;
  285. }
  286. if (!empty($apply->district_id)) {
  287. $agent->manage_district_id = $apply->district_id;
  288. $agent->manage_district_name = $apply->district_name;
  289. }
  290. }
  291. }
  292. // 生成唯一邀请码
  293. $agent->invite_code = $this->generateInviteCode();
  294. $agent->save();
  295. return $agent;
  296. }
  297. /**
  298. * 生成唯一邀请码
  299. * @return string
  300. */
  301. private function generateInviteCode()
  302. {
  303. $maxAttempts = 3; // 最大尝试次数
  304. $attempts = 0;
  305. do {
  306. // 使用通用的generate_code方法生成基础码
  307. $letters = 'ABCDEFGHJKLMNPQRSTUVWXYZ3456789';
  308. $shuffleStr = str_shuffle($letters);
  309. $code = substr($shuffleStr, 0, 6);
  310. // 检查代理商表中是否已存在
  311. $exists = AgentModel::where('invite_code', $code)->find();
  312. $attempts++;
  313. if (!$exists) {
  314. return $code;
  315. }
  316. } while ($attempts < $maxAttempts);
  317. // 如果3次尝试都失败,使用时间戳后缀确保唯一性
  318. $fallbackLetters = 'ABCDEFGHJKLMNPQRSTUVWXYZ3456789';
  319. $fallbackCode = substr(str_shuffle($fallbackLetters), 0, 4) . substr(time(), -2);
  320. return $fallbackCode;
  321. }
  322. /**
  323. * 获取用户的申请记录
  324. */
  325. public function getUserApply($userId)
  326. {
  327. return ApplyModel::where('user_id', $userId)
  328. ->with(['identity', 'province', 'city', 'district'])
  329. ->order('id desc')
  330. ->find();
  331. }
  332. }