18 lines
15 KiB
PHP
18 lines
15 KiB
PHP
<!doctype html><html lang="pt-MZ"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Diário integrado · SGF</title><style>body{font:16px system-ui;background:#f3f7f5;color:#173e36;margin:0}main{max-width:1120px;margin:auto;padding:24px}section,article{background:white;border:1px solid #bed0c9;border-radius:8px;padding:18px;margin:16px 0}label{display:block;margin:10px 0}input,textarea,select,button{font:inherit;padding:10px;max-width:100%;box-sizing:border-box}input,select,textarea{display:block;width:100%}table{width:100%;border-collapse:collapse}td,th{text-align:left;padding:8px;border-bottom:1px solid #ddd}a{color:#174d71}.notice{background:#fff3cf;padding:14px}nav{display:flex;gap:18px;flex-wrap:wrap}</style></head><body><main id="composed-ledger" data-context="{{ $context }}" data-csrf="{{ $csrf }}">
|
|
@php($money=fn($v)=>number_format($v/100,2,',',' ').' MZN')
|
|
<section><h2>Procurar a origem individual</h2><form method="get"><label>Tipo de origem<select name="source_kind">@foreach(['all'=>'Todas as famílias','supplier_payable.recognised'=>'Obrigação de compra','allocation.confirmed'=>'Afectação a fornecedor','allocation.reversed'=>'Reversão a fornecedor','sales.invoice'=>'Documento comercial','receivable.allocated'=>'Afectação de cliente','receivable.reversed'=>'Reversão de cliente','receivable.reduced'=>'Crédito nominal de cliente','receivable.reduction_reversed'=>'Reversão do crédito nominal','workshop.direct_cost.validated'=>'Custo de oficina','industry.cost.validated'=>'Custo industrial','cash.receipt_classified'=>'Classificação de Caixa','cash.expense_confirmed'=>'Despesa de Caixa','stock.receipt'=>'Entrada física','stock.issue'=>'Saída física','stock.return'=>'Devolução física','stock.adjustment'=>'Diferença de inventário','stock.supplier_return'=>'Devolução ao fornecedor'] as $value=>$label)<option value="{{ $value }}" @selected($data['source_pagination']['kind']===$value)>{{ $label }}</option>@endforeach</select></label><label>Registos de cada família por página<select name="source_per_page">@foreach([25,100] as $size)<option value="{{ $size }}" @selected($data['source_pagination']['per_page']===$size)>{{ $size }}</option>@endforeach</select></label><button>Consultar origens</button></form><p>As famílias são paginadas separadamente. Escolher um tipo não escolhe um documento nem prepara um lançamento.</p>@php($p=$data['source_pagination'])<nav aria-label="Paginação das origens">Página {{ $p['page'] }} de {{ $p['last_page'] }} @if($p['page']>1)<a href="{{ request()->fullUrlWithQuery(['source_page'=>$p['page']-1]) }}">Anterior</a>@endif @if($p['page']<$p['last_page'])<a href="{{ request()->fullUrlWithQuery(['source_page'=>$p['page']+1]) }}">Seguinte</a>@endif</nav></section>
|
|
<nav><a href="/">Voltar ao SGF</a><a href="/sgf">Trocar função QA</a><a href="/general-ledger/trial-balance?from_on=2026-01-01&to_on=2026-12-31">Balancete e razão por conta</a></nav><h1>Contabilidade · diário integrado</h1><p>Empresa {{ $data['sgf_scope']['company_id'] }} · Unidade {{ $data['sgf_scope']['unit_id'] }}</p><p class="notice">Contas e período artificiais. Um só diário para origens de Compras, Comercial, Oficinas e Stock. Preparar não lança; revisão distinta e aplicação individual voltam a conferir a origem. Estes dados não constituem emissão fiscal, pagamento real ou demonstração financeira legal.</p><p id="ledger-result" role="status"></p>
|
|
@if($data['permissions']['prepare'])<section><h2>Preparar um lançamento</h2><form data-ledger-action="capture"><label>Origem individual<select name="source" required><option value="">Escolha explicitamente o documento ou efeito</option>@foreach($data['sources'] as $source)<option value="{{ $source['kind'] }}|{{ $source['id'] }}">{{ $source['label'] }}@if($source['amount']!==null) · {{ $money($source['amount']) }}@endif</option>@endforeach</select></label><label>Data explícita<input name="journal_on" type="date" required></label><label>Período<select name="period_key" required><option value="">Escolha</option>@foreach($data['cycle']['periods'] as $period)@if($period->status==='open')<option value="{{ $period->period_key }}">{{ $period->period_key }} · {{ $period->starts_on }} a {{ $period->ends_on }}</option>@endif @endforeach</select></label><label>Fundamento<textarea name="reason" required minlength="3" maxlength="2000"></textarea></label><button>Preparar a fotografia e mostrar o impacto</button></form></section>@endif
|
|
<section><h2>Conferências e impacto</h2>@foreach($data['proposals'] as $p)@php($snapshot=json_decode($p->snapshot,true))@php($review=collect($data['reviews'])->first(fn($r)=>$r->proposal_id===$p->id))@php($part=collect($data['cycle']['corrections'])->contains(fn($c)=>in_array($p->id,[$c->reverse_proposal_id,$c->replacement_proposal_id],true)))<article><h3>Conferência #{{ $p->id }} · versão {{ $p->capture_version }}</h3><p>{{ $p->reason }}</p><p>Data {{ $snapshot['journal_on'] }} · {{ $snapshot['period']['period_key'] }} · Preparador #{{ $p->prepared_by }}</p><table><thead><tr><th>Conta artificial</th><th>Débito</th><th>Crédito</th></tr></thead><tbody>@foreach($snapshot['lines'] as $line)<tr><td>{{ $line['account_code'] }}</td><td>{{ $money($line['debit_minor']) }}</td><td>{{ $money($line['credit_minor']) }}</td></tr>@endforeach</tbody></table><p>Impacto equilibrado: {{ $money($snapshot['impact']['debit_minor']) }}. Sem alterar o saldo financeiro ou executar outro movimento físico.</p>
|
|
@if($review)<p>Decisão: {{ $review->decision==='approved'?'Aprovada':'Recusada' }} por outra função · {{ $review->reason }}</p>@endif
|
|
@if($p->journal_id)<p>Aplicada no lançamento #{{ $p->journal_id }}.</p>@elseif(!$part&&$data['permissions']['validate']&&!$review&&$p->prepared_by!==$data['current_actor'])<form data-ledger-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="">Escolha</option><option value="approved">Aprovar este impacto</option><option value="rejected">Recusar</option></select></label><label>Fundamento independente<textarea name="reason" required minlength="3"></textarea></label><button>Revalidar e registar revisão</button></form>
|
|
@elseif(!$part&&$data['permissions']['post']&&$review?->decision==='approved'&&$p->prepared_by===$data['current_actor'])<form data-ledger-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"></textarea></label><button>Revalidar e aplicar este impacto uma vez</button></form>@endif</article>@endforeach</section>
|
|
<section><h2>Lançamentos</h2><p>Débitos {{ $money($data['totals']['debit_minor']) }} · Créditos {{ $money($data['totals']['credit_minor']) }}</p><table><thead><tr><th>Lançamento</th><th>Data</th><th>Valor</th><th>Fundamento</th></tr></thead><tbody>@foreach($data['journals'] as $j)<tr><td>#{{ $j->id }}</td><td>{{ $j->journal_on }}</td><td>{{ $money($j->debit_minor) }}</td><td>{{ $j->reason }}</td></tr>@endforeach</tbody></table><nav>Página {{ $data['pagination']['page'] }} de {{ $data['pagination']['last_page'] }} @if($data['pagination']['page']>1)<a href="?page={{ $data['pagination']['page']-1 }}">Anterior</a>@endif @if($data['pagination']['page']<$data['pagination']['last_page'])<a href="?page={{ $data['pagination']['page']+1 }}">Seguinte</a>@endif</nav></section>
|
|
<section><h2>Correcção por estorno e substituição</h2>@if($data['permissions']['correct_prepare'])<form data-ledger-action="correct-prepare"><label>Original a corrigir<select name="journal_id" required><option value="">Escolha o original</option>@foreach($data['journals'] as $j)@php($kind=json_decode($j->snapshot,true)['source']['effect_type'])@if(in_array($kind,['supplier_payable.recognised','workshop.direct_cost.validated','industry.cost.validated'],true))<option value="{{ $j->id }}">#{{ $j->id }} · {{ $money($j->debit_minor) }} · {{ $j->journal_on }}</option>@endif @endforeach</select></label><label>Data da correcção<input name="journal_on" type="date" required></label><label>Período<input name="period_key" value="QA-2026-INTEGRADO" required></label><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Preparar o par indivisível para revisão</button></form>@endif
|
|
@foreach($data['cycle']['corrections'] as $c)@php($reverse=json_decode($c->reverse_snapshot,true))@php($replace=json_decode($c->replacement_snapshot,true))<article><h3>Correcção #{{ $c->id }} do original #{{ $c->original_journal_id }}</h3><p>Estorno {{ $money($reverse['impact']['debit_minor']) }} e substituição {{ $money($replace['impact']['debit_minor']) }} · {{ $c->reason }}</p>@if($c->result)<p>Par aplicado nos lançamentos #{{ $c->result->reverse_journal_id }}/#{{ $c->result->replacement_journal_id }}.</p>@elseif($data['permissions']['correct_validate']&&!$c->reverse_review&&$c->prepared_by!==$data['current_actor'])<form data-ledger-action="correct-validate"><input type="hidden" name="correction_id" value="{{ $c->id }}"><input type="hidden" name="revision" value="{{ $c->revision }}"><label>Decisão<select name="decision" required><option value="">Escolha</option><option value="approved">Aprovar o par mostrado</option><option value="rejected">Recusar</option></select></label><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Rever o par exacto</button></form>@elseif($data['permissions']['correct_post']&&$c->reverse_review?->decision==='approved'&&$c->replacement_review?->decision==='approved'&&$c->prepared_by===$data['current_actor'])<form data-ledger-action="correct-post"><input type="hidden" name="correction_id" value="{{ $c->id }}"><input type="hidden" name="revision" value="{{ $c->revision }}"><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Aplicar estorno e substituição atomicamente</button></form>@endif</article>@endforeach</section>
|
|
<section><h2>Conferência e fecho do período de ensaio</h2>@if($data['permissions']['period_prepare'])<form data-ledger-action="period-prepare"><label>Período<input name="period_key" value="QA-2026-INTEGRADO" required></label><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Conferir origens e pendências antes do fecho</button></form>@endif
|
|
@foreach($data['cycle']['period_checks'] as $check)@php($snapshot=json_decode($check->snapshot,true))@php($review=collect($data['cycle']['period_reviews'])->first(fn($r)=>$r->check_id===$check->id))@php($closed=collect($data['cycle']['period_closures'])->contains(fn($r)=>$r->check_id===$check->id))<article><h3>{{ $check->period_key }} · conferência #{{ $check->id }}</h3><p>{{ $snapshot['facts'] }} factos · {{ $snapshot['pending'] }} pendências · Débitos {{ $money($snapshot['debit_minor']) }} / Créditos {{ $money($snapshot['credit_minor']) }}</p>@if($closed)<p>Período QA fechado; sem reabertura neste percurso.</p>@elseif($data['permissions']['period_validate']&&!$review&&$check->prepared_by!==$data['current_actor'])<form data-ledger-action="period-validate"><input type="hidden" name="check_id" value="{{ $check->id }}"><input type="hidden" name="revision" value="{{ $check->revision }}"><label>Decisão<select name="decision" required><option value="">Escolha</option><option value="approved">Aprovar conferência</option><option value="rejected">Recusar</option></select></label><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Rever a conferência exacta</button></form>@elseif($data['permissions']['period_close']&&$review?->decision==='approved'&&$check->prepared_by===$data['current_actor'])<form data-ledger-action="period-close"><input type="hidden" name="check_id" value="{{ $check->id }}"><input type="hidden" name="revision" value="{{ $check->revision }}"><label>Fundamento<textarea name="reason" required minlength="3"></textarea></label><button>Revalidar tudo e fechar o período QA</button></form>@endif</article>@endforeach</section>
|
|
<section><h2>Stock · taxa de valorização</h2>@foreach($data['stock'] as $s)<article><p>Artigo #{{ $s['book']['stock_item_id'] }} · Armazém #{{ $s['book']['warehouse_id'] }} · Saldo físico {{ $s['physical_balance_milli']/1000 }} {{ $s['book']['unit_code'] }}</p>@if(isset($s['ownership']['owned_quantity_milli']))<p>Propriedade total deste artigo {{ $s['ownership']['owned_quantity_milli']/1000 }} {{ $s['book']['unit_code'] }}, incluindo {{ $s['ownership']['in_transit_milli']/1000 }} em trânsito. Transferências internas não são consumo.</p>@else<p>{{ $s['ownership']['ownership_pending']??'Propriedade por conferir' }}</p>@endif @if($data['permissions']['prepare'])<form data-ledger-action="rate-prepare" data-stock-rate><input type="hidden" name="book_id" value="{{ $s['book']['id'] }}"><input type="hidden" name="version" value="{{ $s['rates'][0]->version??0 }}"><label>Custo unitário artificial (MZN/UN)<input name="unit_amount" required inputmode="decimal"></label><label>Fundamento<textarea name="reason" required minlength="10"></textarea></label><button>Preparar taxa para revisão distinta</button></form>@endif @foreach($s['rates'] as $rate)<p>Taxa v{{ $rate->version }} · {{ $money($rate->unit_minor) }}/UN · {{ $rate->review?->decision??'Por rever' }}</p>@if($data['permissions']['validate']&&!$rate->review&&$rate->prepared_by!==$data['current_actor'])<form data-ledger-action="rate-review" data-stock-rate><input type="hidden" name="rate_id" value="{{ $rate->id }}"><input type="hidden" name="version" value="{{ $rate->version }}"><label>Decisão<select name="decision" required><option value="">Escolha</option><option value="approved">Aprovar esta taxa</option><option value="rejected">Recusar</option></select></label><label>Fundamento<textarea name="reason" required minlength="10"></textarea></label><button>Rever a taxa actual</button></form>@endif @endforeach</article>@endforeach</section>
|
|
<section id="chart"><h2>Plano de contas de teste</h2><p>Contas artificiais do mesmo diário e desta empresa/unidade. A classificação comercial tem proposta e revisão próprias; consultar uma conta não cria um lançamento.</p><form method="get"><label>Pesquisar código ou designação<input name="account_q" maxlength="80" value="{{ request('account_q','') }}"></label><label>Contas por página<select name="accounts_per_page">@foreach([25,100] as $size)<option value="{{ $size }}" @selected($data['chart_pagination']['per_page']===$size)>{{ $size }}</option>@endforeach</select></label><button>Consultar contas</button></form><table><thead><tr><th>Código</th><th>Designação</th><th>Moeda</th><th>Consulta</th></tr></thead><tbody>@foreach($data['chart_accounts'] as $account)<tr><td>{{ $account->code }}</td><td>{{ $account->label }}</td><td>{{ $account->currency }}</td><td><a href="{{ '/general-ledger/account-ledger?'.http_build_query(['from_on'=>'2026-01-01','to_on'=>'2026-12-31','account_id'=>$account->id]) }}">Abrir razão desta conta</a></td></tr>@endforeach</tbody></table>@php($p=$data['chart_pagination'])<nav aria-label="Paginação do plano de contas">Página {{ $p['page'] }} de {{ $p['last_page'] }} @if($p['page']>1)<a href="{{ request()->fullUrlWithQuery(['accounts_page'=>$p['page']-1]) }}#chart">Anterior</a>@endif @if($p['page']<$p['last_page'])<a href="{{ request()->fullUrlWithQuery(['accounts_page'=>$p['page']+1]) }}#chart">Seguinte</a>@endif</nav></section>
|
|
</main><script type="module" src="/sgf-composed-ledger.mjs"></script></body></html>
|