Skip to content

Commit 2f57ec7

Browse files
1 parent 315dcec commit 2f57ec7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1904
-1
lines changed

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
java-version: ${{ matrix.java-version }}
3030
cache: maven
3131
- name: Maven tests
32-
run: mvn verify
32+
run: mvn verify -Pexamples
3333
- name: Upload XBuilder e2e Yaml files
3434
uses: actions/upload-artifact@v4
3535
with:

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"java.configuration.updateBuildConfiguration": "interactive"
3+
}

examples/pom.xml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>io.github.project-openubl</groupId>
8+
<artifactId>xhandler-parent</artifactId>
9+
<version>5.0.3-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<artifactId>examples-parent</artifactId>
14+
<name>Examples - Parent</name>
15+
<description>Examples parent</description>
16+
<packaging>pom</packaging>
17+
18+
<modules>
19+
<module>xbuilder</module>
20+
<module>xsender</module>
21+
<module>wildfly</module>
22+
<module>tomcat</module>
23+
<module>springbot</module>
24+
</modules>
25+
26+
<build>
27+
<pluginManagement>
28+
<plugins>
29+
<plugin>
30+
<groupId>org.apache.maven.plugins</groupId>
31+
<artifactId>maven-war-plugin</artifactId>
32+
<version>3.4.0</version>
33+
<configuration>
34+
<failOnMissingWebXml>false</failOnMissingWebXml>
35+
</configuration>
36+
</plugin>
37+
</plugins>
38+
</pluginManagement>
39+
</build>
40+
</project>

