Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 94 additions & 4 deletions src/Danfse/DanfseTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,12 @@ public function buildData(array $nfse): array
'numero_dps' => $this->val($infDps, 'nDPS') ?: '-',
'serie_dps' => $this->val($infDps, 'serie') ?: '-',
'emissao_dps' => $this->formatter->dateTime($this->val($infDps, 'dhEmi')),
'ambiente' => Ambiente::fromValue($this->val($infDps, 'tpAmb'))->value,
'ambiente' => Ambiente::fromValue($this->val($infDps, 'tpAmb'))->value,
'ambiente_gerador' => $this->val($infNfse, 'ambGer') ?: '-',
'municipio_emissao' => $this->val($infNfse, 'xLocEmi') ?: '-',
'emitente_nfse' => $this->emitterLabel($this->val($infDps, 'tpEmit')),
'situacao_nfse' => $this->statusLabel($this->val($infNfse, 'cStat')),
'finalidade_nfse' => $this->purposeLabel($this->val($infDps, 'IBSCBS', 'finNFSe')),

'emitente' => [
'nome' => $this->val($emit, 'xNome') ?: '-',
Expand Down Expand Up @@ -164,9 +169,12 @@ public function buildData(array $nfse): array
'tributacao_federal' => [
'irrf' => $this->currencyOrDash($this->val($tribFed, 'vRetIRRF')),
'cp' => $this->currencyOrDash($this->val($tribFed, 'vRetCP')),
'csll' => $this->currencyOrDash($this->val($tribFed, 'vRetCSLL')),
'contribuicoes_sociais' => $this->currencyOrDash($this->val($tribFed, 'vRetCSLL')),
'pis' => $this->currencyOrDash($this->val($tribFed, 'piscofins', 'vPis')),
'cofins' => $this->currencyOrDash($this->val($tribFed, 'piscofins', 'vCofins')),
'descricao_retencao' => $this->pisCofinsRetentionLabel(
$this->val($tribFed, 'piscofins', 'tpRetPisCofins'),
),
],

'totais' => [
Expand Down Expand Up @@ -194,20 +202,39 @@ public function buildData(array $nfse): array
'municipais' => $this->percentOrDash($this->val($totTrib, 'pTotTribMun')),
],

'ibs_cbs' => $ibsCbs === [] ? null : [
'ibs_cbs' => [
'cst_classificacao' => $this->joinedOrDash(
$this->val($infDps, 'IBSCBS', 'valores', 'trib', 'gIBSCBS', 'CST'),
$this->val($infDps, 'IBSCBS', 'valores', 'trib', 'gIBSCBS', 'cClassTrib'),
),
'indicador_operacao' => $this->val($infDps, 'IBSCBS', 'cIndOp') ?: '-',
'localidade_incidencia' => $this->val($ibsCbs, 'xLocalidadeIncid')
?: $this->val($ibsCbs, 'cLocalidadeIncid')
?: '-',
'exclusoes_reducoes' => $this->sumCurrency(
$this->val($infNfse, 'valores', 'vISSQN'),
$this->val($tribFed, 'piscofins', 'vPis'),
$this->val($tribFed, 'piscofins', 'vCofins'),
),
'base_calculo' => $this->currencyOrDash($this->val($ibsCbsValores, 'vBC')),
'aliquota_ibs_uf' => $this->percentOrDash($this->val($ibsCbsValores, 'uf', 'pIBSUF')),
'aliquota_ibs_municipal' => $this->percentOrDash($this->val($ibsCbsValores, 'mun', 'pIBSMun')),
'aliquota_cbs' => $this->percentOrDash($this->val($ibsCbsValores, 'fed', 'pCBS')),
'total_ibs' => $this->currencyOrDash($this->val($ibsCbsTotais, 'gIBS', 'vIBSTot')),
'total_cbs' => $this->currencyOrDash($this->val($ibsCbsTotais, 'gCBS', 'vCBS')),
'total_ibs_cbs' => $ibsCbs === [] ? '-' : $this->sumCurrency(
$this->val($ibsCbsTotais, 'gIBS', 'vIBSTot'),
$this->val($ibsCbsTotais, 'gCBS', 'vCBS'),
),
'valor_total_nfse' => $this->currencyOrDash($this->val($ibsCbsTotais, 'vTotNF')),
],

'informacoes_complementares' => $this->val($serv, 'infoCompl', 'xInfComp'),
'informacoes_complementares' => $this->complementaryInformation(
$this->val($serv, 'infoCompl', 'xInfComp'),
$this->percentOrDash($this->val($totTrib, 'pTotTribFed')),
$this->percentOrDash($this->val($totTrib, 'pTotTribEst')),
$this->percentOrDash($this->val($totTrib, 'pTotTribMun')),
),
];
}

