36 lines
10 KiB
TypeScript
36 lines
10 KiB
TypeScript
import {useState} from 'react';
|
||
import {newSecondhand,switchSecondhandTreatment,switchSecondhandCategory,secondhandBook,secondhandConditions,secondhandCategoryConditions,secondhandCurrent,secondhandReportRows,secondhandSource,secondhandTreatments,secondhandCategories,recordSecondhands,saveSecondhandBook,type SecondhandBook,type SecondhandRow} from '@/lib/iva-secondhand';
|
||
|
||
export function SimulationSecondhand({draft,onChange}:{draft:Record<string,unknown>;onChange:(field:string,value:string)=>void}){
|
||
const[error,setError]=useState('');let book:SecondhandBook;
|
||
try{book=secondhandBook(draft);}catch(cause){return<p role="alert">{String(cause)}</p>;}
|
||
const save=(next:SecondhandBook)=>{try{onChange('modelo_a_snapshot',saveSecondhandBook(draft,next));setError('');}catch(cause){setError(String(cause));}};
|
||
const change=(id:string,patch:Partial<SecondhandRow>)=>save({...book,rows:book.rows.map(row=>row.id===id?{...row,...patch}:row)});
|
||
return<details className="space-y-3 rounded border p-3">
|
||
<summary>Bens emsegunda mão — revenda pela margem eleilão</summary>
|
||
<p>Oportunidade: {String(draft.context_opportunity||'entrada geral')}. Uma linha porbem.P125identifica categoria/estatuto;P092ouP093determina a base aplicável.Sem compensação de perdas entrebens,nova dedução ou IVAcalculado.</p>
|
||
<p>Revendedor:contraprestação total comIVA−preço compra,parcela positiva÷1.16 ebase arredondada à unidade48(6)b.16%é parâmetro do divisor,não IVAcalculado neste percurso.Leilão:facturado−líquidocomitente−IVApróprio identificado;líquido=adjudicação−comissão.Não substituir IVA desconhecido porzero.</p>
|
||
<p>{secondhandSource}</p>{error&&<p role="alert">{error}</p>}
|
||
<button type="button" className="underline" onClick={()=>save({...book,rows:[...book.rows,newSecondhand(crypto.randomUUID(),String(draft.currency??''))]})}>Acrescentar bem individual</button>
|
||
{book.rows.map(row=><details key={row.id} className="rounded border p-3"><summary>{row.description||'Bem por identificar'} — {row.period||'mês por indicar'}</summary>
|
||
<div className="grid gap-3 md:grid-cols-2">
|
||
<label>Percurso da margem<select className="block rounded border p-2" value={row.treatment} onChange={e=>change(row.id,switchSecondhandTreatment(row,e.target.value))}><option value="">Por indicar</option>{secondhandTreatments.map(t=><option key={t.id} value={t.id}>{t.label}</option>)}</select></label>
|
||
<label>Categoria do bem<select className="block rounded border p-2" value={row.category} onChange={e=>change(row.id,switchSecondhandCategory(row,e.target.value))}><option value="">Por indicar</option>{secondhandCategories.map(c=><option key={c.id} value={c.id}>{c.label}</option>)}</select></label>
|
||
<label>Natureza dos dados<select className="block rounded border p-2" value={row.origin} onChange={e=>change(row.id,{origin:e.target.value as SecondhandRow['origin']})}><option value="projected">Projectados / pressupostos</option><option value="effective">Efectivos declarados</option></select></label>
|
||
{([['description','Bem/operação identificados'],['operationRef','Referência da operação'],['operationDate','Data da operação / prevista'],['period','Mês da operação'],['currency','Moeda dos montantes'],['documentRef','Documento / referência da previsão'],['documentDate','Data do documento / prevista'],['goodsRef','Identidade do bem individual'],['operatorRef','Operador e estatuto revendedor/organizador'],['categoryRef','Características e referência da classificação'],['sourceRef','Fornecedor/comitente,origem e referência'],['scope','Âmbito:bem,partes,operação eperíodo'],['evidence','Fundamento factual / pressupostos']] as const).map(([field,label])=><label key={field}>{label}<input className="block rounded border p-2" type={['operationDate','documentDate'].includes(field)?'date':field==='period'?'month':'text'} value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}/></label>)}
|
||
<label>Qualidade do fornecedor/comitente<select className="block rounded border p-2" value={row.sourceType} onChange={e=>change(row.id,{sourceType:e.target.value})}><option value="">Por esclarecer</option><option value="private">Particular</option><option value="margin_reseller">Revendedor sujeito à margem</option><option value="exempt_9_12_e">Transmissão no âmbito9(12)e</option><option value="legacy_35_42">Referência histórica a35/42 — conferir situação2026</option><option value="other">Outro enquadramento por esclarecer</option></select></label>
|
||
{([['domesticPurchase','Aquisição dos bens no território nacional'],['domesticTaxable','Transmissão interna tributável,não exportação isenta13']] as const).map(([field,label])=><label key={field}>{label}<select className="block rounded border p-2" value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}><option value="">Por esclarecer</option><option value="yes">Sim</option><option value="no">Não</option></select></label>)}
|
||
{row.category==='art'&&<><label>Tipo de objecto de arte<select className="block rounded border p-2" value={row.artSubtype} onChange={e=>change(row.id,{artSubtype:e.target.value})}><option value="">Por indicar</option><option value="original">Quadro,pintura ou desenho original</option><option value="print">Gravura,estampa ou litografia</option><option value="sculpture">Escultura ou estatuária</option><option value="ceramic">Cerâmica</option></select></label>{row.artSubtype==='print'&&<label>Tiragem total<input className="block rounded border p-2" value={row.editionCount} onChange={e=>change(row.id,{editionCount:e.target.value})}/></label>}{row.artSubtype==='ceramic'&&<label>Cerâmica única,executada eassinada pelo artista<select className="block rounded border p-2" value={row.ceramicUniqueSigned} onChange={e=>change(row.id,{ceramicUniqueSigned:e.target.value})}><option value="">Por esclarecer</option><option value="yes">Sim</option><option value="no">Não</option></select></label>}</>}
|
||
{row.category==='collection'&&<><label>Tipo de colecção<select className="block rounded border p-2" value={row.collectionSubtype} onChange={e=>change(row.id,{collectionSubtype:e.target.value})}><option value="">Por indicar</option><option value="postal">Postal/filatélica</option><option value="scientific">Colecções/espécimes científicos3(6)c</option><option value="historical">Interesse histórico,arqueológico,paleontológico,etnográfico ou numismático</option></select></label>{row.collectionSubtype==='postal'&&<label>Fora decirculação esem destino aser posto emcirculação<select className="block rounded border p-2" value={row.postalNotCirculating} onChange={e=>change(row.id,{postalNotCirculating:e.target.value})}><option value="">Por esclarecer</option><option value="yes">Sim</option><option value="no">Não</option></select></label>}</>}
|
||
{row.category==='antique'&&<label>Idade emanos<input className="block rounded border p-2" value={row.ageYears} onChange={e=>change(row.id,{ageYears:e.target.value})}/></label>}
|
||
{row.treatment==='reseller_margin'&&<><label>Opção do revendedor<select className="block rounded border p-2" value={row.regimeChoice} onChange={e=>change(row.id,{regimeChoice:e.target.value})}><option value="">Por esclarecer</option><option value="margin">Regime da margem</option><option value="general">Regime geral — outra fórmula</option></select></label>{([['grossSale','Contraprestação total devida pelocliente,comIVA incluído'],['purchasePrice','Preço compra do mesmo bem'],['purchaseRef','Justificação/referência do preço compra']] as const).map(([field,label])=><label key={field}>{label}<input className="block rounded border p-2" value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}/></label>)}</>}
|
||
{row.treatment==='auction_margin'&&([['grossInvoice','Montante facturado ao comprador49(4)'],['hammerPrice','Preço de adjudicação'],['principalCommission','Comissão obtida/aobter do comitente'],['auctionRef','Contrato de comissão de venda emnome próprio eleilão'],['principalRef','Comitente e referência do líquido'],['ownVat','IVApróprio relativo àtransmissão,identificado'],['ownVatRef','Referência/composição do IVApróprio identificado']] as const).map(([field,label])=><label key={field}>{label}<input className="block rounded border p-2" value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}/></label>)}
|
||
</div>
|
||
<p>Os montantes ocultos de outro percurso são conservados esó entram na fórmula escolhida.Situação antiga35/42não activa margem automaticamente em2026;sem novo certificado/aprovador.</p>
|
||
<fieldset><legend>Condições da classificação eregime</legend>{[...secondhandConditions,...secondhandCategoryConditions(row.category),['regimeConfirmed','Condições47/48(1)ou49(1),papéis/contrato equadro temporal conferidos'],['compositionConfirmed','Composição monetária corresponde ao percurso:revenda comIVA no total,ou leilão comfacturado,líquidocomitente eIVApróprio separados,sem dupla subtracção']] .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 as ''|'yes'|'no'}})}><option value="">Por indicar</option><option value="yes">Sim</option><option value="no">Não</option></select></label>)}</fieldset>
|
||
</details>)}
|
||
{!!book.rows.length&&<button type="button" className="rounded bg-emerald-800 p-2 text-white" onClick={()=>{try{save(recordSecondhands(draft,book));}catch(cause){setError(String(cause));}}}>Classificar bens,calcular bases eguardar versão</button>}
|
||
{book.result&&<><p role="status">{secondhandCurrent(draft,book)?'Classificações/bases correspondentes às entradas guardadas.':'Entradas alteradas;resultados históricos conservados.'} {book.history?.length??0} versões anteriores.Sem compensar margens entrebens,calcular IVA ou dedução/campo11.</p><dl>{secondhandReportRows(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>;
|
||
}
|