examples/springbot/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
## Demo XBuilder and XSender using Spring Boot
2+
3+
Download this repository and execute
4+
5+
```shell
6+
mvn spring-boot:run
7+
```
8+
9+
### Use the demo
10+
11+
Open [http://localhost:8080](http://localhost:8080)
12+
13+
![Screenshot](./screenshot.png)

examples/springbot/pom.xml

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
4+
<modelVersion>4.0.0</modelVersion>
5+
6+
<parent>
7+
<groupId>io.github.project-openubl</groupId>
8+
<artifactId>examples-parent</artifactId>
9+
<version>5.0.3-SNAPSHOT</version>
10+
<relativePath>../pom.xml</relativePath>
11+
</parent>
12+
13+
<artifactId>examples-springbot</artifactId>
14+
<name>Examples - Springbot</name>
15+
16+
<properties>
17+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18+
<surefire.plugin.version>3.0.0-M4</surefire.plugin.version>
19+
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
20+
<spring.boot-version>2.7.8</spring.boot-version>
21+
</properties>
22+
23+
<dependencyManagement>
24+
<dependencies>
25+
<dependency>
26+
<groupId>org.springframework.boot</groupId>
27+
<artifactId>spring-boot-dependencies</artifactId>
28+
<version>${spring.boot-version}</version>
29+
<type>pom</type>
30+
<scope>import</scope>
31+
</dependency>
32+
<dependency>
33+
<groupId>org.apache.camel.springboot</groupId>
34+
<artifactId>camel-spring-boot-bom</artifactId>
35+
<version>3.20.3</version>
36+
<type>pom</type>
37+
<scope>import</scope>
38+
</dependency>
39+
</dependencies>
40+
</dependencyManagement>
41+
<dependencies>
42+
<!-- Openubl dependencies -->
43+
<dependency>
44+
<groupId>io.github.project-openubl</groupId>
45+
<artifactId>xbuilder</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>io.github.project-openubl</groupId>
49+
<artifactId>spring-boot-xsender</artifactId>
50+
<version>4.1.4</version>
51+
</dependency>
52+
53+
<!-- Spring minimum libraries -->
54+
<dependency>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-web</artifactId>
57+
</dependency>
58+
59+
<!-- Optional: test dependencies -->
60+
<dependency>
61+
<groupId>org.springframework.boot</groupId>
62+
<artifactId>spring-boot-starter-test</artifactId>
63+
<scope>test</scope>
64+
</dependency>
65+
<dependency>
66+
<groupId>org.apache.camel</groupId>
67+
<artifactId>camel-test-spring-junit5</artifactId>
68+
<scope>test</scope>
69+
</dependency>
70+
</dependencies>
71+
72+
<build>
73+
<plugins>
74+
<plugin>
75+
<groupId>org.springframework.boot</groupId>
76+
<artifactId>spring-boot-maven-plugin</artifactId>
77+
<version>${spring.boot-version}</version>
78+
<executions>
79+
<execution>
80+
<goals>
81+
<goal>repackage</goal>
82+
</goals>
83+
</execution>
84+
</executions>
85+
</plugin>
86+
<plugin>
87+
<artifactId>maven-surefire-plugin</artifactId>
88+
<version>${surefire.plugin.version}</version>
89+
</plugin>
90+
<plugin>
91+
<artifactId>maven-compiler-plugin</artifactId>
92+
<version>3.11.0</version>
93+
<configuration>
94+
<release>11</release>
95+
<source>11</source>
96+
<target>11</target>
97+
</configuration>
98+
</plugin>
99+
</plugins>
100+
</build>
101+
102+
</project>

examples/springbot/screenshot.png

18.4 KB
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.github.project.openubl.quickstart.xbuilder.springboot;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.ComponentScan;
6+
7+
@ComponentScan
8+
@ComponentScan("io.github.project.openubl.spring.xsender.runtime")
9+
@SpringBootApplication
10+
public class Application {
11+
12+
public static void main(String[] args) {
13+
SpringApplication.run(Application.class, args);
14+
}
15+
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package io.github.project.openubl.quickstart.xbuilder.springboot;
2+
3+
import io.github.project.openubl.xbuilder.content.catalogs.Catalog6;
4+
import io.github.project.openubl.xbuilder.content.models.common.Cliente;
5+
import io.github.project.openubl.xbuilder.content.models.common.Proveedor;
6+
import io.github.project.openubl.xbuilder.content.models.standard.general.DocumentoVentaDetalle;
7+
import io.github.project.openubl.xbuilder.content.models.standard.general.Invoice;
8+
import io.github.project.openubl.xbuilder.enricher.ContentEnricher;
9+
import io.github.project.openubl.xbuilder.enricher.config.DateProvider;
10+
import io.github.project.openubl.xbuilder.enricher.config.Defaults;
11+
import io.github.project.openubl.xbuilder.renderer.TemplateProducer;
12+
import io.github.project.openubl.xbuilder.signature.CertificateDetails;
13+
import io.github.project.openubl.xbuilder.signature.CertificateDetailsFactory;
14+
import io.github.project.openubl.xbuilder.signature.XMLSigner;
15+
import io.github.project.openubl.xbuilder.signature.XmlSignatureHelper;
16+
import io.quarkus.qute.Template;
17+
import org.springframework.web.bind.annotation.RequestBody;
18+
import org.springframework.web.bind.annotation.RequestMapping;
19+
import org.springframework.web.bind.annotation.RequestMethod;
20+
import org.springframework.web.bind.annotation.RestController;
21+
import org.w3c.dom.Document;
22+
23+
import java.io.InputStream;
24+
import java.math.BigDecimal;
25+
import java.nio.charset.StandardCharsets;
26+
import java.security.PrivateKey;
27+
import java.security.cert.X509Certificate;
28+
import java.time.LocalDate;
29+
30+
@RestController
31+
public class XBuilderController {
32+
33+
Defaults defaults = Defaults.builder()
34+
.icbTasa(new BigDecimal("0.2"))
35+
.igvTasa(new BigDecimal("0.18"))
36+
.build();
37+
38+
DateProvider dateProvider = LocalDate::now;
39+
40+
@RequestMapping(
41+
method = RequestMethod.POST,
42+
value = "/api/create-xml",
43+
produces = "text/plain"
44+
)
45+
public String createXML(@RequestBody String clientName) throws Exception {
46+
Invoice invoice = createInvoice(clientName);
47+
48+
ContentEnricher enricher = new ContentEnricher(defaults, dateProvider);
49+
enricher.enrich(invoice);
50+
51+
Template template = TemplateProducer.getInstance().getInvoice();
52+
String xml = template.data(invoice).render();
53+
54+
// Sign XML
55+
InputStream ksInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("LLAMA-PE-CERTIFICADO-DEMO-12345678912.pfx");
56+
CertificateDetails certificate = CertificateDetailsFactory.create(ksInputStream, "password");
57+
58+
X509Certificate x509Certificate = certificate.getX509Certificate();
59+
PrivateKey privateKey = certificate.getPrivateKey();
60+
Document signedXML = XMLSigner.signXML(xml, "Project OpenUBL", x509Certificate, privateKey);
61+
62+
// Return
63+
byte[] bytesFromDocument = XmlSignatureHelper.getBytesFromDocument(signedXML);
64+
return new String(bytesFromDocument, StandardCharsets.ISO_8859_1);
65+
}
66+
67+
private Invoice createInvoice(String clientName) {
68+
return Invoice.builder()
69+
.serie("F001")
70+
.numero(1)
71+
.proveedor(Proveedor.builder()
72+
.ruc("12345678912")
73+
.razonSocial("Softgreen S.A.C.")
74+
.build()
75+
)
76+
.cliente(Cliente.builder()
77+
.nombre(clientName)
78+
.numeroDocumentoIdentidad("12121212121")
79+
.tipoDocumentoIdentidad(Catalog6.RUC.toString())
80+
.build()
81+
)
82+
.detalle(DocumentoVentaDetalle.builder()
83+
.descripcion("Item1")
84+
.cantidad(new BigDecimal("10"))
85+
.precio(new BigDecimal("100"))
86+
.unidadMedida("KGM")
87+
.build()
88+
)
89+
.detalle(DocumentoVentaDetalle.builder()
90+
.descripcion("Item2")
91+
.cantidad(new BigDecimal("10"))
92+
.precio(new BigDecimal("100"))
93+
.unidadMedida("KGM")
94+
.build()
95+
)
96+
.build();
97+
}
98+
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.github.project.openubl.quickstart.xbuilder.springboot;
2+
3+
import io.github.project.openubl.xsender.Constants;
4+
import io.github.project.openubl.xsender.camel.utils.CamelData;
5+
import io.github.project.openubl.xsender.camel.utils.CamelUtils;
6+
import io.github.project.openubl.xsender.company.CompanyCredentials;
7+
import io.github.project.openubl.xsender.company.CompanyURLs;
8+
import io.github.project.openubl.xsender.files.BillServiceFileAnalyzer;
9+
import io.github.project.openubl.xsender.files.BillServiceXMLFileAnalyzer;
10+
import io.github.project.openubl.xsender.files.ZipFile;
11+
import io.github.project.openubl.xsender.models.SunatResponse;
12+
import io.github.project.openubl.xsender.sunat.BillServiceDestination;
13+
import org.apache.camel.CamelContext;
14+
import org.springframework.beans.factory.annotation.Autowired;
15+
import org.springframework.web.bind.annotation.PostMapping;
16+
import org.springframework.web.bind.annotation.RequestParam;
17+
import org.springframework.web.bind.annotation.RestController;
18+
import org.springframework.web.multipart.MultipartFile;
19+
20+
@RestController
21+
public class XSenderController {
22+
23+
@Autowired
24+
private CamelContext camelContext;
25+
26+
CompanyURLs companyURLs = CompanyURLs.builder()
27+
.invoice("https://e-beta.sunat.gob.pe/ol-ti-itcpfegem-beta/billService")
28+
.perceptionRetention("https://e-beta.sunat.gob.pe/ol-ti-itemision-otroscpe-gem-beta/billService")
29+
.despatch("https://api-cpe.sunat.gob.pe/v1/contribuyente/gem")
30+
.build();
31+
32+
CompanyCredentials credentials = CompanyCredentials.builder()
33+
.username("12345678959MODDATOS")
34+
.password("MODDATOS")
35+
.token("accessTokenParaGuiasDeRemision")
36+
.build();
37+
38+
@PostMapping("/api/file/upload")
39+
public String uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
40+
byte[] bytes = file.getBytes();
41+
42+
BillServiceFileAnalyzer fileAnalyzer = new BillServiceXMLFileAnalyzer(bytes, companyURLs);
43+
44+
// Archivo ZIP
45+
ZipFile zipFile = fileAnalyzer.getZipFile();
46+
47+
// Configuración para enviar xml y Configuración para consultar ticket
48+
BillServiceDestination fileDestination = fileAnalyzer.getSendFileDestination();
49+
BillServiceDestination ticketDestination = fileAnalyzer.getVerifyTicketDestination();
50+
51+
// Send file
52+
CamelData camelData = CamelUtils.getBillServiceCamelData(zipFile, fileDestination, credentials);
53+
54+
SunatResponse sendFileSunatResponse = camelContext.createProducerTemplate()
55+
.requestBodyAndHeaders(
56+
Constants.XSENDER_BILL_SERVICE_URI,
57+
camelData.getBody(),
58+
camelData.getHeaders(),
59+
SunatResponse.class
60+
);
61+
62+
return fileAnalyzer.getXmlContent().getDocumentType() + " " + sendFileSunatResponse.getStatus();
63+
}
64+
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIIEogIBAAKCAQEAt1IT3CtWuVOP03CFd3jSl4wTOXm8TRPhOyDNsPQU5A+eJWJ5
3+
7v5HY/AE9aLaBQxl/UV0Qr/yMyHUgj1ZOyRsYuC4e8XzPiVpHqPjZonARi3bT+ry
4+
/1f4lBmDrLZdsJLGG9xnFoCv2XEC3FtCln1AUXMGmChJziNnmhpvtQwB6SPIKZSt
5+
eVU1sEUDdC91MdYwZxEojYzfW5m1sd/owL/slRb3qegH2YPjLWx2dOZRWU3L5TOv
6+
50dSzZOsP6B1kDesJpB7iKkUJRoq3icmxQE1AjComIPKuoPKwwZUuzeUkkgoTbBN
7+
Lpc2kMDu1M2X3m3lF8Ca7qwhvK5qzKfU+YWAnwIDAQABAoIBAFCX2PtWYk4fmn+O
8+
XF7l00+k2V7PUiVgtAhWp5c/9188Ln6pCIo1aBVblBKZgdfuV3g9bJtb35LzMIYB
9+
ipUhsjTWLsTbhdCwicJassKFlO5FgsFjvWjcuAAEJ4tqsU3LeSUOhJO0B5tEv8k4
10+
pdGbRweH1kJWk/v4PLfXH30sxjpELcEwyGjFUuKGKVFliwuLXVKlBijgrq2M+GCG
11+
1A7vO9O0JR3yGq4r8ERzJI0zNy62RzjLPF2bes0168ovcJ3Kidt2gYVVf+2kGTvc
12+
skBWdIVWFgVYtNKNoy+5Y8qPMH+7QmuDA0gMt6mXdRJHL6p0Yy+yZLCZqeDoGjgU
13+
WvsrjeECgYEA6xxwS4w3qp2H8Fn1WmLOJo1EOieqRCvJLc/srHbmYxKOqEdzp/Lt
14+
uheZ1XpzsgLSPIaD3JnEj+8a7n7J0B6ZKkyoPBUTLLilm/qPe/+C7WKWaidhXVXJ
15+
q9Dmoyo9zLBSKqm0QJBCNEvZ7DT4RtyFL0Y0HWntIeBcrXAdfBss4NUCgYEAx5us
16+
axT6CoYPGqQZgorg3WgxAcA0WpbiyBdpFVsOycbpwWqQlqGLDNOvyjzyUSGMrGo3
17+
ObAsW6cOpKkapXfq2hTCbHupecm/4QYoDOPo7hAHwCuy/ODHJhzo5OM53n8EggFW
18+
XnomzvadKyAY9/+0fH2WZxns3EwKs5YO2fTtdaMCgYAWhaTkN8xlVa3eAmAUhn6F
19+
BudQQth2q1McRly/sKwlNXPg/uc/YXAQcY5U+uP2W3rUPXaIPVqtBxSnYBHpE+VM
20+
PgenqcUqdY23wWrZUAK0xsrt5FPZYwxsnxhY7QT6hLF6UMNpo+gTpmh7zh8yepFv
21+
k+QOJUWIBzwZiTHp35iO+QKBgHnzelvR7RIQ5Zl5OLyw7MFYrthK/bF7DgMBioop
22+
n9dXV+l7mertt26WxofgxIsc3D1ah3MPV4qHfkLLriP6J9olZMOyqdBmmnx4rm9x
23+
rxYDZTjbefdVvVZjw0ZULT7qi26CMqp2Js+7jDqU2axq5XJJqGJFTJkrPD6MJ3ay
24+
VYHRAoGAGG+rgP44tjwu0qmmUDfdp1tlMzUwVmM3pvjw1+RKYQprt+K3cUlBliPf
25+
VKMs9aQ0J6VrjrkNHTL85VzeOK6QYnsKZuski3GD0hA3XVE3u4SuMCb3Rmt6eLVr
26+
f9UGabwN9n5il3ZV7+qCmvpYGZzQ1A8+jZgbFWW3bp4BuIiwbbg=
27+
-----END RSA PRIVATE KEY-----

0 commit comments

Comments
 (0)