@@ -17,6 +17,7 @@ class XmlBuilder
1717{
1818 private const XSD_NAMESPACE = 'http://www.sped.fazenda.gov.br/nfse ' ;
1919 private const XSD_SCHEMA = 'http://www.sped.fazenda.gov.br/nfse tiDPS_v1.00.xsd ' ;
20+ private const DPS_VERSION = '1.01 ' ;
2021
2122 public function buildDps (DpsData $ dps ): string
2223 {
@@ -25,29 +26,32 @@ public function buildDps(DpsData $dps): string
2526 $ doc ->formatOutput = true ;
2627
2728 $ root = $ doc ->createElementNS (self ::XSD_NAMESPACE , 'DPS ' );
29+ $ root ->setAttribute ('versao ' , self ::DPS_VERSION );
2830 $ root ->setAttribute ('xsi:schemaLocation ' , self ::XSD_SCHEMA );
2931 $ root ->setAttribute ('xmlns:xsi ' , 'http://www.w3.org/2001/XMLSchema-instance ' );
3032 $ doc ->appendChild ($ root );
3133
3234 $ infDps = $ doc ->createElement ('infDPS ' );
33- $ infDps ->setAttribute ('Id ' , ' DPS ' . $ dps -> cnpjPrestador . date ( ' YmdHis ' ));
35+ $ infDps ->setAttribute ('Id ' , $ this -> buildIdentifier ( $ dps ));
3436 $ root ->appendChild ($ infDps );
3537
3638 // Municipality
3739 $ cMun = $ doc ->createElement ('cMun ' , $ dps ->municipioIbge );
3840 $ infDps ->appendChild ($ cMun );
41+ $ infDps ->appendChild ($ doc ->createElement ('cLocEmi ' , $ dps ->municipioIbge ));
3942
4043 // Prestador
4144 $ prest = $ doc ->createElement ('prest ' );
4245 $ cnpj = $ doc ->createElement ('CNPJ ' , $ dps ->cnpjPrestador );
4346 $ prest ->appendChild ($ cnpj );
47+ $ prest ->appendChild ($ this ->buildRegTrib ($ doc , $ dps ));
4448 $ infDps ->appendChild ($ prest );
4549
4650 // Service block
4751 $ serv = $ doc ->createElement ('serv ' );
4852
4953 $ itemListaServico = $ doc ->createElement ('cServ ' );
50- $ itemListaServico ->appendChild ($ doc ->createElement ('cTribNac ' , $ dps ->itemListaServico ));
54+ $ itemListaServico ->appendChild ($ doc ->createElement ('cTribNac ' , $ dps ->codigoTributacaoNacional ));
5155 $ serv ->appendChild ($ itemListaServico );
5256
5357 $ serv ->appendChild ($ doc ->createElement ('xDescServ ' , htmlspecialchars ($ dps ->discriminacao , ENT_XML1 )));
@@ -60,25 +64,55 @@ public function buildDps(DpsData $dps): string
6064
6165 // Values
6266 $ valores = $ doc ->createElement ('valores ' );
63- $ valores ->appendChild ($ doc ->createElement ('vServ ' , $ dps ->valorServico ));
64- $ valores ->appendChild ($ this ->buildTrib ($ doc , $ dps ));
67+
68+ $ vServPrest = $ doc ->createElement ('vServPrest ' );
69+ $ vServPrest ->appendChild ($ doc ->createElement ('vServ ' , $ dps ->valorServico ));
70+ $ valores ->appendChild ($ vServPrest );
71+
72+ $ valores ->appendChild ($ this ->buildTotTrib ($ doc , $ dps ));
6573 $ infDps ->appendChild ($ valores );
6674
67- // Regime especial de tributação (optional)
68- if ($ dps ->regimeEspecialTributacao !== null ) {
69- $ infDps ->appendChild ($ doc ->createElement ('regEspTrib ' , (string ) $ dps ->regimeEspecialTributacao ));
75+ return $ doc ->saveXML () ?: '' ;
76+ }
77+
78+ private function buildIdentifier (DpsData $ dps ): string
79+ {
80+ return 'DPS '
81+ . $ dps ->municipioIbge
82+ . $ dps ->tipoAmbiente
83+ . $ dps ->cnpjPrestador
84+ . str_pad ($ dps ->serie , 5 , '0 ' , STR_PAD_LEFT )
85+ . str_pad ($ dps ->numeroDps , 15 , '0 ' , STR_PAD_LEFT );
86+ }
87+
88+ private function buildTotTrib (\DOMDocument $ doc , DpsData $ dps ): \DOMElement
89+ {
90+ $ totTrib = $ doc ->createElement ('totTrib ' );
91+
92+ // tribMun contains ISS and conditional pAliq
93+ $ tribMun = $ doc ->createElement ('tribMun ' );
94+ $ tribMun ->appendChild ($ doc ->createElement ('tribISSQN ' , $ dps ->issRetido ? '2 ' : '1 ' ));
95+ $ tribMun ->appendChild ($ doc ->createElement ('tpRetISSQN ' , (string ) $ dps ->tipoRetencaoIss ));
96+
97+ // E0617: For não optante (opSimpNac=1), pAliq must NOT be present
98+ if ($ dps ->opcaoSimplesNacional !== 1 ) {
99+ $ tribMun ->appendChild ($ doc ->createElement ('pAliq ' , $ dps ->aliquota ));
70100 }
71101
72- return $ doc ->saveXML () ?: '' ;
102+ $ totTrib ->appendChild ($ tribMun );
103+
104+ // E0715: indTotTrib is ALWAYS included to avoid schema validation errors
105+ $ totTrib ->appendChild ($ doc ->createElement ('indTotTrib ' , (string ) $ dps ->indicadorTributacao ));
106+
107+ return $ totTrib ;
73108 }
74109
75- private function buildTrib (\DOMDocument $ doc , DpsData $ dps ): \DOMElement
110+ private function buildRegTrib (\DOMDocument $ doc , DpsData $ dps ): \DOMElement
76111 {
77- $ trib = $ doc ->createElement ('tribMun ' );
78- $ trib ->appendChild ($ doc ->createElement ('tribISSQN ' , $ dps ->issRetido ? '2 ' : '1 ' ));
79- $ trib ->appendChild ($ doc ->createElement ('pAliq ' , $ dps ->aliquota ));
112+ $ regTrib = $ doc ->createElement ('regTrib ' );
113+ $ regTrib ->appendChild ($ doc ->createElement ('regEspTrib ' , (string ) $ dps ->regimeEspecialTributacao ));
80114
81- return $ trib ;
115+ return $ regTrib ;
82116 }
83117
84118 private function buildToma (\DOMDocument $ doc , DpsData $ dps ): \DOMElement
0 commit comments