Expand Down Expand Up @@ -318,6 +345,69 @@ private function sumCurrency(string ...$values): string
return $hasValue ? $this->formatter->currency((string) $total) : '-';
}

private function emitterLabel(string $value): string
{
return match ($value) {
'1' => 'Prestador',
'2' => 'Tomador',
'3' => 'Intermediário',
default => '-',
};
}

private function statusLabel(string $value): string
{
return $value === '100' ? 'NFS-e Gerada' : ($value !== '' ? $value : '-');
}

private function purposeLabel(string $value): string
{
return match ($value) {
'0' => 'NFS-e regular',
'1' => 'NFS-e de crédito',
'2' => 'NFS-e de débito',
default => '-',
};
}

private function pisCofinsRetentionLabel(string $value): string
{
return match ($value) {
'0' => '0 - PIS/COFINS/CSLL Não Retidos',
'1' => '1 - PIS/COFINS Retidos',
'2' => '2 - PIS/COFINS Não Retidos',
'3' => '3 - PIS/COFINS/CSLL Retidos',
'4' => '4 - PIS/COFINS Retidos, CSLL Não Retido',
'5' => '5 - PIS Retido, COFINS/CSLL Não Retido',
default => '-',
};
}

private function joinedOrDash(string ...$values): string
{
if (array_filter($values, static fn (string $value): bool => $value !== '') === []) {
return '-';
}

return implode(' / ', array_map(static fn (string $value): string => $value !== '' ? $value : '-', $values));
}

private function complementaryInformation(
string $existing,
string $federal,
string $state,
string $municipal,
): string {
$taxes = sprintf(
'Totais aproximados dos Tributos cfe. Lei n° 12.741/2012: Federais: %s; Estaduais: %s; Municipais: %s;',
$federal,
$state,
$municipal,
);

return trim($existing) === '' ? $taxes : trim($existing) . "\n" . $taxes;
}

