validate(['page'=>'sometimes|integer|min:1|max:100000','per_page'=>'sometimes|integer|in:25,100']);abort_if(array_diff(array_keys($r->query()),array_keys($d))!==[],422); $s=$context->identifiers();$unit=$context->unitId();abort_unless($unit,403); foreach(['stock.view','general_ledger.view']as$p)$permissions->require($context->userId(),$s['tenant_id'],$s['company_id'],$p,$unit); $binding=config('stock_ledger.read_sources.'.$s['tenant_id'].':'.$s['company_id'].':'.$unit); if(!$binding)return response()->json(['status'=>'unavailable','message'=>'Livro de valorização autorizado ainda não ligado a este contexto.'],503)->header('Cache-Control','no-store'); abort_unless(app()->environment('budget-testing'),403); $host=DB::connection();$h=$host->getConfig();$run=(string)getenv('SGF_ISOLATED_REGRESSION_RUN'); abort_unless(preg_match('/^[a-f0-9]{12}$/D',$run)&&($h['driver']??null)==='pgsql'&&($h['host']??null)==='127.0.0.1'&&(string)($h['port']??'')==='55439'&&preg_match('/^budget_core_sgf_([a-f0-9]{12})$/D',$h['database']??'',$hm)&&($h['username']??null)==='stock_ledger_sgf_'.$hm[1]&&empty($h['url'])&&empty($h['read'])&&empty($h['write']),403); $hi=$host->selectOne("SELECT current_database() db,current_user role,current_setting('cluster_name') cluster");abort_unless($hi->db===$h['database']&&$hi->role===$h['username']&&$hi->cluster==='sgf_modular_regression_'.$run,403); abort_unless(($binding['connection']??null)==='stock_valuation_source'&&is_int($binding['book_id']??null)&&($binding['book_id']??0)>0,503); $c=DB::connection('stock_valuation_source');$cfg=$c->getConfig(); abort_unless(($cfg['driver']??null)==='pgsql'&&($cfg['host']??null)==='127.0.0.1'&&(string)($cfg['port']??'')==='55439'&&preg_match('/^compras_receipts_test_([a-f0-9]{12})$/D',$cfg['database']??'',$m)&&($cfg['username']??null)==='stock_valuation_read_'.$m[1]&&empty($cfg['url'])&&empty($cfg['read'])&&empty($cfg['write'])&&($cfg['search_path']??'public')==='public',403); $native=$binding['native_scope']??[];abort_unless(array_keys($native)===['tenant_id','company_id','unit_id']&&is_int($native['tenant_id'])&&$native['tenant_id']>0&&$native['company_id']===0&&$native['unit_id']===0,503); try{$data=$c->transaction(function()use($c,$cfg,$run,$native,$binding,$d){ abort_unless($c->transactionLevel()===1,503);$c->statement('SET TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY'); $i=$c->selectOne("SELECT current_database() db,current_user role,current_setting('cluster_name') cluster,current_setting('default_transaction_read_only') ro,rolsuper OR rolcreatedb OR rolcreaterole OR rolreplication OR rolbypassrls elevated FROM pg_roles WHERE rolname=current_user"); abort_unless($i->db===$cfg['database']&&$i->role===$cfg['username']&&$i->cluster==='sgf_modular_regression_'.$run&&$i->ro==='on'&&!$i->elevated,403); foreach(['stock_movements','gl_journals','gl_lines','gl_stock_rates','gl_stock_books']as$table)abort_if($c->selectOne("SELECT has_table_privilege(current_user,?,'INSERT,UPDATE,DELETE') writes",[$table])->writes,403); $book=$c->table('gl_stock_books')->where($native)->where('id',$binding['book_id'])->first();abort_unless($book,503,'Livro composto incompatível.'); abort_unless($c->table('stock_items')->where(['tenant_id'=>$native['tenant_id'],'id'=>$book->stock_item_id,'unit'=>$book->unit_code])->exists() &&$c->table('warehouses')->where(['tenant_id'=>$native['tenant_id'],'id'=>$book->warehouse_id])->exists(),503,'Artigo/armazém/unidade da origem incompatíveis.'); $page=(int)($d['page']??1);$size=(int)($d['per_page']??25); $physical=$c->table('stock_movements')->where(['tenant_id'=>$native['tenant_id'],'stock_item_id'=>$book->stock_item_id,'warehouse_id'=>$book->warehouse_id]); $journals=$c->table('gl_journals')->where($native)->where('snapshot->source->stock_book_id',$book->id);$count=(clone$journals)->count(); $rows=(clone$journals)->orderBy('id')->offset(($page-1)*$size)->limit($size)->get();$ids=$rows->pluck('id')->all();$lines=$c->table('gl_lines')->where($native)->whereIn('journal_id',$ids)->orderBy('journal_id')->orderBy('line_no')->get(); $postedIds=(clone$journals)->selectRaw("(snapshot->'source'->>'stock_movement_id')::bigint"); $unposted=(clone$physical)->whereNotIn('id',$postedIds)->count(); $rate=$c->table('gl_stock_rates')->where($native)->where('book_id',$book->id)->orderByDesc('version')->first();$review=$rate?$c->table('gl_stock_rate_reviews')->where($native)->where('rate_id',$rate->id)->first():null; $stale=$rate?(clone$journals)->where('snapshot->source->stock_rate_id','<>',$rate->id)->count():$count; $net=$c->table('gl_lines as l')->join('gl_accounts as a','a.id','=','l.account_id')->where(['l.tenant_id'=>$native['tenant_id'],'l.company_id'=>0,'l.unit_id'=>0,'a.code'=>'QA-STOCK'])->whereIn('l.journal_id',(clone$journals)->select('id'))->selectRaw('coalesce(sum(l.debit_minor-l.credit_minor),0) net')->first(); return ['synthetic_only'=>true,'single_canonical_book'=>true,'status'=>$rate&&$review&&$review->decision==='approved'&&$unposted===0&&$stale===0?'reconciled':'pending','reconciliation_scope'=>'physical_movement_coverage_and_rate_ids_only','current_source_dependencies_validated'=>false,'book'=>['id'=>$book->id,'stock_item_id'=>$book->stock_item_id,'warehouse_id'=>$book->warehouse_id,'unit'=>$book->unit_code,'period_key'=>$book->period_key],'physical_quantity_milli'=>(int)(clone$physical)->sum('quantity_milli'),'physical_revision'=>(int)(clone$physical)->max('id'),'posted_stock_value_minor'=>(int)$net->net,'currency'=>'MZN','unposted_movements'=>$unposted,'stale_rate_journals'=>$stale,'journals'=>$rows->all(),'lines'=>$lines->all(),'pagination'=>['page'=>$page,'per_page'=>$size,'total'=>$count],'source_identity'=>['database'=>$i->db,'role'=>$i->role],'operation_executed'=>false]; });}catch(\PDOException $e){$state=$e->errorInfo[0]??$e->getCode();if(str_starts_with((string)$state,'08')||in_array($state,['28P01','3D000','42P01','42703','57014'],true))return response()->json(['status'=>'unavailable','message'=>'Livro de valorização indisponível ou incompatível.'],503)->header('Cache-Control','no-store');throw$e;} if($r->is('api/*'))return response()->json($data)->header('Cache-Control','no-store'); return response()->view('accounting.stock-valuation-read',['data'=>$data])->header('Cache-Control','no-store'); } }