Order.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. <?php
  2. namespace app\controller\api;
  3. use app\extra\basic\Base;
  4. use app\extra\jhfPay\Pay;
  5. use app\extra\tools\CodeExtend;
  6. use app\middleware\WxMiddleware;
  7. use app\model\saas\SaasCart;
  8. use app\model\saas\SaasDiscount;
  9. use app\model\saas\SaasOrder;
  10. use app\model\saas\SaasOrderDetail;
  11. use app\model\saas\SaasPrintClient;
  12. use app\model\saas\SaasShop;
  13. use app\model\saas\SaasUser;
  14. use app\model\saas\SaasUserBuy;
  15. use app\model\saas\SaasUserLog;
  16. use LinFly\Annotation\Route\Controller;
  17. use LinFly\Annotation\Route\Middleware;
  18. use LinFly\Annotation\Route\Route;
  19. use support\Request;
  20. use support\Response;
  21. use think\facade\Db;
  22. #[Controller(prefix: "/wx_api/order"),Middleware(WxMiddleware::class)]
  23. class Order extends Base
  24. {
  25. protected array $noNeedLogin = [];
  26. protected array $types = [
  27. '1_1_1' => ['name' => '彩色-单面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  28. '1_2_1' => ['name' => '彩色-双面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  29. '2_1_1' => ['name' => '黑白-单面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  30. '2_2_1' => ['name' => '黑白-双面', 'amount' => 0, 'quantity' => 0,'discount' => 0],
  31. ];
  32. protected array $color = ["1" => "彩色", "2" => "黑白"];
  33. protected array $duplex = ["1" => "单面", "2" => "双面"];
  34. protected array $package = ["1" => "店内打印", "2" => '远程自取' , "3" => "商家配送"];
  35. #[Route(path: "list",methods: "get")]
  36. public function getOrderList(Request $request): Response
  37. {
  38. try {
  39. $param = $this->_valid([
  40. "page.require" => "参数错误",
  41. "size.require" => "参数错误",
  42. "type.require" => "参数错误",
  43. "shop.require" => "请选择店铺"
  44. ]);
  45. if (!is_array($param)) return error($param);
  46. $map = ["openid" => $request->user['openid'],"shop_id" => $param['shop']];
  47. $model = (new SaasOrder);
  48. if ($param['type'] > 0) {
  49. $map['status'] = $param['type'] - 1;
  50. } else {
  51. $model = $model->where("status",">",0);
  52. }
  53. $resp = $model->where($map)->append(["total"])->with(['shop' => function($query){
  54. $query->field('shop_id,shop_name');
  55. }])->withAttr(["total" => function($val,$resp){
  56. return (new SaasOrderDetail)->where("order_sn",$resp['order_sn'])->sum("number");
  57. }])->order("create_at desc")->paginate([
  58. "list_rows" => $param['size'],
  59. "page" => $param['page']
  60. ]);
  61. return success("ok",$resp->toArray());
  62. } catch (\Throwable $throwable) {
  63. return error($throwable->getMessage());
  64. }
  65. }
  66. /**
  67. * 订单详情
  68. * @param Request $request
  69. * @return Response
  70. */
  71. #[Route(path: "detail",methods: "get")]
  72. public function getOrderDetail(Request $request): Response
  73. {
  74. try {
  75. $param = $this->_valid([
  76. "order.require" => "参数错误"
  77. ]);
  78. if (!is_array($param)) return error($param);
  79. $resp = (new SaasOrder)->where("openid",$request->user['openid'])->where("order_sn",$param['order'])->append(["total","subscribe"])->with(['shop' => function($query){
  80. $query->field('shop_id,shop_name,shop_address');
  81. },"detail" => function($query){
  82. $query->field('order_sn,name,color,paper_size,duplex,number,page,extension,path,icon');
  83. }])->withAttr(["total" => function($val,$resp){
  84. return (new SaasOrderDetail)->where("order_sn",$resp['order_sn'])->sum("number");
  85. },"subscribe" => function(){
  86. return ["495E40hqOKoz5j_mWcf-UcmF6wkj_yIwCrTXicicH5w","UXJjDQ7NGstSwOxrKf_laGDmpID8Mm5MpXwFAd45d8U"];
  87. }])->findOrEmpty();
  88. if ($resp->isEmpty()) return error("订单数据错误");
  89. $resp['package_name'] = $this->package[$resp['package']];
  90. $resp['money'] = format_money($resp['money'] / 100);
  91. return success("ok",$resp->toArray());
  92. } catch (\Throwable $throwable) {
  93. return error($throwable->getMessage());
  94. }
  95. }
  96. /**
  97. * @param Request $request
  98. * @return Response
  99. */
  100. #[Route(path: "create",methods: "post")]
  101. public function createOrder(Request $request): Response
  102. {
  103. try {
  104. $param = $this->_valid([
  105. "shop.require" => trans("empty.require"),
  106. "print.require" => trans("empty.require"),
  107. "pay.require" => trans("empty.require"), // 1微信支付 2会员卡支付 3会员卡充值并支付
  108. "printName.default" => "",
  109. "express.require" => trans("empty.require"),
  110. "card.default" => "",
  111. "gift.default" => 0
  112. ],$request->method());
  113. if (!is_array($param)) return error($param);
  114. $cart = (new SaasCart)->where("shop_id",$param['shop'])->where("print_id",$param['print'])->where("openid",$request->user['openid'])->order("create_at desc")->select();
  115. if ($cart->isEmpty()) return error('请重新下单进行支付');
  116. $totalAmount = $totalDiscount = 0;
  117. foreach ($cart as $k=>$v){
  118. $key = $v['color'] . '_' . $v['duplex'] . '_' . $v['source'];
  119. if (isset($this->types[$key])) {
  120. $this->types[$key]['quantity'] += $v['page'];
  121. $this->types[$key]['amount'] += $v['money'];
  122. }
  123. $cart[$k] = $v;
  124. $cart[$k]['money'] = format_money($v['money'] / 100,2);
  125. $cart[$k]['name'] = msubstr($v['name'],0,12);
  126. }
  127. $printData = (new SaasPrintClient)->where("shop_id",$param['shop'])->where("code",$param['print'])->select();
  128. if ($printData->isEmpty()) return error('无可用打印机');
  129. // 计算折扣
  130. foreach ($this->types as $k=>$v) {
  131. $discount = (new SaasDiscount)->where("shop_id",$param['shop'])->where("keys",$k)->where("number",'<',$v['quantity'])->findOrEmpty();
  132. if (!$discount->isEmpty()) {
  133. $v['discount'] = round($v['amount'] * $discount['rate']);
  134. $this->types[$k]['discount'] = $v['discount'];
  135. }
  136. $totalAmount += $v['amount']; // 实际金额
  137. $totalDiscount += $v['discount']; // 折扣后金额
  138. }
  139. $orderSn = CodeExtend::uniqidDate(16).date("is").rand(1,9);
  140. $totalDay = (new SaasOrder)->where("shop_id",$param['shop'])->whereDay("create_at")->count();
  141. $orderData = [
  142. "shop_id" => $param['shop'], // 所属店铺
  143. "parent_id" => $param['shop'], // 消费店铺
  144. "openid" => $request->user['openid'],
  145. "order_sn" => $orderSn,
  146. "money" => $totalAmount,
  147. "discount" => $totalDiscount==0?$totalAmount:$totalDiscount, // 跟原价相等无折扣
  148. "print_name" => $param['printName'],
  149. "print_id" => $param['print'],
  150. "package" => $param['express'],
  151. "package_sn" => date('md')."-".sprintf("%02d",($totalDay+1)),
  152. "extra_money" => 0,
  153. "remark" => $param['remark']??''
  154. ];
  155. $shop = (new SaasShop)->where("shop_id",$param['shop'])->findOrEmpty();
  156. if ($param['pay'] == 2) { // 会员卡支付
  157. $card = (new SaasUser)->where("openid",$request->user['openid'])->where("shop_id",$param['shop'])->findOrEmpty();
  158. $payMoney = $totalDiscount > 0 ? $totalDiscount : $totalAmount;
  159. if ($payMoney >= $card['balance']) {
  160. return error("卡内余额不足~");
  161. }
  162. // 直接支付
  163. $card->balance = ($card['balance'] - $payMoney);
  164. $card->total_consume = ($card['total_consume'] + $payMoney);
  165. $card->save();
  166. $orderData['pay_type'] = 2;
  167. $orderData['status'] = 1;
  168. $orderData['pay_at'] = getDateFull();
  169. (new SaasOrder)->insertGetId($orderData);
  170. (new SaasUserLog)->insertGetId([
  171. "openid" => $request->user['openid'],
  172. "shop_id" => $param['shop'],
  173. "order_sn" => $orderSn,
  174. "money" => $payMoney,
  175. "card_no" => strtoupper(md5($request->user['openid'].$param['shop'])),
  176. "type" => 1,
  177. "balance" => $card['balance'] - $payMoney,
  178. ]);
  179. events("create-order",['shop' => $param['shop'],'print' => $param['print'],'openid' => $request->user['openid'],"order" => $orderSn]);
  180. return success("支付成功",['type' => 2,'data' => []]);
  181. }
  182. $options = [
  183. 'body' => "{$shop['shop_name']}-{$param['printName']}",
  184. 'out_trade_no' => $orderSn."-".$orderData['package_sn'],
  185. "attach" => $orderSn,
  186. 'total_fee' => $orderData['money'],
  187. 'openid' => $request->user['openid'],
  188. 'trade_type' => 'JSAPI',
  189. 'spbill_create_ip' => $request->getRealIp(),
  190. "notify_url" => "https://panel.huiyinduo.cn/notify/wx"
  191. ];
  192. if ($orderData['money'] <= 0) {
  193. return error("数据变动请重新上传再下单");
  194. }
  195. if ($param['pay'] == 3 && !empty($param['card'])) { // 开通会员卡并充值
  196. $buyCard = json_decode($param['card'],true);
  197. (new SaasUserBuy)->insertGetId([
  198. "shop_id" => $param['shop'],
  199. "money" => $buyCard['money'] * 100,
  200. "total_money" => ($buyCard['money'] * 100) + ($buyCard['old_money'] * 100),
  201. "order_sn" => $orderSn,
  202. "openid" => $request->user['openid'],
  203. "card_no" => strtoupper(md5($request->user['openid'].$param['shop']))
  204. ]);
  205. $options['body'] = $shop['shop_name']."-充值支付";
  206. $options['total_fee'] = $buyCard['money'] * 100;
  207. $options['notify_url'] = "https://panel.huiyinduo.cn/notify/recharge";
  208. }
  209. (new SaasOrder)->insertGetId($orderData);
  210. $param_data["order_no"] = $orderSn;
  211. $param_data["app_id"] = sConf("wechat.jhf_appid");
  212. $param_data["pay_channel"] = "wx_lite";
  213. $param_data["pay_amt"] = format_money($options['total_fee'] / 100 , 2);
  214. $param_data["goods_title"] = $options['body'];
  215. $param_data["device_info"] = array("device_ip" => $request->getRealIp());
  216. $param_data['notify_url'] = $options['notify_url'];
  217. $param_data["expend"] = [
  218. "wx_app_id" => sConf("wechat.mini_appid"),
  219. "open_id" => $request->user['openid']
  220. ];
  221. $respJhf = (new Pay)->config([
  222. "appid" => sConf("wechat.jhf_appid"),
  223. "mch_id" => sConf("wechat.jhf_mch_id"),
  224. "aeskey" => sConf("wechat.jhf_aeskey"),
  225. "pubkey" => sConf("wechat.jhf_pubkey"),
  226. "prikey" => sConf("wechat.jhf_prikey"),
  227. ])->createPay($param_data);
  228. // $wechat = new \WeChat\Pay($this->getWxConfig());
  229. // // 生成预支付码
  230. // echo getDateFull()."生成支付二维码\n";
  231. // print_r($options);
  232. // $result = $wechat->createOrder($options);
  233. if (isset($respJhf['code'])) {
  234. return error("发起支付失败");
  235. }
  236. // 创建JSAPI参数签名
  237. $resp = json_decode($respJhf['expend']['pay_info'],true);
  238. $resp['timestamp'] = $resp['timeStamp'];
  239. return success("ok",['type' => 1,"data" => $resp]);
  240. } catch (\Throwable $throwable) {
  241. echo $throwable->getLine()."\n";
  242. echo $throwable->getFile()."\n";
  243. return error($throwable->getMessage());
  244. }
  245. }
  246. /**
  247. * 小程序配置
  248. * @return array
  249. */
  250. protected function getWxConfig(): array
  251. {
  252. return [
  253. 'token' => 'test',
  254. 'appid' => sConf("wechat.mini_appid"),
  255. 'appsecret' => sConf("wechat.mini_secret"),
  256. 'encodingaeskey' => 'BJIUzE0gqlWy0GxfPp4J1oPTBmOrNDIGPNav1YFH5Z5',
  257. // 配置商户支付参数(可选,在使用支付功能时需要)
  258. 'mch_id' => sConf("wechat.mch_id"),
  259. 'mch_key' => sConf("wechat.mch_key")
  260. ];
  261. }
  262. }