SyncSealDrugReportService.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <?php
  2. namespace App\Services;
  3. use App\Models\DrugReportInfo;
  4. use Carbon\Carbon;
  5. use Illuminate\Support\Facades\Log;
  6. class SyncSealDrugReportService
  7. {
  8. /** @var string 查询上游企业的待签收药检报告信息 */
  9. const QUERY_DRUG_REPORT = 'querydrugreport';
  10. /** @var string 查询上传报告信息接口 */
  11. const QUERY_SEAL_DRUG_REPORT = 'querysealdrugreport';
  12. /** @var string 一张网报告操作日志 */
  13. const DRUG_REPORT_OPT_HISTORY = 'drugreport.opt.history';
  14. protected $log;
  15. /** @var QueryDrugReportService */
  16. protected $queryDrugReportService;
  17. /**
  18. * 检查同步来源
  19. * @param string $source
  20. * @return bool
  21. */
  22. protected function checkSource(string $source): bool
  23. {
  24. return (in_array($source, [
  25. self::QUERY_DRUG_REPORT,
  26. self::QUERY_SEAL_DRUG_REPORT,
  27. self::DRUG_REPORT_OPT_HISTORY]));
  28. }
  29. /**
  30. * 根据来源设置日志频道
  31. * @param string $source
  32. * @return void
  33. */
  34. protected function setLog(string $source)
  35. {
  36. if (self::QUERY_SEAL_DRUG_REPORT == $source) {
  37. $this->log = Log::channel('sync_seal');
  38. } elseif (self::DRUG_REPORT_OPT_HISTORY == $source) {
  39. $this->log = Log::channel('sync_opt');
  40. } else {
  41. $this->log = Log::channel('sync');
  42. }
  43. }
  44. /**
  45. * 分批次同步数据
  46. * @param string $source
  47. * @param bool $isFull
  48. * @param string $startTime
  49. * @param string $endTime
  50. * @param int $page
  51. * @param int $pageSize
  52. * @return int
  53. */
  54. public function syncDrugReport(string $source, bool $isFull, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20): int
  55. {
  56. if (!$this->checkSource($source)) {
  57. $this->log->error("来源[source]不正确,无法进行同步", [
  58. 'source' => $source,
  59. 'params' => [
  60. 'is_full' => $isFull,
  61. 'start_time' => $startTime,
  62. 'end_time' => $endTime,
  63. 'page' => $page,
  64. 'page_size' => $pageSize,
  65. ],
  66. ]);
  67. return 0;
  68. }
  69. $this->setLog($source);
  70. $total = 0;
  71. $this->log->notice($isFull ? "开始全量同步" : "开始增量同步", [
  72. 'source' => $source,
  73. 'params' => [
  74. 'is_full' => $isFull,
  75. 'start_time' => $startTime,
  76. 'end_time' => $endTime,
  77. 'page' => $page,
  78. 'page_size' => $pageSize,
  79. ],
  80. ]);
  81. if (empty($endTime)) {
  82. $endTime = Carbon::parse($startTime)->copy()->endOfMonth()->toDateTimeString();
  83. }
  84. $this->queryDrugReportService = app(QueryDrugReportService::class);
  85. do {
  86. $month = Carbon::parse($startTime)->copy()->format('Ym');
  87. try {
  88. if (Carbon::parse($startTime)->isFuture()) {
  89. $this->log->warning("时间大于当前时间,同步终止", [
  90. 'source' => $source,
  91. 'params' => [
  92. 'is_full' => $isFull,
  93. 'start_time' => $startTime,
  94. 'end_time' => $endTime,
  95. 'page' => $page,
  96. 'page_size' => $pageSize,
  97. ]
  98. ]);
  99. break;
  100. }
  101. $this->log->info("批次 {$month}[{$page}] 开始处理", [
  102. 'source' => $source,
  103. 'params' => [
  104. 'is_full' => $isFull,
  105. 'start_time' => $startTime,
  106. 'end_time' => $endTime,
  107. 'page' => $page,
  108. 'page_size' => $pageSize,
  109. ]
  110. ]);
  111. // 分批次拉取数据
  112. $data = $this->queryDrugReport($source, $startTime, $endTime, $page, $pageSize);
  113. if (empty($data)) {
  114. $this->log->warning("批次 {$month}[{$page}] 没有数据", [
  115. 'source' => $source,
  116. 'params' => [
  117. 'is_full' => $isFull,
  118. 'start_time' => $startTime,
  119. 'end_time' => $endTime,
  120. 'page' => $page,
  121. 'page_size' => $pageSize,
  122. ]
  123. ]);
  124. if ($isFull) {
  125. $next = Carbon::parse($startTime)->copy()->addMonth();
  126. $startTime = $next->startOfMonth()->toDateTimeString();
  127. $endTime = $next->endOfMonth()->toDateTimeString();
  128. $page = 1;
  129. continue;
  130. }
  131. break;
  132. }
  133. // 处理并保存数据
  134. $saveCount = $this->saveDrugReport($source, $data);
  135. $total += $saveCount;
  136. $this->log->info("批次 {$month}[{$page}] 处理完成", [
  137. 'source' => $source,
  138. 'fetch_count' => count($data),
  139. 'save_count' => $saveCount,
  140. 'total' => $total,
  141. ]);
  142. // 检查是否还有更多数据
  143. if (count($data) <> $pageSize) {
  144. if ($isFull) {
  145. $next = Carbon::parse($startTime)->copy()->addMonth();
  146. $startTime = $next->startOfMonth()->toDateTimeString();
  147. $endTime = $next->endOfMonth()->toDateTimeString();
  148. $page = 1;
  149. continue;
  150. }
  151. break;
  152. }
  153. $page++;
  154. // 避免请求过于频繁
  155. sleep(1);
  156. } catch (\Exception $e) {
  157. $this->log->error("批次 {$month}[{$page}] 数据获取失败", [
  158. 'source' => $source,
  159. 'params' => [
  160. 'is_full' => $isFull,
  161. 'start_time' => $startTime,
  162. 'end_time' => $endTime,
  163. 'page' => $page,
  164. 'page_size' => $pageSize,
  165. ],
  166. 'error' => $e->getMessage()
  167. ]);
  168. // continue;
  169. break;
  170. }
  171. } while (true);
  172. $this->log->notice($isFull ? "全量同步完成" : "增量同步完成", [
  173. 'source' => $source,
  174. 'total' => $total
  175. ]);
  176. return $total;
  177. }
  178. /**
  179. * 查询药检报告数据
  180. * @param string $source
  181. * @param string $startTime
  182. * @param string $endTime
  183. * @param int $page
  184. * @param int $pageSize
  185. * @return array
  186. * @throws \Exception
  187. */
  188. protected function queryDrugReport(string $source, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20): array
  189. {
  190. if (self::QUERY_DRUG_REPORT == $source) {
  191. return $this->queryDrugReportService->queryDrugReport($startTime, $endTime, $page, $pageSize);
  192. }
  193. if (self::QUERY_SEAL_DRUG_REPORT == $source) {
  194. return $this->queryDrugReportService->querySealDrugReport($startTime, $endTime, $page, $pageSize);
  195. }
  196. if (self::DRUG_REPORT_OPT_HISTORY == $source) {
  197. $startDate = Carbon::parse($startTime)->copy()->toDateString();
  198. $endDate = Carbon::parse($endTime)->copy()->toDateString();
  199. return $this->queryDrugReportService->drugReportOptHistory($startDate, $endDate, $page, $pageSize);
  200. }
  201. return [];
  202. }
  203. /**
  204. * 处理并保存批次数据
  205. * @param string $source
  206. * @param array $data
  207. * @return int
  208. */
  209. protected function saveDrugReport(string $source, array $data): int
  210. {
  211. try {
  212. if (self::QUERY_SEAL_DRUG_REPORT == $source) {
  213. $data = $this->correctSealDrugReport($data);
  214. } elseif (self::DRUG_REPORT_OPT_HISTORY == $source) {
  215. $data = $this->correctDrugReportOptHistory($data);
  216. } else {
  217. $data = $this->correctDrugReport($data);
  218. }
  219. return DrugReportInfo::bulkUpsert($data);
  220. } catch (\Throwable $e) {
  221. $this->log->error("保存批次数据失败", [
  222. 'data' => $data,
  223. 'error' => $e->getMessage()
  224. ]);
  225. return 0;
  226. }
  227. }
  228. /**
  229. * 处理【待签收】医药报告批次数据
  230. * @param array $data
  231. * @return array
  232. */
  233. protected function correctDrugReport(array $data): array
  234. {
  235. return array_map(function ($item) {
  236. return [
  237. 'report_id' => $item['drug_report_id'] ?? '',
  238. 'batch_no' => $item['produce_batch_no'] ?? '',
  239. 'drug_id' => $item['drug_id'] ?? '',
  240. 'drug_name' => $item['physic_name'] ?? '',
  241. 'pkg_spec' => $item['pkg_spec'] ?? '',
  242. 'prepn_spec' => $item['prepn_spec'] ?? '',
  243. 'prepn_type_desc' => $item['prepn_type_desc'] ?? '',
  244. 'bill_type' => $item['bill_type'] ?? 0,
  245. 'bill_id' => $item['bill_id'] ?? '',
  246. 'bill_detail_id' => $item['bill_detail_id'] ?? '',
  247. 'bill_time' => $item['bill_time'] ?? '',
  248. 'bill_code' => $item['bill_code'] ?? '',
  249. 'produce_date' => $item['produce_date'] ?? '',
  250. 'produce_ent_id' => $item['produce_ent_id'] ?? '',
  251. 'produce_ent_name' => $item['produce_ent_name'] ?? '',
  252. 'ass_ref_ent_id' => $item['ass_ref_ent_id'] ?? '',
  253. 'from_ref_ent_id' => $item['from_ref_ent_id'] ?? '',
  254. 'from_ent_name' => $item['from_ent_name'] ?? '',
  255. 'report_url' => $item['sealed_report_url'] ?? '',
  256. // 'file_name' => $item['file_name'] ?? '',
  257. 'report_sign_status' => $item['drug_report_sign_status'] ?? '',
  258. 'raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
  259. ];
  260. }, $data);
  261. }
  262. /**
  263. * 处理【已签收】医药报告批次数据
  264. * @param array $data
  265. * @return array
  266. */
  267. protected function correctSealDrugReport(array $data): array
  268. {
  269. return array_map(function ($item) {
  270. return [
  271. 'report_v2_id' => $item['drug_report_v2_id'] ?? '',
  272. 'report_name' => $item['drug_report_name'] ?? '',
  273. 'report_no' => $item['report_no'] ?? '',
  274. 'report_date' => $item['report_date'] ?? '',
  275. 'batch_no' => $item['batch_no'] ?? '',
  276. 'drug_id' => $item['drug_ent_base_info_id'] ?? '',
  277. 'drug_name' => $item['drug_name'] ?? '',
  278. 'prod_code' => $item['prod_code'] ?? '',
  279. 'pkg_spec' => $item['pkg_spec'] ?? '',
  280. 'prepn_spec' => $item['prepn_spec'] ?? '',
  281. 'pkg_ratio_list' => json_encode($item['pkg_ratio_list'] ?? [], JSON_UNESCAPED_UNICODE),
  282. 'seal_report_url' => $item['sealed_report_url'] ?? '',
  283. 'seal_raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
  284. ];
  285. }, $data);
  286. }
  287. /**
  288. * 处理医药报告操作批次数据
  289. * @param array $data
  290. * @return array
  291. */
  292. protected function correctDrugReportOptHistory(array $data): array
  293. {
  294. return array_map(function ($item) {
  295. return [
  296. 'batch_no' => $item['batch_no'] ?? '',
  297. 'drug_id' => $item['drug_id'] ?? '',
  298. 'opt_raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
  299. ];
  300. }, $data);
  301. }
  302. }