Prepare grouped L2 A B C with customs deduction exclusions and exact affected totals
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import type {Acquisition} from '@/lib/iva-acquisitions';
|
||||
import {acquisitionImportSources,expenseOptions,newAcquisitionBC,reuseAcquisitionImport,type AcquisitionBC} from '@/lib/iva-acquisition-bc';
|
||||
export function AcquisitionImportsExclusions({draft,row,onChange}:{draft:Record<string,unknown>;row:Acquisition;onChange:(patch:Partial<Acquisition>)=>void}){
|
||||
const b=row.bc;const update=(patch:Partial<AcquisitionBC>)=>onChange({bc:{...(b??newAcquisitionBC()),...patch}});
|
||||
const choice=(key:'reducedSupply'|'belongs'|'ownImportVat',label:string)=><label className="block">{label}<select value={b?.[key]??''} onChange={e=>update({[key]:e.target.value})}><option value="">Por indicar</option><option value="yes">Sim</option><option value="no">Não</option></select></label>;
|
||||
const fact=(key:string,label:string)=><label className="block" key={key}>{label}<select value={b?.facts[key]??''} onChange={e=>update({facts:{...b?.facts,[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>;
|
||||
if(!b)return <div><button type="button" onClick={()=>onChange({bc:newAcquisitionBC()})}>Analisar exclusões e excepções desta aquisição — C</button><button type="button" onClick={()=>onChange({bc:newAcquisitionBC(),field:'11',domestic:'no',documentType:'customs'})}>Preparar importação — B/campo11 (conserva valores e documento)</button></div>;
|
||||
const imported=row.domestic==='no';const sources=acquisitionImportSources(draft);
|
||||
return <fieldset className="space-y-2 rounded border p-3"><legend>Importações e exclusões — B/C</legend>
|
||||
<p>Dados existentes conservados;as respostas são factos declarados ou pressupostos de projecção. Informação em falta fica indeterminada. Alterar a natureza da despesa conserva respostas anteriores sem as aplicar a outro tratamento.</p>
|
||||
{imported&&<><p>Campo11:IVA devido na importação de bens pelo documento aduaneiro. Não calcula direitosL13,não copia o valor aduaneiro como IVA e não exige fornecedor estrangeiro inscrito no IVA interno.</p>
|
||||
<label className="block">Reutilizar registo de importação existente<select value="" onChange={e=>{const source=sources.find(s=>s.map+'/'+s.row.id===e.target.value);if(source)onChange(reuseAcquisitionImport(draft,row,source.map,source.row.id));}}><option value="">Escolher correspondência;apenas preenche dados vazios</option>{sources.map(s=><option key={s.map+'/'+s.row.id} value={s.map+'/'+s.row.id}>{s.label}</option>)}</select></label>
|
||||
{b.source&&<p>Origem conservada:{b.source.map}/{b.source.id}. Reutilizar novamente adopta a origem actual,sem substituir edições.</p>}
|
||||
{(['importer','goodsRef','vatRef'] as const).map((key,i)=><label className="block" key={key}>{['Importador identificado','Bens/operação/linha abrangidos','Fonte do montante de IVA devido — bilhete/pressuposto'][i]}<input value={b[key]} onChange={e=>update({[key]:e.target.value})}/></label>)}
|
||||
{choice('belongs','Bilhete na titularidade do sujeito passivo/importador desta aquisição')}
|
||||
{fact('exigibleInPeriod','IVA aduaneiro tornou-se exigível no período de dedução indicado,conforme a fonte/documento21(1);não basta a data de emissão do bilhete')}
|
||||
{choice('ownImportVat','Montante é apenas IVA próprio devido nesta importação,sem somar novamente IVA de serviço incluído na base dos bens')}
|
||||
<label className="block">Situação do IVA da importação<select value={b.vatBasis} onChange={e=>update({vatBasis:e.target.value as AcquisitionBC['vatBasis']})}><option value="">Por identificar</option><option value="due">IVA devido identificado no documento/pressuposto</option><option value="exempt">Importação isenta — IVAzero expressamente indicado</option><option value="zero">Montantezero expresso,com fundamento</option><option value="unknown">Montante desconhecido</option></select></label>
|
||||
<p>IVA isento/zero não é montante desconhecido. Para ausência de imposto a deduzir,indique zero expressamente no IVA;isençãoL1 não preenche esse montante.</p></>}
|
||||
{!imported&&choice('reducedSupply','O IVA suportado respeita a fornecimento abrangido pelo artigo17-A (20(2))')}
|
||||
<label className="block">Natureza da despesa para dedução<select value={b.expense} onChange={e=>update({expense:e.target.value})}><option value="">Por identificar</option>{expenseOptions.map(([v,l])=><option key={v} value={v}>{l}</option>)}</select></label>
|
||||
{b.expense==='vehicle'&&<>{fact('tourism','Bem abrangido20(1)(a):viatura de turismo,barco de recreio,helicóptero,avião,moto/motociclo. Viatura:inclui reboque;não destinada unicamente a mercadorias/uso agrícola,comercial ou industrial,ou mista/passageiros até9lugares incluindo condutor')}{b.facts.tourism==='yes'&&fact('saleOrExploit','Venda ou exploração deste bem constitui objecto da actividade20(3)(a)')}</>}
|
||||
{b.expense==='fuel'&&<>{fact('resale','Combustível adquirido para revenda,com actividade e destino identificados20(3)(a)')}{b.facts.resale==='no'&&<><label>Combustível<select value={b.fuelKind} onChange={e=>update({fuelKind:e.target.value as AcquisitionBC['fuelKind']})}><option value="">Por identificar</option><option value="diesel">Gasóleo</option><option value="other">Outro combustível normalmente utilizável em viaturas</option></select></label>{b.fuelKind==='diesel'&&<><label>Utilização do gasóleo<select value={b.dieselUse} onChange={e=>update({dieselUse:e.target.value as AcquisitionBC['dieselUse']})}><option value="">Por identificar</option><option value="heavy_passengers">Veículo pesado de passageiros</option><option value="public_passengers">Veículo licenciado para transporte público de passageiros,excepto rent a car</option><option value="machine">Máquina consumidora de gasóleo que não é veículo matriculado</option><option value="agriculture">Tractor com emprego exclusivo/predominante em operações inerentes à actividade agrícola</option><option value="other">Outro uso — dedução50%</option></select></label>{b.dieselUse&&b.dieselUse!=='other'&&fact('dieselScope','O uso e as características correspondem integralmente à categoria20(1)(b)(i–iv) seleccionada')}</>}</>}</>}
|
||||
{b.expense==='lodging_food'&&fact('commercialTraveller','Alojamento/alimentação de viajante comercial,agindo por conta própria,no quadro da actividade profissional20(3)(b)')}
|
||||
{b.expense==='telephone'&&fact('ownLandline','Serviço de telefone fixo em nome do sujeito passivo20(1)(e)')}
|
||||
{b.expense==='beverages'&&<>{fact('beverageSpecial','Bebidas de abastecimento de bordo nas alíneas13(1)(c/d/h),com origemL1 identificada;tabaco e recepção não estão abrangidos por esta excepção')}{b.facts.beverageSpecial==='yes'&&<><label>Via13(2) para esta parcela<select value={b.beveragePath} onChange={e=>update({beveragePath:e.target.value as AcquisitionBC['beveragePath']})}><option value="">Por escolher</option><option value="deduction">Dedução nesta aquisição — L2</option><option value="refund">Restituição — percursoL3,sem apuramento aqui</option></select></label>{fact('onlyDeduction','Parcela identificada exclusivamente para dedução;sem pedido/restituição da mesma parcela')}{fact('notCoastalFishing','Se origem13(1)(d):embarcação de salvamento/assistência marítima,sem ser pesca costeira cujas provisões ficam excluídas')}</>}</>}
|
||||
<label className="block">Factos e referência documental da classificação/excepção<input value={b.evidence} onChange={e=>update({evidence:e.target.value})}/></label>
|
||||
</fieldset>;
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import {acquisitionOperationChoices,createAcquisitionRightLink,linkedOperationRight,type AcquisitionRightLink} from '@/lib/iva-acquisition-right';
|
||||
import {acquisitionOperationChoices,createAcquisitionRightLink,linkedOperationRight,linkedBeverageDeductionRight,type AcquisitionRightLink} from '@/lib/iva-acquisition-right';
|
||||
import type {Acquisition} from '@/lib/iva-acquisitions';
|
||||
|
||||
export function AcquisitionOperationLink({draft,row,onChange}:{draft:Record<string,unknown>;row:Acquisition;onChange:(patch:Partial<Acquisition>)=>void}){
|
||||
const choices=acquisitionOperationChoices(draft),link=row.deductionLink;
|
||||
const adopt=(id:string)=>onChange({deductionLink:createAcquisitionRightLink(draft,id)});
|
||||
const patch=(value:Partial<AcquisitionRightLink>)=>{if(link)onChange({deductionLink:{...link,...value}});};
|
||||
const result=link?linkedOperationRight(draft,link):null;
|
||||
const result=link?(row.bc?.expense==='beverages'&&row.bc.facts.beverageSpecial==='yes'&&row.bc.beveragePath==='deduction'?linkedBeverageDeductionRight(draft,link,row.bc.facts.notCoastalFishing==='yes'):linkedOperationRight(draft,link)):null;
|
||||
return <fieldset className="space-y-2 rounded border p-3"><legend>Aquisição → direito à dedução — L2-A</legend>
|
||||
<p>Reutilize a classificação existente. A ligação conserva montantes, documento e escolhas da aquisição; não cria outra compra. Importações, despesas especiais e afectação parcial conservam enquadramento próprio.</p>
|
||||
{choices.length===1&&!link?<button type="button" onClick={()=>adopt(choices[0].id)}>Reutilizar operação existente: {choices[0].label}</button>:<label>Operação de destino<select value={link?.operationId??''} onChange={e=>e.target.value?adopt(e.target.value):onChange({deductionLink:undefined})}><option value="">Sem vínculo L2-A</option>{choices.map(c=><option key={c.id} value={c.id}>{c.label}</option>)}</select></label>}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { AcquisitionOperationLink } from './acquisition-operation-link';
|
||||
import { AcquisitionImportsExclusions } from './acquisition-imports-exclusions';
|
||||
import { acquisitionRightVersion } from '@/lib/iva-acquisition-right';
|
||||
import { acquisitionBook, acquisitionCurrent, acquisitionExcludedFields, acquisitionPlanReferences, acquisitionReportRows, recordAcquisitions, newAcquisition, reuseAcquisitions, saveAcquisitionBook, type Acquisition, type AcquisitionBook } from '@/lib/iva-acquisitions';
|
||||
import { acquisitionTreatmentIssue, continueWithoutFormerExploration, formerExplorationSource, type AcquisitionTreatment } from '@/lib/iva-acquisition-continuity';
|
||||
@@ -22,7 +23,7 @@ export function SimulationAcquisitions({draft,onChange}:{draft:Record<string,unk
|
||||
<p>Oportunidade em tratamento: {String(draft.context_opportunity||'entrada geral')}. Moeda de origem: {book.currency||'por indicar'}. A compra registada não gera automaticamente IVA dedutível.</p>
|
||||
{book.currency && draft.currency!==book.currency && <p role="alert">As compras conservam {book.currency}; o projecto está em {String(draft.currency||'moeda por indicar')}. Reveja a moeda no projecto. Os montantes e o resultado anterior não foram convertidos ou reinterpretados.</p>}
|
||||
{!book.currency && !!draft.currency && <button type="button" className="underline" onClick={()=>save({...book,currency:String(draft.currency),rows:book.rows.map(row=>row.sourceCurrency?row:{...row,sourceCurrency:String(draft.currency)})})}>Confirmar explicitamente {String(draft.currency)} como moeda de origem dos valores sem moeda, conservando os montantes</button>}
|
||||
<p>L2-A: aquisições internas em MZN e afectação exclusiva a uma operação classificada, com direito, sem direito ou indeterminado. Documento e dedução no mesmo período de2026; importações, exclusões especiais, afectação parcial e regularizações conservam percursos próprios. Nas projecções, cada confirmação é um pressuposto. Indique dois valores entre líquido, IVA e bruto; o terceiro é obtido sem taxa de compra presumida.</p>
|
||||
<p>Aquisições em MZN/2026,ligadas à operação de destino:com direito,sem direito ou indeterminadas. A/B/C distinguem compras internas,importações de bens e exclusões/excepções. Documento e dedução no mesmo mês;afectação mista,proporções18(6),dedução posterior e regularizações conservam percursos próprios. Nas projecções,cada confirmação é um pressuposto. Compras internas:indique dois valores entre líquido,IVA e bruto. Importações:IVA expressamente identificado no bilhete;custos líquido/bruto são opcionais,sem calcular direitos ou presumir taxa.</p>
|
||||
<label className="block">Adquirente sujeito passivo de IVA no regime normal (efectivo ou pressuposto da projecção)<select className="block rounded border p-2" value={book.taxpayerRegistered??''} onChange={e=>save({...book,taxpayerRegistered:e.target.value as AcquisitionBook['taxpayerRegistered']})}><option value="">Por confirmar</option><option value="yes">Sim</option><option value="no">Não / outro enquadramento — fora deste lote</option></select></label>
|
||||
{error&&<p role="alert">{error}</p>}
|
||||
<details className="rounded border p-2"><summary>Indicar mês da aquisição pelo documento ou pressuposto da projecção</summary>
|
||||
@@ -34,6 +35,7 @@ export function SimulationAcquisitions({draft,onChange}:{draft:Record<string,unk
|
||||
<button type="button" className="ml-3 underline" disabled={!book.periods.length} onClick={()=>save({...book,rightVersion:acquisitionRightVersion,rows:[...book.rows,newAcquisition(crypto.randomUUID(),book.periods[0]?.period??'',book.currency)]})}>Acrescentar aquisição em falta</button>
|
||||
{book.rows.map(row=><details key={row.id} className="rounded border p-3"><summary>{row.description||'Aquisição adicional'} — {row.period} — campo{row.field}</summary>
|
||||
<AcquisitionOperationLink draft={draft} row={row} onChange={patch=>change(row.id,patch)}/>
|
||||
<AcquisitionImportsExclusions draft={draft} row={row} onChange={patch=>change(row.id,patch)}/>
|
||||
<details className="rounded border p-2"><summary>Enquadramento especial da aquisição / referência anterior</summary>
|
||||
<label>Tratamento da aquisição<select value={row.acquisitionTreatment??''} onChange={e=>row.acquisitionTreatment==='former_exploration_exemption'&&e.target.value!=='former_exploration_exemption'?run(()=>save({...book,rows:book.rows.map(item=>item.id===row.id?continueWithoutFormerExploration(item):item)})):change(row.id,{acquisitionTreatment:e.target.value as AcquisitionTreatment})}><option value="">Enquadramento normal; sem benefício especial indicado</option><option value="former_exploration_exemption">Antiga isenção de prospecção/pesquisa —14(2)(c),eliminada</option><option value="normal">Continuidade pelo enquadramento normal</option></select></label>
|
||||
{acquisitionTreatmentIssue(row.acquisitionTreatment)&&<p role="status">{acquisitionTreatmentIssue(row.acquisitionTreatment)}</p>}
|
||||
@@ -44,19 +46,19 @@ export function SimulationAcquisitions({draft,onChange}:{draft:Record<string,unk
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<label>Descrição<input className="block rounded border p-2" value={row.description} onChange={e=>change(row.id,{description:e.target.value})}/></label>
|
||||
{row.sourceMonth===null && <label>Reutilizar valor existente, sem presumir que o orçamento é uma factura<select className="block rounded border p-2" value="" onChange={e=>run(()=>{const ref=references.find(r=>r.key===e.target.value);if(ref)change(row.id,{sourceMonth:ref.month,sourcePeriod:ref.period,sourceField:ref.kind,sourceAmount:ref.amount,sourceCurrency:ref.currency,...(ref.kind==='asset'?{}:{period:ref.period})});})}><option value="">Escolher apenas se corresponde a esta aquisição</option>{references.filter(ref=>ref.kind===(row.field==='08'?'asset':row.field==='10'?'operating':'inventory')).map(ref=><option key={ref.key} value={ref.key}>{ref.label}: {ref.amount??'sem informação'} {ref.currency}</option>)}</select></label>}
|
||||
{select(row,'field','Categoria',[['08','08 — Imobilizado'],['09','09 — Existências'],['10','10 — Outros bens e serviços']])}
|
||||
{select(row,'field','Categoria',[['08','08 — Imobilizado'],['09','09 — Existências'],['10','10 — Outros bens e serviços'],...(row.bc?[['11','11 — Importações de bens'] as [string,string]]:[])])}
|
||||
{select(row,'origin','Natureza dos dados',[['projected','Projectados / pressupostos'],['effective','Efectivos declarados']])}
|
||||
<label>Período de dedução<input className="block rounded border p-2" type="month" value={row.period} onChange={e=>change(row.id,{period:e.target.value})}/></label>
|
||||
{row.sourceMonth!==null && <label>O valor de origem corresponde a<select className="block rounded border p-2" value={row.sourceBasis} onChange={e=>{const basis=e.target.value as Acquisition['sourceBasis'];change(row.id,{sourceBasis:basis,...(basis==='net'&&!row.net?{net:row.sourceAmount??''}:basis==='gross'&&!row.gross?{gross:row.sourceAmount??''}:{})});}}><option value="">Por classificar</option><option value="net">Valor sem IVA</option><option value="gross">Valor com IVA</option></select></label>}
|
||||
{(['net','vat','gross'] as const).map((field,index)=><label key={field}>{['Valor líquido','IVA indicado','Valor bruto'][index]} ({row.sourceCurrency})<input className="block rounded border p-2" inputMode="decimal" value={row[field]} onChange={e=>change(row.id,{[field]:e.target.value})}/></label>)}
|
||||
{select(row,'documentType','Tipo de documento',[['invoice','Factura'],['equivalent','Documento equivalente']])}
|
||||
{select(row,'documentType','Tipo de documento',row.domestic==='no'&&row.bc?[['customs','Bilhete de despacho de importação']]:[['invoice','Factura'],['equivalent','Documento equivalente']])}
|
||||
<label>Referência do documento / previsão<input className="block rounded border p-2" value={row.documentRef} onChange={e=>change(row.id,{documentRef:e.target.value})}/></label>
|
||||
<label>Linha do documento, se discriminado em várias aquisições<input className="block rounded border p-2" value={row.documentLine} onChange={e=>change(row.id,{documentLine:e.target.value})}/></label>
|
||||
<label>Data do documento / prevista<input className="block rounded border p-2" type="date" value={row.documentDate} onChange={e=>change(row.id,{documentDate:e.target.value})}/></label>
|
||||
<label>Fornecedor / previsto<input className="block rounded border p-2" value={row.supplier} onChange={e=>change(row.id,{supplier:e.target.value})}/></label>
|
||||
{!(row.bc&&row.domestic==='no')&&<label>Fornecedor / previsto<input className="block rounded border p-2" value={row.supplier} onChange={e=>change(row.id,{supplier:e.target.value})}/></label>}
|
||||
{select(row,'domestic','Aquisição interna',yesNo)}
|
||||
{row.acquisitionTreatment!=='former_exploration_exemption'&&<>
|
||||
{select(row,'supplierRegistered','Fornecedor inscrito no IVA',yesNo)}
|
||||
{!(row.bc&&row.domestic==='no')&&select(row,'supplierRegistered','Fornecedor inscrito no IVA',yesNo)}
|
||||
{select(row,'legalDocument','Documento emitido em forma legal',yesNo)}
|
||||
{select(row,'held','Documento na posse do adquirente / previsto na projecção',yesNo)}
|
||||
{select(row,'allocation','Afectação',[['taxable_only',row.deductionLink?'Exclusiva à operação ligada':'Exclusiva a operações tributadas'],['mixed','Mista / parcial — fora deste lote'],['no_right','Operações sem direito à dedução']])}
|
||||
@@ -64,11 +66,12 @@ export function SimulationAcquisitions({draft,onChange}:{draft:Record<string,unk
|
||||
{select(row,'integrity','Operação real / pressuposto regular, sem simulação, margem de segunda mão ou impedimentos do art.18(3–5)',yesNo)}
|
||||
</>}
|
||||
</div>
|
||||
<p>Fundamento: CIVA arts.18–21, fontes e versão no resultado. Não se calcula dedução parcial, excepção de despesa ou dedução posterior neste lote.</p>
|
||||
<p>Fundamento:CIVA18–21,fontes e versão no resultado. {row.bc?'Aplicam-se apenas as exclusões/excepções documentadas escolhidas;gasóleo50% conserva fracção exacta. Sem pro rata,proporções18(6) ou regularização neste incremento.':'Afectação parcial,despesa especial e dedução posterior exigem percurso próprio;use a análiseC quando aplicável.'}</p>
|
||||
{row.sourceMonth===null && <button type="button" className="mr-3 underline" onClick={()=>save({...book,rows:book.rows.filter(r=>r.id!==row.id)})}>Remover esta aquisição introduzida directamente</button>}
|
||||
{row.sourceMonth!==null && <button type="button" className="underline" onClick={()=>run(()=>{const ref=acquisitionPlanReferences(draft).find(r=>r.month===row.sourceMonth && r.kind===(row.sourceField??'inventory'));if(!ref)throw new Error('Origem não disponível; conserve o registo e reveja o plano.');if(draft.currency!==row.sourceCurrency)throw new Error('Moeda divergente; não adoptar montantes de outra moeda.');change(row.id,{sourceAmount:ref.amount,sourcePeriod:ref.period,...(row.sourceBasis==='net'?{net:ref.amount??'',gross:''}:row.sourceBasis==='gross'?{gross:ref.amount??'',net:''}:{})});})}>Adoptar explicitamente o valor actual do plano (conserva histórico)</button>}
|
||||
</details>)}
|
||||
{book.periods.map(period=><details key={period.period} className="rounded border p-3"><summary>{period.period} — cobertura das parcelas — {period.complete && period.absent.length===acquisitionExcludedFields.length?'confirmada':'por completar'}</summary>
|
||||
{book.rows.some(r=>r.bc)&&<label className="block"><input type="checkbox" checked={period.importsComplete??false} onChange={e=>save({...book,periods:book.periods.map(p=>p.period===period.period?{...p,importsComplete:e.target.checked}:p)})}/> Incluí todas as importações de bens/campo11 deste período,mesmo isentas ou sem direito;sem somar novamente IVA de serviços incluídos na base.</label>}
|
||||
<label className="block"><input type="checkbox" checked={period.complete} onChange={e=>save({...book,periods:book.periods.map(p=>p.period===period.period?{...p,complete:e.target.checked}:p)})}/> Incluí todas as aquisições08–10 deste período, incluindo as sem direito à dedução; uma lista vazia significa que não houve essas aquisições.</label>
|
||||
<p>Campos fora deste lote: assinale apenas quando não existiram as respectivas operações. Uma parcela não assinalada permanece indeterminada.</p>
|
||||
{acquisitionExcludedFields.map(field=><label className="block" key={field}><input type="checkbox" checked={period.absent.includes(field)} onChange={e=>save({...book,periods:book.periods.map(p=>p.period===period.period?{...p,absent:e.target.checked?[...p.absent,field]:p.absent.filter(f=>f!==field)}:p)})}/> Sem operações no campo{field} — {labels[field]}</label>)}
|
||||
|
||||
Reference in New Issue
Block a user