@@ -179,6 +179,184 @@ public function test_toXml_local_layout_nfe_txt(): void
179179 $ this ->assertStringContainsString ('<NFe ' , $ xml );
180180 }
181181
182+ // =========================================================================
183+ // toXml - LOCAL_V12 complete fixture (covers many parser entities)
184+ // =========================================================================
185+
186+ public function test_toXml_local_v12_complete_fixture (): void
187+ {
188+ $ txt = file_get_contents ($ this ->fixturesPath . 'nfe_4.00_local_v12_completa.txt ' );
189+ $ notas = $ this ->parseTxt ($ txt );
190+
191+ $ parser = new Parser ('4.00 ' , Parser::LOCAL_V12 );
192+ $ xml = $ parser ->toXml ($ notas [0 ]);
193+
194+ $ this ->assertNotNull ($ xml );
195+ $ nfe = new \SimpleXMLElement ($ xml );
196+
197+ // Referências (BA03, BA19, BA20)
198+ $ this ->assertNotEmpty ($ nfe ->infNFe ->ide ->NFref );
199+
200+ // Retirada (F, F02)
201+ $ this ->assertEquals ('RUA RETIRADA ' , (string )$ nfe ->infNFe ->retirada ->xLgr );
202+ $ this ->assertEquals ('12345678000195 ' , (string )$ nfe ->infNFe ->retirada ->CNPJ );
203+
204+ // Entrega (G, G02)
205+ $ this ->assertEquals ('RUA ENTREGA ' , (string )$ nfe ->infNFe ->entrega ->xLgr );
206+ $ this ->assertEquals ('98765432000100 ' , (string )$ nfe ->infNFe ->entrega ->CNPJ );
207+
208+ // DI (I18, I25)
209+ $ this ->assertEquals ('12345678 ' , (string )$ nfe ->infNFe ->det [0 ]->prod ->DI ->nDI );
210+ $ this ->assertEquals ('FABRICANTE1 ' , (string )$ nfe ->infNFe ->det [0 ]->prod ->DI ->adi ->cFabricante );
211+
212+ // Medicamentos (I80)
213+ $ this ->assertEquals ('LOTE001 ' , (string )$ nfe ->infNFe ->det [0 ]->prod ->rastro ->nLote );
214+
215+ // II (P)
216+ $ this ->assertEquals ('10.00 ' , (string )$ nfe ->infNFe ->det [0 ]->imposto ->II ->vII );
217+
218+ // PISST (R)
219+ $ this ->assertNotNull ($ nfe ->infNFe ->det [0 ]->imposto ->PISST );
220+
221+ // COFINSST (T)
222+ $ this ->assertNotNull ($ nfe ->infNFe ->det [0 ]->imposto ->COFINSST );
223+
224+ // ICMS20 (N04)
225+ $ this ->assertEquals ('20 ' , (string )$ nfe ->infNFe ->det [0 ]->imposto ->ICMS ->ICMS20 ->CST );
226+
227+ // ICMS40 (N06) on second item
228+ $ this ->assertEquals ('40 ' , (string )$ nfe ->infNFe ->det [1 ]->imposto ->ICMS ->ICMS40 ->CST );
229+
230+ // PIS NT (Q04) on second item
231+ $ this ->assertEquals ('04 ' , (string )$ nfe ->infNFe ->det [1 ]->imposto ->PIS ->PISNT ->CST );
232+
233+ // COFINS NT (S04) on second item
234+ $ this ->assertEquals ('04 ' , (string )$ nfe ->infNFe ->det [1 ]->imposto ->COFINS ->COFINSNT ->CST );
235+
236+ // Transporte (X03, X26, X33)
237+ $ this ->assertEquals ('TRANSPORTADORA TESTE ' , (string )$ nfe ->infNFe ->transp ->transporta ->xNome );
238+ $ this ->assertEquals ('2 ' , (string )$ nfe ->infNFe ->transp ->vol ->qVol );
239+ $ this ->assertNotEmpty ((string )$ nfe ->infNFe ->transp ->vol ->lacres ->nLacre );
240+
241+ // Cobrança (Y02, Y07)
242+ $ this ->assertEquals ('503 ' , (string )$ nfe ->infNFe ->cobr ->fat ->nFat );
243+ $ this ->assertEquals ('001 ' , (string )$ nfe ->infNFe ->cobr ->dup ->nDup );
244+
245+ // infAdic (Z04, Z07, Z10)
246+ $ this ->assertNotEmpty ((string )$ nfe ->infNFe ->infAdic ->infCpl );
247+ }
248+
249+ public function test_dump_local_v12_complete_fixture (): void
250+ {
251+ $ txt = file_get_contents ($ this ->fixturesPath . 'nfe_4.00_local_v12_completa.txt ' );
252+ $ notas = $ this ->parseTxt ($ txt );
253+
254+ $ parser = new Parser ('4.00 ' , Parser::LOCAL_V12 );
255+ $ result = $ parser ->dump ($ notas [0 ]);
256+
257+ $ this ->assertIsArray ($ result );
258+ $ this ->assertNotEmpty ($ result );
259+
260+ // Verify specific tags were parsed
261+ $ tags = array_map (fn ($ item ) => $ item ->tag , $ result );
262+ $ this ->assertContains ('BA03 ' , $ tags );
263+ $ this ->assertContains ('BA19 ' , $ tags );
264+ $ this ->assertContains ('BA20 ' , $ tags );
265+ $ this ->assertContains ('F ' , $ tags );
266+ $ this ->assertContains ('F02 ' , $ tags );
267+ $ this ->assertContains ('G ' , $ tags );
268+ $ this ->assertContains ('G02 ' , $ tags );
269+ $ this ->assertContains ('I18 ' , $ tags );
270+ $ this ->assertContains ('I25 ' , $ tags );
271+ $ this ->assertContains ('I80 ' , $ tags );
272+ $ this ->assertContains ('P ' , $ tags );
273+ $ this ->assertContains ('R ' , $ tags );
274+ $ this ->assertContains ('R02 ' , $ tags );
275+ $ this ->assertContains ('T ' , $ tags );
276+ $ this ->assertContains ('T02 ' , $ tags );
277+ $ this ->assertContains ('N04 ' , $ tags );
278+ $ this ->assertContains ('N06 ' , $ tags );
279+ $ this ->assertContains ('Q04 ' , $ tags );
280+ $ this ->assertContains ('S04 ' , $ tags );
281+ $ this ->assertContains ('X33 ' , $ tags );
282+ $ this ->assertContains ('Y07 ' , $ tags );
283+ $ this ->assertContains ('Z04 ' , $ tags );
284+ $ this ->assertContains ('Z07 ' , $ tags );
285+ $ this ->assertContains ('Z10 ' , $ tags );
286+ }
287+
288+ public function test_toXml_local_v12_icms_variados (): void
289+ {
290+ $ txt = file_get_contents ($ this ->fixturesPath . 'nfe_4.00_local_v12_icms_variados.txt ' );
291+ $ notas = $ this ->parseTxt ($ txt );
292+
293+ $ parser = new Parser ('4.00 ' , Parser::LOCAL_V12 );
294+ $ xml = $ parser ->toXml ($ notas [0 ]);
295+
296+ $ this ->assertNotNull ($ xml );
297+ $ nfe = new \SimpleXMLElement ($ xml );
298+
299+ // 5 items
300+ $ this ->assertCount (5 , $ nfe ->infNFe ->det );
301+
302+ // ICMS00 (N02)
303+ $ this ->assertEquals ('00 ' , (string )$ nfe ->infNFe ->det [0 ]->imposto ->ICMS ->ICMS00 ->CST );
304+
305+ // ICMS10 (N03)
306+ $ this ->assertEquals ('10 ' , (string )$ nfe ->infNFe ->det [1 ]->imposto ->ICMS ->ICMS10 ->CST );
307+
308+ // PIS via Q03 on item 2 (CST 02 gera PISAliq com campos de quantidade)
309+ $ this ->assertNotNull ($ nfe ->infNFe ->det [1 ]->imposto ->PIS );
310+
311+ // COFINS via S03 on item 2
312+ $ this ->assertNotNull ($ nfe ->infNFe ->det [1 ]->imposto ->COFINS );
313+
314+ // ICMS30 (N05)
315+ $ this ->assertEquals ('30 ' , (string )$ nfe ->infNFe ->det [2 ]->imposto ->ICMS ->ICMS30 ->CST );
316+
317+ // PISOutr (Q05 + Q07) on item 3
318+ $ this ->assertEquals ('99 ' , (string )$ nfe ->infNFe ->det [2 ]->imposto ->PIS ->PISOutr ->CST );
319+ $ this ->assertEquals ('100.00 ' , (string )$ nfe ->infNFe ->det [2 ]->imposto ->PIS ->PISOutr ->vBC );
320+
321+ // COFINSOutr (S05 + S07) on item 3
322+ $ this ->assertEquals ('99 ' , (string )$ nfe ->infNFe ->det [2 ]->imposto ->COFINS ->COFINSOutr ->CST );
323+ $ this ->assertEquals ('100.00 ' , (string )$ nfe ->infNFe ->det [2 ]->imposto ->COFINS ->COFINSOutr ->vBC );
324+
325+ // ICMS51 (N07)
326+ $ this ->assertEquals ('51 ' , (string )$ nfe ->infNFe ->det [3 ]->imposto ->ICMS ->ICMS51 ->CST );
327+
328+ // ICMS60 (N08)
329+ $ this ->assertEquals ('60 ' , (string )$ nfe ->infNFe ->det [4 ]->imposto ->ICMS ->ICMS60 ->CST );
330+ }
331+
332+ public function test_dump_icms_variados (): void
333+ {
334+ $ txt = file_get_contents ($ this ->fixturesPath . 'nfe_4.00_local_v12_icms_variados.txt ' );
335+ $ notas = $ this ->parseTxt ($ txt );
336+
337+ $ parser = new Parser ('4.00 ' , Parser::LOCAL_V12 );
338+ $ result = $ parser ->dump ($ notas [0 ]);
339+
340+ $ this ->assertIsArray ($ result );
341+ $ tags = array_map (fn ($ item ) => $ item ->tag , $ result );
342+ $ this ->assertContains ('N02 ' , $ tags );
343+ $ this ->assertContains ('N03 ' , $ tags );
344+ $ this ->assertContains ('N05 ' , $ tags );
345+ $ this ->assertContains ('N07 ' , $ tags );
346+ $ this ->assertContains ('N08 ' , $ tags );
347+ $ this ->assertContains ('Q03 ' , $ tags );
348+ $ this ->assertContains ('Q05 ' , $ tags );
349+ $ this ->assertContains ('S03 ' , $ tags );
350+ $ this ->assertContains ('S05 ' , $ tags );
351+ }
352+
353+ public function test_dump_unknown_tag_throws_exception (): void
354+ {
355+ $ this ->expectException (\NFePHP \NFe \Exception \DocumentsException::class);
356+ $ parser = new Parser ('4.00 ' , Parser::LOCAL_V12 );
357+ $ parser ->dump (['UNKNOWN|test| ' ]);
358+ }
359+
182360 // =========================================================================
183361 // Helper to split TXT into notes arrays (mimicking Convert logic)
184362 // =========================================================================
0 commit comments