| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- <?php
- namespace addons\HuifuPay\common\service;
- use addons\HuifuPay\common\models\HuifuPayOrderModel;
- use addons\HuifuPay\common\service\HuifuService;
- use addons\LuckyGroup\common\models\LuckyGroupOrder;
- use addons\Store\common\models\StoreCashierOrder;
- use addons\Store\common\models\StoreOrder;
- use addons\Store\common\models\StoreSettings;
- use api\modules\v1\forms\user\WechatForm;
- use common\enums\AddonsEnum;
- use common\enums\PayTypeEnum;
- use common\helpers\ArrayHelper;
- use common\helpers\FileHelper;
- use common\enums\StatusEnum;
- use common\models\common\PaymentTrade;
- use common\models\common\PaymentTradeLog;
- use common\models\common\PaymentTradeOrder;
- use common\models\common\UserBankCard;
- use common\models\mall\Mall;
- use common\models\mall\MallAddons;
- use common\models\order\Order;
- use common\models\user\UserInfo;
- use yii\db\Exception;
- use \Yii;
- use common\helpers\LockHelper;
- class PayService
- {
- const LOCK = 'update_user_huifu_order_status';
- public $mall_id = null;
- public function __construct($mall_id = null)
- {
- if (!empty($mall_id)) {
- $this->mall_id = $mall_id;
- }
- }
- // 下单
- /**
- * 作者:zengfanhua
- * 创建时间:2023/12/28 15:10:04
- * @trade Object
- */
- public function create(PaymentTrade $trade, $trade_type, $openid,$smsCode, $extra_config = [])
- {
- $trade_type = trim($trade_type);
- $config = \Yii::$app->services->setting->addons->get($trade->mall_id, AddonsEnum::ADDONS_NAME_HUIFU_PAY, 'basic');
- if (!empty($extra_config)) {
- foreach ($extra_config as $config_key => $config_value) {
- isset($config[$config_key]) && $config[$config_key] = $config_value;
- }
- }
- new WechatForm(['mall_id' => $trade->mall_id]);
- $order_setting = \Yii::$app->services->setting->mall->get($trade->mall_id, 'order');
- $order_auto_handle_time = 30;
- if (!empty($order_setting)) {
- $order_auto_handle_time = $order_setting['payment_expire_time'];
- }
- $expireDate = time() + ($order_auto_handle_time * 60);
- $huifuService = new HuifuService($trade->mall_id);
- $notify_url = \Yii::$app->services->setting->platform->get('system.api_url') . "/huifu-pay/notify/notify";
- $result = [];
- //分账对象
- $splitAccount = [];
- $total_price=0;
- if ($config['huifupay_ledger_status'] && !empty(json_decode($config['huifupay_ledger_list'], true))) {
- $sList = json_decode($config['huifupay_ledger_list'], true);
- foreach ($sList as $key => $value) {
- $scale = bcdiv($value['num'], 100,4);
- $price = bcmul($trade->getOnlinePayFee(), $scale, 2);
- $item = [
- 'num' => $price,
- 'id' => $value['id']
- ];
- $splitAccount[] = $item;
- $total_price=bcadd($price,$total_price,2);
- }
- //精度损失处理
- if($total_price<$trade->getOnlinePayFee())
- {
- $no_price = bcsub($trade->getOnlinePayFee(),$total_price,2);
- $base_price=$splitAccount[count($splitAccount)-1]['num'];
- $splitAccount[count($splitAccount)-1]['num']=bcadd($base_price,$no_price,2);
- }
- }
- // 判断是否需要延迟分账 delay_acct_flag
- $t_data['delay_acct_flag'] = self::getSplitAccount($trade); // 是否延迟分账
- // 判断是否为门店订单,如果是门店订单,那么就判断是否需要延迟分账
- // try {
- switch ($trade_type) {
- case 'app_alipay':
- case 'h5_alipay':
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => $trade->getOnlinePayFee(),
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- ];
- $result = $huifuService->preAliOrder($data, $notify_url, $expireDate, $splitAccount);
- break;
- case 'app_wechat':
- case 'h5_wechat':
- case 'wechat':
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => $trade->getOnlinePayFee(),
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- ];
- $resultPre = $huifuService->preWxOrder($data, $notify_url, $expireDate, $splitAccount);
- //除了小程序,获取openid,生成一个中间页打开微信小程序
- $out_trade_no = $trade->out_trade_no;
- $data = [
- 'path' => '/plugins4/HuifuPay/call-pay',
- 'query' => 'trade_sn=' . $out_trade_no . '&pre_order_id=' . $resultPre['pre_order_id'],
- 'env_version' => 'trial',
- ];
- $wechatService = new WechatService();
- $res = $wechatService->getScheme($data);
- if (!empty($res['errcode'])) {
- throw new Exception($res['errmsg']);
- }
- $result = ['openlink' => $res['openlink'], 'req_seq_id' => $resultPre['req_seq_id']];
- break;
- case 'mp_wechat':
- //$mp_wechat_appid = \Yii::$app->params['wechatMiniProgramConfig']['app_id'];
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => $trade->getOnlinePayFee(),
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- ];
- //$result = $huifuService->preAliOrder($data, $notify_url, $expireDate,$splitAccount);
- $result = $huifuService->preWxOrder($data, $notify_url, $expireDate, $splitAccount);
- break;
- case 'big_pay':
- $result = ['trade_no' => $trade->out_trade_no];
- return ['result' => $result];
- case 'balance_pay':
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => $trade->getOnlinePayFee(),
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- ];
- if(empty($splitAccount))
- {
- throw new Exception('余额支付必须分账,请在后台设置');
- }
- $result = $huifuService->balancePay($data, $splitAccount);
- if ($result['trans_stat'] == 'S') {
- //修改交易状态
- $trade->pay_type = PayTypeEnum::HUIFUPAY;
- $trade->is_pay = 1;
- $trade->pay_time = time();
- $trade->third_trade_no=$result['req_seq_id'];
- if (!$trade->save()) {
- throw new Exception('支付流水修改失败');
- }
- $orders = Yii::$app->services->pay->changePaymentTradeOrder($trade, PayTypeEnum::HUIFUPAY, 'balance_pay');
- Yii::$app->services->pay->notify($orders);
- return ['result' => ['trade_no' => $trade->out_trade_no]];
- }
- return ['result' => 'fail'];
- case 'fast_pay':
- if(empty($smsCode))
- {
- throw new Exception('请输入短信验证码');
- }
- $data = [
- 'goods_title' => $trade->title,
- 'sms_code' => $smsCode,
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- ];
- $payOrder = HuifuPayOrderModel::find()
- ->where(['trade_no' => $trade->out_trade_no])
- ->orderBy('id desc')
- ->one();
- $data['order_id']=$payOrder['hf_order_no'];
- $result = $huifuService->sendPaySmsConfirm($data, $notify_url);
- return ['amount' => $trade->total_fee, 'order_no' => $trade->out_trade_no];
- case 'T_MINIAPP':
- //查询用户open_id
- $user_info = UserInfo::findOne(['user_id' => $trade['user_id'], 'status' => StatusEnum::ENABLED, 'platform' => 'mp-wx']);
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => sprintf('%.2f', $trade->getOnlinePayFee()),
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'delay_acct_flag'=>$t_data['delay_acct_flag'],
- 'trade_type'=>$trade_type,
- 'mall_id'=>$trade['mall_id'],
- 'open_id'=>!empty($user_info) ? $user_info['openid'] : '',
- ];
- $result = $huifuService->preWxOrder2($data, $notify_url, $expireDate, $splitAccount);
- if(!empty($result['resp_code']!='00000100')){
- throw new Exception($result['resp_desc']);
- }
- break;
- }
- // } catch (\Throwable $e) {
- // dd($e->getMessage());
- // }
- //创建本地关联订单
- try {
- if ($result) {
- //添加记录
- $order = new HuifuPayOrderModel();
- $order->mall_id = $trade->mall_id;
- $order->hf_order_no = $result['req_seq_id']; //汇付流水号
- $order->trade_no = $trade->out_trade_no;
- $order->created_at = time();
- $order->updated_at = time();
- $order->payment_id = $trade->id;
- $order->trade_type = $trade_type;
- $order->save();
- $trade->trade_type=$trade_type;
- $trade->save();
- }
- } catch (\Exception $e) {
- throw new Exception($e->getMessage());
- }
- switch ($trade_type){
- case 'T_MINIAPP':
- $pay_info = json_decode($result['pay_info'],true);
- $pay_info['timestamp'] = $pay_info['timeStamp'];
- return $pay_info;
- default:
- return ['result' => $result];
- }
- }
- /**
- * 分账
- * @param PaymentTrade $trade
- * @return array|array[]|string
- */
- public static function getSplitAccount(PaymentTrade $trade)
- {
- // 判断是否为门店订单
- $to = PaymentTradeOrder::findOne(['trade_id' => $trade->id]);
- if (strpos($to->order_no, 'C') === 0) {
- $order = StoreCashierOrder::findOne(['order_no' => $to->order_no]);
- } else {
- $order = Order::findOne(['order_no' => $to->order_no]);
- }
- if (!empty($order->store_id)) {
- // 判断是否有设置分账
- $storeSetting = StoreSettings::findOne(['store_id' => $order->store_id]);
- if ($storeSetting->store_service_fee == 2 && !empty($storeSetting->huifu_mch_no)) { // 需要分账
- // 这里写分账数据
- // return [
- // [
- // 'huifu_id' => $storeSetting->huifu_mch_no,
- // 'div_amt' => bcmul($trade->getOnlinePayFee(), bcsub(1,bcmul($storeSetting->store_service_ratio, 0.01, 2), 2), 2),
- // ]
- // ];
- return 'Y';
- }
- }
- return 'N';
- }
- public function bigPay(PaymentTrade $trade, $cardId)
- {
- $huifuService = new HuifuService($trade->mall_id);
- $config = \Yii::$app->services->setting->addons->get($trade->mall_id, AddonsEnum::ADDONS_NAME_HUIFU_PAY, 'basic');
- $data = [
- 'goods_title' => $trade->title,
- 'amount' => $trade->getOnlinePayFee(),
- 'huifu_id' => $config['huifupay_huifu_id'],
- ];
- //获得银行卡信息
- $card = UserBankCard::findOne(['id' => $cardId]);
- if (!$card) {
- throw new Exception('找不到银行卡');
- }
- $data['real_name'] = $card->payer_name;
- $data['bank_card_no'] = $card->bank_card_no;
- $notify_url = \Yii::$app->services->setting->platform->get('system.api_url') . "/huifu-pay/notify/notify";
- $result = $huifuService->bigPay($notify_url, $data);
- //创建本地关联订单
- try {
- if ($result) {
- //添加记录
- $order = new HuifuPayOrderModel();
- $order->mall_id = $trade->mall_id;
- $order->hf_order_no = $result['req_seq_id']; //汇付流水号
- $order->trade_no = $trade->out_trade_no;
- $order->created_at = time();
- $order->updated_at = time();
- $order->payment_id = $trade->id;
- $order->trade_type = 'big_pay';
- $order->save();
- $trade->trade_type='big_pay';
- $trade->save();
- }
- } catch (\Exception $e) {
- throw new Exception($e->getMessage());
- }
- return $result;
- }
- /**
- * 支付回调
- *
- * @param PaymentTrade $trade
- * @param array $params 回调参数
- * @return boolean
- */
- public function notify(PaymentTrade $trade, array $params)
- {
- $lock_key = self::LOCK . $trade['out_trade_no'];
- $identification = uniqid();
- $transaction = Yii::$app->db->beginTransaction();
- try {
- //加锁
- $res = LockHelper::lock($lock_key, $identification, 100, 100);
- if (!$res) throw new \PHPUnit\Util\Exception('无法获取锁');
- // 支付完成
- if ($trade->is_pay == 1) return true;
- // 支付金额验证
- if (bccomp($params['trans_amt'], $trade->getOnlinePayFee()) !== 0) throw new Exception('支付金额不一致');
- // 修改支付流水
- $trade->pay_type = $trade->isMixedPay() ? PayTypeEnum::MIXED : PayTypeEnum::HUIFUPAY;
- $trade->is_pay = 1;
- $trade->pay_time = time();
- $trade->third_trade_no = $params['req_seq_id'] ?? '';
- $trade->second_trade_no = $params['out_ord_id'] ?? '';
- if (!$trade->save()) throw new Exception('支付流水修改失败');
- // 业务回调
- $orders = Yii::$app->services->pay->changePaymentTradeOrder($trade, PayTypeEnum::HUIFUPAY);
- $transaction->commit();
- Yii::$app->services->pay->notify($orders);
- LockHelper::uLock($lock_key, $identification);
- return true;
- } catch (\Exception $e) {
- $transaction->rollBack();
- LockHelper::uLock($lock_key, $identification);
- // 记录报错日志
- FileHelper::writeLog($this->getLogPath('error'), json_encode(ArrayHelper::toArray([
- 'message' => $e->getMessage(),
- 'line' => $e->getLine(),
- 'file' => method_exists($e, 'getFile') ? $e->getFile() : '',
- 'trace' => $e->getTrace(),
- 'code' => $e->getCode(),
- ])));
- return false;
- }
- }
- /**
- * @param $type
- * @return string
- */
- protected function getLogPath($type)
- {
- return Yii::getAlias('@runtime') . "/huifu/" . date('Y_m_d') . '/' . $type . '.txt';
- }
- public function refund($params, $extra_config = [])
- {
-
- try {
- $mall_id = $this->mall_id;
- $refund = $params['refund'];
- $order_id = $refund['order_id'];
- $refund_source = $params['refund_source'] ?? 'Mall';
- $pay_type = $params['pay_type'];
- if ($pay_type != PayTypeEnum::HUIFUPAY) return false;
- if ($refund_source === 'Mall') {
- $order = Order::findOne(['id' => $order_id, 'mall_id' => $mall_id]);
- if (!empty($params['order_type']) && $params['order_type'] == 'LuckyGroup') {
- if (MallAddons::isInstall($mall_id, 'LuckyGroup')) {
- $order = LuckyGroupOrder::findOne(['id' => $order_id, 'mall_id' => $mall_id, 'status' => StatusEnum::ENABLED]);
- }
- }
- if (empty($order)) {
- throw new Exception('订单不存在');
- }
- }
- $payment_trade = PaymentTrade::findOne(['id' => $params['payment_trade_id'],'is_pay' => 1]);
- $third_trade_no = $payment_trade['third_trade_no'];
- $config = \Yii::$app->services->setting->addons->get($this->mall_id, AddonsEnum::ADDONS_NAME_HUIFU_PAY, 'basic');
- if (!empty($extra_config)) {
- foreach ($extra_config as $config_key => $config_value) {
- isset($config[$config_key]) && $config[$config_key] = $config_value;
- }
- }
- //分账对象
- $splitAccount = [];
- $total_price=0;
- if ($config['huifupay_ledger_status'] && !empty(json_decode($config['huifupay_ledger_list'], true))) {
- $sList = json_decode($config['huifupay_ledger_list'], true);
- foreach ($sList as $key => $value) {
- $scale = bcdiv($value['num'], 100,4);
- $price = bcmul($payment_trade->getOnlinePayFee(), $scale, 2);
- $item = [
- 'num' => $price,
- 'id' => $value['id']
- ];
- $splitAccount[] = $item;
- $total_price=bcadd($price,$total_price,2);
- }
- //精度损失处理
- if($total_price<$payment_trade->getOnlinePayFee())
- {
- $no_price = bcsub($payment_trade->getOnlinePayFee(),$total_price,2);
- $base_price=$splitAccount[count($splitAccount)-1]['num'];
- $splitAccount[count($splitAccount)-1]['num']=bcadd($base_price,$no_price,2);
- }
- }
- if ($payment_trade['trade_type'] == 'big_pay') {
- throw new Exception('大额支付不支持在线退款');
- }
- $huifuService = new HuifuService($mall_id);
- $data = [
- 'huifu_id' => $config['huifupay_huifu_id'],
- 'amount' => sprintf('%.2f', $params['refund_price']),
- 'old_req_date' => date("Ymd", $payment_trade['created_at']),
- 'org_req_seq_id' => $third_trade_no,
- ];
- if ($payment_trade['trade_type'] == 'balance_pay') {
- $result=$huifuService->balanceReturn($data,$splitAccount);
- }
- else if($payment_trade['trade_type'] == 'big_pay'||$payment_trade['trade_type'] == 'fast_pay')
- {
- $result=$huifuService->onlineRefund($data,$splitAccount);
- }
- else
- {
- $result=$huifuService->refund($data,$splitAccount);
- }
-
- if ($result['trans_stat']=='S'||$result['trans_stat']=='P') {
- return [true, 'ok'];
- }
- return [false, '退款失败'];
- } catch (\Exception $e) {
- return [false, $e->getMessage()];
- }
- }
- }
|