SyncDrugReportService.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. namespace App\Servers;
  3. use App\Models\DrugReportInfo;
  4. use App\Models\DrugReportAss;
  5. use App\Models\DrugReport;
  6. use App\Servers\Aliyun\Oss;
  7. use App\Servers\QueryDrugReportService;
  8. use Carbon\Carbon;
  9. use App\Facades\Servers\Logs\Log;
  10. use GuzzleHttp\Client;
  11. class SyncDrugReportService
  12. {
  13. /** @var string 查询上游企业的待签收药检报告信息 */
  14. const QUERY_DRUG_REPORT = 'querydrugreport';
  15. /** @var string 查询上传报告信息接口 */
  16. const QUERY_SEAL_DRUG_REPORT = 'querysealdrugreport';
  17. /** @var string 一张网报告操作日志 */
  18. const DRUG_REPORT_OPT_HISTORY = 'drugreport.opt.history';
  19. /** @var string 查询上游出库单 */
  20. const QUERY_DRUG_REPORT_ASS = 'querydrugreportass';
  21. /** @var Log */
  22. protected $log;
  23. /** @var QueryDrugReportService */
  24. protected $queryDrugReportService;
  25. protected $time;
  26. /**
  27. * 分批次同步数据
  28. * @param string $source
  29. * @param bool $isFull
  30. * @param string $startTime
  31. * @param string $endTime
  32. * @param int $page
  33. * @param int $pageSize
  34. * @return array
  35. */
  36. public function syncDrugReport(string $source, bool $isFull, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20,$isSeal=1)
  37. {
  38. $isFull = true;
  39. $total = 0;
  40. Log::error('syncDrug','开始全量同步:');
  41. $time = time();
  42. $oldEndTime = $endTime;
  43. if (empty($endTime)) {
  44. $endTime = Carbon::parse($startTime)->copy()->endOfMonth()->toDateTimeString();
  45. }
  46. $this->queryDrugReportService = new QueryDrugReportService();
  47. $count = 0;
  48. do {
  49. $month = Carbon::parse($startTime)->copy()->format('Ym');
  50. try {
  51. if (Carbon::parse($startTime)->isFuture()) {
  52. Log::error('syncDrug','时间大于当前时间,同步终止:');
  53. break;
  54. }
  55. sleep(1);
  56. // 分批次拉取数据
  57. $data = $this->queryDrugReport($source, $startTime, $endTime, $page, $pageSize, $isSeal);
  58. $total_num = $data['total_num'];
  59. $data = $data['data'];
  60. if ($page == 1){
  61. $count += $total_num;
  62. }
  63. if (empty($data)) {
  64. if ($isFull) {
  65. $next = Carbon::parse($startTime)->copy()->addMonth();
  66. $startTime = $next->startOfMonth()->toDateTimeString();
  67. $endTime = $next->endOfMonth()->toDateTimeString();
  68. $page = 1;
  69. continue;
  70. }
  71. break;
  72. }
  73. var_dump($startTime,$endTime,$count,$total_num,$page);
  74. // 处理并保存数据
  75. $saveCount = $this->saveDrugReport($source, $data, $isSeal);
  76. $total += $saveCount;
  77. // 检查是否还有更多数据
  78. if (count($data) <> $pageSize) {
  79. if ($isFull) {
  80. $next = Carbon::parse($startTime)->copy()->addMonth();
  81. $startTime = $next->startOfMonth()->toDateTimeString();
  82. $endTime = $next->endOfMonth()->toDateTimeString();
  83. $page = 1;
  84. continue;
  85. }
  86. break;
  87. }
  88. $page++;
  89. } catch (\Exception $e) {
  90. // continue;
  91. break;
  92. }
  93. } while (true);
  94. return ['total'=>$total,'count'=>$count];
  95. }
  96. /**
  97. * 查询药检报告数据
  98. * @param string $source
  99. * @param string $startTime
  100. * @param string $endTime
  101. * @param int $page
  102. * @param int $pageSize
  103. * @return array
  104. * @throws \Exception
  105. */
  106. protected function queryDrugReport(string $source, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20, $isSeal=1): array
  107. {
  108. if (self::QUERY_DRUG_REPORT == $source) {
  109. return $this->queryDrugReportService->queryDrugReport($startTime, $endTime, $page, $pageSize);
  110. }
  111. if (self::QUERY_SEAL_DRUG_REPORT == $source) {
  112. return $this->queryDrugReportService->querySealDrugReport($startTime, $endTime, $page, $pageSize,$isSeal);
  113. }
  114. if (self::DRUG_REPORT_OPT_HISTORY == $source) {
  115. $startDate = Carbon::parse($startTime)->copy()->toDateString();
  116. $endDate = Carbon::parse($endTime)->copy()->toDateString();
  117. return $this->queryDrugReportService->drugReportOptHistory($startDate, $endDate, $page, $pageSize);
  118. }
  119. if (self::QUERY_DRUG_REPORT_ASS == $source) {
  120. //$startDate = Carbon::parse($startTime)->copy()->toDateString();
  121. //$endDate = Carbon::parse($endTime)->copy()->toDateString();
  122. return $this->queryDrugReportService->querydrugreportass($startTime, $endTime, $page, $pageSize);
  123. }
  124. return [];
  125. }
  126. /**
  127. * 处理并保存批次数据
  128. * @param string $source
  129. * @param array $data
  130. * @return int
  131. */
  132. protected function saveDrugReport(string $source, array $data, $isSeal=1)
  133. {
  134. try {
  135. if (self::DRUG_REPORT_OPT_HISTORY == $source) {
  136. return $this->processDrugReportOptHistory($data);
  137. }
  138. if (self::QUERY_DRUG_REPORT_ASS == $source) {
  139. $data = $this->correctDrugReportAss($data);
  140. try {
  141. $DrugReport = new DrugReport();
  142. $a = $DrugReport::query()->insert($data);
  143. if (!$a){
  144. Log::error('syncDrug','添加数据失败:'.$a,$data);
  145. }
  146. }catch (\Throwable $exception){
  147. Log::error('syncDrug','添加数据失败',$data);
  148. dd($exception->getMessage());
  149. }
  150. return count($data);
  151. }
  152. if (self::QUERY_SEAL_DRUG_REPORT == $source) {
  153. $data = $this->correctSealDrugReport($data,$isSeal);
  154. try {
  155. $DrugReport = new DrugReportInfo();
  156. $a = $DrugReport::query()->insert($data);
  157. if (!$a){
  158. Log::error('syncDrug','添加数据失败:'.$a,$data);
  159. }
  160. }catch (\Throwable $exception){
  161. Log::error('syncDrug','添加数据失败',$data);
  162. dd($exception->getMessage());
  163. }
  164. return count($data);
  165. }
  166. return DrugReportInfo::bulkUpsert($data);
  167. } catch (\Throwable $e) {
  168. Log::error('syncDrug','添加数据失败:'.$e->getMessage(),$data);
  169. return 0;
  170. }
  171. }
  172. /**
  173. * 处理【待签收】医药报告批次数据
  174. * @param array $data
  175. * @return array
  176. */
  177. protected function correctDrugReport(array $data): array
  178. {
  179. return array_map(function ($item) {
  180. return [
  181. 'report_id' => $item['drug_report_id'] ?? '',
  182. 'batch_no' => $item['produce_batch_no'] ?? '',
  183. 'drug_id' => $item['drug_id'] ?? '',
  184. 'physic_name' => $item['physic_name'] ?? '',
  185. 'pkg_spec' => $item['pkg_spec'] ?? '',
  186. 'prepn_spec' => $item['prepn_spec'] ?? '',
  187. 'prepn_type_desc' => $item['prepn_type_desc'] ?? '',
  188. 'bill_type' => $item['bill_type'] ?? 0,
  189. 'bill_id' => $item['bill_id'] ?? '',
  190. 'bill_detail_id' => $item['bill_detail_id'] ?? '',
  191. 'bill_time' => $item['bill_time'] ?? '',
  192. 'bill_code' => $item['bill_code'] ?? '',
  193. 'produce_date' => $item['produce_date'] ?? '',
  194. 'produce_ent_id' => $item['produce_ent_id'] ?? '',
  195. 'produce_ent_name' => $item['produce_ent_name'] ?? '',
  196. 'ass_ref_ent_id' => $item['ass_ref_ent_id'] ?? '',
  197. 'from_ref_ent_id' => $item['from_ref_ent_id'] ?? '',
  198. 'from_ent_name' => $item['from_ent_name'] ?? '',
  199. 'report_url' => $item['sealed_report_url'] ?? '',
  200. // 'file_name' => $item['file_name'] ?? '',
  201. 'report_sign_status' => $item['drug_report_sign_status'] ?? '',
  202. 'raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
  203. ];
  204. }, $data);
  205. }
  206. /**
  207. * 处理【已签收】医药报告批次数据
  208. * @param array $data
  209. * @return array
  210. */
  211. /* protected function correctSealDrugReport(array $data): array
  212. {
  213. return array_map(function ($item) {
  214. return [
  215. 'report_v2_id' => $item['drug_report_v2_id'] ?? '',
  216. 'report_name' => $item['drug_report_name'] ?? '',
  217. 'report_no' => $item['report_no'] ?? '',
  218. 'report_date' => $item['report_date'] ?? '',
  219. 'batch_no' => $item['batch_no'] ?? '',
  220. 'drug_id' => $item['drug_ent_base_info_id'] ?? '',
  221. 'physic_name' => $item['physic_name'] ?? '',
  222. 'prod_code' => $item['prod_code'] ?? '',
  223. 'pkg_spec' => $item['pkg_spec'] ?? '',
  224. 'prepn_spec' => $item['prepn_spec'] ?? '',
  225. 'pkg_ratio_list' => json_encode($item['pkg_ratio_list'] ?? [], JSON_UNESCAPED_UNICODE),
  226. 'seal_report_url' => $item['sealed_report_url'] ?? '',
  227. 'seal_raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
  228. ];
  229. }, $data);
  230. }*/
  231. /**
  232. * 处理医药报告操作批次数据
  233. * @param array $data
  234. * @return int
  235. */
  236. protected function processDrugReportOptHistory(array $data): int
  237. {
  238. $count = 0;
  239. foreach ($data as $item) {
  240. try {
  241. // 操作类型(insertReport:新增报告、deleteReport:删除报告、sealReport:报告签章、updateReport:报告更新)
  242. $optType = $item['opt_type'];
  243. $drugReportInfo = DrugReportInfo::query()->where([
  244. 'batch_no' => $item['batch_no'],
  245. 'drug_id' => $item['drug_id'],
  246. ])->first();
  247. if (empty($drugReportInfo)) {
  248. $drugReportInfo = DrugReportInfo::create([
  249. 'batch_no' => $item['batch_no'],
  250. 'drug_id' => $item['drug_id'],
  251. 'report_v2_id' => $item['report_v2_id'],
  252. 'report_date' => $item['report_date'],
  253. 'report_name' => $item['report_name'],
  254. 'report_no' => $item['report_no'],
  255. ]);
  256. }
  257. switch ($optType) {
  258. case "deleteReport":
  259. $drugReportInfo->delete();
  260. break;
  261. case "sealReport":
  262. $optTime = Carbon::parse($item['opt_time']);
  263. $updateTime = Carbon::parse($drugReportInfo->update_time);
  264. if ($optTime->gt($updateTime)) {
  265. $drugReportInfo->is_sign = 1;
  266. $drugReportInfo->is_seal = 1;
  267. $drugReportInfo->sync_seal_opt = 1;
  268. }
  269. break;
  270. }
  271. $drugReportInfo->opt_raw_data = json_encode($item, JSON_UNESCAPED_UNICODE);
  272. $drugReportInfo->save();
  273. $count ++;
  274. } catch (\Exception $e) {
  275. log::info("保存数据项失败");
  276. continue;
  277. }
  278. }
  279. return $count;
  280. }
  281. /**
  282. * 处理【上游出库单】医药报告批次数据
  283. * @param array $data
  284. * @return array
  285. */
  286. public function correctDrugReportAss(array $data): array
  287. {
  288. $this->time = time();
  289. $list = [];
  290. foreach ($data as $item) {
  291. if (!empty($item['sealed_report_url'])) {
  292. $fileName = $item['physic_name'] . '_' . str_replace('/', '', $item['pkg_spec']) . '_' . $item['produce_batch_no'];
  293. $fileName = uniqid($fileName.'_').'.pdf';
  294. try {
  295. //上传报告pdf到oss
  296. $Oss = new Oss();
  297. $client = new Client(); // GuzzleHttp的客户端实例
  298. $response = $client->get($item['sealed_report_url']); // 下载文件
  299. $body = $response->getBody(); // 获取响应体
  300. $content = (string)$body; // 转换为字符串内容
  301. // 上传文件到OSS
  302. $ossPath = 'path/' . date('Y') . '/' . date('m') . '/' . $fileName;
  303. $res = $Oss->putObject($ossPath, $content);
  304. $item['sealed_report_url'] = $res;
  305. $item['file_name'] = $fileName;
  306. } catch (\Throwable $th) {
  307. var_dump('上传oss报表失败:' . $th->getMessage());
  308. Log::error('syncDrug/oss', '上传oss报表失败:' . $th->getMessage(), $item);
  309. }
  310. }
  311. $list[] = [
  312. 'bill_id' => $item['bill_id'] ?? '',//单据ID
  313. 'batch_no' => $item['produce_batch_no'] ?? '',//批号
  314. 'drug_id' => $item['drug_id'] ?? '',// 药品ID
  315. 'bill_type' => $item['bill_type'] ?? 0,//单据类型
  316. 'bill_detail_id' => $item['bill_detail_id'] ?? '',// 单据明细ID
  317. 'bill_time' => strtotime($item['bill_time']) ?? '',//单据时间
  318. 'pkg_spec' => $item['pkg_spec'] ?? '',//包装
  319. 'prepn_spec' => $item['prepn_spec'] ?? '',//制剂
  320. 'physic_name' => $item['physic_name'] ?? '',//药品名
  321. 'prepn_type_desc' => $item['prepn_type_desc'] ?? '',//剂型
  322. 'drug_report_sign_status' => $item['drug_report_sign_status'] ?? '',//报告状态(0 :待发送 2:待签收 3:已签收 4:已拒绝 7:对方已签收(更正待处理) 13:对方已拒绝(更正待签收))
  323. 'bill_code' => $item['bill_code'] ?? '',//单据编码
  324. 'produce_date' => strtotime($item['produce_date']) ?? '',// 生产日期
  325. 'produce_ent_id' => $item['produce_ent_id'] ?? '',//生产企业ID
  326. 'ass_ref_ent_id' => $item['ass_ref_ent_id'] ?? '',//委托企业
  327. 'report_name' => $item['file_name'] ?? '',//报告名称
  328. 'seal_report_url' => $item['sealed_report_url'] ?? '',//签章URL
  329. 'from_ref_ent_id' => $item['from_ref_ent_id'] ?? '',//发货企业id
  330. 'from_ent_name' => $item['from_ent_name'] ?? '',//发货企业名称
  331. 'crt_date' => strtotime($item['crt_date']) ?? '',//单据上传日期
  332. 'signed_time' => strtotime($item['signed_time']) ?? '',//签收时间
  333. 'seal_status' => $item['seal_status'] ?? '',//盖章状态 0:待盖章 5:已盖章 6:同批号已盖章
  334. 'report_id' => $item['drug_report_id'] ?? '',//报告ID
  335. 'produce_ent_name' => $item['produce_ent_name'] ?? '',//生产企业
  336. 'create_time' => $this->time,
  337. 'update_time' => $this->time,
  338. ];
  339. }
  340. return $list;
  341. }
  342. /**
  343. * 处理【本企业上传】医药报告批次数据
  344. * @param array $data
  345. * @return array
  346. */
  347. public function correctSealDrugReport(array $data,$isSeal=1): array
  348. {
  349. $this->time = time();
  350. $list = [];
  351. foreach ($data as $item) {
  352. if (!empty($item['sealed_report_url'])) {
  353. try {
  354. $fileName = $item['drug_name'] . '_' . str_replace('/', '', $item['pkg_spec']) . '_' . $item['batch_no'];
  355. $fileName = uniqid($fileName.'_').'.pdf';
  356. //上传报告pdf到oss
  357. $Oss = new Oss();
  358. $client = new Client(); // GuzzleHttp的客户端实例
  359. $response = $client->get($item['sealed_report_url']); // 下载文件
  360. $body = $response->getBody(); // 获取响应体
  361. $content = (string)$body; // 转换为字符串内容
  362. // 上传文件到OSS
  363. $ossPath = 'local/' . date('Y') . '/' . date('m') . '/' . $fileName;
  364. $res = $Oss->putObject($ossPath, $content);
  365. $item['sealed_report_url'] = $res;
  366. $item['file_name'] = $fileName;
  367. } catch (\Throwable $th) {
  368. var_dump('上传oss报表失败:' . $th->getMessage());
  369. Log::error('syncDrug/oss', '上传oss报表失败:' . $th->getMessage(), $item);
  370. }
  371. }
  372. $list[] = [
  373. 'report_id' => $item['report_id'] ?? '',
  374. 'report_v2_id' => $item['drug_report_v2_id'] ?? '',
  375. 'report_name' => $item['file_name'] ?? '',
  376. 'report_no' => $item['report_no'] ?? '',
  377. 'report_date' => $item['report_date'] ?? '',
  378. 'batch_no' => $item['batch_no'] ?? '',
  379. 'drug_id' => $item['drug_ent_base_info_id'] ?? '',
  380. 'physic_name' => $item['drug_name'] ?? '',
  381. 'prod_code' => $item['prod_code'] ?? '',
  382. 'pkg_spec' => $item['pkg_spec'] ?? '',
  383. 'prepn_spec' => $item['prepn_spec'] ?? '',
  384. 'seal_report_url' => $item['sealed_report_url'] ?? '',
  385. 'is_seal' => $isSeal,
  386. 'create_time'=>$this->time,
  387. 'update_time'=>$this->time,
  388. ];
  389. }
  390. return $list;
  391. }
  392. }