import { Injectable } from '@nestjs/common';
import { DatabaseService } from '../../../infrastructure/database/database.service';
import { DomainConflictError } from '../../../common/errors/domain-conflict.error';
@Injectable()
export class FiscalPayloadService {
constructor(private readonly database:DatabaseService) {}
async forCheck(input:{organizationId:string;locationId:string;checkId:string;transactionType:string}) {
const check=await this.database.query<any>(
`select id,gross_total_minor,tax_total_minor,currency_code
from checks where id=$1 and organization_id=$2 and location_id=$3`,
[input.checkId,input.organizationId,input.locationId],
);
if(!check[0]) throw new DomainConflictError('fiscal.check_not_found');
const tax=await this.database.query<any>(
`select tax_rate_basis_points,
sum(gross_minor)::bigint as gross_minor,
sum(tax_minor)::bigint as tax_minor
from check_items
where check_id=$1 and status<>'voided'
group by tax_rate_basis_points
order by tax_rate_basis_points`,
[input.checkId],
);
const payments=await this.database.query<any>(
`select t.tender_type,sum(p.amount_minor)::bigint as amount_minor
from payments p
join tenders t on t.id=p.tender_id
where p.check_id=$1 and p.status in ('captured','refunded')
group by t.tender_type`,
[input.checkId],
);
const toDecimal=(minor:any)=>{
const n=BigInt(minor??0);
const sign=n<0n?'-':'';
const abs=n<0n?-n:n;
return `${sign}${abs/100n}.${String(abs%100n).padStart(2,'0')}`;
};
const vatRate=(bp:number)=>{
if(bp===1900) return 'NORMAL';
if(bp===700) return 'REDUCED_1';
if(bp===0) return 'NULL';
throw new DomainConflictError('fiscal.tax_rate_mapping_missing',{basisPoints:bp});
};
const paymentType=(t:string)=>{
if(t==='cash') return 'CASH';
if(t==='card') return 'NON_CASH';
return 'NON_CASH';
};
return {
transactionType:input.transactionType,
currencyCode:check[0].currency_code,
grossTotalMinor:String(check[0].gross_total_minor),
amountsPerVatRate:tax.map((x:any)=>({
vatRate:vatRate(Number(x.tax_rate_basis_points)),
amountDecimal:toDecimal(x.gross_minor),
sourceTaxRateBasisPoints:Number(x.tax_rate_basis_points),
})),
amountsPerPaymentType:payments.map((x:any)=>({
paymentType:paymentType(x.tender_type),
amountDecimal:toDecimal(x.amount_minor),
})),
};
}
}
