CloudPrint.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\utils;
  8. use app\models\Cloud;
  9. use app\models\CloudSetting;
  10. use app\models\Goods;
  11. use app\models\Order;
  12. use app\models\OrderDetail;
  13. use app\models\PtActivityOrder;
  14. use app\models\PtActivityOrderDetail;
  15. /**
  16. * 云打印
  17. * Class CloudPrint
  18. * @package app\utils
  19. */
  20. class CloudPrint
  21. {
  22. /**
  23. * TODO: 后续补充
  24. * @var array
  25. * 订单类型 0--普通订单 1--秒杀订单 2--拼团订单 3--砍价订单
  26. */
  27. private static $validType = [0, 1, 2, 3];
  28. /**
  29. * 下单时云打印订单
  30. * @param $order_id
  31. * @param $order_type
  32. * @param int $store_id
  33. */
  34. public static function doPrint($order_id, $order_type, $store_id = 1)
  35. {
  36. try {
  37. if (empty($order_id) || !in_array($order_type, self::$validType)) {
  38. \Yii::warning(['CLOUD PRINT NOT VALID, PARAMS: ', [$order_id, $order_type, $store_id]]);
  39. return;
  40. }
  41. switch ($order_type) {
  42. case 0:
  43. $order_info = Order::find()->select(['is_pay','mch_id','order_no','created_at','total_price', 'name',
  44. 'mobile', 'address', 'pay_price'])->where(['id' => $order_id])->asArray()->one();
  45. $order_detail_list = OrderDetail::find()
  46. ->alias('o')
  47. ->where(['o.order_id' => $order_id])
  48. ->select('o.goods_id,o.total_price,o.attr as o_attr,o.num,o.goods_id,o.order_id')
  49. ->asArray()
  50. ->all();
  51. break;
  52. case 1:
  53. $order_info = MsOrder::find()->select(['is_pay','mch_id','order_no','created_at','total_price', 'name',
  54. 'mobile', 'address', 'pay_price'])->where(['id' => $order_id])->asArray()->one();
  55. $order_detail_list = MsOrder::find()
  56. ->alias('o')
  57. ->where(['o.order_id' => $order_id])
  58. ->select('o.goods_id,o.total_price,o.attr as o_attr,o.num,o.goods_id,o.order_id')
  59. ->asArray()
  60. ->all();
  61. break;
  62. case 2:
  63. $order_info = PtActivityOrder::find()->select(['is_pay','store_id','order_no','created_at','total_price', 'name',
  64. 'mobile', 'address', 'pay_price'])->where(['id' => $order_id])->asArray()->one();
  65. $order_detail_list = PtActivityOrderDetail::find()
  66. ->alias('o')
  67. ->where(['o.order_id' => $order_id])
  68. ->select('o.goods_id,o.total_price,o.attr as o_attr,o.num,o.goods_id,o.order_id')
  69. ->asArray()
  70. ->all();
  71. break;
  72. case 3:
  73. $order_info = BargainOrder::find()->select(['is_pay','mch_id','order_no','created_at','total_price', 'name',
  74. 'mobile', 'address', 'pay_price'])->where(['id' => $order_id])->asArray()->one();
  75. $order_detail_list = BargainOrderDetail::find()
  76. ->alias('o')
  77. ->where(['o.order_id' => $order_id])
  78. ->select('o.goods_id,o.total_price,o.attr as o_attr,o.num,o.goods_id,o.order_id')
  79. ->asArray()
  80. ->all();
  81. break;
  82. default:
  83. return;
  84. break;
  85. }
  86. if($order_info['is_pay'] == 1){
  87. $order_info['is_pay'] = '已支付';
  88. }else{
  89. $order_info['is_pay'] = '货到付款';
  90. }
  91. $mch_id = $order_info['mch_id'];
  92. // 查询订单下单时是否开启打印
  93. $cloud_on = CloudSetting::find()->select(['type', 'cloud_id'])->where(['store_id' => $store_id,
  94. 'mch_id' => $mch_id,'is_delete' => 0])->asArray()->one();
  95. if (empty($cloud_on)) {
  96. return;
  97. }
  98. $is_res = json_decode($cloud_on['type']);
  99. $is_on = $is_res->pay;
  100. if ($is_on == 1 && $order_info['is_pay'] == 1) {
  101. foreach($order_detail_list as & $arr1){
  102. $g_id = $arr1['goods_id'];
  103. if ($order_type == 1) {
  104. $g_info = MsGoods::find()->alias('g')->where(['id' => $g_id])->select(['g.id','g.name',
  105. 'g.unit','g.price','g.attr'])->asArray()->one();
  106. } else if ($order_type == 2) {
  107. $g_info = PtGoods::find()->alias('g')->where(['id' => $g_id])->select(['g.id','g.name',
  108. 'g.unit','g.price','g.attr'])->asArray()->one();
  109. } else if ($order_type == 3) {
  110. $g_info = BargainGoods::find()->alias('g')->where(['id' => $g_id])->select(['g.id','g.name',
  111. 'g.unit','g.price','g.attr'])->asArray()->one();
  112. } else {
  113. $g_info = Goods::find()->alias('g')->where(['id' => $g_id])->select(['g.id','g.name','g.unit',
  114. 'g.price','g.attr'])->asArray()->one();
  115. }
  116. $arr1['id'] = $g_info['id'];
  117. $arr1['name'] = $g_info['name'];
  118. $arr1['unit'] = $g_info['unit'];
  119. $arr1['price'] = $g_info['price'];
  120. $arr1['attr'] = $g_info['attr'];
  121. }
  122. $cloud_id = $cloud_on['cloud_id'];
  123. $setting = Cloud::find()->select(['cloud_setting'])->where(['id' => $cloud_id])->asArray()->one();
  124. $setting_json = json_decode($setting['cloud_setting']);
  125. $send_html = self::createHtml($setting_json, $order_info, $order_detail_list, $order_type);
  126. // 抓取设置的云打印机参数
  127. if ($order_info['total_price'] > $setting_json->minimoney) {
  128. $name = $setting_json->name;
  129. $app_id = $setting_json->app_id;
  130. $app_key = $setting_json->app_key;
  131. $time_stamp = time();
  132. $sign = md5('app_id=' . $app_id . '&sign_type=MD5&time_stamp=' . $time_stamp . '&key=' . $app_key);
  133. $sign = strtoupper($sign);
  134. $token = self::getToken($sign,$app_id,$time_stamp);
  135. $token_arr = json_decode($token,true);
  136. $token = $token_arr['return_data']['access_token'];
  137. $cus_order_id = time().rand(100,999);
  138. //初始化
  139. $curl = curl_init();
  140. //设置抓取的ur
  141. curl_setopt($curl, CURLOPT_URL, 'https://mcp.jolimark.com/mcp/v3/sys/PrintRichHtmlCode');
  142. //设置头文件的信息作为数据流输出
  143. curl_setopt($curl, CURLOPT_HEADER, 1);
  144. //设置获取的信息以文件流的形式返回,而不是直接输出。
  145. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  146. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
  147. //设置post方式提交
  148. curl_setopt($curl, CURLOPT_POST, 1);
  149. //设置post数据
  150. $post_data = array(
  151. "app_id" => $app_id,
  152. "access_token" => $token,
  153. "device_ids" => $name,
  154. "copies" => 1,
  155. "cus_orderid" => $cus_order_id,
  156. "bill_content" => $send_html,
  157. "paper_type" => 1,
  158. );
  159. // post提交的数据
  160. curl_setopt($curl, CURLOPT_POSTFIELDS, $post_data);
  161. // 执行命令
  162. curl_exec($curl);
  163. curl_close($curl);
  164. }
  165. }
  166. } catch (\Throwable $e) {
  167. \Yii::warning($e->getMessage());
  168. }
  169. }
  170. /**
  171. * @param $attrStr
  172. * @param $searchAttrIds
  173. * @return bool
  174. */
  175. public static function getNo($attrStr, $searchAttrIds){
  176. $attr = json_decode($attrStr,true);
  177. foreach ($attr as $item){
  178. $attrIds = array_column($item, 'attr_id');
  179. if ($attrIds == $searchAttrIds){
  180. return $item['no'];
  181. }
  182. }
  183. return false;
  184. }
  185. /**
  186. * @param $setting_json
  187. * @param $order_info
  188. * @param $order_detail_list
  189. * @param $order_type
  190. * @return string
  191. */
  192. public static function createHtml($setting_json, $order_info, $order_detail_list, $order_type)
  193. {
  194. $order_title = $setting_json->order_title;
  195. $order_address = $setting_json->order_address;
  196. $order_mobile = $setting_json->order_mobile;
  197. $order_desc = $setting_json->order_desc;
  198. $no = 0;
  199. $order_count_price = 0;
  200. foreach ($order_detail_list as & $arr) {
  201. $no = $no + 1;
  202. $push_arr = [];
  203. $search = $arr['o_attr'];
  204. $search_arr = json_decode($search, true);
  205. foreach ($search_arr as & $vv) {
  206. array_push($push_arr, $vv['attr_id']);
  207. }
  208. $arr['no'] = self::getNo($arr['o_attr'], $push_arr);
  209. $g_id = $arr['goods_id'];
  210. $order_id = $arr['order_id'];
  211. if ($order_type == 1) {
  212. $g_info_attr = MsOrder::find()->where(['is_delete' => 0,'order_id' => $order_id,'goods_id' => $g_id])
  213. ->select(['attr'])->asArray()->one();
  214. } else if ($order_type == 2) {
  215. $g_info_attr = PtOrderDetail::find()->where(['is_delete' => 0,'order_id' => $order_id,'goods_id' => $g_id])
  216. ->select(['attr'])->asArray()->one();
  217. } else if ($order_type == 3) {
  218. $g_info_attr = BargainOrderDetail::find()->where(['is_delete' => 0,'order_id' => $order_id,'goods_id' => $g_id])
  219. ->select(['attr'])->asArray()->one();
  220. } else {
  221. $g_info_attr = OrderDetail::find()->where(['is_delete' => 0,'order_id' => $order_id,'goods_id' => $g_id])
  222. ->select(['attr'])->asArray()->one();
  223. }
  224. $attr_list = json_decode($g_info_attr['attr']);
  225. if (is_array($attr_list)){
  226. foreach ($attr_list as $attr){
  227. $attr_str=$attr->attr_group_name.":".$attr->attr_name;
  228. }
  229. }
  230. $tr2 = "<tr>
  231. <td class='fontsize20 text-cont style='font-size: 23px'>" . $no . "</td>"
  232. . "<td style='height: 45px;font-size: 23px;overflow: hidden'>" . $arr['name'] . "</td>"
  233. . "<td style='height: 45px;font-size: 23px;'>" . $attr_str . "</td>"
  234. . "<td style='height: 45px;font-size: 23px'>" . $arr['no'] . "</td>"
  235. . "<td style='height: 45px;font-size: 23px'>" . $arr['unit'] . "</td>"
  236. . "<td style='height: 45px;font-size: 23px'>" . $arr['num'] . "</td>"
  237. . "<td style='height: 45px;font-size: 23px'>" . $arr['total_price'] / $arr['num'] . "</td>"
  238. . "<td style='height: 45px;font-size: 23px'>" . $arr['total_price']
  239. . "<td style='height: 45px;font-size: 23px'></td style='height: 45px;font-size: 23px'></tr>";
  240. $order_count_price = $order_count_price + $arr['total_price'];
  241. }
  242. $html = "
  243. <!DOCTYPE html>
  244. <html lang='en'>
  245. <style>
  246. html, body, div, ul, li, h1, h2, h3, h4, h5, h6, p, dl, dt, dd, ol, form, input, textarea, th, td, select {
  247. margin: 0;
  248. padding: 0;
  249. }
  250. *{box-sizing: border-box;}
  251. html, body {
  252. min-height: 100%;
  253. }
  254. body {
  255. font-family: 'Microsoft YaHei';
  256. font-size:14px;
  257. color:#333;
  258. }
  259. h1, h2, h3, h4, h5, h6{font-weight:normal;}
  260. ul,ol {
  261. list-style: none;
  262. }
  263. img {
  264. border: none;
  265. vertical-align: middle;
  266. }
  267. a {
  268. text-decoration: none;
  269. color: #232323;
  270. }
  271. table {
  272. border-collapse: collapse;
  273. table-layout: fixed;
  274. }
  275. input, textarea {
  276. outline: none;
  277. border: none;
  278. }
  279. textarea {
  280. resize: none;
  281. overflow: auto;
  282. }
  283. .clearfix {
  284. zoom: 1;
  285. }
  286. .clearfix:after {
  287. content: '.';
  288. width: 0;
  289. height: 0;
  290. visibility: hidden;
  291. display: block;
  292. clear: both;
  293. overflow:hidden;
  294. }
  295. .fl {
  296. float: left
  297. }
  298. .fr {
  299. float: right
  300. }
  301. .tl {
  302. text-align: left;
  303. }
  304. .tc {
  305. text-align: center
  306. }
  307. .tr {
  308. text-align: right;
  309. }
  310. .ellipse {
  311. overflow: hidden;
  312. text-overflow: ellipsis;
  313. white-space: nowrap;
  314. }
  315. .inline{
  316. display: inline-block;
  317. *display: inline;
  318. *zoom: 1;
  319. }
  320. body {
  321. font-size: 16px;
  322. }
  323. .title {
  324. font-size: 36px;
  325. margin-left: 30%;
  326. }
  327. table {
  328. margin: 0 auto;
  329. }
  330. .column div {
  331. display: flex;
  332. justify-content: space-between;
  333. }
  334. .info td {
  335. padding-right: 10px;
  336. }
  337. td {
  338. height: 34px;
  339. }
  340. .serial {
  341. width: 5%;
  342. }
  343. .name {
  344. width: 25%;
  345. }
  346. .bar_code {
  347. width: 18%;
  348. }
  349. .unit{
  350. width: 7%;
  351. }
  352. .num {
  353. width: 7%;
  354. }
  355. .unit_price {
  356. width: 7%;
  357. }
  358. .money {
  359. width: 9%;
  360. }
  361. .desc{
  362. width: 12%;
  363. }
  364. .text-cont {
  365. text-align: center;
  366. }
  367. .fontsize20 {
  368. font-size: 20px;
  369. }
  370. .fontsize15 {
  371. font-size: 15px;
  372. white-space: nowrap;
  373. -moz-text-overflow: ellipsis;
  374.   overflow: hidden;
  375.   text-overflow: ellipsis;
  376. }
  377. .header {
  378. font-size: 18px;
  379. background-color: #CCC;
  380. }
  381. .img_box {
  382. display: flex;
  383. }
  384. .img_box img {
  385. width: 110px;
  386. height: 110px;
  387. background-color: #ccc;
  388. }
  389. .phone span {
  390. padding-right: 10px;
  391. }
  392. .flex {
  393. display: flex;
  394. }
  395. .flex_name {
  396. width: 74px;
  397. }
  398. .info{
  399. width: 96%;
  400. }
  401. .info2{
  402. width: 96%;
  403. float: left;
  404. margin-left: 2%;
  405. }
  406. .footer {
  407. width: 96%;
  408. margin: 0 auto;
  409. display: flex;
  410. }
  411. </style>
  412. <body style='width: 100%;margin-top: 5%'>
  413. <h2 class='title'>".$order_title."</h2>
  414. <table border='0' class='info'>
  415. <tr>
  416. <td style='width: 40%;font-size: 20px;' >订单号:" . $order_info['order_no'] . "</td>
  417. <td style='width: 30%;font-size: 20px;'>客户电话:" . $order_info['mobile'] . "</td>
  418. <td style='width: 30%;font-size: 20px;'>下单时间:" . date('Y-m-d', $order_info['created_at']) . "</td>
  419. </tr>
  420. <tr>
  421. <td style='width: 40%;font-size: 20px;'>客户:" . $order_info['name'] . "</td>
  422. <td style='width: 30%;font-size: 20px;'>客户地址:" . $order_info['address'] . "</td>
  423. <td style='width: 30%;font-size: 20px;'>支付方式:" . $order_info['is_pay'] . "</td>
  424. </tr>
  425. </table>
  426. <table border='1' class='info2'>
  427. <tr class='text-cont header'>
  428. <td class='serial' style='height: 45px;font-size: 25px'>序</td>
  429. <td class='name' style='height: 45px;font-size: 25px'>产品名称</td>
  430. <td class='name' style='height: 45px;font-size: 25px' >规格</td>
  431. <td class='bar_code' style='height: 45px;font-size: 25px' >条码</td>
  432. <td class='unit' style='height: 45px;font-size: 25px'>单位</td>
  433. <td class='num' style='height: 45px;font-size: 25px'>数量</td>
  434. <td class='unit_price' style='height: 45px;font-size: 25px'>单价</td>
  435. <td class='money' style='height: 45px;font-size: 25px'>金额</td>
  436. <td class='desc' style='height: 45px;font-size: 25px'>备注</td>
  437. </tr>
  438. " . $tr2 . "
  439. <tr>
  440. <td colspan='6' style='padding-left: 10px;height: 45px;font-size: 25px'>合计金额:</td>
  441. <td style='height: 45px;font-size: 25px'>" . $order_count_price . "</td>
  442. <td style='height: 45px;font-size: 25px'>" . "</td>
  443. </tr>
  444. </table>
  445. <div class='footer'>
  446. <div>
  447. <div class='phone' style='font-size: 20px;'>
  448. 联系电话:<span>".$order_mobile."</span>
  449. </div>
  450. <div class='flex' style='font-size: 20px;'>
  451. <div class='flex_name'>
  452. 地址:
  453. </div>
  454. <div style='font-size: 20px;'>
  455. ".$order_address."
  456. </div>
  457. </div>
  458. <div style='font-size: 20px;'>
  459. 产品注明:".$order_desc."
  460. </div>
  461. </div>
  462. </div>
  463. </body>
  464. </html>
  465. ";
  466. return $html;
  467. }
  468. /**
  469. * @param $sign
  470. * @param $app_id
  471. * @param $time_stamp
  472. * @return mixed
  473. */
  474. public static function getToken($sign, $app_id, $time_stamp)
  475. {
  476. // 初始化
  477. $curl = curl_init();
  478. $url = 'https://mcp.jolimark.com/mcp/v3/sys/GetAccessToken?app_id=' . $app_id . '&time_stamp=' . $time_stamp
  479. . '&sign=' . $sign . '&sign_type=MD5';
  480. // 设置抓取的url
  481. curl_setopt($curl, CURLOPT_URL, $url);
  482. // 设置头文件的信息作为数据流输出
  483. curl_setopt($curl, CURLOPT_HEADER, 0);
  484. //设置获取的信息以文件流的形式返回,而不是直接输出。
  485. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  486. curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,false);
  487. // 执行命令
  488. $data = curl_exec($curl);
  489. // 关闭URL请求
  490. curl_close($curl);
  491. return $data;
  492. }
  493. }