Ver Fonte

全量同步流程优化

LAPTOP-VT1IP978\suxio há 2 semanas atrás
pai
commit
88ae4d381d

+ 12 - 0
README.md

@@ -1 +1,13 @@
 # 电子药检报告
+
+```bash
+php artisan sync:drug-report --source=querydrugreport --full --start-time="2025-01-01 00:00:00"
+```
+
+```bash
+php artisan sync:drug-report --source=querysealdrugreport --full --start-time="2025-03-01 00:00:00"
+```
+
+```bash
+php artisan sync:drug-report --source=drugreport.opt.history --full --start-time="2025-03-01 00:00:00"
+```

+ 10 - 5
app/Console/Commands/SyncSealDrugReportCommand.php

@@ -8,22 +8,27 @@ use Illuminate\Console\Command;
 
 class SyncSealDrugReportCommand extends Command
 {
-    // php artisan sync:seal-drug-report --full --start-time="2025-03-01 00:00:00" --end-time="2025-03-31 23:59:59"
-    protected $signature = 'sync:seal-drug-report {--full : 全量模式} {--start-time= : 开始时间} {--end-time= : 结束时间} {--page=1} {--page-size=20}';
+    protected $signature = 'sync:drug-report {--source= : 来源} {--full : 全量模式} {--start-time= : 开始时间} {--end-time= : 结束时间} {--page=1 : 当前页码} {--page-size=20 : 每页大小}';
 
-    protected $description = '同步已签收药检报告数据';
+    protected $description = '同步药检报告数据';
 
     public function handle(SyncSealDrugReportService $service): int
     {
+        $source = $this->option('source');
         $isFull = (bool)$this->option('full');
         $startTime = $this->option('start-time') ?? Carbon::today()->startOfDay();
-        $endTime = $this->option('end-time')/* ?? Carbon::now()*/;
+        $endTime = $this->option('end-time') ?? ''; // Carbon::now()
         $page = $this->option('page') ?? 1;
         $pageSize = $this->option('page-size') ?? 20;
 
+        if (empty($source)) {
+            echo "参数错误,未指定来源[source]", PHP_EOL;
+            return Command::FAILURE;
+        }
+
         echo $isFull ? "全量同步开始" : "增量同步开始", sprintf('[%d, %s, %s, %d, %d]……', $isFull, $startTime, $endTime, $page, $pageSize), PHP_EOL;
 
-        $count = $service->syncSealDrugReport($isFull, $startTime, $endTime, $page, $pageSize);
+        $count = $service->syncDrugReport($source, $isFull, $startTime, $endTime, $page, $pageSize);
 
         echo $isFull ? "全量同步结束" : "增量同步结束", ",共处理 {$count} 条记录!", PHP_EOL;
 

+ 9 - 6
app/Models/DrugReportInfo.php

@@ -13,9 +13,8 @@ use Illuminate\Support\Facades\DB;
  * App\Models\DrugReportInfo
  *
  * @property int $id
- * @property string $drug_report_v2_id 药检报告ID(来源于querysealdrugreport)
  * @property string $drug_report_id 报告ID(来源于querydrugreport)
- * @property string $report_id 报告ID(来源于querysealdrugreport)
+ * @property string $report_id 报告ID
  * @property string $report_name 报告名称
  * @property string $report_no 报告编号
  * @property string $report_date 报告日期
@@ -39,8 +38,10 @@ use Illuminate\Support\Facades\DB;
  * @property string $from_ref_ent_id 发货企业ID
  * @property string $from_ent_name 发货企业
  * @property string $sealed_report_url 盖章报告URL
- * @property array|null $raw_data 待签收原始数据(来源于querydrugreport)
- * @property array|null $seal_raw_data 已签收原始数据(来源于querysealdrugreport)
+ * @property string $report_sign_status 报告签收状态(0-待发送、2-待签收、3-已签收、4-已拒绝、7-对方已签收/更正待处理、13-对方已拒绝/更正待签收)
+ * @property array|null $raw_data 报告待签收原始数据(来源querydrugreport)
+ * @property array|null $seal_raw_data 报告已签收原始数据(来源querysealdrugreport)
+ * @property array|null $opt_raw_data 报告操作原始数据(来源drugreport.opt.history)
  * @property int $is_sign 是否签收(1-未签收、2-已签收)
  * @property int $is_seal 是否盖章(1-未盖章、2-已盖章)
  * @property Carbon $create_time 创建时间
@@ -62,12 +63,12 @@ use Illuminate\Support\Facades\DB;
  * @method static Builder|DrugReportInfo whereDrugId($value)
  * @method static Builder|DrugReportInfo whereDrugName($value)
  * @method static Builder|DrugReportInfo whereDrugReportId($value)
- * @method static Builder|DrugReportInfo whereDrugReportV2Id($value)
  * @method static Builder|DrugReportInfo whereFromEntName($value)
  * @method static Builder|DrugReportInfo whereFromRefEntId($value)
  * @method static Builder|DrugReportInfo whereId($value)
  * @method static Builder|DrugReportInfo whereIsSeal($value)
  * @method static Builder|DrugReportInfo whereIsSign($value)
+ * @method static Builder|DrugReportInfo whereOptRawData($value)
  * @method static Builder|DrugReportInfo wherePkgRatioList($value)
  * @method static Builder|DrugReportInfo wherePkgSpec($value)
  * @method static Builder|DrugReportInfo wherePrepnSpec($value)
@@ -81,6 +82,7 @@ use Illuminate\Support\Facades\DB;
  * @method static Builder|DrugReportInfo whereReportId($value)
  * @method static Builder|DrugReportInfo whereReportName($value)
  * @method static Builder|DrugReportInfo whereReportNo($value)
+ * @method static Builder|DrugReportInfo whereReportSignStatus($value)
  * @method static Builder|DrugReportInfo whereSealRawData($value)
  * @method static Builder|DrugReportInfo whereSealedReportUrl($value)
  * @method static Builder|DrugReportInfo whereUpdateTime($value)
@@ -102,16 +104,17 @@ class DrugReportInfo extends Model
         'pkg_ratio_list' => 'array',
         'raw_data' => 'array',
         'seal_raw_data' => 'array',
+        'opt_raw_data' => 'array',
     ];
 
     protected $hidden = [
         'create_time',
         'update_time',
-        'drug_report_v2_id',
         'drug_report_id',
         'pkg_ratio_list',
         'raw_data',
         'seal_raw_data',
+        'opt_raw_data',
     ];
 
     /**

+ 12 - 0
app/Services/QueryDrugReportService.php

@@ -55,6 +55,10 @@ class QueryDrugReportService
             throw new \Exception($resp->res_result->msg_info);
         }
 
+        if (!isset($resp->res_result->model->result->onenet_drug_report_top_d_t_o)) {
+            return [];
+        }
+
         return json_decode(json_encode(
             $resp->res_result->model->result->onenet_drug_report_top_d_t_o
         ), true);
@@ -89,6 +93,10 @@ class QueryDrugReportService
             throw new \Exception($resp->result->msg_info);
         }
 
+        if (!isset($resp->result->model->result_list->ocr_seal_drug_report_d_t_o)) {
+            return [];
+        }
+
         return json_decode(json_encode(
             $resp->result->model->result_list->ocr_seal_drug_report_d_t_o
         ), true);
@@ -120,6 +128,10 @@ class QueryDrugReportService
             throw new \Exception($resp->result->msg_info);
         }
 
+        if (!isset($resp->result->model->result_list->top_drug_report_opt_log)) {
+            return [];
+        }
+
         return json_decode(json_encode(
             $resp->result->model->result_list->top_drug_report_opt_log
         ), true);

+ 189 - 34
app/Services/SyncSealDrugReportService.php

@@ -8,10 +8,53 @@ use Illuminate\Support\Facades\Log;
 
 class SyncSealDrugReportService
 {
-    protected $source = 'querysealdrugreport';
+    /** @var string 查询上游企业的待签收药检报告信息 */
+    const QUERY_DRUG_REPORT = 'querydrugreport';
+
+    /** @var string 查询上传报告信息接口 */
+    const QUERY_SEAL_DRUG_REPORT = 'querysealdrugreport';
+
+    /** @var string 一张网报告操作日志 */
+    const DRUG_REPORT_OPT_HISTORY = 'drugreport.opt.history';
+
+    protected $log;
+
+    /** @var QueryDrugReportService */
+    protected $queryDrugReportService;
+
+    /**
+     * 检查同步来源
+     * @param string $source
+     * @return bool
+     */
+    protected function checkSource(string $source): bool
+    {
+        return (in_array($source, [
+            self::QUERY_DRUG_REPORT,
+            self::QUERY_SEAL_DRUG_REPORT,
+            self::DRUG_REPORT_OPT_HISTORY]));
+    }
+
+    /**
+     * 根据来源设置日志频道
+     * @param string $source
+     * @return void
+     */
+    protected function setLog(string $source)
+    {
+        if (self::QUERY_SEAL_DRUG_REPORT == $source) {
+            $this->log = Log::channel('sync_seal');
+        } elseif (self::DRUG_REPORT_OPT_HISTORY == $source) {
+            $this->log = Log::channel('sync_opt');
+        } else {
+            $this->log = Log::channel('sync');
+        }
+    }
+
 
     /**
      * 分批次同步数据
+     * @param string $source
      * @param bool $isFull
      * @param string $startTime
      * @param string $endTime
@@ -19,13 +62,28 @@ class SyncSealDrugReportService
      * @param int $pageSize
      * @return int
      */
-    public function syncSealDrugReport(bool $isFull, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20): int
+    public function syncDrugReport(string $source, bool $isFull, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20): int
     {
-        $hasMore = true;
+        if (!$this->checkSource($source)) {
+            $this->log->error("来源[source]不正确,无法进行同步", [
+                'source' => $source,
+                'params' => [
+                    'is_full' => $isFull,
+                    'start_time' => $startTime,
+                    'end_time' => $endTime,
+                    'page' => $page,
+                    'page_size' => $pageSize,
+                ],
+            ]);
+            return 0;
+        }
+
+        $this->setLog($source);
+
         $total = 0;
 
-        Log::channel('sync')->warning($isFull ? "开始全量同步" : "开始增量同步", [
-            'source' => $this->source,
+        $this->log->notice($isFull ? "开始全量同步" : "开始增量同步", [
+            'source' => $source,
             'params' => [
                 'is_full' => $isFull,
                 'start_time' => $startTime,
@@ -39,13 +97,14 @@ class SyncSealDrugReportService
             $endTime = Carbon::parse($startTime)->copy()->endOfMonth()->toDateTimeString();
         }
 
-        $queryDrugReportService = app(QueryDrugReportService::class);
+        $this->queryDrugReportService = app(QueryDrugReportService::class);
 
-        while ($hasMore) {
+        do {
+            $month = Carbon::parse($startTime)->copy()->format('Ym');
             try {
                 if (Carbon::parse($startTime)->isFuture()) {
-                    Log::channel('sync')->warning("时间大于当前时间,同步终止", [
-                        'source' => $this->source,
+                    $this->log->warning("时间大于当前时间,同步终止", [
+                        'source' => $source,
                         'params' => [
                             'is_full' => $isFull,
                             'start_time' => $startTime,
@@ -57,8 +116,8 @@ class SyncSealDrugReportService
                     break;
                 }
 
-                Log::channel('sync')->info("批次 {$page} 开始处理", [
-                    'source' => $this->source,
+                $this->log->info("批次 {$month}[{$page}] 开始处理", [
+                    'source' => $source,
                     'params' => [
                         'is_full' => $isFull,
                         'start_time' => $startTime,
@@ -69,10 +128,10 @@ class SyncSealDrugReportService
                 ]);
 
                 // 分批次拉取数据
-                $data = $queryDrugReportService->querySealDrugReport($startTime, $endTime, $page, $pageSize);
+                $data = $this->queryDrugReport($source, $startTime, $endTime, $page, $pageSize);
                 if (empty($data)) {
-                    Log::channel('sync')->warning("批次 {$page} 没有数据", [
-                        'source' => $this->source,
+                    $this->log->warning("批次 {$month}[{$page}] 没有数据", [
+                        'source' => $source,
                         'params' => [
                             'is_full' => $isFull,
                             'start_time' => $startTime,
@@ -83,29 +142,37 @@ class SyncSealDrugReportService
                     ]);
 
                     if ($isFull) {
-                        $startTime = Carbon::parse($startTime)->copy()->addMonth()->startOfMonth()->toDateTimeString();
-                        $endTime = Carbon::parse($endTime)->copy()->addMonth()->endOfMonth()->toDateTimeString();
+                        $next = Carbon::parse($startTime)->copy()->addMonth();
+                        $startTime = $next->startOfMonth()->toDateTimeString();
+                        $endTime = $next->endOfMonth()->toDateTimeString();
                         $page = 1;
                         continue;
                     }
-
-//                    $hasMore = false;
                     break;
                 }
 
                 // 处理并保存数据
-                $saveCount = $this->saveSealDrugReport($data);
+                $saveCount = $this->saveDrugReport($source, $data);
                 $total += $saveCount;
 
-                Log::channel('sync')->info("批次 {$page} 处理完成", [
-                    'source' => $this->source,
+                $this->log->info("批次 {$month}[{$page}] 处理完成", [
+                    'source' => $source,
                     'fetch_count' => count($data),
                     'save_count' => $saveCount,
                     'total' => $total,
                 ]);
 
                 // 检查是否还有更多数据
-                $hasMore = (count($data) === $pageSize);
+                if (count($data) <> $pageSize) {
+                    if ($isFull) {
+                        $next = Carbon::parse($startTime)->copy()->addMonth();
+                        $startTime = $next->startOfMonth()->toDateTimeString();
+                        $endTime = $next->endOfMonth()->toDateTimeString();
+                        $page = 1;
+                        continue;
+                    }
+                    break;
+                }
 
                 $page++;
 
@@ -113,8 +180,8 @@ class SyncSealDrugReportService
                 sleep(1);
 
             } catch (\Exception $e) {
-                Log::channel('sync')->error('获取批次数据失败', [
-                    'source' => $this->source,
+                $this->log->error("批次 {$month}[{$page}] 数据获取失败", [
+                    'source' => $source,
                     'params' => [
                         'is_full' => $isFull,
                         'start_time' => $startTime,
@@ -124,30 +191,68 @@ class SyncSealDrugReportService
                     ],
                     'error' => $e->getMessage()
                 ]);
-                continue;
+//                continue;
+                break;
             }
-        }
+        } while (true);
 
-        Log::channel('sync')->warning($isFull ? "全量同步完成" : "增量同步完成", [
-            'source' => $this->source,
+        $this->log->notice($isFull ? "全量同步完成" : "增量同步完成", [
+            'source' => $source,
             'total' => $total
         ]);
 
         return $total;
     }
 
+    /**
+     * 查询药检报告数据
+     * @param string $source
+     * @param string $startTime
+     * @param string $endTime
+     * @param int $page
+     * @param int $pageSize
+     * @return array
+     * @throws \Exception
+     */
+    protected function queryDrugReport(string $source, string $startTime, string $endTime = '', int $page = 1, int $pageSize = 20): array
+    {
+        if (self::QUERY_DRUG_REPORT == $source) {
+            return $this->queryDrugReportService->queryDrugReport($startTime, $endTime, $page, $pageSize);
+        }
+
+        if (self::QUERY_SEAL_DRUG_REPORT == $source) {
+            return $this->queryDrugReportService->querySealDrugReport($startTime, $endTime, $page, $pageSize);
+        }
+
+        if (self::DRUG_REPORT_OPT_HISTORY == $source) {
+            $startDate = Carbon::parse($startTime)->copy()->toDateString();
+            $endDate = Carbon::parse($endTime)->copy()->toDateString();
+            return $this->queryDrugReportService->drugReportOptHistory($startDate, $endDate, $page, $pageSize);
+        }
+
+        return [];
+    }
+
     /**
      * 处理并保存批次数据
+     * @param string $source
      * @param array $data
      * @return int
      */
-    protected function saveSealDrugReport(array $data): int
+    protected function saveDrugReport(string $source, array $data): int
     {
         try {
-            $data = $this->correctSealDrugReport($data);
+            if (self::QUERY_SEAL_DRUG_REPORT == $source) {
+                $data = $this->correctSealDrugReport($data);
+            } elseif (self::DRUG_REPORT_OPT_HISTORY  == $source) {
+                $data = $this->correctDrugReportOptHistory($data);
+            } else {
+                $data = $this->correctDrugReport($data);
+            }
+
             return DrugReportInfo::bulkUpsert($data);
         } catch (\Throwable $e) {
-            Log::channel('sync')->error("保存批次数据失败", [
+            $this->log->error("保存批次数据失败", [
                 'data' => $data,
                 'error' => $e->getMessage()
             ]);
@@ -156,7 +261,42 @@ class SyncSealDrugReportService
     }
 
     /**
-     * 处理批次数据
+     * 处理【待签收】医药报告批次数据
+     * @param array $data
+     * @return array
+     */
+    protected function correctDrugReport(array $data): array
+    {
+        return array_map(function ($item) {
+            return [
+                'drug_report_id' => $item['drug_report_id'] ?? '',
+                'report_name' => $item['file_name'] ?? '',
+                'batch_no' => $item['produce_batch_no'] ?? '',
+                'drug_id' => $item['drug_id'] ?? '',
+                'drug_name' => $item['physic_name'] ?? '',
+                'pkg_spec' => $item['pkg_spec'] ?? '',
+                'prepn_spec' => $item['prepn_spec'] ?? '',
+                'prepn_type_desc' => $item['prepn_type_desc'] ?? '',
+                'bill_type' => $item['bill_type'] ?? 0,
+                'bill_id' => $item['bill_id'] ?? '',
+                'bill_detail_id' => $item['bill_detail_id'] ?? '',
+                'bill_time' => $item['bill_time'] ?? '',
+                'bill_code' => $item['bill_code'] ?? '',
+                'produce_date' => $item['produce_date'] ?? '',
+                'produce_ent_id' => $item['produce_ent_id'] ?? '',
+                'produce_ent_name' => $item['produce_ent_name'] ?? '',
+                'ass_ref_ent_id' => $item['ass_ref_ent_id'] ?? '',
+                'from_ref_ent_id' => $item['from_ref_ent_id'] ?? '',
+                'from_ent_name' => $item['from_ent_name'] ?? '',
+                'sealed_report_url' => $item['sealed_report_url'] ?? '',
+                'report_sign_status' => $item['drug_report_sign_status'] ?? '',
+                'raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
+            ];
+        }, $data);
+    }
+
+    /**
+     * 处理【已签收】医药报告批次数据
      * @param array $data
      * @return array
      */
@@ -164,7 +304,6 @@ class SyncSealDrugReportService
     {
         return array_map(function ($item) {
             return [
-                'drug_report_v2_id' => $item['drug_report_v2_id'] ?? '',
                 'report_id' => $item['report_id'] ?? '',
                 'report_name' => $item['drug_report_name'] ?? '',
                 'report_no' => $item['report_no'] ?? '',
@@ -177,7 +316,23 @@ class SyncSealDrugReportService
                 'prepn_spec' => $item['prepn_spec'] ?? '',
                 'pkg_ratio_list' => json_encode($item['pkg_ratio_list'] ?? [], JSON_UNESCAPED_UNICODE),
                 'sealed_report_url' => $item['sealed_report_url'] ?? '',
-                'seal_raw_data' => json_encode($data ?? [], JSON_UNESCAPED_UNICODE),
+                'seal_raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
+            ];
+        }, $data);
+    }
+
+    /**
+     * 处理医药报告操作批次数据
+     * @param array $data
+     * @return array
+     */
+    protected function correctDrugReportOptHistory(array $data): array
+    {
+        return array_map(function ($item) {
+            return [
+                'batch_no' => $item['batch_no'] ?? '',
+                'drug_id' => $item['drug_id'] ?? '',
+                'opt_raw_data' => json_encode($item ?? [], JSON_UNESCAPED_UNICODE),
             ];
         }, $data);
     }

+ 25 - 5
config/logging.php

@@ -97,12 +97,14 @@ return [
         ],
 
         'emergency' => [
-            'path' => storage_path('logs/error.log'),
+            'driver' => 'daily',
+            'path' => storage_path('logs/laravel.log'),
+            'days' => 14,
         ],
 
         'sql' => [
             'driver' => 'daily',
-            'path' => storage_path('logs/sql.log'),
+            'path' => storage_path('logs/sql/sql.log'),
             'level' => 'debug',
             'days' => 7,
             'permission' => 0664,
@@ -111,7 +113,25 @@ return [
 
         'sync' => [
             'driver' => 'daily',
-            'path' => storage_path('logs/sync.log'),
+            'path' => storage_path('logs/sync/sync.log'),
+            'level' => 'debug',
+            'days' => 30,
+            'permission' => 0664,
+            'replace_placeholders' => true,
+        ],
+
+        'sync_seal' => [
+            'driver' => 'daily',
+            'path' => storage_path('logs/sync/sync-seal.log'),
+            'level' => 'debug',
+            'days' => 30,
+            'permission' => 0664,
+            'replace_placeholders' => true,
+        ],
+
+        'sync_opt' => [
+            'driver' => 'daily',
+            'path' => storage_path('logs/sync/sync-opt.log'),
             'level' => 'debug',
             'days' => 30,
             'permission' => 0664,
@@ -120,9 +140,9 @@ return [
 
         'api' => [
             'driver' => 'daily',
-            'path' => storage_path('logs/api.log'),
+            'path' => storage_path('logs/api/api.log'),
             'level' => 'info',
-            'days' => 14,
+            'days' => 7,
         ],
     ],