diff --git a/app/Actions/VacationRequest/BulkCreateAction.php b/app/Actions/VacationRequest/BulkCreateAction.php
new file mode 100644
index 00000000..d2d989bd
--- /dev/null
+++ b/app/Actions/VacationRequest/BulkCreateAction.php
@@ -0,0 +1,40 @@
+id;
+
+ try {
+ $request = $this->createAction->execute($data, $creator);
+
+ $requests->push($request);
+ } catch (ValidationException $e) {
+ $errors->push($user->profile->full_name . " - " . $e->getMessage());
+ }
+ }
+
+ return collect([
+ "requests" => $requests,
+ "errors" => $errors,
+ ]);
+ }
+}
diff --git a/app/Http/Controllers/VacationRequestController.php b/app/Http/Controllers/VacationRequestController.php
index 74a389c2..f3b94d09 100644
--- a/app/Http/Controllers/VacationRequestController.php
+++ b/app/Http/Controllers/VacationRequestController.php
@@ -16,6 +16,7 @@
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
use Toby\Actions\VacationRequest\AcceptAsAdministrativeAction;
use Toby\Actions\VacationRequest\AcceptAsTechnicalAction;
+use Toby\Actions\VacationRequest\BulkCreateAction;
use Toby\Actions\VacationRequest\CancelAction;
use Toby\Actions\VacationRequest\CreateAction;
use Toby\Actions\VacationRequest\RejectAction;
@@ -23,6 +24,7 @@
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Domain\VacationTypeConfigRetriever;
use Toby\Enums\VacationType;
+use Toby\Http\Requests\BulkVacationRequestRequest;
use Toby\Http\Requests\VacationRequestRequest;
use Toby\Http\Resources\SimpleUserResource;
use Toby\Http\Resources\SimpleVacationRequestResource;
@@ -246,6 +248,30 @@ public function create(Request $request): Response
]);
}
+ public function bulkCreate(Request $request, VacationTypeConfigRetriever $configRetriever): Response
+ {
+ $this->authorize("createRequestsOnBehalfOfEmployee");
+
+ $users = User::query()
+ ->orderByProfileField("last_name")
+ ->orderByProfileField("first_name")
+ ->get();
+
+ foreach ($users as $user) {
+ $typesByUser[$user->id] = VacationType::all()
+ ->filter(fn(VacationType $type): bool => $configRetriever->isAvailableFor($type, $user->profile->employment_form))
+ ->filter(fn(VacationType $type): bool => $configRetriever->isRequestAllowedFor($type, $request->user()->role))
+ ->pluck("value");
+ }
+
+ return inertia("VacationRequest/BulkCreate", [
+ "types" => VacationType::casesToSelect(),
+ "users" => SimpleUserResource::collection($users),
+ "typesByUser" => $typesByUser ?? [],
+ "vacationFromDate" => $request->get("from_date"),
+ ]);
+ }
+
/**
* @throws AuthorizationException
* @throws ValidationException
@@ -267,6 +293,35 @@ public function store(VacationRequestRequest $request, CreateAction $createActio
->with("success", __("Request created."));
}
+ /**
+ * @throws AuthorizationException
+ * @throws ValidationException
+ */
+ public function bulkStore(BulkVacationRequestRequest $request, BulkCreateAction $bulkCreateAction): RedirectResponse
+ {
+ $this->authorize("createRequestsOnBehalfOfEmployee");
+
+ if ($request->wantsSkipFlow()) {
+ $this->authorize("skipRequestFlow");
+ }
+
+ $result = $bulkCreateAction->execute($request->getUsers(), $request->getData(), $request->user());
+
+ if ($result["errors"]->isNotEmpty()) {
+ $messages = [];
+
+ foreach ($result["errors"] as $key => $error) {
+ $messages["vacationRequests.$key"] = $error;
+ }
+
+ throw ValidationException::withMessages($messages);
+ }
+
+ return redirect()
+ ->route("vacation.requests.indexForApprovers")
+ ->with("success", __("Request created."));
+ }
+
/**
* @throws AuthorizationException
*/
diff --git a/app/Http/Requests/BulkVacationRequestRequest.php b/app/Http/Requests/BulkVacationRequestRequest.php
new file mode 100644
index 00000000..240bc3bf
--- /dev/null
+++ b/app/Http/Requests/BulkVacationRequestRequest.php
@@ -0,0 +1,50 @@
+ ["required", "exists:users,id"],
+ "type" => ["required", new Enum(VacationType::class)],
+ "from" => ["required", "date_format:" . DateFormats::DATE],
+ "to" => ["required", "date_format:" . DateFormats::DATE],
+ "flowSkipped" => ["nullable", "boolean"],
+ "comment" => ["nullable"],
+ ];
+ }
+
+ public function getUsers(): Collection
+ {
+ $users = $this->collect("users");
+
+ return User::query()->whereKey($users)->get();
+ }
+
+ public function getData(): array
+ {
+ return [
+ "type" => $this->get("type"),
+ "from" => $this->get("from"),
+ "to" => $this->get("to"),
+ "comment" => $this->get("comment"),
+ "flow_skipped" => $this->boolean("flowSkipped"),
+ ];
+ }
+
+ public function wantsSkipFlow(): bool
+ {
+ return $this->boolean("flowSkipped");
+ }
+}
diff --git a/package-lock.json b/package-lock.json
index 536175be..56d2d1a6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5 +1,5 @@
{
- "name": "toby",
+ "name": "application",
"lockfileVersion": 3,
"requires": true,
"packages": {
diff --git a/resources/js/Pages/VacationRequest/BulkCreate.vue b/resources/js/Pages/VacationRequest/BulkCreate.vue
new file mode 100644
index 00000000..e2760927
--- /dev/null
+++ b/resources/js/Pages/VacationRequest/BulkCreate.vue
@@ -0,0 +1,383 @@
+
+
+
+
+ Dodaj kilka wniosków
+
+