diff --git a/api/config/main.php b/api/config/main.php index eeea5cd..d75ad01 100644 --- a/api/config/main.php +++ b/api/config/main.php @@ -38,16 +38,6 @@ return [ 'prefix' => function ($message) { } ], - [ - 'class' => 'yii\log\FileTarget', - 'levels' => ['error', 'warning'], - 'categories' => ['refund_log'], - 'logFile' => '@app/runtime/logs/refund_log.log', - 'logVars' => [], - 'exportInterval' => 1, - 'prefix' => function ($message) { - } - ], ], ], 'user' => [ @@ -104,9 +94,7 @@ return [ 'controller' => 'wx-payment', 'pluralize' => false, 'extraPatterns' => [ - 'GET web' => 'web', 'POST notify' => 'notify', - 'POST apply-refund' => 'apply-refund', ] ], ], diff --git a/api/controllers/WxPaymentController.php b/api/controllers/WxPaymentController.php index cf9b42d..634da81 100644 --- a/api/controllers/WxPaymentController.php +++ b/api/controllers/WxPaymentController.php @@ -8,10 +8,6 @@ namespace api\controllers; - -use api\logic\WxPaymentLogic; -use yii\filters\auth\HttpBearerAuth; -use yii\helpers\ArrayHelper; use yii\web\Response; use Yii; use yii\web\BadRequestHttpException; @@ -21,16 +17,6 @@ class WxPaymentController extends CommonController public $modelClass = 'backend\modules\shop\models\ars\Order'; public $className = 'api\logic\WxPaymentLogic'; - public function behaviors() - { - return ArrayHelper::merge(parent::behaviors(), [ - 'authenticatior' => [ - 'class' => HttpBearerAuth::className(), - 'except' => ['notify'], - ] - ]); - } - public function actions() { $action = parent::actions(); @@ -38,23 +24,9 @@ class WxPaymentController extends CommonController unset($action['update']); unset($action['view']); unset($action['delete']); - $action['options'] = [ - 'class' => 'yii\rest\OptionsAction', - 'collectionOptions' => ['PUT', 'GET', 'OPTIONS'] - ]; return $action; } - public function actionWeb() - { - return $this->object->wxPayment(WxPaymentLogic::PAY_TYPE_WEB); - } - - public function actionMiniProgram() - { - return $this->object->wxPayment(WxPaymentLogic::PAY_TYPE_MINI_PROGRAM); - } - /** * @return array|bool * @throws BadRequestHttpException @@ -68,16 +40,4 @@ class WxPaymentController extends CommonController return $this->object->notify(); } - /** - * @return bool - * @throws BadRequestHttpException - * @throws \yii\db\Exception - * @throws \yii\web\NotFoundHttpException - * 申请退款 - */ - public function actionApplyRefund() - { - return $this->object->applyRefund(); - } - } \ No newline at end of file diff --git a/api/logic/WxPaymentLogic.php b/api/logic/WxPaymentLogic.php index 477f284..4425e7a 100644 --- a/api/logic/WxPaymentLogic.php +++ b/api/logic/WxPaymentLogic.php @@ -8,166 +8,16 @@ namespace api\logic; -use backend\modules\shop\models\ars\Order; -use backend\modules\shop\models\ars\PaymentLog; -use backend\modules\shop\models\ars\RefundLog; -use backend\modules\shop\models\ars\WxPayConfig; -use Yii; -use EasyWeChat\Factory; -use yii\db\Exception; +use backend\modules\payment\logic\WxPaymentManager; use yii\helpers\Json; use yii\httpclient\Client; use yii\web\BadRequestHttpException; -use yii\base\BaseObject; -use yii\web\NotFoundHttpException; -use yii\web\ServerErrorHttpException; +use backend\modules\shop\models\ars\PaymentLog; +use yii\db\Exception; +use Yii; -class WxPaymentLogic extends BaseObject +class WxPaymentLogic extends WxPaymentManager { - /*支付类型*/ - const PAY_TYPE_WEB = 1; - const PAY_TYPE_MINI_PROGRAM = 2; - /*支付状态*/ - const STATUS_PAYMENT_WAITING = 0; - const STATUS_PAYMENT_SUCCESS = 1; - /*退款状态*/ - const STATUS_REFUND_WAIT = 0; //退款待审核 - const STATUS_REFUND_CONFIRM = 1; //退款待确认 - const STATUS_REFUND_SUCCESS = 2; //退款成功 - const STATUS_REFUND_PORTION = 3; //部分退款 - /*发起支付方式*/ - const TRADE_TYPE_JS_API = 'JSAPI'; - - public $appId; - public $mchId; - public $key; - public $certPath; - public $keyPath; - public $notifyUrl; - public $tradeType; - public $payType; - public $app; - public $order; - public $viewAction = 'view'; - - - /** - * @param $payType - * @return mixed - * @throws BadRequestHttpException - * @throws Exception - * 微信统一下单 - */ - public function wxPayment($payType) - { - $this->payType = $payType; - $unifyParams = $this->applyPaymentData(); - return $this->unify($unifyParams); - } - - /** - * @return array - * @throws BadRequestHttpException - * @throws Exception - * 生成支付参数 - */ - private function applyPaymentData() - { - $orderId = Yii::$app->request->getBodyParam('order_id');/*int 商品id*/ - $paymentAmount = Yii::$app->request->getBodyParam('payment_amount');/*int 商品id*/ - $notifyUrl = Yii::$app->request->getBodyParam('notify_url');/*int 商品id*/ - if (empty($orderId) || empty($paymentAmount) || empty($notifyUrl)) { - throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); - } - - $this->tradeType = self::TRADE_TYPE_JS_API; - $this->savePaymentLog($orderId, $paymentAmount, $notifyUrl); - - $params = [ - 'body' => '订单支付', - 'out_trade_no' => $orderId, - 'total_fee' => round($paymentAmount * 100), - 'openid' => Yii::$app->user->identity->wx_openid, - ]; - return $params; - } - - /** - * @param string $orderId - * @param float $paymentAmount - * @param string $notifyUrl - * @throws Exception - * 保存支付信息 - */ - private function savePaymentLog($orderId, $paymentAmount, $notifyUrl) - { - $paymentLog = PaymentLog::findOne(['order_id' => $this->order->order_sn]); - if (!$paymentLog) { - $paymentLog = new PaymentLog(); - } - $paymentLog->order_id = $orderId; - $paymentLog->payment_amount = $paymentAmount; - $paymentLog->notify_url = $notifyUrl; - $paymentLog->type = $this->payType; - $paymentLog->status = self::STATUS_PAYMENT_WAITING; - if (!$paymentLog->save()) { - throw new Exception(Helper::errorMessageStr($paymentLog->errors)); - } - } - - protected function getApp() - { - $this->initObject(); - $config = [ - 'app_id' => $this->appId, - 'mch_id' => $this->mchId, - 'key' => $this->key, - 'cert_path' => $this->certPath, - 'key_path' => $this->keyPath, - 'notify_url' => $this->notifyUrl, - 'trade_type' => $this->tradeType, -// 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式 - ]; - $this->app = Factory::payment($config); - // 判断当前是否为沙箱模式: -// $this->app->inSandbox(); - } - - /** - * @var WxPayConfig $wxPayConfig - */ - private function initObject() - { - $path = Yii::getAlias('@backend'); - $wxPayConfig = WxPayConfig::find()->one(); - switch ($this->payType) { - case self::PAY_TYPE_WEB: - // $wxConfig = WxConfig::find()->one(); -// $this->appId = trim($wxConfig->appid); - break; - case self::PAY_TYPE_MINI_PROGRAM: - // $miniProgramConfig = MiniProgramConfig::find()->one(); -// $this->appId = trim($miniProgramConfig->appid); - break; - } - $this->mchId = $wxPayConfig->mch_id; - $this->certPath = trim($path . $wxPayConfig->cert_path); - $this->keyPath = trim($path . $wxPayConfig->key_path); - $this->notifyUrl = Yii::$app->request->hostInfo . '/wx-payment/notify'; - } - - /** - * @param $unifyParams - * @return mixed - * 统一下单 - */ - private function unify($unifyParams) - { - $this->getApp(); - return $this->app->order->unify($unifyParams); - } - - /** * @return array|bool * @throws BadRequestHttpException @@ -219,15 +69,14 @@ class WxPaymentLogic extends BaseObject } /** - * @param $notifyData $tra->rollBack(); - + * @param $notifyData * @param $status * @return bool * @throws \yii\base\InvalidConfigException * @throws \yii\httpclient\Exception * 转发异步回调信息 */ - private function forwardNotify($notifyData, $status) + protected function forwardNotify($notifyData, $status) { $notify = [ 'notify' => [ @@ -249,85 +98,4 @@ class WxPaymentLogic extends BaseObject } } - /** - * @return bool - * @throws BadRequestHttpException - * @throws Exception - * @throws NotFoundHttpException - * 申请退款 - */ - public function applyRefund() - { - $orderId = Yii::$app->request->getBodyParam('order_id'); - $refundId = Yii::$app->request->getBodyParam('wx_refund_id'); - $refundAmount = Yii::$app->request->getBodyParam('refund_amount'); - $refundAccount = Yii::$app->request->getBodyParam('refund_account'); - $reason = Yii::$app->request->getBodyParam('reason'); - if (empty($orderId) || empty($refundId) || empty($refundAmount) || empty($reason)) { - throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); - } - $paymentLog = PaymentLog::findOne(['order_id' => $orderId]); - if (empty($paymentLog)) { - throw new NotFoundHttpException('订单支付信息未找到'); - } - if (RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT])) { - throw new BadRequestHttpException('此订单存在等待审核的退款申请'); - } - - $refundedAmount = RefundLog::find() - ->where(['order_id' => $orderId, 'status' => self::STATUS_PAYMENT_SUCCESS]) - ->sum('refund_amount') ?? 0; - - $refundLog = new RefundLog(); - $refundLog->order_id = $orderId; - $refundLog->wx_refund_id = Helper::timeRandomNum(3, 'P'); - $refundLog->reason = $reason; - $refundLog->order_amount = $paymentLog->payment_amount; - $refundLog->refund_amount = $refundAmount; - $refundLog->refunded_amount = $refundedAmount; - $refundLog->type = $paymentLog->type; - $refundLog->status = self::STATUS_REFUND_WAIT; - $refundLog->refund_account = $refundAccount; - $refundLog->applyed_at = time(); - if (!$refundLog->save()) { - throw new Exception(Helper::errorMessageStr($refundLog->errors)); - } - return true; - } - - - /** - * @param $data - * @return bool - * 支付成功回调验证签名和支付金额 - */ - public function checkSign($data) - { - $this->initObject(); - $notifySign = $data['sign']; - unset($data['sign']); - $sign = $this->_sign($data); - if ($notifySign == $sign) { - return true; - } else { - return false; - } - } - - /** - * @param $arr - * @return string - * 微信签名方法 - */ - private function _sign($arr) - { - $arr = array_filter($arr); - ksort($arr); - $arr['key'] = $this->key; - $queryString = http_build_query($arr); - $queryString = urldecode($queryString); - return strtoupper(md5($queryString)); - } - - } \ No newline at end of file diff --git a/backend/config/main.php b/backend/config/main.php index e5d61e8..6cce506 100644 --- a/backend/config/main.php +++ b/backend/config/main.php @@ -53,6 +53,16 @@ return [ 'prefix' => function ($message) { } ], + [ + 'class' => 'yii\log\FileTarget', + 'levels' => ['error', 'warning'], + 'categories' => ['refund_log'], + 'logFile' => '@app/runtime/logs/refund_log.log', + 'logVars' => [], + 'exportInterval' => 1, + 'prefix' => function ($message) { + } + ], ], ], 'errorHandler' => [ diff --git a/backend/config/params.php b/backend/config/params.php index 7f754b9..86036f8 100644 --- a/backend/config/params.php +++ b/backend/config/params.php @@ -1,4 +1,18 @@ 'admin@example.com', + 'logistics' => [ + 'SELF' => '商家配送', + 'shunfeng' => '顺丰速运', + 'suteng' => '速腾快递', + 'shentong' => '申通快递', + 'zhongtong' => '中通快递', + 'yuantong' => '圆通快递', + 'huitong' => '百世快递(原汇通)', + 'yunda' => '韵达快递', + 'yousu' => 'UC优速快递', + 'gnxb' => '邮政小包', + 'youzhengguonei' => '邮政包裹/平邮/挂号信', + 'jingdong' => '京东快递', + ], ]; diff --git a/backend/modules/payment/logic/WxPaymentManager.php b/backend/modules/payment/logic/WxPaymentManager.php new file mode 100644 index 0000000..1476ffb --- /dev/null +++ b/backend/modules/payment/logic/WxPaymentManager.php @@ -0,0 +1,358 @@ +tradeType = self::TRADE_TYPE_JS_API; + $this->payType = $payType; + $this->notifyUrl = $notifyUrl; + + $unifyParams = $this->applyPaymentData($orderId, $orderAmount, $paymentAmount, $notifyUrl); + $result = $this->unify($unifyParams); + if ($result['return_code'] == 'FAIL') { + throw new BadRequestHttpException($result['return_msg']); + } + if ($result['return_code'] == 'SUCCESS' && $result['return_msg'] == 'OK' && $result['result_code'] == 'FAIL') { + throw new BadRequestHttpException($result['err_code_des']); + } + return Json::decode($this->getBridgeConfig($result['prepay_id']), true); + } + + /** + * @param $prepayId + * @return array|string + */ + private function getBridgeConfig($prepayId) + { + $this->initObject(); + return $this->app->jssdk->bridgeConfig($prepayId); + } + + /** + * @param string $orderId + * @param int $orderAmount + * @param int $paymentAmount + * @param string $notifyUrl + * @return array + * @throws BadRequestHttpException + * @throws Exception + * 生成支付参数 + */ + private function applyPaymentData($orderId, $orderAmount, $paymentAmount, $notifyUrl) + { + $this->savePaymentLog($orderId, $orderAmount, $paymentAmount, $notifyUrl); + + $params = [ + 'body' => '订单支付', + 'out_trade_no' => $orderId, + 'total_fee' => $paymentAmount, + 'openid' => Yii::$app->user->identity->wx_openid, + ]; + return $params; + } + + /** + * @param string $orderId + * @param int $orderAmount + * @param int $paymentAmount + * @param string $notifyUrl + * @throws BadRequestHttpException + * @throws Exception + * 保存支付信息 + */ + private function savePaymentLog($orderId, $orderAmount, $paymentAmount, $notifyUrl) + { + $paymentLog = PaymentLog::findOne(['order_id' => $orderId]); + if (!$paymentLog) { + $paymentLog = new PaymentLog(); + } elseif (!empty($paymentLog->wx_payment_id)) { + throw new BadRequestHttpException('此订单号也有支付信息,不能重复'); + } + $paymentLog->order_id = $orderId; + $paymentLog->order_amount = $orderAmount; + $paymentLog->payment_amount = $paymentAmount; + $paymentLog->notify_url = $this->notifyUrl; + $paymentLog->type = $this->payType; + $paymentLog->status = self::STATUS_PAYMENT_WAITING; + if (!$paymentLog->save()) { + throw new Exception(Helper::errorMessageStr($paymentLog->errors)); + } + } + + protected function getApp() + { + $this->initObject(); + $config = [ + 'app_id' => $this->appId, + 'mch_id' => $this->mchId, + 'key' => $this->key, + 'cert_path' => $this->certPath, + 'key_path' => $this->keyPath, + 'notify_url' => $this->notifyUrl, + 'trade_type' => $this->tradeType, + 'sandbox' => true, // 设置为 false 或注释则关闭沙箱模式 + ]; + $this->app = Factory::payment($config); + //判断当前是否为沙箱模式: + $this->app->inSandbox(); + } + + /** + * @var WxPayConfig $wxPayConfig + */ + private function initObject() + { + $path = Yii::getAlias('@backend'); + $wxPayConfig = WxPayConfig::find()->one(); + switch ($this->payType) { + case self::PAY_TYPE_WEB: + // $wxConfig = WxConfig::find()->one(); +// $this->appId = trim($wxConfig->appid); + break; + case self::PAY_TYPE_MINI_PROGRAM: + // $miniProgramConfig = MiniProgramConfig::find()->one(); +// $this->appId = trim($miniProgramConfig->appid); + break; + } + $this->mchId = trim($wxPayConfig->mch_id); + $this->key = trim($wxPayConfig->key); + $this->certPath = trim($path . $wxPayConfig->cert_path); + $this->keyPath = trim($path . $wxPayConfig->key_path); + $this->notifyUrl = Yii::$app->request->hostInfo . '/wx-payment/notify'; + + $this->mchId = '1395812402'; + $this->key = '51CF5EE3B2E35B9843E17E6099325A65'; + } + + /** + * @param $unifyParams + * @return mixed + * 统一下单 + */ + private function unify($unifyParams) + { + $unifyParams['trade_type'] = $this->tradeType; + $this->getApp(); + return $this->app->order->unify($unifyParams); + } + + /** + * @param $data + * @return bool + * 支付成功回调验证签名和支付金额 + */ + public function checkSign($data) + { + $this->initObject(); + $notifySign = $data['sign']; + unset($data['sign']); + $sign = $this->_sign($data); + if ($notifySign == $sign) { + return true; + } else { + return false; + } + } + + /** + * @param $arr + * @return string + * 微信签名方法 + */ + private function _sign($arr) + { + $arr = array_filter($arr); + ksort($arr); + $arr['key'] = $this->key; + $queryString = http_build_query($arr); + $queryString = urldecode($queryString); + return strtoupper(md5($queryString)); + } + + +/*************************************** Refund ************************************************/ + /** + * @param string $orderId + * @param int $refundAmount + * @param string $refundAccount + * @param int $reason + * @return RefundLog + * @throws BadRequestHttpException + * @throws Exception + * @throws NotFoundHttpException + * 申请退款 + */ + public function applyRefund($orderId, $refundAmount, $refundAccount, $reason) + { + if (empty($orderId) || empty($refundAmount) || empty($refundAccount) || empty($reason)) { + throw new BadRequestHttpException(Helper::REQUEST_BAD_PARAMS); + } + $paymentLog = PaymentLog::findOne(['order_id' => $orderId]); + if (empty($paymentLog)) { + throw new NotFoundHttpException('订单支付信息未找到'); + } + if (RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT])) { + throw new BadRequestHttpException('此订单存在等待审核的退款申请'); + } + $refundedAmount = RefundLog::find() + ->where(['order_id' => $orderId, 'status' => self::STATUS_PAYMENT_SUCCESS]) + ->sum('refund_amount') ?? 0; + + $refundLog = new RefundLog(); + $refundLog->order_id = $orderId; + $refundLog->wx_refund_id = Helper::timeRandomNum(3, 'R'); + $refundLog->reason = $reason; + $refundLog->order_amount = $paymentLog->payment_amount; + $refundLog->refund_amount = $refundAmount; + $refundLog->refunded_amount = $refundedAmount; + $refundLog->type = $paymentLog->type; + $refundLog->status = self::STATUS_REFUND_WAIT; + $refundLog->refund_account = $refundAccount; + $refundLog->applyed_at = time(); + if (!$refundLog->save()) { + throw new Exception(Helper::errorMessageStr($refundLog->errors)); + } + return $refundLog; + } + + /** + * @param string $orderId + * @param int $refundAmount + * @param int $operatorId + * @return array|mixed + * @throws BadRequestHttpException + * @throws NotFoundHttpException + */ + public function refund($orderId, $refundAmount, $operatorId) + { + $paymentLog = PaymentLog::findOne(['order_id' => $orderId]); + if (empty($paymentLog)) { + throw new NotFoundHttpException('订单支付信息未找到'); + } + $refundLog = RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT]); + if (empty($refundLog)) { + throw new NotFoundHttpException('订单退款信息未找到'); + } + + $this->executeRefund($paymentLog, $refundLog, $refundAmount); + return $this->updateRefundInfo($paymentLog, $refundLog, $operatorId); + } + + /** + * @param PaymentLog $paymentLog + * @param RefundLog $refundLog + * @param $refundAmount + * @throws BadRequestHttpException + */ + private function executeRefund($paymentLog, $refundLog, $refundAmount) + { + /*参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数*/ + $this->getApp(); + $config = [ + 'refund_desc' => '退款' + ]; + $result = $this->app->refund->byTransactionId( + $paymentLog->wx_payment_id, + $refundLog->wx_refund_id, + $paymentLog->payment_amount, + $refundAmount, + $config + ); + Yii::info($result, 'refund_log'); + + if ($result['return_code'] == 'FAIL' || $result['return_msg'] != 'OK' || $result['result_code'] == 'FAIL') { + throw new BadRequestHttpException($result['return_msg']); + } + if ($result['err_code_des']) { + throw new BadRequestHttpException($result['err_code_des']); + } + } + + /** + * @param PaymentLog $paymentLog + * @param RefundLog $refundLog + * @param int $operatorId + * @return array + */ + private function updateRefundInfo($paymentLog, $refundLog, $operatorId) + { + $tra = Yii::$app->db->beginTransaction(); + try { + $paymentLog->wx_refund_id = $refundLog->wx_refund_id; + $paymentLog->refund_account = $refundLog->refund_account; + $paymentLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; + if (!$paymentLog->save()) { + throw new Exception(Helper::errorMessageStr($paymentLog->errors)); + } + + $refundLog->operator_id = $operatorId; + $refundLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; + $refundLog->finished_at = time(); + if (!$refundLog->save()) { + throw new Exception(Helper::errorMessageStr($refundLog->errors)); + } + + $tra->commit(); + return ['status' => true]; + } catch (Exception $e) { + $tra->rollBack(); + return ['status' => false, 'info' => $e->getMessage()]; + } + } + +} \ No newline at end of file diff --git a/backend/modules/shop/controllers/DeliveryController.php b/backend/modules/shop/controllers/DeliveryController.php index 2569281..3938206 100644 --- a/backend/modules/shop/controllers/DeliveryController.php +++ b/backend/modules/shop/controllers/DeliveryController.php @@ -2,6 +2,7 @@ namespace backend\modules\shop\controllers; +use backend\modules\shop\logic\delivery\DeliveryManager; use Yii; use backend\modules\shop\models\ars\Delivery; use backend\modules\shop\models\searchs\DeliverySearch; @@ -53,8 +54,12 @@ class DeliveryController extends Controller */ public function actionView($id) { + $model = $this->findModel($id); + $logistics = DeliveryManager::queryLogistics($model->order_id); + return $this->render('view', [ - 'model' => $this->findModel($id), + 'model' => $model, + 'logistics' => $logistics, ]); } @@ -146,4 +151,5 @@ class DeliveryController extends Controller 'columns' => $searchModel->columns() ]); } + } diff --git a/backend/modules/shop/controllers/OrderController.php b/backend/modules/shop/controllers/OrderController.php index ece17fc..70e2fca 100755 --- a/backend/modules/shop/controllers/OrderController.php +++ b/backend/modules/shop/controllers/OrderController.php @@ -102,11 +102,11 @@ class OrderController extends Controller } /** - * Deletes an existing Order model. - * If deletion is successful, the browser will be redirected to the 'index' page. - * @param integer $id - * @return mixed - * @throws NotFoundHttpException if the model cannot be found + * @param $id + * @return \yii\web\Response + * @throws NotFoundHttpException + * @throws \Throwable + * @throws \yii\db\StaleObjectException */ public function actionDelete($id) { @@ -190,15 +190,15 @@ class OrderController extends Controller public function actionRefund($id) { $model = RefundLog::findOne([ - 'order_id' => $id, + 'order_id' => Order::findOne($id)->order_sn, 'status' => WxPaymentLogic::STATUS_REFUND_WAIT ]); - if (Yii::$app->request->post('RefundLog')) { + if (Yii::$app->request->post()) { $wxPayment = Yii::createObject([ - 'class' => 'backend\modules\shop\logic\payment\WxPaymentManager' + 'class' => 'backend\modules\payment\logic\WxPaymentManager' ]); - $res = $wxPayment->refund($model, Yii::$app->user->id); + $res = $wxPayment->refund($model->order_id, $model->refund_amount, Yii::$app->user->id); if ($res['status']) { return $this->redirect(['index']); } else { @@ -207,7 +207,7 @@ class OrderController extends Controller } return $this->render('refund', [ - 'model' => $model + 'model' => $model, ]); } diff --git a/backend/modules/shop/logic/delivery/DeliveryManager.php b/backend/modules/shop/logic/delivery/DeliveryManager.php index 98cd00e..9ae43f0 100644 --- a/backend/modules/shop/logic/delivery/DeliveryManager.php +++ b/backend/modules/shop/logic/delivery/DeliveryManager.php @@ -10,9 +10,13 @@ use backend\modules\shop\models\ars\OrderGoods; use Yii; use yii\db\Exception; use yii\helpers\ArrayHelper; +use yii\helpers\Json; +use yii\web\NotFoundHttpException; class DeliveryManager { + const LOGISTICS_URL = 'http://route.showapi.com/64-19'; + /** * @param Order $order * @param Delivery $delivery @@ -40,7 +44,7 @@ class DeliveryManager throw new Exception('order shipping_status update false'); } - if ($orderStatus == Order::STATUS_SHIPMENT_PORTION || Delivery::findOne(['!=', 'id', $delivery->id])) { + if ($orderStatus == Order::STATUS_SHIPMENT_PORTION || Delivery::find()->where(['!=', 'id', $delivery->id])->andWhere(['order_id' => $delivery->order_id])->one()) { $delivery->type = Delivery::TYPE_SHIPMENT_PORTION; } else { $delivery->type = Delivery::TYPE_SHIPMENT_ALL; @@ -155,9 +159,70 @@ class DeliveryManager $data['unShipped'][] = $orderGoods; } } - return $data; } + + /** + * @param $orderId + * @return array|mixed + * @throws NotFoundHttpException + * 查询物流接口 + */ + public static function queryLogistics($orderId) + { + $delivery = Delivery::findOne(['order_id' => $orderId]); + if (!$delivery) { + throw new NotFoundHttpException('发货信息未找到'); + } + + $cache = Yii::$app->cache; + if ($cache->exists($delivery->shipping_id)) { + return $cache->get($delivery->shipping_id); + } + + $logisticsParams = self::createLogisticsParam($delivery); //创建参数(包括签名的处理) + $url = self::LOGISTICS_URL . '?' . $logisticsParams; + $result = Json::decode(file_get_contents($url), false); + if (isset($result->showapi_res_body)) { + $cache->set($delivery->shipping_id, $result->showapi_res_body, 7200); //设置缓存2个小时 + return $result->showapi_res_body; + } else { + return []; + } + } + + /** + * @param Delivery $delivery + * @return string + * 查询物流 创建参数(包括签名的处理) + */ + private static function createLogisticsParam($delivery) + { + $params = [ + 'showapi_appid' => Yii::$app->params['logistics_config']['logistics_appid'], + 'com' => $delivery->shipping_name , //物流单位 + 'nu' => $delivery->invoice_sn, //运单号 + //添加其他参数 + ]; + + $paraStr = ""; + $signStr = ""; + ksort($params); + foreach ($params as $key => $val) { + if ($key != '' && $val != '') { + $signStr .= $key.$val; + $paraStr .= $key . '=' . urlencode($val) . '&'; + } + } + $signStr .= Yii::$app->params['logistics_config']['logistics_secret']; + + //排好序的参数加上secret,进行md5,将md5后的值作为参数,便于服务器的效验 + $sign = strtolower(md5($signStr)); + $paraStr .= 'showapi_sign=' . $sign; + return $paraStr; + } + + } \ No newline at end of file diff --git a/backend/modules/shop/logic/payment/WxPaymentManager.php b/backend/modules/shop/logic/payment/WxPaymentManager.php deleted file mode 100644 index 96e05c2..0000000 --- a/backend/modules/shop/logic/payment/WxPaymentManager.php +++ /dev/null @@ -1,71 +0,0 @@ - $refundLog->order_id]); - if (empty($paymentLog)) { - throw new NotFoundHttpException('订单支付信息未找到'); - } - $refundLog = RefundLog::findOne(['order_id' => $orderId, 'status' => self::STATUS_REFUND_WAIT]); - if (!$refundLog) { - throw new NotFoundHttpException('订单退款信息未找到'); - } - - /*参数分别为:微信订单号、商户退款单号、订单金额、退款金额、其他参数*/ - $this->getApp(); - $config = ['refund_desc' => '退款']; - $result = $this->app->refund->byTransactionId( - $paymentLog->wx_refund_id, - $refundLog->wx_refund_id, - round($paymentLog->payment_amount * 100), - round($refundLog->refund_amount * 100), - $config - ); - Yii::info($result, 'refund_log'); - - if ($result['return_code'] == 'FAIL' || $result['return_msg'] != 'OK' || $result['result_code'] == 'FAIL') { - throw new BadRequestHttpException($result['return_msg']); - } - if ($result['err_code_des']) { - throw new BadRequestHttpException($result['err_code_des']); - } - $tra = Yii::$app->db->beginTransaction(); - try { - $paymentLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; - if (!$paymentLog->save()) { - throw new Exception(Helper::errorMessageStr($paymentLog->errors)); - } - $refundLog->operator_id = $operatorId; - $refundLog->status = $refundLog->refund_amount < $paymentLog->payment_amount ? self::STATUS_REFUND_SUCCESS : self::STATUS_REFUND_PORTION; - $refundLog->finished_at = time(); - if (!$refundLog->save()) { - throw new Exception(Helper::errorMessageStr($refundLog->errors)); - } - $tra->commit(); - return ['status' => 'true']; - } catch (Exception $e) { - $tra->rollBack(); - return ['status' => false, 'info' => $e->getMessage()]; - } - } -} \ No newline at end of file diff --git a/backend/modules/shop/migrations/m191218_122251_add_column_invoice_sn_in_delivery.php b/backend/modules/shop/migrations/m191218_122251_add_column_invoice_sn_in_delivery.php new file mode 100644 index 0000000..e9f75cc --- /dev/null +++ b/backend/modules/shop/migrations/m191218_122251_add_column_invoice_sn_in_delivery.php @@ -0,0 +1,41 @@ +addColumn('ats_delivery', 'invoice_sn', $this->string()->after('shipping_id')->comment('运单号')); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->dropColumn('ats_delivery', 'invoice_sn'); + return true; + } + + /* + // Use up()/down() to run migration code without a transaction. + public function up() + { + + } + + public function down() + { + echo "m191218_122251_add_column_invoice_sn_in_delivery cannot be reverted.\n"; + + return false; + } + */ +} diff --git a/backend/modules/shop/models/ars/Delivery.php b/backend/modules/shop/models/ars/Delivery.php index efa69d5..5b4431b 100755 --- a/backend/modules/shop/models/ars/Delivery.php +++ b/backend/modules/shop/models/ars/Delivery.php @@ -12,6 +12,7 @@ use yii\behaviors\TimestampBehavior; * @property int $order_id 订单id * @property string $shipping_name 货流名称 * @property string $shipping_id 运货单位 + * @property string $invoice_sn 运单号 * @property int $type 类型 * @property string $goods 商品 * @property int $status 状态 @@ -45,6 +46,7 @@ class Delivery extends \yii\db\ActiveRecord [['goods', 'decription'], 'string'], [['shipping_name'], 'string', 'max' => 50], [['shipping_id'], 'string', 'max' => 10], + [['invoice_sn'], 'string', 'max' => 255], ]; } @@ -58,6 +60,7 @@ class Delivery extends \yii\db\ActiveRecord 'order_id' => '订单id', 'shipping_name' => '货流名称', 'shipping_id' => '运货单位', + 'invoice_sn' => '运单号', 'type' => '类型', 'goods' => '商品', 'status' => '状态', @@ -112,4 +115,12 @@ class Delivery extends \yii\db\ActiveRecord return array_key_exists($column, $dropDownList) ? $dropDownList[$column] : false; } + public function beforeSave($insert) + { + if ($insert) { + $this->shipping_name = Yii::$app->params['logistics'][$this->shipping_id]; + } + return parent::beforeSave($insert); // TODO: Change the autogenerated stub + } + } diff --git a/backend/modules/shop/models/ars/WxPayConfig.php b/backend/modules/shop/models/ars/WxPayConfig.php index b59bdee..6ff414b 100644 --- a/backend/modules/shop/models/ars/WxPayConfig.php +++ b/backend/modules/shop/models/ars/WxPayConfig.php @@ -13,7 +13,7 @@ use yii\redis\ActiveRecord; * @property int $id * @property int $user_id 用户id * @property int $mch_id 商户号 - * @property string $key + * @property string $key 支付秘钥 * @property string $cert_path cert文件路径 * @property string $key_path key文件路径 */ diff --git a/backend/modules/shop/models/searchs/DeliverySearch.php b/backend/modules/shop/models/searchs/DeliverySearch.php index 9016666..0b1b369 100644 --- a/backend/modules/shop/models/searchs/DeliverySearch.php +++ b/backend/modules/shop/models/searchs/DeliverySearch.php @@ -65,7 +65,7 @@ class DeliverySearch extends Delivery 'width' => '10%', ], [ - 'attribute' => 'shipping_id', + 'attribute' => 'invoice_sn', 'width' => '10%', ], [ @@ -99,11 +99,6 @@ class DeliverySearch extends Delivery 'icon' => 'list', 'title' => '详情', ], - [ - 'name' => 'update', - 'icon' => 'pencil', - 'title' => '修改' - ], ], ], diff --git a/backend/modules/shop/models/searchs/OrderSearch.php b/backend/modules/shop/models/searchs/OrderSearch.php index c813618..4dd4ad8 100755 --- a/backend/modules/shop/models/searchs/OrderSearch.php +++ b/backend/modules/shop/models/searchs/OrderSearch.php @@ -135,6 +135,11 @@ class OrderSearch extends Order 'icon' => 'list', 'title' => '详情', ], + [ + 'name' => 'update', + 'icon' => 'pencil', + 'title' => '修改' + ], [ 'name' => 'delivery', 'icon' => 'box', @@ -163,9 +168,9 @@ class OrderSearch extends Order ] ], [ - 'name' => 'delivery', - 'icon' => 'box', - 'title' => '发货', + 'name' => 'refund', + 'icon' => 'dollar', + 'title' => '退款', 'hide' => [ 'attributes' => [ 'status', @@ -188,11 +193,6 @@ class OrderSearch extends Order 'rule' => 'or' ] ], - [ - 'name' => 'update', - 'icon' => 'pencil', - 'title' => '修改' - ] ], ], ]; diff --git a/backend/modules/shop/views/delivery/_form.php b/backend/modules/shop/views/delivery/_form.php index a58650e..6b8ff30 100644 --- a/backend/modules/shop/views/delivery/_form.php +++ b/backend/modules/shop/views/delivery/_form.php @@ -12,9 +12,9 @@ use yii\bootstrap4\ActiveForm; - field($model, 'shipping_name')->textInput(['maxlength' => true]) ?> + field($model, 'shipping_id')->dropDownList(Yii::$app->params['logistics']) ?> - field($model, 'shipping_id')->textInput(['maxlength' => true]) ?> + field($model, 'invoice_sn')->textInput(['maxlength' => true]) ?> field($model, 'status')->textInput() ?> diff --git a/backend/modules/shop/views/delivery/info.php b/backend/modules/shop/views/delivery/info.php new file mode 100644 index 0000000..4fc3cef --- /dev/null +++ b/backend/modules/shop/views/delivery/info.php @@ -0,0 +1,37 @@ + + + $model, + 'attributes' => [ + 'id', + 'order_id', + 'shipping_name', + 'shipping_id', + [ + 'attribute' => 'type', + 'value' => function ($model) { + return Delivery::dropDown('type', $model->type); + } + ], + 'status', + 'decription:ntext', + [ + 'attribute' => 'created_at', + 'value' => function ($model) { + return date('Y-m-d H:i:s', $model->created_at); + } + ], + [ + 'attribute' => 'updated_at', + 'value' => function ($model) { + return date('Y-m-d H:i:s', $model->updated_at); + } + ], + ], + ]); +?> \ No newline at end of file diff --git a/backend/modules/shop/views/delivery/logistics.php b/backend/modules/shop/views/delivery/logistics.php index 4fc3cef..9ff636d 100644 --- a/backend/modules/shop/views/delivery/logistics.php +++ b/backend/modules/shop/views/delivery/logistics.php @@ -1,37 +1,51 @@ - $model, - 'attributes' => [ - 'id', - 'order_id', - 'shipping_name', - 'shipping_id', - [ - 'attribute' => 'type', - 'value' => function ($model) { - return Delivery::dropDown('type', $model->type); - } - ], - 'status', - 'decription:ntext', - [ - 'attribute' => 'created_at', - 'value' => function ($model) { - return date('Y-m-d H:i:s', $model->created_at); - } - ], - [ - 'attribute' => 'updated_at', - 'value' => function ($model) { - return date('Y-m-d H:i:s', $model->updated_at); - } - ], - ], - ]); -?> \ No newline at end of file +

+ 'btn btn-success']) ?> +

+ +
+ +
+ + expTextName) ? $logistics->expTextName : ''?> +
+ +
+ + mailNo) ? $logistics->mailNo : ''?> +
+ +
+ + tel) ? $logistics->tel : ''?> +
+ +
+ + updateStr) ? $logistics->updateStr : '' ?> +
+ +
+ data)) { + foreach ($logistics->data as $value) { + echo '
' . + "
$value->time
" . + "
$value->context
" . + '
'; + } + } + ?> +
+ +
diff --git a/backend/modules/shop/views/delivery/view.php b/backend/modules/shop/views/delivery/view.php index 4ecdaaa..b440027 100644 --- a/backend/modules/shop/views/delivery/view.php +++ b/backend/modules/shop/views/delivery/view.php @@ -5,12 +5,14 @@ use kartik\tabs\TabsX; /* @var $this yii\web\View */ /* @var $model backend\modules\shop\models\ars\Delivery */ +/* @var $logistics */ $this->title = $model->id; $this->params['breadcrumbs'][] = ['label' => 'Deliveries', 'url' => ['index']]; $this->params['breadcrumbs'][] = $this->title; Yii::$app->params['bsVersion'] = '4.x'; \yii\web\YiiAsset::register($this); + ?>
@@ -23,9 +25,16 @@ Yii::$app->params['bsVersion'] = '4.x'; 'bordered' => true, 'items' => [ [ - 'label' => ' 物流信息', + 'label' => ' 发货信息', + 'content' => $this->render('info', [ + 'model' => $model, + ]), + ], + [ + 'label' => ' 物流信息', 'content' => $this->render('logistics', [ 'model' => $model, + 'logistics' => $logistics ]), ], [ diff --git a/backend/modules/shop/views/order/logistics.php b/backend/modules/shop/views/order/logistics.php index 53f9699..d1433eb 100644 --- a/backend/modules/shop/views/order/logistics.php +++ b/backend/modules/shop/views/order/logistics.php @@ -1,9 +1,14 @@ + +
- field($delivery, 'shipping_name')->textInput(['maxlength' => true]) ?> - field($delivery, 'shipping_id')->textInput(['maxlength' => true]) ?> + field($delivery, 'shipping_id')->dropDownList(Yii::$app->params['logistics']) ?> - field($delivery, 'status')->textInput() ?> + field($delivery, 'invoice_sn')->textInput(['maxlength' => true]) ?> field($delivery, 'decription')->textarea(['rows' => 6]) ?>
diff --git a/backend/modules/shop/views/order/refund.php b/backend/modules/shop/views/order/refund.php index 1a1988d..38e313e 100644 --- a/backend/modules/shop/views/order/refund.php +++ b/backend/modules/shop/views/order/refund.php @@ -8,6 +8,7 @@ use kartik\form\ActiveForm; $this->title = '退款订单:' . $model->order_id; $this->params['breadcrumbs'][] = ['label' => '订单列表', 'url' => ['index']]; +Yii::$app->params['bsVersion'] = '4.x'; ?>
diff --git a/common/config/params.php b/common/config/params.php index b18cb95..1500a08 100644 --- a/common/config/params.php +++ b/common/config/params.php @@ -5,4 +5,9 @@ return [ 'senderEmail' => 'noreply@example.com', 'senderName' => 'Example.com mailer', 'user.passwordResetTokenExpire' => 3600, + + 'logistics_config' => [ + 'logistics_appid' => '73887', + 'logistics_secret' => '85e067c34f094c9f8be1278557889c5e', + ], ];