RechargeForm.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. <?php
  2. /**
  3. * RechargeForm.php
  4. * todo 文件描述
  5. * Created on 2024/11/30 下午4:00
  6. * @author: hankaige
  7. */
  8. namespace app\modules\client\models\v1\cashier;
  9. use app\jobs\ReOrderWechatProfitSharingJob;
  10. use app\models\AccountLog;
  11. use app\models\CashierActionLog;
  12. use app\models\Level;
  13. use app\models\Option;
  14. use app\models\Recharge;
  15. use app\models\ReOrder;
  16. use app\models\SaasUser;
  17. use app\models\SharingReceiver;
  18. use app\models\User;
  19. use app\modules\common\models\NotifyForm;
  20. use app\utils\OrderNo;
  21. use app\utils\Share\BonusPool;
  22. use app\utils\Wechat\WechatNewPay;
  23. use app\utils\Wechat\WechatPay;
  24. use app\utils\Wechat\WechatShare;
  25. use yii\base\Model;
  26. use yii\helpers\ArrayHelper;
  27. use yii\helpers\Json;
  28. class RechargeForm extends Model
  29. {
  30. public $store_id;
  31. public $user_id;
  32. public $pay_price;
  33. public $recharge_id;
  34. public $pay_type;
  35. public $order_no;
  36. public $pay_code;
  37. // 支付方式
  38. const WECHAT_PAY = 1;
  39. const CASH_PAY = 3;
  40. const SUBMIT_ORDER = 'submit_order';
  41. const PAY_ORDER = 'pay_order';
  42. public function rules(): array
  43. {
  44. return [
  45. [['store_id', 'user_id', 'pay_type'], 'required', 'on' => [self::SUBMIT_ORDER]],
  46. [['store_id', 'user_id', 'pay_type', 'recharge_id'], 'integer', 'on' => [self::SUBMIT_ORDER]],
  47. [['pay_price'], 'number', 'on' => [self::SUBMIT_ORDER]],
  48. [['order_no', 'pay_code'], 'string', 'on' => [self::PAY_ORDER]],
  49. [['order_no'], 'required', 'on' => [self::PAY_ORDER]],
  50. ];
  51. }
  52. public function attributeLabels(): array
  53. {
  54. return [
  55. 'store_id' => '商城ID',
  56. 'user_id' => '用户ID',
  57. 'pay_price' => '充值支付金额',
  58. 'pay_type' => '支付方式',
  59. 'order_no' => '支付的订单号',
  60. 'pay_code' => '付款码信息'
  61. ];
  62. }
  63. public function recharge(): array
  64. {
  65. try {
  66. if (!$this->validate()) {
  67. return ['code' => 1, 'msg' => $this->getErrorSummary(FALSE)[0]];
  68. }
  69. $user = User::findOne($this->user_id);
  70. if (empty($user)) {
  71. throw new \Exception('充值用户不存在');
  72. }
  73. // 验证是否开启了自定义余额充值金额
  74. $name = [
  75. 'recharge_custom_status',
  76. ];
  77. $data = Option::get($name, get_store_id(), 'recharge');
  78. $data = array_column($data, NULL, 'name');
  79. $customStatus = $data['recharge_custom_status']['value'];// 是否开启自定义充值金额
  80. if ($customStatus == 0 && $this->recharge_id == 0) {
  81. throw new \Exception('请选择充值方案');
  82. }
  83. if ($customStatus == 1 && $this->recharge_id == 0 && empty($this->pay_price)) {
  84. throw new \Exception('请输入充值金额');
  85. }
  86. if ($this->recharge_id > 0) {
  87. $rechargePlan = Recharge::find()->where(['id' => $this->recharge_id, 'store_id' => $this->store_id, 'is_delete' => Recharge::IS_DELETE_NO])->one();
  88. if (empty($rechargePlan)) {
  89. throw new \Exception('充值方案不存在');
  90. }
  91. // 充值赠送金额计算
  92. $this->pay_price = $rechargePlan->pay_price;
  93. $sendPrice = $rechargePlan->send_price;
  94. // 是否可以充值条件判断
  95. if (!empty($rechargePlan->assign_member)) {
  96. $condition = json_decode($rechargePlan->assign_member, TRUE);
  97. $numeric_array = array_map('intval', $condition);
  98. $levelType = Level::find()->where(['store_id' => get_store_id(), 'is_delete' => Level::NOT_DELETE])->andWhere(['level' => $numeric_array])->asArray()->all();
  99. if (in_array(0, $numeric_array)) {
  100. } else if (isset($user->level) && in_array($user->level, $numeric_array)) {
  101. } else {
  102. $names = ArrayHelper::getColumn(
  103. $levelType,
  104. function ($item) {
  105. return is_array($item['name']) ? implode(', ', $item['name']) : $item['name'];
  106. }
  107. );
  108. $levelNames = implode(', ', $names);
  109. if (!empty($levelNames)) {
  110. throw new \Exception("仅限 {$levelNames} 购买");
  111. }
  112. }
  113. }
  114. // 充值赠送积分计算
  115. $sendIntegral = $rechargePlan->send_integral;
  116. // 充值升级会员
  117. $levelUp = $rechargePlan->level_up;
  118. // 充值方案ID
  119. $rechargePlanId = $rechargePlan->id;
  120. } else {
  121. $sendPrice = 0;
  122. $sendIntegral = 0;
  123. $levelUp = 0;
  124. $rechargePlanId = 0;
  125. }
  126. $t = \Yii::$app->db->beginTransaction();
  127. // 创建充值订单
  128. $reOrder = new ReOrder();
  129. $reOrder->store_id = $this->store_id;
  130. $reOrder->order_no = OrderNo::getOrderNo(OrderNo::ORDER_RECHARGE);
  131. $reOrder->user_id = $user->id;
  132. $reOrder->pay_price = $this->pay_price;
  133. $reOrder->send_price = $sendPrice;
  134. $reOrder->send_integral = $sendIntegral;
  135. $reOrder->pay_type = $this->pay_type;
  136. $reOrder->is_delete = 0;
  137. $reOrder->created_at = time();
  138. $reOrder->create_user_id = get_user_id();
  139. if ($levelUp && $rechargePlanId) {
  140. $reOrder->level_up = $levelUp;
  141. $reOrder->recharge_id = $rechargePlanId;// 2024-12-19 这里的支付金额不对
  142. }
  143. // 订单生成失败 返回业务逻辑错误
  144. if (!$reOrder->save()) {
  145. $t->rollBack();
  146. throw new \Exception('订单生成失败');
  147. }
  148. if ($this->pay_type == self::CASH_PAY) {
  149. self::payConfirm($user, $reOrder);
  150. return [
  151. 'code' => 0,
  152. 'msg' => '余额充值成功',
  153. 'data' => [
  154. 'need_pay' => 0,
  155. 'order_no' => $reOrder->order_no
  156. ]
  157. ];
  158. }
  159. $t->commit();
  160. return [
  161. 'code' => 0,
  162. 'msg' => '充值订单创建成功',
  163. 'data' => [
  164. 'need_pay' => 1,
  165. 'order_no' => $reOrder->order_no
  166. ]
  167. ];
  168. } catch (\Exception $e) {
  169. return ['code' => 1, 'msg' => $e->getMessage()];
  170. }
  171. }
  172. public function pay(): array
  173. {
  174. try {
  175. if (!$this->validate()) {
  176. throw new \Exception($this->getErrorSummary(FALSE)[0]);
  177. }
  178. $order = ReOrder::find()->where(['order_no' => $this->order_no, 'is_pay' => ReOrder::NOT_PAY, 'is_delete' => ReOrder::NOT_DELETE])->one();
  179. if (empty($order)) {
  180. throw new \Exception('订单不存在');
  181. }
  182. $user = User::findOne($order->user_id);
  183. if ($order->pay_type == self::WECHAT_PAY) {
  184. if (is_profit_pay()) {
  185. $result = WechatNewPay::micropay($order, OrderNo::ORDER_MALL, '余额充值', $order->pay_price, 0, $this->pay_code);
  186. } else {
  187. $result = WechatPay::micropay($order, OrderNo::ORDER_MALL, '余额充值', $order->pay_price, 0, $this->pay_code);
  188. }
  189. if ($result['return_code'] == 'SUCCESS') {
  190. if ($result['result_code'] === 'FAIL') {
  191. // 如果返回结果不是 等待用户输入密码 则直接返回
  192. if ($result['err_code'] == 'USERPAYING') {
  193. $result = $this->checkOrderPay($order, 0);
  194. } else {
  195. return [
  196. 'code' => 1,
  197. 'msg' => '微信支付参数错误',
  198. 'data' => $result
  199. ];
  200. }
  201. }
  202. if ($result['result_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' && $result['trade_type'] == 'MICROPAY') {
  203. $t = \Yii::$app->db->beginTransaction();
  204. $order->transaction_id = $result['transaction_id'];
  205. $order->is_pay = 1;
  206. $order->pay_time = time();
  207. if (!$order->save()) {
  208. $t->rollBack();
  209. throw new \Exception('订单状态更新失败');
  210. }
  211. self::payConfirm($user, $order);
  212. $t->commit();
  213. $notifyForm = new NotifyForm();
  214. $notifyForm->addRechargeReceiver($order);
  215. queue_push(new ReOrderWechatProfitSharingJob(['store_id' => $this->store_id, 'order' => $order]), 60);
  216. return ['code' => 0, 'msg' => '余额充值成功'];
  217. }
  218. return [
  219. 'code' => 1,
  220. 'msg' => '微信支付错误',
  221. 'data' => $result
  222. ];
  223. } else {
  224. throw new \Exception('微信支付失败'.$result['return_msg']);
  225. }
  226. } else {
  227. throw new \Exception('暂不支持该支付方式');
  228. }
  229. } catch (\Exception $e) {
  230. return ['code' => 1, 'msg' => $e->getMessage()];
  231. }
  232. }
  233. public function checkOrderPay($order, $num = 0)
  234. {
  235. sleep(5);
  236. if ($num >= 45) {
  237. return ['result_code' => 'FAIL', 'data' => '支付超时'];
  238. }
  239. $num += 5;
  240. if (is_profit_pay()) {
  241. $result = WechatNewPay::orderQuery($order);
  242. } else {
  243. $result = WechatPay::orderQuery($order);
  244. }
  245. if ($result['return_code'] == 'SUCCESS') {
  246. if ($result['trade_state'] == 'USERPAYING') {
  247. return $this->checkOrderPay($order, $num);
  248. } else {
  249. return $result;
  250. }
  251. }
  252. }
  253. private static function payConfirm($user, $order): void
  254. {
  255. try {
  256. try {
  257. // 用户充值成为股东
  258. BonusPool::generalUserRecharge($order->user_id, $order->store_id);
  259. } catch (\Exception $e) {
  260. }
  261. $order->pay_time = time();
  262. $order->pay_type = self::CASH_PAY;
  263. $before = $user->money;
  264. $user->money += floatval($order->pay_price) + floatval($order->send_price);
  265. if ($order->send_integral > 0) {
  266. $old_integral = $user->integral;
  267. $user->integral += $order->send_integral;
  268. $user->total_integral += $order->send_integral;
  269. $log = new AccountLog();
  270. $log->store_id = get_store_id();
  271. $log->user_id = $user->id;
  272. $log->type = AccountLog::TYPE_INTEGRAL;
  273. $log->log_type = AccountLog::LOG_TYPE_INCOME;
  274. $log->amount = $order->send_integral;
  275. $log->desc = "充值赠送, 订单号:{$order->order_no}";
  276. $log->before = $old_integral;
  277. $log->after = $user->integral;
  278. $log->operator = 'system';
  279. $log->operator_id = 0;
  280. $log->operator_type = AccountLog::TYPE_OPERATOR_NORMAL;
  281. $log->created_at = time();
  282. $log->order_id = $order->id;
  283. $log->order_type = AccountLog::TYPE_PLATFORM_ORDER;
  284. $log->save();
  285. }
  286. $user->save();
  287. $log = new AccountLog();
  288. $log->store_id = $order->store_id;
  289. $log->user_id = $user->id;
  290. $log->type = AccountLog::TYPE_BALANCE;
  291. $log->log_type = AccountLog::LOG_TYPE_INCOME;
  292. $log->amount = floatval($order->pay_price) + floatval($order->send_price);
  293. $log->desc = "充值余额微信在线支付,付款金额:{$order->pay_price}元,赠送金额:{$order->send_price}元。";
  294. $log->before = $before;
  295. $log->after = $user->money;
  296. $log->operator = '';
  297. $log->operator_id = 0;
  298. $log->operator_type = AccountLog::TYPE_OPERATOR_NORMAL;
  299. $log->created_at = time();
  300. $log->order_id = $order->id;
  301. $log->order_type = AccountLog::TYPE_RECHARGE_ORDER;
  302. $log->save();
  303. // 生成操作记录
  304. $user = User::findOne($order->user_id);
  305. CashierActionLog::setLog($order->store_id,get_user_id(),CashierActionLog::RECHARGE_MONEY,'给'.$user->nickname.'用户充值余额');
  306. } catch (\Exception $e) {
  307. }
  308. }
  309. }