Warenwirtschaft: Einheit (g/ml) als Pflichtfeld über der bestellten Menge
Die Einheit hing bisher als Anhang rechts am Mengenfeld — auf breiten Monitoren außer Sicht, und „g" war stiller Default. Jetzt: - Eigenes Pflichtfeld „Einheit der bestellten Menge" direkt VOR der Menge mit „Bitte wählen"; beim Neuanlegen muss bewusst Gramm oder Milliliter gewählt werden, beim Bearbeiten ist die gespeicherte Einheit vorbelegt. - Hinweis unter der Einheit sagt, ob ml möglich ist (Dichte hinterlegt, Wert wird genannt) oder erst gepflegt werden muss; ml bleibt ohne Dichte gesperrt. Mengen-Hinweis und ml→g-Live-Vorschau folgen der Auswahl. - Server: Store-/UpdateStockEntryRequest weisen Rohstoff-Einkäufe ohne Einheit ab (Verpackung bleibt ohne Einheit). Bestehende Tests ergänzt, neuer Test für die Pflicht. - In-App-Doku (Hinweise, Testleitfaden) nachgezogen. Suite: 390 grün. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
23381a37f5
commit
be1d8fdc39
9 changed files with 94 additions and 22 deletions
|
|
@ -70,6 +70,10 @@ class StoreStockEntryRequest extends FormRequest
|
||||||
if (empty($this->input('quality_id'))) {
|
if (empty($this->input('quality_id'))) {
|
||||||
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
|
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
|
||||||
}
|
}
|
||||||
|
// Einheit ist Pflicht: bewusst g oder ml wählen (kein stiller Gramm-Default).
|
||||||
|
if (! in_array($this->input('ordered_unit'), ['gram', 'ml'], true)) {
|
||||||
|
$validator->errors()->add('ordered_unit', __('Bitte die Einheit der bestellten Menge wählen (Gramm oder Milliliter).'));
|
||||||
|
}
|
||||||
// AP-42: ml-Erfassung nur, wenn für den Rohstoff eine Dichte hinterlegt ist.
|
// AP-42: ml-Erfassung nur, wenn für den Rohstoff eine Dichte hinterlegt ist.
|
||||||
if ($this->input('ordered_unit') === 'ml') {
|
if ($this->input('ordered_unit') === 'ml') {
|
||||||
$density = Ingredient::query()->whereKey($this->input('ingredient_id'))->value('density');
|
$density = Ingredient::query()->whereKey($this->input('ingredient_id'))->value('density');
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,10 @@ class UpdateStockEntryRequest extends FormRequest
|
||||||
if (empty($this->input('quality_id'))) {
|
if (empty($this->input('quality_id'))) {
|
||||||
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
|
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
|
||||||
}
|
}
|
||||||
|
// Einheit ist Pflicht: bewusst g oder ml wählen (kein stiller Gramm-Default).
|
||||||
|
if (! in_array($this->input('ordered_unit'), ['gram', 'ml'], true)) {
|
||||||
|
$validator->errors()->add('ordered_unit', __('Bitte die Einheit der bestellten Menge wählen (Gramm oder Milliliter).'));
|
||||||
|
}
|
||||||
// AP-42: ml-Erfassung nur mit hinterlegter Dichte.
|
// AP-42: ml-Erfassung nur mit hinterlegter Dichte.
|
||||||
if ($this->input('ordered_unit') === 'ml') {
|
if ($this->input('ordered_unit') === 'ml') {
|
||||||
$density = Ingredient::query()->whereKey($this->input('ingredient_id'))->value('density');
|
$density = Ingredient::query()->whereKey($this->input('ingredient_id'))->value('density');
|
||||||
|
|
|
||||||
|
|
@ -426,8 +426,10 @@ dadurch für die Bedienung ändert:
|
||||||
höchstens ±5 % vom Soll abweicht.
|
höchstens ±5 % vom Soll abweicht.
|
||||||
- **Rohstoff-Dichte für ml-Einkäufe (V7.0):** Wird ein Rohstoff in **ml**
|
- **Rohstoff-Dichte für ml-Einkäufe (V7.0):** Wird ein Rohstoff in **ml**
|
||||||
eingekauft (z. B. eine Tinktur), aber in **Gramm** geführt, hinterlegt man am
|
eingekauft (z. B. eine Tinktur), aber in **Gramm** geführt, hinterlegt man am
|
||||||
Rohstoff die **Dichte (g/ml)**. Im Wareneingang kann dann die Einheit **ml**
|
Rohstoff die **Dichte (g/ml)**. Im Wareneingang wird die **Einheit** (g oder
|
||||||
gewählt werden; gespeichert wird der über die Dichte errechnete Gramm-Wert.
|
ml) als Pflichtfeld **über der Menge** bewusst gewählt (seit 14.09.2026, vorher
|
||||||
|
unauffällig rechts neben dem Feld); bei ml zeigt das Mengenfeld live
|
||||||
|
„ml × Dichte = g“, gespeichert wird der errechnete Gramm-Wert.
|
||||||
Ohne hinterlegte Dichte ist keine ml-Erfassung möglich.
|
Ohne hinterlegte Dichte ist keine ml-Erfassung möglich.
|
||||||
- **Produktion: Entwurf vs. Abschließen (V7.0):** **„Zwischenspeichern (Entwurf)"**
|
- **Produktion: Entwurf vs. Abschließen (V7.0):** **„Zwischenspeichern (Entwurf)"**
|
||||||
sichert eine Produktion **ohne Bestandsbuchung** und ohne fachliche Prüfung —
|
sichert eine Produktion **ohne Bestandsbuchung** und ohne fachliche Prüfung —
|
||||||
|
|
|
||||||
|
|
@ -223,12 +223,13 @@
|
||||||
|
|
||||||
**Neu (AP-42):**
|
**Neu (AP-42):**
|
||||||
- Am Rohstoff optionales Feld **Dichte (g/ml)**.
|
- Am Rohstoff optionales Feld **Dichte (g/ml)**.
|
||||||
- Im Einkauf/Wareneingang lässt sich die Einheit **g oder ml** wählen; bei **ml** wird über die Dichte in Gramm umgerechnet und **als Gramm gespeichert**.
|
- Im Einkauf/Wareneingang ist die **Einheit der bestellten Menge** (g oder ml) ein eigenes **Pflichtfeld über der Menge** („Bitte wählen“, seit 14.09.2026); bei **ml** wird über die Dichte in Gramm umgerechnet und **als Gramm gespeichert** — die Umrechnung erscheint live unter dem Mengenfeld.
|
||||||
|
|
||||||
**So testen:**
|
**So testen:**
|
||||||
1. Bei einer in ml gekauften Tinktur die **Dichte** hinterlegen (z. B. 0,79).
|
1. Bei einer in ml gekauften Tinktur die **Dichte** hinterlegen (z. B. 0,79).
|
||||||
2. Einen Wareneingang mit Einheit **ml** erfassen (z. B. 100 ml) → gespeichert/gebucht werden 79 g.
|
2. Einen Wareneingang mit Einheit **ml** erfassen (z. B. 100 ml) → gespeichert/gebucht werden 79 g.
|
||||||
3. Ohne hinterlegte Dichte ist die ml-Auswahl gesperrt (Prüfung).
|
3. Ohne hinterlegte Dichte ist die ml-Auswahl gesperrt (Prüfung).
|
||||||
|
4. Ohne gewählte Einheit lässt sich der Rohstoff-Einkauf nicht speichern (Prüfung).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,20 +112,31 @@
|
||||||
? formatWawiQuantity($orderedIsMl ? $model->ordered_quantity / $model->density_used : $model->ordered_quantity)
|
? formatWawiQuantity($orderedIsMl ? $model->ordered_quantity / $model->density_used : $model->ordered_quantity)
|
||||||
: '';
|
: '';
|
||||||
@endphp
|
@endphp
|
||||||
|
@php
|
||||||
|
// Einheit steht als eigenes Pflichtfeld VOR der Menge (nicht mehr als Anhang
|
||||||
|
// rechts am Feld — auf breiten Monitoren lag es außer Sicht). Neu: bewusst
|
||||||
|
// wählen („Bitte wählen"); beim Bearbeiten ist die gespeicherte Einheit vorbelegt.
|
||||||
|
$orderedUnitValue = old('ordered_unit', $isEdit ? ($orderedIsMl ? 'ml' : 'gram') : '');
|
||||||
|
@endphp
|
||||||
|
<div class="form-group" id="ordered-unit-wrap" style="display:none;">
|
||||||
|
<label for="ordered_unit">{{ __('Einheit der bestellten Menge') }} <span class="text-danger">*</span></label>
|
||||||
|
<select name="ordered_unit" id="ordered_unit" class="form-control @error('ordered_unit') is-invalid @enderror">
|
||||||
|
<option value="" @selected($orderedUnitValue === '')>{{ __('Bitte wählen') }}</option>
|
||||||
|
<option value="gram" @selected($orderedUnitValue === 'gram')>{{ __('Gramm (g)') }}</option>
|
||||||
|
<option value="ml" @selected($orderedUnitValue === 'ml')>{{ __('Milliliter (ml) – wird über die Dichte in Gramm umgerechnet') }}</option>
|
||||||
|
</select>
|
||||||
|
<small class="text-muted d-block" id="ordered-unit-hint"></small>
|
||||||
|
@error('ordered_unit')
|
||||||
|
<div class="invalid-feedback d-block">{{ $message }}</div>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="ordered_quantity">{{ __('Bestellte Menge') }} <span class="text-danger">*</span></label>
|
<label for="ordered_quantity">{{ __('Bestellte Menge') }} <span class="text-danger">*</span></label>
|
||||||
<div class="input-group">
|
<input type="text" name="ordered_quantity" id="ordered_quantity"
|
||||||
<input type="text" name="ordered_quantity" id="ordered_quantity"
|
class="form-control @error('ordered_quantity') is-invalid @enderror"
|
||||||
class="form-control @error('ordered_quantity') is-invalid @enderror"
|
value="{{ old('ordered_quantity', $orderedDisplay) }}"
|
||||||
value="{{ old('ordered_quantity', $orderedDisplay) }}"
|
required>
|
||||||
required>
|
|
||||||
<div class="input-group-append" id="ordered-unit-wrap" style="display:none;">
|
|
||||||
<select name="ordered_unit" id="ordered_unit" class="form-control">
|
|
||||||
<option value="gram" @selected(old('ordered_unit', $orderedIsMl ? 'ml' : 'gram') === 'gram')>g</option>
|
|
||||||
<option value="ml" @selected(old('ordered_unit', $orderedIsMl ? 'ml' : 'gram') === 'ml')>ml</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<small class="text-muted d-block" id="ordered-quantity-hint">{{ __('Bei Rohstoff in Gramm, bei Verpackung in Stück.') }}</small>
|
<small class="text-muted d-block" id="ordered-quantity-hint">{{ __('Bei Rohstoff in Gramm, bei Verpackung in Stück.') }}</small>
|
||||||
<small class="d-block font-weight-bold text-body mt-1" id="ordered-quantity-preview" style="display:none;"></small>
|
<small class="d-block font-weight-bold text-body mt-1" id="ordered-quantity-preview" style="display:none;"></small>
|
||||||
@error('ordered_quantity')
|
@error('ordered_quantity')
|
||||||
|
|
|
||||||
|
|
@ -78,15 +78,20 @@
|
||||||
|
|
||||||
function applyOrderedUnit() {
|
function applyOrderedUnit() {
|
||||||
var isIng = $('#entry_type').val() === 'ingredient';
|
var isIng = $('#entry_type').val() === 'ingredient';
|
||||||
|
var $unit = $('#ordered_unit');
|
||||||
|
// Einheit ist eigenes Pflichtfeld vor der Menge — nur bei Rohstoffen sichtbar
|
||||||
|
// und nur dann required (ein verstecktes required-Feld blockiert das Absenden).
|
||||||
$('#ordered-unit-wrap').toggle(isIng);
|
$('#ordered-unit-wrap').toggle(isIng);
|
||||||
|
$unit.prop('required', isIng);
|
||||||
|
|
||||||
var density = isIng ? currentDensity() : null;
|
var density = isIng ? currentDensity() : null;
|
||||||
var hasDensity = density != null && density > 0;
|
var hasDensity = density != null && density > 0;
|
||||||
$('#ordered_unit option[value="ml"]').prop('disabled', !hasDensity);
|
$unit.find('option[value="ml"]').prop('disabled', !hasDensity);
|
||||||
if (!hasDensity && $('#ordered_unit').val() === 'ml') {
|
if (!hasDensity && $unit.val() === 'ml') {
|
||||||
$('#ordered_unit').val('gram');
|
$unit.val('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var $unitHint = $('#ordered-unit-hint');
|
||||||
var $hint = $('#ordered-quantity-hint');
|
var $hint = $('#ordered-quantity-hint');
|
||||||
var $preview = $('#ordered-quantity-preview');
|
var $preview = $('#ordered-quantity-preview');
|
||||||
$preview.hide().text('');
|
$preview.hide().text('');
|
||||||
|
|
@ -94,17 +99,27 @@
|
||||||
$hint.text('{{ __('Bei Verpackung in Stück.') }}');
|
$hint.text('{{ __('Bei Verpackung in Stück.') }}');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($('#ordered_unit').val() === 'ml' && hasDensity) {
|
|
||||||
|
if (!$('#ingredient_id').val()) {
|
||||||
|
$unitHint.text('{{ __('Zuerst den Inhaltsstoff wählen — davon hängt ab, ob ml möglich ist.') }}');
|
||||||
|
} else if (hasDensity) {
|
||||||
|
$unitHint.text('{{ __('Dichte hinterlegt') }} (' + formatDensity(density) + ' g/ml) — {{ __('Erfassung in Gramm oder Milliliter möglich.') }}');
|
||||||
|
} else {
|
||||||
|
$unitHint.text('{{ __('Keine Dichte am Rohstoff hinterlegt — nur Gramm möglich. Für ml zuerst die Dichte pflegen.') }}');
|
||||||
|
}
|
||||||
|
|
||||||
|
var unit = $unit.val();
|
||||||
|
if (unit === 'ml' && hasDensity) {
|
||||||
$hint.text('{{ __('Erfassung in ml — der Bestand wird über die Dichte in Gramm gebucht.') }}');
|
$hint.text('{{ __('Erfassung in ml — der Bestand wird über die Dichte in Gramm gebucht.') }}');
|
||||||
var ml = parseNumber($('#ordered_quantity').val());
|
var ml = parseNumber($('#ordered_quantity').val());
|
||||||
if (ml != null && ml > 0) {
|
if (ml != null && ml > 0) {
|
||||||
// AP-42: Live-Vorschau der ml→g-Umrechnung direkt am Mengenfeld.
|
// AP-42: Live-Vorschau der ml→g-Umrechnung direkt am Mengenfeld.
|
||||||
$preview.text(formatQuantity(ml) + ' ml × ' + formatDensity(density) + ' g/ml = ' + formatQuantity(ml * density) + ' g').show();
|
$preview.text(formatQuantity(ml) + ' ml × ' + formatDensity(density) + ' g/ml = ' + formatQuantity(ml * density) + ' g').show();
|
||||||
}
|
}
|
||||||
} else if (hasDensity) {
|
} else if (unit === 'gram') {
|
||||||
$hint.text('{{ __('In Gramm — oder Einheit auf ml stellen (Dichte hinterlegt).') }}');
|
$hint.text('{{ __('Erfassung in Gramm.') }}');
|
||||||
} else {
|
} else {
|
||||||
$hint.text('{{ __('In Gramm. Für ml-Erfassung zuerst die Dichte am Rohstoff pflegen.') }}');
|
$hint.text('{{ __('Bitte zuerst oben die Einheit wählen.') }}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use App\Models\Ingredient;
|
use App\Models\Ingredient;
|
||||||
use App\Models\Location;
|
use App\Models\Location;
|
||||||
use App\Models\MaterialQuality;
|
use App\Models\MaterialQuality;
|
||||||
|
use App\Models\PackagingItem;
|
||||||
use App\Models\StockEntry;
|
use App\Models\StockEntry;
|
||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
use App\Repositories\StockEntryRepository;
|
use App\Repositories\StockEntryRepository;
|
||||||
|
|
@ -253,3 +254,30 @@ test('N-06: bei rohstoffwechsel wird keine fremde alte dichte übernommen', func
|
||||||
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
|
'ordered_quantity' => '100', 'ordered_unit' => 'ml', 'price_per_kg' => '10,00',
|
||||||
])->assertSessionHasErrors('ordered_quantity');
|
])->assertSessionHasErrors('ordered_quantity');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('einheit ist pflichtfeld: rohstoff-einkauf ohne einheit wird abgelehnt', function () {
|
||||||
|
[$admin, $ingredient, $location, $supplier, $quality] = densSetup(0.79);
|
||||||
|
$this->actingAs($admin, 'user');
|
||||||
|
|
||||||
|
$base = [
|
||||||
|
'entry_type' => 'ingredient', 'ingredient_id' => (string) $ingredient->id, 'supplier_id' => (string) $supplier->id,
|
||||||
|
'location_id' => (string) $location->id, 'quality_id' => (string) $quality->id, 'ordered_at' => '2026-09-14',
|
||||||
|
'ordered_quantity' => '100', 'price_per_kg' => '10,00',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Kein stiller Gramm-Default mehr: leer und fehlend werden beide abgewiesen.
|
||||||
|
$this->from(route('admin.inventory.stock-entries.create'))->post(route('admin.inventory.stock-entries.store'), $base + ['ordered_unit' => ''])
|
||||||
|
->assertRedirect(route('admin.inventory.stock-entries.create'))
|
||||||
|
->assertSessionHasErrors('ordered_unit');
|
||||||
|
$this->from(route('admin.inventory.stock-entries.create'))->post(route('admin.inventory.stock-entries.store'), $base)
|
||||||
|
->assertSessionHasErrors('ordered_unit');
|
||||||
|
expect(StockEntry::query()->count())->toBe(0);
|
||||||
|
|
||||||
|
// Verpackung kennt keine Einheit — dort bleibt das Feld ohne Wirkung.
|
||||||
|
$packaging = PackagingItem::factory()->create();
|
||||||
|
$this->post(route('admin.inventory.stock-entries.store'), [
|
||||||
|
'entry_type' => 'packaging', 'packaging_item_id' => (string) $packaging->id, 'supplier_id' => (string) $supplier->id,
|
||||||
|
'location_id' => (string) $location->id, 'ordered_at' => '2026-09-14', 'ordered_quantity' => '10', 'price_total' => '5,00',
|
||||||
|
])->assertSessionHasNoErrors();
|
||||||
|
expect(StockEntry::query()->count())->toBe(1);
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ test('admin creates pending stock entry with unit gram', function () {
|
||||||
'quality_id' => (string) $quality->id,
|
'quality_id' => (string) $quality->id,
|
||||||
'ordered_at' => '2026-03-27',
|
'ordered_at' => '2026-03-27',
|
||||||
'ordered_quantity' => '1000',
|
'ordered_quantity' => '1000',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg' => '12,50',
|
'price_per_kg' => '12,50',
|
||||||
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
||||||
|
|
||||||
|
|
@ -194,6 +195,7 @@ test('listForIndex sorts pending before received', function () {
|
||||||
'quality_id' => (string) $quality->id,
|
'quality_id' => (string) $quality->id,
|
||||||
'ordered_at' => '2026-01-01',
|
'ordered_at' => '2026-01-01',
|
||||||
'ordered_quantity' => '100',
|
'ordered_quantity' => '100',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg' => '1',
|
'price_per_kg' => '1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
@ -205,6 +207,7 @@ test('listForIndex sorts pending before received', function () {
|
||||||
'quality_id' => (string) $quality->id,
|
'quality_id' => (string) $quality->id,
|
||||||
'ordered_at' => '2026-06-01',
|
'ordered_at' => '2026-06-01',
|
||||||
'ordered_quantity' => '200',
|
'ordered_quantity' => '200',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg' => '1',
|
'price_per_kg' => '1',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ test('net price derives gross from tax rate on store', function () {
|
||||||
'tax_rate_id' => (string) $tax->id,
|
'tax_rate_id' => (string) $tax->id,
|
||||||
'ordered_at' => '2026-06-01',
|
'ordered_at' => '2026-06-01',
|
||||||
'ordered_quantity' => '1000',
|
'ordered_quantity' => '1000',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg' => '10,00',
|
'price_per_kg' => '10,00',
|
||||||
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
||||||
|
|
||||||
|
|
@ -82,6 +83,7 @@ test('gross price derives net from tax rate on store', function () {
|
||||||
'tax_rate_id' => (string) $tax->id,
|
'tax_rate_id' => (string) $tax->id,
|
||||||
'ordered_at' => '2026-06-01',
|
'ordered_at' => '2026-06-01',
|
||||||
'ordered_quantity' => '1000',
|
'ordered_quantity' => '1000',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg_gross' => '11,90',
|
'price_per_kg_gross' => '11,90',
|
||||||
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
||||||
|
|
||||||
|
|
@ -108,6 +110,7 @@ test('without tax rate net equals gross', function () {
|
||||||
'quality_id' => (string) $quality->id,
|
'quality_id' => (string) $quality->id,
|
||||||
'ordered_at' => '2026-06-01',
|
'ordered_at' => '2026-06-01',
|
||||||
'ordered_quantity' => '500',
|
'ordered_quantity' => '500',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
'price_per_kg' => '8,00',
|
'price_per_kg' => '8,00',
|
||||||
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
])->assertRedirect(route('admin.inventory.stock-entries.index'));
|
||||||
|
|
||||||
|
|
@ -135,6 +138,7 @@ test('ingredient requires net or gross price', function () {
|
||||||
'quality_id' => (string) $quality->id,
|
'quality_id' => (string) $quality->id,
|
||||||
'ordered_at' => '2026-06-01',
|
'ordered_at' => '2026-06-01',
|
||||||
'ordered_quantity' => '500',
|
'ordered_quantity' => '500',
|
||||||
|
'ordered_unit' => 'gram',
|
||||||
])->assertSessionHasErrors('price_per_kg');
|
])->assertSessionHasErrors('price_per_kg');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue