feat : coupon
This commit is contained in:
22
app/Service/Admin/Order/OrderInfoService.php
Normal file
22
app/Service/Admin/Order/OrderInfoService.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Order;
|
||||
|
||||
use App\Service\Admin\BaseService;
|
||||
|
||||
class OrderInfoService extends BaseService
|
||||
{
|
||||
public function handle()
|
||||
{
|
||||
//todo Write logic
|
||||
return $this->return->success();
|
||||
}
|
||||
}
|
||||
22
app/Service/Admin/Order/OrderListService.php
Normal file
22
app/Service/Admin/Order/OrderListService.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Order;
|
||||
|
||||
use App\Service\Admin\BaseService;
|
||||
|
||||
class OrderListService extends BaseService
|
||||
{
|
||||
public function handle()
|
||||
{
|
||||
//todo Write logic
|
||||
return $this->return->success();
|
||||
}
|
||||
}
|
||||
83
app/Service/Admin/Order/RefundService.php
Normal file
83
app/Service/Admin/Order/RefundService.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Order;
|
||||
|
||||
use App\Constants\Common\RefundCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Service\Admin\BaseService;
|
||||
use App\Service\Amqp\Refund\FullRefundOrderService;
|
||||
use App\Service\Amqp\Refund\PartialRefundOrderService;
|
||||
use Exception;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class RefundService extends BaseService
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
try {
|
||||
$orderId = (int)$this->request->input('order_id');
|
||||
|
||||
$service = new FullRefundOrderService();
|
||||
$service->orderId = $orderId;
|
||||
$service->reason = $this->request->input('reason','');
|
||||
$service->type = RefundCode::FULL_GOOD_REFUND;
|
||||
|
||||
$service->handle();
|
||||
|
||||
return $this->return->success();
|
||||
}catch (Exception $e) {
|
||||
throw new ErrException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
public function refundPartial(): array
|
||||
{
|
||||
try {
|
||||
$orderId = (int)$this->request->input('order_id');
|
||||
$orderGoodIds = $this->request->input('order_good_ids');
|
||||
if (empty($orderGoodIds)) throw new ErrException('请选择商品再退款');
|
||||
|
||||
$service = new PartialRefundOrderService();
|
||||
$service->orderId = $orderId;
|
||||
$service->reason = $this->request->input('reason','');
|
||||
$service->orderGoodIds = $orderGoodIds;
|
||||
$service->type = RefundCode::PARTIAL_GOOD_REFUND;
|
||||
|
||||
$service->handle();
|
||||
|
||||
return $this->return->success();
|
||||
}catch (Exception $e) {
|
||||
throw new ErrException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function refundBatch(): array
|
||||
{
|
||||
$siteId = $this->request->input('site_id');
|
||||
$cycleId = (int)$this->request->input('cycle_id');
|
||||
|
||||
return $this->return->success();
|
||||
}
|
||||
}
|
||||
301
app/Service/Amqp/Refund/BaseRefundOrderService.php
Normal file
301
app/Service/Amqp/Refund/BaseRefundOrderService.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Amqp\Refund;
|
||||
|
||||
use App\Constants\Common\OrderCode;
|
||||
use App\Constants\Common\PayCode;
|
||||
use App\Constants\Common\RefundCode;
|
||||
use App\Model\Order;
|
||||
use App\Model\OrderGood;
|
||||
use App\Model\PayOrder;
|
||||
use App\Model\RefundOrder;
|
||||
use App\Model\UserCoupon;
|
||||
use App\Service\Common\Pay\Wx\WxJsRechargeOrderService;
|
||||
use App\Service\ServiceTrait\Api\OrderTrait;
|
||||
use Exception;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
abstract class BaseRefundOrderService
|
||||
{
|
||||
use OrderTrait;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public int $orderId;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public string $reason;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public int $type;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $orderGoodIds = [];
|
||||
|
||||
/**
|
||||
* @var Order
|
||||
*/
|
||||
#[Inject]
|
||||
protected Order $orderModel;
|
||||
|
||||
/**
|
||||
* @var PayOrder
|
||||
*/
|
||||
#[Inject]
|
||||
protected PayOrder $payOrderModel;
|
||||
|
||||
/**
|
||||
* @var Order
|
||||
*/
|
||||
protected Order $orderInfo;
|
||||
|
||||
/**
|
||||
* @var PayOrder
|
||||
*/
|
||||
protected PayOrder $payInfo;
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
public float $refundAmount;
|
||||
|
||||
abstract function handle();
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
protected function getOrderInfo(): void
|
||||
{
|
||||
$this->orderInfo = match ($this->orderType) {
|
||||
OrderCode::ORDER_TYPE_GOOD => $this->orderModel->getInfoById($this->orderId),
|
||||
// OrderCode::ORDER_TYPE_BALANCE => $this->orderModel->getInfoById($this->orderId),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $orderGoodList;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $totalGoodsPrice = '0';
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function checkGoodOrder(): void
|
||||
{
|
||||
if (empty($this->orderInfo)) throw new Exception('订单信息不存在:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type]));
|
||||
|
||||
if (!in_array($this->orderInfo->status,OrderCode::CAN_REFUND_STATUS)) throw new Exception('订单状态不能退款:'.json_encode($this->orderInfo->toArray()));
|
||||
|
||||
//余额订单必须退款全部金额
|
||||
// if ($this->type == OrderCode::ORDER_TYPE_BALANCE && $this->refundAmount != $this->orderInfo->actual_price) throw new Exception('余额订单必须退款全部金额:'.json_encode($this->orderInfo->toArray()));
|
||||
|
||||
if ($this->type != RefundCode::PARTIAL_GOOD_REFUND) return;
|
||||
|
||||
if (empty($this->orderGoodIds)) throw new Exception('商品信息不存在:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type,'goods_list' => $this->orderGoodIds]));
|
||||
|
||||
$orderGoodList = $this->orderGoodModel->whereIn('id',$this->orderGoodIds)->where('order_id',$this->orderId)->get();
|
||||
if ($orderGoodList->isEmpty()) throw new Exception('该订单没有这些商品信息:'.json_encode(['order_id' => $this->orderId,'order_type' => $this->type,'goods_list' => $this->orderGoodIds]));
|
||||
$this->orderGoodList = $orderGoodList->toArray();
|
||||
unset($orderGoodList);
|
||||
foreach ($this->orderGoodList as $orderGood) {
|
||||
if (!in_array($orderGood['status'],OrderCode::CAN_REFUND_STATUS)) throw new Exception('商品状态不能退款:'.json_encode(['order_info' => $this->orderInfo->toArray(),'order_good' => $orderGood,'goods_list' => $this->orderGoodIds]));
|
||||
|
||||
$oneGoodTotalPrice = bcmul((string)$orderGood['unit_price'],(string)$orderGood['quantity'],2);
|
||||
$this->totalGoodsPrice = bcadd($this->totalGoodsPrice, $oneGoodTotalPrice,2) ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getPayOrder(): void
|
||||
{
|
||||
$this->payInfo = $this->payOrderModel->getInfoByOrderIdAndType($this->orderId, $this->orderType);
|
||||
|
||||
if (empty($this->payInfo)) throw new Exception('支付信息不存在');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function getRefundAmount(): void
|
||||
{
|
||||
$this->refundAmount = match ($this->type) {
|
||||
RefundCode::BALANCE_REFUND => $this->getBalanceRefundAmount(),
|
||||
RefundCode::FULL_GOOD_REFUND => $this->getFullGoodRefundAmount(),
|
||||
RefundCode::PARTIAL_GOOD_REFUND => $this->getPartialGoodAmount(),
|
||||
default => throw new Exception('退款类型错误'),
|
||||
};
|
||||
|
||||
if ($this->refundAmount <= 0) throw new Exception('退款金额不能为0');
|
||||
}
|
||||
|
||||
/**
|
||||
* @var RefundOrder
|
||||
*/
|
||||
#[Inject]
|
||||
protected RefundOrder $refundOrderModel;
|
||||
|
||||
private function getBalanceRefundAmount(): float
|
||||
{
|
||||
$isRefundMoney = $this->refundOrderModel->getAllMoneyByOrderId($this->refundInfo->order_id,$this->refundInfo->order_type);
|
||||
|
||||
return $this->payInfo->pay_money - $isRefundMoney;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
private function getFullGoodRefundAmount(): float
|
||||
{
|
||||
$isRefundMoney = $this->refundOrderModel->getAllMoneyByOrderId($this->refundInfo->order_id,$this->refundInfo->order_type);
|
||||
|
||||
// 部分退款会验证 pay_money != order_money throw error 所以不需要判断
|
||||
return $this->payInfo->pay_money - $isRefundMoney;
|
||||
}
|
||||
|
||||
|
||||
protected UserCoupon $userCouponModel;
|
||||
|
||||
/**
|
||||
* @return float
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getPartialGoodAmount(): float
|
||||
{
|
||||
if ($this->totalGoodsPrice <= 0) throw new Exception('商品退款价格不能为0');
|
||||
// 部分退款 不支持 价格不一致
|
||||
if ($this->payInfo->pay_money != $this->orderInfo->actual_price) throw new Exception('价格不一致的订单无法部分退款');
|
||||
|
||||
$isRefundMoney = $this->refundOrderModel->getSuccessMoneyByOrderId($this->refundInfo->order_id,$this->refundInfo->order_type);
|
||||
|
||||
return floatval(min($this->payInfo->pay_money - $isRefundMoney,$this->totalGoodsPrice));
|
||||
}
|
||||
|
||||
/**
|
||||
* @var RefundOrder
|
||||
*/
|
||||
protected RefundOrder $refundInfo;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function insertRefundOrder(): void
|
||||
{
|
||||
$this->refundInfo = new RefundOrder();
|
||||
|
||||
$this->refundInfo->user_id = $this->orderInfo->user_id;
|
||||
$this->refundInfo->order_type = $this->type;
|
||||
$this->refundInfo->order_id = $this->orderId;
|
||||
$this->refundInfo->pay_id = $this->payInfo->id;
|
||||
$this->refundInfo->refund_status = RefundCode::WAIT_REFUND;
|
||||
$this->refundInfo->refund_money = $this->refundAmount;
|
||||
$this->refundInfo->refund_type = $this->payInfo->recharge_type;
|
||||
$this->refundInfo->refund_order_sno = $this->generateRefundOrderNo($this->type, $this->orderInfo->user_id);
|
||||
$this->refundInfo->reason = $this->reason;
|
||||
|
||||
if (!$this->refundInfo->save()) throw new Exception('退款订单创建失败');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
protected function refund(): void
|
||||
{
|
||||
$rechargeService = match ($this->refundInfo->refund_type)
|
||||
{
|
||||
PayCode::ALIPAY => $this->setAliPayRefund(),
|
||||
PayCode::WECHAT_PAY => $this->setWechatPayRefund(),
|
||||
};
|
||||
|
||||
$rechargeService->setConfig();
|
||||
$rechargeService->setRefundNotify();
|
||||
|
||||
$rechargeService->refund(
|
||||
$this->refundAmount,
|
||||
(float)$this->payInfo->pay_money,
|
||||
$this->orderInfo->order_sno,
|
||||
$this->refundInfo->refund_order_sno,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function updateRefund(): void
|
||||
{
|
||||
$status = RefundCode::WAIT_BY_PAY_TOOL;
|
||||
$errMsg = '等待支付工具退款';
|
||||
|
||||
$this->refundInfo->refund_status = $status;
|
||||
$this->refundInfo->remark = $errMsg;
|
||||
|
||||
if (!$this->refundInfo->save()) throw new Exception('退款订单更新失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $errMsg
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function updateError(string $errMsg = ''): void
|
||||
{
|
||||
if (empty($this->refundInfo)) return;
|
||||
|
||||
$status = RefundCode::REFUND_FAIL;
|
||||
$errMsg = empty($errMsg) ? '未知错误' : $errMsg;
|
||||
|
||||
$this->refundInfo->refund_status = $status;
|
||||
$this->refundInfo->remark = $errMsg;
|
||||
|
||||
if (!$this->refundInfo->save()) throw new Exception('退款订单更新失败');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
protected function setAliPayRefund(): null
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WxJsRechargeOrderService
|
||||
*/
|
||||
protected function setWechatPayRefund(): WxJsRechargeOrderService
|
||||
{
|
||||
return new WxJsRechargeOrderService();
|
||||
}
|
||||
}
|
||||
54
app/Service/Amqp/Refund/FullRefundOrderService.php
Normal file
54
app/Service/Amqp/Refund/FullRefundOrderService.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Amqp\Refund;
|
||||
|
||||
use App\Constants\Common\OrderCode;
|
||||
use Exception;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class FullRefundOrderService extends BaseRefundOrderService
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $orderType = OrderCode::ORDER_TYPE_GOOD;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$this->getOrderInfo();
|
||||
|
||||
$this->checkGoodOrder();
|
||||
|
||||
$this->getPayOrder();
|
||||
|
||||
$this->getRefundAmount();
|
||||
|
||||
$this->insertRefundOrder();
|
||||
|
||||
$this->refund();
|
||||
|
||||
$this->updateRefund();
|
||||
} catch (Exception $e) {
|
||||
$errArr = explode(":", $e->getMessage());
|
||||
$errMsg = $errArr[0];
|
||||
$this->updateError($errMsg);
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
62
app/Service/Amqp/Refund/PartialRefundOrderService.php
Normal file
62
app/Service/Amqp/Refund/PartialRefundOrderService.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Amqp\Refund;
|
||||
|
||||
use App\Constants\Common\OrderCode;
|
||||
use App\Model\OrderGood;
|
||||
use Exception;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class PartialRefundOrderService extends BaseRefundOrderService
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $orderType = OrderCode::ORDER_TYPE_GOOD;
|
||||
|
||||
/**
|
||||
* @var OrderGood
|
||||
*/
|
||||
#[Inject]
|
||||
protected OrderGood $orderGoodModel;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
* @throws Exception
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
try {
|
||||
$this->getOrderInfo();
|
||||
|
||||
$this->checkGoodOrder();
|
||||
|
||||
$this->getPayOrder();
|
||||
|
||||
$this->getRefundAmount();
|
||||
|
||||
$this->insertRefundOrder();
|
||||
|
||||
$this->refund();
|
||||
|
||||
$this->updateRefund();
|
||||
} catch (Exception $e) {
|
||||
$errArr = explode(":", $e->getMessage());
|
||||
$errMsg = $errArr[0];
|
||||
$this->updateError($errMsg);
|
||||
throw new Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
namespace App\Service\Api\Order;
|
||||
|
||||
use App\Constants\Common\OrderCode;
|
||||
use App\Constants\Common\RefundCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Model\Order;
|
||||
use App\Model\PayOrder;
|
||||
@@ -55,7 +56,7 @@ class RefundOrderService extends BaseService
|
||||
if (empty($payInfo)) throw new ErrException('订单支付信息不存在');
|
||||
|
||||
//立即取消
|
||||
$this->joinRefundQueue($orderId, $type, (float)$payInfo->pay_money, '用户主动取消订单');
|
||||
$this->joinRefundQueue($orderId, RefundCode::FULL_GOOD_REFUND, '用户主动取消订单');
|
||||
|
||||
return $this->return->success();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Service\Common\Pay\Wx;
|
||||
|
||||
use App\Constants\Common\OrderCode;
|
||||
use App\Constants\Common\PayCode;
|
||||
use App\Constants\Common\RefundCode;
|
||||
use App\Service\ServiceTrait\Api\CateringTrait;
|
||||
use App\Service\ServiceTrait\Api\CheckOrderCallBackTrait;
|
||||
use App\Service\ServiceTrait\Api\CouponTrait;
|
||||
@@ -90,7 +91,7 @@ class WxJsRechargeOrderService extends WxJsRechargeBaseService
|
||||
});
|
||||
|
||||
//已经截单 自动退款
|
||||
if (!$this->isCatering) $this->joinRefundQueue($this->orderId,OrderCode::ORDER_TYPE_GOOD,$this->orderInfo->actual_price,'已截单,系统自动退款');
|
||||
if (!$this->isCatering) $this->joinRefundQueue($this->orderId,RefundCode::FULL_GOOD_REFUND,'已截单,系统自动退款');
|
||||
|
||||
//todo 发送订阅通知
|
||||
// $this->sendGainCoinMsg();
|
||||
|
||||
@@ -44,19 +44,17 @@ trait OrderChangeStatusTrait
|
||||
|
||||
/**
|
||||
* @param int $orderId
|
||||
* @param int $type
|
||||
* @param float|int $amount amount = 0 全部 amount > 0 部分
|
||||
* @param int $type refundCode
|
||||
* @param string $reason
|
||||
* @return void
|
||||
* @throws ContainerExceptionInterface
|
||||
* @throws NotFoundExceptionInterface
|
||||
*/
|
||||
protected function joinRefundQueue(int $orderId, int $type, float|int $amount = 0, string $reason = '系统自动'): void
|
||||
protected function joinRefundQueue(int $orderId, int $type, string $reason = '系统自动'): void
|
||||
{
|
||||
$message = new RefundOrderProducer([
|
||||
'order_id' => $orderId,
|
||||
'type' => $type,
|
||||
'amount' => $amount,
|
||||
'reason' => $reason
|
||||
]);
|
||||
$producer = ApplicationContext::getContainer()->get(Producer::class);
|
||||
|
||||
Reference in New Issue
Block a user