This commit is contained in:
2026-11-02 08:10:00 +02:00
parent 504b01b244
commit b44378b899
14 changed files with 655 additions and 121 deletions
+39
View File
@@ -59,6 +59,45 @@ test('internal request is the exit document and partial deliveries consume only
$this->get('/stock/requisicoes/'.$this->r->id)->assertOk()->assertInertia(fn (Assert $p) => $p->component('stock/request')->where('progress.state', 'closed')->where('progress.delivered.0', 4000));
});
test('reservations protect stock from unrelated issues and cancellation releases only the undelivered balance', function () {
warehouseCommand($this, $this->f['issuer'], 'submit', ['partial_allowed' => true]);
warehouseCommand($this, $this->reviewer, 'authorize', ['partial_allowed' => true]);
expect(app(WarehouseFulfilment::class)->progress($this->r)['reserved'])->toBe([4000]);
$this->actingAs($this->f['receiver']);
$issue=['kind'=>'issue','reference'=>'UNRELATED','idempotency_key'=>(string)Str::uuid(),'responsible_id'=>$this->f['issuer']->id,'warehouse_id'=>$this->f['warehouse']->id,'stock_item_id'=>$this->f['stock']->id,'quantity'=>'7.000','destination'=>'Outra oficina','reason'=>'Tentativa de saída que consumiria reserva.'];
expect(fn()=>app(StockWorkflow::class)->record($this->f['receiver'],$issue))->toThrow(\Illuminate\Validation\ValidationException::class);
expect(app(StockWorkflow::class)->balance($this->f['stock']->id,$this->f['warehouse']->id)['quantity'])->toBe(10000);
warehouseCommand($this,$this->f['receiver'],'deliver',['lines'=>[['index'=>0,'quantity'=>'1.500']]]);
expect(app(WarehouseFulfilment::class)->progress($this->r)['reserved'])->toBe([2500]);
$cancel=warehouseCommand($this,$this->reviewer,'cancel');
$this->postJson('/stock/requisicoes/'.$this->r->id.'/eventos',$cancel)->assertRedirect();
$p=app(WarehouseFulfilment::class)->progress($this->r);
expect($p['state'])->toBe('cancelled')->and($p['reserved'])->toBe([0])->and($p['cancelled'])->toBe([2500])->and($p['remaining'])->toBe([0]);
$this->actingAs($this->f['receiver']);
app(StockWorkflow::class)->record($this->f['receiver'],$issue);
expect(app(StockWorkflow::class)->balance($this->f['stock']->id,$this->f['warehouse']->id)['quantity'])->toBe(1500);
});
test('competing integral authorizations do not overbook and partial reservations can be replenished explicitly', function () {
warehouseCommand($this,$this->f['issuer'],'submit');
warehouseCommand($this,$this->reviewer,'authorize');
$original=$this->r;
$this->actingAs($this->f['issuer']);
$data=$this->draftData;$data['operation_key']=(string)Str::uuid();$data['lines'][0]['quantity']='8.000';
$this->r=app(WarehouseRequests::class)->draft($this->f['issuer'],$data);
warehouseCommand($this,$this->f['issuer'],'submit',['partial_allowed'=>true]);
$this->actingAs($this->reviewer)->postJson('/stock/requisicoes/'.$this->r->id.'/eventos',['operation_key'=>(string)Str::uuid(),'version'=>1,'action'=>'authorize','reason'=>'Tentativa de reservar mais que o stock livre.'])->assertUnprocessable();
expect(app(WarehouseFulfilment::class)->progress($this->r)['state'])->toBe('submitted');
warehouseCommand($this,$this->reviewer,'authorize',['partial_allowed'=>true]);
expect(app(WarehouseFulfilment::class)->progress($this->r)['reserved'])->toBe([6000]);
$second=$this->r;$this->r=$original;
warehouseCommand($this,$this->reviewer,'cancel');
$this->r=$second;
warehouseCommand($this,$this->reviewer,'reserve');
expect(app(WarehouseFulfilment::class)->progress($this->r)['reserved'])->toBe([8000]);
expect(fn()=>DB::table('warehouse_reservations')->where('warehouse_request_id',$second->id)->update(['quantity_milli'=>0]))->toThrow(\Illuminate\Database\QueryException::class);
});
test('warehouse authorization rejects self decision stale version and unauthorized physical delivery', function () {
supplyGrant($this->f['issuer'], ['warehouse_request_review']);
warehouseCommand($this, $this->f['issuer'], 'submit');