Order.php 11 KB

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