private function generateQrCode(string $chaveAcesso, Ambiente $ambiente): string
{
$renderer = new ImageRenderer(
Expand Down
103 changes: 53 additions & 50 deletions src/Danfse/HTMLTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,24 +151,12 @@
<?php endif; ?>
</td>
<td class="municipality-cell">
<?php if ($municipality): ?>
<table>
<tr>
<?php if ($municipality->logoDataUri): ?>
<td><img style="height: 30pt; width: auto" src="<?= htmlspecialchars($municipality->logoDataUri) ?>" alt="Prefeitura" /></td>
<?php endif; ?>
<td style="font-size: 7pt;">
<?= htmlspecialchars($municipality->name) ?><br>
<?php if ($municipality->department): ?>
<?= htmlspecialchars($municipality->department) ?><br>
<?php endif; ?>
<?php if ($municipality->email): ?>
<?= htmlspecialchars($municipality->email) ?>
<?php endif; ?>
</td>
</tr>
</table>
<?php if ($municipality && $municipality->logoDataUri): ?>
<img style="height: 22pt; width: auto" src="<?= htmlspecialchars($municipality->logoDataUri) ?>" alt="Prefeitura" /><br>
<?php endif; ?>
Município: <?= $data['municipio_emissao'] ?><br>
Ambiente Gerador: <?= $data['ambiente_gerador'] ?><br>
Tipo de Ambiente: <?= $data['ambiente'] ?>
</td>
</tr>
</table>
Expand Down Expand Up @@ -219,6 +207,22 @@
</td>
</tr>
</table>
<table>
<tr>
<td style="width: 33.33%;">
<span class="label">Emitente da NFS-e</span>
<span class="value"><?= $data['emitente_nfse'] ?></span>
</td>
<td style="width: 33.33%;">
<span class="label">Situação da NFS-e</span>
<span class="value"><?= $data['situacao_nfse'] ?></span>
</td>
<td style="width: 33.33%;">
<span class="label">Finalidade</span>
<span class="value"><?= $data['finalidade_nfse'] ?></span>
</td>
</tr>
</table>
</div>

<!-- Emitente -->
Expand Down Expand Up @@ -479,26 +483,29 @@
<span class="value"><?= $data['tributacao_federal']['cp'] ?? '-' ?></span>
</td>
<td style="width: 25%;">
<span class="label">CSLL - Retida</span>
<span class="value"><?= $data['tributacao_federal']['csll'] ?? '-' ?></span>
<span class="label">Contribuições Sociais - Retidas</span>
<span class="value"><?= $data['tributacao_federal']['contribuicoes_sociais'] ?? '-' ?></span>
</td>
<td style="width: 25%;"></td>
</tr>
<tr>
<td colspan="2">
<td>
<span class="label">PIS - Débito Apuração Própria</span>
<span class="value"><?= $data['tributacao_federal']['pis'] ?? '-' ?></span>
</td>
<td colspan="2">
<td>
<span class="label">COFINS - Débito Apuração Própria</span>
<span class="value"><?= $data['tributacao_federal']['cofins'] ?? '-' ?></span>
</td>
<td colspan="2">
<span class="label">Descrição Contrib. Sociais - Retidas</span>
<span class="value"><?= $data['tributacao_federal']['descricao_retencao'] ?? '-' ?></span>
</td>
</tr>
</table>
</div>

<!-- Tributação IBS / CBS (NT 008 v1.02) -->
<?php if ($data['ibs_cbs'] !== null): ?>
<div class="bordered-section">
<table>
<tr>
Expand All @@ -507,10 +514,24 @@
</td>
</tr>
<tr>
<td style="width: 25%;">
<span class="label">CST / cClassTrib</span>
<span class="value"><?= $data['ibs_cbs']['cst_classificacao'] ?></span>
</td>
<td style="width: 25%;">
<span class="label">Indicador de Operação</span>
<span class="value"><?= $data['ibs_cbs']['indicador_operacao'] ?></span>
</td>
<td style="width: 25%;">
<span class="label">Localidade de Incidência</span>
<span class="value"><?= $data['ibs_cbs']['localidade_incidencia'] ?></span>
</td>
<td style="width: 25%;">
<span class="label">Exclusões e Reduções da Base de Cálculo</span>
<span class="value"><?= $data['ibs_cbs']['exclusoes_reducoes'] ?></span>
</td>
</tr>
<tr>
<td style="width: 25%;">
<span class="label">Base de Cálculo</span>
<span class="value"><?= $data['ibs_cbs']['base_calculo'] ?></span>
Expand All @@ -523,6 +544,10 @@
<span class="label">Alíquota IBS Município</span>
<span class="value"><?= $data['ibs_cbs']['aliquota_ibs_municipal'] ?></span>
</td>
<td style="width: 25%;">
<span class="label">Reduções de Alíquota IBS/CBS</span>
<span class="value">-</span>
</td>
</tr>
<tr>
<td>
Expand All @@ -544,7 +569,6 @@
</tr>
</table>
</div>
<?php endif; ?>

<!-- Valor Total -->
<div class="bordered-section">
Expand Down Expand Up @@ -577,38 +601,17 @@
<span class="label">Total das Retenções Federais</span>
<span class="value"><?= $data['totais']['retencoes_federais'] ?? '-' ?></span>
</td>
<td colspan="2">
<span class="label">PIS/COFINS - Débito Apur. Própria</span>
<span class="value"><?= $data['totais']['pis_cofins'] ?? '-' ?></span>
</td>
<td>
<span class="label">Valor Líquido da NFS-e</span>
<span class="value" style="font-weight: bold;"><?= $data['totais']['valor_liquido'] ?></span>
</td>
</tr>
</table>
</div>

<!-- Totais Aproximados de Tributos -->
<div class="bordered-section">
<table>
<tr>
<td colspan="3" class="section-header">
<span class="section-title">TOTAIS APROXIMADOS DOS TRIBUTOS</span>
</td>
</tr>
<tr>
<td style="width: 33.33%; text-align: center;">
<span class="label">Federais</span>
<span class="value"><?= $data['totais_tributos']['federais'] ?? '-' ?></span>
</td>
<td style="width: 33.33%; text-align: center;">
<span class="label">Estaduais</span>
<span class="value"><?= $data['totais_tributos']['estaduais'] ?? '-' ?></span>
<td>
<span class="label">Total do IBS/CBS</span>
<span class="value"><?= $data['ibs_cbs']['total_ibs_cbs'] ?></span>
</td>
<td style="width: 33.33%; text-align: center;">
<span class="label">Municipais</span>
<span class="value"><?= $data['totais_tributos']['municipais'] ?? '-' ?></span>
<td>
<span class="label">Valor Líquido da NFS-e + IBS/CBS</span>
<span class="value"><?= $data['ibs_cbs']['valor_total_nfse'] ?></span>
</td>
</tr>
</table>
Expand Down
6 changes: 6 additions & 0 deletions src/Dto/DpsData.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ public function __construct(
/** Descrição do serviço prestado. */
public string $discriminacao,

/** Optional provider phone published in the DPS. */
public string $prestadorTelefone = '',

/** Optional provider e-mail published in the DPS. */
public string $prestadorEmail = '',

/** Tipo de ambiente (1-Produção | 2-Homologação). */
public int $tipoAmbiente = 2,

Expand Down
9 changes: 9 additions & 0 deletions src/Xml/XmlBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,15 @@ public function buildDps(DpsData $dps): string
$prest = $doc->createElement('prest');
$cnpj = $doc->createElement('CNPJ', $dps->cnpjPrestador);
$prest->appendChild($cnpj);

if ($dps->prestadorTelefone !== '') {
$prest->appendChild($doc->createElement('fone', $dps->prestadorTelefone));
}

if ($dps->prestadorEmail !== '') {
$prest->appendChild($doc->createElement('email', htmlspecialchars($dps->prestadorEmail, ENT_XML1)));
}

$prest->appendChild($this->buildRegTrib($doc, $dps));
$infDps->appendChild($prest);

Expand Down
27 changes: 24 additions & 3 deletions tests/Unit/Danfse/DanfseGoldenReferenceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public function testIbsCbsReferenceRendersOnlyAuthorizedTotals(): void
self::assertStringContainsString('TRIBUTAÇÃO IBS / CBS', $html);
}

public function testLegacyAuthorizedXmlWithoutIbsCbsKeepsLegacyLayout(): void
public function testAuthorizedXmlWithoutIbsCbsStillRendersRequiredV2Section(): void
{
$nfse = $this->fixtureData();
unset($nfse['infNFSe']['IBSCBS']);
Expand All @@ -113,11 +113,32 @@ public function testLegacyAuthorizedXmlWithoutIbsCbsKeepsLegacyLayout(): void
$data = $template->buildData($nfse);
$html = $template->render($nfse, new DanfseConfig());

self::assertNull($data['ibs_cbs']);
self::assertStringNotContainsString('TRIBUTAÇÃO IBS / CBS', $html);
self::assertIsArray($data['ibs_cbs']);
self::assertSame('-', $data['ibs_cbs']['base_calculo']);
self::assertSame('-', $data['ibs_cbs']['total_ibs_cbs']);
self::assertStringContainsString('TRIBUTAÇÃO IBS / CBS', $html);
self::assertStringContainsString('DANFSe v2.0', $html);
}

public function testFederalRetentionUsesOfficialV2Semantics(): void
{
$nfse = $this->fixtureData();
$nfse['infNFSe']['DPS']['infDPS']['valores']['trib']['tribFed']['piscofins']['tpRetPisCofins'] = '4';
$nfse['infNFSe']['DPS']['infDPS']['valores']['trib']['tribFed']['vRetCSLL'] = '1149.75';

$template = new DanfseTemplate();
$data = $template->buildData($nfse);
$html = $template->render($nfse, new DanfseConfig());

self::assertSame('R$ 1.149,75', $data['tributacao_federal']['contribuicoes_sociais']);
self::assertSame(
'4 - PIS/COFINS Retidos, CSLL Não Retido',
$data['tributacao_federal']['descricao_retencao'],
);
self::assertStringContainsString('Contribuições Sociais - Retidas', $html);
self::assertStringContainsString('Descrição Contrib. Sociais - Retidas', $html);
}

public function testHomologationReferenceCarriesVisibleMarker(): void
{
$nfse = $this->fixtureData();
Expand Down
Loading
Loading