diff --git a/app/Admin/Services/WorkFlowService.php b/app/Admin/Services/WorkFlowService.php index dedbd6e..2a2b38c 100644 --- a/app/Admin/Services/WorkFlowService.php +++ b/app/Admin/Services/WorkFlowService.php @@ -28,6 +28,7 @@ class WorkFlowService extends BaseService * * @param WorkflowCheck $check 待审核记录 * @param Employee $user 申请人 + * * @return bool true: 成功, false: 失败, $this->getError(): 错误消息 */ public function apply(WorkflowCheck $check, Employee $user) diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 56af264..5cc2140 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -4,6 +4,8 @@ namespace App\Exceptions; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Throwable; +use Illuminate\Http\{Request}; +use Illuminate\Validation\ValidationException; class Handler extends ExceptionHandler { @@ -18,13 +20,26 @@ class Handler extends ExceptionHandler 'password_confirmation', ]; + protected $dontReport = [ + RuntimeException::class, + ]; + /** * Register the exception handling callbacks for the application. */ public function register(): void { - $this->reportable(function (Throwable $e) { - // + $this->renderable(function (RuntimeException $e, Request $request) { + return response(['code' => $e->getCode(), 'message' => $e->getMessage()], $e->getHttpStatusCode()); }); } + + protected function invalidJson($request, ValidationException $exception) + { + return response()->json([ + 'code' => $exception->status, + 'message' => $exception->getMessage(), + 'errors' => $exception->errors(), + ], $exception->status); + } } diff --git a/app/Http/Controllers/Api/ReimbursementController.php b/app/Http/Controllers/Api/ReimbursementController.php index 2d9b08b..9575357 100644 --- a/app/Http/Controllers/Api/ReimbursementController.php +++ b/app/Http/Controllers/Api/ReimbursementController.php @@ -4,14 +4,17 @@ namespace App\Http\Controllers\Api; use App\Admin\Services\WorkFlowService; use App\Exceptions\RuntimeException; -use App\Http\Resources\ReimbursementResource; +use App\Http\Resources\{ReimbursementResource, WorkflowLogResource}; use App\Models\{Keyword, Reimbursement, WorkflowCheck}; -use Illuminate\Http\Request; +use Illuminate\Http\{Request, Response}; use Illuminate\Support\Facades\DB; use Illuminate\Validation\Rule; use App\Enums\CheckStatus; use Throwable; +/** + * 报销管理 + */ class ReimbursementController extends Controller { public function index(Request $request) @@ -72,19 +75,8 @@ class ReimbursementController extends Controller public function show($id, Request $request): ReimbursementResource { - /** @var \App\Models\Employee */ - $user = $request->user(); - - /** @var \App\Models\Reimbursement */ - $reimbursement = $user->reimbursements()->find($id); - - if (is_null($reimbursement)) { - throw new RuntimeException('报销记录未找到'); - } - - return ReimbursementResource::make( - $reimbursement->load(['type', 'workflow', 'employee', 'store']), - ); + $reimbursement = Reimbursement::with(['type', 'workflow', 'employee', 'store'])->findOrFail($id); + return ReimbursementResource::make($reimbursement); } public function update($id, Request $request, WorkFlowService $workFlowService): ReimbursementResource @@ -157,4 +149,52 @@ class ReimbursementController extends Controller return response()->noContent(); } + + public function checkList(Request $request) + { + $user = $request->user(); + $query = Reimbursement::with(['workflow', 'type', 'store']) + ->whereHas('workflow', fn($q) => $q->where('check_status', CheckStatus::Processing)) + ->whereHas('workflow.logs', fn($q) => $q->own($user))->orderBy('created_at', 'desc'); + + $list = $query->paginate($request->input('per_page')); + + return ReimbursementResource::collection($list); + } + + public function check($id, Request $request, WorkFlowService $workFlowService) + { + $request->validate([ + 'status' => ['required'], + 'remarks' => [Rule::requiredIf(fn() => !$request->input('status'))] + ], [ + 'remarks.required_if' => '未通过原因必填', + ]); + $info = Reimbursement::findOrFail($id); + $user = $request->user(); + try { + DB::beginTransaction(); + $log = $info->workflow->logs()->where('check_status', CheckStatus::Processing)->first(); + if (!$log) { + throw new RuntimeException('审核已经完成'); + } + if (!$workFlowService->check($user, $log, !!$request->input('status'), ['remarks' => $request->input('remarks')])) { + throw new RuntimeException($workFlowService->getError()); + } + + DB::commit(); + return response('', Response::HTTP_OK); + } catch (\Exception $e) { + DB::rollBack(); + throw new RuntimeException($e->getMessage()); + } + } + + public function logs($id) + { + $info = Reimbursement::findOrFail($id); + $logs = $info->workflow->logs()->sort()->get(); + + return WorkflowLogResource::collection($logs); + } } diff --git a/app/Http/Controllers/Api/WorkflowController.php b/app/Http/Controllers/Api/WorkflowController.php deleted file mode 100644 index 40e8a7d..0000000 --- a/app/Http/Controllers/Api/WorkflowController.php +++ /dev/null @@ -1,40 +0,0 @@ -validate([ - 'subject_type' => 'required', - ]); - $user = $this->guard()->user(); - $query = WorkflowLog::with(['check.subject']) - ->whereHas('check',fn($q) => $q->where('subject_type', $request->input('subject_type'))) - ->own($user) - ->where('check_status', CheckStatus::Processing) - ->orderBy('created_at', 'desc'); - $list = $query->paginate($request->input('per_page')); - return WorkflowLogResource::collection($list); - } - - public function show($id, Request $request) - { - $request->validate([ - 'subject_type' => 'required', - ]); - $user = $this->guard()->user(); - $info = WorkflowLog::with(['check.subject'])->own($user)->findOrFail($id); - - return WorkflowLogResource::make($info); - } -} diff --git a/app/Http/Resources/WorkflowLogResource.php b/app/Http/Resources/WorkflowLogResource.php index 61a7c05..b08eebd 100644 --- a/app/Http/Resources/WorkflowLogResource.php +++ b/app/Http/Resources/WorkflowLogResource.php @@ -3,6 +3,7 @@ namespace App\Http\Resources; use Illuminate\Http\Request; +use App\Enums\CheckStatus; use Illuminate\Http\Resources\Json\JsonResource; class WorkflowLogResource extends JsonResource @@ -25,7 +26,7 @@ class WorkflowLogResource extends JsonResource 'checked_at' => $this->checked_at?->timestamp, 'remarks' => $this->remarks, 'check_status' => $this->check_status, - 'check_status_text' => $this->check_status?->text(), + 'check_status_text' => $this->check_status->text(), 'sort' => $this->sort, 'check' => WorkflowCheckResource::make($this->whenLoaded('check')), ]; diff --git a/app/Models/WorkflowLog.php b/app/Models/WorkflowLog.php index c51a64f..3d4563f 100644 --- a/app/Models/WorkflowLog.php +++ b/app/Models/WorkflowLog.php @@ -16,6 +16,7 @@ class WorkflowLog extends Model protected $casts = [ 'check_type' => CheckType::class, 'check_status' => CheckStatus::class, + 'checked_at' => 'datetime', ]; public function check() @@ -30,7 +31,7 @@ class WorkflowLog extends Model public function scopeSort($q) { - return $q->orderBy('batch_id')->orderBy('sort'); + return $q->orderBy('batch_id', 'desc')->orderBy('sort', 'desc'); } public function scopeOwn($builder, $user) diff --git a/database/migrations/2024_03_27_113404_create_workflows_table.php b/database/migrations/2024_03_27_113404_create_workflows_table.php index 743f066..2942f47 100644 --- a/database/migrations/2024_03_27_113404_create_workflows_table.php +++ b/database/migrations/2024_03_27_113404_create_workflows_table.php @@ -31,11 +31,6 @@ return new class extends Migration $table->unsignedInteger('check_status')->default(CheckStatus::None->value)->comment('审核状态'); $table->timestamp('checked_at')->nullable()->comment('审核通过时间'); $table->string('check_remarks')->nullable()->comment('审核未通过原因'); - - $table->string('check_type')->comment('审核类型{job, user}'); - $table->string('check_value')->comment('审核类型值'); - $table->string('check_name')->comment('审核名称(展示用)'); - $table->timestamps(); $table->comment('审核申请'); }); diff --git a/routes/api.php b/routes/api.php index 9a774b5..310180b 100644 --- a/routes/api.php +++ b/routes/api.php @@ -55,12 +55,8 @@ Route::group([ }); // 报销管理 - // Route::group(['middleware' => ['user_role:store_user']], function () { - // }); - Route::get('reimbursements/checks', [\App\Http\Controllers\Api\ReimbursementController::class, 'checkList']); + Route::get('reimbursements/check', [\App\Http\Controllers\Api\ReimbursementController::class, 'checkList']); + Route::post('reimbursements/{id}/check', [\App\Http\Controllers\Api\ReimbursementController::class, 'check']); + Route::get('reimbursements/{id}/logs', [\App\Http\Controllers\Api\ReimbursementController::class, 'logs']); Route::apiResource('reimbursements', \App\Http\Controllers\Api\ReimbursementController::class); - - // 审核 - Route::get('workflow', [\App\Http\Controllers\Api\WorkflowController::class, 'index']); - Route::get('workflow/{id}', [\App\Http\Controllers\Api\WorkflowController::class, 'show']); });