368 lines
15 KiB
PHP
368 lines
15 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Command;
|
|
|
|
use App\Model\Pharmacy;
|
|
use App\Model\Product;
|
|
use App\Model\ProductPlatform;
|
|
use App\Utils\Log;
|
|
use Extend\Prescription\Prescription;
|
|
use Hyperf\Command\Command as HyperfCommand;
|
|
use Hyperf\Command\Annotation\Command;
|
|
use Hyperf\DbConnection\Db;
|
|
use Hyperf\Utils\Coroutine\Concurrent;
|
|
use Psr\Container\ContainerInterface;
|
|
use Symfony\Component\Console\Input\InputArgument;
|
|
|
|
/**
|
|
* 更新处方平台商品
|
|
*/
|
|
#[Command]
|
|
class getProductCommand extends HyperfCommand
|
|
{
|
|
protected array $active_pharmacies = [];
|
|
|
|
protected function getPharmacy(string $code)
|
|
{
|
|
if (empty($this->active_pharmacies)) {
|
|
$list = Pharmacy::where('status', 1)->get();
|
|
foreach ($list as $p) {
|
|
$this->active_pharmacies[$p->pharmacy_code] = $p;
|
|
}
|
|
}
|
|
return $this->active_pharmacies[$code] ?? null;
|
|
}
|
|
public function __construct(protected ContainerInterface $container)
|
|
{
|
|
parent::__construct('getProduct:command');
|
|
}
|
|
|
|
public function configure()
|
|
{
|
|
parent::configure();
|
|
$this->setDescription('获取处方平台商品数据');
|
|
}
|
|
|
|
protected function logInfo(string $message): void
|
|
{
|
|
$this->line(date('Y-m-d H:i:s') . ' [INFO] ' . $message);
|
|
Log::getInstance('getProductCommand')->info($message);
|
|
}
|
|
|
|
protected function logWarn(string $message): void
|
|
{
|
|
$this->warn(date('Y-m-d H:i:s') . ' [WARN] ' . $message);
|
|
Log::getInstance('getProductCommand')->warning($message);
|
|
}
|
|
|
|
protected function logError(string $message): void
|
|
{
|
|
$this->error(date('Y-m-d H:i:s') . ' [ERROR] ' . $message);
|
|
Log::getInstance('getProductCommand')->error($message);
|
|
}
|
|
|
|
// 主逻辑处理
|
|
public function handle()
|
|
{
|
|
$startTime = microtime(true);
|
|
$this->logInfo("================== [getProductCommand] 处方平台商品目录同步开始 ==================");
|
|
|
|
$stats = [
|
|
'total_received' => 0,
|
|
'created' => 0,
|
|
'updated' => 0,
|
|
'unchanged' => 0,
|
|
'skipped_invalid' => 0,
|
|
'skipped_pharmacy' => 0,
|
|
'failed' => 0,
|
|
];
|
|
|
|
try {
|
|
// 预加载已启用的药房列表
|
|
if (empty($this->active_pharmacies)) {
|
|
$list = Pharmacy::where('status', 1)->get();
|
|
foreach ($list as $p) {
|
|
$this->active_pharmacies[$p->pharmacy_code] = $p;
|
|
}
|
|
}
|
|
|
|
if (empty($this->active_pharmacies)) {
|
|
$this->logError("未找到任何已启用的药房配置,请先在药房管理中添加并启用药房后再执行同步");
|
|
return;
|
|
}
|
|
|
|
$pharmacyListStr = implode(', ', array_map(function ($p) {
|
|
return "{$p->pharmacy_name}({$p->pharmacy_code})";
|
|
}, array_values($this->active_pharmacies)));
|
|
$this->logInfo("当前系统已启用药房 (" . count($this->active_pharmacies) . " 个): [{$pharmacyListStr}]");
|
|
|
|
$prescription = new Prescription();
|
|
$page = 1;
|
|
$page_size = 100;
|
|
|
|
$this->logInfo("正在请求第 1 页商品目录数据 (pageSize={$page_size})...");
|
|
$result = $prescription->getProd(1, $page_size);
|
|
|
|
if (empty($result) || !isset($result['rows'])) {
|
|
$this->logWarn("处方平台未返回有效的商品目录数据,任务结束");
|
|
return;
|
|
}
|
|
|
|
$totalCount = (int)($result['count'] ?? count($result['rows']));
|
|
$totalPages = (int)ceil($totalCount / $page_size);
|
|
$this->logInfo("处方平台商品目录查询成功: 平台总数据量={$totalCount} 条,总页数={$totalPages} 页");
|
|
|
|
// 处理第 1 页
|
|
$this->logInfo(">>> 正在处理第 1/{$totalPages} 页数据 (当前页 " . count($result['rows']) . " 条)...");
|
|
foreach ($result['rows'] as $item) {
|
|
$stats['total_received']++;
|
|
$this->handleData($item, $stats);
|
|
}
|
|
|
|
// 处理后续页
|
|
if ($totalPages > 1) {
|
|
for ($i = 2; $i <= $totalPages; $i++) {
|
|
$this->logInfo(">>> 正在请求并处理第 {$i}/{$totalPages} 页数据...");
|
|
try {
|
|
$pageResult = $prescription->getProd($i, $page_size);
|
|
if (!isset($pageResult['rows']) || empty($pageResult['rows'])) {
|
|
$this->logWarn("第 {$i} 页返回空数据,跳过");
|
|
continue;
|
|
}
|
|
|
|
foreach ($pageResult['rows'] as $item) {
|
|
$stats['total_received']++;
|
|
$this->handleData($item, $stats);
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$this->logError("第 {$i} 页商品同步失败: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$this->logError("商品同步全局异常: " . $e->getMessage());
|
|
}
|
|
|
|
$duration = round(microtime(true) - $startTime, 2);
|
|
$this->logInfo("================== [getProductCommand] 处方平台商品目录同步完成 ==================");
|
|
$this->logInfo("总耗时: {$duration}s | 平台接收: {$stats['total_received']} 条 | 新增入库: {$stats['created']} 条 | 变更更新: {$stats['updated']} 条 | 资料无变动: {$stats['unchanged']} 条 | 非本院药房忽略: {$stats['skipped_pharmacy']} 条 | 字段缺失跳过: {$stats['skipped_invalid']} 条 | 处理失败: {$stats['failed']} 条");
|
|
}
|
|
|
|
/**
|
|
* 参数设置
|
|
* @return array[]
|
|
*/
|
|
protected function getArguments(): array
|
|
{
|
|
return [
|
|
// ['sign', InputArgument::REQUIRED, '签名数据']
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 入库
|
|
* @param array $item
|
|
* @param array $stats
|
|
* @return bool
|
|
*/
|
|
protected function handleData(array $item, array &$stats): bool
|
|
{
|
|
if (empty($item['drugCode']) || empty($item['drugPrice']) || empty($item['thirdCode']) || empty($item['thirdDrugCode']) || empty($item['approvalNumber'])) {
|
|
$drugName = $item['tradeName'] ?? '未知名';
|
|
$this->logWarn("【跳过-字段缺失】药品 [{$drugName}] 缺少必要字段(drugCode/drugPrice/thirdCode/thirdDrugCode/approvalNumber)");
|
|
$stats['skipped_invalid']++;
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
Db::beginTransaction();
|
|
|
|
$pharmacy = $this->getPharmacy($item['thirdCode']);
|
|
if (empty($pharmacy)) {
|
|
Db::rollBack();
|
|
$stats['skipped_pharmacy']++;
|
|
return false;
|
|
}
|
|
|
|
// 查询是否存在
|
|
$params = array();
|
|
$params['product_platform_code'] = $item['drugCode'];
|
|
$params['product_pharmacy_code'] = $item['thirdDrugCode'];
|
|
$params['license_number'] = $item['approvalNumber'];
|
|
$params['pharmacy_code'] = $item['thirdCode'];
|
|
$product_platform = ProductPlatform::getOne($params);
|
|
if (!empty($product_platform)) {
|
|
// 已存在,更新
|
|
$product_platform_data = array();
|
|
$product_data = array();
|
|
|
|
// 商品名称
|
|
if (isset($item['tradeName'])) {
|
|
if ($product_platform['product_name'] != $item['tradeName']) {
|
|
$product_platform_data['product_name'] = $item['tradeName'];
|
|
$product_data['product_name'] = $item['tradeName'];
|
|
}
|
|
}
|
|
|
|
// 商品价格
|
|
if ($product_platform['product_price'] != $item['drugPrice']) {
|
|
$product_platform_data['product_price'] = $item['drugPrice'];
|
|
$product_data['product_price'] = $item['drugPrice'];
|
|
}
|
|
|
|
// 药品类型
|
|
if (isset($item['drugClassCode'])) {
|
|
if ($item['drugClassCode'] == 1) {
|
|
$product_type = 1;
|
|
} elseif ($item['drugClassCode'] == 2) {
|
|
$product_type = 2;
|
|
} else {
|
|
$product_type = 0;
|
|
}
|
|
|
|
if ($product_platform['product_type'] != $product_type) {
|
|
$product_platform_data['product_type'] = $product_type;
|
|
$product_data['product_type'] = $product_type;
|
|
}
|
|
}
|
|
|
|
// 商品规格
|
|
if (isset($item['specifications'])) {
|
|
if ($product_platform['product_spec'] != $item['specifications']) {
|
|
$product_platform_data['product_spec'] = $item['specifications'];
|
|
$product_data['product_spec'] = $item['specifications'];
|
|
}
|
|
}
|
|
|
|
// 生产厂家
|
|
if (isset($item['manufacturer'])) {
|
|
if ($product_platform['manufacturer'] != $item['manufacturer']) {
|
|
$product_platform_data['manufacturer'] = $item['manufacturer'];
|
|
$product_data['manufacturer'] = $item['manufacturer'];
|
|
}
|
|
}
|
|
|
|
// 零售包装单位
|
|
if (isset($item['packingUnit'])) {
|
|
if ($product_platform['retail_unit'] != $item['packingUnit']) {
|
|
$product_platform_data['retail_unit'] = $item['packingUnit'];
|
|
$product_data['packaging_unit'] = $item['packingUnit'];
|
|
}
|
|
}
|
|
|
|
// 基本包装数量
|
|
if (isset($item['basicPackingCount'])) {
|
|
if ($product_platform['packaging_count'] != $item['basicPackingCount']) {
|
|
$product_platform_data['packaging_count'] = $item['basicPackingCount'];
|
|
}
|
|
}
|
|
|
|
// 基本包装单位
|
|
if (isset($item['basicPackingUnit'])) {
|
|
if ($product_platform['packaging_unit'] != $item['basicPackingUnit']) {
|
|
$product_platform_data['packaging_unit'] = $item['basicPackingUnit'];
|
|
}
|
|
}
|
|
|
|
// 单次剂量单位
|
|
if (isset($item['defaultSingleDosageUnit'])) {
|
|
if ($product_platform['single_unit'] != $item['defaultSingleDosageUnit']) {
|
|
$product_platform_data['single_unit'] = $item['defaultSingleDosageUnit'];
|
|
}
|
|
}
|
|
|
|
$product_platform_data['pharmacy_code'] = $item['thirdCode'];
|
|
$product_data['pharmacy_code'] = $item['thirdCode'];
|
|
$product_data['pharmacy_id'] = (string)$pharmacy->pharmacy_id;
|
|
|
|
if (!empty($product_platform_data)) {
|
|
// 更新商品表-处方平台
|
|
$params = array();
|
|
$params['product_platform_id'] = $product_platform['product_platform_id'];
|
|
ProductPlatform::edit($params, $product_platform_data);
|
|
|
|
if (!empty($product_data)) {
|
|
// 获取商品表数据
|
|
$params = array();
|
|
$params['product_platform_id'] = $product_platform['product_platform_id'];
|
|
$product = Product::getOne($params);
|
|
if (!empty($product)) {
|
|
// 更新商品表
|
|
$params = array();
|
|
$params['product_platform_id'] = $product_platform['product_platform_id'];
|
|
Product::edit($params, $product_data);
|
|
}
|
|
}
|
|
$this->logInfo("【更新药品】药房 [{$pharmacy->pharmacy_name}({$item['thirdCode']})] 药品 [{$item['tradeName']}] (ID: {$product_platform['product_platform_id']}, 价格: {$item['drugPrice']})");
|
|
$stats['updated']++;
|
|
} else {
|
|
$stats['unchanged']++;
|
|
}
|
|
} else {
|
|
// 不存在,创建
|
|
$data = array();
|
|
$data['pharmacy_code'] = $item['thirdCode'];
|
|
if (isset($item['tradeName'])) {
|
|
$data['product_name'] = $item['tradeName'];
|
|
}
|
|
$data['product_price'] = $item['drugPrice'];
|
|
|
|
if (isset($item['drugClassCode'])) {
|
|
if ($item['drugClassCode'] == 1) {
|
|
$data['product_type'] = 1;
|
|
} elseif ($item['drugClassCode'] == 2) {
|
|
$data['product_type'] = 2;
|
|
} else {
|
|
$data['product_type'] = 0;
|
|
}
|
|
}
|
|
|
|
$data['product_platform_code'] = $item['drugCode'];
|
|
$data['product_pharmacy_code'] = $item['thirdDrugCode'];
|
|
|
|
if (isset($item['specifications'])) {
|
|
$data['product_spec'] = $item['specifications'];
|
|
}
|
|
$data['license_number'] = $item['approvalNumber'];
|
|
if (isset($item['manufacturer'])) {
|
|
$data['manufacturer'] = $item['manufacturer'];
|
|
}
|
|
if (isset($item['defaultSingleDosageUnit'])) {
|
|
$data['single_unit'] = $item['defaultSingleDosageUnit'];
|
|
}
|
|
if (isset($item['basicPackingUnit'])) {
|
|
$data['packaging_unit'] = $item['basicPackingUnit'];
|
|
}
|
|
if (isset($item['basicPackingCount'])) {
|
|
$data['packaging_count'] = $item['basicPackingCount'];
|
|
}
|
|
if (isset($item['packingUnit'])) {
|
|
$data['retail_unit'] = $item['packingUnit'];
|
|
}
|
|
|
|
$product_platform = ProductPlatform::addProductPlatform($data);
|
|
if (empty($product_platform)) {
|
|
Db::rollBack();
|
|
$this->logError("【新增失败】药房 [{$pharmacy->pharmacy_name}({$item['thirdCode']})] 药品 [{$item['tradeName']}] 写入数据库失败");
|
|
$stats['failed']++;
|
|
return false;
|
|
}
|
|
$this->logInfo("【新增入库】药房 [{$pharmacy->pharmacy_name}({$item['thirdCode']})] 药品 [{$item['tradeName']}] (平台编码: {$item['drugCode']}, 批准文号: {$item['approvalNumber']}, 价格: {$item['drugPrice']})");
|
|
$stats['created']++;
|
|
}
|
|
|
|
Db::commit();
|
|
} catch (\Throwable $e) {
|
|
Db::rollBack();
|
|
$drugName = $item['tradeName'] ?? '未知名';
|
|
$this->logError("【更新异常】药品 [{$drugName}] (thirdDrugCode: {$item['thirdDrugCode']}) 异常: " . $e->getMessage());
|
|
$stats['failed']++;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|