19 lines
3.2 KiB
PHP
19 lines
3.2 KiB
PHP
<?php
|
|
namespace App\Modules\Services;
|
|
use Brick\Math\{BigRational,RoundingMode};
|
|
/** Approved QA representation policy. No classification, issuance or financial effects. */
|
|
final class FiscalDocumentMath
|
|
{
|
|
public const POLICY='SGF-QA-LINE-TRUNCATE2-INCLUDED-RESIDUAL-v1';
|
|
public static function calculate(array $lines,string $mode,string $rate):array
|
|
{
|
|
if(!in_array($mode,['net_added','gross_included'],true)||BigRational::of($rate)->isLessThanOrEqualTo(0)||BigRational::of($rate)->isGreaterThanOrEqualTo(1))throw new \InvalidArgumentException('Modalidade/taxa artificial inválida.');$baseSum=BigRational::of(0);$taxSum=BigRational::of(0);$totalSum=BigRational::of(0);$exactBaseSum=BigRational::of(0);$exactTaxSum=BigRational::of(0);$rows=[];$pending=[];$r=BigRational::of($rate);
|
|
foreach($lines as$i=>$line){$amount=BigRational::of($line['quantity'])->multipliedBy($line['unit_price']);$base=$mode==='net_added'?$amount:$amount->dividedBy(BigRational::of(1)->plus($r));$tax=$mode==='net_added'?$base->multipliedBy($r):$amount->minus($base);$taxDoc=$tax->toScale(2,RoundingMode::Down);$taxDocR=BigRational::of((string)$taxDoc);$baseDoc=null;$total=null;
|
|
try{if($mode==='net_added'){$baseDoc=$base->toScale(2,RoundingMode::Unnecessary);$total=$base->plus($taxDocR)->toScale(2,RoundingMode::Unnecessary);}else{$gross=$amount->toScale(2,RoundingMode::Unnecessary);$baseDoc=BigRational::of((string)$gross)->minus($taxDocR)->toScale(2);$total=$gross;}}catch(\Brick\Math\Exception\RoundingNecessaryException){$pending[]='Linha '.($i+1).': '.($mode==='net_added'?'base':'bruto').' não representável em duas casas; não truncado.';}
|
|
$rows[]=['line'=>($i+1),'reference'=>$line['reference'],'quantity'=>$line['quantity'],'unit_price'=>$line['unit_price'],'amount_exact_fraction'=>(string)$amount->simplified(),'base_exact_fraction'=>(string)$base->simplified(),'tax_exact_fraction'=>(string)$tax->simplified(),'base_document'=>$baseDoc===null?null:(string)$baseDoc,'tax_document'=>(string)$taxDoc,'total_document'=>$total===null?null:(string)$total,'base_difference_fraction'=>$baseDoc===null?null:(string)BigRational::of((string)$baseDoc)->minus($base)->simplified(),'tax_difference_fraction'=>(string)$tax->minus($taxDocR)->simplified()];
|
|
$exactBaseSum=$exactBaseSum->plus($base);$exactTaxSum=$exactTaxSum->plus($tax);if($baseDoc!==null){$baseSum=$baseSum->plus(BigRational::of((string)$baseDoc));$taxSum=$taxSum->plus($taxDocR);$totalSum=$totalSum->plus(BigRational::of((string)$total));}
|
|
}
|
|
return ['state'=>$pending?'pending_representation':'determined_qa','policy'=>self::POLICY,'price_mode'=>$mode,'rate'=>$rate,'lines'=>$rows,'base_exact_fraction'=>(string)$exactBaseSum->simplified(),'tax_exact_fraction'=>(string)$exactTaxSum->simplified(),'base_document'=>$pending?null:(string)$baseSum->toScale(2),'tax_document'=>$pending?null:(string)$taxSum->toScale(2),'total'=>$pending?null:(string)$totalSum->toScale(2),'base_difference_fraction'=>$pending?null:(string)$baseSum->minus($exactBaseSum)->simplified(),'tax_difference_fraction'=>$pending?null:(string)$exactTaxSum->minus($taxSum)->simplified(),'aggregation'=>'sum_document_lines','pending'=>$pending,'synthetic_only'=>true,'legal_use'=>false,'financial_effects'=>0];
|
|
}
|
|
}
|