Files
webman-buildadmin-mall/app/admin/controller/mall/Order.php

319 lines
9.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\admin\controller\mall;
use Throwable;
use app\common\controller\Backend;
use app\common\library\MallBonusGrantPush;
use app\common\model\MallOrder;
use app\common\model\MallUserAsset;
use support\think\Db;
use support\Response;
use Webman\Http\Request;
/**
* 统一订单(后台列表)
*/
class Order extends Backend
{
/**
* @var object|null
* @phpstan-var \app\common\model\MallOrder|null
*/
protected ?object $model = null;
protected array|string $preExcludeFields = ['id', 'create_time', 'update_time'];
protected array $withJoinTable = ['mallItem'];
protected string|array $quickSearchField = ['user_id', 'external_transaction_id', 'playx_transaction_id'];
protected string|array $indexField = [
'id',
'user_id',
'type',
'status',
'mall_item_id',
'points_cost',
'amount',
'multiplier',
'external_transaction_id',
'playx_transaction_id',
'grant_status',
'fail_reason',
'reject_reason',
'shipping_company',
'shipping_no',
'receiver_name',
'receiver_phone',
'receiver_address',
'mall_address_id',
'create_time',
'update_time',
];
public function initialize(): void
{
parent::initialize();
$this->model = new \app\common\model\MallOrder();
}
/**
* 查看
* @throws Throwable
*/
public function index(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->get('select') || $request->post('select')) {
return $this->select($request);
}
[$where, $alias, $limit, $order] = $this->queryBuilder();
$res = $this->model
->with(['mallItem' => function ($query) {
$query->field('id,title');
}])
->visible(['mallItem' => ['title']])
->alias($alias)
->where($where)
->order($order)
->paginate($limit);
return $this->success('', [
'list' => $res->items(),
'total' => $res->total(),
'remark' => get_route_remark(),
]);
}
/**
* PHYSICAL 发货:更新 shipping_company/shipping_no并将状态置为 SHIPPED
*/
public function ship(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$data = $request->post();
$id = $data['id'] ?? 0;
$shippingCompany = $data['shipping_company'] ?? '';
$shippingNo = $data['shipping_no'] ?? '';
if (!$id || $shippingCompany === '' || $shippingNo === '') {
return $this->error(__('Missing required fields'));
}
$order = MallOrder::where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
if ($order->type !== MallOrder::TYPE_PHYSICAL) {
return $this->error(__('Order type not PHYSICAL'));
}
if ($order->status !== MallOrder::STATUS_PENDING) {
return $this->error(__('Order status must be PENDING'));
}
Db::startTrans();
try {
$order->shipping_company = $shippingCompany;
$order->shipping_no = $shippingNo;
$order->status = MallOrder::STATUS_SHIPPED;
$order->save();
Db::commit();
} catch (Throwable $e) {
Db::rollback();
return $this->error($e->getMessage());
}
return $this->success(__('Shipped successfully'));
}
/**
* 审核通过(非 PHYSICAL更新状态为 COMPLETED
*/
public function approve(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$id = $request->post('id', 0);
if (!$id) {
return $this->error(__('Missing required fields'));
}
$order = MallOrder::where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
if ($order->status !== MallOrder::STATUS_PENDING) {
return $this->error(__('Order status must be PENDING'));
}
if ($order->type === MallOrder::TYPE_PHYSICAL) {
return $this->error(__('Order type not supported'));
}
Db::startTrans();
try {
$order->status = MallOrder::STATUS_COMPLETED;
$order->update_time = time();
$order->save();
Db::commit();
} catch (Throwable $e) {
Db::rollback();
return $this->error($e->getMessage());
}
return $this->success(__('Approved successfully'));
}
/**
* 审核驳回:更新状态为 REJECTED并退回积分到 available_points所有类型通用
*/
public function reject(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$data = $request->post();
$id = $data['id'] ?? 0;
$rejectReason = $data['reject_reason'] ?? '';
if (!$id) {
return $this->error(__('Missing required fields'));
}
$order = MallOrder::where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
if ($order->status !== MallOrder::STATUS_PENDING) {
return $this->error(__('Order status must be PENDING'));
}
if ($order->type === MallOrder::TYPE_PHYSICAL && $rejectReason === '') {
return $this->error(__('Missing required fields'));
}
Db::startTrans();
try {
$asset = MallUserAsset::where('playx_user_id', $order->user_id ?? '')->find();
if (!$asset) {
throw new \RuntimeException('User asset not found');
}
$refund = $order->points_cost ?? 0;
if ($refund > 0) {
$asset->available_points += $refund;
$asset->save();
}
$order->status = MallOrder::STATUS_REJECTED;
$order->reject_reason = $rejectReason;
if ($order->type === MallOrder::TYPE_BONUS) {
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
} else {
$order->grant_status = MallOrder::GRANT_NOT_APPLICABLE;
}
$order->update_time = time();
$order->save();
Db::commit();
} catch (Throwable $e) {
Db::rollback();
return $this->error($e->getMessage());
}
return $this->success(__('Rejected successfully'));
}
/**
* 手动推送红利(同步调用 PlayX不限制自动重试次数成功则 ACCEPTED失败写入 fail_reason
*/
public function retry(Request $request): Response
{
$response = $this->initializeBackend($request);
if ($response !== null) {
return $response;
}
if ($request->method() !== 'POST') {
return $this->error(__('Parameter error'));
}
$id = $request->post('id', 0);
if (!$id) {
return $this->error(__('Missing required fields'));
}
$order = MallOrder::where('id', $id)->find();
if (!$order) {
return $this->error(__('Record not found'));
}
if ($order->type !== MallOrder::TYPE_BONUS) {
return $this->error(__('Only BONUS can retry'));
}
if ($order->status !== MallOrder::STATUS_PENDING) {
return $this->error(__('Order status must be PENDING'));
}
$allowedStatuses = [
MallOrder::GRANT_NOT_SENT,
MallOrder::GRANT_SENT_PENDING,
MallOrder::GRANT_FAILED_RETRYABLE,
MallOrder::GRANT_FAILED_FINAL,
];
if (!in_array($order->grant_status, $allowedStatuses, true)) {
return $this->error(__('Current grant status cannot be manually pushed'));
}
if (strval(config('playx.api.base_url', '')) === '') {
return $this->error(__('PlayX API not configured'));
}
$result = MallBonusGrantPush::push($order);
if ($result['ok']) {
$order->grant_status = MallOrder::GRANT_ACCEPTED;
$order->playx_transaction_id = $result['playx_transaction_id'];
$order->fail_reason = null;
$order->update_time = time();
$order->save();
return $this->success(__('Push succeeded'));
}
$failReason = __('Manual push failed') . ': ' . $result['message'];
$order->fail_reason = $failReason;
$order->grant_status = MallOrder::GRANT_FAILED_FINAL;
$order->update_time = time();
$order->save();
return $this->error($failReason);
}
}