Product.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. <?php
  2. namespace app\admin\controller\store;
  3. use app\common\controller\AdminController;
  4. use app\http\IResponse;
  5. use think\Db;
  6. use Lettered\Support\Exceptions\EvidentException;
  7. use app\common\validate\IDMustBePositiveInt;
  8. class Product extends AdminController
  9. {
  10. /**
  11. * 新增规格
  12. *
  13. * @author 许祖兴 < zuxing.xu@lettered.cn>
  14. * @date 2020/6/19 17:08
  15. *
  16. * @return mixed
  17. * @throws \think\db\exception\DataNotFoundException
  18. * @throws \think\db\exception\ModelNotFoundException
  19. * @throws \think\exception\DbException
  20. */
  21. public function createSpec()
  22. {
  23. // 接收数据
  24. $params = $this->request->param();
  25. // 数据校验
  26. $valid = $this->validate($params,[
  27. 'name|规格名称' => 'require',
  28. ]);
  29. (true !== $valid) && IResponse::failure($valid);
  30. // 1. 存在性
  31. $model = model('common/GoodsSpec');
  32. if ($spec = $model->where(['spec_name' => $params['name']])->find())
  33. {
  34. //直接返回id
  35. return IResponse::success($spec);
  36. }
  37. // 不存在则新增
  38. return IResponse::success($model->create([
  39. 'spec_name' => $params['name']
  40. ],true));
  41. }
  42. /**
  43. * 新增规格属性
  44. *
  45. * @author 许祖兴 < zuxing.xu@lettered.cn>
  46. * @date 2020/6/19 17:10
  47. *
  48. * @return mixed
  49. * @throws \think\db\exception\DataNotFoundException
  50. * @throws \think\db\exception\ModelNotFoundException
  51. * @throws \think\exception\DbException
  52. */
  53. public function createSpecValue()
  54. {
  55. // 接收数据
  56. $params = $this->request->param();
  57. // 数据校验
  58. $valid = $this->validate($params,[
  59. 'spec_id|规格ID' => 'require',
  60. 'name|规格属性名称' => 'require',
  61. ]);
  62. (true !== $valid) && IResponse::failure($valid);
  63. // 1. 存在性
  64. $model = model('common/GoodsSpecValue');
  65. if ($value = $model->where(['spec_id' => $params['spec_id'],'value_name' => $params['name']])->find())
  66. {
  67. //直接返回id
  68. return IResponse::success($value);
  69. }
  70. // 不存在则新增
  71. return IResponse::success($model->create([
  72. 'spec_id' => $params['spec_id'],
  73. 'value_name' => $params['name']
  74. ],true));
  75. }
  76. /**
  77. * 取得商品规格
  78. *
  79. * @author 许祖兴 < zuxing.xu@lettered.cn>
  80. * @date 2020/6/19 17:00
  81. *
  82. * @param $id
  83. * @return mixed
  84. * @throws \think\db\exception\DataNotFoundException
  85. * @throws \think\db\exception\ModelNotFoundException
  86. * @throws \think\exception\DbException
  87. */
  88. public function getSkuById($id)
  89. {
  90. // 获取规格
  91. $skus = model('common/GoodsSku')
  92. ->where(['goods_id' => $id])
  93. ->select();
  94. $spec = [];
  95. $values = [];
  96. $ret = [];
  97. // 取出这个产品的SPEC SPEC_VALUE
  98. foreach ($skus as $sku) {
  99. $ret['sku'][] = [
  100. 'ids' => dejson($sku['spec_param']),
  101. 'price' => $sku['price'],
  102. 'pin_price' => $sku['pin_price'],
  103. 'instock_price' => $sku['instock_price'],
  104. 'stock' => $sku['stock'],
  105. ];
  106. foreach (dejson($sku['spec_param']) as $sp) {
  107. foreach ($sp as $sid => $vid) {
  108. $spec[] = model('GoodsSpec')->where(['id' => $sid])->find();
  109. $values[] = model('GoodsSpecValue')->where(['spec_id' => $sid, 'id' => $vid])->find();
  110. }
  111. }
  112. }
  113. // 构造
  114. foreach (array_unique($spec) as $s => $k) {
  115. $sub = [];
  116. foreach (array_unique($values) as $i => $v) {
  117. if ($v['spec_id'] == $k['id']) {
  118. $sub[] = [
  119. 'id' => $v['id'],
  120. 'name' => $v['value_name']
  121. ];
  122. }
  123. }
  124. $ret['spec'][] = [
  125. 'id' => $k['id'],
  126. 'name' => $k['spec_name'],
  127. 'sub' => $sub
  128. ];
  129. }
  130. return IResponse::success($ret);
  131. }
  132. /**
  133. * 获取商品信息
  134. *
  135. * @return mixed
  136. * @throws \think\exception\DbException
  137. */
  138. public function index()
  139. {
  140. $where = [];
  141. //组合搜索
  142. !empty(input('name')) && $where[]
  143. = ['name', 'like', '%' . input('name') . '%'];
  144. !empty(input('seller_id')) && $where[]
  145. = ['seller_id', 'eq', input('seller_id')];
  146. !empty(input('category_id')) && $where[]
  147. = ['category_id', 'eq', input('category_id')];
  148. !empty(input('area')) && $where[]
  149. = ['area_id', 'eq', input('area')];
  150. $product = model('common/Goods');
  151. return IResponse::paginate($product->where($where)->with(['category'])->order(['created_at' => 'desc'])
  152. ->paginate(input('limit'),false));
  153. }
  154. /**
  155. * 新增产品
  156. *
  157. * @return mixed
  158. */
  159. public function save()
  160. {
  161. // 接收数据
  162. $params = $this->request->param();
  163. // 数据校验
  164. $valid = $this->validate($params,[
  165. 'cover_img|产品主图' => 'require',
  166. 'name|产品名称' => 'require|unique:Goods',
  167. 'sku|产品规格' => 'require',
  168. 'is_pin|是否拼团' => 'require',
  169. 'pin_sum|拼团人数' => 'requireWith:is_pin',
  170. 'pin_number|成团人数' => 'requireWith:is_pin',
  171. 'content|产品详情' => 'require',
  172. 'sku| 商品规格参数' => 'require'
  173. ],[
  174. 'email.unique' => '重复产品名称!'
  175. ]);
  176. (true !== $valid) && IResponse::failure($valid);
  177. Db::startTrans();
  178. // 保存数据
  179. $goodsId = model('common/Goods')->storeBy($params);
  180. try {
  181. // sku处理
  182. $insku = dejson($params['sku']);
  183. //库存
  184. $stock = 0;
  185. foreach ($insku as &$sku){
  186. $sku['goods_id'] = $goodsId;
  187. $sku['spec_param'] = enjson($sku['ids']);
  188. $sku['param'] = enjson($sku['param']);
  189. $stock += $sku['stock'];
  190. model('common/GoodsSku')::create($sku,true);
  191. }
  192. if($stock == 0){
  193. throw new EvidentException([
  194. 'errmsg' => '当前商品库存不能未0!'
  195. ]);
  196. }
  197. // 进货价
  198. $iprice = array_column($insku, 'instock_price');
  199. sort($iprice);
  200. // 价格
  201. $price = array_column($insku, 'price');
  202. sort($price);
  203. // 拼团价格
  204. $pprice = array_column($insku, 'pin_price');
  205. sort($pprice);
  206. // 更新信息
  207. model('common/Goods')->updateBy($goodsId, [
  208. 'stock' => $stock,
  209. 'instock_price' => $iprice[0],
  210. 'price' => $price[0],
  211. 'pin_price' => $pprice[0]
  212. ]);
  213. Db::commit();
  214. }catch (\Exception $e){
  215. Db::rollback();
  216. }
  217. return $goodsId ? IResponse::success([],'新增产品成功'):
  218. IResponse::failure('新增产品异常');
  219. }
  220. /**
  221. * 更新产品信息
  222. *
  223. * @author 许祖兴 < zuxing.xu@lettered.cn>
  224. * @date 2020/7/2 22:13
  225. *
  226. * @param $id
  227. * @return mixed
  228. * @throws \think\Exception
  229. * @throws \think\exception\PDOException
  230. */
  231. public function update($id)
  232. {
  233. // 接收数据
  234. $params = $this->request->param();
  235. // 查询
  236. $goods = model('common/Goods')->findBy($id);
  237. // 是否更改状态操作
  238. if (isset($params['status']) && $params['status'] != '') {
  239. $valid = $this->validate($params, [
  240. 'status|配置状态' => 'require|integer'
  241. ]);
  242. }else {
  243. // 数据校验
  244. $valid = $this->validate($params, [
  245. 'cover_img|产品主图' => 'require',
  246. 'name|产品名称' => 'require|unique:Goods',
  247. 'sku|产品规格' => 'require',
  248. 'is_pin|是否拼团' => 'require',
  249. 'pin_sum|拼团人数' => 'requireWith:is_pin',
  250. 'pin_number|成团人数' => 'requireWith:is_pin',
  251. 'content|产品详情' => 'require',
  252. 'sku| 商品规格参数' => 'require'
  253. ]);
  254. }
  255. // 错误返回
  256. (true !== $valid) && IResponse::failure($valid);
  257. // 删除旧数据
  258. //TODO 模型方法有bug,等待优化
  259. $this->app->db()->name('goods_sku')->where(['goods_id' => $goods['id']])->delete();
  260. // sku处理
  261. $insku = dejson($params['sku']);
  262. $stock = 0;
  263. foreach ($insku as &$sku){
  264. $sku['goods_id'] = $goods['id'];
  265. $sku['spec_param'] = enjson($sku['ids']);
  266. $sku['param'] = enjson($sku['param']);
  267. $stock += $sku['stock'];
  268. model('common/GoodsSku')::create($sku,true);
  269. }
  270. if($stock == 0){
  271. throw new EvidentException([
  272. 'errmsg' => '当前商品库存不能未0!'
  273. ]);
  274. }
  275. // 库存
  276. $params['stock'] = $stock;
  277. // 进货价
  278. $iprice = array_column($insku, 'instock_price');
  279. sort($iprice);
  280. $params['instock_price'] = $iprice[0];
  281. // 价格
  282. $price = array_column($insku, 'price');
  283. sort($price);
  284. $params['price'] = $price[0];
  285. // 拼团价格
  286. $pprice = array_column($insku, 'pin_price');
  287. sort($pprice);
  288. $params['pin_price'] = $pprice[0];
  289. // 更新信息
  290. $goods->updateBy($id, $params);
  291. return IResponse::success('更新产品信息成功');
  292. }
  293. /**
  294. * 删除产品
  295. *
  296. * @param $id
  297. * @return \think\response\Json
  298. */
  299. public function delete($id)
  300. {
  301. model('common/Goods')->deleteBy($id);
  302. return IResponse::success([],'删除产品成功');
  303. }
  304. /*********************订单**********************/
  305. /**
  306. *
  307. * @return mixed
  308. * @throws \think\exception\DbException
  309. */
  310. public function order()
  311. {
  312. $where = [];
  313. //组合搜索
  314. !empty(input('name')) && $where[]
  315. = ['name', 'like', '%' . input('name') . '%'];
  316. (!empty(input('pin')) || input('pin') == '0') &&
  317. $where[] = ['is_pin', 'eq', input('pin')];
  318. (!empty(input('status')) || input('status') == '0') &&
  319. $where[] = ['status', 'eq', input('status')];
  320. !empty(input('area')) && $where[]
  321. = ['area_id', 'eq', input('area')];
  322. !empty(input('keywords')) && $where[]
  323. = ['user_id|order_no', 'like', '%' . input('keywords') . '%'];
  324. // 时间处理
  325. if (!empty(input('created_at'))){
  326. list($start, $end) = str2arr(input('created_at'),'-');
  327. $where[] = ['created_at', 'between', [strtotime($start), strtotime($end)]];
  328. }
  329. $order = model('common/GoodsOrder');
  330. return IResponse::paginate($order->where($where)->with(['user','seller','addr','detail'])
  331. ->order(['created_at' => 'desc'])
  332. ->paginate(input('limit'),false));
  333. }
  334. public function getOrderDetailById($id){
  335. (new IDMustBePositiveInt())->valid();
  336. //
  337. $order = model('common/GoodsOrderDetail');
  338. // TODO 商家要依据自己的ID查询
  339. return IResponse::paginate($order ->where(['order_id' => $id])
  340. ->order(['created_at' => 'desc'])
  341. ->paginate(input('limit'),false));
  342. }
  343. /**
  344. * 获取售后
  345. *
  346. * @author 许祖兴 < zuxing.xu@lettered.cn>
  347. * @date 2020/10/26 17:07
  348. *
  349. * @return \think\response\Json
  350. * @throws \think\exception\DbException
  351. */
  352. public function getOrderService(){
  353. $where = [];
  354. (!empty(input('status')) || input('status') == '0') &&
  355. $where[] = ['status', 'eq', input('status')];
  356. (!empty(input('action')) || input('action') == '0') &&
  357. $where[] = ['action', 'eq', input('action')];
  358. !empty(input('pay_type')) && $where[]
  359. = ['pay_type', 'eq', input('pay_type')];
  360. !empty(input('keywords')) && $where[]
  361. = ['user_id|order_id|mobile', 'like', '%' . input('keywords') . '%'];
  362. // 时间处理
  363. if (!empty(input('created_at'))){
  364. list($start, $end) = str2arr(input('created_at'),'-');
  365. $where[] = ['created_at', 'between', [strtotime($start), strtotime($end)]];
  366. }
  367. $service = model('common/GoodsOrderService')->with(['user','seller','order']);
  368. // TODO 商家要依据自己的ID查询
  369. return IResponse::paginate($service->where($where)->order(['created_at' => "desc"])
  370. ->paginate(input('limit'),false));
  371. }
  372. /**
  373. * 服务单处理
  374. *
  375. * @author 许祖兴 < zuxing.xu@lettered.cn>
  376. * @date 2020/10/26 18:16
  377. *
  378. * @param $id
  379. * @return \think\response\Json
  380. */
  381. public function actionServiceOrder($id)
  382. {
  383. $param = $this->request->param();
  384. $valid = $this->validate($param, [
  385. 'action|操作状态' => 'require'
  386. ]);
  387. // 错误返回
  388. (true !== $valid) && $this->ApiErr($valid);
  389. $model = model('common/GoodsOrderService');
  390. $service = $model->findBy($id);
  391. $msg = "操作";
  392. switch ($param['action']) {
  393. case "review":
  394. $msg = "审核订单";
  395. $model->updateBy($id, [
  396. 'status' => 3
  397. ]);
  398. $order = model('common/GoodsOrder')->findBy($service['order_id']);
  399. // 退钱
  400. model('common/Users')->changeBalance(
  401. $order['user_id'],
  402. $order['pay_price'],
  403. "售后订单退款",
  404. true);
  405. // 订单改服务状态
  406. model('common/GoodsOrder')->updateBy($order['id'], [
  407. 'in_service' => 2, // 已退款
  408. 'service_rec' => 1, // 标记售后
  409. // 'status' => 0 // 关闭
  410. ]);
  411. break;
  412. case "reject":
  413. $msg = "拒绝订单";
  414. $model->updateBy($id, [
  415. 'status' => 2
  416. ]);
  417. // 订单改服务状态
  418. model('common/GoodsOrder')->updateBy($id, [
  419. 'in_service' => 0
  420. ]);
  421. break;
  422. }
  423. return IResponse::success([],$msg . '成功');
  424. }
  425. /**
  426. *
  427. * @author 许祖兴 < zuxing.xu@lettered.cn>
  428. * @date 2020/7/15 15:59
  429. *
  430. * @return mixed
  431. */
  432. public function plectronOrder(){
  433. // 收参数
  434. $params = $this->request->param();
  435. foreach (str2arr($params['ids']) as $id){
  436. $user = model('common/GoodsOrder')->getBy($id);
  437. if ($this->request->isDelete()){
  438. $user->deleteBy($id);
  439. }
  440. $user->allowField(true)->updateBy($id, $params);
  441. }
  442. return IResponse::success([],'操作成功');
  443. }
  444. /**
  445. * 订单操作
  446. *
  447. * @author 许祖兴 < zuxing.xu@lettered.cn>
  448. * @date 2020/7/30 16:42
  449. *
  450. * @param $id
  451. * @return mixed
  452. * @throws \think\db\exception\DataNotFoundException
  453. * @throws \think\db\exception\ModelNotFoundException
  454. * @throws \think\exception\DbException
  455. * @throws \think\exception\PDOException
  456. */
  457. public function actionOrder($id)
  458. {
  459. $param = $this->request->param();
  460. $valid = $this->validate($param, [
  461. 'action|操作状态' => 'require'
  462. ]);
  463. // 查订单
  464. $order = model('common/GoodsOrder')->where(['id' => $id])->find();
  465. if ($order['status'] == 0){
  466. return IResponse::failure("当前订单已关闭");
  467. }
  468. // 错误返回
  469. (true !== $valid) && IResponse::failure($valid);
  470. $model = model('common/GoodsOrder');
  471. switch ($param['action']){
  472. case "ship":
  473. $msg = "发货";
  474. // 拦截确认过的订单
  475. if ($order['status'] >= 3){
  476. return IResponse::failure("当前订单已发货");
  477. }
  478. // 状态以及时间
  479. $model->updateBy($id,[
  480. 'shipping_at' => time(),
  481. 'status' => 3
  482. ]);
  483. break;
  484. case "confirm":
  485. $msg = "确认";
  486. // 拦截确认过的订单
  487. if ($order['status'] >= 4){
  488. return IResponse::failure("当前订单已确认");
  489. }
  490. // 查商品信息 取得商品进货价
  491. // 计算利润
  492. // 利润的百分几
  493. // 利润 count * ( total_price - instock )
  494. // 总利润
  495. $cgo_total = 0;
  496. // 子单明细
  497. $its = model('common/GoodsOrderDetail')->where(['order_id' => $order['id']])->select();
  498. foreach ($its as $itsv) {
  499. // 产品
  500. $goin = model('common/GoodsSku')->where(['goods_id' => $itsv['goods_id'],'param' => enjson(str2arr($itsv['spec'],','))])->value('instock_price');
  501. $cgo_total += sprintf("%.2f", round($itsv['total_price'] - $goin, 2));
  502. }
  503. // 奖励期权条件 -- 资产消费不得期权
  504. if ($order && $order['is_pin'] !== 1 && $order['pay_type'] !== 'property'){
  505. // 用户期权
  506. // order_property_reward
  507. $order_property_reward = sys_config('order_property_reward','store');
  508. // 计算 交易金额$order['total_price'] * order_property_reward //2020 12 09改为利润$cgo_total
  509. $reward = sprintf("%.3f", round(((float)$order_property_reward / 100) * $cgo_total, 3));
  510. if($reward > 0){// 更新
  511. model('common/Users')->changeProperty(
  512. $order['user_id'],
  513. $reward,
  514. '订单完成,奖励资产【' . $reward . "】",
  515. true
  516. );
  517. }
  518. }
  519. // 查找上级
  520. $parent = model('common/UsersInviteRelation')->getBy(['invite_id' => $order['user_id']]);
  521. // 上级推荐奖励
  522. if ($parent['form_id'] !== 0) {
  523. // 取得收益百分几
  524. $user_spread_reward_scale = sys_config('user_spread_reward_scale','user');
  525. // 计算收益
  526. $reward = sprintf("%.2f", round(((float)$user_spread_reward_scale / 100) * $cgo_total, 2));
  527. model('common/Users')->changeBalance(
  528. $parent['form_id'],
  529. $reward,
  530. "下级消费奖励,奖金【" . $reward .'】',
  531. true
  532. );
  533. }
  534. // 系统帮助用户自主确认订单
  535. $model->updateBy($id,[
  536. 'received_at' => time(),
  537. 'status' => 4
  538. ]);
  539. break;
  540. case "delete":
  541. $msg = "删除";
  542. $model->deleteBy($id);
  543. break;
  544. }
  545. return IResponse::success([],$msg . '成功');
  546. }
  547. /************ 分类 **********************/
  548. public function categories()
  549. {
  550. $where = [];
  551. //组合搜索
  552. $user = model('common/GoodsCategory');
  553. return IResponse::paginate($user->where($where)->order(['parent_id' => 'asc'])
  554. ->paginate(input('limit'),false));
  555. }
  556. /**
  557. * 新增分类
  558. *
  559. * @return mixed
  560. */
  561. public function category()
  562. {
  563. // 接收数据
  564. $params = $this->request->param();
  565. // 数据校验
  566. $valid = $this->validate($params,[
  567. 'name|产品分类' => 'require|unique:GoodsCategory',
  568. ],[
  569. 'email.unique' => '重复产品分类名称!'
  570. ]);
  571. (true !== $valid) && IResponse::failure($valid);
  572. // 保存数据
  573. $goodsId = model('common/GoodsCategory')->storeBy($params);
  574. return $goodsId ? IResponse::success([],'新增产品分类成功'):
  575. IResponse::failure('新增产品分类异常');
  576. }
  577. /**
  578. * 更新分类
  579. *
  580. * @return mixed
  581. */
  582. public function updateCategory($id)
  583. {
  584. // 接收数据
  585. $params = $this->request->param();
  586. // 查询
  587. $goods = model('common/GoodsCategory')->findBy($id);
  588. // 是否更改状态操作
  589. if (isset($params['status']) && $params['status'] != '') {
  590. $valid = $this->validate($params, [
  591. 'status|配置状态' => 'require|integer'
  592. ]);
  593. }else {
  594. // 数据校验
  595. $valid = $this->validate($params,[
  596. 'name|产品分类' => 'require',
  597. ]);
  598. }
  599. // 错误返回
  600. (true !== $valid) && IResponse::failure($valid);
  601. // 更新用户信息
  602. $goods->updateBy($id, $params);
  603. return IResponse::success('更新分类信息成功');
  604. }
  605. /**
  606. * 删除分类
  607. * @param $id
  608. *
  609. * @return mixed
  610. */
  611. public function deleteCategory($id)
  612. {
  613. model('common/GoodsCategory')->deleteBy($id);
  614. return IResponse::success([],'删除产品分类成功');
  615. }
  616. }