30 lines
9.2 KiB
PHP
30 lines
9.2 KiB
PHP
@php
|
|
$closed=$data['period']?->status==='closed';
|
|
$money=fn($n)=>number_format($n/100,2,',',' ').' MZN';
|
|
$pager=function($key,$p)use($data){$q=$data['query'];$links=[];foreach([-1=>'Anterior',1=>'Seguinte'] as $d=>$label)if($p['page']+$d>=1&&$p['page']+$d<=$p['last_page'])$links[]=['label'=>$label,'url'=>'?'.http_build_query(array_merge($q,[$key=>$p['page']+$d]))];return $links;};
|
|
@endphp
|
|
<!doctype html><html lang="pt"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Percurso financeiro composto QA</title><style>body{font:17px system-ui;background:#f3f6f5;color:#142b28;margin:0}main{max-width:1100px;margin:auto;padding:24px}section,header{background:white;border:1px solid #d5e0dc;border-radius:12px;padding:24px;margin:18px 0}article{border-top:1px solid #ddd;padding:16px 0}a{color:#125a4b}label{display:block;margin:12px 0}textarea,select,button{font:inherit;padding:10px;max-width:95%}textarea{display:block;width:90%}pre,code{white-space:pre-wrap;overflow-wrap:anywhere}.notice{background:#fff2cc;padding:16px}nav a{margin-right:20px}</style></head><body><main>
|
|
<header><a href="/qa/cost-demo">Perfis e guia QA</a> · <a href="/general-ledger">Diário detalhado</a> · <a href="/general-ledger/trial-balance?from_on=2026-10-01&to_on=2026-10-31">Balancete e razão</a><h1>Vendas, fornecedores e custos no mesmo diário</h1><p class="notice">Exclusivamente sintético. Empresa #{{ $data['scope']['company_id'] }} / unidade #{{ $data['scope']['unit_id'] }}. Sem emissão fiscal, dinheiro ou utilização real.</p><p>Os cartões mostram evidências registadas. Abra cada origem para conferir o estado actual, dependências, versões e impacto antes de decidir. Nenhuma associação ou operação é executada ao consultar este painel.</p></header><p id="error" role="alert"></p>
|
|
@foreach(array_merge(['sales'=>'Comercial e recebíveis','costs'=>'Oficina e custos directos','suppliers'=>'Obrigações a fornecedores'],config('industrial_ledger.synthetic_enabled')===true?['industrial'=>'Lote industrial e CIF seleccionado']:[]) as $kind=>$label)
|
|
@php $panel=$data['panels'][$kind]; @endphp
|
|
<section><h2>{{ $label }}</h2>@if(!$panel['allowed'])<p>Consulta da origem indisponível para este perfil.</p>@else
|
|
@forelse($panel['rows'] as $row)<article>
|
|
@if($kind==='sales')<h3><a href="/general-ledger/sales?invoice_id={{ $row['invoice_id'] }}">Factura {{ $row['number'] }}</a></h3><p>Abertura financeira confirmada: {{ $row['confirmed_opening']?'sim':'não' }}. Lançamento original: {{ $row['original_journal_id']??'pendente' }}.</p>
|
|
@elseif($kind==='costs')<h3><a href="/general-ledger/costs?order_id={{ $row['order_id'] }}">Ordem #{{ $row['order_id'] }}</a></h3><p>Cálculo #{{ $row['calculation_id']??'pendente' }} / versão {{ $row['calculation_version']??'—' }}. Decisão registada: {{ $row['recorded_decision']??'pendente' }}. Original #{{ $row['original_journal_id']??'pendente' }}; resultado de correcção #{{ $row['recorded_correction_result_id']??'pendente' }}.</p><p>Conferência actual das dependências exigida na origem.</p>
|
|
@elseif($kind==='industrial')<h3><a href="/general-ledger/industrial?lot_id={{ $row['lot_id'] }}">Lote #{{ $row['lot_id'] }}</a></h3><p>Resultado #{{ $row['result_id']??'pendente' }} / versão {{ $row['result_version']??'—' }} · decisão registada {{ $row['recorded_decision']??'pendente' }} · lançamento #{{ $row['original_journal_id']??'pendente' }}. Conferir dependências actuais na origem; residual separado.</p>
|
|
@else<h3><a href="/general-ledger?obligation_id={{ $row['obligation_id'] }}">Fornecedor · {{ $row['document_number'] }}</a></h3><p>Principal reconhecido {{ $money($row['principal_minor']) }}; este valor não representa saldo actual. Lançamento original #{{ $row['original_journal_id']??'pendente' }}.</p><a href="/general-ledger/flow?source={{ $row['source_id'] }}">Conferir origem e obrigação</a>@endif
|
|
</article>@empty<p>Nenhum registo neste contexto e página.</p>@endforelse
|
|
@php $key=['sales'=>'invoices_page','costs'=>'costs_page','suppliers'=>'suppliers_page','industrial'=>'industrial_page'][$kind]; @endphp<nav aria-label="Páginas de {{ $label }}"><p>Página {{ $panel['pagination']['page'] }} de {{ $panel['pagination']['last_page'] }} · {{ $panel['pagination']['total'] }} registos · 25 por página</p>@foreach($pager($key,$panel['pagination']) as $link)<a href="{{ $link['url'] }}">{{ $link['label'] }}</a>@endforeach</nav>@endif</section>@endforeach
|
|
<section><h2>Diário conjunto</h2><p>Débitos {{ $money($data['book']['totals']['debit_minor']) }} · créditos {{ $money($data['book']['totals']['credit_minor']) }}.</p>@foreach($data['book']['journals'] as $j)@php $source=json_decode($j->snapshot,true)['source']; @endphp<article><p>Lançamento #{{ $j->id }} · {{ $source['effect_type'] }} · {{ $j->journal_on }} · {{ $money($j->debit_minor) }}</p><p>Proposta #{{ $j->proposal_id }} · revisão #{{ $j->review_id }} · autor #{{ $j->posted_by }} · {{ $j->reason }}</p></article>@endforeach<nav aria-label="Páginas do diário">Página {{ $data['book']['pagination']['page'] }} de {{ $data['book']['pagination']['last_page'] }} @foreach($pager('journals_page',$data['book']['pagination']) as $link)<a href="{{ $link['url'] }}">{{ $link['label'] }}</a>@endforeach</nav></section>
|
|
<section><h2>Conferência e fecho conjunto</h2><p>Período {{ $data['period']?->period_key }} · {{ $data['period']?->status }}. A confirmação revalida todas as fontes compostas, incluindo as que não aparecem nesta página. Uma pendência impede o fecho.</p>@if($closed)<p class="notice">Período QA encerrado. Consulta preservada, sem reabertura.</p>@elseif(!$data['all_current_source_views'])<p>Este perfil não pode conferir todas as origens. Não há acções de fecho neste painel.</p>@endif
|
|
@if(!$closed&&$data['all_current_source_views']&&$data['period_permissions']['period_prepare'])<form data-action="period-prepare"><input type="hidden" name="period_key" value="{{ $data['period']->period_key }}"><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Capturar evidências e impacto do período</button></form>@endif
|
|
@foreach($data['checks']['rows'] as $item)@php $p=(object)$item['capture'];$r=$item['review']; @endphp<article><h3>Conferência #{{ $p->id }}</h3><p>Preparador #{{ $p->prepared_by }} · {{ $p->reason }} · versão <code>{{ $p->revision }}</code></p><details><summary>Evidências e impacto capturados</summary><pre>{{ $p->snapshot }}</pre></details>@if($r)<p>{{ $r->decision }} · autor #{{ $r->actor_id }} · {{ $r->reason }}</p>@endif
|
|
@if(!$closed&&$data['all_current_source_views']&&!$r&&$data['period_permissions']['period_validate']&&$p->prepared_by!==auth()->id())<form data-action="period-validate"><input type="hidden" name="check_id" value="{{ $p->id }}"><input type="hidden" name="revision" value="{{ $p->revision }}"><label>Decisão<select name="decision" required><option value="">Escolher</option><option value="approved">Aprovar versão exacta</option><option value="rejected">Recusar</option></select></label><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Registar conferência independente</button></form>@endif
|
|
@if(!$closed&&$data['all_current_source_views']&&$r?->decision==='approved'&&$data['period_permissions']['period_close']&&$p->prepared_by===auth()->id())<form data-action="period-close"><input type="hidden" name="check_id" value="{{ $p->id }}"><input type="hidden" name="revision" value="{{ $p->revision }}"><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Revalidar e fechar este período QA</button></form>@endif
|
|
@if($item['closure'])<p>Fecho #{{ $item['closure']->id }} · {{ $item['closure']->reason }}</p>@endif</article>@endforeach<nav aria-label="Páginas das conferências">Página {{ $data['checks']['pagination']['page'] }} de {{ $data['checks']['pagination']['last_page'] }} @foreach($pager('checks_page',$data['checks']['pagination']) as $link)<a href="{{ $link['url'] }}">{{ $link['label'] }}</a>@endforeach</nav></section>
|
|
@include('accounting.receipt-recovery')
|
|
</main><script>
|
|
const csrf=@json(csrf_token()),context=@json(session('company_context.token'));
|
|
for(const form of document.querySelectorAll('[data-action]'))form.onsubmit=async e=>{e.preventDefault();const data=Object.fromEntries(new FormData(form));if('check_id' in data)data.check_id=Number(data.check_id);const body=JSON.stringify(data);if(form.dataset.body!==body){form.dataset.body=body;form.dataset.key=crypto.randomUUID();}const button=form.querySelector('button');button.disabled=true;document.querySelector('#error').textContent='';try{const r=await fetch('/api/general-ledger/'+form.dataset.action,{method:'POST',credentials:'same-origin',headers:{Accept:'application/json','Content-Type':'application/json','X-CSRF-TOKEN':csrf,'X-SGF-Context':context,'Idempotency-Key':form.dataset.key},body});const result=await r.json();if(!r.ok)throw Error(result.message||'Conferência recusada.');location.reload();}catch(err){document.querySelector('#error').textContent=err.message+' Chave do pedido: '+form.dataset.key+'. Abra novamente as origens e confira as versões antes de repetir.';}finally{button.disabled=false;}};
|
|
</script></body></html>
|