24 lines
11 KiB
PHP
24 lines
11 KiB
PHP
@php $c=$data['cost'];$id=$c['order_id'];$source=$c['source'];$facts=$c['facts'];$closed=collect($data['periods'])->where('period_key','QA-2026-10')->sortByDesc('version')->first()?->status==='closed';$money=fn($n)=>($n<0?'-':'').number_format(intdiv(abs($n),100),0,',',' ').','.str_pad((string)(abs($n)%100),2,'0',STR_PAD_LEFT).' MZN'; @endphp
|
|
<!doctype html><html lang="pt"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Custo directo e diário QA</title><style>body{font:17px system-ui;background:#f3f6f5;color:#142b28;margin:0}main{max-width:1100px;margin:auto;padding:24px}header,section{background:white;border:1px solid #d5e0dc;border-radius:12px;padding:24px;margin:18px 0}article{border-top:1px solid #ddd;padding:18px 0}label{display:block;margin:12px 0}input,select,textarea,button{font:inherit;padding:10px;max-width:95%}textarea{display:block;width:90%}.notice{background:#fff2cc;padding:16px}pre{white-space:pre-wrap;overflow-wrap:anywhere}a{color:#125a4b}code{overflow-wrap:anywhere}</style></head><body><main>
|
|
<header><a href="/general-ledger">Diário</a> · <a href="/general-ledger/trial-balance?from_on=2026-10-01&to_on=2026-10-31">Balancete e razão QA</a> · <a href="/qa/cost-demo">Perfis do ensaio</a><h1>Oficina → custo directo validado → Contabilidade</h1><p class="notice">EXCLUSIVAMENTE SINTÉTICO. Custo directo conhecido do perímetro seleccionado, não custo completo, margem, stock valorizado ou salário. Contas artificiais; nenhuma execução monetária.</p><p>Empresa #{{ $c['scope']['company_id'] }} / unidade #{{ $c['scope']['unit_id'] }}. Validar o custo não lança automaticamente. Capturar, rever e aplicar são decisões individuais.</p></header><p id="error" role="alert"></p>
|
|
<section><h2>Perímetros explicitamente compostos</h2>@foreach($c['orders'] as $o)<p><a href="?order_id={{ $o->order_id }}">Ordem #{{ $o->order_id }}</a> · {{ $o->reason }}</p>@endforeach</section>
|
|
@if($facts)<section><h2>Conferência da ordem #{{ $id }}</h2><p>{{ $facts['conference']['order']['reference'] }} · cálculo #{{ $facts['conference']['calculation']['id']??'pendente' }} / versão {{ $facts['conference']['calculation']['version']??'—' }} · decisão {{ $facts['conference']['decision']['decision']??'pendente' }}</p><p>Conhecidos {{ $facts['conference']['snapshot']['known_subtotal_exact']??'—' }} MZN; total seleccionado {{ $facts['conference']['snapshot']['selected_direct_total_exact']??'indisponível' }} MZN.</p>@if($c['pending'])<p class="notice">{{ $c['pending'] }}</p>@endif<details><summary>Origens verificadas, taxas, decisões e versões</summary><pre>{{ json_encode($facts,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) }}</pre></details>
|
|
@if($source)<p>Impacto proposto: D QA-CUSTO-DIRECTO {{ $money($source['principal_minor']) }} / C QA-COMPENSACAO-ENSAIO {{ $money($source['principal_minor']) }}. Sem alterar a origem ou criar dívida.</p>@if(!$closed&&$data['permissions']['prepare']&&!count($data['book']['journals']))<form data-action="effect-prepare"><input type="hidden" name="effect_type" value="workshop.direct_cost.validated"><input type="hidden" name="source_id" value="{{ $id }}"><input type="hidden" name="rule_key" value="QA-DIRECT-COST"><label>Data explícita<input type="date" name="journal_on" value="2026-10-29" required></label><label>Período<input name="period_key" value="QA-2026-10" required></label><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Capturar fonte e impacto — sem lançar</button></form>@endif @endif
|
|
@if($closed)<p class="notice">Período QA fechado; conservar a consulta e os comprovativos. Sem reabertura.</p>@endif</section>@endif
|
|
@if($c['accounting_state']==='requires_correction')<p class="notice">A fonte actual difere do custo lançado ou está pendente. Não criar outro reconhecimento; a conferência do período exige uma resolução explícita.</p>@endif
|
|
@if(config('cost_ledger.correction_enabled')===true)@include('accounting.cost-correction')@endif
|
|
<section><h2>Propostas e conferência contabilística</h2>@foreach($data['book']['proposals'] as $p)@php $snap=json_decode($p->snapshot,true);$isPart=in_array($snap['source']['effect_type'],['journal.reversal','journal.replacement','workshop.direct_cost.reversal','workshop.direct_cost.replacement','industry.cost.reversal','industry.cost.replacement'],true);$r=collect($data['book']['reviews'])->firstWhere('proposal_id',$p->id); @endphp<article><h3>Proposta #{{ $p->id }} · versão da captura {{ $p->capture_version }}</h3><p>{{ $p->reason }} · preparador #{{ $p->prepared_by }} · revisão exacta <code>{{ $p->revision }}</code></p><ul>@foreach($snap['lines'] as $l)<li>{{ $l['account_code'] }} — D {{ $money($l['debit_minor']) }} / C {{ $money($l['credit_minor']) }}</li>@endforeach</ul><details><summary>Fotografia imutável capturada</summary><pre>{{ json_encode($snap,JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) }}</pre></details>@if($r)<p>{{ $r->decision }} por #{{ $r->reviewed_by }} · {{ $r->reason }}</p>@endif
|
|
@if(!$closed&&!$isPart&&$data['permissions']['validate']&&!$r&&$p->prepared_by!==auth()->id())<form data-action="validate"><input type="hidden" name="proposal_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 independente<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Registar conferência — sem aplicar</button></form>@endif
|
|
@if(!$closed&&!$isPart&&$data['permissions']['post']&&$r?->decision==='approved'&&!$p->journal_id&&$p->prepared_by===auth()->id())<form data-action="post"><input type="hidden" name="proposal_id" value="{{ $p->id }}"><input type="hidden" name="revision" value="{{ $p->revision }}"><label>Fundamento da aplicação<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Revalidar e aplicar este custo uma vez</button></form>@endif</article>@endforeach</section>
|
|
<section><h2>Lançamentos e histórico por origem</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)<details><summary>Lançamento #{{ $j->id }} · {{ $j->journal_on }} · {{ $money($j->debit_minor) }}</summary><p>Proposta #{{ $j->proposal_id }} · revisão #{{ $j->review_id }} · aplicador #{{ $j->posted_by }} · {{ $j->reason }}</p><pre>{{ json_encode(json_decode($j->snapshot,true),JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE) }}</pre></details>@endforeach @foreach($data['book']['events'] as $e)<p>#{{ $e->id }} · {{ $e->kind }} · autor #{{ $e->actor_id }} · {{ $e->reason }}</p>@endforeach</section>
|
|
<section><h2>Conferência e fecho do período composto</h2><p>Inclui todas as fontes compostas da empresa/unidade. Custo pendente, alterado ou ainda não lançado impede o fecho; ocultar uma linha na página não a exclui da conferência.</p>@if(!$closed&&$data['permissions']['period_prepare'])<form data-action="period-prepare"><input type="hidden" name="period_key" value="QA-2026-10"><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Capturar conferência do período</button></form>@endif
|
|
@foreach($data['period_checks'] as $p)@php $r=collect($data['period_reviews'])->firstWhere('check_id',$p->id); @endphp<article><h3>Conferência #{{ $p->id }}</h3><p>{{ $p->reason }} · versão <code>{{ $p->revision }}</code></p><details><summary>Impacto e fotografia do período</summary><pre>{{ $p->snapshot }}</pre></details>@if($r)<p>{{ $r->decision }} · autor #{{ $r->actor_id }} · {{ $r->reason }}</p>@endif
|
|
@if(!$closed&&!$r&&$data['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</option><option value="rejected">Recusar</option></select></label><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Conferir período sem fechar</button></form>@endif
|
|
@if(!$closed&&$r?->decision==='approved'&&$data['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 o período QA</button></form>@endif</article>@endforeach @foreach($data['period_closures'] as $c)<p>Fecho #{{ $c->id }} · {{ $c->period_key }} v{{ $c->period_version }} · {{ $c->reason }}</p>@endforeach</section>
|
|
@php $pages=array_merge([$data['cost']['pagination']['last_page'],$data['book']['pagination']['last_page']],array_column($data['pagination'],'last_page'),array_column($data['book']['evidence_pagination'],'last_page'));$page=$data['book']['pagination']['page'];$last=max($pages); @endphp<nav aria-label="Paginação das evidências"><p>Página {{ $page }} de {{ $last }} · cada lista limitada a25 registos</p>@foreach([-1=>'Anterior',1=>'Seguinte'] as $delta=>$label)@if($page+$delta>=1&&$page+$delta<=$last)<a href="?{{ http_build_query(array_filter(['order_id'=>$id,'page'=>$page+$delta],fn($v)=>$v!==null)) }}">{{ $label }}</a>@endif @endforeach</nav>
|
|
@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));for(const k of ['source_id','proposal_id','check_id','journal_id','correction_id'])if(k in data)data[k]=Number(data[k]);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+'. Confira a versão e o histórico antes de repetir.';}finally{button.disabled=false;}};
|
|
</script></body></html>
|