Warenwirtschaft: F-10 — Versandabschluss nur mit Zahlungsfreigabe
Board-Statuswechsel auf „versendet“ prüft serverseitig isReadyToShip() (Rechnung/API weiterhin erlaubt); Button im Board ohne Freigabe deaktiviert. Konfektionieren bleibt vor Zahlungseingang möglich. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
db27f040e6
commit
f93b16c8f7
3 changed files with 47 additions and 1 deletions
|
|
@ -92,6 +92,15 @@ class OrderFulfillmentController extends Controller
|
|||
return redirect()->route('admin.inventory.orders.index');
|
||||
}
|
||||
|
||||
// Prüfung 08.09.2026 F-10: „versendet“ (Bestandsabzug) nur für versandfertige
|
||||
// Bestellungen — Zahlung eingegangen bzw. Rechnung/API (Kundenentscheid 16.07.2026,
|
||||
// isReadyToShip). Konfektionieren bleibt auch vor Zahlungseingang möglich.
|
||||
if ((int) $request->input('shipped') === 2 && ! $order->isReadyToShip()) {
|
||||
session()->flash('alert-error', __('Bestellung #:id wartet auf Zahlung und kann noch nicht als versendet gebucht werden.', ['id' => $id]));
|
||||
|
||||
return redirect()->route('admin.inventory.orders.index', array_filter(['filter' => $request->input('back_filter')]));
|
||||
}
|
||||
|
||||
app(OrderStatusService::class)->setShipped($id, (int) $request->input('shipped'), auth()->id(), lockStatus: true);
|
||||
|
||||
session()->flash('alert-success', (int) $request->input('shipped') === 2
|
||||
|
|
|
|||
|
|
@ -227,7 +227,12 @@
|
|||
</button>
|
||||
</form>
|
||||
@endif
|
||||
@if (in_array((int) $order->shipped, [0, 1], true))
|
||||
@if (in_array((int) $order->shipped, [0, 1], true) && ! $readyToShip)
|
||||
{{-- F-10: ohne Zahlungsfreigabe kein Versandabschluss (Server prüft ebenfalls) --}}
|
||||
<button type="button" class="btn btn-sm btn-primary" disabled title="{{ __('Wartet auf Zahlung — Versand erst nach Zahlungseingang') }}">
|
||||
<span class="fas fa-shipping-fast mr-1"></span><span class="of-btn-text">{{ __('Versendet') }}</span>
|
||||
</button>
|
||||
@elseif (in_array((int) $order->shipped, [0, 1], true))
|
||||
<form action="{{ route('admin.inventory.orders.status', $order->id) }}" method="post" class="d-inline"
|
||||
onsubmit="return confirm(@json(__('Bestellung als versendet buchen? Der Produktbestand wird abgezogen.')));">
|
||||
@csrf
|
||||
|
|
|
|||
|
|
@ -423,3 +423,35 @@ test('api-bestellung bekommt keine rechnung im system', function () {
|
|||
expect($order->fresh()->invoice)->toBeNull()
|
||||
->and(session('alert-error'))->toContain('API-Bestellung');
|
||||
});
|
||||
|
||||
test('F-10: ohne zahlungsfreigabe kein versandabschluss ueber das board, konfektionieren bleibt moeglich', function () {
|
||||
$product = ofMakeProduct('OF F10');
|
||||
$order = ofMakeOrder([['product' => $product, 'qty' => 1]], ['txaction' => 'failed', 'paid' => false], 'vor');
|
||||
expect($order->isReadyToShip())->toBeFalse();
|
||||
|
||||
$staff = ofMakeUser(1);
|
||||
$this->actingAs($staff)
|
||||
->post(route('admin.inventory.orders.status', $order->id), ['shipped' => 2])
|
||||
->assertRedirect(route('admin.inventory.orders.index'));
|
||||
|
||||
expect((int) $order->fresh()->shipped)->toBe(0)
|
||||
->and(session('alert-error'))->toContain('wartet auf Zahlung')
|
||||
->and(ProductStockMovement::query()->where('product_id', $product->id)->count())->toBe(0);
|
||||
|
||||
// Board zeigt den Versand-Button nur deaktiviert.
|
||||
$this->actingAs($staff)->get(route('admin.inventory.orders.index'))
|
||||
->assertOk()->assertSee('Wartet auf Zahlung — Versand erst nach Zahlungseingang');
|
||||
|
||||
$this->actingAs($staff)
|
||||
->post(route('admin.inventory.orders.status', $order->id), ['shipped' => 1])
|
||||
->assertRedirect();
|
||||
expect((int) $order->fresh()->shipped)->toBe(1);
|
||||
|
||||
// Nach Zahlungseingang geht der Versand.
|
||||
$order->forceFill(['txaction' => 'paid', 'paid' => true])->save();
|
||||
$this->actingAs($staff)
|
||||
->post(route('admin.inventory.orders.status', $order->id), ['shipped' => 2])
|
||||
->assertRedirect();
|
||||
expect((int) $order->fresh()->shipped)->toBe(2)
|
||||
->and(ProductStockMovement::query()->where('product_id', $product->id)->count())->toBe(1);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue