MerchantRepository.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. <?php
  2. namespace app\common\repositories\system\merchant;
  3. use app\common\dao\system\merchant\MerchantDao;
  4. use app\common\model\store\product\ProductReply;
  5. use app\common\repositories\BaseRepository;
  6. use app\common\repositories\store\product\ProductCopyRepository;
  7. use app\common\repositories\store\product\ProductRepository;
  8. use app\common\repositories\store\product\SpuRepository;
  9. use app\common\repositories\store\shipping\ShippingTemplateRepository;
  10. use app\common\repositories\store\StoreCategoryRepository;
  11. use app\common\repositories\system\attachment\AttachmentRepository;
  12. use app\common\repositories\user\UserBillRepository;
  13. use app\common\repositories\user\UserRelationRepository;
  14. use app\common\repositories\user\UserVisitRepository;
  15. use app\common\repositories\wechat\RoutineQrcodeRepository;
  16. use ln\jobs\ClearMerchantStoreJob;
  17. use ln\services\QrcodeService;
  18. use ln\services\UploadService;
  19. use ln\services\WechatService;
  20. use FormBuilder\Exception\FormBuilderException;
  21. use FormBuilder\Factory\Elm;
  22. use FormBuilder\Form;
  23. use think\db\exception\DataNotFoundException;
  24. use think\db\exception\DbException;
  25. use think\db\exception\ModelNotFoundException;
  26. use think\Exception;
  27. use think\exception\ValidateException;
  28. use think\facade\Db;
  29. use think\facade\Queue;
  30. use think\facade\Route;
  31. use think\Model;
  32. /**
  33. * Class MerchantRepository
  34. * @package app\common\repositories\system\merchant
  35. * @mixin MerchantDao
  36. * @author zfy
  37. * @day 2020-04-16
  38. */
  39. class MerchantRepository extends BaseRepository
  40. {
  41. /**
  42. * MerchantRepository constructor.
  43. * @param MerchantDao $dao
  44. */
  45. public function __construct(MerchantDao $dao)
  46. {
  47. $this->dao = $dao;
  48. }
  49. /**
  50. * @param array $where
  51. * @param $page
  52. * @param $limit
  53. * @return array
  54. * @throws DataNotFoundException
  55. * @throws DbException
  56. * @throws ModelNotFoundException
  57. * @author zfy
  58. * @day 2020-04-16
  59. */
  60. public function lst(array $where, $page, $limit)
  61. {
  62. $query = $this->dao->search($where);
  63. $count = $query->count($this->dao->getPk());
  64. $list = $query->page($page, $limit)->setOption('field', [])
  65. ->with([
  66. 'admin' => function ($query) {
  67. $query->field('mer_id,account');
  68. },
  69. 'merchantCategory',
  70. 'merchantType'
  71. ])
  72. ->field('sort, mer_id, mer_name, real_name, mer_phone, mer_address, mark, status, create_time,is_best,is_trader,type_id,category_id,copy_product_num,export_dump_num')->select();
  73. return compact('count', 'list');
  74. }
  75. public function count()
  76. {
  77. $valid = $this->dao->search(['status' => 1])->count();
  78. $invalid = $this->dao->search(['status' => 0])->count();
  79. return compact('valid', 'invalid');
  80. }
  81. /**
  82. * @param int|null $id
  83. * @param array $formData
  84. * @return Form
  85. * @throws FormBuilderException
  86. * @author zfy
  87. * @day 2020-04-16
  88. */
  89. public function form(?int $id = null, array $formData = [])
  90. {
  91. $form = Elm::createForm(is_null($id) ? Route::buildUrl('systemMerchantCreate')->build() : Route::buildUrl('systemMerchantUpdate', ['id' => $id])->build());
  92. /** @var MerchantCategoryRepository $make */
  93. $make = app()->make(MerchantCategoryRepository::class);
  94. $config = systemConfig(['broadcast_room_type', 'broadcast_goods_type']);
  95. $rule = [
  96. Elm::input('mer_name', '商户名称')->required(),
  97. Elm::select('category_id', '商户分类')->options(function () use ($make) {
  98. return $make->allOptions();
  99. })->requiredNum()->col(12),
  100. Elm::select('type_id', '店铺类型')->options(function () {
  101. $options = array_merge([['value' => 0, 'label' => '请选择']], app()->make(MerchantTypeRepository::class)->getOptions());
  102. return $options;
  103. })->requiredNum()->col(12),
  104. Elm::input('mer_account', '商户账号')->required()->disabled(!is_null($id))->required(!is_null($id)),
  105. Elm::password('mer_password', '登录密码')->required()->disabled(!is_null($id))->required(!is_null($id)),
  106. Elm::input('real_name', '商户姓名'),
  107. Elm::input('mer_phone', '商户手机号')->col(12)->required(),
  108. Elm::number('commission_rate', '手续费(%)')->col(12),
  109. Elm::input('mer_keyword', '商户关键字')->col(12),
  110. Elm::input('mer_address', '商户地址'),
  111. Elm::textarea('mark', '备注'),
  112. Elm::number('sort', '排序', 0),
  113. $id ? Elm::hidden('status', 1) : Elm::switches('status', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  114. Elm::switches('is_bro_room', '直播间审核', $config['broadcast_room_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  115. Elm::switches('is_audit', '产品审核', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  116. Elm::switches('is_bro_goods', '直播间商品审核', $config['broadcast_goods_type'] == 1 ? 0 : 1)->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  117. Elm::switches('is_best', '是否推荐')->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  118. Elm::switches('is_trader', '是否自营')->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  119. ];
  120. $form->setRule($rule);
  121. return $form->setTitle(is_null($id) ? '添加商户' : '编辑商户')->formData($formData);
  122. }
  123. /**
  124. * @param array $formData
  125. * @return Form
  126. * @throws FormBuilderException
  127. * @author zfy
  128. * @day 2020/6/25
  129. */
  130. public function merchantForm(array $formData = [])
  131. {
  132. $form = Elm::createForm(Route::buildUrl('merchantUpdate')->build());
  133. $rule = [
  134. Elm::textarea('mer_info', '店铺简介')->required(),
  135. Elm::input('service_phone', '服务电话')->required(),
  136. Elm::frameImage('mer_banner', '店铺Banner(710*200px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_banner&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]),
  137. Elm::frameImage('mer_avatar', '店铺头像(120*120px)', '/' . config('admin.merchant_prefix') . '/setting/uploadPicture?field=mer_avatar&type=1')->modal(['modal' => false])->width('896px')->height('480px')->props(['footer' => false]),
  138. Elm::switches('mer_state', '是否开启', 1)->activeValue(1)->inactiveValue(0)->inactiveText('关闭')->activeText('开启')->col(12),
  139. ];
  140. $form->setRule($rule);
  141. return $form->setTitle('编辑店铺信息')->formData($formData);
  142. }
  143. /**
  144. * @param $id
  145. * @return Form
  146. * @throws FormBuilderException
  147. * @throws DataNotFoundException
  148. * @throws DbException
  149. * @throws ModelNotFoundException
  150. * @author zfy
  151. * @day 2020-04-16
  152. */
  153. public function updateForm($id)
  154. {
  155. $data = $this->dao->get($id)->toArray();
  156. /** @var MerchantAdminRepository $make */
  157. $make = app()->make(MerchantAdminRepository::class);
  158. $data['mer_account'] = $make->merIdByAccount($id);
  159. $data['mer_password'] = '***********';
  160. return $this->form($id, $data);
  161. }
  162. /**
  163. * @param array $data
  164. * @author zfy
  165. * @day 2020-04-17
  166. */
  167. public function createMerchant(array $data)
  168. {
  169. if ($this->fieldExists('mer_name', $data['mer_name']))
  170. throw new ValidateException('商户名已存在');
  171. if ($data['mer_phone'] && isPhone($data['mer_phone']))
  172. throw new ValidateException('请输入正确的手机号');
  173. $merchantCategoryRepository = app()->make(MerchantCategoryRepository::class);
  174. $adminRepository = app()->make(MerchantAdminRepository::class);
  175. if (!$data['category_id'] || !$merchantCategoryRepository->exists($data['category_id']))
  176. throw new ValidateException('商户分类不存在');
  177. if ($adminRepository->fieldExists('account', $data['mer_account']))
  178. throw new ValidateException('账号已存在');
  179. /** @var MerchantAdminRepository $make */
  180. $make = app()->make(MerchantAdminRepository::class);
  181. return Db::transaction(function () use ($data, $make) {
  182. $account = $data['mer_account'];
  183. $password = $data['mer_password'];
  184. unset($data['mer_account'], $data['mer_password']);
  185. $merchant = $this->dao->create($data);
  186. $make->createMerchantAccount($merchant, $account, $password);
  187. app()->make(ShippingTemplateRepository::class)->createDefault($merchant->mer_id);
  188. app()->make(ProductCopyRepository::class)->defaulCopyNum($merchant->mer_id);
  189. return $merchant;
  190. });
  191. }
  192. /**
  193. * @Author:Qinii
  194. * @Date: 2020/5/30
  195. * @param $where
  196. * @param $page
  197. * @param $limit
  198. * @return array
  199. */
  200. public function getList($where, $page, $limit, $userInfo)
  201. {
  202. $where['status'] = 1;
  203. $where['mer_state'] = 1;
  204. $where['is_del'] = 0;
  205. if (isset($where['location'])) {
  206. $data = @explode(',', (string)$where['location']);
  207. if (2 != count(array_filter($data ?: []))) {
  208. unset($where['location']);
  209. } else {
  210. $where['location'] = [
  211. 'lat' => (float)$data[0],
  212. 'long' => (float)$data[1],
  213. ];
  214. }
  215. }
  216. if ($where['keyword'] !== '') {
  217. app()->make(UserVisitRepository::class)->searchMerchant($userInfo ? $userInfo['uid'] : 0, $where['keyword']);
  218. }
  219. $query = $this->dao->search($where)->with(['showProduct']);
  220. $count = $query->count($this->dao->getPk());
  221. $status = systemConfig('mer_location');
  222. $list = $query->page($page, $limit)->setOption('field', [])->field('care_count,is_trader,type_id,mer_id,mer_banner,mini_banner,mer_name, mark,mer_avatar,product_score,service_score,postage_score,sales,status,is_best,create_time,long,lat')
  223. ->with(['type_name'])->select()->each(function ($item) use ($status, $where) {
  224. $data = $item->showProduct->toArray();
  225. unset($item->showProduct);
  226. $recommend = array_slice($data, 0, 3);
  227. if ($status && $item['lat'] && $item['long'] && isset($where['location']['lat'], $where['location']['long'])) {
  228. $distance = getDistance($where['location']['lat'], $where['location']['long'], $item['lat'], $item['long']);
  229. if ($distance < 0.9) {
  230. $distance = max(bcmul($distance, 1000, 0), 1) . 'm';
  231. } else {
  232. $distance .= 'km';
  233. }
  234. $item['distance'] = $distance;
  235. }
  236. return $item['recommend'] = $recommend;
  237. });
  238. return compact('count', 'list');
  239. }
  240. /**
  241. * @Author:Qinii
  242. * @Date: 2020/5/30
  243. * @param int $id
  244. * @return array|Model|null
  245. */
  246. public function merExists(int $id)
  247. {
  248. return ($this->dao->get($id));
  249. }
  250. /**
  251. * @Author:Qinii
  252. * @Date: 2020/5/30
  253. * @param $id
  254. * @param $userInfo
  255. * @return array|Model|null
  256. */
  257. public function detail($id, $userInfo)
  258. {
  259. $merchant = $this->dao->apiGetOne($id)->hidden(["real_name", "mer_phone", "reg_admin_id", "sort", "is_del", "is_audit", "is_best", "mer_state", "bank", "bank_number", "bank_name", 'update_time',
  260. 'financial_alipay', 'financial_bank', 'financial_wechat', 'financial_type']);
  261. $merchant->append(['type_name', 'isset_certificate']);
  262. $merchant['care'] = false;
  263. if ($userInfo)
  264. $merchant['care'] = $this->getCareByUser($id, $userInfo->uid);
  265. return $merchant;
  266. }
  267. /**
  268. * @Author:Qinii
  269. * @Date: 2020/5/30
  270. * @param int $merId
  271. * @param int $userId
  272. * @return bool
  273. */
  274. public function getCareByUser(int $merId, int $userId)
  275. {
  276. if (app()->make(UserRelationRepository::class)->getWhere(['type' => 10, 'type_id' => $merId, 'uid' => $userId]))
  277. return true;
  278. return false;
  279. }
  280. /**
  281. * @Author:Qinii
  282. * @Date: 2020/5/30
  283. * @param $merId
  284. * @param $where
  285. * @param $page
  286. * @param $limit
  287. * @param $userInfo
  288. * @return mixed
  289. */
  290. public function productList($merId, $where, $page, $limit, $userInfo)
  291. {
  292. return app()->make(ProductRepository::class)->getApiSearch($merId, $where, $page, $limit, $userInfo);
  293. }
  294. /**
  295. * @Author:Qinii
  296. * @Date: 2020/5/30
  297. * @param int $id
  298. * @return mixed
  299. */
  300. public function categoryList(int $id)
  301. {
  302. return app()->make(StoreCategoryRepository::class)->getApiFormatList($id, 1);
  303. }
  304. public function wxQrcode($merId)
  305. {
  306. $siteUrl = systemConfig('site_url');
  307. $name = md5('mwx' . $merId . date('Ymd')) . '.jpg';
  308. $attachmentRepository = app()->make(AttachmentRepository::class);
  309. $imageInfo = $attachmentRepository->getWhere(['attachment_name' => $name]);
  310. if (isset($imageInfo['attachment_src']) && strstr($imageInfo['attachment_src'], 'http') !== false && curl_file_exist($imageInfo['attachment_src']) === false) {
  311. $imageInfo->delete();
  312. $imageInfo = null;
  313. }
  314. if (!$imageInfo) {
  315. $codeUrl = rtrim($siteUrl, '/') . '/pages/store/home/index?id=' . $merId;//二维码链接
  316. if (systemConfig('open_wechat_share')) {
  317. $qrcode = WechatService::create(false)->qrcodeService();
  318. $codeUrl = $qrcode->forever('_scan_url_mer_' . $merId)->url;
  319. }
  320. $imageInfo = app()->make(QrcodeService::class)->getQRCodePath($codeUrl, $name);
  321. if (is_string($imageInfo)) throw new ValidateException('二维码生成失败');
  322. $imageInfo['dir'] = tidy_url($imageInfo['dir'], null, $siteUrl);
  323. $attachmentRepository->create(systemConfig('upload_type') ?: 1, -2, $merId, [
  324. 'attachment_category_id' => 0,
  325. 'attachment_name' => $imageInfo['name'],
  326. 'attachment_src' => $imageInfo['dir']
  327. ]);
  328. $urlCode = $imageInfo['dir'];
  329. } else $urlCode = $imageInfo['attachment_src'];
  330. return $urlCode;
  331. }
  332. public function routineQrcode($merId)
  333. {
  334. $name = md5('smrt' . $merId . date('Ymd')) . '.jpg';
  335. return tidy_url(app()->make(QrcodeService::class)->getRoutineQrcodePath($name, 'pages/store/home/index', 'id=' . $merId), 0);
  336. }
  337. public function copyForm(int $id)
  338. {
  339. $form = Elm::createForm(Route::buildUrl('systemMerchantChangeCopy', ['id' => $id])->build());
  340. $form->setRule([
  341. Elm::input('copy_num', '复制次数', $this->dao->getCopyNum($id))->disabled(true)->readonly(true),
  342. Elm::radio('type', '修改类型', 1)
  343. ->setOptions([
  344. ['value' => 1, 'label' => '增加'],
  345. ['value' => 2, 'label' => '减少'],
  346. ]),
  347. Elm::number('num', '修改数量', 0)->required()
  348. ]);
  349. return $form->setTitle('修改复制商品次数');
  350. }
  351. public function delete($id)
  352. {
  353. Db::transaction(function () use ($id) {
  354. $this->dao->update($id, ['is_del' => 1]);
  355. app()->make(MerchantAdminRepository::class)->deleteMer($id);
  356. Queue::push(ClearMerchantStoreJob::class,['mer_id' => $id]);
  357. });
  358. }
  359. /**
  360. * TODO 清理删除商户但没有删除的商品数据
  361. * @author Qinii
  362. * @day 5/15/21
  363. */
  364. public function clearRedundancy()
  365. {
  366. $ret = $this->dao->search(['is_del' => 1])->value('mer_id');
  367. try{
  368. foreach ($ret as $mer_id){
  369. app()->make(ProductRepository::class)->clearMerchantProduct($mer_id);
  370. }
  371. }catch(\Exception $exception) {
  372. throw new ValidateException($exception->getMessage());
  373. }
  374. }
  375. public function addLockMoney(int $merId, string $orderType, int $orderId, float $money)
  376. {
  377. if ($money <= 0) return;
  378. if (systemConfig('mer_lock_time')) {
  379. app()->make(UserBillRepository::class)->incBill($merId, 'mer_lock_money', $orderType, [
  380. 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId,
  381. 'mer_id' => $merId,
  382. 'status' => 0,
  383. 'title' => '商户佣金冻结',
  384. 'number' => $money,
  385. 'mark' => '冻结商户佣金',
  386. 'balance' => 0
  387. ]);
  388. } else {
  389. $this->dao->addMoney($merId, $money);
  390. }
  391. }
  392. public function checkCrmebNum(int $merId,string $type)
  393. {
  394. $merchant = $this->dao->get($merId);
  395. switch ($type){
  396. case 'copy':
  397. if(!systemConfig('copy_product_status')){
  398. throw new ValidateException('复制商品未开启');
  399. }
  400. if(!$merchant['copy_product_num']){
  401. throw new ValidateException('复制商品剩余次数不足');
  402. }
  403. break;
  404. case 'dump':
  405. if(!systemConfig('crmeb_serve_dump')){
  406. throw new ValidateException('电子面单未开启');
  407. }
  408. if(!$merchant['export_dump_num']){
  409. throw new ValidateException('电子面单剩余次数不足');
  410. }
  411. break;
  412. }
  413. return true;
  414. }
  415. public function subLockMoney(int $merId, string $orderType, int $orderId, float $money)
  416. {
  417. if ($money <= 0) return;
  418. $make = app()->make(UserBillRepository::class);
  419. $bill = $make->search(['category' => 'mer_lock_money', 'type' => $orderType, 'mer_id' => $merId, 'link_id' => $orderId, 'status' => 0])->find();
  420. if (!$bill) {
  421. $this->dao->subMoney($merId, $money);
  422. } else {
  423. $make->decBill($merId, 'mer_refund_money', $orderType, [
  424. 'link_id' => ($orderType === 'order' ? 1 : 2) . $orderId,
  425. 'mer_id' => $merId,
  426. 'status' => 1,
  427. 'title' => '商户佣金冻结退款',
  428. 'number' => $money,
  429. 'mark' => '冻结商户佣金退款',
  430. 'balance' => 0
  431. ]);
  432. }
  433. }
  434. }