Files
xk-api-yii/member/modules/v1/controllers/CallbackController.php

598 lines
29 KiB
PHP

<?php
namespace member\modules\v1\controllers;
use Carbon\Carbon;
use common\enums\ProductOrderEnum;
use common\enums\SystemNoticeTypeEnum;
use common\events\ProductOrderEvent;
use common\forms\ProductCancelForm;
use common\forms\ProductRefundForm;
use common\helpers\FuncHelper;
use common\jobs\ProductOrderSyncPlatformJob;
use common\models\oldDb\Address;
use common\models\oldDb\Callback;
use common\models\oldDb\DoctorInfo;
use common\models\oldDb\Drug;
use common\models\oldDb\FundWater;
use common\models\oldDb\PaymentProductOrder;
use common\models\oldDb\PaymentProductRefund;
use common\models\oldDb\PaymentRegister;
use common\models\oldDb\PaymentRegisterRefund;
use common\models\oldDb\Prescription;
use common\models\oldDb\ProcessRule;
use common\models\oldDb\ProductOrder;
use common\models\oldDb\ProductOrderItems;
use common\models\oldDb\ProductOrderRefund;
use common\models\oldDb\Region;
use common\models\oldDb\Register;
use common\models\oldDb\RegisterRefund;
use common\models\oldDb\StoreUser;
use common\models\oldDb\SystemNotice;
use common\models\oldDb\UserPatient;
use common\modelsgii\oldDb\ChineseMedicine;
use common\modelsgii\oldDb\PayConfig;
use common\services\UploadService;
use common\services\WechatService;
use member\models\forms\ProductOrderSubmitForm;
use member\models\forms\RegisterSubmitForm;
use Yii;
use yii\base\Exception;
use yii\helpers\Json;
use yii\web\Response;
class CallbackController extends \yii\web\Controller
{
public $enableCsrfValidation = false;
/**
* 下单回调
* @return mixed
*/
public function actionNotify()
{
Yii::$app->response->format = Response::FORMAT_RAW;
Yii::$app->response->formatters = [];
$response = WechatService::getInstance()->payment->handlePaidNotify(function ($notify, $fail) {
/**
* {"appid":"wx36bbb299d88c6127","bank_type":"ZJRCUB_DEBIT","cash_fee":"1","fee_type":"CNY","is_subscribe":"N","mch_id":"1496340382","nonce_str":"637ed1617f5f3","openid":"o88xX5Z-mpVWWV-yw2X6MefDIUqE","out_trade_no":"PY20221124100521434224","result_code":"SUCCESS","return_code":"SUCCESS","sign":"FAB5D4E3AD785DBF7D6FB1FE0E1A897E","time_end":"20221124100606","total_fee":"1","trade_type":"JSAPI","transaction_id":"4200001675202211242752421487"}
*/
//记录回调信息
$callback = new Callback();
$callback->content = json_encode($notify);
$callback->type = 'order';
$callback->save();
if ($notify['return_code'] == 'SUCCESS' && $notify['result_code'] == 'SUCCESS') {
$t = \Yii::$app->db->beginTransaction();
try {
$out_trade_no = $notify['out_trade_no'];
$paymentProductOrder = PaymentProductOrder::find()->where([
'pay_order_no' => $out_trade_no
])->one();
if ($paymentProductOrder) {
$data['order_no'] = $paymentProductOrder->order_no;
$data['transaction_id'] = $notify['transaction_id'];
$data['pay_order_no'] = $out_trade_no;
$data['pay_type'] = 1;
$productOrderPayForm = new ProductOrderSubmitForm();
$order = $productOrderPayForm->paid($data);
$order_type = 1;
} else {
$PaymentRegister = PaymentRegister::find()->where([
'pay_order_no' => $out_trade_no
])->one();
if (!$PaymentRegister) {
throw new Exception('订单不存在');
}
$data['order_no'] = $PaymentRegister->order_no;
$data['transaction_id'] = $notify['transaction_id'];
$data['pay_type'] = 1;
$RegisterSubmitForm = new RegisterSubmitForm();
$order = $RegisterSubmitForm->paid($data);
$order_type = 2;
}
// 增加流水记录
$fundWater = new FundWater();
$fundWater->store_id = $order->store_id; // 入账
$fundWater->type = 'enter'; // 入账
$fundWater->order_type = $order_type;
$fundWater->order_id = $order->id;
$fundWater->user_id = $order->user_id;
$fundWater->service_user_id = $order_type == 1 ? $order->su_id : $order->service_user_id;
$fundWater->order_no = $order->order_no;
$fundWater->price = $order_type == 1 ? $order->total_pay_price : $order->price;
$fundWater->pay_type = 1; //微信
$fundWater->saveOrFail();
//回调处理成功
$callback->status = 1;
$callback->save();
$t->commit();
return true;
} catch (\Exception $exception) {
$t->rollBack();
$callback->message = $exception->getMessage();
$callback->save();
return $fail('通信失败,请稍后再通知我');
}
}
});
// $response = unserialize('O:41:"Symfony\\Component\\HttpFoundation\\Response":6:{s:7:"headers";O:50:"Symfony\\Component\\HttpFoundation\\ResponseHeaderBag":5:{s:23:"' . "\0" . '*' . "\0" . 'computedCacheControl";a:1:{s:8:"no-cache";b:1;}s:10:"' . "\0" . '*' . "\0" . 'cookies";a:0:{}s:14:"' . "\0" . '*' . "\0" . 'headerNames";a:2:{s:13:"cache-control";s:13:"Cache-Control";s:4:"date";s:4:"Date";}s:10:"' . "\0" . '*' . "\0" . 'headers";a:2:{s:13:"cache-control";a:1:{i:0;s:8:"no-cache";}s:4:"date";a:1:{i:0;s:29:"Wed, 09 Mar 2022 02:19:18 GMT";}}s:15:"' . "\0" . '*' . "\0" . 'cacheControl";a:0:{}}s:10:"' . "\0" . '*' . "\0" . 'content";s:96:"<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";s:10:"' . "\0" . '*' . "\0" . 'version";s:3:"1.0";s:13:"' . "\0" . '*' . "\0" . 'statusCode";i:200;s:13:"' . "\0" . '*' . "\0" . 'statusText";s:2:"OK";s:10:"' . "\0" . '*' . "\0" . 'charset";N;}');
return $response;
}
/**
* 退款回调
*/
public function actionRefundNotify()
{
Yii::$app->response->format = Response::FORMAT_RAW;
Yii::$app->response->formatters = [];
$response = WechatService::getInstance()->payment->handleRefundedNotify(function ($message, $reqInfo, $fail) {
// 其中 $message['req_info'] 获取到的是加密信息
// $reqInfo 为 message['req_info'] 解密后的信息
// 你的业务逻辑...
/**
* {"cash_refund_fee":"1","out_refund_no":"RF20221124103051025400","out_trade_no":"PY20221124100521434224","refund_account":"REFUND_SOURCE_RECHARGE_FUNDS","refund_fee":"1","refund_id":"50300503882022112427569050043","refund_recv_accout":"\u6d59\u6c5f\u519c\u4fe1\u501f\u8bb0\u53617865","refund_request_source":"API","refund_status":"SUCCESS","settlement_refund_fee":"1","settlement_total_fee":"1","success_time":"2022-11-24 10:31:00","total_fee":"1","transaction_id":"4200001675202211242752421487"}
*/
//记录回调信息
$callback = new Callback();
$callback->content = json_encode($reqInfo);
$callback->type = 'refund';
$callback->save();
$t = \Yii::$app->db->beginTransaction();
try {
$transaction_id = $reqInfo['transaction_id'];
$out_refund_no = $reqInfo['out_refund_no'];
$paymentProductOrder = PaymentProductOrder::find()->where([
'transaction_id' => $transaction_id,
])->one();
if ($paymentProductOrder) {
if ($paymentProductOrder->is_pay != 1) {
throw new Exception('支付订单不存在');
}
$order = ProductOrder::find()->where([
'order_no' => $paymentProductOrder->order_no,
])->with('prescription')->one();
if (!$order || $order->is_pay != 1) {
throw new Exception('订单不存在');
}
$order_type = 1;
$refund = ProductOrderRefund::find()->where(['refund_no' => $out_refund_no])->one();//退款订单
$payment_refund = PaymentProductRefund::find()->where(['refund_no' => $out_refund_no])->one();
} else {
$PaymentRegister = PaymentRegister::find()->where([
'transaction_id' => $transaction_id
])->one();
if (!$PaymentRegister || $PaymentRegister->is_pay != 1) {
throw new \yii\db\Exception('支付订单不存在');
}
$order = Register::find()->where([
'order_no' => $PaymentRegister->order_no,
])->one();
if (!$order || $order->is_pay != 1) {
throw new Exception('订单不存在');
}
$order_type = 2;
$refund = RegisterRefund::find()->where(['refund_no' => $out_refund_no])->one();//退款订单
$payment_refund = PaymentRegisterRefund::find()->where(['refund_no' => $out_refund_no])->one();
}
if (!$refund || !$payment_refund) {
throw new Exception('退款订单不存在');
}
if ($reqInfo['refund_status'] == 'SUCCESS') {
if ($order_type == 1) {
$order->refund_status = 3;//已退款
$order->status = ProductOrderEnum::REFUND;//已退款
$order->refund_time = time();
$order->save();
if ($order->is_online) { //平台订单状态同步
\Yii::$app->queue->delay(0)->push(new ProductOrderSyncPlatformJob([
'orderId' => $order->id,
'status' => 3
]));
}
}
$refund->is_refund = 1;
$refund->refund_time = date('Y-m-d H:i:s', strtotime($reqInfo['success_time']));
$refund->save();
$payment_refund->is_pay = 1;
$payment_refund->pay_type = 1;
$payment_refund->save();
} else {
$refund->is_refund = -1;
$refund->save();
$payment_refund->is_pay = -1;
$payment_refund->save();
}
// 增加流水记录
$fundWater = new FundWater();//出账
$fundWater->store_id = $order->store_id;
$fundWater->order_type = $order_type;
$fundWater->type = 'refund'; // 出账
$fundWater->order_id = $order->id;
$fundWater->user_id = $order->user_id;
$fundWater->service_user_id = $order_type == 1 ? $order->su_id : $order->service_user_id;
$fundWater->refund_no = $refund->refund_no;
$fundWater->price = $order_type == 1 ? $order->total_pay_price : $order->price;
$fundWater->pay_type = 1; //微信
$fundWater->saveOrFail();
$callback->status = 1;
$callback->save();
$t->commit();
return true; // 返回 true 告诉微信“我已处理完成”
// 或返回错误原因 $fail('参数格式校验错误');
} catch (\Exception $exception) {
$t->rollBack();
$callback->message = $exception->getMessage();
$callback->save();
$fail($exception->getMessage());
}
});
return $response;
}
/**
* 阿里oss直传回调
*/
public function actionUploadNotify()
{
// 1.获取OSS的签名header和公钥url header
$headers = Yii::$app->request->getHeaders();
$authorizationBase64 = "";
$pubKeyUrlBase64 = "";
if (isset($headers['authorization'])) {
$authorizationBase64 = $headers['authorization'];
} else {
if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$authorizationBase64 = $_SERVER['HTTP_AUTHORIZATION'];
}
}
if (isset($headers['x-oss-pub-key-url'])) {
$pubKeyUrlBase64 = $headers['x-oss-pub-key-url'];
} else {
if (isset($_SERVER['HTTP_X_OSS_PUB_KEY_URL'])) {
$pubKeyUrlBase64 = $_SERVER['HTTP_X_OSS_PUB_KEY_URL'];
}
}
if ($authorizationBase64 == '' || $pubKeyUrlBase64 == '') {
throw new Exception('参数异常');
}
// 2.获取OSS的签名
$authorization = base64_decode($authorizationBase64);
// 4.获取回调body
$body = file_get_contents('php://input');
// 5.拼接待签名字符串
$authStr = '';
$path = $_SERVER['REQUEST_URI'];
$pos = strpos($path, '?');
if ($pos === false) {
$authStr = urldecode($path) . "\n" . $body;
} else {
$authStr = urldecode(substr($path, 0, $pos)) . substr($path, $pos, strlen($path) - $pos) . "\n" . $body;
}
// 3.获取公钥
$pubKey = (new UploadService())->getPublicKey($pubKeyUrlBase64);
if ($pubKey == "") {
throw new Exception('公钥异常');
}
// 6.验证签名
$ok = openssl_verify($authStr, $authorization, $pubKey, OPENSSL_ALGO_MD5);
if (!$ok) {
throw new Exception('签名异常');
}
$data = (new UploadService())->getBody($body);
return $data;
}
// 互医订单同步
public function actionPlatformNotify()
{
Yii::$app->response->format = Response::FORMAT_RAW;
$content = file_get_contents('php://input');
$callback = new Callback();
$callback->content = $content;
$callback->type = 'platform_notify';
$callback->save();
$t = \Yii::$app->db->beginTransaction();
try {
$data = json_decode($content, true);
$config = \Yii::$app->params;
switch ($data['type']) {
case 'order_create'://订单创建
$sign = md5($data['order']['order_no'] . $data['time'] . $config['platform']['token'] . $data['type']);
if ($sign != $data['sign']) {
throw new Exception('sign不匹配');
}
$isExist = ProductOrder::find()->where(['sync_order_no' => $data['order']['order_no'], 'is_online' => 1])->one();
if ($isExist) {
throw new Exception('产品订单已存在');
}
$userPatient = UserPatient::findOne([
'user_id' => $data['order']['user_id'],
'id_card' => $data['order']['patient']['id_card'],
'is_delete' => 0
]);
$storeUser = StoreUser::find()->where([
'user_id' => $data['order']['user_id'],
'is_online' => 1
])->one();
$repice = $data['order']['recipe'];
$prescription_type = $data['order']['prescription_type'];
$priceTotal = $data['order']['total_price'];
foreach ($data['order']['goods'] as $v) {
$drug = Drug::find()->alias('d')->where(['d.id' => $v['id']])->joinWith('drugStoreDrug')->one();
if (!$drug) {
throw new Exception('基础药品不存在:' . $v['id']);
}
}
$is_decoct = $data['order']['decoct'];
$process_price = 0;
$dosage = $data['order']['dosage'];
$process_rule_id = 0;
$process_rule = '';
$process_rule_note = '';
if ($prescription_type == 1 || $prescription_type == 3) { //中药
$ids = array_column($data['order']['goods'], 'id');
$medicine = ChineseMedicine::find()->select('id,drug_id,name,order,unit,number,price,drug_number,buy_price')->with(['unit', 'useWay'])->where(['in', 'id', $ids])->asArray()->all();
// $price = 0;
// $totalNum = 0;
// foreach ($medicine as $value){
// $drugNumber = (int) $value['number'] * (int) $dosage;
// $totalNum += $drugNumber;
// $price+=$value['number'] * $value['price'] * $dosage;
// }
if ($is_decoct == 1) {
$process_rule_id = 6;
$processRule = ProcessRule::find()->where(['id' => 6])->one();
$process_rule = '加工方式:汤剂-浓煎-' . $data['order']['volume'] . ',' . $processRule->price . '元/,共' . $dosage . '贴';
$process_price = $processRule->price * $dosage;
$priceTotal += $process_price;
}
}
if ($prescription_type == 1) {
$prescription_no = 'ZY' . rand(111111, 999999) . time();
} elseif ($prescription_type == 2) {
$prescription_no = 'XY' . rand(111111, 999999) . time();
} else {
$prescription_no = 'GY' . rand(111111, 999999) . time();
}
$prescription_content['prescription_no'] = $prescription_no;
$prescription_content['repice'] = $data['order']['recipe'];
$prescription_content['created_at'] = date('Y-m-d', time());
$prescription_content['doctor_order'] = $data['order']['doctor_order'];
$prescription_content['clinical_diagnose'] = $data['order']['clinical_diagnose'];
$prescription_content['category'] = '自费';
$prescription_content['patient'] = $userPatient;
$prescription_content['patient']['age'] = FuncHelper::getAgeFromIdNo($userPatient->id_card);
$prescription_content['doctor'] = DoctorInfo::find()->select('su_id,name,depart_id,title_id')->where(['su_id' => $data['order']['doctor_id']])->with(['depart', 'title'])->asArray()->one();
$prescription_content['total_pay_price'] = $priceTotal;
$prescription = new Prescription();
$prescription->store_id = $storeUser->store_id ?? 11001;
$prescription->register_id = 0;
$prescription->prescription_no = $prescription_no;
$prescription->online_prescription_no = $data['order']['prescription_no'];
$prescription->su_id = $data['order']['doctor_id'];
$prescription->user_id = $userPatient->user_id;
$prescription->up_id = $userPatient->id;
$prescription->status = 0;
$prescription->type = 1;//普通方
$prescription->is_online = 1;
$prescription->content = Json::encode($prescription_content);
$prescription->prescription_type = $prescription_type;
$prescription->category = 1;
$prescription->process_rule_id = $process_rule_id;
$prescription->process_rule = $process_rule;
$prescription->process_rule_note = $process_rule_note;
$over_time = \Yii::$app->params['prescription']['over_time'];
$doctor_order = [];
if (date('H') >= 16) {
$doctor_order[] = '该处方有效期延长为三天内有效';
$over_time = 72 * 3600;
}
if ($repice[0]['dosage'] > 7) {
$doctor_order[] = '患者需长期使用此药,开具超七天用量';
}
$doctor_order[] = $data['order']['doctor_order'];
$prescription->valid_hours = $over_time / 3600;
$prescription->doctor_order = implode('|', $doctor_order);
$prescription->clinical_diagnose = $data['order']['clinical_diagnose'];
$prescription->total_pay_price = $priceTotal;
$prescription->saveOrFail();
//获取支付方式配置
$payConfig = PayConfig::findOne(['status' => 1, 'current_use' => 1]);
$productOrder = new ProductOrder();
$productOrder->store_id = $storeUser->store_id ?? 11001;
$productOrder->is_online = 1;
$productOrder->online_prescription_status = 0;
$productOrder->dosage = isset($data['order']['dosage']) ? $data['order']['dosage'] : 0;
$productOrder->su_id = $data['order']['doctor_id'];
$productOrder->user_id = $data['order']['user_id'];
$productOrder->up_id = $userPatient->id ?? 0;
$productOrder->order_no = Carbon::now()->format('YmdHis') . rand(10000, 99999) . rand(10000, 99999);
$productOrder->sync_order_no = $data['order']['order_no'];
$productOrder->order_type = 2; //商城订单
$productOrder->prescription_type = $data['order']['prescription_type'];
$productOrder->p_id = $prescription->id;
$productOrder->status = 0;
$productOrder->items_price = $data['order']['total_price'];
$productOrder->process_price = $process_price;
$productOrder->trans_expenses = 0;
$productOrder->type = $payConfig->pay_type ?? 2;//1微信 2易票联
$totalPayPrice = $priceTotal;
$userAddress = Address::find()->select('id,name,mobile,province,region,detail_address')->where(['user_id' => $data['order']['user_id']])->orderBy('is_default DESC')->asArray()->all();
if ($userAddress) {
$productOrder->address_id = $userAddress[0]['id'];
$productOrder->address = Json::encode($userAddress[0]);
$productOrder->express_name = $userAddress[0]['name'];
$productOrder->express_mobile = $userAddress[0]['mobile'];
$productOrder->express_region = $userAddress[0]['region'];
$productOrder->express_address = $userAddress[0]['detail_address'];
$region = Region::find()->where(['name' => $userAddress[0]['province']])->one();
$productOrder->trans_expenses = $region->express_fee;
$totalPayPrice = $totalPayPrice + $region->express_fee;
}
$productOrder->total_pay_price = $totalPayPrice;
$productOrder->saveOrFail();
$market_price = '0';
foreach ($data['order']['goods'] as $v) {
$drug = Drug::find()->alias('d')->where(['d.id' => $v['id']])->joinWith('drugStoreDrug')->one();
if (!$drug) {
throw new Exception('基础药品不存在:' . $v['id']);
}
$item = new ProductOrderItems();
$item->product_order_id = $productOrder->id;
$item->drug_id = $drug->id;
$item->drug_image = $drug->image;
$item->number = $v['number'];
$item->type = $drug->type;
$item->drug_no = $drug->drug_number;
$item->price = $drug->drugStoreDrug->price;
$item->buy_price = $drug->drugStoreDrug->market_price;
$item->drug_name = $drug->drug_name;
$item->small_info = $drug->small_info;
$item->saveOrFail();
$itemMarketPrice = bcmul($v['number'],$drug->drugStoreDrug->market_price,2);
$market_price = bcadd($market_price,$itemMarketPrice,2);
}
$productOrder->market_price = $market_price;
$productOrder->saveOrFail();
//生成系统消息
$SystemNotice = new SystemNotice();
$SystemNotice->store_id = $storeUser->store_id ?? 11001;
$SystemNotice->content = '您有一条在线问诊流转处方,请及时处理';
$SystemNotice->data = $prescription->id;
$SystemNotice->base_type = SystemNoticeTypeEnum::ONLINE_PRESCRIPTION;
$SystemNotice->scene_type = 2;//用户端
$SystemNotice->user_id = $data['order']['doctor_id'];
$SystemNotice->notice_at = date('Y-m-d H:i:s', time());
$SystemNotice->saveOrFail();
//触发订单创建事件
$event = new ProductOrderEvent();
$event->order = $productOrder;
$event->sender = $this;
\Yii::$app->trigger(ProductOrder::EVENT_CREATED, $event);
break;
case 'prescription_pass'://处方通过
$sign = md5($data['order']['order_no'] . $data['time'] . $config['platform']['token'] . $data['type']);
if ($sign != $data['sign']) {
throw new Exception('sign不匹配');
}
$isExist = ProductOrder::find()->where(['sync_order_no' => $data['order']['order_no'], 'is_online' => 1])->one();
if (!$isExist) {
throw new Exception('产品订单不存在');
}
$isExist->online_prescription_status = 1;
$isExist->save();
break;
case 'prescription_refuse'://处方拒绝
$sign = md5($data['order']['order_no'] . $data['time'] . $config['platform']['token'] . $data['type']);
if ($sign != $data['sign']) {
throw new Exception('sign不匹配');
}
$isExist = ProductOrder::find()->where(['sync_order_no' => $data['order']['order_no'], 'is_online' => 1])->one();
if (!$isExist) {
throw new Exception('产品订单不存在');
}
$isExist->online_prescription_status = 2;
$isExist->save();
//未付款订单取消/已付款订单退款
// 判断订单是否已付款且待发货,是则进行退款操作
if ($isExist->cancel_status == 0 && $isExist->refund_status == 0 && $isExist->status == 1 && $isExist->is_pay == 1) {
// 自动退款
$ProductRefundForm = new ProductRefundForm();
$ProductRefundForm->refund([
'order_id' => $isExist->id,
'user_id' => $isExist->user_id
]);
} else {
// 订单取消
$ProductCancelForm = new ProductCancelForm();
$ProductCancelForm->cancel([
'order_id' => $isExist->id,
'user_id' => $isExist->user_id
], '处方未通过审核,订单取消');
}
break;
case 'doctor_approved':
$sign = md5($data['su_id'] . $data['time'] . $config['platform']['token'] . $data['type']);
if ($sign != $data['sign']) {
throw new Exception('sign不匹配');
}
$isExist = DoctorInfo::find()->where(['su_id' => $data['su_id']])->one();
if (!$isExist) {
throw new Exception('医生不存在');
}
$isExist->is_sync = 2;
$isExist->save();
break;
default:
throw new Exception('错误的回调类型');
break;
}
$callback->status = 1;
$callback->save();
$t->commit();
return true;
} catch (Exception $e) {
$t->rollBack();
$callback->message = $e->getMessage();
$callback->save();
Yii::$app->response->setStatusCode('400');
return false;
}
}
}