| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- <?php
- // +----------------------------------------------------------------------
- // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
- // +----------------------------------------------------------------------
- // | Copyright (c) 2016~2024 https://www.crmeb.com All rights reserved.
- // +----------------------------------------------------------------------
- // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
- // +----------------------------------------------------------------------
- // | Author: CRMEB Team <admin@crmeb.com>
- // +----------------------------------------------------------------------
- namespace app\common\repositories\store\order;
- use app\common\dao\store\order\PresellOrderDao;
- use app\common\model\store\order\PresellOrder;
- use app\common\model\user\User;
- use app\common\repositories\BaseRepository;
- use app\common\repositories\store\product\ProductPresellSkuRepository;
- use app\common\repositories\store\product\ProductRepository;
- use app\common\repositories\system\merchant\FinancialRecordRepository;
- use app\common\repositories\system\merchant\MerchantRepository;
- use app\common\repositories\user\UserBillRepository;
- use app\common\repositories\user\UserMerchantRepository;
- use app\common\repositories\user\UserRepository;
- use app\common\repositories\wechat\WechatUserRepository;
- use crmeb\jobs\UserBrokerageLevelJob;
- use crmeb\services\AlipayService;
- use crmeb\services\CombinePayService;
- use crmeb\services\MiniProgramService;
- use crmeb\services\PayService;
- use crmeb\services\WechatService;
- use think\Exception;
- use think\exception\ValidateException;
- use think\facade\Cache;
- use think\facade\Db;
- use think\facade\Log;
- use think\facade\Queue;
- /**
- * Class PresellOrderRepository
- * @package app\common\repositories\store\order
- * @author xaboy
- * @day 2020/10/27
- * @mixin PresellOrderDao
- */
- class PresellOrderRepository extends BaseRepository
- {
- public function __construct(PresellOrderDao $dao)
- {
- $this->dao = $dao;
- }
- /**
- * 创建订单
- *
- * 本函数用于创建一个新的订单。它通过收集用户ID、订单ID、价格以及订单的开始和结束时间,
- * 来构造订单的基本信息。此外,它还会为预售价订单生成一个新的订单号。
- *
- * @param int $uid 用户ID。标识订单所属的用户。
- * @param string $orderId 订单ID。用于唯一标识订单。
- * @param float $price 订单价格。表示订单的总金额。
- * @param int $final_start_time 订单开始时间。表示订单的有效起始时间。
- * @param int $final_end_time 订单结束时间。表示订单的有效结束时间。
- * @return bool|object 返回创建的订单对象或false,如果创建失败。
- */
- public function createOrder($uid, $orderId, $price, $final_start_time, $final_end_time)
- {
- // 通过DAO层创建订单,传入包括用户ID、订单ID、开始时间、结束时间、价格以及预售价订单号等信息。
- return $this->dao->create([
- 'uid' => $uid,
- 'order_id' => $orderId,
- 'final_start_time' => $final_start_time,
- 'final_end_time' => $final_end_time,
- 'pay_price' => $price,
- 'presell_order_sn' => app()->make(StoreOrderRepository::class)->getNewOrderId(StoreOrderRepository::TYPE_SN_PRESELL)
- ]);
- }
- /**
- * 处理预售订单的支付逻辑。
- *
- * 根据支付方式的不同,选择不同的支付处理方式。支持余额支付以及微信、支付宝等第三方支付。
- * 对于移动端支付,会根据支付类型添加App后缀以区分支付渠道。
- * 在支付前,会触发一个事件,允许其他功能模块在支付前进行额外的操作或校验。
- * 根据支付类型和系统配置,选择使用合并支付服务或普通支付服务来生成支付配置。
- *
- * @param string $type 支付方式,可以是余额(balance)、微信(weixin)、支付宝(alipay)等。
- * @param User $user 进行支付的用户对象。
- * @param PresellOrder $order 预售订单对象。
- * @param string $return_url 支付宝支付时的回调URL,可选。
- * @param bool $isApp 是否为APP支付,用于区分微信支付的普通支付和APP支付。
- * @return array 返回包含支付配置和订单ID的信息。
- */
- public function pay($type, User $user, PresellOrder $order, $return_url = '', $isApp = false)
- {
- // 如果是余额支付,则直接调用余额支付方法
- if ($type === 'balance') {
- return $this->payBalance($user, $order);
- }
- // 如果是微信或支付宝支付,并且是APP支付,则在支付方式后添加App后缀
- if (in_array($type, ['weixin', 'alipay'], true) && $isApp) {
- $type .= 'App';
- }
- // 在支付前触发一个事件,允许其他功能模块进行额外的操作或校验
- event('order.presell.pay.before', compact('order', 'type', 'isApp'));
- // 根据支付类型和系统配置,选择使用合并支付服务或普通支付服务
- if (in_array($type, ['weixin', 'weixinApp', 'routine', 'h5', 'weixinQr'], true) && systemConfig('open_wx_combine')) {
- $service = new CombinePayService($type, $order->getCombinePayParams());
- } else {
- $service = new PayService($type, $order->getPayParams($type === 'alipay' ? $return_url : ''), 'presell');
- }
- // 生成支付配置
- $config = $service->pay($user);
- // 返回支付配置和订单ID,供前端进行支付操作
- return app('json')->status($type, $config + ['order_id' => $order['presell_order_id']]);
- }
- /**
- * 使用余额支付预售价订单。
- *
- * 此方法处理用户使用余额支付预售价订单的流程。它首先检查余额支付是否已开启,然后确保用户余额充足。
- * 如果条件满足,它将在数据库事务中执行支付操作,包括更新用户余额、记录账单和标记订单为支付成功。
- *
- * @param User $user 当前进行支付的用户对象。
- * @param PresellOrder $order 需要支付的预售价订单对象。
- * @throws ValidateException 如果支付方式未开启或用户余额不足,则抛出验证异常。
- * @return json 返回支付成功的响应。
- */
- public function payBalance(User $user, PresellOrder $order)
- {
- // 检查余额支付是否开启,如果没有开启则抛出异常。
- if (!systemConfig('yue_pay_status'))
- throw new ValidateException('未开启余额支付');
- // 检查用户余额是否足够支付订单,如果不足则抛出异常。
- if ($user['now_money'] < $order['pay_price'])
- throw new ValidateException('余额不足,请更换支付方式');
- // 使用数据库事务来确保支付操作的原子性。
- Db::transaction(function () use ($user, $order) {
- // 更新用户的余额,并保存更改。
- $user->now_money = bcsub($user->now_money, $order['pay_price'], 2);
- $user->save();
- // 创建用户账单记录,记录用户余额的减少。
- $userBillRepository = app()->make(UserBillRepository::class);
- $userBillRepository->decBill($user['uid'], 'now_money', 'presell', [
- 'link_id' => $order['presell_order_id'],
- 'status' => 1,
- 'title' => '支付预售尾款',
- 'number' => $order['pay_price'],
- 'mark' => '余额支付支付' . floatval($order['pay_price']) . '元购买商品',
- 'balance' => $user->now_money
- ]);
- // 标记订单为支付成功。
- $this->paySuccess($order);
- });
- // 返回支付成功的响应。
- return app('json')->status('success', '余额支付成功', ['order_id' => $order['presell_order_id']]);
- }
- /**
- * 处理预售订单支付成功后的业务逻辑。
- *
- * @param PresellOrder $order 预售订单对象
- * @param int $is_combine 是否为合并支付,0表示正常支付,1表示合并支付
- * @param array $subOrders 子订单数组,包含交易号等信息
- *
- * 此函数在支付成功后,更新订单状态,记录支付信息,并处理相关的财务记录。
- * 同时,它还处理了订单相关的佣金计算和分佣逻辑。
- */
- public function paySuccess(PresellOrder $order, $is_combine = 0, array $subOrders = [])
- {
- Db::transaction(function () use ($is_combine, $order, $subOrders) {
- $time = date('Y-m-d H:i:s');
- $order->paid = 1;
- $order->pay_time = $time;
- if (isset($subOrders[$order->presell_order_sn])) {
- $order->transaction_id = $subOrders[$order->presell_order_sn]['transaction_id'];
- }
- $order->is_combine = $is_combine;
- $order->order->status = 0;
- $storeOrderRepository = app()->make(StoreOrderRepository::class);
- if ($order->order->order_type == 1) {
- $order->order->verify_code = $storeOrderRepository->verifyCode();
- }
- if (empty($order->order_sn)) {
- $order->order_sn = $storeOrderRepository->getOrderSn($order->order_id);
- }
- $order->order->save();
- $order->save();
- //订单记录
- $statusRepository = app()->make(StoreOrderStatusRepository::class);
- $orderStatus = [
- 'order_id' => $order->order_id,
- 'order_sn' => $order->order_sn,
- 'type' => $statusRepository::TYPE_ORDER,
- 'change_message' => '订单尾款支付成功',
- 'change_type' => $statusRepository::ORDER_STATUS_PRESELL,
- ];
- $i = 1;
- $finance = [];
- $final_price = $order->order->pay_price;
- $order_price = $order->pay_price;
- $pay_price = bcadd($order_price, $final_price, 2);
- $sn = app()->make(FinancialRecordRepository::class)->getSn();
- $finance[] = [
- 'order_id' => $order->order_id,
- 'order_sn' => $order->presell_order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'presell',
- 'financial_pm' => 1,
- 'type' => 2,
- 'number' => $order->pay_price,
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- $finance[] = [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'mer_presell',
- 'financial_pm' => 1,
- 'type' => 0,
- 'number' => $pay_price,
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- // $pay_price = bcsub($pay_price, bcadd($order->order['extension_one'], $order->order['extension_two'], 3), 2);
- if (isset($order->order->orderProduct[0]['cart_info']['presell_extension_one']) && $order->order->orderProduct[0]['cart_info']['presell_extension_one'] > 0) {
- $order_price = bcsub($order_price, $order->order->orderProduct[0]['cart_info']['presell_extension_one'], 2);
- }
- if (isset($order->order->orderProduct[0]['cart_info']['presell_extension_two']) && $order->order->orderProduct[0]['cart_info']['presell_extension_two'] > 0) {
- $order_price = bcsub($order_price, $order->order->orderProduct[0]['cart_info']['presell_extension_two'], 2);
- }
- if (isset($order->order->orderProduct[0]['cart_info']['final_extension_one']) && $order->order->orderProduct[0]['cart_info']['final_extension_one'] > 0) {
- $final_price = bcsub($final_price, $order->order->orderProduct[0]['cart_info']['final_extension_one'], 2);
- }
- if (isset($order->order->orderProduct[0]['cart_info']['final_extension_two']) && $order->order->orderProduct[0]['cart_info']['final_extension_two'] > 0) {
- $final_price = bcsub($final_price, $order->order->orderProduct[0]['cart_info']['final_extension_two'], 2);
- }
- if ($order->order['extension_one'] > 0) {
- $finance[] = [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'brokerage_one',
- 'financial_pm' => 0,
- 'type' => 1,
- 'number' => $order->order['extension_one'],
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- }
- if ($order->order['extension_two'] > 0) {
- $finance[] = [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'brokerage_two',
- 'financial_pm' => 0,
- 'type' => 1,
- 'number' => $order->order['extension_two'],
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- }
- if ($order->order->commission_rate > 0) {
- $commission_rate = ($order->order->commission_rate / 100);
- $finalRatePrice = bcmul($final_price, $commission_rate, 2);
- $orderRatePrice = bcmul($order_price, $commission_rate, 2);
- $ratePrice = bcadd($finalRatePrice, $orderRatePrice, 2);
- $finance[] = [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'presell_charge',
- 'financial_pm' => 1,
- 'type' => 1,
- 'number' => $ratePrice,
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- // $pay_price = bcsub($pay_price, $ratePrice, 2);
- $order_price = bcsub($order_price, $orderRatePrice, 2);
- $final_price = bcsub($final_price, $finalRatePrice, 2);
- }
- $finance[] = [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'presell_true',
- 'financial_pm' => 1,
- 'type' => 2,
- 'number' => bcadd($order_price, $final_price, 2),
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . ($i++),
- 'pay_type' => $order->pay_type,
- ];
- if (!$is_combine && $order->pay_type != 7) {
- app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'presell', $order->presell_order_id, !$order->order->groupOrder->is_combine ? bcadd($order_price, $final_price, 2) : $order_price);
- // app()->make(MerchantRepository::class)->addMoney($order->mer_id, !$order->order->groupOrder->is_combine ? bcadd($order_price, $final_price, 2) : $order_price);
- } else if (!$order->order->groupOrder->is_combine && $order->pay_type != 7) {
- app()->make(MerchantRepository::class)->addLockMoney($order->mer_id, 'presell', $order->presell_order_id, $final_price);
- // app()->make(MerchantRepository::class)->addMoney($order->mer_id, $final_price);
- }
- if ($is_combine) {
- $storeOrderProfitsharingRepository = app()->make(StoreOrderProfitsharingRepository::class);
- $storeOrderProfitsharingRepository->create([
- 'profitsharing_sn' => $storeOrderProfitsharingRepository->getOrderSn(),
- 'order_id' => $order->order->order_id,
- 'mer_id' => $order->mer_id,
- 'transaction_id' => $order->transaction_id ?? '',
- 'profitsharing_price' => $order->pay_price,
- 'profitsharing_mer_price' => $order_price,
- 'type' => $storeOrderProfitsharingRepository::PROFITSHARING_TYPE_PRESELL,
- ]);
- }
- app()->make(UserRepository::class)->update($order->uid, [
- 'pay_price' => Db::raw('pay_price+' . $order->pay_price),
- ]);
- app()->make(ProductPresellSkuRepository::class)->incCount($order->order->orderProduct[0]['activity_id'], $order->order->orderProduct[0]['product_sku'], 'two_pay');
- app()->make(UserMerchantRepository::class)->updatePayTime($order->uid, $order->mer_id, $order->pay_price, false);
- app()->make(FinancialRecordRepository::class)->insertAll($finance);
- $statusRepository->createUserLog($orderStatus);
- });
- if ($order->user->spread_uid) {
- Queue::push(UserBrokerageLevelJob::class, ['uid' => $order->user->spread_uid, 'type' => 'spread_money', 'inc' => $order->pay_price]);
- }
- Queue::push(UserBrokerageLevelJob::class, ['uid' => $order->uid, 'type' => 'pay_money', 'inc' => $order->pay_price]);
- event('order.presll.paySuccess', compact('order'));
- }
- /**
- * 取消预售订单
- * 当预售订单超过支付时间未支付时,调用此函数进行订单取消操作。
- * 主要包括以下几个步骤:
- * 1. 根据预售订单ID查询订单信息,确认订单未支付。
- * 2. 更新订单状态为关闭,并对相关商品库存进行回滚。
- * 3. 如果订单有关联的预付分账信息,处理预付分账的退款及记录。
- * 4. 生成相关的财务记录。
- * 5. 触发相关的事件,供其他系统监听并执行相应的操作。
- *
- * @param int $id 预售订单ID
- */
- public function cancel($id)
- {
- $order = $this->dao->getWhere(['presell_order_id' => $id, 'paid' => 0]);
- if (!$order) return;
- //订单记录
- $statusRepository = app()->make(StoreOrderStatusRepository::class);
- $orderStatus = [
- 'order_id' => $order->order_id,
- 'order_sn' => $order->order_sn,
- 'type' => $statusRepository::TYPE_ORDER,
- 'change_message' => '预售订单超时支付自动关闭',
- 'change_type' => $statusRepository::ORDER_STATUS_PRESELL_CLOSE,
- ];
- event('order.presll.fail.before', compact('order'));
- $productRepository = app()->make(ProductRepository::class);
- Db::transaction(function () use ($productRepository, $order, $orderStatus,$statusRepository) {
- $statusRepository->createSysLog($orderStatus);
- $order->order->status = 11;
- $order->status = 0;
- $order->save();
- $order->order->save();
- foreach ($order->order->orderProduct as $cart) {
- try{
- $productRepository->orderProductIncStock($order->order, $cart);
- }catch (Exception $e) {}
- }
- if ($order->order->firstProfitsharing && $order->order->firstProfitsharing->profitsharing_price > 0) {
- $make = app()->make(FinancialRecordRepository::class);
- $sn = $make->getSn();
- $financial = [[
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'presell_charge',
- 'financial_pm' => 1,
- 'type' => 1,
- 'number' => bcsub($order->order->firstProfitsharing->profitsharing_price, $order->order->firstProfitsharing->profitsharing_mer_price, 2),
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . '0'
- ], [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'mer_presell',
- 'financial_pm' => 1,
- 'type' => 0,
- 'number' => $order->order->firstProfitsharing->profitsharing_mer_pric,
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . '1'
- ], [
- 'order_id' => $order->order->order_id,
- 'order_sn' => $order->order->order_sn,
- 'user_info' => $order->user->nickname,
- 'user_id' => $order->uid,
- 'financial_type' => 'presell_true',
- 'financial_pm' => 1,
- 'type' => 2,
- 'number' => $order->order->firstProfitsharing->profitsharing_mer_price,
- 'mer_id' => $order->mer_id,
- 'financial_record_sn' => $sn . '2'
- ]];
- $make->insertAll($financial);
- try {
- app()->make(StoreOrderProfitsharingRepository::class)->profitsharing($order->order->firstProfitsharing);
- } catch (\Exception $e) {
- Log::info('预售定金分账失败' . $order->order_id . $e->getMessage());
- }
- }
- });
- event('order.presll.fail', compact('order'));
- }
- }
|