diff --git a/.gitignore b/.gitignore index 8204312a..10d3305c 100644 --- a/.gitignore +++ b/.gitignore @@ -54,4 +54,5 @@ target *dependency-reduced-pom.xml /lsp/ -bin/ \ No newline at end of file +bin/ +.vscode/* \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index c5f3f6b9..b84f89c3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,4 @@ { - "java.configuration.updateBuildConfiguration": "interactive" + "java.configuration.updateBuildConfiguration": "interactive", + "java.compile.nullAnalysis.mode": "automatic" } \ No newline at end of file diff --git a/README.md b/README.md index 56252dbd..fb7d5b9f 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,95 @@ +# XHandler Java + [![License](https://img.shields.io/github/license/project-openubl/xhandler?logo=apache)](https://www.apache.org/licenses/LICENSE-2.0) [![CI](https://github.com/project-openubl/xhandler/actions/workflows/ci.yml/badge.svg)](https://github.com/project-openubl/xhandler/actions/workflows/ci.yml) - [![Project Chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg?style=for-the-badge&logo=zulip)](https://projectopenubl.zulipchat.com/) [![Supported JVM Versions](https://img.shields.io/badge/JVM--17-brightgreen.svg?style=for-the-badge&logo=Java)](https://github.com/project-openubl/xhandler/actions/) -| Artifact | Version | -|-------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| XBuilder | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/xbuilder)](https://search.maven.org/artifact/io.github.project-openubl/xbuilder/) | -| XBuilder Quarkus extension | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/quarkus-xbuilder)](https://search.maven.org/artifact/io.github.project-openubl/quarkus-xbuilder/) | -| XSender | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/xsender)](https://search.maven.org/artifact/io.github.project-openubl/xsender/) | -| XSender Quarkus extension | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/quarkus-xsender)](https://search.maven.org/artifact/io.github.project-openubl/quarkus-xsender/) | -| XSender Spring Boot extension | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/spring-boot-xsender)](https://search.maven.org/artifact/io.github.project-openubl/spring-boot-xsender/) | +**XHandler Java** es una suite de herramientas diseñada para facilitar la integración de **Facturación Electrónica en Perú (SUNAT)** en aplicaciones Java. Este repositorio es un "monorepo" que alberga las librerías `XBuilder` y `XSender`, proporcionando una solución integral para crear, firmar y enviar comprobantes de pago electrónicos. + +> [!TIP] +> Si buscas integrar facturación electrónica de manera rápida y estándar, estás en el lugar correcto. + +--- + +## 📦 Ecosistema -# XBuilder +El proyecto se divide en módulos principales y extensiones para frameworks populares: -Librería Java para crear XMLs basados en UBL y los estándares de la SUNAT respecto a la facturación electrónica. +| Componente | Descripción | Maven Central | +|------------|-------------|---------------| +| **XBuilder** | Creación y firma de XMLs (UBL 2.1) | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/xbuilder)](https://search.maven.org/artifact/io.github.project-openubl/xbuilder/) | +| **XSender** | Envío de comprobantes a SUNAT/OSE | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/xsender)](https://search.maven.org/artifact/io.github.project-openubl/xsender/) | +| **Quarkus XBuilder** | Extensión XBuilder para Quarkus | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/quarkus-xbuilder)](https://search.maven.org/artifact/io.github.project-openubl/quarkus-xbuilder/) | +| **Quarkus XSender** | Extensión XSender para Quarkus | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/quarkus-xsender)](https://search.maven.org/artifact/io.github.project-openubl/quarkus-xsender/) | +| **Spring Boot XSender** | Starter XSender para Spring Boot | [![Maven Central](https://img.shields.io/maven-central/v/io.github.project-openubl/spring-boot-xsender)](https://search.maven.org/artifact/io.github.project-openubl/spring-boot-xsender/) | -XBuilder esta diseñado para que puedas crear XMLs fácilmente. +--- -- Crea XMLs sin que necesites conocer nada sobre manejo de archivos XMLs. -- Hace cálculos internos por ti. -- Requiere solamente datos mínimos. +## 🛠️ XBuilder -## ¿Qué puedes hacer con XBuilder? +XBuilder abstrae la complejidad de los estándares UBL y XML, permitiéndote construir documentos tributarios válidos escribiendo código Java simple. -- Crear XMLs -- Firmar XMLs +### Características +- **Simple**: No necesitas manipular XML directamente ni conciliar namespaces complejos. +- **Completo**: Soporte para Facturas, Boletas, Notas de Crédito/Débito, Guías de Remisión y Percepciones/Retenciones. +- **Validado**: Realiza cálculos automáticos y validaciones básicas según normativa SUNAT. -### Update snapshots +### Ejemplo de Uso -```shell -mvn clean test -Dxbuilder.snapshot.update +```java +// Ejemplo simplificado de creación de factura +Invoice invoice = Invoice.builder() + .serie("F001") + .numero(1) + .proveedor(proveedor) + .cliente(cliente) + .detalle(detalle) + .build(); + +XMLInvoice xml = new InvoiceXMLBuilder().build(invoice); ``` -# XSender +> [!NOTE] +> Para actualizar los snapshots de prueba en desarrollo local, ejecuta: +> `mvn clean test -Dxbuilder.snapshot.update` + +--- + +## 🚀 XSender + +XSender se encarga de la comunicación con los servicios SOAP de la SUNAT o de los Operadores de Servicios Electrónicos (OSE). + +### Características +- **Compatible**: Soporta los diversos endpoints de SUNAT (Beta/Producción) y OSEs. +- **Resiliente**: Gestiona el envío de archivos ZIP y el procesamiento de respuestas (CDR, Tickets). +- **Flexible**: Fácil integración con frameworks modernos como Quarkus y Spring Boot. + +--- + +## 💻 Ejemplos + +Explora la carpeta `examples/` para ver implementaciones de referencia: + +- [**Spring Boot**](./examples/springbot): Ejemplo de integración completa usando Spring Boot. +- [**Wildfly**](./examples/wildfly): Ejemplo para servidores de aplicaciones Jakarta EE. +- [**Tomcat**](./examples/tomcat): Ejemplo ligero desplegable en Tomcat. +- [**XBuilder/XSender**](./examples): Ejemplos "standalone" de uso de las librerías. + +--- + +## 📚 Documentación + +Para guías detalladas, referencia de API y tutoriales, consulta nuestra documentación oficial. -Libreria para realizar envíos de comprobantes electrónicos a los servicios web de la SUNAT y/o OSCE de acuerdo a lo -especificado por la SUNAT. +- 📖 **Sitio Web**: [project-openubl.github.io](https://project-openubl.github.io) +- 💬 **Comunidad**: [Únete al chat en Zulip](https://projectopenubl.zulipchat.com/) +- 🐛 **Soporte**: [Reportar un problema o discutir mejoras](https://github.com/project-openubl/xsender/discussions) -# Getting started +--- -- [Documentación](https://project-openubl.github.io) -- [Discusiones](https://github.com/project-openubl/xsender/discussions) +## 📄 Licencia -## License +Este proyecto se distribuye bajo la licencia **Apache 2.0**. Consulta el archivo [LICENSE](LICENSE) para más detalles. -- [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) +Copyright © Project OpenUBL. diff --git a/examples/pom.xml b/examples/pom.xml index 9d62956b..397e7d79 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl xhandler-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/examples/springbot/pom.xml b/examples/springbot/pom.xml index 14d6115f..99797197 100644 --- a/examples/springbot/pom.xml +++ b/examples/springbot/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl examples-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml @@ -47,7 +47,7 @@ io.github.project-openubl spring-boot-xsender - 4.1.4 + 6.0.0-SNAPSHOT diff --git a/examples/springbot/src/main/java/io/github/project/openubl/quickstart/xbuilder/springboot/XBuilderController.java b/examples/springbot/src/main/java/io/github/project/openubl/quickstart/xbuilder/springboot/XBuilderController.java index 626fdae0..87af376e 100644 --- a/examples/springbot/src/main/java/io/github/project/openubl/quickstart/xbuilder/springboot/XBuilderController.java +++ b/examples/springbot/src/main/java/io/github/project/openubl/quickstart/xbuilder/springboot/XBuilderController.java @@ -1,10 +1,13 @@ package io.github.project.openubl.quickstart.xbuilder.springboot; -import io.github.project.openubl.xbuilder.content.catalogs.Catalog6; +import io.github.project.openubl.xbuilder.content.catalogs.*; import io.github.project.openubl.xbuilder.content.models.common.Cliente; import io.github.project.openubl.xbuilder.content.models.common.Proveedor; -import io.github.project.openubl.xbuilder.content.models.standard.general.DocumentoVentaDetalle; -import io.github.project.openubl.xbuilder.content.models.standard.general.Invoice; +import io.github.project.openubl.xbuilder.content.models.standard.general.*; +import io.github.project.openubl.xbuilder.content.models.standard.guia.*; +import io.github.project.openubl.xbuilder.content.models.sunat.baja.*; +import io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.*; +import io.github.project.openubl.xbuilder.content.models.sunat.resumen.*; import io.github.project.openubl.xbuilder.enricher.ContentEnricher; import io.github.project.openubl.xbuilder.enricher.config.DateProvider; import io.github.project.openubl.xbuilder.enricher.config.Defaults; @@ -13,7 +16,6 @@ import io.github.project.openubl.xbuilder.signature.CertificateDetailsFactory; import io.github.project.openubl.xbuilder.signature.XMLSigner; import io.github.project.openubl.xbuilder.signature.XmlSignatureHelper; -import io.quarkus.qute.Template; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -30,70 +32,366 @@ @RestController public class XBuilderController { - Defaults defaults = Defaults.builder() - .icbTasa(new BigDecimal("0.2")) - .igvTasa(new BigDecimal("0.18")) - .build(); - - DateProvider dateProvider = LocalDate::now; - - @RequestMapping( - method = RequestMethod.POST, - value = "/api/create-xml", - produces = "text/plain" - ) - public String createXML(@RequestBody String clientName) throws Exception { - Invoice invoice = createInvoice(clientName); - - ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); - enricher.enrich(invoice); - - Template template = TemplateProducer.getInstance().getInvoice(); - String xml = template.data(invoice).render(); - - // Sign XML - InputStream ksInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("LLAMA-PE-CERTIFICADO-DEMO-12345678912.pfx"); - CertificateDetails certificate = CertificateDetailsFactory.create(ksInputStream, "password"); - - X509Certificate x509Certificate = certificate.getX509Certificate(); - PrivateKey privateKey = certificate.getPrivateKey(); - Document signedXML = XMLSigner.signXML(xml, "Project OpenUBL", x509Certificate, privateKey); - - // Return - byte[] bytesFromDocument = XmlSignatureHelper.getBytesFromDocument(signedXML); - return new String(bytesFromDocument, StandardCharsets.ISO_8859_1); - } - - private Invoice createInvoice(String clientName) { - return Invoice.builder() - .serie("F001") - .numero(1) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre(clientName) - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.toString()) - .build() - ) - .detalle(DocumentoVentaDetalle.builder() - .descripcion("Item1") - .cantidad(new BigDecimal("10")) - .precio(new BigDecimal("100")) - .unidadMedida("KGM") - .build() - ) - .detalle(DocumentoVentaDetalle.builder() - .descripcion("Item2") - .cantidad(new BigDecimal("10")) - .precio(new BigDecimal("100")) - .unidadMedida("KGM") - .build() - ) - .build(); - } + Defaults defaults = Defaults.builder() + .icbTasa(new BigDecimal("0.2")) + .igvTasa(new BigDecimal("0.18")) + .build(); + + DateProvider dateProvider = LocalDate::now; + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/invoice", produces = "text/plain") + public String createInvoiceXML(@RequestBody String clientName) throws Exception { + Invoice input = createInvoice(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getInvoice().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/credit-note", produces = "text/plain") + public String createCreditNoteXML(@RequestBody String clientName) throws Exception { + CreditNote input = createCreditNote(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getCreditNote().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/debit-note", produces = "text/plain") + public String createDebitNoteXML(@RequestBody String clientName) throws Exception { + DebitNote input = createDebitNote(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getDebitNote().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/voided-documents", produces = "text/plain") + public String createVoidedDocumentsXML(@RequestBody String clientName) throws Exception { + VoidedDocuments input = createVoidedDocuments(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getVoidedDocument().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/summary-documents", produces = "text/plain") + public String createSummaryDocumentsXML(@RequestBody String clientName) throws Exception { + SummaryDocuments input = createSummaryDocuments(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getSummaryDocuments().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/perception", produces = "text/plain") + public String createPerceptionXML(@RequestBody String clientName) throws Exception { + Perception input = createPerception(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getPerception().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/retention", produces = "text/plain") + public String createRetentionXML(@RequestBody String clientName) throws Exception { + Retention input = createRetention(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getRetention().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/despatch-advice", produces = "text/plain") + public String createDespatchAdviceXML(@RequestBody String clientName) throws Exception { + DespatchAdvice input = createDespatchAdvice(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getDespatchAdvice().data(input).render(); + return signAndRender(xml); + } + + @RequestMapping(method = RequestMethod.POST, value = "/api/create-xml/reversion", produces = "text/plain") + public String createReversionXML(@RequestBody String clientName) throws Exception { + Reversion input = createReversion(clientName); + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + String xml = TemplateProducer.getInstance().getReversion().data(input).render(); + return signAndRender(xml); + } + + private String signAndRender(String xml) throws Exception { + // Sign XML + InputStream ksInputStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream("LLAMA-PE-CERTIFICADO-DEMO-12345678912.pfx"); + CertificateDetails certificate = CertificateDetailsFactory.create(ksInputStream, "password"); + + X509Certificate x509Certificate = certificate.getX509Certificate(); + PrivateKey privateKey = certificate.getPrivateKey(); + Document signedXML = XMLSigner.signXML(xml, "Project OpenUBL", x509Certificate, privateKey); + + // Return + byte[] bytesFromDocument = XmlSignatureHelper.getBytesFromDocument(signedXML); + return new String(bytesFromDocument, StandardCharsets.ISO_8859_1); + } + + private Invoice createInvoice(String clientName) { + return Invoice.builder() + .serie("F001") + .numero(1) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .unidadMedida("KGM") + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item2") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .unidadMedida("KGM") + .build()) + .build(); + } + + private CreditNote createCreditNote(String clientName) { + return CreditNote.builder() + .serie("FC01") + .numero(1) + .comprobanteAfectadoSerieNumero("F001-1") + .sustentoDescripcion("mi sustento") + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .build()) + .build(); + } + + private DebitNote createDebitNote(String clientName) { + return DebitNote.builder() + .serie("FD01") + .numero(1) + .comprobanteAfectadoSerieNumero("F001-1") + .sustentoDescripcion("mi sustento") + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .build()) + .build(); + } + + private VoidedDocuments createVoidedDocuments(String clientName) { + return VoidedDocuments.builder() + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("F001") + .numero(1) + .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) + .descripcionSustento("Mi sustento1") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("F001") + .numero(2) + .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) + .descripcionSustento("Mi sustento2") + .build()) + .build(); + } + + private SummaryDocuments createSummaryDocuments(String clientName) { + return SummaryDocuments.builder() + .numero(1) + .fechaEmisionComprobantes(dateProvider.now().minusDays(2)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(SummaryDocumentsItem.builder() + .tipoOperacion(Catalog19.ADICIONAR.toString()) + .comprobante(Comprobante.builder() + .tipoComprobante(Catalog1_Invoice.BOLETA.getCode())// + .serieNumero("B001-1") + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12345678") + .tipoDocumentoIdentidad( + Catalog6.DNI.getCode()) + .build()) + .impuestos(ComprobanteImpuestos.builder() + .igv(new BigDecimal("18")) + .icb(new BigDecimal(2)) + .build()) + .valorVenta(ComprobanteValorVenta.builder() + .importeTotal(new BigDecimal("120")) + .gravado(new BigDecimal("120")) + .build()) + .build()) + .build()) + .build(); + } + + private Perception createPerception(String clientName) { + return Perception.builder() + .serie("P001") + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .build()) + .importeTotalPercibido(new BigDecimal("10")) + .importeTotalCobrado(new BigDecimal("210")) + .tipoRegimen(Catalog22.VENTA_INTERNA.getCode()) + .tipoRegimenPorcentaje(Catalog22.VENTA_INTERNA.getPercent()) // + .operacion(PercepcionRetencionOperacion.builder() + .numeroOperacion(1) + .fechaOperacion(LocalDate.of(2022, 01, 31)) + .importeOperacion(new BigDecimal("100")) + .comprobante(io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado + .builder() + .tipoComprobante(Catalog1.FACTURA.getCode()) + .serieNumero("F001-1") + .fechaEmision(LocalDate.of(2022, 01, 31)) + .importeTotal(new BigDecimal("200")) + .moneda("PEN") + .build()) + .build()) + .build(); + } + + private Retention createRetention(String clientName) { + return Retention.builder() + .serie("R001") + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre(clientName) + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .build()) + .importeTotalRetenido(new BigDecimal("10")) + .importeTotalPagado(new BigDecimal("200")) + .tipoRegimen(Catalog23.TASA_TRES.getCode()) + .tipoRegimenPorcentaje(Catalog23.TASA_TRES.getPercent()) // + .operacion(PercepcionRetencionOperacion.builder() + .numeroOperacion(1) + .fechaOperacion(LocalDate.of(2022, 01, 31)) + .importeOperacion(new BigDecimal("100")) + .comprobante(io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado + .builder() + .tipoComprobante(Catalog1.FACTURA.getCode()) + .serieNumero("F001-1") + .fechaEmision(LocalDate.of(2022, 01, 31)) + .importeTotal(new BigDecimal("210")) + .moneda("PEN") + .build()) + .build()) + .build(); + } + + private DespatchAdvice createDespatchAdvice(String clientName) { + return DespatchAdvice.builder() + .serie("T001") + .numero(1) + .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) + .remitente(Remitente.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre(clientName) + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) + .pesoTotal(BigDecimal.ONE) + .pesoTotalUnidadMedida("KG") + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) + .fechaTraslado(dateProvider.now()) + .partida(Partida.builder() + .direccion("DireccionOrigen") + .ubigeo("010101") + .build()) + .destino(Destino.builder() + .direccion("DireccionDestino") + .ubigeo("020202") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("0.5")) + .unidadMedida("KG") + .codigo("123456") + .build()) + .build(); + } + + private Reversion createReversion(String clientName) { + return Reversion.builder() + .numero(1) + .fechaEmision(LocalDate.now()) + .fechaEmisionComprobantes(LocalDate.now().minusDays(1)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("P001") + .numero(1) + .tipoComprobante(Catalog1.PERCEPCION.getCode()) + .descripcionSustento("Anulacion de percepcion por error en emision") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("R001") + .numero(1) + .tipoComprobante(Catalog1.RETENCION.getCode()) + .descripcionSustento("Anulacion de retencion por duplicado") + .build()) + .build(); + } } diff --git a/examples/tomcat/pom.xml b/examples/tomcat/pom.xml index 70835dd4..c0141dce 100644 --- a/examples/tomcat/pom.xml +++ b/examples/tomcat/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl examples-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/examples/wildfly/pom.xml b/examples/wildfly/pom.xml index 78111db5..67ca03bd 100644 --- a/examples/wildfly/pom.xml +++ b/examples/wildfly/pom.xml @@ -7,7 +7,7 @@ io.github.project-openubl examples-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/examples/xbuilder/pom.xml b/examples/xbuilder/pom.xml index a0a32a4b..5cae1e85 100644 --- a/examples/xbuilder/pom.xml +++ b/examples/xbuilder/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl examples-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/examples/xsender/pom.xml b/examples/xsender/pom.xml index e67936a8..cf78146c 100644 --- a/examples/xsender/pom.xml +++ b/examples/xsender/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl examples-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 57b9e058..a12d9ae7 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.github.project-openubl xhandler-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT XHandler - Parent Java library for Creating, Sending XML files to SUNAT diff --git a/xbuilder/core/pom.xml b/xbuilder/core/pom.xml index 63645eef..02a4d321 100644 --- a/xbuilder/core/pom.xml +++ b/xbuilder/core/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl xbuilder-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/DespatchAdviceMapper.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/DespatchAdviceMapper.java index 05f18fcf..d9c2d070 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/DespatchAdviceMapper.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/DespatchAdviceMapper.java @@ -1,6 +1,7 @@ package io.github.project.openubl.xbuilder.content.jaxb.mappers; import io.github.project.openubl.xbuilder.content.jaxb.mappers.common.FirmanteMapper; +import java.util.List; import io.github.project.openubl.xbuilder.content.jaxb.mappers.common.Numero2Translator; import io.github.project.openubl.xbuilder.content.jaxb.mappers.common.SerieNumeroMapper; import io.github.project.openubl.xbuilder.content.jaxb.mappers.common.SerieNumeroTranslator; @@ -10,14 +11,21 @@ import io.github.project.openubl.xbuilder.content.models.common.Proveedor; import io.github.project.openubl.xbuilder.content.models.standard.guia.DespatchAdvice; import io.github.project.openubl.xbuilder.content.models.standard.guia.DespatchAdviceItem; +import io.github.project.openubl.xbuilder.content.models.standard.guia.Comprador; +import io.github.project.openubl.xbuilder.content.models.standard.guia.Tercero; import io.github.project.openubl.xbuilder.content.models.standard.guia.Destinatario; import io.github.project.openubl.xbuilder.content.models.standard.guia.Destino; import io.github.project.openubl.xbuilder.content.models.standard.guia.DocumentoBaja; import io.github.project.openubl.xbuilder.content.models.standard.guia.DocumentoRelacionado; +import io.github.project.openubl.xbuilder.content.models.standard.guia.DocumentoAdicional; import io.github.project.openubl.xbuilder.content.models.standard.guia.Envio; import io.github.project.openubl.xbuilder.content.models.standard.guia.Partida; import io.github.project.openubl.xbuilder.content.models.standard.guia.Remitente; import io.github.project.openubl.xbuilder.content.models.standard.guia.Transportista; +import io.github.project.openubl.xbuilder.content.models.standard.guia.Driver; +import io.github.project.openubl.xbuilder.content.models.standard.guia.GuiaItemAttribute; +import io.github.project.openubl.xbuilder.content.models.standard.guia.Puerto; +import io.github.project.openubl.xbuilder.content.models.standard.guia.Vehicle; import org.mapstruct.Condition; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @@ -26,23 +34,31 @@ @Mapper(uses = { SerieNumeroMapper.class, FirmanteMapper.class -}) +}, nullValuePropertyMappingStrategy = org.mapstruct.NullValuePropertyMappingStrategy.SET_TO_DEFAULT) public interface DespatchAdviceMapper { - @Mapping(target = "serie", source = "documentId", qualifiedBy = {SerieNumeroTranslator.class, SerieTranslator.class}) - @Mapping(target = "numero", source = "documentId", qualifiedBy = {SerieNumeroTranslator.class, Numero2Translator.class}) + @Mapping(target = "serie", source = "documentId", qualifiedBy = { SerieNumeroTranslator.class, + SerieTranslator.class }) + @Mapping(target = "numero", source = "documentId", qualifiedBy = { SerieNumeroTranslator.class, + Numero2Translator.class }) + @Mapping(target = "version", source = "customizationId") @Mapping(target = "fechaEmision", source = "issueDate") @Mapping(target = "horaEmision", source = "issueTime") @Mapping(target = "tipoComprobante", source = "despatchAdviceTypeCode") @Mapping(target = "observaciones", source = "note") @Mapping(target = "documentoBaja", source = "orderReference") - @Mapping(target = "documentoRelacionado", source = "additionalDocumentReference") + @Mapping(target = "documentoRelacionado", ignore = true) @Mapping(target = "firmante", source = "signature") @Mapping(target = "remitente", source = "despatchSupplierParty") @Mapping(target = "destinatario", source = "deliveryCustomerParty") - @Mapping(target = "proveedor", source = "sellerSupplierParty") + @Mapping(target = "proveedor", source = "sellerSupplierParty", qualifiedByName = "mapDespatchAdviceProveedor") + @Mapping(target = "tercero", source = "sellerSupplierParty", qualifiedByName = "mapDespatchAdviceTercero") @Mapping(target = "envio", source = "shipment") @Mapping(target = "detalles", source = "lines") + @Mapping(target = "documentosAdicionales", source = "additionalDocumentReferences", qualifiedByName = "mapDocumentosAdicionales") + @Mapping(target = "comprador", source = "buyerCustomerParty") + @Mapping(target = "documentoAdicional", ignore = true) + @Mapping(target = "detalle", ignore = true) DespatchAdvice map(XMLDespatchAdvice xml); @Mapping(target = "tipoDocumento", source = "orderTypeCode") @@ -55,58 +71,275 @@ public interface DespatchAdviceMapper { @Mapping(target = "ruc", source = "party.partyIdentification.id.value") @Mapping(target = "razonSocial", source = "party.partyLegalEntity.registrationName") + @Mapping(target = "numeroRegistroMTC", source = "party.partyLegalEntity.companyID") Remitente mapRemitente(XMLDespatchAdvice.DespatchSupplierParty xml); + @Mapping(target = "tipo", source = "jobTitle") + @Mapping(target = "tipoDocumentoIdentidad", source = "id.schemeID") + @Mapping(target = "numeroDocumentoIdentidad", source = "id.value") + @Mapping(target = "nombres", source = "firstName") + @Mapping(target = "apellidos", source = "familyName") + @Mapping(target = "licencia", source = "identityDocumentReference.id") + Driver mapDriver(XMLDespatchAdvice.DriverPerson xml); + @Mapping(target = "numeroDocumentoIdentidad", source = "party.partyIdentification.id.value") @Mapping(target = "tipoDocumentoIdentidad", source = "party.partyIdentification.id.schemeID") @Mapping(target = "nombre", source = "party.partyLegalEntity.registrationName") Destinatario mapDestinatario(XMLDespatchAdvice.DeliveryCustomerParty xml); - @Mapping(target = "ruc", source = "customerAssignedAccountId") - @Mapping(target = "nombreComercial", source = "party.partyLegalEntity.registrationName") - Proveedor mapProveedor(XMLDespatchAdvice.SellerSupplierParty xml); + @Named("mapDespatchAdviceProveedor") + default Proveedor mapDespatchAdviceProveedor(XMLDespatchAdvice.SellerSupplierParty xml) { + if (xml == null || xml.getCustomerAssignedAccountId() == null) { + return null; + } + Proveedor.ProveedorBuilder builder = Proveedor.builder(); + builder.ruc(xml.getCustomerAssignedAccountId()); + if (xml.getParty() != null && xml.getParty().getPartyLegalEntity() != null) { + builder.razonSocial(xml.getParty().getPartyLegalEntity().getRegistrationName()); + builder.nombreComercial(xml.getParty().getPartyLegalEntity().getRegistrationName()); + } + return builder.build(); + } + + @Named("mapDespatchAdviceTercero") + default Tercero mapDespatchAdviceTercero(XMLDespatchAdvice.SellerSupplierParty xml) { + if (xml == null || xml.getParty() == null || xml.getParty().getPartyIdentification() == null) { + return null; + } + Tercero.TerceroBuilder builder = Tercero.builder(); + if (xml.getParty().getPartyIdentification().getId() != null) { + builder.numeroDocumentoIdentidad(xml.getParty().getPartyIdentification().getId().getValue()); + builder.tipoDocumentoIdentidad(xml.getParty().getPartyIdentification().getId().getSchemeID()); + } + if (xml.getParty().getPartyLegalEntity() != null) { + builder.nombre(xml.getParty().getPartyLegalEntity().getRegistrationName()); + } + return builder.build(); + } + + @Mapping(target = "tipoDocumentoIdentidad", source = "party.partyIdentification.id.schemeID") + @Mapping(target = "numeroDocumentoIdentidad", source = "party.partyIdentification.id.value") + @Mapping(target = "nombre", source = "party.partyLegalEntity.registrationName") + Comprador mapComprador(XMLDespatchAdvice.BuyerCustomerParty xml); @Mapping(target = "tipoTraslado", source = "handlingCode") - @Mapping(target = "motivoTraslado", source = "information") + @Mapping(target = "motivoTraslado", source = "handlingInstructions") @Mapping(target = "pesoTotal", source = "grossWeightMeasure.value") @Mapping(target = "pesoTotalUnidadMedida", source = "grossWeightMeasure.unitCode") @Mapping(target = "numeroDeBultos", source = "totalTransportHandlingUnitQuantity") - @Mapping(target = "transbordoProgramado", source = "splitConsignmentIndicator") @Mapping(target = "tipoModalidadTraslado", source = "shipmentStage.transportModeCode") @Mapping(target = "fechaTraslado", source = "shipmentStage.transitPeriod.startDate") - @Mapping(target = "numeroDeContenedor", source = "transportHandlingUnit.transportEquipment.id") - @Mapping(target = "codigoDePuerto", source = "firstArrivalPortLocation.id") @Mapping(target = "transportista", source = "shipmentStage", conditionQualifiedByName = "transportistaRequirements") @Mapping(target = "destino", source = "delivery") - @Mapping(target = "partida", source = "originAddress") + @Mapping(target = "partida", source = ".", qualifiedByName = "mapPartidaFromShipment") + @Mapping(target = "choferes", source = "shipmentStage.driverPersons", qualifiedByName = "mapChoferes") + @Mapping(target = "indicadores", source = "specialInstructions", qualifiedByName = "mapIndicadores") + @Mapping(target = "contenedores", source = "transportHandlingUnit", qualifiedByName = "mapContenedores") + @Mapping(target = "pesoItems", source = "netWeightMeasure.value") + @Mapping(target = "sustentoPeso", source = "information") + @Mapping(target = "puerto", source = "firstArrivalPortLocation", qualifiedByName = "mapPuerto") + @Mapping(target = "aeropuerto", source = "firstArrivalPortLocation", qualifiedByName = "mapAeropuerto") + @Mapping(target = "vehiculo", source = "transportHandlingUnit", qualifiedByName = "mapVehiculo") + @Mapping(target = "chofer", ignore = true) + @Mapping(target = "indicador", ignore = true) + @Mapping(target = "contenedor", ignore = true) Envio mapEnvio(XMLDespatchAdvice.Shipment xml); @Condition @Named("transportistaRequirements") default boolean conditionTransportista(XMLDespatchAdvice.ShipmentStage xml) { - return xml.getCarrierParty() != null && xml.getTransportMeans() != null && xml.getDriverPerson() != null; + return xml.getCarrierParty() != null && xml.getTransportMeans() != null && xml.getDriverPersons() != null + && !xml.getDriverPersons().isEmpty(); } - @Mapping(target = "tipoDocumentoIdentidad", source = "carrierParty.partyIdentification.id.value") - @Mapping(target = "numeroDocumentoIdentidad", source = "carrierParty.partyIdentification.id.schemeID") - @Mapping(target = "nombre", source = "carrierParty.partyName.name") - @Mapping(target = "placaDelVehiculo", source = "transportMeans.roadTransport.licensePlateID") - @Mapping(target = "choferTipoDocumentoIdentidad", source = "driverPerson.id.schemeID") - @Mapping(target = "choferNumeroDocumentoIdentidad", source = "driverPerson.id.value") + @Mapping(target = "tipoDocumentoIdentidad", source = "carrierParty.partyIdentification.id.schemeID") + @Mapping(target = "numeroDocumentoIdentidad", source = "carrierParty.partyIdentification.id.value") + @Mapping(target = "nombre", source = "carrierParty.partyLegalEntity.registrationName") + @Mapping(target = "numeroRegistroMTC", source = "carrierParty.partyLegalEntity.companyID") Transportista mapTransportista(XMLDespatchAdvice.ShipmentStage xml); @Mapping(target = "ubigeo", source = "deliveryAddress.id") @Mapping(target = "direccion", source = "deliveryAddress.addressLine.line") + @Mapping(target = "codigoLocal", source = "deliveryAddress.addressTypeCode.value") + @Mapping(target = "ruc", source = "deliveryAddress.addressTypeCode.listID") Destino mapDelivery(XMLDespatchAdvice.Delivery xml); @Mapping(target = "ubigeo", source = "id") @Mapping(target = "direccion", source = "streetName") + @Mapping(target = "codigoLocal", ignore = true) + @Mapping(target = "ruc", ignore = true) Partida mapPartida(XMLDespatchAdvice.OriginAddress xml); @Mapping(target = "unidadMedida", source = "deliveredQuantity.unitCode") @Mapping(target = "cantidad", source = "deliveredQuantity.value") - @Mapping(target = "descripcion", source = "item.name") + @Mapping(target = "descripcion", source = "item", qualifiedByName = "mapItemDescription") @Mapping(target = "codigo", source = "item.sellersItemIdentification.id") @Mapping(target = "codigoSunat", source = "item.commodityClassification.itemClassificationCode") + @Mapping(target = "atributos", source = "item.additionalItemProperties", qualifiedByName = "mapAtributos") + @Mapping(target = "atributo", ignore = true) DespatchAdviceItem mapLine(XMLDespatchAdviceLine xml); + + @Mapping(target = "code", source = "nameCode") + GuiaItemAttribute mapAttribute(XMLDespatchAdviceLine.AdditionalItemProperty xml); + + @Named("mapItemDescription") + default String mapItemDescription(XMLDespatchAdviceLine.Item item) { + if (item == null) { + return null; + } + // Prefer description (new format) over name (old format) + return item.getDescription() != null ? item.getDescription() : item.getName(); + } + + @Named("mapPartidaFromShipment") + default Partida mapPartidaFromShipment(XMLDespatchAdvice.Shipment shipment) { + if (shipment == null) { + return null; + } + + // Try new format first: delivery.despatch.despatchAddress + if (shipment.getDelivery() != null && + shipment.getDelivery().getDespatch() != null && + shipment.getDelivery().getDespatch().getDespatchAddress() != null) { + XMLDespatchAdvice.DespatchAddress addr = shipment.getDelivery().getDespatch().getDespatchAddress(); + return Partida.builder() + .ubigeo(addr.getId()) + .direccion(addr.getAddressLine() != null ? addr.getAddressLine().getLine() : null) + .codigoLocal(addr.getAddressTypeCode() != null ? addr.getAddressTypeCode().getValue() : null) + .ruc(addr.getAddressTypeCode() != null ? addr.getAddressTypeCode().getListID() : null) + .build(); + } + + return null; + } + + @Named("mapPrimaryDriverTipo") + default String mapPrimaryDriverTipo(List drivers) { + if (drivers == null || drivers.isEmpty()) + return null; + return drivers.get(0).getId() != null ? drivers.get(0).getId().getSchemeID() : null; + } + + @Named("mapPrimaryDriverNum") + default String mapPrimaryDriverNum(List drivers) { + if (drivers == null || drivers.isEmpty()) + return null; + return drivers.get(0).getId() != null ? drivers.get(0).getId().getValue() : null; + } + + @Named("mapContenedores") + default List mapContenedores(List units) { + if (units == null) + return java.util.Collections.emptyList(); + List result = new java.util.ArrayList<>(); + for (XMLDespatchAdvice.TransportHandlingUnit unit : units) { + if (unit.getPackages() != null) { + unit.getPackages().stream().map(XMLDespatchAdvice.Package::getTraceID) + .filter(java.util.Objects::nonNull) + .forEach(result::add); + } + if (unit.getTransportEquipments() != null) { + // Only add as container if it's NOT a vehicle (simple ID, no transport means) + unit.getTransportEquipments().stream() + .filter(e -> e.getApplicableTransportMeans() == null) + .map(XMLDespatchAdvice.TransportEquipment::getId) + .filter(java.util.Objects::nonNull) + .forEach(result::add); + } + } + return result; + } + + @Named("mapChoferes") + default List mapChoferes(List drivers) { + if (drivers == null) + return java.util.Collections.emptyList(); + return drivers.stream().map(this::mapDriver).collect(java.util.stream.Collectors.toList()); + } + + @Named("mapIndicadores") + default List mapIndicadores(List indicators) { + if (indicators == null) + return java.util.Collections.emptyList(); + return indicators; + } + + @Named("mapAtributos") + default List mapAtributos(List attrs) { + if (attrs == null) + return java.util.Collections.emptyList(); + return attrs.stream().map(this::mapAttribute).collect(java.util.stream.Collectors.toList()); + } + + @Named("mapDocumentosAdicionales") + default List mapDocumentosAdicionales( + List rels) { + if (rels == null) + return java.util.Collections.emptyList(); + return rels.stream().map(this::mapDocumentoAdicional).collect(java.util.stream.Collectors.toList()); + } + + @Named("mapPuerto") + default Puerto mapPuerto(XMLDespatchAdvice.FirstArrivalPortLocation xml) { + if (xml == null || !"1".equals(xml.getLocationTypeCode())) + return null; + return Puerto.builder().codigo(xml.getId()).nombre(xml.getName()).build(); + } + + @Named("mapAeropuerto") + default Puerto mapAeropuerto(XMLDespatchAdvice.FirstArrivalPortLocation xml) { + if (xml == null || !"2".equals(xml.getLocationTypeCode())) + return null; + return Puerto.builder().codigo(xml.getId()).nombre(xml.getName()).build(); + } + + @Named("mapVehiculo") + default Vehicle mapVehiculo(List units) { + if (units == null) + return null; + // The first equipment with transport means or multiple are usually vehicles + return units.stream() + .filter(u -> u.getTransportEquipments() != null) + .flatMap(u -> u.getTransportEquipments().stream()) + .filter(e -> e.getApplicableTransportMeans() != null || e.getAttachedTransportEquipments() != null) + .findFirst() + .map(this::mapDetailedVehicle) + .orElse(null); + } + + default Vehicle mapDetailedVehicle(XMLDespatchAdvice.TransportEquipment xml) { + if (xml == null) + return null; + Vehicle.VehicleBuilder builder = Vehicle.builder().placa(xml.getId()); + if (xml.getApplicableTransportMeans() != null) { + builder.numeroCirculacion(xml.getApplicableTransportMeans().getRegistrationNationalityID()); + } + if (xml.getShipmentDocumentReferences() != null && !xml.getShipmentDocumentReferences().isEmpty()) { + XMLDespatchAdvice.ShipmentDocumentReference doc = xml.getShipmentDocumentReferences().get(0); + if (doc.getId() != null) { + builder.numeroAutorizacion(doc.getId().getValue()); + builder.codigoEmisor(doc.getId().getSchemeID()); + } + } + if (xml.getAttachedTransportEquipments() != null) { + builder.secundarios(xml.getAttachedTransportEquipments().stream() + .map(this::mapDetailedVehicle) + .collect(java.util.stream.Collectors.toList())); + } + return builder.build(); + } + + @Mapping(target = "tipoDocumento", source = "documentTypeCode") + @Mapping(target = "tipoDocumentoDescripcion", source = "documentType") + @Mapping(target = "rucEmisor", source = "issuerParty.partyIdentification.id.value") + @Mapping(target = "numero", source = "id") + DocumentoAdicional mapDocumentoAdicional(XMLDespatchAdvice.AdditionalDocumentReference xml); + + @Named("mapPrimaryAdditionalDocument") + default DocumentoRelacionado mapPrimaryAdditionalDocument( + List rels) { + if (rels == null || rels.isEmpty()) + return null; + return mapDocumentoRelacionado(rels.get(0)); + } } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/SummaryDocumentsMapper.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/SummaryDocumentsMapper.java index 6ade9936..9ecbd9de 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/SummaryDocumentsMapper.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/mappers/SummaryDocumentsMapper.java @@ -25,90 +25,95 @@ import java.util.stream.Collectors; @Mapper(uses = { - SerieNumeroMapper.class, - FirmanteMapper.class, - ProveedorMapper.class + SerieNumeroMapper.class, + FirmanteMapper.class, + ProveedorMapper.class }) public interface SummaryDocumentsMapper { - @Mapping(target = "fechaEmision", source = "issueDate") - @Mapping(target = "firmante", source = "signature") - @Mapping(target = "proveedor", source = "accountingSupplierParty") + @Mapping(target = "fechaEmision", source = "issueDate") + @Mapping(target = "firmante", source = "signature") + @Mapping(target = "proveedor", source = "accountingSupplierParty") - @Mapping(target = "numero", source = "documentId", qualifiedBy = {SerieNumeroTranslator.class, Numero3Translator.class}) - @Mapping(target = "fechaEmisionComprobantes", source = "referenceDate") - @Mapping(target = "comprobantes", source = "lines") - SummaryDocuments map(XMLSummaryDocuments xml); + @Mapping(target = "numero", source = "documentId", qualifiedBy = { SerieNumeroTranslator.class, + Numero3Translator.class }) + @Mapping(target = "fechaEmisionComprobantes", source = "referenceDate") + @Mapping(target = "comprobantes", source = "lines") + SummaryDocuments map(XMLSummaryDocuments xml); - @Mapping(target = "tipoOperacion", source = "status.conditionCode") - @Mapping(target = "comprobante", source = ".") - SummaryDocumentsItem mapLines(XMLSummaryDocumentsLine xml); + @Mapping(target = "tipoOperacion", source = "status.conditionCode") + @Mapping(target = "comprobante", source = ".") + SummaryDocumentsItem mapLines(XMLSummaryDocumentsLine xml); - @Mapping(target = "moneda", source = "totalAmount.currencyID") - @Mapping(target = "tipoComprobante", source = "documentTypeCode") - @Mapping(target = "serieNumero", source = "documentId") - @Mapping(target = "cliente", source = "accountingCustomerParty") - @Mapping(target = "comprobanteAfectado.serieNumero", source = "billingReference.invoiceDocumentReference.id") - @Mapping(target = "comprobanteAfectado.tipoComprobante", source = "billingReference.invoiceDocumentReference.documentTypeCode") - @Mapping(target = "valorVenta", source = ".") - @Mapping(target = "impuestos", source = ".") - Comprobante mapLineComprobante(XMLSummaryDocumentsLine xml); + @Mapping(target = "moneda", source = "totalAmount.currencyID") + @Mapping(target = "tipoComprobante", source = "documentTypeCode") + @Mapping(target = "serieNumero", source = "documentId") + @Mapping(target = "cliente", source = "accountingCustomerParty") + @Mapping(target = "comprobanteAfectado.serieNumero", source = "billingReference.invoiceDocumentReference.id") + @Mapping(target = "comprobanteAfectado.tipoComprobante", source = "billingReference.invoiceDocumentReference.documentTypeCode") + @Mapping(target = "valorVenta", source = ".") + @Mapping(target = "impuestos", source = ".") + Comprobante mapLineComprobante(XMLSummaryDocumentsLine xml); - @Mapping(target = "numeroDocumentoIdentidad", source = "customerAssignedAccountID") - @Mapping(target = "tipoDocumentoIdentidad", source = "additionalAccountID") - Cliente mapCliente(XMLSummaryDocumentsLine.AccountingCustomerParty xml); + @Mapping(target = "numeroDocumentoIdentidad", source = "customerAssignedAccountID") + @Mapping(target = "tipoDocumentoIdentidad", source = "additionalAccountID") + Cliente mapCliente(XMLSummaryDocumentsLine.AccountingCustomerParty xml); - default ComprobanteValorVenta mapLineComprobanteValorVenta(XMLSummaryDocumentsLine xml) { - if (xml == null) { - return null; - } - - Map billingPayments = Optional.ofNullable(xml.getBillingPayments()) - .orElse(Collections.emptyList()) - .stream() - .collect(Collectors.toMap( - XMLSummaryDocumentsLine.BillingPayment::getInstructionId, - XMLSummaryDocumentsLine.BillingPayment::getPaidAmount - )); + default ComprobanteValorVenta mapLineComprobanteValorVenta(XMLSummaryDocumentsLine xml) { + if (xml == null) { + return null; + } - BigDecimal importeTotal = Optional.ofNullable(xml.getTotalAmount()) - .map(XMLSummaryDocumentsLine.TotalAmount::getValue) - .orElse(null); - BigDecimal otrosCargos = Optional.ofNullable(xml.getAllowanceCharge()) - .map(XMLSummaryDocumentsLine.AllowanceCharge::getValue) - .orElse(null); + Map billingPayments = Optional.ofNullable(xml.getBillingPayments()) + .orElse(Collections.emptyList()) + .stream() + .collect(Collectors.toMap( + XMLSummaryDocumentsLine.BillingPayment::getInstructionId, + XMLSummaryDocumentsLine.BillingPayment::getPaidAmount)); - return ComprobanteValorVenta.builder() - .importeTotal(importeTotal) - .gravado(billingPayments.get("01")) - .exonerado(billingPayments.get("02")) - .inafecto(billingPayments.get("03")) - .gratuito(billingPayments.get("05")) - .otrosCargos(otrosCargos) - .build(); - } + BigDecimal importeTotal = Optional.ofNullable(xml.getTotalAmount()) + .map(XMLSummaryDocumentsLine.TotalAmount::getValue) + .orElse(null); + BigDecimal otrosCargos = Optional.ofNullable(xml.getAllowanceCharge()) + .map(XMLSummaryDocumentsLine.AllowanceCharge::getValue) + .orElse(null); - default ComprobanteImpuestos mapLineComprobanteImpuestos(XMLSummaryDocumentsLine xml) { - if (xml == null) { - return null; + return ComprobanteValorVenta.builder() + .importeTotal(importeTotal) + .gravado(billingPayments.get("01")) + .exonerado(billingPayments.get("02")) + .inafecto(billingPayments.get("03")) + .gratuito(billingPayments.get("05")) + .otrosCargos(otrosCargos) + .build(); } - Map taxTotals = Optional.ofNullable(xml.getTaxTotals()) - .orElse(Collections.emptyList()) - .stream() - .collect(Collectors.toMap( - taxTotal -> Optional.ofNullable(taxTotal.getTaxSubtotals()) - .flatMap(f -> Optional.ofNullable(f.getTaxCategory())) - .flatMap(f -> Optional.ofNullable(f.getTaxScheme())) - .flatMap(taxScheme -> Optional.ofNullable(taxScheme.getId())) - .flatMap(code -> Catalog.valueOfCode(Catalog5.class, code)) - .orElse(null), - taxTotal -> Optional.ofNullable(taxTotal.getTaxAmount()).orElse(BigDecimal.ZERO) - )); + default ComprobanteImpuestos mapLineComprobanteImpuestos(XMLSummaryDocumentsLine xml) { + if (xml == null) { + return null; + } - return ComprobanteImpuestos.builder() - .igv(taxTotals.get(Catalog5.IGV)) - .icb(taxTotals.get(Catalog5.ICBPER)) - .build(); - } + Map taxTotals = Optional.ofNullable(xml.getTaxTotals()) + .orElse(Collections.emptyList()) + .stream() + .collect(Collectors.toMap( + taxTotal -> Optional.ofNullable(taxTotal.getTaxSubtotals()) + .flatMap(f -> Optional.ofNullable(f.getTaxCategory())) + .flatMap(f -> Optional.ofNullable(f.getTaxScheme())) + .flatMap(taxScheme -> Optional + .ofNullable(taxScheme.getId())) + .flatMap(code -> Catalog.valueOfCode(Catalog5.class, + code)) + .orElse(null), + taxTotal -> Optional.ofNullable(taxTotal.getTaxAmount()) + .orElse(BigDecimal.ZERO))); + + return ComprobanteImpuestos.builder() + .igv(taxTotals.get(Catalog5.IGV)) + .icb(taxTotals.get(Catalog5.ICBPER)) + .isc(taxTotals.get(Catalog5.ISC)) + .ivap(taxTotals.get(Catalog5.IMPUESTO_ARROZ_PILADO)) + .otros(taxTotals.get(Catalog5.OTROS)) + .build(); + } } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdvice.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdvice.java index b2a71c16..d010512c 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdvice.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdvice.java @@ -23,6 +23,11 @@ @Data @NoArgsConstructor public class XMLDespatchAdvice { + @XmlElement(name = "UBLVersionID", namespace = XMLConstants.CBC) + private String ublVersionId; + + @XmlElement(name = "CustomizationID", namespace = XMLConstants.CBC) + private String customizationId; @XmlElement(name = "ID", namespace = XMLConstants.CBC) private String documentId; @@ -45,7 +50,7 @@ public class XMLDespatchAdvice { private OrderReference orderReference; @XmlElement(name = "AdditionalDocumentReference", namespace = XMLConstants.CAC) - private AdditionalDocumentReference additionalDocumentReference; + private List additionalDocumentReferences; @XmlElement(name = "Signature", namespace = XMLConstants.CAC) private XMLSignature signature; @@ -59,6 +64,9 @@ public class XMLDespatchAdvice { @XmlElement(name = "SellerSupplierParty", namespace = XMLConstants.CAC) private SellerSupplierParty sellerSupplierParty; + @XmlElement(name = "BuyerCustomerParty", namespace = XMLConstants.CAC) + private BuyerCustomerParty buyerCustomerParty; + @XmlElement(name = "Shipment", namespace = XMLConstants.CAC) private Shipment shipment; @@ -87,6 +95,21 @@ public static class AdditionalDocumentReference { @XmlElement(name = "DocumentTypeCode", namespace = XMLConstants.CBC) private String documentTypeCode; + + @XmlElement(name = "DocumentType", namespace = XMLConstants.CBC) + private String documentType; + + @XmlElement(name = "IssuerParty", namespace = XMLConstants.CAC) + private IssuerParty issuerParty; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.IssuerParty") + @Data + @NoArgsConstructor + public static class IssuerParty { + @XmlElement(name = "PartyIdentification", namespace = XMLConstants.CAC) + private PartyIdentification partyIdentification; } @XmlAccessorType(XmlAccessType.NONE) @@ -138,8 +161,22 @@ public static class ID { public static class PartyLegalEntity { @XmlElement(name = "RegistrationName", namespace = XMLConstants.CBC) private String registrationName; + + @XmlElement(name = "CompanyID", namespace = XMLConstants.CBC) + private String companyID; } + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.BuyerCustomerParty") + @Data + @NoArgsConstructor + public static class BuyerCustomerParty { + @XmlElement(name = "CustomerAssignedAccountId", namespace = XMLConstants.CBC) + private String customerAssignedAccountId; + + @XmlElement(name = "Party", namespace = XMLConstants.CAC) + private Party party; + } @XmlAccessorType(XmlAccessType.NONE) @XmlType(name = "DespatchAdvice.DeliveryCustomerParty") @@ -179,8 +216,14 @@ public static class Shipment { @XmlElement(name = "TotalTransportHandlingUnitQuantity", namespace = XMLConstants.CBC) private Integer totalTransportHandlingUnitQuantity; - @XmlElement(name = "SplitConsignmentIndicator", namespace = XMLConstants.CBC) - private Boolean splitConsignmentIndicator; + @XmlElement(name = "HandlingInstructions", namespace = XMLConstants.CBC) + private String handlingInstructions; + + @XmlElement(name = "SpecialInstructions", namespace = XMLConstants.CBC) + private List specialInstructions; + + @XmlElement(name = "NetWeightMeasure", namespace = XMLConstants.CBC) + private GrossWeightMeasure netWeightMeasure; @XmlElement(name = "ShipmentStage", namespace = XMLConstants.CAC) private ShipmentStage shipmentStage; @@ -189,10 +232,7 @@ public static class Shipment { private Delivery delivery; @XmlElement(name = "TransportHandlingUnit", namespace = XMLConstants.CAC) - private TransportHandlingUnit transportHandlingUnit; - - @XmlElement(name = "OriginAddress", namespace = XMLConstants.CAC) - private OriginAddress originAddress; + private List transportHandlingUnit; @XmlElement(name = "FirstArrivalPortLocation", namespace = XMLConstants.CAC) private FirstArrivalPortLocation firstArrivalPortLocation; @@ -228,7 +268,7 @@ public static class ShipmentStage { private TransportMeans transportMeans; @XmlElement(name = "DriverPerson", namespace = XMLConstants.CAC) - private DriverPerson driverPerson; + private List driverPersons; } @XmlAccessorType(XmlAccessType.NONE) @@ -251,6 +291,9 @@ public static class CarrierParty { @XmlElement(name = "PartyName", namespace = XMLConstants.CAC) private PartyName partyName; + + @XmlElement(name = "PartyLegalEntity", namespace = XMLConstants.CAC) + private PartyLegalEntity partyLegalEntity; } @XmlAccessorType(XmlAccessType.NONE) @@ -287,6 +330,27 @@ public static class RoadTransport { public static class DriverPerson { @XmlElement(name = "ID", namespace = XMLConstants.CBC) private ID id; + + @XmlElement(name = "FirstName", namespace = XMLConstants.CBC) + private String firstName; + + @XmlElement(name = "FamilyName", namespace = XMLConstants.CBC) + private String familyName; + + @XmlElement(name = "JobTitle", namespace = XMLConstants.CBC) + private String jobTitle; + + @XmlElement(name = "IdentityDocumentReference", namespace = XMLConstants.CAC) + private IdentityDocumentReference identityDocumentReference; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.IdentityDocumentReference") + @Data + @NoArgsConstructor + public static class IdentityDocumentReference { + @XmlElement(name = "ID", namespace = XMLConstants.CBC) + private String id; } @XmlAccessorType(XmlAccessType.NONE) @@ -296,6 +360,33 @@ public static class DriverPerson { public static class Delivery { @XmlElement(name = "DeliveryAddress", namespace = XMLConstants.CAC) private DeliveryAddress deliveryAddress; + + @XmlElement(name = "Despatch", namespace = XMLConstants.CAC) + private Despatch despatch; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.Despatch") + @Data + @NoArgsConstructor + public static class Despatch { + @XmlElement(name = "DespatchAddress", namespace = XMLConstants.CAC) + private DespatchAddress despatchAddress; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.DespatchAddress") + @Data + @NoArgsConstructor + public static class DespatchAddress { + @XmlElement(name = "ID", namespace = XMLConstants.CBC) + private String id; + + @XmlElement(name = "AddressTypeCode", namespace = XMLConstants.CBC) + private AddressTypeCode addressTypeCode; + + @XmlElement(name = "AddressLine", namespace = XMLConstants.CAC) + private AddressLine addressLine; } @XmlAccessorType(XmlAccessType.NONE) @@ -306,10 +397,25 @@ public static class DeliveryAddress { @XmlElement(name = "ID", namespace = XMLConstants.CBC) private String id; + @XmlElement(name = "AddressTypeCode", namespace = XMLConstants.CBC) + private AddressTypeCode addressTypeCode; + @XmlElement(name = "AddressLine", namespace = XMLConstants.CAC) private AddressLine addressLine; } + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.AddressTypeCode") + @Data + @NoArgsConstructor + public static class AddressTypeCode { + @XmlValue + private String value; + + @XmlAttribute(name = "listID") + private String listID; + } + @XmlAccessorType(XmlAccessType.NONE) @XmlType(name = "DespatchAdvice.AddressLine") @Data @@ -325,7 +431,22 @@ public static class AddressLine { @NoArgsConstructor public static class TransportHandlingUnit { @XmlElement(name = "TransportEquipment", namespace = XMLConstants.CAC) - private TransportEquipment transportEquipment; + private List transportEquipments; + + @XmlElement(name = "Package", namespace = XMLConstants.CAC) + private List packages; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.Package") + @Data + @NoArgsConstructor + public static class Package { + @XmlElement(name = "ID", namespace = XMLConstants.CBC) + private String id; + + @XmlElement(name = "TraceID", namespace = XMLConstants.CBC) + private String traceID; } @XmlAccessorType(XmlAccessType.NONE) @@ -335,6 +456,33 @@ public static class TransportHandlingUnit { public static class TransportEquipment { @XmlElement(name = "ID", namespace = XMLConstants.CBC) private String id; + + @XmlElement(name = "ApplicableTransportMeans", namespace = XMLConstants.CAC) + private ApplicableTransportMeans applicableTransportMeans; + + @XmlElement(name = "AttachedTransportEquipment", namespace = XMLConstants.CAC) + private List attachedTransportEquipments; + + @XmlElement(name = "ShipmentDocumentReference", namespace = XMLConstants.CAC) + private List shipmentDocumentReferences; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.ApplicableTransportMeans") + @Data + @NoArgsConstructor + public static class ApplicableTransportMeans { + @XmlElement(name = "RegistrationNationalityID", namespace = XMLConstants.CBC) + private String registrationNationalityID; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdvice.ShipmentDocumentReference") + @Data + @NoArgsConstructor + public static class ShipmentDocumentReference { + @XmlElement(name = "ID", namespace = XMLConstants.CBC) + private ID id; } @XmlAccessorType(XmlAccessType.NONE) @@ -356,5 +504,11 @@ public static class OriginAddress { public static class FirstArrivalPortLocation { @XmlElement(name = "ID", namespace = XMLConstants.CBC) private String id; + + @XmlElement(name = "LocationTypeCode", namespace = XMLConstants.CBC) + private String locationTypeCode; + + @XmlElement(name = "Name", namespace = XMLConstants.CBC) + private String name; } } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdviceLine.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdviceLine.java index 5a5505ba..791e3409 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdviceLine.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/jaxb/models/XMLDespatchAdviceLine.java @@ -3,6 +3,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAttribute; @@ -42,11 +44,32 @@ public static class Item { @XmlElement(name = "Name", namespace = XMLConstants.CBC) private String name; + @XmlElement(name = "Description", namespace = XMLConstants.CBC) + private String description; + @XmlElement(name = "SellersItemIdentification", namespace = XMLConstants.CAC) private SellersItemIdentification sellersItemIdentification; @XmlElement(name = "CommodityClassification", namespace = XMLConstants.CAC) private CommodityClassification commodityClassification; + + @XmlElement(name = "AdditionalItemProperty", namespace = XMLConstants.CAC) + private List additionalItemProperties; + } + + @XmlAccessorType(XmlAccessType.NONE) + @XmlType(name = "DespatchAdviceLine.AdditionalItemProperty") + @Data + @NoArgsConstructor + public static class AdditionalItemProperty { + @XmlElement(name = "Name", namespace = XMLConstants.CBC) + private String name; + + @XmlElement(name = "NameCode", namespace = XMLConstants.CBC) + private String nameCode; + + @XmlElement(name = "Value", namespace = XMLConstants.CBC) + private String value; } @XmlAccessorType(XmlAccessType.NONE) diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/EmbededDespatch.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/EmbededDespatch.java new file mode 100644 index 00000000..e1910c63 --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/EmbededDespatch.java @@ -0,0 +1,49 @@ +package io.github.project.openubl.xbuilder.content.models.standard.general; + +import io.github.project.openubl.xbuilder.content.models.common.Cliente; +import io.github.project.openubl.xbuilder.content.models.common.Direccion; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmbededDespatch { + + @Schema(description = "Punto de llegada") + private Direccion llegada; + + @Schema(description = "Punto de partida") + private Direccion partida; + + @Schema(description = "Datos del transportista") + private Cliente transportista; + + @Schema(description = "Numero de licencia de conducir") + private String nroLicencia; + + @Schema(description = "Placa del vehiculo") + private String transpPlaca; + + @Schema(description = "Codigo de autorizacion del transporte") + private String transpCodeAuth; + + @Schema(description = "Marca del vehiculo") + private String transpMarca; + + @Schema(description = "Modalidad de traslado. Catalog 18") + private String modTraslado; + + @Schema(description = "Peso bruto total") + private BigDecimal pesoBruto; + + @Schema(description = "Unidad de medida del peso bruto") + private String undPesoBruto; + +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/Invoice.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/Invoice.java index 248d59da..63257183 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/Invoice.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/Invoice.java @@ -45,6 +45,11 @@ public class Invoice extends SalesDocument { private Detraccion detraccion; private Percepcion percepcion; + /** + * Guia de remision embebida (Factura Guia) + */ + private EmbededDespatch guiaEmbebida; + /** * Anticipos asociados al comprobante */ diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/SalesDocument.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/SalesDocument.java index 6a45f35c..3d2d6581 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/SalesDocument.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/general/SalesDocument.java @@ -99,4 +99,10 @@ public abstract class SalesDocument extends Document { @Singular @ArraySchema private List documentosRelacionados; + + /** + * Cargos globales del documento + */ + @Singular + private List cargos; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Comprador.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Comprador.java new file mode 100644 index 00000000..47c0f2e7 --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Comprador.java @@ -0,0 +1,36 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Modelo para el comprador en la guía de remisión. + * Representa al adquiriente de los bienes cuando aplica. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Comprador { + + /** + * Tipo de documento de identidad (Catálogo 06) + */ + @Schema(description = "Catalogo 06", requiredMode = Schema.RequiredMode.REQUIRED) + private String tipoDocumentoIdentidad; + + /** + * Número de documento de identidad + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String numeroDocumentoIdentidad; + + /** + * Razón social o nombre + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String nombre; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdvice.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdvice.java index 4b9e7be5..9337c08a 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdvice.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdvice.java @@ -21,6 +21,11 @@ @NoArgsConstructor @AllArgsConstructor public class DespatchAdvice { + /** + * Versión del formato de la guía de remisión (ejemplo: 2.0) + */ + private String version; + /** * Serie del comprobante */ @@ -56,6 +61,13 @@ public class DespatchAdvice { @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) private DocumentoRelacionado documentoRelacionado; + /** + * Documentos adicionales relacionados al transporte (Catálogo 61) + */ + @Singular("documentoAdicional") + @Schema(description = "Documentos adicionales relacionados al transporte") + private List documentosAdicionales; + @Schema(description = "Persona que firma electrónicamente el comprobante. Si NULL los datos del proveedor son usados.") private Firmante firmante; @@ -68,6 +80,18 @@ public class DespatchAdvice { @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Proveedor proveedor; + /** + * Datos del tercero (vendedor de los bienes cuando aplica) + */ + @Schema(description = "Tercero/Vendedor de los bienes") + private Tercero tercero; + + /** + * Datos del comprador (adquiriente de los bienes) + */ + @Schema(description = "Comprador/Adquiriente de los bienes") + private Comprador comprador; + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private Envio envio; diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdviceItem.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdviceItem.java index d8ca3ae5..6184d717 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdviceItem.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DespatchAdviceItem.java @@ -4,9 +4,11 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.Singular; import lombok.extern.jackson.Jacksonized; import java.math.BigDecimal; +import java.util.List; @Jacksonized @Data @@ -20,4 +22,7 @@ public class DespatchAdviceItem { private String descripcion; private String codigo; private String codigoSunat; + + @Singular + private List atributos; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Destino.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Destino.java index 93d531de..1093c9d0 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Destino.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Destino.java @@ -1,5 +1,6 @@ package io.github.project.openubl.xbuilder.content.models.standard.guia; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,6 +11,22 @@ @NoArgsConstructor @AllArgsConstructor public class Destino { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String ubigeo; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String direccion; + + /** + * Código de establecimiento del punto de llegada + */ + @Schema(description = "Código de local anexo de llegada") + private String codigoLocal; + + /** + * RUC asociado al punto de llegada + */ + @Schema(description = "RUC asociado al punto de llegada") + private String ruc; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DocumentoAdicional.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DocumentoAdicional.java new file mode 100644 index 00000000..310cd139 --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/DocumentoAdicional.java @@ -0,0 +1,43 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Modelo para documentos adicionales relacionados al transporte. + * Catálogo 61 de SUNAT. + * Basado en el modelo AdditionalDoc de greenter. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DocumentoAdicional { + + /** + * Código del tipo de documento (Catálogo 61) + */ + @Schema(description = "Catalogo 61", requiredMode = Schema.RequiredMode.REQUIRED) + private String tipoDocumento; + + /** + * Descripción del tipo de documento + */ + @Schema(description = "Descripción del tipo de documento") + private String tipoDocumentoDescripcion; + + /** + * Número del documento + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String numero; + + /** + * RUC del emisor del documento + */ + @Schema(description = "RUC del emisor del documento") + private String rucEmisor; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Driver.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Driver.java new file mode 100644 index 00000000..83e5902e --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Driver.java @@ -0,0 +1,54 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Modelo para conductor/chofer de la guía de remisión. + * Basado en el modelo Driver de greenter. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Driver { + + /** + * Tipo de conductor: "Principal" o "Secundario" + */ + @Schema(description = "Tipo de conductor: Principal o Secundario") + private String tipo; + + /** + * Tipo de documento de identidad del chofer (Catálogo 06) + */ + @Schema(description = "Catalogo 06", requiredMode = Schema.RequiredMode.REQUIRED) + private String tipoDocumentoIdentidad; + + /** + * Número de documento de identidad del chofer + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String numeroDocumentoIdentidad; + + /** + * Nombres del conductor + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String nombres; + + /** + * Apellidos del conductor + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String apellidos; + + /** + * Número de licencia de conducir + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String licencia; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Envio.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Envio.java index 49c1a724..5dcf868b 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Envio.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Envio.java @@ -5,9 +5,11 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.Singular; import java.math.BigDecimal; import java.time.LocalDate; +import java.util.List; @Data @Builder @@ -17,6 +19,7 @@ public class Envio { @Schema(description = "Catalog 20", requiredMode = Schema.RequiredMode.REQUIRED) private String tipoTraslado; + private String motivoTraslado; @Schema(requiredMode = Schema.RequiredMode.REQUIRED) @@ -25,8 +28,19 @@ public class Envio { @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String pesoTotalUnidadMedida; + /** + * Peso de los ítems seleccionados (en KGM) + */ + @Schema(description = "Peso bruto de los items seleccionados") + private BigDecimal pesoItems; + + /** + * Sustento de la diferencia del peso bruto total respecto al peso de los ítems + */ + @Schema(description = "Sustento de diferencia de peso") + private String sustentoPeso; + private Integer numeroDeBultos; - private boolean transbordoProgramado; @Schema(description = "Catalog 18", requiredMode = Schema.RequiredMode.REQUIRED) private String tipoModalidadTraslado; @@ -34,12 +48,48 @@ public class Envio { @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private LocalDate fechaTraslado; - private String numeroDeContenedor; - private String codigoDePuerto; + /** + * Lista de contenedores/precintos + */ + @Singular("contenedor") + @Schema(description = "Lista de contenedores o precintos") + private List contenedores; + + /** + * Puerto de embarque/desembarque + */ + @Schema(description = "Puerto de embarque/desembarque (Catalogo 63)") + private Puerto puerto; + + /** + * Aeropuerto de embarque/desembarque + */ + @Schema(description = "Aeropuerto de embarque/desembarque (Catalogo 64)") + private Puerto aeropuerto; @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Transportista transportista; + /** + * Lista de conductores (principal y secundarios) + */ + @Singular("chofer") + @Schema(description = "Lista de conductores") + private List choferes; + + /** + * Vehículo principal con posibles vehículos secundarios + */ + @Schema(description = "Vehículo de transporte") + private Vehicle vehiculo; + + /** + * Indicadores especiales de transporte (SUNAT_Envio_*) + */ + @Singular("indicador") + @Schema(description = "Indicadores especiales de transporte") + private List indicadores; + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED) private Partida partida; diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/GuiaItemAttribute.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/GuiaItemAttribute.java new file mode 100644 index 00000000..d107dbee --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/GuiaItemAttribute.java @@ -0,0 +1,18 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.jackson.Jacksonized; + +@Jacksonized +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class GuiaItemAttribute { + private String code; + private String name; + private String value; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Partida.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Partida.java index 623ed9f1..fbff322b 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Partida.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Partida.java @@ -1,5 +1,6 @@ package io.github.project.openubl.xbuilder.content.models.standard.guia; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,6 +11,22 @@ @NoArgsConstructor @AllArgsConstructor public class Partida { + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String ubigeo; + + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String direccion; + + /** + * Código de establecimiento del punto de partida + */ + @Schema(description = "Código de local anexo de partida") + private String codigoLocal; + + /** + * RUC asociado al punto de partida + */ + @Schema(description = "RUC asociado al punto de partida") + private String ruc; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Puerto.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Puerto.java new file mode 100644 index 00000000..cb4e26ca --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Puerto.java @@ -0,0 +1,30 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Modelo para puerto o aeropuerto de embarque/desembarque. + * Basado en el modelo Puerto de greenter. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Puerto { + + /** + * Código del puerto (Catálogo 63) o aeropuerto (Catálogo 64) + */ + @Schema(description = "Código del puerto (Cat. 63) o aeropuerto (Cat. 64)", requiredMode = Schema.RequiredMode.REQUIRED) + private String codigo; + + /** + * Nombre del puerto o aeropuerto + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String nombre; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Remitente.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Remitente.java index a2705777..dd2fc4c5 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Remitente.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Remitente.java @@ -17,4 +17,7 @@ public class Remitente { @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String razonSocial; + + @Schema(description = "Número de registro del Ministerio de Transportes y Comunicaciones") + private String numeroRegistroMTC; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Tercero.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Tercero.java new file mode 100644 index 00000000..8c75d6a6 --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Tercero.java @@ -0,0 +1,36 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Modelo para tercero/proveedor en la guía de remisión. + * Representa al vendedor de los bienes cuando aplica. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Tercero { + + /** + * Tipo de documento de identidad (Catálogo 06) + */ + @Schema(description = "Catalogo 06", requiredMode = Schema.RequiredMode.REQUIRED) + private String tipoDocumentoIdentidad; + + /** + * Número de documento de identidad + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String numeroDocumentoIdentidad; + + /** + * Razón social o nombre + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String nombre; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Transportista.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Transportista.java index fe02e9c7..4413f90a 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Transportista.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Transportista.java @@ -21,13 +21,10 @@ public class Transportista { @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private String nombre; - @Schema(requiredMode = Schema.RequiredMode.REQUIRED) - private String placaDelVehiculo; - - @Schema(description = "Catalogo 06", requiredMode = Schema.RequiredMode.REQUIRED) - private String choferTipoDocumentoIdentidad; - - @Schema(requiredMode = Schema.RequiredMode.REQUIRED) - private String choferNumeroDocumentoIdentidad; + /** + * Número de registro del Ministerio de Transportes y Comunicaciones + */ + @Schema(description = "Número de registro MTC") + private String numeroRegistroMTC; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Vehicle.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Vehicle.java new file mode 100644 index 00000000..f1c381eb --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/standard/guia/Vehicle.java @@ -0,0 +1,53 @@ +package io.github.project.openubl.xbuilder.content.models.standard.guia; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.Singular; + +import java.util.List; + +/** + * Modelo para vehículo de transporte de la guía de remisión. + * Soporta vehículo principal y vehículos secundarios (carreta, etc.). + * Basado en el modelo Vehicle de greenter. + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Vehicle { + + /** + * Número de placa del vehículo + */ + @Schema(requiredMode = Schema.RequiredMode.REQUIRED) + private String placa; + + /** + * Número de tarjeta de circulación (TUC) + */ + @Schema(description = "Número de tarjeta única de circulación") + private String numeroCirculacion; + + /** + * Número de autorización o certificado de habilitación vehicular + */ + @Schema(description = "Número de autorización o certificado de habilitación") + private String numeroAutorizacion; + + /** + * Código de la entidad emisora de la autorización + */ + @Schema(description = "Código de entidad autorizadora") + private String codigoEmisor; + + /** + * Lista de vehículos secundarios (carretas, semirremolques, etc.) + */ + @Singular + @Schema(description = "Vehículos secundarios adjuntos") + private List secundarios; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/baja/Reversion.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/baja/Reversion.java new file mode 100644 index 00000000..57fa796c --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/baja/Reversion.java @@ -0,0 +1,17 @@ +package io.github.project.openubl.xbuilder.content.models.sunat.baja; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import lombok.extern.jackson.Jacksonized; + +@Jacksonized +@Data +@SuperBuilder +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class Reversion extends VoidedDocuments { +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/Comprobante.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/Comprobante.java index ab66d667..42f828a2 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/Comprobante.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/Comprobante.java @@ -15,7 +15,7 @@ public class Comprobante { @Schema(requiredMode = Schema.RequiredMode.AUTO, description = "Moneda del comprobante declarado") private String moneda; - + @Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "Catalogo 01") private String tipoComprobante; @@ -31,5 +31,7 @@ public class Comprobante { @Schema(requiredMode = Schema.RequiredMode.REQUIRED) private ComprobanteImpuestos impuestos; + private SummaryPerception percepcion; + private ComprobanteAfectado comprobanteAfectado; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/ComprobanteImpuestos.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/ComprobanteImpuestos.java index 80fe384e..49772424 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/ComprobanteImpuestos.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/ComprobanteImpuestos.java @@ -19,4 +19,13 @@ public class ComprobanteImpuestos { @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "ICB del comprobante") private BigDecimal icb; + + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "ISC del comprobante") + private BigDecimal isc; + + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "IVAP del comprobante") + private BigDecimal ivap; + + @Schema(requiredMode = Schema.RequiredMode.NOT_REQUIRED, description = "Otros tributos del comprobante") + private BigDecimal otros; } diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/SummaryPerception.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/SummaryPerception.java new file mode 100644 index 00000000..c8fafc33 --- /dev/null +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/content/models/sunat/resumen/SummaryPerception.java @@ -0,0 +1,31 @@ +package io.github.project.openubl.xbuilder.content.models.sunat.resumen; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SummaryPerception { + + @Schema(description = "Codigo de regimen de percepcion. Catalogo 22") + private String codReg; + + @Schema(description = "Tasa de percepcion") + private BigDecimal tasa; + + @Schema(description = "Monto base de percepcion") + private BigDecimal mtoBase; + + @Schema(description = "Monto de percepcion") + private BigDecimal mto; + + @Schema(description = "Monto total de percepcion") + private BigDecimal mtoTotal; +} diff --git a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/renderer/TemplateProducer.java b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/renderer/TemplateProducer.java index 05c38ff9..38ab3e91 100644 --- a/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/renderer/TemplateProducer.java +++ b/xbuilder/core/src/main/java/io/github/project/openubl/xbuilder/renderer/TemplateProducer.java @@ -36,6 +36,10 @@ public Template getDespatchAdvice() { return EngineProducer.getInstance().getEngine().getTemplate("Renderer/despatchAdvice.xml"); } + public Template getReversion() { + return EngineProducer.getInstance().getEngine().getTemplate("Renderer/reversion.xml"); + } + private static class TemplateProducerHolder { private static final TemplateProducer INSTANCE = new TemplateProducer(); diff --git a/xbuilder/core/src/main/resources/templates/Renderer/despatchAdvice.xml b/xbuilder/core/src/main/resources/templates/Renderer/despatchAdvice.xml index 476a8283..7a89706d 100644 --- a/xbuilder/core/src/main/resources/templates/Renderer/despatchAdvice.xml +++ b/xbuilder/core/src/main/resources/templates/Renderer/despatchAdvice.xml @@ -7,7 +7,7 @@ > {#include ubl/standard/include/ubl-extensions.xml /} {#include ubl/standard/include/general-data.xml item=this /} - {tipoComprobante} + {tipoComprobante} {#if observaciones} {/if} @@ -23,6 +23,22 @@ {documentoRelacionado.tipoDocumento} {/if} + {#each documentosAdicionales.orEmpty} + + {it.numero} + {it.tipoDocumento} + {#if it.tipoDocumentoDescripcion} + {it.tipoDocumentoDescripcion} + {/if} + {#if it.rucEmisor} + + + {it.rucEmisor} + + + {/if} + + {/each} {#include ubl/common/signature.xml firmante=this.firmante /} {remitente.ruc} @@ -32,6 +48,9 @@ + {#if remitente.numeroRegistroMTC} + {remitente.numeroRegistroMTC} + {/if} @@ -45,7 +64,30 @@ - {#if proveedor} + {#if comprador} + + + + {comprador.numeroDocumentoIdentidad} + + + + + + + {/if} + {#if tercero} + + + + {tercero.numeroDocumentoIdentidad} + + + + + + + {#else if proveedor} {proveedor.ruc} @@ -56,16 +98,24 @@ {/if} - 1 + SUNAT_Envio {envio.tipoTraslado} {#if envio.motivoTraslado} - {envio.motivoTraslado} + {envio.motivoTraslado} + {/if} + {#if envio.sustentoPeso} + {envio.sustentoPeso} {/if} {envio.pesoTotal.scale(3)} + {#if envio.pesoItems} + {envio.pesoItems.scale(3)} + {/if} {#if envio.numeroDeBultos} {envio.numeroDeBultos} {/if} - {envio.transbordoProgramado} + {#each envio.indicadores.orEmpty} + {it} + {/each} {envio.tipoModalidadTraslado} @@ -76,42 +126,111 @@ {envio.transportista.numeroDocumentoIdentidad} - - - + + + {#if envio.transportista.numeroRegistroMTC} + {envio.transportista.numeroRegistroMTC} + {/if} + - - - {envio.transportista.placaDelVehiculo} - - + {/if} + {#each envio.choferes.orEmpty} - {envio.transportista.choferNumeroDocumentoIdentidad} + {it.numeroDocumentoIdentidad} + {#if it.nombres} + {it.nombres} + {/if} + {#if it.apellidos} + {it.apellidos} + {/if} + {#if it.tipo} + {it.tipo} + {/if} + {#if it.licencia} + + {it.licencia} + + {/if} - {/if} + {/each} + {#if envio.destino} {envio.destino.ubigeo} + {#if envio.destino.codigoLocal} + {envio.destino.codigoLocal} + {/if} {envio.destino.direccion} + {/if} + {#if envio.partida} + + + {envio.partida.ubigeo} + {#if envio.partida.codigoLocal} + {envio.partida.codigoLocal} + {/if} + + {envio.partida.direccion} + + + + {/if} - {#if envio.numeroDeContenedor} + {#each envio.contenedores.orEmpty} + + + {it_index.add(1)} + {it} + + + {/each} + {#if envio.vehiculo} - {envio.numeroDeContenedor} + {envio.vehiculo.placa} + {#if envio.vehiculo.numeroCirculacion} + + {envio.vehiculo.numeroCirculacion} + + {/if} + {#each envio.vehiculo.secundarios.orEmpty} + + {it.placa} + {#if it.numeroCirculacion} + + {it.numeroCirculacion} + + {/if} + {#if it.numeroAutorizacion} + + {it.numeroAutorizacion} + + {/if} + + {/each} + {#if envio.vehiculo.numeroAutorizacion} + + {envio.vehiculo.numeroAutorizacion} + + {/if} {/if} - - {envio.partida.ubigeo} - {envio.partida.direccion} - - {#if envio.codigoDePuerto} + {#if envio.puerto} + + {envio.puerto.codigo} + 1 + {envio.puerto.nombre} + + {#else if envio.aeropuerto} - {{ envio.codigoDePuerto }} + {envio.aeropuerto.codigo} + 2 + {envio.aeropuerto.nombre} {/if} @@ -124,7 +243,7 @@ {#if it.descripcion} - + {/if} {it.codigo} @@ -134,6 +253,15 @@ {it.codigoSunat} {/if} + {#each it.atributos.orEmpty} + + {it.name} + {it.code} + {#if it.value} + {it.value} + {/if} + + {/each} {/each} diff --git a/xbuilder/core/src/main/resources/templates/Renderer/invoice.xml b/xbuilder/core/src/main/resources/templates/Renderer/invoice.xml index 7ad5e75e..5c8a16a6 100644 --- a/xbuilder/core/src/main/resources/templates/Renderer/invoice.xml +++ b/xbuilder/core/src/main/resources/templates/Renderer/invoice.xml @@ -48,6 +48,74 @@ {/if} + {#if guiaEmbebida} + + + + {guiaEmbebida.llegada.ubigueo} + {guiaEmbebida.llegada.direccion} + {#if guiaEmbebida.llegada.urbanizacion} + {guiaEmbebida.llegada.urbanizacion} + {/if} + {guiaEmbebida.llegada.provincia} + {guiaEmbebida.llegada.departamento} + {guiaEmbebida.llegada.distrito} + + {guiaEmbebida.llegada.codigoPais} + + + + + + {guiaEmbebida.partida.ubigueo} + {guiaEmbebida.partida.direccion} + {#if guiaEmbebida.partida.urbanizacion} + {guiaEmbebida.partida.urbanizacion} + {/if} + {guiaEmbebida.partida.provincia} + {guiaEmbebida.partida.departamento} + {guiaEmbebida.partida.distrito} + + {guiaEmbebida.partida.codigoPais} + + + + + {guiaEmbebida.pesoBruto} + + {guiaEmbebida.modTraslado} + + {fechaEmision} + + + + {guiaEmbebida.transportista.numeroDocumentoIdentidad} + + + + + + + {guiaEmbebida.nroLicencia} + + + + + {guiaEmbebida.llegada.ubigueo} + {guiaEmbebida.llegada.direccion} + + {guiaEmbebida.llegada.codigoPais} + + + + + + {guiaEmbebida.transpPlaca} + + + + + {/if} {#if detraccion} Detraccion @@ -85,6 +153,15 @@ {it.monto} {/each} + {#each cargos.orEmpty} + + true + {it.tipo} + {it.porcentaje.scale(2)} + {it.monto.scale(2)} + {it.monto.scale(2)} + + {/each} {#each descuentos.orEmpty} false diff --git a/xbuilder/core/src/main/resources/templates/Renderer/reversion.xml b/xbuilder/core/src/main/resources/templates/Renderer/reversion.xml new file mode 100644 index 00000000..a9c62caa --- /dev/null +++ b/xbuilder/core/src/main/resources/templates/Renderer/reversion.xml @@ -0,0 +1,26 @@ + + + {#include ubl/standard/include/ubl-extensions.xml /} + 2.0 + 1.0 + RR-{fechaEmision.format('yyyyMMdd')}-{numero} + {fechaEmisionComprobantes} + {fechaEmision} + {#include ubl/common/signature.xml firmante=this.firmante /} + {#include ubl/sunat/include/supplier.xml proveedor=this.proveedor /} + {#each comprobantes.orEmpty} + + {it_index.add(1)} + {it.tipoComprobante} + {it.serie} + {it.numero} + {it.descripcionSustento} + + {/each} + diff --git a/xbuilder/core/src/main/resources/templates/Renderer/summaryDocuments.xml b/xbuilder/core/src/main/resources/templates/Renderer/summaryDocuments.xml index 7f1b4a10..979271a2 100644 --- a/xbuilder/core/src/main/resources/templates/Renderer/summaryDocuments.xml +++ b/xbuilder/core/src/main/resources/templates/Renderer/summaryDocuments.xml @@ -38,6 +38,15 @@ {/if} + {#if it.comprobante.percepcion} + + {it.comprobante.percepcion.codReg} + {it.comprobante.percepcion.tasa.scale(2)} + {it.comprobante.percepcion.mto.scale(2)} + {it.comprobante.percepcion.mtoTotal.scale(2)} + {it.comprobante.percepcion.mtoBase.scale(2)} + + {/if} {it.tipoOperacion} @@ -100,6 +109,51 @@ {/if} + {#if it.comprobante.impuestos.isc} + + {it.comprobante.impuestos.isc} + + {it.comprobante.impuestos.isc} + + + 2000 + ISC + EXC + + + + + {/if} + {#if it.comprobante.impuestos.ivap} + + {it.comprobante.impuestos.ivap} + + {it.comprobante.impuestos.ivap} + + + 1016 + IVAP + VAT + + + + + {/if} + {#if it.comprobante.impuestos.otros} + + {it.comprobante.impuestos.otros} + + {it.comprobante.impuestos.otros} + + + 9999 + OTROS + OTH + + + + + {/if} {/each} diff --git a/xbuilder/core/src/main/resources/templates/ubl/standard/include/general-data.xml b/xbuilder/core/src/main/resources/templates/ubl/standard/include/general-data.xml index 3ab314c0..99ff4825 100644 --- a/xbuilder/core/src/main/resources/templates/ubl/standard/include/general-data.xml +++ b/xbuilder/core/src/main/resources/templates/ubl/standard/include/general-data.xml @@ -1,5 +1,5 @@ 2.1 - 2.0 + {item.version ?: '2.0'} {item.serie}-{item.numero} {item.fechaEmision} {#if item.horaEmision} diff --git a/xbuilder/core/src/test/java/e2e/AbstractTest.java b/xbuilder/core/src/test/java/e2e/AbstractTest.java index ec62ade5..47e613d5 100644 --- a/xbuilder/core/src/test/java/e2e/AbstractTest.java +++ b/xbuilder/core/src/test/java/e2e/AbstractTest.java @@ -28,6 +28,7 @@ import io.github.project.openubl.xbuilder.content.models.standard.general.Invoice; import io.github.project.openubl.xbuilder.content.models.standard.guia.DespatchAdvice; import io.github.project.openubl.xbuilder.content.models.sunat.baja.VoidedDocuments; +import io.github.project.openubl.xbuilder.content.models.sunat.baja.Reversion; import io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Perception; import io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Retention; import io.github.project.openubl.xbuilder.content.models.sunat.resumen.SummaryDocuments; @@ -56,7 +57,8 @@ public class AbstractTest { private static final CreditNoteMapper creditNoteMapper = Mappers.getMapper(CreditNoteMapper.class); private static final DebitNoteMapper debitNoteMapper = Mappers.getMapper(DebitNoteMapper.class); private static final VoidedDocumentsMapper voidedDocumentsMapper = Mappers.getMapper(VoidedDocumentsMapper.class); - private static final SummaryDocumentsMapper summaryDocumentsMapper = Mappers.getMapper(SummaryDocumentsMapper.class); + private static final SummaryDocumentsMapper summaryDocumentsMapper = Mappers + .getMapper(SummaryDocumentsMapper.class); private static final PerceptionMapper perceptionMapper = Mappers.getMapper(PerceptionMapper.class); private static final RetentionMapper retentionMapper = Mappers.getMapper(RetentionMapper.class); private static final DespatchAdviceMapper despatchAdviceMapper = Mappers.getMapper(DespatchAdviceMapper.class); @@ -81,7 +83,8 @@ public YAMLMapper getYamlMapper() { public void writeYaml(String kind, Object input, String snapshotFilename) throws URISyntaxException, IOException { String rootDir = getClass().getName().replaceAll("\\.", "/"); - String snapshotFileContent = Files.readString(Paths.get(getClass().getClassLoader().getResource(rootDir + "/" + snapshotFilename).toURI())); + String snapshotFileContent = Files.readString( + Paths.get(getClass().getClassLoader().getResource(rootDir + "/" + snapshotFilename).toURI())); Path directoryPath = Paths.get("../quarkus-extension/integration-tests/src/test/resources").resolve(rootDir); Files.createDirectories(directoryPath); @@ -90,8 +93,7 @@ public void writeYaml(String kind, Object input, String snapshotFilename) throws getYamlMapper().writeValue(filePath.toFile(), Map.of( "kind", kind, "input", input, - "snapshot", snapshotFileContent - )); + "snapshot", snapshotFileContent)); } protected void assertInput(Invoice input, String snapshotFilename) throws Exception { @@ -285,4 +287,28 @@ protected void assertInput(DespatchAdvice input, String snapshotFilename) throws writeYaml("DespatchAdvice", input, snapshotFilename); } + + protected void assertInputReversion(Reversion input, String snapshotFilename) throws Exception { + ContentEnricher enricher = new ContentEnricher(defaults, dateProvider); + enricher.enrich(input); + + // When + Template template = TemplateProducer.getInstance().getReversion(); + String xml = template.data(input).render(); + + String reconstructedXml; + try (StringReader reader = new StringReader(xml);) { + XMLVoidedDocuments xmlPojo = (XMLVoidedDocuments) JAXBContext.newInstance(XMLVoidedDocuments.class) + .createUnmarshaller() + .unmarshal(new InputSource(reader)); + VoidedDocuments inputFromXml = voidedDocumentsMapper.map(xmlPojo); + reconstructedXml = TemplateProducer.getInstance().getReversion().data(inputFromXml).render(); + } + + // Then + XMLAssertUtils.assertSnapshot(xml, reconstructedXml, getClass(), snapshotFilename); + XMLAssertUtils.assertSendSunat(xml, XMLAssertUtils.VOIDED_DOCUMENTS_XSD); + + writeYaml("Reversion", input, snapshotFilename); + } } diff --git a/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest.java b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest.java new file mode 100644 index 00000000..cb702470 --- /dev/null +++ b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest.java @@ -0,0 +1,75 @@ +package e2e.renderer.despatchadvice; + +import e2e.AbstractTest; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog1; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog6; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog18; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog20; +import io.github.project.openubl.xbuilder.content.models.standard.guia.*; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +public class DespatchAdviceCarrierTest extends AbstractTest { + + @Test + public void testCarrierData() throws Exception { + // Given + DespatchAdvice input = DespatchAdvice.builder() + .serie("V001") + .numero(1) + .version("2.1") + .tipoComprobante(Catalog1.GUIA_REMISION_TRANSPORTISTA.getCode()) // 31 + .remitente(Remitente.builder() // En una 31, el remitente es el Transportista emitente + .ruc("20123456789") + .razonSocial("Transportes Veloz S.A.C.") + .numeroRegistroMTC("MTC-654321") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .numeroDocumentoIdentidad("20876543210") + .nombre("Cliente Final S.A.") + .build()) + .tercero(Tercero.builder() // El Remitente original (el que solicita el transporte) + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .numeroDocumentoIdentidad("20555555555") + .nombre("Empresa Vendedora S.A.C.") + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.VENTA.getCode()) + .pesoTotal(new BigDecimal("500.00")) + .pesoTotalUnidadMedida("KGM") + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PUBLICO.getCode()) + .fechaTraslado(dateProvider.now()) + .chofer(Driver.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("44444444") + .nombres("Carlos") + .apellidos("Guerrero") + .licencia("L5555555") + .build()) + .vehiculo(Vehicle.builder() + .placa("XYZ-789") + .numeroCirculacion("TUC-V001") + .build()) + .partida(Partida.builder() + .direccion("Almacen Principal") + .ubigeo("150101") + .build()) + .destino(Destino.builder() + .direccion("Tienda Centro") + .ubigeo("150102") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("10.00")) + .unidadMedida("NIU") + .codigo("PROD-99") + .descripcion("Mercaderia variada") + .build()) + .build(); + + // When/Then + assertInput(input, "carrierData.xml"); + } +} diff --git a/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceComplexTest.java b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceComplexTest.java new file mode 100644 index 00000000..e65ef81d --- /dev/null +++ b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceComplexTest.java @@ -0,0 +1,117 @@ +package e2e.renderer.despatchadvice; + +import e2e.AbstractTest; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog1; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog18; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog20; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog6; +import io.github.project.openubl.xbuilder.content.models.standard.guia.*; +import org.junit.jupiter.api.Test; + +import java.math.BigDecimal; + +public class DespatchAdviceComplexTest extends AbstractTest { + + @Test + public void testComplexData() throws Exception { + // Given + DespatchAdvice input = DespatchAdvice.builder() + .serie("T001") + .numero(100) + .version("2.1") + .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) + .remitente(Remitente.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre("Mi Cliente S.A.C.") + .build()) + .comprador(Comprador.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre("Mi Cliente S.A.C.") + .build()) + .documentoAdicional(DocumentoAdicional.builder() + .tipoDocumento("09") + .numero("T001-1") + .rucEmisor("20100010001") + .tipoDocumentoDescripcion("GUIA REMISION") + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.VENTA.getCode()) + .pesoTotal(new BigDecimal("100.50")) + .pesoTotalUnidadMedida("KGM") + .pesoItems(new BigDecimal("90.00")) + .sustentoPeso("Empaque madera") + .numeroDeBultos(10) + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PUBLICO.getCode()) + .fechaTraslado(dateProvider.now()) + .chofer(Driver.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("11111111") + .nombres("Juan") + .apellidos("Perez") + .licencia("Q1234567") + .tipo("CONDUCTOR_PRINCIPAL") + .build()) + .chofer(Driver.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("22222222") + .nombres("Jose") + .apellidos("Gomez") + .tipo("COPILOTO") + .build()) + .contenedor("CONT-001") + .contenedor("CONT-002") + .vehiculo(Vehicle.builder() + .placa("ABC-123") + .numeroCirculacion("TUC-001") + .numeroAutorizacion("AUTH-001") + .codigoEmisor("MTC") + .secundario(Vehicle.builder() + .placa("CAR-456") + .numeroCirculacion("TUC-SEC") + .build()) + .build()) + .puerto(Puerto.builder() + .codigo("CALLAO") + .nombre("Puerto del Callao") + .build()) + .partida(Partida.builder() + .direccion("Av. Origen 123") + .ubigeo("010101") + .codigoLocal("0001") + .ruc("12345678912") + .build()) + .destino(Destino.builder() + .direccion("Av. Destino 456") + .ubigeo("020202") + .codigoLocal("0002") + .ruc("87654321098") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("5.00")) + .unidadMedida("NIU") + .codigo("ITEM-01") + .descripcion("Caja de herramientas") + .atributo(GuiaItemAttribute.builder() + .name("Color") + .code("1001") + .value("Rojo") + .build()) + .atributo(GuiaItemAttribute.builder() + .name("Marca") + .code("1002") + .value("ToolMaster") + .build()) + .build()) + .build(); + + assertInput(input, "complexData.xml"); + } + +} diff --git a/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceTest.java b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceTest.java index 2d019efd..73cca961 100644 --- a/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceTest.java +++ b/xbuilder/core/src/test/java/e2e/renderer/despatchadvice/DespatchAdviceTest.java @@ -18,52 +18,45 @@ public class DespatchAdviceTest extends AbstractTest { - @Test - public void testBasicMinData() throws Exception { - // Given - DespatchAdvice input = DespatchAdvice.builder() - .serie("T001") - .numero(1) - .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) - .remitente(Remitente.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .destinatario(Destinatario.builder() - .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) - .numeroDocumentoIdentidad("12345678") - .nombre("mi cliente") - .build() - ) - .envio(Envio.builder() - .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) - .pesoTotal(BigDecimal.ONE) - .pesoTotalUnidadMedida("KG") - .transbordoProgramado(false) - .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) - .fechaTraslado(dateProvider.now()) - .partida(Partida.builder() - .direccion("DireccionOrigen") - .ubigeo("010101") - .build() - ) - .destino(Destino.builder() - .direccion("DireccionDestino") - .ubigeo("020202") - .build() - ) - .build() - ) - .detalle(DespatchAdviceItem.builder() - .cantidad(new BigDecimal("0.5")) - .unidadMedida("KG") - .codigo("123456") - .build() - ) - .build(); + @Test + public void testBasicMinData() throws Exception { + // Given + DespatchAdvice input = DespatchAdvice.builder() + .serie("T001") + .numero(1) + .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) + .remitente(Remitente.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre("mi cliente") + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) + .pesoTotal(BigDecimal.ONE) + .pesoTotalUnidadMedida("KG") + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) + .fechaTraslado(dateProvider.now()) + .partida(Partida.builder() + .direccion("DireccionOrigen") + .ubigeo("010101") + .build()) + .destino(Destino.builder() + .direccion("DireccionDestino") + .ubigeo("020202") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("0.5")) + .unidadMedida("KG") + .codigo("123456") + .build()) + .build(); - assertInput(input, "minData.xml"); - } + assertInput(input, "minData.xml"); + } } diff --git a/xbuilder/core/src/test/java/e2e/renderer/reversion/ReversionTest.java b/xbuilder/core/src/test/java/e2e/renderer/reversion/ReversionTest.java new file mode 100644 index 00000000..cadfb2a7 --- /dev/null +++ b/xbuilder/core/src/test/java/e2e/renderer/reversion/ReversionTest.java @@ -0,0 +1,67 @@ +package e2e.renderer.reversion; + +import e2e.AbstractTest; +import io.github.project.openubl.xbuilder.content.catalogs.Catalog1; +import io.github.project.openubl.xbuilder.content.models.common.Proveedor; +import io.github.project.openubl.xbuilder.content.models.sunat.baja.Reversion; +import io.github.project.openubl.xbuilder.content.models.sunat.baja.VoidedDocumentsItem; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; + +/** + * Test for Reversion (Comunicacion de Baja de Retenciones/Percepciones). + * Reversion uses prefix "RR-" instead of "RA-" for the document ID. + */ +public class ReversionTest extends AbstractTest { + + @Test + public void testReversionWithPerceptions() throws Exception { + // Given - Reverting perceptions (type 40) + Reversion input = Reversion.builder() + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("P001") + .numero(1) + .tipoComprobante(Catalog1.PERCEPCION.getCode()) + .descripcionSustento("Anulacion de percepcion por error en emision") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("P001") + .numero(2) + .tipoComprobante(Catalog1.PERCEPCION.getCode()) + .descripcionSustento("Anulacion de percepcion por duplicado") + .build()) + .build(); + + assertInputReversion(input, "reversion.xml"); + } + + @Test + public void testReversionWithRetentions() throws Exception { + // Given - Reverting retentions (type 20) + Reversion input = Reversion.builder() + .numero(2) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("R001") + .numero(1) + .tipoComprobante(Catalog1.RETENCION.getCode()) + .descripcionSustento("Anulacion de retencion por error en calculo") + .build()) + .build(); + + assertInputReversion(input, "reversion_retention.xml"); + } +} diff --git a/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest/carrierData.xml b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest/carrierData.xml new file mode 100644 index 00000000..5bdcab82 --- /dev/null +++ b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceCarrierTest/carrierData.xml @@ -0,0 +1,122 @@ + + + + + + + + 2.1 + 2.1 + V001-1 + 2019-12-24 + 31 + + 20123456789 + + + 20123456789 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + 20123456789 + + + 20123456789 + + + + MTC-654321 + + + + + + + 20876543210 + + + + + + + + + + 20555555555 + + + + + + + + SUNAT_Envio + 01 + 500.000 + + 01 + + 2019-12-24 + + + 44444444 + Carlos + Guerrero + + L5555555 + + + + + + 150102 + + Tienda Centro + + + + + 150101 + + Almacen Principal + + + + + + + XYZ-789 + + TUC-V001 + + + + + + 1 + 10.00 + + 1 + + + + + PROD-99 + + + + diff --git a/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceComplexTest/complexData.xml b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceComplexTest/complexData.xml new file mode 100644 index 00000000..4bfd1add --- /dev/null +++ b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceComplexTest/complexData.xml @@ -0,0 +1,179 @@ + + + + + + + + 2.1 + 2.1 + T001-100 + 2019-12-24 + 09 + + T001-1 + 09 + GUIA REMISION + + + 20100010001 + + + + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + 12345678912 + + + 12345678912 + + + + + + + + + + 12345678 + + + + + + + + + + 12345678 + + + + + + + + SUNAT_Envio + 01 + Empaque madera + 100.500 + 90.000 + 10 + + 01 + + 2019-12-24 + + + 11111111 + Juan + Perez + CONDUCTOR_PRINCIPAL + + Q1234567 + + + + 22222222 + Jose + Gomez + COPILOTO + + + + + 020202 + 0002 + + Av. Destino 456 + + + + + 010101 + 0001 + + Av. Origen 123 + + + + + + + 1 + CONT-001 + + + + + 2 + CONT-002 + + + + + ABC-123 + + TUC-001 + + + CAR-456 + + TUC-SEC + + + + AUTH-001 + + + + + CALLAO + 1 + Puerto del Callao + + + + 1 + 5.00 + + 1 + + + + + ITEM-01 + + + Color + 1001 + Rojo + + + Marca + 1002 + ToolMaster + + + + diff --git a/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceTest/minData.xml b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceTest/minData.xml index 30aab7f8..e82a1f7c 100644 --- a/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceTest/minData.xml +++ b/xbuilder/core/src/test/resources/e2e/renderer/despatchadvice/DespatchAdviceTest/minData.xml @@ -14,7 +14,7 @@ 2.0 T001-1 2019-12-24 - 09 + 09 12345678912 @@ -53,10 +53,9 @@ - 1 + SUNAT_Envio 18 1.000 - false 02 @@ -70,11 +69,15 @@ DireccionDestino + + + 010101 + + DireccionOrigen + + + - - 010101 - DireccionOrigen - 1 diff --git a/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion.xml b/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion.xml new file mode 100644 index 00000000..65ab4987 --- /dev/null +++ b/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion.xml @@ -0,0 +1,58 @@ + + + + + + + + 2.0 + 1.0 + RR-20220131-1 + 2022-01-29 + 2022-01-31 + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + 12345678912 + 6 + + + + + + + + 1 + 40 + P001 + 1 + Anulacion de percepcion por error en emision + + + 2 + 40 + P001 + 2 + Anulacion de percepcion por duplicado + + diff --git a/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion_retention.xml b/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion_retention.xml new file mode 100644 index 00000000..0464120a --- /dev/null +++ b/xbuilder/core/src/test/resources/e2e/renderer/reversion/ReversionTest/reversion_retention.xml @@ -0,0 +1,51 @@ + + + + + + + + 2.0 + 1.0 + RR-20220131-2 + 2022-01-29 + 2022-01-31 + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + 12345678912 + 6 + + + + + + + + 1 + 20 + R001 + 1 + Anulacion de retencion por error en calculo + + diff --git a/xbuilder/pom.xml b/xbuilder/pom.xml index 25592c3f..08f6c1de 100644 --- a/xbuilder/pom.xml +++ b/xbuilder/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl xhandler-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xbuilder/quarkus-extension/deployment/pom.xml b/xbuilder/quarkus-extension/deployment/pom.xml index 3ab50eba..69e19aeb 100644 --- a/xbuilder/quarkus-extension/deployment/pom.xml +++ b/xbuilder/quarkus-extension/deployment/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xbuilder-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xbuilder-deployment Quarkus Xbuilder - Deployment diff --git a/xbuilder/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xbuilder/deployment/QuarkusXbuilderProcessor.java b/xbuilder/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xbuilder/deployment/QuarkusXbuilderProcessor.java index b8dab8fb..32efa317 100644 --- a/xbuilder/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xbuilder/deployment/QuarkusXbuilderProcessor.java +++ b/xbuilder/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xbuilder/deployment/QuarkusXbuilderProcessor.java @@ -69,10 +69,8 @@ void registerTemplates(BuildProducer resource) thr "templates/ubl/sunat/include/supplier.xml", "templates/ubl/sunat/include/agent-party.xml", - "templates/ubl/sunat/include/receiver-party.xml" - ) - ); - // resource.produce(new NativeImageResourceDirectoryBuildItem("templates")); + "templates/ubl/sunat/include/receiver-party.xml")); + // resource.produce(new NativeImageResourceDirectoryBuildItem("templates")); } @BuildStep @@ -82,14 +80,12 @@ void registerServices(BuildProducer services) throws I // find out all the implementation classes listed in the service files Set implementations = ServiceUtil.classNamesNamedIn( Thread.currentThread().getContextClassLoader(), - service - ); + service); // register every listed implementation class so they can be instantiated // in native-image at run-time services.produce( - new ServiceProviderBuildItem(RuleFactory.class.getName(), implementations.toArray(new String[0])) - ); + new ServiceProviderBuildItem(RuleFactory.class.getName(), implementations.toArray(new String[0]))); } @BuildStep @@ -103,8 +99,7 @@ ReflectiveClassBuildItem reflectionModelsLombok() { "io.github.project.openubl.xbuilder.content.models.sunat.resumen.SummaryDocuments$SummaryDocumentsBuilderImpl", "io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Perception$PerceptionBuilderImpl", - "io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Retention$RetentionBuilderImpl" - ); + "io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Retention$RetentionBuilderImpl"); } @BuildStep @@ -215,8 +210,7 @@ ReflectiveClassBuildItem reflectionJaxbLombok() { "io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplierSunat$Party", "io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplierSunat$PartyLegalEntity", - "io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplierSunat$PartyName" - ); + "io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplierSunat$PartyName"); } @BuildStep @@ -300,6 +294,18 @@ ReflectiveClassBuildItem reflectionModels() { io.github.project.openubl.xbuilder.content.models.standard.guia.Remitente.RemitenteBuilder.class, io.github.project.openubl.xbuilder.content.models.standard.guia.Transportista.class, io.github.project.openubl.xbuilder.content.models.standard.guia.Transportista.TransportistaBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Driver.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Driver.DriverBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Vehicle.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Vehicle.VehicleBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Puerto.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Puerto.PuertoBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.DocumentoAdicional.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.DocumentoAdicional.DocumentoAdicionalBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Tercero.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Tercero.TerceroBuilder.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Comprador.class, + io.github.project.openubl.xbuilder.content.models.standard.guia.Comprador.CompradorBuilder.class, io.github.project.openubl.xbuilder.content.catalogs.Catalog.class, io.github.project.openubl.xbuilder.content.catalogs.CatalogContadoCredito.class, @@ -363,8 +369,7 @@ ReflectiveClassBuildItem reflectionModels() { io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado.class, io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado.ComprobanteAfectadoBuilder.class, io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.PercepcionRetencionOperacion.class, - io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.PercepcionRetencionOperacion.PercepcionRetencionOperacionBuilder.class - ); + io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.PercepcionRetencionOperacion.PercepcionRetencionOperacionBuilder.class); } @BuildStep @@ -425,8 +430,7 @@ ReflectiveClassBuildItem reflectionJaxb() { io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplier.class, io.github.project.openubl.xbuilder.content.jaxb.models.XMLSupplierSunat.class, io.github.project.openubl.xbuilder.content.jaxb.models.XMLVoidedDocuments.class, - io.github.project.openubl.xbuilder.content.jaxb.models.XMLVoidedDocumentsLine.class - ); + io.github.project.openubl.xbuilder.content.jaxb.models.XMLVoidedDocumentsLine.class); } @BuildStep @@ -446,8 +450,7 @@ ReflectiveClassBuildItem mapstruct() { "io.github.project.openubl.xbuilder.content.jaxb.mappers.PerceptionMapperImpl", "io.github.project.openubl.xbuilder.content.jaxb.mappers.RetentionMapperImpl", "io.github.project.openubl.xbuilder.content.jaxb.mappers.SummaryDocumentsMapperImpl", - "io.github.project.openubl.xbuilder.content.jaxb.mappers.VoidedDocumentsMapperImpl" - ); + "io.github.project.openubl.xbuilder.content.jaxb.mappers.VoidedDocumentsMapperImpl"); } @BuildStep @@ -458,7 +461,8 @@ void jaxbRegisterClassesToBeBound(BuildProducer c classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLDebitNote.class.getName()); classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLDespatchAdvice.class.getName()); classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLVoidedDocuments.class.getName()); - classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLSummaryDocuments.class.getName()); + classesToBeBound + .add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLSummaryDocuments.class.getName()); classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLPercepcion.class.getName()); classesToBeBound.add(io.github.project.openubl.xbuilder.content.jaxb.models.XMLRetention.class.getName()); diff --git a/xbuilder/quarkus-extension/integration-tests/pom.xml b/xbuilder/quarkus-extension/integration-tests/pom.xml index 7cff5e83..c2e71ebc 100644 --- a/xbuilder/quarkus-extension/integration-tests/pom.xml +++ b/xbuilder/quarkus-extension/integration-tests/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xbuilder-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xbuilder-integration-tests Quarkus Xbuilder - Integration Tests diff --git a/xbuilder/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResource.java b/xbuilder/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResource.java index a8a46046..7b942c05 100644 --- a/xbuilder/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResource.java +++ b/xbuilder/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResource.java @@ -22,6 +22,7 @@ import io.github.project.openubl.xbuilder.content.models.standard.general.Invoice; import io.github.project.openubl.xbuilder.content.models.standard.guia.DespatchAdvice; import io.github.project.openubl.xbuilder.content.models.sunat.baja.VoidedDocuments; +import io.github.project.openubl.xbuilder.content.models.sunat.baja.Reversion; import io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Perception; import io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.Retention; import io.github.project.openubl.xbuilder.content.models.sunat.resumen.SummaryDocuments; @@ -42,8 +43,6 @@ import jakarta.xml.bind.Unmarshaller; import java.io.IOException; import java.io.StringReader; -import java.nio.file.Files; -import java.nio.file.Paths; import java.time.LocalDate; import static io.github.project.openubl.quarkus.xbuilder.XBuilder.Type.CREDIT_NOTE; @@ -54,6 +53,7 @@ import static io.github.project.openubl.quarkus.xbuilder.XBuilder.Type.RETENTION; import static io.github.project.openubl.quarkus.xbuilder.XBuilder.Type.SUMMARY_DOCUMENTS; import static io.github.project.openubl.quarkus.xbuilder.XBuilder.Type.VOIDED_DOCUMENTS; +import static io.github.project.openubl.quarkus.xbuilder.XBuilder.Type.REVERSION; @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.TEXT_PLAIN) @@ -71,7 +71,8 @@ public class QuarkusXbuilderResource { private static final CreditNoteMapper creditNoteMapper = Mappers.getMapper(CreditNoteMapper.class); private static final DebitNoteMapper debitNoteMapper = Mappers.getMapper(DebitNoteMapper.class); private static final VoidedDocumentsMapper voidedDocumentsMapper = Mappers.getMapper(VoidedDocumentsMapper.class); - private static final SummaryDocumentsMapper summaryDocumentsMapper = Mappers.getMapper(SummaryDocumentsMapper.class); + private static final SummaryDocumentsMapper summaryDocumentsMapper = Mappers + .getMapper(SummaryDocumentsMapper.class); private static final PerceptionMapper perceptionMapper = Mappers.getMapper(PerceptionMapper.class); private static final RetentionMapper retentionMapper = Mappers.getMapper(RetentionMapper.class); private static final DespatchAdviceMapper despatchAdviceMapper = Mappers.getMapper(DespatchAdviceMapper.class); @@ -291,4 +292,31 @@ public String createDespatchAdviceXml(String xml) { throw new RuntimeException(e); } } + + @POST + @Path("Reversion/from-json") + public String createReversion(JsonObject json) { + Reversion reversion = json.mapTo(Reversion.class); + + ContentEnricher enricher = new ContentEnricher(xBuilder.getDefaults(), () -> LocalDate.of(2022, 1, 25)); + enricher.enrich(reversion); + + Template template = xBuilder.getTemplate(REVERSION); + return template.data(reversion).render(); + } + + @POST + @Consumes(MediaType.TEXT_PLAIN) + @Path("Reversion/from-xml") + public String createReversionXml(String xml) { + Template template = xBuilder.getTemplate(REVERSION); + + try (StringReader reader = new StringReader(xml)) { + XMLVoidedDocuments xmlPojo = (XMLVoidedDocuments) unmarshaller.unmarshal(new InputSource(reader)); + VoidedDocuments inputFromXml = voidedDocumentsMapper.map(xmlPojo); + return template.data(inputFromXml).render(); + } catch (JAXBException e) { + throw new RuntimeException(e); + } + } } diff --git a/xbuilder/quarkus-extension/integration-tests/src/test/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResourceTest.java b/xbuilder/quarkus-extension/integration-tests/src/test/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResourceTest.java index 8f71fc6c..6c251524 100644 --- a/xbuilder/quarkus-extension/integration-tests/src/test/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResourceTest.java +++ b/xbuilder/quarkus-extension/integration-tests/src/test/java/io/github/project/openubl/quarkus/xbuilder/it/QuarkusXbuilderResourceTest.java @@ -58,1218 +58,1547 @@ @QuarkusTest public class QuarkusXbuilderResourceTest { - public YAMLMapper getYamlMapper() { - YAMLMapper mapper = new YAMLMapper(new YAMLFactory()); - mapper.registerModule(new JavaTimeModule()); - mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); - mapper.configure(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE, true); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - return mapper; - } + public YAMLMapper getYamlMapper() { + YAMLMapper mapper = new YAMLMapper(new YAMLFactory()); + mapper.registerModule(new JavaTimeModule()); + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE, true); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper; + } - @Test - public void testAllYamlFilesFromSnapshot() throws URISyntaxException, IOException { - YAMLMapper yamlMapper = getYamlMapper(); + @Test + public void testAllYamlFilesFromSnapshot() throws URISyntaxException, IOException { + YAMLMapper yamlMapper = getYamlMapper(); - URL url = getClass().getClassLoader().getResource("e2e"); - Path path = Paths.get(url.toURI()); - Files.walk(path, 5) - .filter(p -> !p.toFile().isDirectory()) - .forEach(p -> { - try { - Map jsonObject = yamlMapper.readValue(p.toFile(), Map.class); - String kind = (String) jsonObject.get("kind"); - String snapshot = (String) jsonObject.get("snapshot"); - Map input = (Map) jsonObject.get("input"); + URL url = getClass().getClassLoader().getResource("e2e"); + Path path = Paths.get(url.toURI()); + Files.walk(path, 5) + .filter(p -> !p.toFile().isDirectory()) + .forEach(p -> { + try { + Map jsonObject = yamlMapper.readValue(p.toFile(), + Map.class); + String kind = (String) jsonObject.get("kind"); + String snapshot = (String) jsonObject.get("snapshot"); + Map input = (Map) jsonObject + .get("input"); - given() + given() + .when() + .contentType(ContentType.JSON) + .body(input) + .post("/quarkus-xbuilder/" + kind + "/from-json") + .then() + .statusCode(200) + .body(is(snapshot)); + + given() + .when() + .contentType(ContentType.TEXT) + .body(snapshot) + .post("/quarkus-xbuilder/" + kind + "/from-xml") + .then() + .statusCode(200) + .body(is(snapshot)); + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + + @Test + public void testInvoice() { + Invoice invoice = Invoice.builder() + .serie("F001") + .numero(1) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .build()) + .build(); + + given() .when() .contentType(ContentType.JSON) - .body(input) - .post("/quarkus-xbuilder/" + kind + "/from-json") + .body(invoice) + .post("/quarkus-xbuilder/Invoice/from-json") .then() .statusCode(200) - .body(is(snapshot)); + .body(is( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.1\n" + + " 2.0\n" + + " F001-1\n" + + " 2022-01-25\n" + + " 01\n" + + + " PEN\n" + + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " 0000\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12121212121\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " FormaPago\n" + + " Contado\n" + + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1000.00\n" + + + " 1200.00\n" + + + " 0\n" + + + " 0\n" + + + " 1200.00\n" + + + " \n" + + " \n" + + " 1\n" + + " 10\n" + + + " 1000.00\n" + + + " \n" + + " \n" + + " 120.00\n" + + + " 01\n" + + + " \n" + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " 20.00\n" + + + " 10\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " 100.00\n" + + + " \n" + + " \n" + + "\n")); + } + + @Test + public void testCreditNote() { + CreditNote creditNote = CreditNote.builder() + .serie("FC01") + .numero(1) + .comprobanteAfectadoSerieNumero("F001-1") + .sustentoDescripcion("mi sustento") + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .build()) + .build(); - given() + given() .when() - .contentType(ContentType.TEXT) - .body(snapshot) - .post("/quarkus-xbuilder/" + kind + "/from-xml") + .contentType(ContentType.JSON) + .body(creditNote) + .post("/quarkus-xbuilder/CreditNote/from-json") .then() .statusCode(200) - .body(is(snapshot)); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - - @Test - public void testInvoice() { - Invoice invoice = Invoice.builder() - .serie("F001") - .numero(1) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.toString()) - .build() - ) - .detalle(DocumentoVentaDetalle.builder() - .descripcion("Item1") - .cantidad(new BigDecimal("10")) - .precio(new BigDecimal("100")) - .build() - ) - .build(); - - given() - .when() - .contentType(ContentType.JSON) - .body(invoice) - .post("/quarkus-xbuilder/Invoice/from-json") - .then() - .statusCode(200) - .body(is( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.1\n" + - " 2.0\n" + - " F001-1\n" + - " 2022-01-25\n" + - " 01\n" + - " PEN\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0000\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12121212121\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " FormaPago\n" + - " Contado\n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1000.00\n" + - " 1200.00\n" + - " 0\n" + - " 0\n" + - " 1200.00\n" + - " \n" + - " \n" + - " 1\n" + - " 10\n" + - " 1000.00\n" + - " \n" + - " \n" + - " 120.00\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " 20.00\n" + - " 10\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 100.00\n" + - " \n" + - " \n" + - "\n" - ) - ); - } + .body(is( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.1\n" + + " 2.0\n" + + " FC01-1\n" + + " 2022-01-25\n" + + " PEN\n" + + + " \n" + + " F001-1\n" + + " 01\n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " F001-1\n" + + " 01\n" + + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " 0000\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12121212121\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1000.00\n" + + + " 1200.00\n" + + + " 1200.00\n" + + + " \n" + + " \n" + + " 1\n" + + " 10\n" + + + " 1000.00\n" + + + " \n" + + " \n" + + " 120.00\n" + + + " 01\n" + + + " \n" + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " 20.00\n" + + + " 10\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " 100.00\n" + + + " \n" + + " \n" + + "\n")); + } - @Test - public void testCreditNote() { - CreditNote creditNote = CreditNote.builder() - .serie("FC01") - .numero(1) - .comprobanteAfectadoSerieNumero("F001-1") - .sustentoDescripcion("mi sustento") - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.toString()) - .build() - ) - .detalle(DocumentoVentaDetalle.builder() - .descripcion("Item1") - .cantidad(new BigDecimal("10")) - .precio(new BigDecimal("100")) - .build() - ) - .build(); + @Test + public void testDebitNote() { + DebitNote debitNote = DebitNote.builder() + .serie("FD01") + .numero(1) + .comprobanteAfectadoSerieNumero("F001-1") + .sustentoDescripcion("mi sustento") + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.toString()) + .build()) + .detalle(DocumentoVentaDetalle.builder() + .descripcion("Item1") + .cantidad(new BigDecimal("10")) + .precio(new BigDecimal("100")) + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(creditNote) - .post("/quarkus-xbuilder/CreditNote/from-json") - .then() - .statusCode(200) - .body(is( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.1\n" + - " 2.0\n" + - " FC01-1\n" + - " 2022-01-25\n" + - " PEN\n" + - " \n" + - " F001-1\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " F001-1\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0000\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12121212121\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1000.00\n" + - " 1200.00\n" + - " 1200.00\n" + - " \n" + - " \n" + - " 1\n" + - " 10\n" + - " 1000.00\n" + - " \n" + - " \n" + - " 120.00\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " 20.00\n" + - " 10\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 100.00\n" + - " \n" + - " \n" + - "\n" - ) - ); - } + given() + .when() + .contentType(ContentType.JSON) + .body(debitNote) + .post("/quarkus-xbuilder/DebitNote/from-json") + .then() + .statusCode(200) + .body(is( + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.1\n" + + " 2.0\n" + + " FD01-1\n" + + " 2022-01-25\n" + + " PEN\n" + + + " \n" + + " F001-1\n" + + " 01\n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " F001-1\n" + + " 01\n" + + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " 0000\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12121212121\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1000.00\n" + + + " 1200.00\n" + + + " 1200.00\n" + + + " \n" + + " \n" + + " 1\n" + + " 10\n" + + + " 1000.00\n" + + + " \n" + + " \n" + + " 120.00\n" + + + " 01\n" + + + " \n" + + " \n" + + " \n" + + " 200.00\n" + + + " \n" + + " 1000.00\n" + + + " 200.00\n" + + + " \n" + + " S\n" + + + " 20.00\n" + + + " 10\n" + + + " \n" + + " 1000\n" + + + " IGV\n" + + " VAT\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " 100.00\n" + + + " \n" + + " \n" + + "\n")); + } - @Test - public void testDebitNote() { - DebitNote debitNote = DebitNote.builder() - .serie("FD01") - .numero(1) - .comprobanteAfectadoSerieNumero("F001-1") - .sustentoDescripcion("mi sustento") - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.toString()) - .build() - ) - .detalle(DocumentoVentaDetalle.builder() - .descripcion("Item1") - .cantidad(new BigDecimal("10")) - .precio(new BigDecimal("100")) - .build() - ) - .build(); + @Test + public void testVoidedDocuments() { + VoidedDocuments voidedDocuments = VoidedDocuments.builder() + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("F001") + .numero(1) + .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) + .descripcionSustento("Mi sustento1") + .build()) + .comprobante(VoidedDocumentsItem.builder() + .serie("F001") + .numero(2) + .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) + .descripcionSustento("Mi sustento2") + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(debitNote) - .post("/quarkus-xbuilder/DebitNote/from-json") - .then() - .statusCode(200) - .body(is( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.1\n" + - " 2.0\n" + - " FD01-1\n" + - " 2022-01-25\n" + - " PEN\n" + - " \n" + - " F001-1\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " F001-1\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 0000\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12121212121\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1000.00\n" + - " 1200.00\n" + - " 1200.00\n" + - " \n" + - " \n" + - " 1\n" + - " 10\n" + - " 1000.00\n" + - " \n" + - " \n" + - " 120.00\n" + - " 01\n" + - " \n" + - " \n" + - " \n" + - " 200.00\n" + - " \n" + - " 1000.00\n" + - " 200.00\n" + - " \n" + - " S\n" + - " 20.00\n" + - " 10\n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 100.00\n" + - " \n" + - " \n" + - "\n" - ) - ); - } + given() + .when() + .contentType(ContentType.JSON) + .body(voidedDocuments) + .post("/quarkus-xbuilder/VoidedDocuments/from-json") + .then() + .statusCode(200) + .body(is("\n" + + "\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.0\n" + + " 1.0\n" + + " RA-20220131-1\n" + + " 2022-01-29\n" + + " 2022-01-31\n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " 6\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " 01\n" + + " F001\n" + + " 1\n" + + " Mi sustento1\n" + + + " \n" + + " \n" + + " 2\n" + + " 01\n" + + " F001\n" + + " 2\n" + + " Mi sustento2\n" + + + " \n" + + "\n")); + } - @Test - public void testVoidedDocuments() { - VoidedDocuments voidedDocuments = VoidedDocuments.builder() - .numero(1) - .fechaEmision(LocalDate.of(2022, 01, 31)) - .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .comprobante(VoidedDocumentsItem.builder() - .serie("F001") - .numero(1) - .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) - .descripcionSustento("Mi sustento1") - .build() - ) - .comprobante(VoidedDocumentsItem.builder() - .serie("F001") - .numero(2) - .tipoComprobante(Catalog1_Invoice.FACTURA.getCode()) - .descripcionSustento("Mi sustento2") - .build() - ) - .build(); + @Test + public void testSummaryDocuments() { + SummaryDocuments summaryDocuments = SummaryDocuments.builder() + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .comprobante(SummaryDocumentsItem.builder() + .tipoOperacion(Catalog19.ADICIONAR.toString()) + .comprobante(Comprobante.builder() + .tipoComprobante(Catalog1_Invoice.BOLETA.getCode())// + .serieNumero("B001-1") + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12345678") + .tipoDocumentoIdentidad( + Catalog6.DNI.getCode()) + .build()) + .impuestos(ComprobanteImpuestos.builder() + .igv(new BigDecimal("18")) + .icb(new BigDecimal(2)) + .build()) + .valorVenta(ComprobanteValorVenta.builder() + .importeTotal(new BigDecimal("120")) + .gravado(new BigDecimal("120")) + .build()) + .build()) + .build()) + .comprobante(SummaryDocumentsItem.builder() + .tipoOperacion(Catalog19.ADICIONAR.toString()) + .comprobante(Comprobante.builder() + .tipoComprobante(Catalog1.NOTA_CREDITO.getCode()) + .serieNumero("BC02-2") + .comprobanteAfectado(ComprobanteAfectado.builder() + .serieNumero("B002-2") + .tipoComprobante(Catalog1.BOLETA + .getCode()) // + .build()) + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12345678") + .tipoDocumentoIdentidad( + Catalog6.DNI.getCode())// + .build()) + .impuestos(ComprobanteImpuestos.builder() + .igv(new BigDecimal("18")) + .build()) + .valorVenta(ComprobanteValorVenta.builder() + .importeTotal(new BigDecimal("118")) + .gravado(new BigDecimal("118")) + .build()) + .build()) + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(voidedDocuments) - .post("/quarkus-xbuilder/VoidedDocuments/from-json") - .then() - .statusCode(200) - .body(is("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.0\n" + - " 1.0\n" + - " RA-20220131-1\n" + - " 2022-01-29\n" + - " 2022-01-31\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " 6\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " 01\n" + - " F001\n" + - " 1\n" + - " Mi sustento1\n" + - " \n" + - " \n" + - " 2\n" + - " 01\n" + - " F001\n" + - " 2\n" + - " Mi sustento2\n" + - " \n" + - "\n")); - } + given() + .when() + .contentType(ContentType.JSON) + .body(summaryDocuments) + .post("/quarkus-xbuilder/SummaryDocuments/from-json") + .then() + .statusCode(200) + .body(is("\n" + + "\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.0\n" + + " 1.1\n" + + " RC-20220131-1\n" + + " 2022-01-29\n" + + " 2022-01-31\n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " 6\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " 03\n" + + " B001-1\n" + + " \n" + + " 12345678\n" + + + " 1\n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " 120\n" + + " \n" + + " 120\n" + + + " 01\n" + + " \n" + + " \n" + + " 18\n" + + " \n" + + " 18\n" + + + " \n" + + " \n" + + " 1000\n" + + " IGV\n" + + " VAT\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " \n" + + " 2\n" + + + " \n" + + " \n" + + " 7152\n" + + " ICBPER\n" + + " OTH\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2\n" + + " 07\n" + + " BC02-2\n" + + " \n" + + " 12345678\n" + + + " 1\n" + + " \n" + + " \n" + + " \n" + + " B002-2\n" + + " 03\n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " \n" + + " 118\n" + + " \n" + + " 118\n" + + + " 01\n" + + " \n" + + " \n" + + " 18\n" + + " \n" + + " 18\n" + + + " \n" + + " \n" + + " 1000\n" + + " IGV\n" + + " VAT\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n")); + } - @Test - public void testSummaryDocuments() { - SummaryDocuments summaryDocuments = SummaryDocuments.builder() - .numero(1) - .fechaEmision(LocalDate.of(2022, 01, 31)) - .fechaEmisionComprobantes(LocalDate.of(2022, 01, 29)) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .comprobante(SummaryDocumentsItem.builder() - .tipoOperacion(Catalog19.ADICIONAR.toString()) - .comprobante(Comprobante.builder() - .tipoComprobante(Catalog1_Invoice.BOLETA.getCode())// - .serieNumero("B001-1") - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12345678") - .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) - .build() - ) - .impuestos(ComprobanteImpuestos.builder() - .igv(new BigDecimal("18")) - .icb(new BigDecimal(2)) - .build() - ) - .valorVenta(ComprobanteValorVenta.builder() - .importeTotal(new BigDecimal("120")) - .gravado(new BigDecimal("120")) - .build() - ) - .build() - ) - .build() - ) - .comprobante(SummaryDocumentsItem.builder() - .tipoOperacion(Catalog19.ADICIONAR.toString()) - .comprobante(Comprobante.builder() - .tipoComprobante(Catalog1.NOTA_CREDITO.getCode()) - .serieNumero("BC02-2") - .comprobanteAfectado(ComprobanteAfectado.builder() - .serieNumero("B002-2") - .tipoComprobante(Catalog1.BOLETA.getCode()) // - .build() - ) + @Test + public void testPerception() { + Perception perception = Perception.builder() + .serie("P001") + .numero(1) + .fechaEmision(LocalDate.of(2022, 01, 31)) + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12345678") - .tipoDocumentoIdentidad(Catalog6.DNI.getCode())// - .build() - ) - .impuestos(ComprobanteImpuestos.builder() - .igv(new BigDecimal("18")) - .build() - ) - .valorVenta(ComprobanteValorVenta.builder() - .importeTotal(new BigDecimal("118")) - .gravado(new BigDecimal("118")) - .build() - ) - .build() - ) - .build() - ) - .build(); + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .build()) + .importeTotalPercibido(new BigDecimal("10")) + .importeTotalCobrado(new BigDecimal("210")) + .tipoRegimen(Catalog22.VENTA_INTERNA.getCode()) + .tipoRegimenPorcentaje(Catalog22.VENTA_INTERNA.getPercent()) // + .operacion(PercepcionRetencionOperacion.builder() + .numeroOperacion(1) + .fechaOperacion(LocalDate.of(2022, 01, 31)) + .importeOperacion(new BigDecimal("100")) + .comprobante( + io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado + .builder() + .tipoComprobante(Catalog1.FACTURA + .getCode()) + .serieNumero("F001-1") + .fechaEmision(LocalDate.of(2022, 01, + 31)) + .importeTotal(new BigDecimal("200")) + .moneda("PEN") + .build()) + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(summaryDocuments) - .post("/quarkus-xbuilder/SummaryDocuments/from-json") - .then() - .statusCode(200) - .body(is("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.0\n" + - " 1.1\n" + - " RC-20220131-1\n" + - " 2022-01-29\n" + - " 2022-01-31\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " 6\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " 03\n" + - " B001-1\n" + - " \n" + - " 12345678\n" + - " 1\n" + - " \n" + - " \n" + - " 1\n" + - " \n" + - " 120\n" + - " \n" + - " 120\n" + - " 01\n" + - " \n" + - " \n" + - " 18\n" + - " \n" + - " 18\n" + - " \n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2\n" + - " \n" + - " 2\n" + - " \n" + - " \n" + - " 7152\n" + - " ICBPER\n" + - " OTH\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2\n" + - " 07\n" + - " BC02-2\n" + - " \n" + - " 12345678\n" + - " 1\n" + - " \n" + - " \n" + - " \n" + - " B002-2\n" + - " 03\n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " \n" + - " 118\n" + - " \n" + - " 118\n" + - " 01\n" + - " \n" + - " \n" + - " 18\n" + - " \n" + - " 18\n" + - " \n" + - " \n" + - " 1000\n" + - " IGV\n" + - " VAT\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - "\n")); - } + given() + .when() + .contentType(ContentType.JSON) + .body(perception) + .post("/quarkus-xbuilder/Perception/from-json") + .then() + .statusCode(200) + .body(is("\n" + + "\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.0\n" + + " 1.0\n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + " \n" + + " \n" + + " \n" + + " P001-1\n" + + " 2022-01-31\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 12121212121\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " 01\n" + + + " 2\n" + + " 10\n" + + + " 210\n" + + + " \n" + + " F001-1\n" + + " 2022-01-31\n" + + " 200\n" + + + " \n" + + " 1\n" + + " 100\n" + + + " 2022-01-31\n" + + " \n" + + " \n" + + " 10\n" + + + " 2022-01-31\n" + + + " 210\n" + + + " \n" + + " \n" + + "\n")); + } - @Test - public void testPerception() { - Perception perception = Perception.builder() - .serie("P001") - .numero(1) - .fechaEmision(LocalDate.of(2022, 01, 31)) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) - .build() - ) - .importeTotalPercibido(new BigDecimal("10")) - .importeTotalCobrado(new BigDecimal("210")) - .tipoRegimen(Catalog22.VENTA_INTERNA.getCode()) - .tipoRegimenPorcentaje(Catalog22.VENTA_INTERNA.getPercent()) // - .operacion(PercepcionRetencionOperacion.builder() - .numeroOperacion(1) - .fechaOperacion(LocalDate.of(2022, 01, 31)) - .importeOperacion(new BigDecimal("100")) - .comprobante(io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado.builder() - .tipoComprobante(Catalog1.FACTURA.getCode()) - .serieNumero("F001-1") + @Test + public void testRetention() { + Retention retention = Retention.builder() + .serie("R001") + .numero(1) .fechaEmision(LocalDate.of(2022, 01, 31)) - .importeTotal(new BigDecimal("200")) - .moneda("PEN") - .build() - ) - .build() - ) - .build(); + .proveedor(Proveedor.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .cliente(Cliente.builder() + .nombre("Carlos Feria") + .numeroDocumentoIdentidad("12121212121") + .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) + .build()) + .importeTotalRetenido(new BigDecimal("10")) + .importeTotalPagado(new BigDecimal("200")) + .tipoRegimen(Catalog23.TASA_TRES.getCode()) + .tipoRegimenPorcentaje(Catalog23.TASA_TRES.getPercent()) // + .operacion(PercepcionRetencionOperacion.builder() + .numeroOperacion(1) + .fechaOperacion(LocalDate.of(2022, 01, 31)) + .importeOperacion(new BigDecimal("100")) + .comprobante( + io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado + .builder() + .tipoComprobante(Catalog1.FACTURA + .getCode()) + .serieNumero("F001-1") + .fechaEmision(LocalDate.of(2022, 01, + 31)) + .importeTotal(new BigDecimal("210")) + .moneda("PEN") + .build()) + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(perception) - .post("/quarkus-xbuilder/Perception/from-json") - .then() - .statusCode(200) - .body(is("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.0\n" + - " 1.0\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " P001-1\n" + - " 2022-01-31\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12121212121\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 01\n" + - " 2\n" + - " 10\n" + - " 210\n" + - " \n" + - " F001-1\n" + - " 2022-01-31\n" + - " 200\n" + - " \n" + - " 1\n" + - " 100\n" + - " 2022-01-31\n" + - " \n" + - " \n" + - " 10\n" + - " 2022-01-31\n" + - " 210\n" + - " \n" + - " \n" + - "\n")); - } + given() + .when() + .contentType(ContentType.JSON) + .body(retention) + .post("/quarkus-xbuilder/Retention/from-json") + .then() + .statusCode(200) + .body(is("\n" + + "\n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.0\n" + + " 1.0\n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + " \n" + + " \n" + + " \n" + + " R001-1\n" + + " 2022-01-31\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " 12121212121\n" + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " 01\n" + + + " 3\n" + + " 10\n" + + + " 200\n" + + + " \n" + + " F001-1\n" + + " 2022-01-31\n" + + " 210\n" + + + " \n" + + " 1\n" + + " 100\n" + + + " 2022-01-31\n" + + " \n" + + " \n" + + " 10\n" + + + " 2022-01-31\n" + + + " 200\n" + + + " \n" + + " \n" + + "\n")); + } - @Test - public void testRetention() { - Retention retention = Retention.builder() - .serie("R001") - .numero(1) - .fechaEmision(LocalDate.of(2022, 01, 31)) - .proveedor(Proveedor.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .cliente(Cliente.builder() - .nombre("Carlos Feria") - .numeroDocumentoIdentidad("12121212121") - .tipoDocumentoIdentidad(Catalog6.RUC.getCode()) - .build() - ) - .importeTotalRetenido(new BigDecimal("10")) - .importeTotalPagado(new BigDecimal("200")) - .tipoRegimen(Catalog23.TASA_TRES.getCode()) - .tipoRegimenPorcentaje(Catalog23.TASA_TRES.getPercent()) // - .operacion(PercepcionRetencionOperacion.builder() - .numeroOperacion(1) - .fechaOperacion(LocalDate.of(2022, 01, 31)) - .importeOperacion(new BigDecimal("100")) - .comprobante(io.github.project.openubl.xbuilder.content.models.sunat.percepcionretencion.ComprobanteAfectado.builder() - .tipoComprobante(Catalog1.FACTURA.getCode()) - .serieNumero("F001-1") - .fechaEmision(LocalDate.of(2022, 01, 31)) - .importeTotal(new BigDecimal("210")) - .moneda("PEN") - .build() - ) - .build() - ) - .build(); + @Test + public void testDespatchAdvice() { + DespatchAdvice despatchAdvice = DespatchAdvice.builder() + .serie("T001") + .numero(1) + .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) + .remitente(Remitente.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre("mi cliente") + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) + .pesoTotal(BigDecimal.ONE) + .pesoTotalUnidadMedida("KG") + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) + .fechaTraslado(LocalDate.of(2022, 1, 25)) + .partida(Partida.builder() + .direccion("DireccionOrigen") + .ubigeo("010101") + .build()) + .destino(Destino.builder() + .direccion("DireccionDestino") + .ubigeo("020202") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("0.5")) + .unidadMedida("KG") + .codigo("123456") + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(retention) - .post("/quarkus-xbuilder/Retention/from-json") - .then() - .statusCode(200) - .body(is("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.0\n" + - " 1.0\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " R001-1\n" + - " 2022-01-31\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12121212121\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 01\n" + - " 3\n" + - " 10\n" + - " 200\n" + - " \n" + - " F001-1\n" + - " 2022-01-31\n" + - " 210\n" + - " \n" + - " 1\n" + - " 100\n" + - " 2022-01-31\n" + - " \n" + - " \n" + - " 10\n" + - " 2022-01-31\n" + - " 200\n" + - " \n" + - " \n" + - "\n")); - } + given() + .when() + .contentType(ContentType.JSON) + .body(despatchAdvice) + .post("/quarkus-xbuilder/DespatchAdvice/from-json") + .then() + .statusCode(200) + .body(is("\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 2.1\n" + + " 2.0\n" + + " T001-1\n" + + " 2022-01-25\n" + + " 09\n" + + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " 12345678912\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " #PROJECT-OPENUBL-SIGN\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678912\n" + + + " \n" + + " \n" + + " 12345678912\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 12345678\n" + + + " \n" + + " \n" + + " \n" + + + " \n" + + " \n" + + " \n" + + " \n" + + " SUNAT_Envio\n" + + " 18\n" + + + " 1.000\n" + + + " \n" + + " 02\n" + + + " \n" + + " 2022-01-25\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 020202\n" + + + " \n" + + " DireccionDestino\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 010101\n" + + + " \n" + + " DireccionOrigen\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " 1\n" + + " 0.5\n" + + + " \n" + + " 1\n" + + " \n" + + " \n" + + " \n" + + " 123456\n" + + " \n" + + " \n" + + " \n" + + "\n")); + } - @Test - public void testDespatchAdvice() { - DespatchAdvice despatchAdvice = DespatchAdvice.builder() - .serie("T001") - .numero(1) - .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) - .remitente(Remitente.builder() - .ruc("12345678912") - .razonSocial("Softgreen S.A.C.") - .build() - ) - .destinatario(Destinatario.builder() - .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) - .numeroDocumentoIdentidad("12345678") - .nombre("mi cliente") - .build() - ) - .envio(Envio.builder() - .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) - .pesoTotal(BigDecimal.ONE) - .pesoTotalUnidadMedida("KG") - .transbordoProgramado(false) - .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) - .fechaTraslado(LocalDate.of(2022, 1, 25)) - .partida(Partida.builder() - .direccion("DireccionOrigen") - .ubigeo("010101") - .build() - ) - .destino(Destino.builder() - .direccion("DireccionDestino") - .ubigeo("020202") - .build() - ) - .build() - ) - .detalle(DespatchAdviceItem.builder() - .cantidad(new BigDecimal("0.5")) - .unidadMedida("KG") - .codigo("123456") - .build() - ) - .build(); + @Test + public void testDespatchAdvice2() { + DespatchAdvice despatchAdvice = DespatchAdvice.builder() + .serie("T001") + .numero(1) + .tipoComprobante(Catalog1.GUIA_REMISION_REMITENTE.getCode()) + .remitente(Remitente.builder() + .ruc("12345678912") + .razonSocial("Softgreen S.A.C.") + .build()) + .destinatario(Destinatario.builder() + .tipoDocumentoIdentidad(Catalog6.DNI.getCode()) + .numeroDocumentoIdentidad("12345678") + .nombre("mi cliente") + .build()) + .envio(Envio.builder() + .tipoTraslado(Catalog20.TRASLADO_EMISOR_ITINERANTE_CP.getCode()) + .pesoTotal(BigDecimal.ONE) + .pesoTotalUnidadMedida("KG") + .tipoModalidadTraslado(Catalog18.TRANSPORTE_PRIVADO.getCode()) + .fechaTraslado(LocalDate.of(2022, 1, 25)) + .partida(Partida.builder() + .direccion("DireccionOrigen") + .ubigeo("010101") + .build()) + .destino(Destino.builder() + .direccion("DireccionDestino") + .ubigeo("020202") + .build()) + .build()) + .detalle(DespatchAdviceItem.builder() + .cantidad(new BigDecimal("0.5")) + .unidadMedida("KG") + .codigo("123456") + .build()) + .build(); - given() - .when() - .contentType(ContentType.JSON) - .body(despatchAdvice) - .post("/quarkus-xbuilder/DespatchAdvice/from-json") - .then() - .statusCode(200) - .body(is("\n" + - "\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 2.1\n" + - " 2.0\n" + - " T001-1\n" + - " 2022-01-25\n" + - " 09\n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " #PROJECT-OPENUBL-SIGN\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " 12345678912\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 12345678\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " 18\n" + - " 1.000\n" + - " false\n" + - " \n" + - " 02\n" + - " \n" + - " 2022-01-25\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 020202\n" + - " \n" + - " DireccionDestino\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " 010101\n" + - " DireccionOrigen\n" + - " \n" + - " \n" + - " \n" + - " 1\n" + - " 0.5\n" + - " \n" + - " 1\n" + - " \n" + - " \n" + - " \n" + - " 123456\n" + - " \n" + - " \n" + - " \n" + - "\n")); - } + given() + .when() + .contentType(ContentType.JSON) + .body(despatchAdvice) + .post("/quarkus-xbuilder/DespatchAdvice/from-json") + .then() + .statusCode(200) + .body(is( + """ + + + + + + + + 2.1 + 2.0 + T001-1 + 2022-01-25 + 09 + + 12345678912 + + + 12345678912 + + + + + + + + #PROJECT-OPENUBL-SIGN + + + + + 12345678912 + + + 12345678912 + + + + + + + + + + 12345678 + + + + + + + + SUNAT_Envio + 18 + 1.000 + + 02 + + 2022-01-25 + + + + + 020202 + + DireccionDestino + + + + + 010101 + + DireccionOrigen + + + + + + + 1 + 0.5 + + 1 + + + + 123456 + + + + + """)); + } } diff --git a/xbuilder/quarkus-extension/pom.xml b/xbuilder/quarkus-extension/pom.xml index d7c7def2..d685aa92 100644 --- a/xbuilder/quarkus-extension/pom.xml +++ b/xbuilder/quarkus-extension/pom.xml @@ -7,7 +7,7 @@ io.github.project-openubl xbuilder-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xbuilder/quarkus-extension/runtime/pom.xml b/xbuilder/quarkus-extension/runtime/pom.xml index 97fc9b28..8319dcf1 100644 --- a/xbuilder/quarkus-extension/runtime/pom.xml +++ b/xbuilder/quarkus-extension/runtime/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xbuilder-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xbuilder Quarkus Xbuilder - Runtime diff --git a/xbuilder/quarkus-extension/runtime/src/main/java/io/github/project/openubl/quarkus/xbuilder/XBuilder.java b/xbuilder/quarkus-extension/runtime/src/main/java/io/github/project/openubl/quarkus/xbuilder/XBuilder.java index 4db2edb6..e16ab53b 100644 --- a/xbuilder/quarkus-extension/runtime/src/main/java/io/github/project/openubl/quarkus/xbuilder/XBuilder.java +++ b/xbuilder/quarkus-extension/runtime/src/main/java/io/github/project/openubl/quarkus/xbuilder/XBuilder.java @@ -16,7 +16,8 @@ enum Type { SUMMARY_DOCUMENTS("summaryDocuments.xml"), PERCEPTION("perception.xml"), RETENTION("retention.xml"), - DESPATCH_ADVICE("despatchAdvice.xml"); + DESPATCH_ADVICE("despatchAdvice.xml"), + REVERSION("reversion.xml"); private final String templatePath; diff --git a/xsender/core/pom.xml b/xsender/core/pom.xml index 2d912e48..fe93d097 100644 --- a/xsender/core/pom.xml +++ b/xsender/core/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xsender/pom.xml b/xsender/pom.xml index 80ba4b5f..2cd668a7 100644 --- a/xsender/pom.xml +++ b/xsender/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl xhandler-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xsender/quarkus-extension/deployment/pom.xml b/xsender/quarkus-extension/deployment/pom.xml index fc37dbd5..cc3414e4 100644 --- a/xsender/quarkus-extension/deployment/pom.xml +++ b/xsender/quarkus-extension/deployment/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xsender-deployment Quarkus XSender - Deployment diff --git a/xsender/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xsender/deployment/QuarkusXsenderProcessor.java b/xsender/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xsender/deployment/QuarkusXsenderProcessor.java index 205a325b..67f4db39 100644 --- a/xsender/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xsender/deployment/QuarkusXsenderProcessor.java +++ b/xsender/quarkus-extension/deployment/src/main/java/io/github/project/openubl/quarkus/xsender/deployment/QuarkusXsenderProcessor.java @@ -1,7 +1,33 @@ package io.github.project.openubl.quarkus.xsender.deployment; import io.github.project.openubl.quarkus.xsender.XSender; -import io.github.project.openubl.xsender.camel.routes.SunatRouteBuilder; +import io.github.project.openubl.xsender.Constants; +import io.github.project.openubl.xsender.camel.routes.*; +import io.github.project.openubl.xsender.camel.utils.CamelData; +import io.github.project.openubl.xsender.camel.utils.CamelUtils; +import io.github.project.openubl.xsender.company.CompanyCredentials; +import io.github.project.openubl.xsender.company.CompanyURLs; +import io.github.project.openubl.xsender.files.BillServiceFileAnalyzer; +import io.github.project.openubl.xsender.files.BillServiceXMLFileAnalyzer; +import io.github.project.openubl.xsender.files.ZipFile; +import io.github.project.openubl.xsender.files.exceptions.UnsupportedXMLFileException; +import io.github.project.openubl.xsender.files.xml.DocumentType; +import io.github.project.openubl.xsender.files.xml.XmlContent; +import io.github.project.openubl.xsender.files.xml.XmlContentProvider; +import io.github.project.openubl.xsender.files.xml.XmlHandler; +import io.github.project.openubl.xsender.models.Metadata; +import io.github.project.openubl.xsender.models.Status; +import io.github.project.openubl.xsender.models.Sunat; +import io.github.project.openubl.xsender.models.SunatResponse; +import io.github.project.openubl.xsender.models.rest.PayloadDocumentDto; +import io.github.project.openubl.xsender.models.rest.ResponseAccessTokenSuccessDto; +import io.github.project.openubl.xsender.models.rest.ResponseDocumentErrorDto; +import io.github.project.openubl.xsender.models.rest.ResponseDocumentSuccessDto; +import io.github.project.openubl.xsender.sunat.BillConsultServiceDestination; +import io.github.project.openubl.xsender.sunat.BillServiceDestination; +import io.github.project.openubl.xsender.sunat.catalog.Catalog1; +import io.github.project.openubl.xsender.utils.ByteUtils; +import io.github.project.openubl.xsender.utils.CdrReader; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.processor.DotNames; import io.quarkus.deployment.annotations.BuildProducer; @@ -9,6 +35,9 @@ import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; +import org.apache.camel.http.base.HttpOperationFailedException; +import org.apache.cxf.binding.soap.SoapFault; +import org.apache.cxf.transport.http.HTTPException; import java.net.URISyntaxException; @@ -33,107 +62,87 @@ AdditionalBeanBuildItem additionalBeans() { @BuildStep void registerTemplates(BuildProducer resource) throws URISyntaxException { - resource.produce( - new NativeImageResourceBuildItem( - "wsdl/billService.wsdl", - "wsdl/billConsultService.wsdl", - "wsdl/billValidService.wsdl" - ) - ); + resource.produce(new NativeImageResourceBuildItem( + "wsdl/billService.wsdl", + "wsdl/billConsultService.wsdl", + "wsdl/billValidService.wsdl")); } @BuildStep ReflectiveClassBuildItem projectReflection() { - return new ReflectiveClassBuildItem( - true, - false, - io.github.project.openubl.xsender.Constants.class, - io.github.project.openubl.xsender.camel.routes.CxfEndpointConfiguration.class, - io.github.project.openubl.xsender.camel.routes.RestSunatErrorResponseProcessor.class, - io.github.project.openubl.xsender.camel.routes.RestSunatResponseProcessor.class, - io.github.project.openubl.xsender.camel.routes.SunatRouteBuilder.class, - io.github.project.openubl.xsender.camel.routes.SoapSunatErrorResponseProcessor.class, - io.github.project.openubl.xsender.camel.routes.SoapSunatResponseProcessor.class, - io.github.project.openubl.xsender.camel.routes.TicketResponseType.class, - - io.github.project.openubl.xsender.camel.utils.CamelData.class, - io.github.project.openubl.xsender.camel.utils.CamelData.CamelDataBuilder.class, - io.github.project.openubl.xsender.camel.utils.CamelUtils.class, - - io.github.project.openubl.xsender.company.CompanyCredentials.class, - io.github.project.openubl.xsender.company.CompanyCredentials.CompanyCredentialsBuilder.class, - io.github.project.openubl.xsender.company.CompanyURLs.class, - io.github.project.openubl.xsender.company.CompanyURLs.CompanyURLsBuilder.class, - - io.github.project.openubl.xsender.files.BillServiceFileAnalyzer.class, - io.github.project.openubl.xsender.files.BillServiceXMLFileAnalyzer.class, - io.github.project.openubl.xsender.files.ZipFile.class, - io.github.project.openubl.xsender.files.ZipFile.ZipFileBuilder.class, - io.github.project.openubl.xsender.files.exceptions.UnsupportedXMLFileException.class, - io.github.project.openubl.xsender.files.xml.DocumentType.class, - io.github.project.openubl.xsender.files.xml.XmlContent.class, - io.github.project.openubl.xsender.files.xml.XmlContentProvider.class, - io.github.project.openubl.xsender.files.xml.XmlHandler.class, - - io.github.project.openubl.xsender.models.rest.PayloadDocumentDto.class, - io.github.project.openubl.xsender.models.rest.PayloadDocumentDto.PayloadDocumentDtoBuilder.class, - io.github.project.openubl.xsender.models.rest.PayloadDocumentDto.Archivo.class, - io.github.project.openubl.xsender.models.rest.PayloadDocumentDto.Archivo.ArchivoBuilder.class, - io.github.project.openubl.xsender.models.rest.ResponseAccessTokenSuccessDto.class, - io.github.project.openubl.xsender.models.rest.ResponseAccessTokenSuccessDto.ResponseAccessTokenSuccessDtoBuilder.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentErrorDto.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentErrorDto.ResponseDocumentErrorDtoBuilder.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentErrorDto.Error.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentErrorDto.Error.ErrorBuilder.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentSuccessDto.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentSuccessDto.ResponseDocumentSuccessDtoBuilder.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentSuccessDto.Error.class, - io.github.project.openubl.xsender.models.rest.ResponseDocumentSuccessDto.Error.ErrorBuilder.class, - io.github.project.openubl.xsender.models.Metadata.class, - io.github.project.openubl.xsender.models.Metadata.MetadataBuilder.class, - io.github.project.openubl.xsender.models.Status.class, - io.github.project.openubl.xsender.models.Sunat.class, - io.github.project.openubl.xsender.models.Sunat.SunatBuilder.class, - io.github.project.openubl.xsender.models.SunatResponse.class, - io.github.project.openubl.xsender.models.SunatResponse.SunatResponseBuilder.class, - - io.github.project.openubl.xsender.sunat.BillServiceDestination.class, - io.github.project.openubl.xsender.sunat.BillServiceDestination.BillServiceDestinationBuilder.class, - io.github.project.openubl.xsender.sunat.BillServiceDestination.SoapOperation.class, - io.github.project.openubl.xsender.sunat.BillServiceDestination.RestOperation.class, - io.github.project.openubl.xsender.sunat.BillConsultServiceDestination.class, - io.github.project.openubl.xsender.sunat.BillConsultServiceDestination.BillConsultServiceDestinationBuilder.class, - io.github.project.openubl.xsender.sunat.BillConsultServiceDestination.Operation.class, - io.github.project.openubl.xsender.sunat.catalog.Catalog1.class, - io.github.project.openubl.xsender.utils.ByteUtils.class, - io.github.project.openubl.xsender.utils.CdrReader.class - ); + return ReflectiveClassBuildItem.builder( + Constants.class, + CxfEndpointConfiguration.class, + RestSunatErrorResponseProcessor.class, + RestSunatResponseProcessor.class, + SunatRouteBuilder.class, + SoapSunatErrorResponseProcessor.class, + SoapSunatResponseProcessor.class, + TicketResponseType.class, + CamelData.class, + CamelData.CamelDataBuilder.class, + CamelUtils.class, + CompanyCredentials.class, + CompanyCredentials.CompanyCredentialsBuilder.class, + CompanyURLs.class, + CompanyURLs.CompanyURLsBuilder.class, + BillServiceFileAnalyzer.class, + BillServiceXMLFileAnalyzer.class, + ZipFile.class, + ZipFile.ZipFileBuilder.class, + UnsupportedXMLFileException.class, + DocumentType.class, + XmlContent.class, + XmlContentProvider.class, + XmlHandler.class, + PayloadDocumentDto.class, + PayloadDocumentDto.PayloadDocumentDtoBuilder.class, + PayloadDocumentDto.Archivo.class, + PayloadDocumentDto.Archivo.ArchivoBuilder.class, + ResponseAccessTokenSuccessDto.class, + ResponseAccessTokenSuccessDto.ResponseAccessTokenSuccessDtoBuilder.class, + ResponseDocumentErrorDto.class, + ResponseDocumentErrorDto.ResponseDocumentErrorDtoBuilder.class, + ResponseDocumentErrorDto.Error.class, + ResponseDocumentErrorDto.Error.ErrorBuilder.class, + ResponseDocumentSuccessDto.class, + ResponseDocumentSuccessDto.ResponseDocumentSuccessDtoBuilder.class, + ResponseDocumentSuccessDto.Error.class, + ResponseDocumentSuccessDto.Error.ErrorBuilder.class, + Metadata.class, + Metadata.MetadataBuilder.class, + Status.class, + Sunat.class, + Sunat.SunatBuilder.class, + SunatResponse.class, + SunatResponse.SunatResponseBuilder.class, + BillServiceDestination.class, + BillServiceDestination.BillServiceDestinationBuilder.class, + BillServiceDestination.SoapOperation.class, + BillServiceDestination.RestOperation.class, + BillConsultServiceDestination.class, + BillConsultServiceDestination.BillConsultServiceDestinationBuilder.class, + BillConsultServiceDestination.Operation.class, + Catalog1.class, + ByteUtils.class, + CdrReader.class).methods().build(); } @BuildStep ReflectiveClassBuildItem soapReflection() { - return new ReflectiveClassBuildItem( - true, - false, - org.apache.cxf.binding.soap.SoapFault.class, - org.apache.cxf.transport.http.HTTPException.class - ); + return ReflectiveClassBuildItem.builder(SoapFault.class, HTTPException.class) + .methods().build(); } @BuildStep ReflectiveClassBuildItem restReflection() { - return new ReflectiveClassBuildItem( - true, - false, - org.apache.camel.http.base.HttpOperationFailedException.class - ); + return ReflectiveClassBuildItem.builder(HttpOperationFailedException.class) + .methods().build(); } @BuildStep ReflectiveClassBuildItem sunatReflection() { - return new ReflectiveClassBuildItem( - true, - true, + return ReflectiveClassBuildItem.builder( service.sunat.gob.pe.billservice.BillService.class, service.sunat.gob.pe.billservice.StatusResponse.class, service.sunat.gob.pe.billservice.GetStatus.class, @@ -145,7 +154,6 @@ ReflectiveClassBuildItem sunatReflection() { service.sunat.gob.pe.billservice.SendSummary.class, service.sunat.gob.pe.billservice.SendSummaryResponse.class, service.sunat.gob.pe.billservice.ObjectFactory.class, - service.sunat.gob.pe.billconsultservice.BillService.class, service.sunat.gob.pe.billconsultservice.StatusResponse.class, service.sunat.gob.pe.billconsultservice.GetStatus.class, @@ -153,14 +161,12 @@ ReflectiveClassBuildItem sunatReflection() { service.sunat.gob.pe.billconsultservice.GetStatusCdr.class, service.sunat.gob.pe.billconsultservice.GetStatusCdrResponse.class, service.sunat.gob.pe.billconsultservice.ObjectFactory.class, - service.sunat.gob.pe.billvalidservice.BillValidService.class, service.sunat.gob.pe.billvalidservice.StatusResponse.class, service.sunat.gob.pe.billvalidservice.ValidaCDPcriterios.class, service.sunat.gob.pe.billvalidservice.ValidaCDPcriteriosResponse.class, service.sunat.gob.pe.billvalidservice.VerificaCPEarchivo.class, service.sunat.gob.pe.billvalidservice.VerificaCPEarchivoResponse.class, - service.sunat.gob.pe.billvalidservice.ObjectFactory.class - ); + service.sunat.gob.pe.billvalidservice.ObjectFactory.class).methods().fields().build(); } } diff --git a/xsender/quarkus-extension/integration-tests/pom.xml b/xsender/quarkus-extension/integration-tests/pom.xml index 42f0d9b8..f4b7f04e 100644 --- a/xsender/quarkus-extension/integration-tests/pom.xml +++ b/xsender/quarkus-extension/integration-tests/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xsender-integration-tests Quarkus XSender - Integration Tests diff --git a/xsender/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xsender/it/QuarkusXSenderResource.java b/xsender/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xsender/it/QuarkusXSenderResource.java index d757914f..c73e75b9 100644 --- a/xsender/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xsender/it/QuarkusXSenderResource.java +++ b/xsender/quarkus-extension/integration-tests/src/main/java/io/github/project/openubl/quarkus/xsender/it/QuarkusXSenderResource.java @@ -27,200 +27,207 @@ @ApplicationScoped public class QuarkusXSenderResource { - @Inject - ProducerTemplate producerTemplate; - - CompanyURLs companyURLs = CompanyURLs - .builder() - .invoice("https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService") - .perceptionRetention("https://e-beta.sunat.gob.pe/ol-ti-itemision-guia-gem-beta/billService") - .despatch("https://api-cpe.sunat.gob.pe/v1/contribuyente/gem") - .build(); - - CompanyCredentials credentials = CompanyCredentials - .builder() - .username("12345678959MODDATOS") - .password("MODDATOS") - .token("myToken") - .build(); - - @POST - @Path("bill-service/send-invoice") - public String sendInvoice() throws Exception { - InputStream is = Thread - .currentThread() - .getContextClassLoader() - .getResourceAsStream("xmls/12345678912-01-F001-1.xml"); - - BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); - - ZipFile zipFile = fileAnalyzer.getZipFile(); - BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); - CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); - - SunatResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), SunatResponse.class); - - return sunatResponse.getStatus().toString(); - } - - @POST - @Path("bill-service/send-voided-document") - public String sendVoidedDocument() throws Exception { - InputStream is = Thread - .currentThread() - .getContextClassLoader() - .getResourceAsStream("xmls/12345678912-RA-20200328-1.xml"); - - BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); - - ZipFile zipFile = fileAnalyzer.getZipFile(); - BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); - CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); - - SunatResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), SunatResponse.class); - - return sunatResponse.getSunat().getTicket(); - } - - @POST - @Path("consult-service/get-status") - public String consultService_getStatus() throws Exception { - BillConsultServiceDestination destination = BillConsultServiceDestination.builder() - .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") - .operation(BillConsultServiceDestination.Operation.GET_STATUS) - .build(); - - CamelData camelData = getBillConsultService( - "20494918910", - "01", - "F001", - 102, - destination, - credentials - ); - - try { - service.sunat.gob.pe.billconsultservice.StatusResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_CONSULT_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), service.sunat.gob.pe.billconsultservice.StatusResponse.class); - } catch (CamelExecutionException e) { - return e.getCause().getMessage(); + @Inject + ProducerTemplate producerTemplate; + + CompanyURLs companyURLs = CompanyURLs + .builder() + .invoice("https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService") + .perceptionRetention("https://e-beta.sunat.gob.pe/ol-ti-itemision-guia-gem-beta/billService") + .despatch("https://api-cpe.sunat.gob.pe/v1/contribuyente/gem") + .build(); + + CompanyCredentials credentials = CompanyCredentials + .builder() + .username("12345678959MODDATOS") + .password("MODDATOS") + .token("myToken") + .build(); + + @POST + @Path("bill-service/send-invoice") + public String sendInvoice() throws Exception { + InputStream is = Thread + .currentThread() + .getContextClassLoader() + .getResourceAsStream("xmls/12345678912-01-F001-1.xml"); + + BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); + + ZipFile zipFile = fileAnalyzer.getZipFile(); + BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); + CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); + + SunatResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), + camelData.getHeaders(), SunatResponse.class); + + return sunatResponse.getStatus().toString(); } - throw new IllegalStateException("Excepcion no atrapada"); - } - - @POST - @Path("consult-service/get-status-cdr") - public String consultService_getStatusCdr() throws Exception { - BillConsultServiceDestination destination = BillConsultServiceDestination.builder() - .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") - .operation(BillConsultServiceDestination.Operation.GET_STATUS_CDR) - .build(); - - CamelData camelData = getBillConsultService( - "20494918910", - "01", - "F001", - 102, - destination, - credentials - ); - - try { - service.sunat.gob.pe.billconsultservice.StatusResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_CONSULT_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), service.sunat.gob.pe.billconsultservice.StatusResponse.class); - } catch (CamelExecutionException e) { - return e.getCause().getMessage(); - } + @POST + @Path("bill-service/send-voided-document") + public String sendVoidedDocument() throws Exception { + InputStream is = Thread + .currentThread() + .getContextClassLoader() + .getResourceAsStream("xmls/12345678912-RA-20200328-1.xml"); - throw new IllegalStateException("Excepcion no atrapada"); - } + BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); - @POST - @Path("bill-service/send-despatch-advice") - public String sendDespatchAdvice() throws Exception { - InputStream is = Thread - .currentThread() - .getContextClassLoader() - .getResourceAsStream("xmls/20000000001-31-VVV1-1.xml"); + ZipFile zipFile = fileAnalyzer.getZipFile(); + BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); + CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); - BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); + SunatResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), + camelData.getHeaders(), SunatResponse.class); - ZipFile zipFile = fileAnalyzer.getZipFile(); - BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); - CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); + return sunatResponse.getSunat().getTicket(); + } - try { - SunatResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), SunatResponse.class); - } catch (CamelExecutionException e) { - return e.getCause().getMessage(); + @POST + @Path("consult-service/get-status") + public String consultService_getStatus() throws Exception { + BillConsultServiceDestination destination = BillConsultServiceDestination.builder() + .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") + .operation(BillConsultServiceDestination.Operation.GET_STATUS) + .build(); + + CamelData camelData = getBillConsultService( + "20494918910", + "01", + "F001", + 102, + destination, + credentials); + + try { + service.sunat.gob.pe.billconsultservice.StatusResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_CONSULT_SERVICE_URI, + camelData.getBody(), camelData.getHeaders(), + service.sunat.gob.pe.billconsultservice.StatusResponse.class); + } catch (CamelExecutionException e) { + return e.getCause().getMessage(); + } + + throw new IllegalStateException("Excepcion no atrapada"); } - throw new IllegalStateException("Excepcion no atrapada"); - } - - @POST - @Path("consult-valid-service/validate-data") - public String consultValidService_validateData() throws Exception { - BillValidServiceDestination destination = BillValidServiceDestination.builder() - .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") - .build(); - - CamelData camelData = getBillValidService( - "20494918910", - "01", - "F001", - "102", - "06", - "12345678", - "01-12-2022", - 120.5, - "", - destination, - credentials - ); - - try { - service.sunat.gob.pe.billvalidservice.StatusResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_VALID_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), service.sunat.gob.pe.billvalidservice.StatusResponse.class); - } catch (CamelExecutionException e) { - return e.getCause().getMessage(); + @POST + @Path("consult-service/get-status-cdr") + public String consultService_getStatusCdr() throws Exception { + BillConsultServiceDestination destination = BillConsultServiceDestination.builder() + .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") + .operation(BillConsultServiceDestination.Operation.GET_STATUS_CDR) + .build(); + + CamelData camelData = getBillConsultService( + "20494918910", + "01", + "F001", + 102, + destination, + credentials); + + try { + service.sunat.gob.pe.billconsultservice.StatusResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_CONSULT_SERVICE_URI, + camelData.getBody(), camelData.getHeaders(), + service.sunat.gob.pe.billconsultservice.StatusResponse.class); + } catch (CamelExecutionException e) { + return e.getCause().getMessage(); + } + + throw new IllegalStateException("Excepcion no atrapada"); } - throw new IllegalStateException("Excepcion no atrapada"); - } - - @POST - @Path("consult-valid-service/validate-file") - public String consultValidService_validateFile() throws Exception { - String fileName = "12345678912-01-F001-1.xml"; - byte[] fileContent = Thread - .currentThread() - .getContextClassLoader() - .getResourceAsStream("xmls/" + fileName) - .readAllBytes(); - - BillValidServiceDestination destination = BillValidServiceDestination.builder() - .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") - .build(); - - CamelData camelData = getBillValidService( - fileName, - fileContent, - destination, - credentials - ); - - try { - service.sunat.gob.pe.billvalidservice.StatusResponse sunatResponse = producerTemplate - .requestBodyAndHeaders(Constants.XSENDER_BILL_VALID_SERVICE_URI, camelData.getBody(), camelData.getHeaders(), service.sunat.gob.pe.billvalidservice.StatusResponse.class); - } catch (CamelExecutionException e) { - return e.getCause().getMessage(); + @POST + @Path("bill-service/send-despatch-advice") + public String sendDespatchAdvice() throws Exception { + InputStream is = Thread + .currentThread() + .getContextClassLoader() + .getResourceAsStream("xmls/20000000001-31-VVV1-1.xml"); + + BillServiceXMLFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(is, companyURLs); + + ZipFile zipFile = fileAnalyzer.getZipFile(); + BillServiceDestination destination = fileAnalyzer.getSendFileDestination(); + CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, destination, credentials); + + try { + SunatResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_SERVICE_URI, camelData.getBody(), + camelData.getHeaders(), SunatResponse.class); + } catch (CamelExecutionException e) { + return e.getCause().getMessage(); + } + + throw new IllegalStateException("Excepcion no atrapada"); } - throw new IllegalStateException("Excepcion no atrapada"); - } + @POST + @Path("consult-valid-service/validate-data") + public String consultValidService_validateData() throws Exception { + BillValidServiceDestination destination = BillValidServiceDestination.builder() + .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") + .build(); + + CamelData camelData = getBillValidService( + "20494918910", + "01", + "F001", + "102", + "06", + "12345678", + "01-12-2022", + 120.5, + "", + destination, + credentials); + + try { + service.sunat.gob.pe.billvalidservice.StatusResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_VALID_SERVICE_URI, + camelData.getBody(), camelData.getHeaders(), + service.sunat.gob.pe.billvalidservice.StatusResponse.class); + } catch (CamelExecutionException e) { + return e.getCause().getMessage(); + } + + throw new IllegalStateException("Excepcion no atrapada"); + } + + @POST + @Path("consult-valid-service/validate-file") + public String consultValidService_validateFile() throws Exception { + String fileName = "12345678912-01-F001-1.xml"; + byte[] fileContent = Thread + .currentThread() + .getContextClassLoader() + .getResourceAsStream("xmls/" + fileName) + .readAllBytes(); + + BillValidServiceDestination destination = BillValidServiceDestination.builder() + .url("https://e-factura.sunat.gob.pe/ol-it-wsconscpegem/billConsultService") + .build(); + + CamelData camelData = getBillValidService( + fileName, + fileContent, + destination, + credentials); + + try { + service.sunat.gob.pe.billvalidservice.StatusResponse sunatResponse = producerTemplate + .requestBodyAndHeaders(Constants.XSENDER_BILL_VALID_SERVICE_URI, + camelData.getBody(), camelData.getHeaders(), + service.sunat.gob.pe.billvalidservice.StatusResponse.class); + } catch (CamelExecutionException e) { + return e.getCause().getMessage(); + } + + throw new IllegalStateException("Excepcion no atrapada"); + } } diff --git a/xsender/quarkus-extension/pom.xml b/xsender/quarkus-extension/pom.xml index 2d0e9329..ca897455 100644 --- a/xsender/quarkus-extension/pom.xml +++ b/xsender/quarkus-extension/pom.xml @@ -7,7 +7,7 @@ io.github.project-openubl xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xsender/quarkus-extension/runtime/pom.xml b/xsender/quarkus-extension/runtime/pom.xml index b9a41bfd..13b626d1 100644 --- a/xsender/quarkus-extension/runtime/pom.xml +++ b/xsender/quarkus-extension/runtime/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl quarkus-xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT quarkus-xsender Quarkus XSender - Runtime diff --git a/xsender/spring-boot-extension/integration-tests/pom.xml b/xsender/spring-boot-extension/integration-tests/pom.xml index 9d103754..2f66fcfa 100644 --- a/xsender/spring-boot-extension/integration-tests/pom.xml +++ b/xsender/spring-boot-extension/integration-tests/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl spring-boot-xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT spring-boot-xsender-integration-tests Spring Boot XSender - Integration Tests diff --git a/xsender/spring-boot-extension/pom.xml b/xsender/spring-boot-extension/pom.xml index efc2abfa..a9295c06 100644 --- a/xsender/spring-boot-extension/pom.xml +++ b/xsender/spring-boot-extension/pom.xml @@ -7,7 +7,7 @@ io.github.project-openubl xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT ../pom.xml diff --git a/xsender/spring-boot-extension/runtime/pom.xml b/xsender/spring-boot-extension/runtime/pom.xml index 8fa93417..92aa9db4 100644 --- a/xsender/spring-boot-extension/runtime/pom.xml +++ b/xsender/spring-boot-extension/runtime/pom.xml @@ -6,7 +6,7 @@ io.github.project-openubl spring-boot-xsender-parent - 5.0.3-SNAPSHOT + 6.0.0-SNAPSHOT spring-boot-xsender Spring Boot XSender - Runtime