Files
Investidor-V2/resources/js/lib/iva-production-option.ts
T

37 lines
4.8 KiB
TypeScript

export type ProductionTaxOption = {mode:''|'annual'|'startup';declarationDate:string;startupDate:string;returnStatus:''|'none'|'declared';returnDeclarationDate:string;operationDate:string;origin?:{rowId:string;description:string;establishment:string}};
export const productionOptionVersion='production-option/2';
// Civil Code 279(c), read with 296: the term ends at 24:00 on this date.
// A missing anniversary day is clamped within the same month, never rolled to March.
export function productionMinimumTermEnd(effective:string):string {
const year=Number(effective.slice(0,4))+5,month=Number(effective.slice(5,7)),day=Number(effective.slice(8,10));
const leap=year%4===0&&(year%100!==0||year%400===0);
const lastDay=[31,leap?29:28,31,30,31,30,31,31,30,31,30,31][month-1];
return `${String(year).padStart(4,'0')}-${String(month).padStart(2,'0')}-${String(Math.min(day,lastDay)).padStart(2,'0')}`;
}
export const productionReturnEffective=(declarationDate:string):string=>String(Number(declarationDate.slice(0,4))+1).padStart(4,'0')+'-01-01';
export const emptyProductionTaxOption = ():ProductionTaxOption=>({mode:'',declarationDate:'',startupDate:'',returnStatus:'',returnDeclarationDate:'',operationDate:''});
export function productionOptionCheck(option:ProductionTaxOption|undefined,period:string):{error?:string;summary?:string} {
const valid=(value:unknown):value is string=>typeof value==='string'&&/^\d{4}-\d{2}-\d{2}$/.test(value)&&Number(value.slice(0,4))>=1&&Number.isFinite(new Date(value+'T00:00:00Z').valueOf())&&new Date(value+'T00:00:00Z').toISOString().slice(0,10)===value;
if(!option||!['annual','startup'].includes(option.mode)||!valid(option.declarationDate)||!valid(option.operationDate))return {error:'Indique o tipo/data da declaração de opção e a data da operação; não se presume renúncia eficaz.'};
if(option.operationDate.slice(0,7)!==period)return {error:'A data da operação deve pertencer ao período desta linha; não repartir montantes automaticamente.'};
let effective=String(Number(option.declarationDate.slice(0,4))+1).padStart(4,'0')+'-01-01';
if(option.mode==='startup'){
if(!valid(option.startupDate)||option.declarationDate>option.startupDate)return {error:'Na opção constante da declaração de início, indique a data de início e uma declaração que não lhe seja posterior.'};
effective=option.startupDate;
}
if(option.operationDate<effective)return {error:`Opção ainda sem efeitos nesta operação; início de efeitos ${effective}.`};
if(!['none','declared'].includes(option.returnStatus))return {error:'Indique expressamente se existe declaração de regresso à isenção; informação desconhecida não significa ausência de declaração.'};
if(option.returnStatus==='none'&&option.returnDeclarationDate)return {error:'Foi indicada ausência de declaração de regresso, mas existe uma data guardada; resolva a divergência explicitamente.'};
let end='';
if(option.returnStatus==='declared'){
if(!valid(option.returnDeclarationDate))return {error:'Data da declaração de regresso à isenção em falta ou inválida; não presumir uma data.'};
const anniversary=productionMinimumTermEnd(effective);
if(option.returnDeclarationDate<option.declarationDate)return {error:'A declaração de regresso antecede a declaração de opção; resolva a divergência do histórico.'};
if(option.returnDeclarationDate>anniversary)return {error:`A declaração de regresso indicada é posterior ao termo às 24 horas de ${anniversary}; o CIVA, art.11(3), exige entrega antes de expirar o prazo. Não presumir efeitos para esta declaração tardia.`};
end=productionReturnEffective(option.returnDeclarationDate);
if(end<=anniversary)return {error:`O regresso não pode produzir efeitos antes de terminado o prazo mínimo, às 24 horas de ${anniversary}.`};
if(option.operationDate>=end)return {error:`Opção já cessou na data desta operação; regresso à isenção com efeitos ${end}. Reveja o tratamento.`};
}
return {summary:`Art.11 (${productionOptionVersion}): declaração ${option.declarationDate} (${option.mode==='startup'?'opção no início da actividade':'opção anual'}); efeitos ${effective}; termo mínimo às 24 horas de ${productionMinimumTermEnd(effective)} (Código Civil, arts.279.º,c), e296.º); operação ${option.operationDate}; ${end?`declaração de regresso ${option.returnDeclarationDate}, efeitos ${end} (CIVA, art.11(3)); o termo do prazo não antecipa estes efeitos`:'ausência de declaração de regresso expressamente indicada; tributação continua, sem caducidade automática ao fim de cinco anos'}.${option.origin?` Opção reutilizada de ${option.origin.description} (${option.origin.rowId}), estabelecimento ${option.origin.establishment}; escolha confirmada nesta linha.`:''}`};
}