408 lines
13 KiB
PHP
408 lines
13 KiB
PHP
<?php
|
|
|
|
namespace Peidikeji\Order\Http\Api;
|
|
|
|
use Peidikeji\Order\Exceptions\OrderException;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Resources\UserAddressResource;
|
|
use App\Models\UserAddress;
|
|
use App\Models\Zone;
|
|
use App\Services\Kuaidi100Service;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\Rule;
|
|
use Illuminate\Validation\Rules\Enum;
|
|
use Peidikeji\Merchant\Models\Merchant;
|
|
use Peidikeji\Order\Enums\OrderScene;
|
|
use Peidikeji\Order\Enums\OrderStatus;
|
|
use Peidikeji\Order\Enums\PayWay;
|
|
use Peidikeji\Order\Enums\ShipWay;
|
|
use Peidikeji\Order\Http\Resources\OrderResource;
|
|
use Peidikeji\Order\Http\Resources\OrderShipResouce;
|
|
use Peidikeji\Order\OrderService;
|
|
use Peidikeji\Order\OrderStore;
|
|
|
|
class OrderController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$query = $user->orders()->with(['goods', 'merchant'])->filter($request->all());
|
|
|
|
$list = $query->sort()->paginate($request->input('per_page'));
|
|
|
|
return $this->json(OrderResource::collection($list));
|
|
}
|
|
|
|
public function total()
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$query = $user->orders();
|
|
|
|
$maps = [
|
|
'unpay' => OrderStatus::None,
|
|
'paid' => OrderStatus::Paid,
|
|
'send_full' => OrderStatus::SendFull,
|
|
'receive' => OrderStatus::Receive
|
|
];
|
|
$data = [];
|
|
|
|
foreach($maps as $key => $status) {
|
|
$data[$key] = $query->clone()->filter(['status' => $status->value])->count();
|
|
}
|
|
|
|
return $this->json($data);
|
|
}
|
|
|
|
public function sure(Request $request)
|
|
{
|
|
$request->validate([
|
|
'scene' => ['required', new Enum(OrderScene::class)],
|
|
'goods' => [Rule::requiredIf(!$request->filled('cart_id')), 'array'],
|
|
'cart_id' => ['array'],
|
|
'merchant_id' => [Rule::requiredIf($request->input('scene') === OrderScene::Merchant->value)],
|
|
]);
|
|
$user = auth('api')->user();
|
|
|
|
$service = OrderStore::init()->user($user)->scene($request->input('scene'));
|
|
|
|
if ($request->filled('merchant_id')) {
|
|
$merchant = Merchant::findOrFail($request->input('merchant_id'));
|
|
if (!$merchant->enable()) {
|
|
throw new OrderException('店铺不可用');
|
|
}
|
|
$service->merchant($merchant);
|
|
}
|
|
|
|
$goods = $request->input('goods');
|
|
if ($request->filled('cart_id')) {
|
|
$goods = $this->formatCartGoods($user->carts()->whereIn('id', $request->input('cart_id'))->get());
|
|
}
|
|
$service->goods($goods);
|
|
|
|
// 收货地址
|
|
$address = null;
|
|
if ($request->filled('address_id')) {
|
|
$address = $user->addresses()->find($request->input('address_id'));
|
|
if (!$address) {
|
|
return $this->error('收货地址不存在');
|
|
}
|
|
}
|
|
if (!$address) {
|
|
$address = $user->addresses()->orderBy('is_default', 'desc')->orderBy('created_at', 'desc')->first();
|
|
}
|
|
|
|
$service->ship(ShipWay::Express->value, $this->formatAddress($address));
|
|
|
|
// 计算最大积分抵扣
|
|
$maxScore = floatval($service->orderGoodsList->sum('score_max_amount'));
|
|
$score = $request->input('score');
|
|
$userScore = floatval($user->profit);
|
|
if (!$score) {
|
|
$score = $userScore > $maxScore ? $maxScore : $userScore;
|
|
}
|
|
$service->score($score);
|
|
|
|
$goodsList = $service->orderGoodsList;
|
|
|
|
$dataList = collect();
|
|
|
|
foreach($goodsList->groupBy('merchant_id') as $id => $list) {
|
|
|
|
$dataList->push([
|
|
'merchant' => $id ? Merchant::select('id', 'name')->find($id) : ['id' => null, 'name' => '自营店铺'],
|
|
'list' => $list
|
|
]);
|
|
}
|
|
|
|
// 付款金额
|
|
$payMoney = $service->getPayMoney();
|
|
|
|
return $this->json([
|
|
'address' => $address ? UserAddressResource::make($address) : null,
|
|
'list' => $dataList,
|
|
'score' => [
|
|
'has' => $userScore,
|
|
'use' => $score,
|
|
'max' => $maxScore,
|
|
'bonus' => $service->getUserBonus($payMoney),
|
|
],
|
|
'price' => [
|
|
'goods' => floatval($goodsList->sum('price')),
|
|
'ship' => $service->ship['money'],
|
|
'coupon' => 0,
|
|
'vip' => $service->vip['money'],
|
|
'score' => $service->score['money'],
|
|
'total' => $payMoney,
|
|
]
|
|
]);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$request->validate([
|
|
'scene' => ['required', new Enum(OrderScene::class)]
|
|
]);
|
|
|
|
$scene = $request->input('scene');
|
|
$store = OrderStore::init()->scene($scene)->user($user)->remarks($request->input('remarks'));
|
|
// 自营商城下单
|
|
if ($scene === OrderScene::Online->value) {
|
|
$request->validate([
|
|
'goods' => [Rule::requiredIf(!$request->filled('cart_id')), 'array'],
|
|
'cart_id' => ['array'],
|
|
'address' => [Rule::requiredIf(!$request->filled('address_id')), 'array'],
|
|
]);
|
|
|
|
$goods = $request->input('goods');
|
|
if ($request->filled('cart_id')) {
|
|
$goods = $this->formatCartGoods($user->carts()->whereIn('id', $request->input('cart_id'))->get());
|
|
}
|
|
$store->goods($goods);
|
|
|
|
$address = null;
|
|
if ($request->filled('address_id')) {
|
|
$address = $user->addresses()->find($request->input('address_id'));
|
|
if (!$address) {
|
|
return $this->error('收货地址不存在');
|
|
}
|
|
}
|
|
if (!$address) {
|
|
$address = $request->input('address');
|
|
}
|
|
|
|
$store->ship(ShipWay::Express->value, $this->formatAddress($address));
|
|
|
|
$store->score($request->input('score', 0));
|
|
}
|
|
// 店铺下单
|
|
else if ($scene === OrderScene::Merchant->value) {
|
|
$request->validate([
|
|
'goods' => [Rule::requiredIf(!$request->filled('cart_id')), 'array'],
|
|
'cart_id' => ['array'],
|
|
'merchant_id' => 'required',
|
|
]);
|
|
|
|
$merchant = Merchant::findOrFail($request->input('merchant_id'));
|
|
if (!$merchant->enable()) {
|
|
throw new OrderException('店铺不可用');
|
|
}
|
|
$store->merchant($merchant);
|
|
|
|
$goods = $request->input('goods');
|
|
if ($request->filled('cart_id')) {
|
|
$goods = $this->formatCartGoods($user->carts()->whereIn('id', $request->input('cart_id'))->get());
|
|
}
|
|
$store->goods($goods);
|
|
|
|
$store->ship(ShipWay::Pick->value);
|
|
|
|
// 验证店铺返现余额是否足够
|
|
$payMoney = $store->getPayMoney();
|
|
$ratio = $merchant->profit_ratio / 100;
|
|
$userProfit = round($payMoney * $ratio, 2, PHP_ROUND_HALF_DOWN);
|
|
$merchantUser = $merchant->user;
|
|
if ($merchantUser->profit < $userProfit) {
|
|
throw new OrderException('店铺返现账户余额不足');
|
|
}
|
|
}
|
|
// 扫码付款
|
|
else if ($scene === OrderScene::Scan->value) {
|
|
$request->validate([
|
|
'money' => 'required',
|
|
'merchant_id' => 'required',
|
|
]);
|
|
|
|
$merchant = Merchant::findOrFail($request->input('merchant_id'));
|
|
if (!$merchant->enable()) {
|
|
throw new OrderException('店铺不可用');
|
|
}
|
|
$store->merchant($merchant);
|
|
$store->money($request->input('money'));
|
|
} else {
|
|
return $this->error('未知下单场景');
|
|
}
|
|
try {
|
|
DB::beginTransaction();
|
|
$order = $store->create();
|
|
// 删除购物车商品
|
|
if ($request->filled('cart_id')) {
|
|
$user->carts()->whereIn('id', $request->input('cart_id'))->delete();
|
|
}
|
|
$result = OrderResource::make($order);
|
|
if ($request->filled('pay_way')) {
|
|
$result = [];
|
|
$payData = OrderService::make()->pay($order, $request->input('pay_way'));
|
|
$result['order'] = OrderResource::make($order);
|
|
$result['payment'] = $payData;
|
|
}
|
|
DB::commit();
|
|
return $this->json($result);
|
|
} catch (\Exception $e) {
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function show($id)
|
|
{
|
|
$user = auth('api')->user();
|
|
$order = $user->orders()->with(['goods'])->findOrFail($id);
|
|
|
|
return $this->json(OrderResource::make($order));
|
|
}
|
|
|
|
public function pay($id, Request $request)
|
|
{
|
|
$request->validate([
|
|
'pay_way' => ['required', new Enum(PayWay::class)]
|
|
]);
|
|
|
|
$user = auth('api')->user();
|
|
|
|
$order = $user->orders()->findOrFail($id);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
$result = OrderService::make()->pay($order, PayWay::WxMini->value);
|
|
DB::commit();
|
|
return $this->json($result);
|
|
} catch (\Exception $e) {
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function cancel($id, Request $request)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$order = $user->orders()->findOrFail($id);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
OrderService::make()->cancel($order);
|
|
$order->options()->create([
|
|
'user_type' => get_class($user),
|
|
'user_id' => $user->id,
|
|
'description' => '用户取消订单',
|
|
'attribute' => [
|
|
'is_closed' => 1
|
|
]
|
|
]);
|
|
DB::commit();
|
|
return $this->success('订单成功取消');
|
|
} catch (\Exception $e) {
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function receive($id)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$order = $user->orders()->findOrFail($id);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
OrderService::make()->receive($order);
|
|
$order->options()->create([
|
|
'user_type' => get_class($user),
|
|
'user_id' => $user->id,
|
|
'description' => '用户 确认收货',
|
|
'attribute' => [
|
|
'is_closed' => 1
|
|
]
|
|
]);
|
|
DB::commit();
|
|
return $this->success('收货成功');
|
|
} catch (\Exception $e) {
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function destroy($id)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$order = $user->orders()->findOrFail($id);
|
|
|
|
try {
|
|
DB::beginTransaction();
|
|
OrderService::make()->delete($order);
|
|
DB::commit();
|
|
return $this->success('删除成功');
|
|
} catch (\Exception $e) {
|
|
return $this->error($e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function ships($id)
|
|
{
|
|
$user = auth('api')->user();
|
|
|
|
$order = $user->orders()->findOrFail($id);
|
|
|
|
$list = $order->ships()->with(['goods'])->sort()->get();
|
|
|
|
return $this->json(OrderShipResouce::collection($list));
|
|
}
|
|
|
|
public function logistics(Request $request)
|
|
{
|
|
$request->validate([
|
|
'order_id' => 'required',
|
|
'ship_id' => 'required',
|
|
]);
|
|
|
|
$user = auth('api')->user();
|
|
$order = $user->orders()->findOrFail($request->input('order_id'));
|
|
$ship = $order->ships()->findOrFail($request->input('ship_id'));
|
|
|
|
return $this->success();
|
|
}
|
|
|
|
protected function formatCartGoods($carts)
|
|
{
|
|
$goods = [];
|
|
foreach($carts as $item) {
|
|
array_push($goods, [
|
|
'id' => $item->goods_id,
|
|
'amount' => $item->amount,
|
|
'spec' => $item->spec,
|
|
'part' => $item->part,
|
|
]);
|
|
}
|
|
|
|
return $goods;
|
|
}
|
|
|
|
protected function formatAddress($userAddress)
|
|
{
|
|
$address = [];
|
|
if ($userAddress instanceof UserAddress) {
|
|
$address = [
|
|
'name' => $userAddress->contact_name,
|
|
'phone' => $userAddress->phone,
|
|
'region' => [$userAddress->province?->name, $userAddress->city?->name, $userAddress->area?->name],
|
|
'zone' => [$userAddress->province_id, $userAddress->city_id, $userAddress->area_id],
|
|
'address' => $userAddress->address,
|
|
'address_id' => $userAddress->id
|
|
];
|
|
} else if (is_array($userAddress)) {
|
|
$address = $userAddress;
|
|
$region = data_get($address, 'region');
|
|
if (!$region || count($region) === 0) {
|
|
throw new OrderException('收货地址格式不正确');
|
|
}
|
|
$area = Zone::where('name', $region[2])->where('type', 'area')->firstOrFail();
|
|
$city = Zone::findOrFail($area->parent_id);
|
|
$address['zone'] = [$city->parent_id, $area->parent_id, $area->id];
|
|
}
|
|
|
|
return $address;
|
|
}
|
|
}
|