FengSu.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. <?php
  2. /**
  3. * ----------------------------------------------------------------------------
  4. * 行到水穷处,坐看云起时
  5. * 开发软件,找贵阳云起信息科技,官网地址:https://www.56q7.com/
  6. * ----------------------------------------------------------------------------
  7. * Author: 老成
  8. * email:85556713@qq.com
  9. */
  10. declare(strict_types=1);
  11. namespace app\admin\command;
  12. use app\common\model\FengsuShip;
  13. use think\console\Command;
  14. use think\console\Input;
  15. use think\console\Output;
  16. use GuzzleHttp\Client;
  17. use app\common\model\CrontabLog;
  18. use app\common\model\ImportSku;
  19. use app\common\model\ShopList;
  20. use app\common\model\ProductConfig;
  21. use app\common\model\ShopDelivery;
  22. use app\common\model\CustomerSpec;
  23. use app\admin\service\FengsuService;
  24. use GuzzleHttp\Psr7\Request;
  25. use app\common\model\ImportList;
  26. use app\admin\service\JuShuiTanService;
  27. use think\facade\Cache;
  28. use app\common\controller\Http;
  29. //抖音
  30. class FengSu extends Command
  31. {
  32. //抖音请求地址
  33. protected $url = 'https://fsdy2.fengsutb.com/amount/ship-list-new';
  34. //抖音请求头部
  35. protected $headers = [
  36. 'Host' => 'fsdy2.fengsutb.com',
  37. 'Accept' => 'application/json, text/plain, */*',
  38. 'Authorization' => 'Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxODYwNTQ1MTExNSIsImRhdGFfcGVybWlzc2lvbiI6InByb2R1Y3RDb3N0IiwibmlrZSI6IjE4NjA1NDUxMTE1IiwiY3JlYXRlZCI6MTc2NDEyNTQwMzQ0OSwiZHBJZCI6MTAwNjczLCJleHAiOjE3NjQ3MzAyMDMsImVuYWJsZWQiOnRydWUsImF1dGhvcml0aWVzIjpbInpodXlvbmdodSJdLCJkcEFjY291bnRJZCI6MTAwNjczfQ.ihv6NRfD2hzU1NQoqttTaZ-mPxqAEXIUICM8MuxVx2tVLEPW9j-uPhHoFz4T3-lH07wTt2ORf1k_SPOQP4PuQg',
  39. 'Content-Type' => 'application/json',
  40. // 'platform' => 'dy',
  41. ];
  42. // 打单平台 1:风速 2:聚水潭
  43. protected $type_id = 1;
  44. //时间间隔
  45. protected $start_end_space_time = 10 * 60;
  46. //下一次时间间隔
  47. protected $next_time_space = 7 * 60;
  48. // 指令配置
  49. protected function configure()
  50. {
  51. $this->setName('feng_su')->setDescription('the task command');
  52. }
  53. //根据shop_id
  54. protected function execute(Input $input, Output $output)
  55. {
  56. $output->writeln('开始同步订单');
  57. $resquet = $this->getOrderList('');
  58. if ($resquet['code'] == 0) {
  59. $fengsu = [];
  60. $fengsu = Cache::get('fengsu');
  61. if ($resquet['data']['list'] != null && !empty($resquet['data']['list'])) {
  62. $fengsu_pageNum = $fengsu['pageNum'];
  63. $fengsu_pageNum = $fengsu_pageNum + 1;
  64. $fengsu = [
  65. 'startTime' => $fengsu['startTime'],
  66. 'endTime' => $fengsu['endTime'],
  67. 'pageNum' => $fengsu_pageNum,
  68. 'next_time_space' => $fengsu['next_time_space']
  69. ];
  70. Cache::set('fengsu', $fengsu);
  71. $list = $resquet['data']['list'];
  72. // dump($list);
  73. // return;
  74. $this->insertOrder($list);
  75. //dump($resquet);
  76. } else {
  77. $now_time = time();
  78. if ($fengsu['startTime'] >= $now_time || ($now_time - $fengsu['startTime']) < ($this->next_time_space)) {
  79. // dump("超时了");
  80. $pre_time_stamp = $this->next_time_space;
  81. $startTime_stamp = $now_time - $pre_time_stamp;
  82. $endTime_stamp = $startTime_stamp + $this->start_end_space_time;
  83. $fengsu = [
  84. 'startTime' => $startTime_stamp,
  85. 'endTime' => $endTime_stamp,
  86. 'pageNum' => 1,
  87. 'next_time_space' => $fengsu['next_time_space']
  88. ];
  89. } else {
  90. $fengsu = [
  91. 'startTime' => $fengsu['startTime'] + $fengsu['next_time_space'],
  92. 'endTime' => $fengsu['endTime'] + $fengsu['next_time_space'],
  93. 'pageNum' => 1,
  94. 'next_time_space' => $fengsu['next_time_space']
  95. ];
  96. }
  97. Cache::set('fengsu', $fengsu);
  98. $output->writeln('没有数据');
  99. }
  100. } else {
  101. $output->writeln('接口错误: ' . $resquet['message']);
  102. }
  103. $output->writeln('ok');
  104. }
  105. public function getOrderList($platform = '')
  106. {
  107. $client = new \GuzzleHttp\Client([
  108. 'verify' => false,
  109. // 或指定证书路径
  110. // 'verify' => '/path/to/cacert.pem'
  111. ]);
  112. $headers = [
  113. 'Accept' => ' application/json, text/plain, */*',
  114. 'Authorization' => site_config("addonsd.authorization_token"),
  115. 'Host' => ' fsdy2.fengsutb.com',
  116. 'platform' => $platform,
  117. 'Content-Type' => ' application/json'
  118. ];
  119. //时间间隔
  120. // $start_end_space_time=10*60;
  121. //下一次时间间隔
  122. // $next_time_space=7*60;
  123. //将查询分为,"2026-01-05 00:00:00~2026-01-05 00:05:00",查询该区间的订单,但是该时间区间单独数量可能超过50条,为了性能又不能一次性查询太多,从而进行分页查询,
  124. //查询不到数据,就往下一个时间区间查询
  125. $todayTime = date("Y-m-d");
  126. $startTime_stamp = strtotime($todayTime . ' 00:00:00');
  127. // $startTime_stamp = strtotime($todayTime . ' 07:20:00');
  128. $endTime_stamp = $startTime_stamp + $this->start_end_space_time;
  129. $pageNum = 1;
  130. $fengsu = [
  131. 'startTime' => $startTime_stamp,
  132. 'endTime' => $endTime_stamp,
  133. 'pageNum' => $pageNum,
  134. 'next_time_space' => $this->next_time_space
  135. ];
  136. $fengsu_cache_data = Cache::get('fengsu');
  137. if (empty($fengsu_cache_data) || $fengsu_cache_data == null) {
  138. Cache::set('fengsu', $fengsu);
  139. }
  140. $fengsu = Cache::get('fengsu');
  141. // 无数据时,获取数据的开始时间会大于现在的时间,这是一个错误的,会导致一直无法获取数据,开始时间一直往后
  142. //当开始时间大于现在时间,将开始时间向前调整3分钟
  143. $now_time = time();
  144. if ($fengsu['startTime'] >= $now_time || ($now_time - $fengsu['startTime']) < ($this->start_end_space_time - $this->next_time_space)) {
  145. // dump("超时了");
  146. $pre_time_stamp = $this->next_time_space;
  147. $startTime_stamp = $now_time - $pre_time_stamp;
  148. $endTime_stamp = $startTime_stamp + $this->start_end_space_time;
  149. $fengsu = [
  150. 'startTime' => $startTime_stamp,
  151. 'endTime' => $endTime_stamp,
  152. 'pageNum' => 1,
  153. 'next_time_space' => $this->next_time_space
  154. ];
  155. }
  156. Cache::set('fengsu', $fengsu);
  157. $startTime = date('Y-m-d H:i:s', $fengsu['startTime']);
  158. $endTime = date('Y-m-d H:i:s', $fengsu['endTime']);
  159. $pageNum = (int)$fengsu['pageNum'];
  160. // dump($startTime);
  161. // dump($fengsu);
  162. // $body = [
  163. // 'startTime' => $startTime,//时间区间
  164. // 'endTime' => $endTime,
  165. // 'sort' => 'CONSIGN_TIME',
  166. // 'sortAsc' => true,
  167. // 'current' => $pageNum,//页数
  168. // 'size' => 50,//每页多少条
  169. // 'tradeStatus' => 2,
  170. // 'fromAccountId' => [],
  171. // 'goodType' => 2,
  172. // 'goodsFlag' => 2
  173. // ];
  174. $body = [
  175. 'startTime' => $startTime,
  176. // 'startTime' =>'2026-01-03 00:23:00',
  177. 'endTime' => $endTime,
  178. // 'endTime' => '2026-01-07 23:30:00',
  179. 'current' => $pageNum,
  180. // 'current' => 1,
  181. 'goodType' => 2,
  182. 'goodsFlag' => 1,
  183. 'orderPrefixSelect' => 'waybillNos',
  184. 'prepareShip' => 0,
  185. 'size' => 100,
  186. 'sort' => 'CONSIGN_TIME',
  187. 'sortAsc' => true,
  188. 'timeType' => 2,
  189. 'tradeStatus' => 2,
  190. 'skuOuterIdExact' => false,
  191. 'skuPropExact' => false,
  192. 'tradeSources' => []
  193. ];
  194. // 'waybillNos' => ['73589756512463']
  195. $body = json_encode($body);
  196. $request = new Request('POST', 'https://fsdy2.fengsutb.com/amount/ship-list-new', $headers, $body);
  197. // $request = new Request('POST', 'https://fsdy2.fengsutb.com/trade/print-list', $headers, $body);
  198. try {
  199. $res = $client->sendAsync($request)->wait();
  200. $json = [];
  201. if ($res->getStatusCode() == 200) {
  202. $json = json_decode($res->getBody()->getContents(), true);
  203. } else {
  204. dump($res->getStatusCode(), '接口返回结果');
  205. }
  206. return $json;
  207. } catch (\Exception $e) {
  208. $errorStr = $e->getMessage();
  209. // 定位response:位置
  210. $pos = strpos($errorStr, 'response:');
  211. if ($pos !== false) {
  212. // 从response:后开始截取
  213. $jsonPart = substr($errorStr, $pos + strlen('response:'));
  214. // 清理空白字符
  215. $jsonPart = preg_replace('/^\s+|\s+$/', '', $jsonPart);
  216. $jsonPart = json_decode($jsonPart, true);
  217. if (!empty($jsonPart)) {
  218. if ($jsonPart['code'] == 401 && $jsonPart['message'] == 'token失效') {
  219. $this->set_fengsu_Authorization($client);
  220. }
  221. }
  222. }
  223. var_dump($e->getMessage());
  224. return null;
  225. }
  226. }
  227. public function insertOrder($order_list)
  228. {
  229. if (!(count($order_list) > 0)) {
  230. return false;
  231. }
  232. $queue = [];
  233. $shopList = new ShopList();
  234. $importSku = new ImportSku();
  235. $productConfig = new ProductConfig();
  236. $shopDelivery = new ShopDelivery();
  237. $customerSpec = new CustomerSpec();
  238. $shopDelivery_list = [];
  239. foreach ($order_list as $item) {
  240. $goods_id = $item['tradeOrderPrintVos'][0]['goodsId'];
  241. $oid = $item['tradeOrderPrintVos'][0]['oid'];
  242. $sku_id = $item['tradeOrderPrintVos'][0]['skuId'];
  243. $waybill_no = $item['tradeOrderPrintVos'][0]['waybillNo'];
  244. if (empty($waybill_no)) continue;
  245. $add_status = JuShuiTanService::prevent_duplicate_additions($sku_id, $waybill_no);
  246. if ($add_status) continue;
  247. // $status = FengsuService::getAdditionalPrice( $shopList, $importSku, $productConfig, $shopDelivery, $customerSpec, $item);
  248. $res = FengsuService::getAdditionalPrice($shopList, $importSku, $productConfig, $shopDelivery, $customerSpec, $item);
  249. $status = $res['status'];
  250. $shopDelivery_list[] = $res['shopDelivery'];
  251. $weight = $item['tradeOrderPrintVos'][0]['weight'];
  252. $weight = strval($weight);
  253. $weight = bcdiv($weight, '500', 2);
  254. $weight = (float)$weight;
  255. $price = $item['tradeOrderPrintVos'][0]['payment'];
  256. $price = strval($price);
  257. $price = bcdiv($price, '100', 2);
  258. $price = (float)$price;
  259. $getPackSpecsFee = JuShuiTanService::getPackSpecsFee($importSku, $item['shopId'], $item['tradeOrderPrintVos'][0]['skuId'], $item['receiverProvince']);
  260. $queue[] = [
  261. 'type_id' => $this->type_id,
  262. 'shop_id' => $item['shopId'],
  263. 'order_id' => $oid,
  264. 'trade_from' => $item['tradeFrom'],
  265. 'province' => $item['receiverProvince'],
  266. 'city' => $item['receiverCity'],
  267. 'company_name' => $item['companyName'],
  268. 'waybill_no' => $waybill_no,
  269. 'consign_time' => $item['tradeOrderPrintVos'][0]['consignTime'],
  270. 'goods_id' => $goods_id,
  271. 'sku_id' => $item['tradeOrderPrintVos'][0]['skuId'],
  272. 'num' => $item['tradeOrderPrintVos'][0]['total'],
  273. 'goods_title' => $item['tradeOrderPrintVos'][0]['goodsTitle'],
  274. 'goods_info' => $item['tradeOrderPrintVos'][0]['skuProp'],
  275. 'weight' => $weight,
  276. 'price' => $price,
  277. 'status' => $status,
  278. 'specs_name' => $getPackSpecsFee['data']['title'],
  279. 'pack_specs_id' => $getPackSpecsFee['data']['id'],
  280. 'labor_cost_money' => $getPackSpecsFee['data']['labor_cost_money'],
  281. 'one_surcharge_money' => $getPackSpecsFee['one_surcharge_money'],
  282. 'two_surcharge_money' => $getPackSpecsFee['two_surcharge_money'],
  283. 'order_status' => $item['tradeOrderPrintVos'][0]['orderStatus']
  284. ];
  285. }
  286. // dump($queue);
  287. // 保存到数据库
  288. $shopDelivery->saveAll($shopDelivery_list);
  289. (new ImportList())->saveAll($queue);
  290. // 更新最后执行时间
  291. CrontabLog::create(['type_id' => 2, 'last_time' => date('Y-m-d H:i:s')]);
  292. }
  293. //更新风速授权token
  294. public function set_fengsu_Authorization($client)
  295. {
  296. $url = 'https://fx.fengsutb.com/gw/user/login';
  297. $headers = [
  298. 'Accept' => '*/*',
  299. 'Accept-Encoding' => 'gzip, deflate, br',
  300. 'User-Agent' => 'PostmanRuntime-ApipostRuntime/1.1.0',
  301. 'Connection' => 'keep-alive',
  302. 'Content-Type' => 'application/json'
  303. ];
  304. $params = [
  305. "mobile" => "data_sync",
  306. "password" => "6YZKdG6iO!",
  307. "verificationCode" => "2588",
  308. "loginType" => "passwordLogin"
  309. ];
  310. $params = json_encode($params);
  311. $request_login = new Request('POST', $url, $headers, $params);
  312. $res = $client->sendAsync($request_login)->wait();
  313. $json = [];
  314. if ($res->getStatusCode() == 200) {
  315. $json = json_decode($res->getBody()->getContents(), true);
  316. } else {
  317. dump($res->getStatusCode(), '接口返回结果');
  318. }
  319. if(!empty($json)){
  320. if($json['code']==0&&$json['message']=='登录成功!'&&!empty($json['data'])){
  321. site_config("addonsd.authorization_token",$json['data']);
  322. dump('token更新成功');
  323. }
  324. }
  325. }
  326. }
  327. //风速接口返回格式
  328. // {
  329. // "shopId": "DY117939700",
  330. // "sysNum": "3908161982177974",
  331. // "groupId": "g3908162034664709",
  332. // "tradeFrom": "dy",
  333. // "tid": "6948414820472788426",
  334. // "fromAccountId": 0,
  335. // "createTime": "2025-11-26 21:27:53",
  336. // "payTime": "2025-11-26 21:27:55",
  337. // "inserTime": "2025-11-27 15:11:27",
  338. // "inventoryPrintTime": null,
  339. // "consignTime": "2025-11-27 15:11:27",
  340. // "refunding": 0,
  341. // "buyerId": "1@#MhctHqbGY6MptrPvaPcNSU6JEPT1RwM+zhPxvrsCvBSVf2u9/qsla+xb9Fu81aUBMmCH",
  342. // "buyerNick": null,
  343. // "buyerMessage": "",
  344. // "sellerFlag": 0,
  345. // "localFlag": 0,
  346. // "sellerMemo": null,
  347. // "localMemo": null,
  348. // "offlineMemo": null,
  349. // "offlineFlag": null,
  350. // "receiverProvince": "黑龙江省",
  351. // "receiverCity": "哈尔滨市",
  352. // "receiverDistrict": "依兰县",
  353. // "receiverTown": "依兰镇",
  354. // "desensitizationName": "昕*",
  355. // "desensitizationPhone": null,
  356. // "desensitizationAddress": "*******",
  357. // "desensitizationMobile": "1**********",
  358. // "modifyAddr": 0,
  359. // "invoiceType": null,
  360. // "invoiceTitle": null,
  361. // "invoiceTaxId": null,
  362. // "promiseShipTime": "2025-12-01 21:27:56",
  363. // "tradeStatus": "WAIT_CONFIRM",
  364. // "payment": 9440,
  365. // "receiptAmount": 9440,
  366. // "postFee": 0,
  367. // "splitType": 1,
  368. // "packageNum": 1,
  369. // "dpAccountId": 100673,
  370. // "bizDpAccountId": 100673,
  371. // "uid": "117939700",
  372. // "bizShopId": "DY117939700",
  373. // "companyName": "中通快递",
  374. // "waybillNo": null,
  375. // "companyId": 3,
  376. // "templateId": 145375,
  377. // "printSize": 1,
  378. // "mergeHash": "6BC35CF08C74762098670BB71B38F77C387FB374",
  379. // "mergeHash2": "AC9CEFB7FD89A32A1AA235A9E09BD69FE838D08D",
  380. // "mergeable": 0,
  381. // "handDeliverFlag": 0,
  382. // "tradeAttr": "{\"promise_type\":1,\"recommend_logistics_list\":\"[]\"}",
  383. // "localAttr": null,
  384. // "senderAddressEntity": null,
  385. // "outChannel": null,
  386. // "tradeFlag": null,
  387. // "link": "",
  388. // "roleFlg": true,
  389. // "shopFlg": true,
  390. // "saleFlg": true,
  391. // "picUrlFlag": true,
  392. // "preSale": 1,
  393. // "preSaleTime": null,
  394. // "splitFailReason": null,
  395. // "businessTag": 0,
  396. // "locked": 0,
  397. // "tradeOrderPrintVos": [
  398. // {
  399. // "distTime": null,
  400. // "orderStatus": "WAIT_CONFIRM",
  401. // "goodsTitle": "田与薯云南圆圆果·榴莲蜜薯软糯蜜甜新鲜高原黄心番薯地瓜粗粮",
  402. // "goodsId": "3665081518029678296",
  403. // "skuProp": "{\"65\":\"小糖豆(50g-150g)\",\"66\":\"5斤(精品装(带箱5斤))\",\"67\":\"5天内发货\"}",
  404. // "companyName": "中通快递",
  405. // "waybillNo": "76767227765924",
  406. // "outerId": null,
  407. // "refundStatus": null,
  408. // "picUrl": "https://p3-aio.ecombdimg.com/obj/ecom-shop-material/jpeg_m_e379a8d857f16246745a757892497184_sx_320989_www1668-1668",
  409. // "total": 1,
  410. // "price": 3980,
  411. // "payment": 3780,
  412. // "receiptAmount": null,
  413. // "orderType": 0,
  414. // "consignTime": "2025-11-27 15:11:27",
  415. // "signTime": null,
  416. // "weight": 0,
  417. // "goodShortName": null,
  418. // "skuShortName": null,
  419. // "oid": "6948414820472788426",
  420. // "packageNum": 1,
  421. // "splitType": 1,
  422. // "companyId": 3,
  423. // "templateId": 145375,
  424. // "outerSkuId": "LFT-LLSPK-4.5-SC-CX",
  425. // "skuId": "3617103894193922",
  426. // "printSize": 1,
  427. // "printTime": "2025-11-27 15:11:22",
  428. // "roleType": 1,
  429. // "roleName": "田与薯官方旗舰店",
  430. // "lastFactoryId": 100673,
  431. // "inventoryPrintSize": 0,
  432. // "inventoryPrintTime": null,
  433. // "platCode": "ZJ",
  434. // "purchaseAttr": null,
  435. // "shelfPosition": "",
  436. // "pushTime": null,
  437. // "orderAttr": "{\"author_name\":\"田与薯官方旗舰店\",\"order_goods_type\":0,\"order_biz\":2,\"pre_sale_label\":\"全款预售\",\"compensate_for_rotten_platform_guarantee\":\"坏了包退官方保障\",\"quick_refund_label\":\"极速退\",\"unsupport_7days_refund\":\"不支持7天\",\"c_biz_self_sell\":\"小店自卖\",\"compass_source_not_ad_mark\":\"非广告\",\"compass_source_content_type_live\":\"直播\",\"afterSaleType\":\"refund\",\"source_platform\":\"\",\"period_purchase_info\":{},\"pack_id\":\"147242304405974025\"}",
  438. // "freeze": 0,
  439. // "freezeReason": null,
  440. // "auditStatus": 2,
  441. // "payStatus": null,
  442. // "settleStatus": null,
  443. // "settleRefundStatus": null,
  444. // "settleAmount": null,
  445. // "templateType": "1",
  446. // "productSkuName": null,
  447. // "productSkuCode": null
  448. // }
  449. // ],
  450. // "tradePrintList": null,
  451. // "platCode": "ZJ",
  452. // "purchaseId": null,
  453. // "purchaseStatus": null,
  454. // "supplierName": null,
  455. // "supplierId": null,
  456. // "purchaseName": null,
  457. // "offerId": null,
  458. // "specId": null,
  459. // "tradeClassify": "NORMAL",
  460. // "payType": "NORMAL",
  461. // "expressType": "NORMAL",
  462. // "msgTradeAttr": null,
  463. // "logisticsNames": null,
  464. // "logisticsTag": 0,
  465. // "tradeSource": null,
  466. // "printBatch": null,
  467. // "printBatchSn": 0,
  468. // "assignDeliveryId": null,
  469. // "factoryId": 100673,
  470. // "prepareShipGroupId": null,
  471. // "prepareShipDeliverStatus": null,
  472. // "prepareShipErrorMsg": null,
  473. // "prepareShipStatus": 0,
  474. // "prepareShipCreateTime": null,
  475. // "prepareShipUpdateTime": null,
  476. // "waybillEntities": [
  477. // {
  478. // "id": 7671095,
  479. // "dpAccountId": 100673,
  480. // "relationId": 3909499998804122,
  481. // "deliveryId": 3,
  482. // "waybillNo": "76767227765924",
  483. // "createdTime": "2025-11-27 15:11:27",
  484. // "recycleFlag": 0
  485. // }
  486. // ],
  487. // "relationId": 3909499998804122,
  488. // "optType": 0,
  489. // "obsStatus": 0,
  490. // "obsTime": null,
  491. // "obsReason": null,
  492. // "printFailReason": null
  493. // },