Хорошо, вот что я придумала. Как объяснялось ранее, это обеспечивает только проверку на стороне сервера, поскольку, как я вижу, у вас нет какой-либо клиентской части.
Первое, что я сделал, - преобразовал проверку в контроллере в запрос, введенный в * 1003. * метод. Я назвал это StoreOrderRequest
App \ Http \ Requests \ StoreOrderRequest
<?php
namespace App\Http\Requests;
use App\Order;
use App\Product;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
/**
* Class StoreOrderRequest
*
* @package App\Http\Requests
*
* @property string $date
* @property int $customer_id
* @property int $workOrder_id
* @property array $product_id
* @property array $rate
* @property array $vat
* @property array $quantity
*/
class StoreOrderRequest extends FormRequest
{
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules(): array
{
return [
'date' => 'required',
'customer_id' => [
'required',
'exists:customers,id',
],
'workOrder_id' => [
'required',
'unique:orders',
],
'details' => 'present',
'product_id' => 'array',
'rate' => 'array',
'vat' => 'array',
'quantity' => 'array',
];
}
/**
* Prepare the data for validation.
*
* @return void
*/
protected function prepareForValidation(): void
{
$this->redirect = route('order');
$this->validator = $this->getValidatorInstance();
$this->validator->after(function (Validator $validator) {
$products = Product::whereIn('id', $this->product_id)->get();
foreach ($this->product_id as $key => $id) {
$rate = $products->firstWhere('id', $id)->rate;
if ($rate < $this->rate[$key]) {
continue;
}
$validator->errors()->add(
'rate.'.$key,
__(
'validation.min.numeric',
[
'attribute' => 'rate',
'min' => $rate
]
)
);
}
});
}
/**
* Create orders.
*
* @return void
*/
protected function save(): void
{
$orders = collect($this->product_id)
->map(function (int $product_id, int $index) {
return array_merge(
$this->only([
'date',
'customer_id',
'workOrder_id',
'details',
]),
[
'product_id' => $this->product_id,
'rate' => $rate = $this->rate[$index],
'vat' => $this->vat[$index],
'quantity' => $qty = $this->quantity[$index],
'remaining' => $qty,
'amount' => $qty * $rate,
]
);
});
Order::insert($orders->toArray());
}
}
Вы увидите, что я использовал метод prepareForValidation
, что позволило нам зарегистрировать after
проверочные хуки. Они проверяют каждую норму продукта и, если она меньше соответствующей записи Product
, добавят ошибку для своего индекса в пакет ошибок.
(Обратите внимание, что я переопределил свойство redirect
по умолчанию для работать с моим тестом - вам, вероятно, не понадобится эта строка, если вы просто возвращаетесь на предыдущую страницу).
Я также создал метод save
, который сохраняет все эти заказы.
Благодаря всему этому мы теперь можем значительно ускорить ваш OrderController::store
метод:
OrderController
/**
* Store new record.
*
* @param \App\Http\Requests\StoreOrderRequest $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(StoreOrderRequest $request): RedirectResponse
{
$request->save();
return redirect()
->route('order')
->with('success', 'Added Successfully');
}
И вот соответствующий тест для выполнения Убедитесь, что все вышеперечисленное работает должным образом:
Тесты \ Feature \ ProductOrderTest
<?php
namespace Tests\Feature;
use App\Order;
use App\Product;
use App\Customer;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProductOrderTest extends TestCase
{
use RefreshDatabase;
/**
* @test
*/
public function validation_fails_with_product_rate_lower_than_original_product_price()
{
$customer = factory(Customer::class)->create();
$product_1 = factory(Product::class)->create(['rate' => 20.50]);
$product_2 = factory(Product::class)->create(['rate' => 95.67]);
$this->assertCount(0, Order::all());
$response = $this->post(route('order.store'), [
'date' => now(),
'customer_id' => $customer->id,
'workOrder_id' => 1,
'details' => 'Order details',
'product_id' => [
0 => $product_1->id,
1 => $product_2->id,
],
'rate' => [
0 => 20.49,
1 => 95.66,
],
'vat' => [
0 => round(20.49 * 0.20),
1 => round(95.66 * 0.20),
],
'quantity' => [
0 => 1,
1 => 1,
],
]);
$response->assertRedirect(route('order'));
$response->assertSessionMissing('success');
$response->assertSessionHasErrors([
'rate.0' => __('validation.min.numeric', [
'attribute' => 'rate',
'min' => 20.50
]),
'rate.1' => __('validation.min.numeric', [
'attribute' => 'rate',
'min' => 95.67
]),
]);
$this->assertCount(0, Order::all());
}
/**
* @test
*/
public function saves_order_with_valid_request()
{
$customer = factory(Customer::class)->create();
$product_1 = factory(Product::class)->create(['rate' => 20.50]);
$product_2 = factory(Product::class)->create(['rate' => 95.67]);
$this->assertCount(0, Order::all());
$response = $this->post(route('order.store'), [
'date' => $date = now(),
'customer_id' => $customer->id,
'workOrder_id' => 1,
'details' => 'Order details',
'product_id' => [
0 => $product_1->id,
1 => $product_2->id,
],
'rate' => [
0 => 20.50,
1 => 95.68,
],
'vat' => [
0 => round(20.50 * 0.20),
1 => round(95.68 * 0.20),
],
'quantity' => [
0 => 1,
1 => 1,
],
]);
$response->assertRedirect(route('order'));
$response->assertSessionHas('success', 'Added Successfully');
$response->assertSessionDoesntHaveErrors();
$this->assertCount(2, Order::all());
$this->assertDatabaseHas('orders', [
'date' => $date = now(),
'customer_id' => $customer->id,
'workOrder_id' => 1,
'details' => 'Order details',
'product_id' => $product_1->id,
'rate' => 20.50,
'vat' => round(20.50 * 0.20),
'quantity' => 1,
'remaining' => 1,
'amount' => 20.50,
]);
$this->assertDatabaseHas('orders', [
'date' => $date = now(),
'customer_id' => $customer->id,
'workOrder_id' => 1,
'details' => 'Order details',
'product_id' => $product_2->id,
'rate' => 95.68,
'vat' => round(95.68 * 0.20),
'quantity' => 1,
'remaining' => 1,
'amount' => 95.68,
]);
}
}