107 lines
3.6 KiB
PHP
107 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Requests;
|
|
|
|
use App\Models\Scenario;
|
|
use App\Models\Stream;
|
|
use Illuminate\Contracts\Validation\ValidationRule;
|
|
use Illuminate\Foundation\Http\FormRequest;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class StoreStreamRequest extends FormRequest
|
|
{
|
|
public function authorize(): bool
|
|
{
|
|
// In production, check if user owns the scenario
|
|
// For now, allow all requests
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get the validation rules that apply to the request.
|
|
*
|
|
* @return array<string, ValidationRule|array|string>
|
|
*/
|
|
public function rules(): array
|
|
{
|
|
return [
|
|
'name' => ['required', 'string', 'max:255'],
|
|
'type' => ['required', Rule::in([Stream::TYPE_INCOME, Stream::TYPE_EXPENSE])],
|
|
'amount' => ['required', 'numeric', 'min:0.01', 'max:999999999.99'],
|
|
'frequency' => [
|
|
'required',
|
|
Rule::in([
|
|
Stream::FREQUENCY_ONCE,
|
|
Stream::FREQUENCY_WEEKLY,
|
|
Stream::FREQUENCY_BIWEEKLY,
|
|
Stream::FREQUENCY_MONTHLY,
|
|
Stream::FREQUENCY_QUARTERLY,
|
|
Stream::FREQUENCY_YEARLY,
|
|
]),
|
|
],
|
|
'start_date' => ['required', 'date', 'date_format:Y-m-d'],
|
|
'end_date' => ['nullable', 'date', 'date_format:Y-m-d', 'after_or_equal:start_date'],
|
|
'bucket_id' => ['nullable', 'exists:buckets,id'],
|
|
'description' => ['nullable', 'string', 'max:1000'],
|
|
];
|
|
}
|
|
|
|
public function messages(): array
|
|
{
|
|
return [
|
|
'type.in' => 'The type must be either income or expense.',
|
|
'frequency.in' => 'Invalid frequency selected.',
|
|
'amount.min' => 'The amount must be greater than zero.',
|
|
'amount.max' => 'The amount is too large.',
|
|
'end_date.after_or_equal' => 'The end date must be after or equal to the start date.',
|
|
'bucket_id.exists' => 'The selected bucket does not exist.',
|
|
];
|
|
}
|
|
|
|
public function withValidator($validator): void
|
|
{
|
|
$validator->after(function ($validator) {
|
|
// Validate that the bucket belongs to the scenario
|
|
if ($this->bucket_id) {
|
|
/** @var Scenario $scenario */
|
|
$scenario = $this->route('scenario');
|
|
|
|
$bucketBelongsToScenario = $scenario->buckets()
|
|
->where('id', $this->bucket_id)
|
|
->exists();
|
|
|
|
if (! $bucketBelongsToScenario) {
|
|
$validator->errors()->add('bucket_id', 'The selected bucket does not belong to this scenario.');
|
|
}
|
|
}
|
|
|
|
// For expense streams, bucket is required
|
|
if ($this->type === Stream::TYPE_EXPENSE && ! $this->bucket_id) {
|
|
$validator->errors()->add('bucket_id', 'A bucket must be selected for expense streams.');
|
|
}
|
|
});
|
|
}
|
|
|
|
protected function prepareForValidation(): void
|
|
{
|
|
// Ensure dates are in the correct format
|
|
if ($this->has('start_date') && ! empty($this->start_date)) {
|
|
$this->merge([
|
|
'start_date' => date('Y-m-d', strtotime($this->start_date)),
|
|
]);
|
|
}
|
|
|
|
if ($this->has('end_date') && ! empty($this->end_date)) {
|
|
$this->merge([
|
|
'end_date' => date('Y-m-d', strtotime($this->end_date)),
|
|
]);
|
|
}
|
|
|
|
// Convert amount to float
|
|
if ($this->has('amount')) {
|
|
$this->merge([
|
|
'amount' => (float) $this->amount,
|
|
]);
|
|
}
|
|
}
|
|
}
|