37 lines
7.6 KiB
TypeScript
37 lines
7.6 KiB
TypeScript
import {useState} from 'react';
|
|
import {newExclusionBase,newExclusionPart,switchExclusionPart,exclusionBook,exclusionConditions,exclusionCurrent,exclusionReportRows,exclusionBaseSource,exclusionTreatments,partConditions,recordExclusions,saveExclusionBook,type ExclusionBook,type ExclusionRow,type ExclusionPart} from '@/lib/iva-exclusion-base';
|
|
|
|
export function SimulationExclusionBase({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
|
const[error,setError]=useState('');let book:ExclusionBook;
|
|
try{book=exclusionBook(draft);}catch(cause){return<p role="alert">{String(cause)}</p>;}
|
|
const save=(next:ExclusionBook)=>{try{onChange('modelo_a_snapshot',saveExclusionBook(draft,next));setError('');}catch(cause){setError(String(cause));}};
|
|
const change=(id:string,patch:Partial<ExclusionRow>)=>save({...book,rows:book.rows.map(row=>row.id===id?{...row,...patch}:row)});
|
|
return<details className="space-y-3 rounded border p-3">
|
|
<summary>Base tributável — exclusões da contraprestação</summary>
|
|
<p>Oportunidade: {String(draft.context_opportunity||'entrada geral')}. Prepare uma composição por operação,partindo do montante sem próprio IVA e com as inclusões aplicáveis já consideradas. Identifique as parcelas e se ainda estão incluídas;subtraia apenas essas parcelas,sem segunda exclusão.</p>
|
|
<p>Cada tratamento tem condições próprias. Indemnização judicial não é qualquer compensação;desconto deve estar concedido;pagamento por conta alheia exige nome/conta do adquirente e adequadas contas de terceiros. Nas embalagens,não se exige devolução já realizada:confira a não transmissão,a indicação separada e a menção de devolução acordada. Reutilize documentos ou declare pressupostos de projecção. Base não é IVA nem regularização.</p>
|
|
<p>{exclusionBaseSource}</p>{error&&<p role="alert">{error}</p>}
|
|
<button type="button" className="underline" onClick={()=>save({...book,rows:[...book.rows,newExclusionBase(crypto.randomUUID(),String(draft.currency??''))]})}>Acrescentar exclusões de operação</button>
|
|
{book.rows.map(row=>{const partChange=(id:string,patch:Partial<ExclusionPart>)=>change(row.id,{parts:row.parts.map(p=>p.id===id?{...p,...patch}:p)});return<details key={row.id} className="rounded border p-3"><summary>{row.description||'Operação por identificar'} — {row.period||'mês por indicar'}</summary>
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
<label>Natureza dos dados<select className="block rounded border p-2" value={row.origin} onChange={e=>change(row.id,{origin:e.target.value as ExclusionRow['origin']})}><option value="projected">Projectados / pressupostos</option><option value="effective">Efectivos declarados</option></select></label>
|
|
{([['description','Operação identificada'],['operationRef','Referência da operação / pressuposto'],['initialAmount','Montante inicial sem próprio IVA (moeda indicada)'],['initialRef','Referência do montante inicial e da sua composição'],['documentRef','Documento da operação / referência da previsão'],['documentDate','Data do documento / prevista'],['period','Mês da operação'],['currency','Moeda de origem'],['exclusionRef','Referência da composição e exclusões aplicáveis'],['evidence','Fundamento factual / pressupostos']] as const).map(([field,label])=><label key={field}>{label}<input className="block rounded border p-2" type={field==='documentDate'?'date':field==='period'?'month':'text'} value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}/></label>)}
|
|
</div>
|
|
<fieldset><legend>Condições das exclusões</legend>{exclusionConditions.map(([key,label])=><label className="block" key={key}>{label}<select className="block rounded border p-2" value={row.conditions[key]??''} onChange={e=>change(row.id,{conditions:{...row.conditions,[key]:e.target.value}})}><option value="">Por indicar</option><option value="yes">Sim</option><option value="no">Não</option></select></label>)}</fieldset>
|
|
<button type="button" className="underline" onClick={()=>change(row.id,{parts:[...row.parts,newExclusionPart(crypto.randomUUID())]})}>Acrescentar parcela desta operação</button>
|
|
{row.parts.map(part=><fieldset key={part.id} className="rounded border p-3"><legend>{part.description||'Parcela por identificar'}</legend>
|
|
<label>Natureza da parcela<select className="block rounded border p-2" value={part.treatment} onChange={e=>partChange(part.id,switchExclusionPart(part,e.target.value))}><option value="">Por indicar</option>{exclusionTreatments.map(t=><option key={t.id} value={t.id}>{t.label}</option>)}</select></label>
|
|
{([['description','Descrição da parcela'],['amount','Montante da parcela sem próprio IVA (moeda indicada)'],['reference','Referência da parcela / pressuposto']] as const).map(([field,label])=><label className="block" key={field}>{label}<input className="block rounded border p-2" value={part[field]} onChange={e=>partChange(part.id,{[field]:e.target.value})}/></label>)}
|
|
<label>Esta parcela ainda está incluída no montante inicial?<select className="block rounded border p-2" value={part.included} onChange={e=>partChange(part.id,{included:e.target.value as ExclusionPart['included']})}><option value="">Por indicar</option><option value="yes">Sim — excluir uma vez</option><option value="no">Não — já excluída,conservar sem nova subtracção</option></select></label>
|
|
<label>Âmbito da exclusão: operação, montantes e condições<input className="block rounded border p-2" value={part.scope} onChange={e=>partChange(part.id,{scope:e.target.value})}/></label>
|
|
{part.treatment==='third_party_payment'&&<><label>Referência das adequadas contas de terceiros<input className="block rounded border p-2" value={part.accountRef} onChange={e=>partChange(part.id,{accountRef:e.target.value})}/></label><label>Adquirente/destinatário em nome e por conta de quem se pagou<input className="block rounded border p-2" value={part.beneficiaryRef} onChange={e=>partChange(part.id,{beneficiaryRef:e.target.value})}/></label></>}
|
|
{part.treatment==='returnable_packaging'&&<label>Indicação separada e menção de devolução acordada na factura/documento<input className="block rounded border p-2" value={part.documentExcerpt} onChange={e=>partChange(part.id,{documentExcerpt:e.target.value})}/></label>}
|
|
{partConditions(part.treatment).map(([key,label])=><label className="block" key={key}>{label}<select className="block rounded border p-2" value={part.conditions[key]??''} onChange={e=>partChange(part.id,{conditions:{...part.conditions,[key]:e.target.value as ExclusionPart['included']}})}><option value="">Por indicar</option><option value="yes">Sim</option><option value="no">Não</option></select></label>)}
|
|
<p>Mudar a natureza conserva os montantes e referências,mas exige rever a correspondência da parcela. Cada parcela será excluída uma única vez nesta operação. Os campos sem aplicação ficam ocultos e conservados.</p>
|
|
</fieldset>)}
|
|
</details>;})}
|
|
{!!book.rows.length&&<button type="button" className="rounded bg-emerald-800 p-2 text-white" onClick={()=>{try{save(recordExclusions(draft,book));}catch(cause){setError(String(cause));}}}>Aplicar exclusões à base e guardar versão</button>}
|
|
{book.result&&<><p role="status">{exclusionCurrent(draft,book)?'Exclusões correspondentes às entradas guardadas.':'Entradas alteradas;exclusões históricas conservadas. Reveja e determine novamente.'} {book.history?.length??0} versões anteriores. IVA e campo11 não são preenchidos por estas bases.</p><dl>{exclusionReportRows(draft).map(([,label,value,origin],index)=><div key={index}><dt className="font-semibold">{label}</dt><dd>{value}<small className="block">{origin}</small></dd></div>)}</dl></>}
|
|
</details>;
|
|
}
|