LogisticService.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. namespace App\Services;
  3. use App\Interfaces\UserFilter;
  4. use App\Logistic;
  5. use App\OracleBasCustomer;
  6. use Carbon\Carbon;
  7. use Illuminate\Database\Eloquent\Builder;
  8. use Illuminate\Support\Facades\Auth;
  9. use Illuminate\Support\Facades\Cache;
  10. use Illuminate\Support\Str;
  11. use App\Traits\ServiceAppAop;
  12. class LogisticService implements UserFilter
  13. {
  14. use ServiceAppAop;
  15. protected $modelClass=Logistic::class;
  16. /** @var CacheService $cacheService */
  17. private $cacheService;
  18. function __construct(){
  19. $this->instant($this->cacheService,'CacheService');
  20. }
  21. public function getSelection($column = ['id','name'], $type = '快递'){
  22. return $this->cacheService->getOrExecute('LogisticAll_'.implode("",$column).Str::studly($type),function()use($column,$type){
  23. $query = Logistic::query()->select($column);
  24. if ($type)$query->where(function ($query)use($type){
  25. /** @var Builder $query */
  26. $query->where("type",$type)->orWhere("type","全部");
  27. });
  28. return $query->get();
  29. },config('cache.expirations.rarelyChange'));
  30. }
  31. public function firstOrCreate(array $params, array $values = null){
  32. return $this->cacheService->getOrExecute('LogisticFirstOrCreate'.md5(json_encode($params).json_encode($values)),function()use($params,$values){
  33. $logistic = Logistic::query();
  34. if ($values)return $logistic->firstOrCreate($params, $values);
  35. return $logistic->firstOrCreate($params);
  36. },config('cache.expirations.commonFrequent'));
  37. }
  38. public function getByWmsOrders($orderHeaders){
  39. $codes = data_get($orderHeaders,'*.userdefine1');
  40. $codes = array_unique($codes);
  41. $codes = array_diff($codes,['','*',null]);
  42. if(!$codes){return [];}
  43. $logistics = Logistic::query()->whereIn('code',$codes)->get();
  44. if($logistics->count() < count($codes)){
  45. $codes = array_diff($codes,data_get($logistics,'*.code'));
  46. $logistic_list = $this->createLogisticByCarrierIds($codes);
  47. $logistics = $logistics->concat($logistic_list);
  48. }
  49. return $logistics;
  50. }
  51. public function createLogisticByCarrierIds($codes){
  52. if(!$codes){return [];}
  53. $baseCustomers = OracleBasCustomer::query()
  54. ->selectRaw('Customer_Type,CustomerID,Descr_C')
  55. ->where('Customer_Type','CA')
  56. ->whereIn('CustomerID',$codes)
  57. ->get();
  58. $insert_params = [];
  59. $created_at = Carbon::now()->format('Y-m-d H:i:s');
  60. foreach ($baseCustomers as $baseCustomer) {
  61. $insert_params[] = [
  62. 'code' => $baseCustomer['customerid'],
  63. 'name' => $baseCustomer['descr_c'],
  64. 'created_at' => $created_at
  65. ];
  66. }
  67. try {
  68. if(count($insert_params) > 0){
  69. $this->insert($insert_params);
  70. LogService::log(__METHOD__, __FUNCTION__, '批量创建 Logistic ' . count($insert_params) . json_encode($insert_params) );
  71. }
  72. } catch (\Exception $e) {
  73. LogService::log(__METHOD__, __FUNCTION__, '批量创建 Logistic error' . json_encode($insert_params) . "||".$e->getMessage() . '||' . $e->getTraceAsString() );
  74. } finally {
  75. return Logistic::query()->whereIn('code',$codes)->get();
  76. }
  77. }
  78. public function find($id)
  79. {
  80. return Logistic::query()->find($id);
  81. }
  82. public function getLogisticByCodes($codes)
  83. {
  84. $collect = collect();
  85. if(count($codes) == 0) return $collect;
  86. foreach ($codes as $code) {
  87. $collect->push($this->getLogisticByCode($code));
  88. }
  89. return $collect;
  90. }
  91. public function getLogisticByCode($code){
  92. return Cache::remember("getLogisticByCode_{$code}", config('cache.expirations.rarelyChange'), function()use($code){
  93. $logistic = Logistic::query()->where('code',$code)->first();
  94. if($logistic)return $logistic;
  95. $baseCustomers = app('OracleBasCustomerService')->first(['Customer_Type'=>'CA','CustomerID'=>$code]);
  96. if(!$baseCustomers)return null;
  97. try {
  98. $logistic = Logistic::query()->create(['name' => $baseCustomers['descr_c'], 'code' => $baseCustomers['customerid']]);
  99. app('LogService')->log(__METHOD__, __FUNCTION__,'创建Logistic SUCCESS'." || ". json_encode($logistic));
  100. return $logistic;
  101. } catch (\Exception $e) {
  102. app('LogService')->log(__METHOD__, __FUNCTION__,'创建Logistic ERROR'." || ". json_encode($logistic)." || ".json_encode($e->getMessage())." || ".json_encode($e->getTraceAsString()));
  103. return null;
  104. }
  105. });
  106. }
  107. function getIdArr(?int $userId = null): array
  108. {
  109. if (!$userId)$userId = Auth::id();
  110. return $this->cacheService->getOrExecute("USER.{$userId}.LOGISTIC.ID", function () use ($userId) {
  111. return array_column($this->getQuery($userId)->get()->toArray(),"id");
  112. });
  113. }
  114. function getCodeArr(?int $userId): array
  115. {
  116. return [];
  117. }
  118. function getQuery(?int $userId = null, $column = "id"): Builder
  119. {
  120. if (!$userId)$userId = Auth::id();
  121. $query = Logistic::query()->select($column);
  122. if (!app("UserService")->checkAdminIdentity($userId)){
  123. $query->whereHas("users",function ($query)use($userId){
  124. $query->where("users.id",$userId);
  125. });
  126. }
  127. return $query;
  128. }
  129. /**
  130. * 断言快递单号所属快递公司
  131. *
  132. * @param string $logisticNumber
  133. * @param bool $multi
  134. *
  135. * @return string|array
  136. */
  137. public function assertExpressCompany(string $logisticNumber, bool $multi = false)
  138. {
  139. $mapping = [
  140. "顺丰" => [
  141. [
  142. "header" => "SF",
  143. "length" => 15,
  144. ],
  145. [
  146. "length" => 12,
  147. "type" => "numeric",
  148. ],
  149. ], "圆通" => [
  150. [
  151. "header" => "YT",
  152. "length" => 15,
  153. ],
  154. [
  155. "length" => 13,
  156. "type" => "numeric",
  157. "multiHeader" => ["61","71","81"],
  158. ],
  159. ], "中通" => [
  160. [
  161. "length" => 12,
  162. "type" => "numeric",
  163. "multiHeader" => ["54","21"],
  164. ],
  165. [
  166. "length" => 14,
  167. "type" => "numeric",
  168. "multiHeader" => ["75","78","73",'74'],
  169. ],
  170. ],"韵达" => [
  171. [
  172. "length" => 13,
  173. "type" => "numeric",
  174. "multiHeader" => ["46","43","42","35","120",'318','530','570'],
  175. ],
  176. [
  177. "length" => 15,
  178. "type" => "numeric",
  179. "multiHeader" => ["46","43","31"],
  180. ],
  181. ], "京东" => [
  182. [
  183. "header" => "JD",
  184. ],
  185. ], "邮政" => [
  186. [
  187. "length" => 13,
  188. "type" => "numeric",
  189. "multiHeader" => ["11","98"],
  190. ],
  191. [
  192. "length" => 13,
  193. "header" => "KH",
  194. ],
  195. ], "极兔" => [
  196. [
  197. "header" => "JT",
  198. ]
  199. ], "跨越" => [
  200. [
  201. "header" => "KY",
  202. "length" => 15,
  203. ],
  204. [
  205. "length" => 11,
  206. "type" => "numeric",
  207. "multiHeader" => ["80"],
  208. ],
  209. ], "申通" => [
  210. [
  211. "multiHeader" => ["77"],
  212. "type" => "numeric",
  213. "length" => 15,
  214. ],
  215. [
  216. "multiHeader" => ["660"],
  217. "type" => "numeric",
  218. "length" => 13,
  219. ],
  220. ], "百世" => [
  221. [
  222. "multiHeader" => ["55"],
  223. "type" => "numeric",
  224. "length" => 15,
  225. ]
  226. ], "EMS" => [
  227. [
  228. "multiHeader" => ["97","10","95","96","99"],
  229. "type" => "numeric",
  230. "length" => 13,
  231. ],
  232. ], "德邦" => [
  233. [
  234. "header" => "DPK",
  235. "length" => 15,
  236. ],
  237. ]
  238. ];
  239. $result = $multi ? [] : "";
  240. foreach ($mapping as $name=>$rules){
  241. foreach ($rules as $rule){
  242. if (!$this->matchingNumber($logisticNumber,$rule))continue;
  243. if ($multi)$result[] = $name;
  244. else return $name;
  245. }
  246. }
  247. return $result;
  248. }
  249. public function matchingNumber(string $logisticNumber, array $rule):bool
  250. {
  251. $len = mb_strlen($logisticNumber);
  252. $match = function (string $key, $val)use($logisticNumber,$len){
  253. switch ($key){
  254. case "header":
  255. return Str::upper(mb_substr($logisticNumber,0,mb_strlen($val))) === $val;
  256. case "length":
  257. return $len==$val;
  258. case "multiHeader":
  259. foreach ($val as $item)if (mb_substr($logisticNumber,0,mb_strlen($item)) === $item)return true;
  260. return false;
  261. case "type":
  262. try {
  263. return eval("return is_{$val}('$logisticNumber');");
  264. }catch (\ParseError $e){
  265. return false;
  266. }
  267. default:
  268. return false;
  269. }
  270. };
  271. foreach ($rule as $key=>$val)if (!$match($key,$val))return false;
  272. return true;
  273. }
  274. }