ByteDance.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace ByteDance;
  8. use app\models\Option;
  9. use app\models\Order;
  10. use app\models\OrderUnion;
  11. use app\utils\OrderNo;
  12. use GuzzleHttp\Exception\GuzzleException;
  13. use yii\base\BaseObject;
  14. use yii\helpers\Json;
  15. class ByteDance
  16. {
  17. /**
  18. * @var 是否是平台小程序
  19. */
  20. public static $is_platform;
  21. public static $store_id;
  22. public static $app_id;
  23. public static $salt;
  24. public static $notify_url = 'bytedance/notify';
  25. /**
  26. * @var \ByteDance\MiniProgram\Application
  27. */
  28. public static $bytedance;
  29. public static function init() {
  30. self::$is_platform = get_params('is_platform', 'yes');
  31. self::$store_id = get_store_id();
  32. if (self::$is_platform == 'no') {
  33. $bytedance_config = Option::get('douyin', self::$store_id, 'store');
  34. if (!empty($bytedance_config['value'])) {
  35. $bytedance_config = Json::decode($bytedance_config['value']);
  36. $config['app_id'] = $bytedance_config['app_id'];
  37. $config['app_secret'] = $bytedance_config['app_secret'];
  38. $config['salt'] = $bytedance_config['salt'];
  39. }
  40. } else {
  41. $bytedance_config = Option::getSaasPlatformBytedance();
  42. $config['app_id'] = $bytedance_config['appid'];
  43. $config['app_secret'] = $bytedance_config['key'];
  44. $config['salt'] = $bytedance_config['salt'];
  45. }
  46. self::$app_id = $config['app_id'];
  47. self::$salt = $config['salt'];
  48. self::$bytedance = Factory::miniProgram($config);
  49. }
  50. /**
  51. * @param $subject
  52. * @param $price
  53. * @param string $body
  54. * @param array $extra
  55. * @throws Kernel\Exceptions\InvalidArgumentException
  56. * @throws Kernel\Exceptions\InvalidConfigException
  57. * @throws \GuzzleHttp\Exception\GuzzleException
  58. */
  59. public static function pay($order, $type, $subject, $total_pay_price = 0, $balance_price = 0, $extra = []) {
  60. if (!$order || (!empty($type) && !in_array($type, OrderNo::$validOrderType)) || ($type != OrderNo::ORDER_UNION && !$subject)) {
  61. return [
  62. 'code' => 1,
  63. 'msg' => '订单信息或订单类型错误'
  64. ];
  65. }
  66. try {
  67. self::init();
  68. $extra['store_id'] = get_store_id();
  69. $params = [
  70. 'app_id' => self::$app_id,
  71. 'valid_time' => 48 * 60 * 60, // 两天
  72. 'cp_extra' => Json::encode($extra),
  73. // 'notify_url' => pay_notify_url(self::$notify_url),
  74. 'notify_url' => 'https://chidian.cyyvip.com/index.php/bytedance/notify',
  75. 'disable_msg' => 0,
  76. 'msg_type' => 'pages/home/home'
  77. ];
  78. if ($type == OrderNo::ORDER_UNION) {
  79. $params['out_order_no'] = OrderNo::getOrderNo(OrderNo::ORDER_UNION);
  80. $params['body'] = $params['subject'] = count($order) . '笔订单合并支付';
  81. $params['total_amount'] = $balance_price > 0 ? floatval($total_pay_price - $balance_price) * 100 : $total_pay_price * 100;
  82. $order_union = new OrderUnion();
  83. $order_union->store_id = get_store_id();
  84. $order_union->user_id = get_user()->id;
  85. $order_union->order_no = $params['out_trade_no'];
  86. $order_union->price = $total_pay_price;
  87. $order_union->is_pay = 0;
  88. $order_union->created_at = time();
  89. $order_union->is_delete = 0;
  90. $order_id_list = [];
  91. foreach ($order as $value) {
  92. $order_id_list[] = $value->id;
  93. }
  94. $order_union->order_id_list = json_encode($order_id_list);
  95. if (!$order_union->save()) {
  96. foreach ($order_union->errors as $error) {
  97. return [
  98. 'code' => 1,
  99. 'msg' => $error
  100. ];
  101. }
  102. }
  103. } else {
  104. $params['out_order_no'] = $order->order_no;
  105. $params['body'] = $params['subject'] = $subject;
  106. $params['total_amount'] = $balance_price > 0 ? floatval($order->pay_price - $balance_price) * 100 : $order->pay_price * 100;
  107. }
  108. $params['sign'] = self::sign($params);
  109. \Yii::warning($params);
  110. $res = self::$bytedance->order->unify($params);
  111. \Yii::warning($res);
  112. if ($type == OrderNo::ORDER_UNION) {
  113. foreach ($order_id_list as $value) {
  114. $value->order_union_id = $order_union->id;
  115. $value->save();
  116. }
  117. }
  118. if (!$res['err_no']) {
  119. return [
  120. 'code' => 0,
  121. 'msg' => 'success',
  122. 'data' => $res['data']
  123. ];
  124. } else {
  125. return [
  126. 'code' => $res['err_no'],
  127. 'msg' => $res['err_tips']
  128. ];
  129. }
  130. } catch (\Exception $e) {
  131. return [
  132. 'code' => 1,
  133. 'msg' => $e->getMessage()
  134. ];
  135. }
  136. }
  137. /**
  138. * @param $subject
  139. * @param $price
  140. * @param string $body
  141. * @param array $extra
  142. * @throws Kernel\Exceptions\InvalidArgumentException
  143. * @throws Kernel\Exceptions\InvalidConfigException
  144. * @throws \GuzzleHttp\Exception\GuzzleException
  145. */
  146. public static function refund($order_no) {
  147. try {
  148. self::init();
  149. $extra['store_id'] = get_store_id();
  150. $params = [
  151. 'app_id' => self::$app_id,
  152. 'cp_extra' => Json::encode($extra),
  153. // 'notify_url' => pay_notify_url(self::$notify_url),
  154. 'notify_url' => 'https://chidian.cyyvip.com/index.php/bytedance/notify',
  155. 'disable_msg' => 0,
  156. 'msg_type' => 'pages/home/home'
  157. ];
  158. $params['out_order_no'] = $order_no;
  159. $params['out_refund_no'] = 'refund123456';
  160. $params['reason'] = '无货';
  161. $params['refund_amount'] = 499 * 100;
  162. $params['sign'] = self::sign($params);
  163. \Yii::warning($params);
  164. $res = self::$bytedance->order->refund($params);
  165. \Yii::warning($res);
  166. if (!$res['err_no']) {
  167. return [
  168. 'code' => 0,
  169. 'msg' => 'success',
  170. 'data' => $res['data']
  171. ];
  172. } else {
  173. return [
  174. 'code' => $res['err_no'],
  175. 'msg' => $res['err_tips']
  176. ];
  177. }
  178. } catch (\Exception $e) {
  179. return [
  180. 'code' => 1,
  181. 'msg' => $e->getMessage()
  182. ];
  183. }
  184. }
  185. /**
  186. * 下单加签
  187. * @param $map
  188. * @return string
  189. */
  190. private static function sign($map) {
  191. $rList = array();
  192. foreach($map as $k =>$v) {
  193. if ($k == "other_settle_params" || $k == "app_id" || $k == "sign" || $k == "thirdparty_id")
  194. continue;
  195. $value = trim(strval($v));
  196. $len = strlen($value);
  197. if ($len > 1 && substr($value, 0, 1) == "\"" && substr($value, $len, $len-1) == "\"")
  198. $value = substr($value, 1, $len - 1);
  199. $value = trim($value);
  200. if ($value == "" || $value == "null")
  201. continue;
  202. array_push($rList, $value);
  203. }
  204. array_push($rList, self::$salt);
  205. sort($rList, 2);
  206. return md5(implode('&', $rList));
  207. }
  208. /**
  209. * @param string $page
  210. * @param array $params
  211. * @return array
  212. */
  213. public static function qrcode($page, $params) {
  214. if (empty($page)) {
  215. return [
  216. 'code' => 1,
  217. 'msg' => 'page不能为空'
  218. ];
  219. }
  220. self::init();
  221. $str = $page;
  222. if (!empty($params)) {
  223. $str .= '?';
  224. foreach ($params as $key => $param) {
  225. $str .= $key . '=' . $param . '&';
  226. }
  227. }
  228. $str = substr($str, 0, -1);
  229. $file_name = md5($page . $str);
  230. // 保存小程序码到文件
  231. $dir = \Yii::$app->runtimePath . '/image/dy_qrcode';
  232. if (! is_dir($dir)) {
  233. mkdir($dir, 0777, true);
  234. }
  235. if (file_exists($dir. '/' .$file_name . '.jpg')) {
  236. $url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . '/runtime/image/dy_qrcode/' . $file_name);
  237. return [
  238. 'code' => 0,
  239. 'root_path' => $dir . '/' . $file_name . '.jpg',
  240. 'url_path' => $url . '.jpg',
  241. ];
  242. }
  243. $params = [
  244. 'path' => $str,
  245. 'set_icon' => true
  246. ];
  247. /**
  248. * @var \ByteDance\Kernel\Http\Response $response
  249. */
  250. $response = self::$bytedance->qrcode->create($params);
  251. if ($response instanceof \ByteDance\Kernel\Http\Response) {
  252. $filename = $response->save($dir, $file_name);
  253. } else {
  254. return [
  255. 'code' => 1,
  256. 'response' => $response,
  257. ];
  258. }
  259. $url = str_replace('http://', 'https://', \Yii::$app->request->hostInfo . '/runtime/image/dy_qrcode/' . $filename);
  260. return [
  261. 'code' => 0,
  262. 'root_path' => $dir . '/' . $filename,
  263. 'url_path' => $url,
  264. ];
  265. }
  266. }