251 lines
5.4 KiB
PHP
251 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace Modules\Mall\Facades;
|
|
|
|
use Exception;
|
|
use Illuminate\Contracts\Auth\Authenticatable;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Modules\Mall\Events\RefundApplied;
|
|
use Modules\Mall\Models\Order as OrderModel;
|
|
use Modules\Mall\Models\Refund as RefundModel;
|
|
|
|
class Refund
|
|
{
|
|
|
|
protected $user;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected string $remark;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected array $logs;
|
|
|
|
protected $refund;
|
|
|
|
protected $order;
|
|
|
|
protected $items;
|
|
|
|
protected $total;
|
|
|
|
/**
|
|
* @throws \Exception
|
|
*/
|
|
public function user($user): Refund
|
|
{
|
|
if ($user instanceof Authenticatable) {
|
|
$this->user = $user;
|
|
} else {
|
|
throw new Exception('非法用户');
|
|
}
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 订单
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 8:46
|
|
* @param OrderModel $order
|
|
* @return $this
|
|
*/
|
|
public function order(OrderModel $order): Refund
|
|
{
|
|
$this->order = $order;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes:商品
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 8:46
|
|
* @param array $items
|
|
* @return Refund
|
|
*/
|
|
public function items(array $items): Refund
|
|
{
|
|
$this->items = $items;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 退款金额
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 8:48
|
|
* @param float $total
|
|
* @return Refund
|
|
*/
|
|
public function total(float $total): Refund
|
|
{
|
|
$this->total = $total;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 设置订单备注信息
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/21 10:31
|
|
* @param string $remark
|
|
* @return $this
|
|
*/
|
|
public function remark(string $remark): Refund
|
|
{
|
|
$this->remark = $remark;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 退款日志
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 11:37
|
|
* @param $logs
|
|
* @return $this
|
|
*/
|
|
public function logs($logs): Refund
|
|
{
|
|
if (! isset($logs['remark']) && ! empty($this->remark)) {
|
|
$logs['remark'] = $this->remark;
|
|
}
|
|
|
|
$this->logs = $logs;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 设置退款商品
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 8:51
|
|
*/
|
|
public function setItems(): Refund
|
|
{
|
|
$this->items = $this->order->items->map(function ($item) {
|
|
return [
|
|
'order_item_id' => $item->id,
|
|
'qty' => $item->qty,
|
|
];
|
|
});
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Notes: 创建退款单
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2021/5/17 8:49
|
|
* @return mixed
|
|
* @throws \Exception
|
|
*/
|
|
public function create()
|
|
{
|
|
|
|
if (! $this->order) {
|
|
throw new Exception('未设置订单');
|
|
}
|
|
|
|
if (empty($this->items)) {
|
|
$this->setItems();
|
|
}
|
|
|
|
if (! $this->order->can('refund')) {
|
|
throw new Exception('订单状态不可退款');
|
|
}
|
|
|
|
$maxAmount = 0;
|
|
$refundItems = [];
|
|
|
|
//判断最大可退数量
|
|
foreach ($this->items as $item) {
|
|
|
|
$orderItem = $this->order->items()->find($item['order_item_id']);
|
|
if (! $orderItem) {
|
|
throw new Exception('未找到可退商品');
|
|
}
|
|
|
|
if (! $orderItem->canRefund()) {
|
|
throw new \Exception('退款/货失败,此商品不可退款/货');
|
|
}
|
|
|
|
if ($item['qty'] <= 0) {
|
|
throw new Exception('【'.$orderItem->source['goods_name'].'】退货数量必须大于0');
|
|
}
|
|
|
|
if ($item['qty'] > $orderItem->qty) {
|
|
throw new Exception('【'.$orderItem->source['goods_name'].'】超过最大可退数量');
|
|
}
|
|
|
|
$maxAmount += $orderItem->price * $item['qty'];
|
|
|
|
$refundItems[] = new RefundItem($orderItem, $item['qty']);
|
|
}
|
|
|
|
// 自动计算退款金额
|
|
if (is_null($this->total)) {
|
|
$this->total = $maxAmount;
|
|
} elseif ($this->total > $maxAmount) {
|
|
throw new Exception('超过最大可退金额');
|
|
}
|
|
|
|
DB::transaction(function () use ($refundItems) {
|
|
$this->refund = $this->order->refunds()
|
|
->create([
|
|
'refund_total' => $this->total,
|
|
'actual_total' => 0,
|
|
'user_id' => $this->user->id,
|
|
'shop_id' => $this->order->shop_id,
|
|
'state' => RefundModel::REFUND_APPLY,
|
|
'remark' => $this->remark,
|
|
]);
|
|
|
|
foreach ($refundItems as $item) {
|
|
$this->refund->items()->create($item->toArray());
|
|
}
|
|
|
|
if ($this->logs) {
|
|
$this->createLog();
|
|
}
|
|
|
|
event(new RefundApplied($this->order, $this->refund));
|
|
|
|
});
|
|
|
|
return $this->refund;
|
|
|
|
}
|
|
|
|
/**
|
|
* Notes: 添加日志
|
|
*
|
|
* @Author: 玄尘
|
|
* @Date : 2020/12/11 11:43
|
|
*/
|
|
public function createLog()
|
|
{
|
|
$logs = $this->logs;
|
|
|
|
if ($this->user) {
|
|
$logs['userable_type'] = get_class($this->user);
|
|
$logs['userable_id'] = $this->user->id;
|
|
$logs['state'] = $this->refund->state;
|
|
}
|
|
|
|
$this->refund->logs()->create($logs);
|
|
}
|
|
|
|
}
|