45 lines
3.8 KiB
PHP
45 lines
3.8 KiB
PHP
<?php
|
|
namespace App\Modules\Purchasing;
|
|
|
|
use App\Shared\Context\CompanyContext;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\{DB,Gate};
|
|
use Tempo\Purchasing\Embedded\Models\{GoodsReceipt,PurchaseOrder};
|
|
|
|
/** Resolve an actual movement to its authorised receipt; URL parent ids are never trusted. */
|
|
final class StockReceiptTraceController
|
|
{
|
|
public function show(int $id,Request $r,ReceiptRuntime $runtime,CompanyContext $ctx)
|
|
{
|
|
abort_unless(config('receipt_qa.stock_trace_enabled')===true&&config('receipt_qa.stock_read_enabled')===true,404);
|
|
abort_if($r->query()!==[],422);
|
|
$scope=$ctx->identifiers()+['unit_id'=>$ctx->unitId()];$user=$ctx->userId();$host=DB::connection();
|
|
return $runtime->run('purchasing_receipts.view',function($actor,$binding)use($id,$scope,$user,$host){
|
|
abort_unless($host->table('permission_grants')->where($scope+['user_id'=>$user,'permission'=>'stock.view'])->sharedLock()->first(),403);
|
|
$tag=substr($host->getDatabaseName(),strlen('budget_core_sgf_'));
|
|
$file='C:/laragon/data/sgf-tempo/run/modular-regression-'.getenv('SGF_ISOLATED_REGRESSION_RUN').'/private/receipt-composition-'.$tag.'/stock-binding.json';
|
|
abort_unless(is_file($file)&&!is_link($file),503,'Origem de stock indisponível.');
|
|
try{$profile=json_decode(file_get_contents($file),true,32,JSON_THROW_ON_ERROR);}catch(\JsonException){abort(503,'Origem de stock incompatível.');}
|
|
$stock=$profile['bindings'][implode(':',array_values($scope)).':'.$user]??null;
|
|
abort_unless($stock&&($stock['source_tenant_id']??null)===$binding['tenant_id']
|
|
&&($profile['connection']['database']??null)===DB::connection()->getDatabaseName()
|
|
&&($stock['schema']??null)==='public'&&($stock['append_only']??false)===true,403);
|
|
$movement=DB::table('stock_movements')->where('tenant_id',$binding['tenant_id'])->where('id',$id)
|
|
->whereIn('warehouse_id',array_values(array_intersect($stock['warehouse_ids']??[],$binding['warehouse_ids'])))
|
|
->where('movement_type','receipt_in')->first(['id','goods_receipt_item_id','stock_item_id','warehouse_id','quantity_milli','snapshot']);
|
|
abort_unless($movement,403,'Movimento fora da origem autorizada.');
|
|
$line=DB::table('goods_receipt_items')->where('tenant_id',$binding['tenant_id'])->where('id',$movement->goods_receipt_item_id)->first();
|
|
abort_unless($line,409,'A evidência de origem exige nova conferência.');
|
|
$receipt=GoodsReceipt::findOrFail($line->goods_receipt_id);
|
|
$order=PurchaseOrder::where('id',$receipt->purchase_order_id)->where(fn($q)=>$q->whereIn('id',$binding['order_ids'])->orWhereIn('requisition_id',RequisitionAccess::ids($binding)))->first();
|
|
abort_unless($order,403);Gate::authorize('viewOrder',[GoodsReceipt::class,$order]);Gate::authorize('view',$receipt);
|
|
try{$snapshot=json_decode($movement->snapshot,true,64,JSON_THROW_ON_ERROR);}catch(\JsonException){abort(409,'A evidência de origem exige nova conferência.');}
|
|
abort_unless($receipt->tenant_id===$binding['tenant_id']&&(int)$receipt->warehouse_id===(int)$movement->warehouse_id
|
|
&&(int)$line->stock_item_id===(int)$movement->stock_item_id&&(string)$line->accepted_milli===(string)$movement->quantity_milli
|
|
&&(int)$movement->quantity_milli>0&&($snapshot['receipt_id']??null)===$receipt->id,409,'O movimento e a recepção exigem nova conferência.');
|
|
return response()->json(['movement_id'=>(int)$movement->id,'order_id'=>$order->id,'receipt_id'=>$receipt->id,
|
|
'href'=>'/purchasing/receipts?order='.$order->id.'&receipt='.$receipt->id,'read_only'=>true])->header('Cache-Control','no-store');
|
|
});
|
|
}
|
|
}
|